diff --git a/.gitattributes b/.gitattributes
index ae17ee40c..a91e62484 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1 @@
**/zz_gen_*.* linguist-generated
-docs/data/zz_cli_help.toml linguist-generated
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index ea3fd9a3a..f8591e2a6 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -7,9 +7,9 @@ body:
attributes:
label: Welcome
options:
- - label: Yes, I'm using a binary release within the two latest releases.
+ - label: Yes, I'm using a binary release within 2 latest releases.
required: true
- - label: Yes, I've searched for similar issues on GitHub and didn't find any.
+ - label: Yes, I've searched similar issues on GitHub and didn't find any.
required: true
- label: Yes, I've included all information below (version, config, etc).
required: true
@@ -45,7 +45,6 @@ body:
- Through Bitnami
- Through 1Panel
- Through Zoraxy
- - Through Certimate
- go install
- Other
validations:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 7f6793167..b29c0d9f5 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -6,7 +6,7 @@ body:
attributes:
label: Welcome
options:
- - label: Yes, I've searched for similar issues on GitHub and didn't find any.
+ - label: Yes, I've searched similar issues on GitHub and didn't find any.
required: true
- type: dropdown
@@ -24,7 +24,6 @@ body:
- Through Bitnami
- Through 1Panel
- Through Zoraxy
- - Through Certimate
- go install
- Other
validations:
diff --git a/.github/ISSUE_TEMPLATE/new_dns_provider.yml b/.github/ISSUE_TEMPLATE/new_dns_provider.yml
index b319bc287..f310e9815 100644
--- a/.github/ISSUE_TEMPLATE/new_dns_provider.yml
+++ b/.github/ISSUE_TEMPLATE/new_dns_provider.yml
@@ -8,21 +8,15 @@ body:
attributes:
label: Welcome
options:
- - label: Yes, I've searched for similar issues on GitHub and didn't find any.
+ - label: Yes, I've searched similar issues on GitHub and didn't find any.
required: true
- label: Yes, the DNS provider exposes a public API.
required: true
- label: Yes, I know that the lego maintainers don't have an account in all DNS providers in the world.
required: true
-
- - type: checkboxes
- id: pr
- attributes:
- label: Implementation
- options:
- label: Yes, I'm able to create a pull request and be able to maintain the implementation.
required: false
- - label: Yes, I can test an implementation with the help of the maintainers if someone creates a pull request.
+ - label: Yes, I'm able to test an implementation if someone creates a pull request to add the support of this DNS provider.
required: false
- type: dropdown
@@ -40,23 +34,10 @@ body:
- Through Bitnami
- Through 1Panel
- Through Zoraxy
- - Through Certimate
- - go install
- Other
validations:
required: true
- - type: dropdown
- id: profile
- attributes:
- label: Who are you?
- options:
- - A customer of this DNS provider
- - An employee of this DNS provider
- - Other (please explain)
- validations:
- required: true
-
- type: input
id: provider-link
attributes:
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index 795320a8d..000000000
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
index 4f9d444fc..46f7f6730 100644
--- a/.github/workflows/documentation.yml
+++ b/.github/workflows/documentation.yml
@@ -12,16 +12,20 @@ jobs:
runs-on: ubuntu-latest
env:
GO_VERSION: stable
- HUGO_VERSION: 0.148.2
+ HUGO_VERSION: 0.131.0
CGO_ENABLED: 0
steps:
- - uses: actions/checkout@v6
+ # https://github.com/marketplace/actions/checkout
+ - name: Check out code
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- - uses: actions/setup-go@v6
+ # https://github.com/marketplace/actions/setup-go-environment
+ - name: Set up Go ${{ env.GO_VERSION }}
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml
index 9dee85035..30ec652a2 100644
--- a/.github/workflows/go-cross.yml
+++ b/.github/workflows/go-cross.yml
@@ -20,8 +20,13 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- - uses: actions/checkout@v6
- - uses: actions/setup-go@v6
+ # https://github.com/marketplace/actions/checkout
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ # https://github.com/marketplace/actions/setup-go-environment
+ - name: Set up Go ${{ matrix.go-version }}
+ uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 33ca106cc..6930ce70a 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -13,44 +13,59 @@ jobs:
runs-on: ubuntu-latest
env:
GO_VERSION: stable
- GOLANGCI_LINT_VERSION: v2.10
- HUGO_VERSION: 0.148.2
+ GOLANGCI_LINT_VERSION: v2.2.1
+ HUGO_VERSION: 0.131.0
CGO_ENABLED: 0
LEGO_E2E_TESTS: CI
MEMCACHED_HOSTS: localhost:11211
steps:
- - uses: actions/checkout@v6
+ # https://github.com/marketplace/actions/checkout
+ - name: Check out code
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- - uses: actions/setup-go@v6
+ # https://github.com/marketplace/actions/setup-go-environment
+ - name: Set up Go ${{ env.GO_VERSION }}
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Check and get dependencies
run: |
- go mod tidy --diff
+ go mod tidy
+ git diff --exit-code go.mod
+ git diff --exit-code go.sum
- name: Generate and Check generated elements
run: |
make generate-dns
git diff --exit-code
- - uses: golangci/golangci-lint-action@v9
- with:
- version: ${{ env.GOLANGCI_LINT_VERSION }}
- install-only: true
+ # https://golangci-lint.run/usage/install#other-ci
+ - name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }}
+ run: |
+ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION}
+ golangci-lint --version
- name: Install Pebble
- run: go install github.com/letsencrypt/pebble/v2/cmd/pebble@v2.9.0
+ run: go install github.com/letsencrypt/pebble/v2/cmd/pebble@v2.7.0
- name: Install challtestsrv
- run: go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@v2.9.0
+ run: go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@v2.7.0
- name: Set up a Memcached server
- run: docker run -d --rm -p 11211:11211 memcached:1.6-alpine
+ uses: niden/actions-memcached@v7
+
+ - name: Setup /etc/hosts
+ run: |
+ echo "127.0.0.1 acme.wtf" | sudo tee -a /etc/hosts
+ echo "127.0.0.1 lego.wtf" | sudo tee -a /etc/hosts
+ echo "127.0.0.1 acme.lego.wtf" | sudo tee -a /etc/hosts
+ echo "127.0.0.1 légô.wtf" | sudo tee -a /etc/hosts
+ echo "127.0.0.1 xn--lg-bja9b.wtf" | sudo tee -a /etc/hosts
- name: Make
run: |
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6a0d3b703..ee3ea21dd 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -5,11 +5,6 @@ on:
tags:
- v*
-permissions:
- # Allow the workflow to write attestations.
- id-token: write
- attestations: write
-
jobs:
release:
@@ -42,11 +37,13 @@ jobs:
docker-images: true
swap-storage: false
- - uses: actions/checkout@v6
+ - name: Check out code
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- - uses: actions/setup-go@v6
+ - name: Set up Go ${{ env.GO_VERSION }}
+ uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
@@ -67,21 +64,11 @@ jobs:
# https://goreleaser.com/ci/actions/
- name: Run GoReleaser
- id: goreleaser
uses: goreleaser/goreleaser-action@v6
with:
- version: v2.13.0
+ version: v2.8.1
args: release -p 1 --clean --timeout=90m
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }}
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
AUR_KEY: ${{ secrets.AUR_KEY }}
-
- - uses: actions/attest-build-provenance@v3
- with:
- subject-checksums: ./dist/lego_${{ fromJSON(steps.goreleaser.outputs.metadata).version }}_checksums.txt
- github-token: ${{ secrets.GH_TOKEN_REPO }}
- - uses: actions/attest-build-provenance@v3
- with:
- subject-checksums: ./dist/digests.txt
- github-token: ${{ secrets.GH_TOKEN_REPO }}
diff --git a/.golangci.yml b/.golangci.yml
index b6ab51ccc..66f3fd9d0 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -50,8 +50,11 @@ linters:
- tagliatelle
- testpackage # not relevant
- tparallel # not relevant
+ - usestdlibvars # false-positive https://github.com/sashamelentyev/usestdlibvars/issues/96
- varnamelen # not relevant
- wrapcheck
+ - wsl_v5 # should be enabled the future.
+ - embeddedstructfieldcheck # should be enabled the future.
settings:
depguard:
@@ -180,12 +183,6 @@ linters:
text: Error return value of `fmt.Fprintln` is not checked
linters:
- errcheck
- - text: "var-naming: avoid meaningless package names"
- linters:
- - revive
- - text: "var-naming: avoid package names that conflict with Go standard library package names"
- linters:
- - revive
- path: certcrypto/crypto.go
text: (tlsFeatureExtensionOID|ocspMustStapleFeature) is a global variable
linters:
@@ -198,8 +195,8 @@ linters:
text: dnsTimeout is a global variable
linters:
- gochecknoglobals
- - path: challenge/dns01/precheck.go
- text: defaultNameserverPort is a global variable
+ - path: challenge/dns01/nameserver_test.go
+ text: findXByFqdnTestCases is a global variable
linters:
- gochecknoglobals
- path: challenge/http01/domain_matcher.go
@@ -222,7 +219,11 @@ linters:
text: load is a global variable
linters:
- gochecknoglobals
- - path: providers/(dns|http)/([\d\w]+/)*[\d\w]+_test.go
+ - path: providers/dns/([\d\w]+/)*[\d\w]+_test.go
+ text: envTest is a global variable
+ linters:
+ - gochecknoglobals
+ - path: providers/http/([\d\w]+/)*[\d\w]+_test.go
text: envTest is a global variable
linters:
- gochecknoglobals
@@ -230,10 +231,6 @@ linters:
text: testCases is a global variable
linters:
- gochecknoglobals
- - path: providers/dns/namecheap/transport.go
- text: (envProxyOnce|envProxyFuncValue) is a global variable
- linters:
- - gochecknoglobals
- path: providers/dns/acmedns/mock_test.go
text: egTestAccount is a global variable
linters:
@@ -269,10 +266,6 @@ 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/.goreleaser.yml b/.goreleaser.yml
index c358f8a38..9bf101420 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -42,10 +42,6 @@ builds:
goarch: 386
- goos: openbsd
goarch: arm
- # Deprecated in go1.25, Removed in go1.26
- # https://go.dev/doc/go1.25#windows
- - goos: windows
- goarch: arm
changelog:
sort: asc
@@ -55,20 +51,6 @@ changelog:
- '(?i)^Detach v[\d|.]+'
- '(?i)^Prepare release v[\d|.]+'
-release:
- skip_upload: false
- github:
- owner: 'go-acme'
- name: 'lego'
- header: |
- lego is an independent, free, and open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
-
- Everybody thinks that the others will donate, but in the end, nobody does.
-
- So if you think that lego is worth it, please consider [donating](https://donate.ldez.dev).
-
- For key updates, see the [changelog](https://github.com/go-acme/lego/blob/HEAD/CHANGELOG.md#v{{ .Major }}{{ .Minor }}{{ .Patch }}).
-
archives:
- id: lego
name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}'
@@ -80,29 +62,87 @@ archives:
- LICENSE
- CHANGELOG.md
-dockers_v2:
- - images:
- - 'goacme/lego'
+docker_manifests:
+ - name_template: 'goacme/lego:{{ .Tag }}'
+ image_templates:
+ - 'goacme/lego:{{ .Tag }}-amd64'
+ - 'goacme/lego:{{ .Tag }}-arm64'
+ - 'goacme/lego:{{ .Tag }}-armv7'
+ - name_template: 'goacme/lego:latest'
+ image_templates:
+ - 'goacme/lego:{{ .Tag }}-amd64'
+ - 'goacme/lego:{{ .Tag }}-arm64'
+ - 'goacme/lego:{{ .Tag }}-armv7'
+ - name_template: 'goacme/lego:v{{ .Major }}.{{ .Minor }}'
+ image_templates:
+ - 'goacme/lego:v{{ .Major }}.{{ .Minor }}-amd64'
+ - 'goacme/lego:v{{ .Major }}.{{ .Minor }}-arm64'
+ - 'goacme/lego:v{{ .Major }}.{{ .Minor }}-armv7'
+
+dockers:
+ - use: buildx
+ goos: linux
+ goarch: amd64
dockerfile: buildx.Dockerfile
- platforms:
- - linux/amd64
- - linux/arm64
- - linux/arm/v7
- tags:
- - 'latest'
- - 'v{{ .Major }}'
- - 'v{{ .Major }}.{{ .Minor }}'
- - '{{ .Tag }}'
- labels:
+ image_templates:
+ - 'goacme/lego:latest-amd64'
+ - 'goacme/lego:{{ .Tag }}-amd64'
+ - 'goacme/lego:v{{ .Major }}.{{ .Minor }}-amd64'
+ build_flag_templates:
+ - '--pull'
# https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
- 'org.opencontainers.image.title': '{{.ProjectName}}'
- 'org.opencontainers.image.description': 'Lets Encrypt/ACME client and library written in Go'
- 'org.opencontainers.image.source': '{{.GitURL}}'
- 'org.opencontainers.image.url': '{{.GitURL}}'
- 'org.opencontainers.image.documentation': 'https://go-acme.github.io/lego'
- 'org.opencontainers.image.created': '{{.Date}}'
- 'org.opencontainers.image.revision': '{{.FullCommit}}'
- 'org.opencontainers.image.version': '{{.Version}}'
+ - '--label=org.opencontainers.image.title={{.ProjectName}}'
+ - '--label=org.opencontainers.image.description=Lets Encrypt/ACME client and library written in Go'
+ - '--label=org.opencontainers.image.source={{.GitURL}}'
+ - '--label=org.opencontainers.image.url={{.GitURL}}'
+ - '--label=org.opencontainers.image.documentation=https://go-acme.github.io/lego'
+ - '--label=org.opencontainers.image.created={{.Date}}'
+ - '--label=org.opencontainers.image.revision={{.FullCommit}}'
+ - '--label=org.opencontainers.image.version={{.Version}}'
+ - '--platform=linux/amd64'
+
+ - use: buildx
+ goos: linux
+ goarch: arm64
+ dockerfile: buildx.Dockerfile
+ image_templates:
+ - 'goacme/lego:latest-arm64'
+ - 'goacme/lego:{{ .Tag }}-arm64'
+ - 'goacme/lego:v{{ .Major }}.{{ .Minor }}-arm64'
+ build_flag_templates:
+ - '--pull'
+ # https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
+ - '--label=org.opencontainers.image.title={{.ProjectName}}'
+ - '--label=org.opencontainers.image.description=Lets Encrypt/ACME client and library written in Go'
+ - '--label=org.opencontainers.image.source={{.GitURL}}'
+ - '--label=org.opencontainers.image.url={{.GitURL}}'
+ - '--label=org.opencontainers.image.documentation=https://go-acme.github.io/lego'
+ - '--label=org.opencontainers.image.created={{.Date}}'
+ - '--label=org.opencontainers.image.revision={{.FullCommit}}'
+ - '--label=org.opencontainers.image.version={{.Version}}'
+ - '--platform=linux/arm64'
+
+ - use: buildx
+ goos: linux
+ goarch: arm
+ goarm: '7'
+ dockerfile: buildx.Dockerfile
+ image_templates:
+ - 'goacme/lego:latest-armv7'
+ - 'goacme/lego:{{ .Tag }}-armv7'
+ - 'goacme/lego:v{{ .Major }}.{{ .Minor }}-armv7'
+ build_flag_templates:
+ - '--pull'
+ # https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
+ - '--label=org.opencontainers.image.title={{.ProjectName}}'
+ - '--label=org.opencontainers.image.description=Lets Encrypt/ACME client and library written in Go'
+ - '--label=org.opencontainers.image.source={{.GitURL}}'
+ - '--label=org.opencontainers.image.url={{.GitURL}}'
+ - '--label=org.opencontainers.image.documentation=https://go-acme.github.io/lego'
+ - '--label=org.opencontainers.image.created={{.Date}}'
+ - '--label=org.opencontainers.image.revision={{.FullCommit}}'
+ - '--label=org.opencontainers.image.version={{.Version}}'
+ - '--platform=linux/arm/v7'
snapcrafts:
- name_template: "{{ .ProjectName }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ae73f70f3..98c7a97ac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,221 +1,12 @@
# Changelog
-lego is an independent, free, open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
-
-Everybody thinks that the others will donate, but in the end, nobody does.
-
-So if you think that lego is worth it, please consider [donating](https://donate.ldez.dev).
-
-## v4.32.0
-
-- Release date: 2026-02-19
-- Tag: [v4.32.0](https://github.com/go-acme/lego/releases/tag/v4.32.0)
-
-### Added
-
-- **[dnsprovider]** Add DNS provider for ArtFiles
-- **[dnsprovider]** Add DNS provider for Leaseweb
-- **[dnsprovider]** Add DNS provider for FusionLayer NameSurfer
-- **[dnsprovider]** Add DNS provider for DDNSS
-- **[dnsprovider]** Add DNS provider for Bluecat v2
-- **[dnsprovider]** Add DNS provider for TodayNIC/时代互联
-- **[dnsprovider]** Add DNS provider for DNSExit
-- **[dnsprovider]** alidns: add line record option
-
-### Changed
-
-- **[dnsprovider]** azure: reinforces deprecation
-- **[dnsprovider]** allinkl: detect zone through API
-
-### Fixed
-
-- **[ari]** fix: implement parsing for Retry-After header according to RFC 7231
-- **[dnsprovider]** namesurfer: fix updateDNSHost
-- **[dnsprovider]** timewebcloud: fix subdomain support
-- **[dnsprovider]** fix: deduplicate authz for DNS01 challenge
-- **[lib,cli]** fix: use IPs to define the main domain
-- **[lib]** fix: preserve domain order
-
-## v4.31.0
-
-- Release date: 2026-01-08
-- Tag: [v4.31.0](https://github.com/go-acme/lego/releases/tag/v4.31.0)
-
-### Added
-
-- **[dnsprovider]** Add DNS provider for ISPConfig
-- **[dnsprovider]** Add DNS Provider for ISPConfig (DDNS Module)
-- **[dnsprovider]** Add DNS provider for Alwaysdata
-- **[dnsprovider]** Add DNS provider for JDCloud
-- **[dnsprovider]** Add DNS provider for 35.com/三五互联
-- **[dnsprovider]** f5xc: add an option to configure the domain of the server
-
-### Changed
-
-- **[lib]** feat: improve ACME error types
-- **[dnsprovider,cname]** namedotcom: follow CNAME
-
-### Fixed
-
-- **[dnsprovider]** hetzner: fix compatibility with _FILE suffix
-- **[dnsprovider]** gandiv5: fix API Key header
-
-## v4.30.1
-
-- Release date: 2025-12-16
-- Tag: [v4.30.1](https://github.com/go-acme/lego/releases/tag/v4.30.1)
-
-Due to an error related to `aliyun/credentials-go`, some artifacts of the v4.30.0 release have not been published.
-
-This release contains the same things as v4.30.0.
-
-## v4.30.0
-
-- Release date: 2025-12-16
-- Tag: [v4.30.0](https://github.com/go-acme/lego/releases/tag/v4.30.0)
-
-### Added
-
-- **[dnsprovider]** Add DNS provider for Ionos Cloud
-- **[dnsprovider]** Add DNS provider for Virtualname
-- **[dnsprovider]** Add DNS Provider for Neodigit
-- **[dnsprovider]** Add DNS provider for Syse.no
-- **[dnsprovider]** Add DNS provider for Gravity
-- **[dnsprovider]** Add DNS provider for hosting.nl
-
-### Changed
-
-- **[cli]** feat: remove email requirement
-
-### Fixed
-
-- **[dnsprovider]** autodns: use the right response structure
-
-## v4.29.0
-
-- Release date: 2025-11-29
-- Tag: [v4.29.0](https://github.com/go-acme/lego/releases/tag/v4.29.0)
-
-### Added
-
-- **[dnsprovider]** Add DNS provider for United-Domains
-- **[dnsprovider]** Add DNS provider for Gigahost.no
-- **[dnsprovider]** Add DNS provider for EdgeCenter
-- **[dnsprovider]** Add DNS provider for AlibabaCloud ESA
-- **[dnsprovider]** edgeone: add zones mapping
-- **[dnsprovider]** namecheap: add experimental proxy support
-
-### Changed
-
-- **[dnsprovider]** gandiv5: update base API URL
-
-### Fixed
-
-- **[dnsprovider]** hetzner: use int64 for IDs
-- **[dnsprovider]** baiducloud: pagination and TTL
-- **[dnsprovider]** inwx: fix API breaking changes with record IDs
-
-## v4.28.1
-
-- Release date: 2025-11-06
-- Tag: [v4.28.1](https://github.com/go-acme/lego/releases/tag/v4.28.1)
-
-### Fixed
-
-- **[cli]** fix: skip nil response
-
-## v4.28.0
-
-- Release date: 2025-10-31
-- Tag: [v4.28.0](https://github.com/go-acme/lego/releases/tag/v4.28.0)
-
-### Added
-
-- **[dnsprovider]** Add DNS provider for Anexia
-- **[dnsprovider]** Add DNS provider for webnames.ca
-- **[dnsprovider]** webnames: rename to webnamesru to avoid ambiguity with webnamesca
-
-### Changed
-
-- **[dnsprovider,log]** hetzner: add deprecation logs
-- **[dnsprovider]** iwantmyname: provider deprecation
-- **[cli]** improve retryable HTTP client error handling
-
-### Fixed
-
-- **[dnsprovider]** hostinger: fix record update
-
-## v4.27.0
-
-- Release date: 2025-10-17
-- Tag: [v4.27.0](https://github.com/go-acme/lego/releases/tag/v4.27.0)
-
-### Added
-
-- **[dnsprovider]** Add DNS provider for Octenium
-- **[dnsprovider]** Add DNS provider for Hostinger
-- **[dnsprovider]** Add DNS provider for Beget.com
-
-### Changed
-
-- **[cli]** support `--private-key` with a PKCS#8 keypair
-- **[dnsprovider]** hetzner: update to new API
-- **[dnsprovider]** otc: adds option to use private zone
-
-### Fixed
-
-- **[lib]** fix: deduplicate order identifiers
-
-## v4.26.0
-
-- Release date: 2025-09-13
-- Tag: [v4.26.0](https://github.com/go-acme/lego/releases/tag/v4.26.0)
-
-### Added
-
-- **[dnsprovider]** Add DNS provider for KeyHelp
-- **[dnsprovider]** Add DNS provider for Binary Lane
-- **[dnsprovider]** Add DNS provider for Tencent EdgeOne
-- **[dnsprovider]** azuredns: pipeline credential support
-- **[dnsprovider]** oraclecloud: handle instance_principal authentication
-
-### Changed
-
-- **[dnsprovider]** oraclecloud: add env var aliases
-- **[dnsprovider]** simply: update to API v2
-- **[lib,cli]** EAB: fallback to base64.URLEncoding
-
-### Fixed
-
-- **[dnsprovider]** selectelv2: add missing options
-
-## v4.25.2
-
-- Release date: 2025-08-06
-- Tag: [v4.25.2](https://github.com/go-acme/lego/releases/tag/v4.25.2)
-
-### Changed
-
-- **[cli,log]** log when dynamic renew date not yet reached
-
-### Fixed
-
-- **[cli]** fix: remove wrong env var
-- **[lib,cli]** fix: enforce HTTPS to the ACME server
-
-## v4.25.1
-
-- Release date: 2025-07-21
-- Tag: [v4.25.1](https://github.com/go-acme/lego/releases/tag/v4.25.1)
+## [v4.25.1](https://github.com/go-acme/lego/releases/tag/v4.25.1) (2025-07-21)
### Fixed
- **[cli]** fix: wrong CLI flag type
-## v4.25.0
-
-- Release date: 2025-07-21
-- Tag: [v4.25.0](https://github.com/go-acme/lego/releases/tag/v4.25.0)
+## [v4.25.0](https://github.com/go-acme/lego/releases/tag/v4.25.0) (2025-07-21)
The binary size of this release is about ~50% smaller compared to previous releases.
@@ -228,7 +19,7 @@ This will also reduce the module cache usage by 320 MB (this will only affect us
- **[lib,cli]** Add an option to disable common name in CSR
### Changed
-
+-
- **[dnsprovider]** vinyldns: add an option to add quotes around the TXT record value
- **[dnsprovider]** ionos: increase default propagation timeout
@@ -236,10 +27,7 @@ This will also reduce the module cache usage by 320 MB (this will only affect us
- **[cli]** fix: enforce domain into renewal command
-## v4.24.0
-
-- Release date: 2025-07-07
-- Tag: [v4.24.0](https://github.com/go-acme/lego/releases/tag/v4.24.0)
+## [v4.24.0](https://github.com/go-acme/lego/releases/tag/v4.24.0) (2025-07-07)
### Added
@@ -262,19 +50,13 @@ This will also reduce the module cache usage by 320 MB (this will only affect us
- **[dnsprovider]** nicmanager: fix mode env var name and value
- **[lib,cli]** Check order identifiers difference between client and server
-## v4.23.1
-
-- Release date: 2025-04-16
-- Tag: [v4.23.1](https://github.com/go-acme/lego/releases/tag/v4.23.1)
+## [v4.23.1](https://github.com/go-acme/lego/releases/tag/v4.23.1) (2025-04-16)
Due to an error related to Snapcraft, some artifacts of the v4.23.0 release have not been published.
This release contains the same things as v4.23.0.
-## v4.23.0
-
-- Release date: 2025-04-16
-- Tag: [v4.23.0](https://github.com/go-acme/lego/releases/tag/v4.23.0)
+## [v4.23.0](https://github.com/go-acme/lego/releases/tag/v4.23.0) (2025-04-16)
### Added
@@ -305,19 +87,13 @@ This release contains the same things as v4.23.0.
- **[dnsprovider]** pdns: fix TXT record cleanup for wildcard domains
- **[dnsprovider]** allinkl: remove `ReturnInfo`
-## v4.22.2
-
-- Release date: 2025-02-17
-- Tag: [v4.22.2](https://github.com/go-acme/lego/releases/tag/v4.22.2)
+## [v4.22.2](https://github.com/go-acme/lego/releases/tag/v4.22.2) (2025-02-17)
### Fixed
- **[dnsprovider]** acme-dns: use new registred account
-## v4.22.1
-
-- Release date: 2025-02-17
-- Tag: [v4.22.1](https://github.com/go-acme/lego/releases/tag/v4.22.1)
+## [v4.22.1](https://github.com/go-acme/lego/releases/tag/v4.22.1) (2025-02-17)
### Fixed
@@ -325,10 +101,7 @@ This release contains the same things as v4.23.0.
### Added
-## v4.22.0
-
-- Release date: 2025-02-17
-- Tag: [v4.22.0](https://github.com/go-acme/lego/releases/tag/v4.22.0)
+## [v4.22.0](https://github.com/go-acme/lego/releases/tag/v4.22.0) (2025-02-17)
### Added
@@ -356,10 +129,7 @@ This release contains the same things as v4.23.0.
- **[cli,log]** remove extra debug logs
-## v4.21.0
-
-- Release date: 2024-12-20
-- Tag: [v4.21.0](https://github.com/go-acme/lego/releases/tag/v4.21.0)
+## [v4.21.0](https://github.com/go-acme/lego/releases/tag/v4.21.0) (2024-12-20)
### Added
@@ -380,17 +150,11 @@ This release contains the same things as v4.23.0.
- **[dnsprovider]** netcup: increase default propagation values
- **[dnsprovider]** otc: use default transport
-## v4.20.4
-
-- Release date: 2024-11-21
-- Tag: [v4.20.4](https://github.com/go-acme/lego/releases/tag/v4.20.4)
+## [v4.20.4](https://github.com/go-acme/lego/releases/tag/v4.20.4) (2024-11-21)
Publish the Snap to the Snapcraft stable channel.
-## v4.20.3
-
-- Release date: 2024-11-21
-- Tag: [v4.20.3](https://github.com/go-acme/lego/releases/tag/v4.20.3)
+## [v4.20.3](https://github.com/go-acme/lego/releases/tag/v4.20.3) (2024-11-21)
### Fixed
@@ -398,10 +162,7 @@ Publish the Snap to the Snapcraft stable channel.
- **[dnsprovider]** directadmin: fix timeout configuration
- **[httpprovider]** fix: HTTP server IPv6 matching
-## v4.20.2
-
-- Release date: 2024-11-11
-- Tag: [v4.20.2](https://github.com/go-acme/lego/releases/tag/v4.20.2)
+## [v4.20.2](https://github.com/go-acme/lego/releases/tag/v4.20.2) (2024-11-11)
### Added
@@ -429,41 +190,28 @@ Publish the Snap to the Snapcraft stable channel.
- **[dnsprovider]** volcengine: set API information within the default configuration
- **[log]** Parse printf verbs in log line output
-## v4.20.1
-
-- Release date: 2024-11-11
+## v4.20.1 (2024-11-11)
Cancelled due to CI failure.
-## v4.20.0
-
-- Release date: 2024-11-11
+## v4.20.0 (2024-11-11)
Cancelled due to CI failure.
-## v4.19.2
-
-- Release date: 2024-10-06
-- Tag: [v4.19.2](https://github.com/go-acme/lego/releases/tag/v4.19.2)
+## [v4.19.2](https://github.com/go-acme/lego/releases/tag/v4.19.2) (2024-10-06)
### Fixed
- **[lib]** go1.22 compatibility
-## v4.19.1
-
-- Release date: 2024-10-06
-- Tag: [v4.19.1](https://github.com/go-acme/lego/releases/tag/v4.19.1)
+## [v4.19.1](https://github.com/go-acme/lego/releases/tag/v4.19.1) (2024-10-06)
### Fixed
- **[dnsprovider]** selectelv2: use baseURL from configuration
- **[dnsprovider]** epik: add User-Agent
-## v4.19.0
-
-- Release date: 2024-10-03
-- Tag: [v4.19.0](https://github.com/go-acme/lego/releases/tag/v4.19.0)
+## [v4.19.0](https://github.com/go-acme/lego/releases/tag/v4.19.0) (2024-10-03)
### Added
@@ -485,10 +233,7 @@ Cancelled due to CI failure.
- **[dnsprovider]** namesilo: restrict CleanUp
- **[dnsprovider]** godaddy: fix cleanup
-## v4.18.0
-
-- Release date: 2024-08-30
-- Tag: [v4.18.0](https://github.com/go-acme/lego/releases/tag/v4.18.0)
+## [v4.18.0](https://github.com/go-acme/lego/releases/tag/v4.18.0) (2024-08-30)
### Added
@@ -510,19 +255,13 @@ Cancelled due to CI failure.
- **[ari]** fix: avoid Int63n panic in ShouldRenewAt()
-## v4.17.4
-
-- Release date: 2024-06-12
-- Tag: [v4.17.4](https://github.com/go-acme/lego/releases/tag/v4.17.4)
+## [v4.17.4](https://github.com/go-acme/lego/releases/tag/v4.17.4) (2024-06-12)
### Fixed
- **[dnsprovider]** Update dependencies
-## v4.17.3
-
-- Release date: 2024-05-28
-- Tag: [v4.17.3](https://github.com/go-acme/lego/releases/tag/v4.17.3)
+## [v4.17.3](https://github.com/go-acme/lego/releases/tag/v4.17.3) (2024-05-28)
### Added
@@ -550,17 +289,13 @@ Cancelled due to CI failure.
- **[dnsprovider]** pdns: reconstruct zone URLs to enable non-root folder API endpoints
- **[dnsprovider]** alidns: fix link to API documentation
-## v4.17.2
-
-- Release date: 2024-05-28
+## v4.17.2 (2024-05-28)
Canceled due to a release failure related to Snapcraft.
The Snapcraft release are disabled for now.
-## v4.17.1
-
-- Release date: 2024-05-28
+## v4.17.1 (2024-05-28)
Canceled due to a release failure related to oci-go-sdk.
@@ -569,25 +304,17 @@ The module `github.com/oracle/oci-go-sdk/v65` uses `github.com/gofrs/flock` but
Due to that we will remove the Solaris build.
-## v4.17.0
-
-- Release date: 2024-05-28
+## v4.17.0 (2024-05-28)
Canceled due to a release failure related to Snapcraft.
-## v4.16.1
-
-- Release date: 2024-03-10
-- Tag: [v4.16.1](https://github.com/go-acme/lego/releases/tag/v4.16.1)
+## [v4.16.1](https://github.com/go-acme/lego/releases/tag/v4.16.1) (2024-03-10)
### Fixed
- **[cli,ari]** fix: don't generate ARI cert ID if ARI is not enable
-## v4.16.0
-
-- Release date: 2024-03-09
-- Tag: [v4.16.0](https://github.com/go-acme/lego/releases/tag/v4.16.0)
+## [v4.16.0](https://github.com/go-acme/lego/releases/tag/v4.16.0) (2024-03-09)
### Added
@@ -608,10 +335,7 @@ Canceled due to a release failure related to Snapcraft.
- **[dnsprovider]** easydns: fix zone detection
- **[dnsprovider]** ns1: fix record creation
-## v4.15.0
-
-- Release date: 2024-01-28
-- Tag: [v4.15.0](https://github.com/go-acme/lego/releases/tag/v4.15.0)
+## [v4.15.0](https://github.com/go-acme/lego/releases/tag/v4.15.0) (2024-01-28)
### Added
@@ -649,10 +373,7 @@ Canceled due to a release failure related to Snapcraft.
- **[dnsprovider]** nifcloud: fix API requests
- **[dnsprovider]** otc: sequential challenge
-## v4.14.1
-
-- Release date: 2023-09-20
-- Tag: [v4.14.1](https://github.com/go-acme/lego/releases/tag/v4.14.1)
+## [v4.14.1](https://github.com/go-acme/lego/releases/tag/v4.14.1) (2023-09-20)
### Fixed
@@ -660,16 +381,11 @@ Canceled due to a release failure related to Snapcraft.
- **[dnsprovider]** bunny: use NRDCG fork
- **[dnsprovider]** ovh: update client to v1.4.2
-## v4.14.1
-
-- Release date: 2023-09-19
+## v4.14.1 (2023-09-19)
Cancelled due to CI failure.
-## v4.14.0
-
-- Release date: 2023-08-20
-- Tag: [v4.14.0](https://github.com/go-acme/lego/releases/tag/v4.14.0)
+## [v4.14.0](https://github.com/go-acme/lego/releases/tag/v4.14.0) (2023-08-20)
### Added
@@ -688,29 +404,20 @@ Cancelled due to CI failure.
- **[dnsprovider]** pdns: fix notify
- **[dnsprovider]** route53: avoid unexpected records deletion
-## v4.13.3
-
-- Release date: 2023-07-25
-- Tag: [v4.13.3](https://github.com/go-acme/lego/releases/tag/v4.13.3)
+## [v4.13.3](https://github.com/go-acme/lego/releases/tag/v4.13.3) (2023-07-25)
### Fixed
- **[dnsprovider]** azuredns: fix configuration from env vars
- **[dnsprovider]** gcore: change API domain
-## v4.13.2
-
-- Release date: 2023-07-21
-- Tag: [v4.13.2](https://github.com/go-acme/lego/releases/tag/v4.13.2)
+## [v4.13.2](https://github.com/go-acme/lego/releases/tag/v4.13.2) (2023-07-21)
### Fixed
- **[dnsprovider]** servercow: fix regression
-## v4.13.1
-
-- Release date: 2023-07-20
-- Tag: [v4.13.1](https://github.com/go-acme/lego/releases/tag/v4.13.1)
+## [v4.13.1](https://github.com/go-acme/lego/releases/tag/v4.13.1) (2023-07-20)
### Added
@@ -731,35 +438,24 @@ Cancelled due to CI failure.
- **[cli]** fix: list command
- **[lib]** fix: ARI explanationURL
-## v4.13.0
-
-- Release date: 2023-07-20
+## v4.13.0 (2023-07-20)
Cancelled due to a CI issue (no space left on device).
-## v4.12.2
-
-- Release date: 2023-06-19
-- Tag: [v4.12.2](https://github.com/go-acme/lego/releases/tag/v4.12.2)
+## [v4.12.2](https://github.com/go-acme/lego/releases/tag/v4.12.2) (2023-06-19)
### Fixed
- **[dnsprovider]** dnsmadeeasy: fix DeleteRecord
- **[lib]** fix: read status code from response
-## v4.12.1
-
-- Release date: 2023-06-06
-- Tag: [v4.12.1](https://github.com/go-acme/lego/releases/tag/v4.12.1)
+## [v4.12.1](https://github.com/go-acme/lego/releases/tag/v4.12.1) (2023-06-06)
### Fixed
- **[dnsprovider]** pdns: fix record value
-## v4.12.0
-
-- Release date: 2023-05-28
-- Tag: [v4.12.0](https://github.com/go-acme/lego/releases/tag/v4.12.0)
+## [v4.12.0](https://github.com/go-acme/lego/releases/tag/v4.12.0) (2023-05-28)
### Added
@@ -777,10 +473,7 @@ Cancelled due to a CI issue (no space left on device).
- **[dnsprovider]** autodns: fixes wrong zone in api call if CNAME is used
- **[cli]** fix: archive only domain-related files on revoke
-## v4.11.0
-
-- Release date: 2023-05-02
-- Tag: [v4.11.0](https://github.com/go-acme/lego/releases/tag/v4.11.0)
+## [v4.11.0](https://github.com/go-acme/lego/releases/tag/v4.11.0) (2023-05-02)
### Added
@@ -802,27 +495,18 @@ Cancelled due to a CI issue (no space left on device).
- **[dnsprovider]** rimuhosting: fix API base URL
-## v4.10.2
-
-- Release date: 2023-02-26
-- Tag: [v4.10.2](https://github.com/go-acme/lego/releases/tag/v4.10.2)
+## [v4.10.2](https://github.com/go-acme/lego/releases/tag/v4.10.2) (2023-02-26)
Fix Docker image builds.
-## v4.10.1
-
-- Release date: 2023-02-25
-- Tag: [v4.10.1](https://github.com/go-acme/lego/releases/tag/v4.10.1)
+## [v4.10.1](https://github.com/go-acme/lego/releases/tag/v4.10.1) (2023-02-25)
### Fixed
- **[dnsprovider,cname]** acmedns: fix CNAME support
- **[dnsprovider]** dynu: fix subdomain support
-## v4.10.0
-
-- Release date: 2023-02-10
-- Tag: [v4.10.0](https://github.com/go-acme/lego/releases/tag/v4.10.0)
+## [v4.10.0](https://github.com/go-acme/lego/releases/tag/v4.10.0) (2023-02-10)
### Added
@@ -848,10 +532,7 @@ Fix Docker image builds.
- **[dnsprovider]** pdns: fix usage of notify only when zone kind is Master or Slave
- **[dnsprovider]** return an error when extracting record name
-## v4.9.1
-
-- Release date: 2022-11-25
-- Tag: [v4.9.1](https://github.com/go-acme/lego/releases/tag/v4.9.1)
+## [v4.9.1](https://github.com/go-acme/lego/releases/tag/v4.9.1) (2022-11-25)
### Changed
@@ -866,10 +547,7 @@ Fix Docker image builds.
- **[dnsprovider]** hurricane: fix CNAME support
- **[lib,cname]** cname: stop trying to traverse cname if none have been found
-## v4.9.0
-
-- Release date: 2022-10-03
-- Tag: [v4.9.0](https://github.com/go-acme/lego/releases/tag/v4.9.0)
+## [v4.9.0](https://github.com/go-acme/lego/releases/tag/v4.9.0) (2022-10-03)
### Added
@@ -899,10 +577,7 @@ Fix Docker image builds.
- **[dnsprovider]** njalla: fix record id unmarshal error
- **[dnsprovider]** tencentcloud: fix subdomain error
-## v4.8.0
-
-- Release date: 2022-06-30
-- Tag: [v4.8.0](https://github.com/go-acme/lego/releases/tag/v4.8.0)
+## [v4.8.0](https://github.com/go-acme/lego/releases/tag/v4.8.0) (2022-06-30)
### Added
@@ -918,10 +593,7 @@ Fix Docker image builds.
- **[dnsprovider]** hetzner: set min TTL to 60s
- **[docs]** refactoring and cleanup
-## v4.7.0
-
-- Release date: 2022-05-27
-- Tag: [v4.7.0](https://github.com/go-acme/lego/releases/tag/v4.7.0)
+## [v4.7.0](https://github.com/go-acme/lego/releases/tag/v4.7.0) (2022-05-27)
### Added
@@ -943,10 +615,7 @@ Fix Docker image builds.
- **[dnsprovider]** tencentcloud: fix InvalidParameter.DomainInvalid error when using DNS challenges
- **[lib]** fix: panic in certcrypto.ParsePEMPrivateKey
-## v4.6.0
-
-- Release date: 2022-01-18
-- Tag: [v4.6.0](https://github.com/go-acme/lego/releases/tag/v4.6.0)
+## [v4.6.0](https://github.com/go-acme/lego/releases/tag/v4.6.0) (2022-01-18)
### Added
@@ -968,19 +637,13 @@ Fix Docker image builds.
- **[dnsprovider]** mythicbeasts: fix token expiration
- **[dnsprovider]** rackspace: change zone ID to string
-## v4.5.3
-
-- Release date: 2021-09-06
-- Tag: [v4.5.3](https://github.com/go-acme/lego/releases/tag/v4.5.3)
+## [v4.5.3](https://github.com/go-acme/lego/releases/tag/v4.5.3) (2021-09-06)
### Fixed
- **[lib,cli]** fix: missing preferred chain param for renew request
-## v4.5.2
-
-- Release date: 2021-09-01
-- Tag: [v4.5.2](https://github.com/go-acme/lego/releases/tag/v4.5.2)
+## [v4.5.2](https://github.com/go-acme/lego/releases/tag/v4.5.2) (2021-09-01)
### Added
@@ -1010,22 +673,15 @@ Fix Docker image builds.
- **[lib]** lib: use permanent error instead of context cancellation
- **[dnsprovider]** desec: bump to v0.6.0
-## v4.5.1
-
-- Release date: 2021-10-01
+## v4.5.1 (2021-09-01)
Cancelled due to a CI issue, replaced by v4.5.2.
-## v4.5.0
-
-- Release date: 2021-09-30
+## v4.5.0 (2021-09-30)
Cancelled due to a CI issue, replaced by v4.5.2.
-## v4.4.0
-
-- Release date: 2021-06-08
-- Tag: [v4.4.0](https://github.com/go-acme/lego/releases/tag/v4.4.0)
+## [v4.4.0](https://github.com/go-acme/lego/releases/tag/v4.4.0) (2021-06-08)
### Added
@@ -1053,19 +709,13 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** nifcloud: Get zone info from dns01.FindZoneByFqdn
- **[cli,lib]** csr: Support the type `NEW CERTIFICATE REQUEST`
-## v4.3.1
-
-- Release date: 2021-03-12
-- Tag: [v4.3.1](https://github.com/go-acme/lego/releases/tag/v4.3.1)
+## [v4.3.1](https://github.com/go-acme/lego/releases/tag/v4.3.1) (2021-03-12)
### Fixed
- **[dnsprovider]** exoscale: fix dependency version.
-## v4.3.0
-
-- Release date: 2021-03-10
-- Tag: [v4.3.0](https://github.com/go-acme/lego/releases/tag/v4.3.0)
+## [v4.3.0](https://github.com/go-acme/lego/releases/tag/v4.3.0) (2021-03-10)
### Added
@@ -1089,10 +739,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[lib]** Increase HTTP client timeouts
- **[lib]** preferred chain only match root name
-## v4.2.0
-
-- Release date: 2021-01-24
-- Tag: [v4.2.0](https://github.com/go-acme/lego/releases/tag/v4.2.0)
+## [v4.2.0](https://github.com/go-acme/lego/releases/tag/v4.2.0) (2021-01-24)
### Added
@@ -1112,38 +759,26 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** pdns: URL request creation.
- **[lib]** errors: Fix instance not being printed
-## v4.1.3
-
-- Release date: 2020-11-25
-- Tag: [v4.1.3](https://github.com/go-acme/lego/releases/tag/v4.1.3)
+## [v4.1.3](https://github.com/go-acme/lego/releases/tag/v4.1.3) (2020-11-25)
### Fixed
- **[dnsprovider]** azure: fix error handling.
-## v4.1.2
-
-- Release date: 2020-11-21
-- Tag: [v4.1.2](https://github.com/go-acme/lego/releases/tag/v4.1.2)
+## [v4.1.2](https://github.com/go-acme/lego/releases/tag/v4.1.2) (2020-11-21)
### Fixed
- **[lib]** fix: preferred chain support.
-## v4.1.1
-
-- Release date: 2020-11-19
-- Tag: [v4.1.1](https://github.com/go-acme/lego/releases/tag/v4.1.1)
+## [v4.1.1](https://github.com/go-acme/lego/releases/tag/v4.1.1) (2020-11-19)
### Fixed
- **[dnsprovider]** otc: select correct zone if multiple returned
- **[dnsprovider]** azure: fix target must be a non-nil pointer
-## v4.1.0
-
-- Release date: 2020-11-06
-- Tag: [v4.1.0](https://github.com/go-acme/lego/releases/tag/v4.1.0)
+## [v4.1.0](https://github.com/go-acme/lego/releases/tag/v4.1.0) (2020-11-06)
### Added
@@ -1161,19 +796,13 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[lib]** acme/api: use postAsGet instead of post for AccountService.Get
- **[lib]** fix: use http.Header.Set method instead of Add.
-## v4.0.1
-
-- Release date: 2020-09-03
-- Tag: [v4.0.1](https://github.com/go-acme/lego/releases/tag/v4.0.1)
+## [v4.0.1](https://github.com/go-acme/lego/releases/tag/v4.0.1) (2020-09-03)
### Fixed
- **[dnsprovider]** exoscale: change dependency version.
-## v4.0.0
-
-- Release date: 2020-09-02
-- Tag: [v4.0.0](https://github.com/go-acme/lego/releases/tag/v4.0.0)
+## [v4.0.0](https://github.com/go-acme/lego/releases/tag/v4.0.0) (2020-09-02)
### Added
@@ -1190,10 +819,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** Removes old Linode provider
- **[lib]** Removes `AddPreCheck` function
-## v3.9.0
-
-- Release date: 2020-09-01
-- Tag: [v3.9.0](https://github.com/go-acme/lego/releases/tag/v3.9.0)
+## [v3.9.0](https://github.com/go-acme/lego/releases/tag/v3.9.0) (2020-09-01)
### Added
@@ -1210,10 +836,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** namesilo: fix cleanup.
-## v3.8.0
-
-- Release date: 2020-07-02
-- Tag: [v3.8.0](https://github.com/go-acme/lego/releases/tag/v3.8.0)
+## [v3.8.0](https://github.com/go-acme/lego/releases/tag/v3.8.0) (2020-07-02)
### Added
@@ -1237,10 +860,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** hetzner: fix record name.
- **[lib]** Registrar.ResolveAccountByKey: Fix malformed request
-## v3.7.0
-
-- Release date: 2020-05-11
-- Tag: [v3.7.0](https://github.com/go-acme/lego/releases/tag/v3.7.0)
+## [v3.7.0](https://github.com/go-acme/lego/releases/tag/v3.7.0) (2020-05-11)
### Added
@@ -1263,10 +883,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[cli]** fix: renew path information.
- **[cli]** Fix account storage location warning message
-## v3.6.0
-
-- Release date: 2020-04-24
-- Tag: [v3.6.0](https://github.com/go-acme/lego/releases/tag/v3.6.0)
+## [v3.6.0](https://github.com/go-acme/lego/releases/tag/v3.6.0) (2020-04-24)
### Added
@@ -1290,10 +907,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** ns1: fix missing domain in log
- **[dnsprovider]** rimuhosting: use HTTP client from config.
-## v3.5.0
-
-- Release date: 2020-03-15
-- Tag: [v3.5.0](https://github.com/go-acme/lego/releases/tag/v3.5.0)
+## [v3.5.0](https://github.com/go-acme/lego/releases/tag/v3.5.0) (2020-03-15)
### Added
@@ -1316,10 +930,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** gcloud: fixes issues when used with GKE Workload Identity
- **[dnsprovider]** oraclecloud: fix subdomain support
-## v3.4.0
-
-- Release date: 2020-02-25
-- Tag: [v3.4.0](https://github.com/go-acme/lego/releases/tag/v3.4.0)
+## [v3.4.0](https://github.com/go-acme/lego/releases/tag/v3.4.0) (2020-02-25)
### Added
@@ -1344,10 +955,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[lib]** crypto: Treat CommonName as optional
- **[lib]** chore: update cenkalti/backoff to v4.
-## v3.3.0
-
-- Release date: 2020-01-08
-- Tag: [v3.3.0](https://github.com/go-acme/lego/releases/tag/v3.3.0)
+## [v3.3.0](https://github.com/go-acme/lego/releases/tag/v3.3.0) (2020-01-08)
### Added
@@ -1363,10 +971,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** Update dnspod, because of API breaking changes.
-## v3.2.0
-
-- Release date: 2019-11-10
-- Tag: [v3.2.0](https://github.com/go-acme/lego/releases/tag/v3.2.0)
+## [v3.2.0](https://github.com/go-acme/lego/releases/tag/v3.2.0) (2019-11-10)
### Added
@@ -1382,10 +987,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** use token as unique ID.
-## v3.1.0
-
-- Release date: 2019-10-07
-- Tag: [v3.1.0](https://github.com/go-acme/lego/releases/tag/v3.1.0)
+## [v3.1.0](https://github.com/go-acme/lego/releases/tag/v3.1.0) (2019-10-07)
### Added
@@ -1403,54 +1005,36 @@ Cancelled due to a CI issue, replaced by v4.5.2.
- **[dnsprovider]** ovh: fix int overflow.
- **[dnsprovider]** bindman: fix client version.
-## v3.0.2
-
-- Release date: 2019-08-15
-- Tag: [v3.0.2](https://github.com/go-acme/lego/releases/tag/v3.0.2)
+## [v3.0.2](https://github.com/go-acme/lego/releases/tag/v3.0.2) (2019-08-15)
### Fixed
- Invalid pseudo version (related to Cloudflare client).
-## v3.0.1
-
-- Release date: 2019-08-14
-- Tag: [v3.0.1](https://github.com/go-acme/lego/releases/tag/v3.0.1)
+## [v3.0.1](https://github.com/go-acme/lego/releases/tag/v3.0.1) (2019-08-14)
There was a problem when creating the tag v3.0.1, this tag has been invalidated.
-## v3.0.0
-
-- Release date: 2019-08-05
-- Tag: [v3.0.0](https://github.com/go-acme/lego/releases/tag/v3.0.0)
+## [v3.0.0](https://github.com/go-acme/lego/releases/tag/v3.0.0) (2019-08-05)
### Changed
- migrate to go module (new import github.com/go-acme/lego/v3/)
- update DNS clients
-## v2.7.2
-
-- Release date: 2019-07-30
-- Tag: [v2.7.2](https://github.com/go-acme/lego/releases/tag/v2.7.2)
+## [v2.7.2](https://github.com/go-acme/lego/releases/tag/v2.7.2) (2019-07-30)
### Fixed
- **[dnsprovider]** vultr: quote TXT record
-## v2.7.1
-
-- Release date: 2019-07-22
-- Tag: [v2.7.1](https://github.com/go-acme/lego/releases/tag/v2.7.1)
+## [v2.7.1](https://github.com/go-acme/lego/releases/tag/v2.7.1) (2019-07-22)
### Fixed
- **[dnsprovider]** vultr: invalid record type.
-## v2.7.0
-
-- Release date: 2019-07-17
-- Tag: [v2.7.0](https://github.com/go-acme/lego/releases/tag/v2.7.0)
+## [v2.7.0](https://github.com/go-acme/lego/releases/tag/v2.7.0) (2019-07-17)
### Added
@@ -1467,10 +1051,7 @@ There was a problem when creating the tag v3.0.1, this tag has been invalidated.
- **[dnsprovider]** otc: Prevent sending empty body.
-## v2.6.0
-
-- Release date: 2019-05-27
-- Tag: [v2.6.0](https://github.com/go-acme/lego/releases/tag/v2.6.0)
+## [v2.6.0](https://github.com/go-acme/lego/releases/tag/v2.6.0) (2019-05-27)
### Added
@@ -1492,10 +1073,7 @@ There was a problem when creating the tag v3.0.1, this tag has been invalidated.
- **[cli]** fix: cli disable-cp option.
- **[dnsprovider]** gcloud: fix zone visibility.
-## v2.5.0
-
-- Release date: 2019-04-17
-- Tag: [v2.5.0](https://github.com/go-acme/lego/releases/tag/v2.5.0)
+## [v2.5.0](https://github.com/go-acme/lego/releases/tag/v2.5.0) (2019-04-17)
### Added
@@ -1514,12 +1092,9 @@ There was a problem when creating the tag v3.0.1, this tag has been invalidated.
- **[dnsprovider]** Disable authz when solve fail.
- Add tzdata to the Docker image.
-## v2.4.0
+## [v2.4.0](https://github.com/go-acme/lego/releases/tag/v2.4.0) (2019-03-25)
-- Release date: 2019-03-25
-- Tag: [v2.4.0](https://github.com/go-acme/lego/releases/tag/v2.4.0)
-
-Migrate from xenolf/lego to go-acme/lego.
+- Migrate from xenolf/lego to go-acme/lego.
### Added
@@ -1532,10 +1107,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[dnsprovider]** hostingde: Use provided ZoneName instead of domain
- **[dnsprovider]** pdns: fix wildcard with SANs
-## v2.3.0
-
-- Release date: 2019-03-11
-- Tag: [v2.3.0](https://github.com/go-acme/lego/releases/tag/v2.3.0)
+## [v2.3.0](https://github.com/go-acme/lego/releases/tag/v2.3.0) (2019-03-11)
### Added
@@ -1559,10 +1131,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[dnsprovider]** vscale: fix TXT records clean up
- **[dnsprovider]** selectel: fix TXT records clean up
-## v2.2.0
-
-- Release date: 2019-02-08
-- Tag: [v2.2.0](https://github.com/go-acme/lego/releases/tag/v2.2.0)
+## [v2.2.0](https://github.com/go-acme/lego/releases/tag/v2.2.0) (2019-02-08)
### Added
@@ -1582,10 +1151,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[dnsprovider]** fastdns: Do not overwrite existing TXT records
- Log wildcard domain correctly in validation
-## v2.1.0
-
-- Release date: 2019-01-24
-- Tag: [v2.1.0](https://github.com/go-acme/lego/releases/tag/v2.1.0)
+## [v2.1.0](https://github.com/go-acme/lego/releases/tag/v2.1.0) (2019-01-24)
### Added
@@ -1602,10 +1168,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[dnsprovider]** alicloud: fix pagination.
- **[dnsprovider]** namecheap: fix panic.
-## v2.0.0
-
-- Release date: 2019-01-09
-- Tag: [v2.0.0](https://github.com/go-acme/lego/releases/tag/v2.0.0)
+## [v2.0.0](https://github.com/go-acme/lego/releases/tag/v2.0.0) (2019-01-09)
### Added
@@ -1657,10 +1220,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[dnsprovider]** Azure: Do not overwrite existing TXT records
- **[dnsprovider]** fix: Cloudflare error.
-## v1.2.0
-
-- Release date: 2018-11-04
-- Tag: [v1.2.0](https://github.com/go-acme/lego/releases/tag/v1.2.0)
+## [v1.2.0](https://github.com/go-acme/lego/releases/tag/v1.2.0) (2018-11-04)
### Added
@@ -1681,10 +1241,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[lib]** Do not send a JWS body when POSTing challenges.
- **[lib]** Support POST-as-GET.
-## v1.1.0
-
-- Release date: 2018-10-16
-- Tag: [v1.1.0](https://github.com/go-acme/lego/releases/tag/v1.1.0)
+## [v1.1.0](https://github.com/go-acme/lego/releases/tag/v1.1.0) (2018-10-16)
### Added
@@ -1720,10 +1277,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[lib]** Submit all dns records up front, then validate serially
-## v1.0.0
-
-- Release date: 2018-05-30
-- Tag: [v1.0.0](https://github.com/go-acme/lego/releases/tag/v1.0.0)
+## [v1.0.0](https://github.com/go-acme/lego/releases/tag/v1.0.0) (2018-05-30)
### Changed
@@ -1732,10 +1286,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[dnsprovider]** Modified Google Cloud provider `gcloud.NewDNSProviderServiceAccount` function to extract the project id directly from the service account file.
- **[dnsprovider]** Made errors more verbose for the Cloudflare provider.
-## v0.5.0
-
-- Release date: 2018-05-29
-- Tag: [v0.5.0](https://github.com/go-acme/lego/releases/tag/v0.5.0)
+## [v0.5.0](https://github.com/go-acme/lego/releases/tag/v0.5.0) (2018-05-29)
### Added
@@ -1769,10 +1320,7 @@ Migrate from xenolf/lego to go-acme/lego.
- **[dnsprovider]** Exoscale: update to latest egoscale version.
- **[dnsprovider]** Route53: Use NewSessionWithOptions instead of deprecated New.
-## 0.4.1
-
-- Release date: 2017-09-26
-- Tag: [0.4.1](https://github.com/go-acme/lego/releases/tag/0.4.1)
+## [0.4.1](https://github.com/go-acme/lego/releases/tag/0.4.1) (2017-09-26)
### Added
@@ -1785,10 +1333,7 @@ Migrate from xenolf/lego to go-acme/lego.
- lib: Fixed an authentication issue with the latest Azure SDK.
-## 0.4.0
-
-- Release date: 2017-07-13
-- Tag: [0.4.0](https://github.com/go-acme/lego/releases/tag/0.4.0)
+## [0.4.0](https://github.com/go-acme/lego/releases/tag/0.4.0) (2017-07-13)
### Added
@@ -1841,10 +1386,7 @@ Migrate from xenolf/lego to go-acme/lego.
- lib: Fixed a condition where we could stall due to an early error condition.
- lib: Fixed an issue where Authz object could end up in an active state after an error condition.
-## 0.3.1
-
-- Release date: 2016-04-19
-- Tag: [0.3.1](https://github.com/go-acme/lego/releases/tag/0.3.1)
+## [0.3.1](https://github.com/go-acme/lego/releases/tag/0.3.1) (2016-04-19)
### Added
@@ -1856,10 +1398,7 @@ Migrate from xenolf/lego to go-acme/lego.
- lib: handleHTTPError should only try to JSON decode error messages with the right content type.
- lib: The propagation checker for the DNS challenge would not retry on send errors.
-## 0.3.0
-
-- Release date: 2016-03-19
-- Tag: [0.3.0](https://github.com/go-acme/lego/releases/tag/0.3.0)
+## [0.3.0](https://github.com/go-acme/lego/releases/tag/0.3.0) (2016-03-19)
### Added
@@ -1894,10 +1433,7 @@ Migrate from xenolf/lego to go-acme/lego.
- lib: Fixed an issue where status codes on ACME challenge responses could lead to no action being taken.
- lib: Fixed a regression when calling the Renew function with a SAN certificate.
-## 0.2.0
-
-- Release date: 2016-01-09
-- Tag: [0.2.0](https://github.com/go-acme/lego/releases/tag/0.2.0)
+## [0.2.0](https://github.com/go-acme/lego/releases/tag/0.2.0) (2016-01-09)
### Added
@@ -1927,10 +1463,7 @@ Migrate from xenolf/lego to go-acme/lego.
- CLI: Fix logic using the `--days` parameter for renew
-## 0.1.1
-
-- Release date: 2015-12-18
-- Tag: [0.1.1](https://github.com/go-acme/lego/releases/tag/0.1.1)
+## [0.1.1](https://github.com/go-acme/lego/releases/tag/0.1.1) (2015-12-18)
### Added
@@ -1950,9 +1483,6 @@ Migrate from xenolf/lego to go-acme/lego.
- lib: Fix possible DOS on GetOCSPForCert
-## 0.1.0
+## [0.1.0](https://github.com/go-acme/lego/releases/tag/0.1.0) (2015-12-03)
-- Release date: 2015-12-03
-- Tag: [0.1.0](https://github.com/go-acme/lego/releases/tag/0.1.0)
-
-Initial release
+- Initial release
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 05e4fa994..a0005cff8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,7 +10,7 @@ To ensure a great and easy experience for everyone, please review the few guidel
- If both of the above do not apply, create a new issue and include as much information as possible.
Bug reports should include all information a person could need to reproduce your problem without the need to
-follow up for more information. If possible, provide detailed steps for us to reproduce it, the expected behavior and the actual behavior.
+follow up for more information. If possible, provide detailed steps for us to reproduce it, the expected behaviour and the actual behaviour.
## Feature proposals and requests
@@ -20,26 +20,31 @@ It is up to you to make a strong point about your proposal and convince us of th
## Pull requests
-Create an issue and wait for a maintainer to approve it BEFORE opening a pull request.
-
Patches, new features and improvements are a great way to help the project.
Please keep them focused on one thing and do not include unrelated commits.
-All pull requests that alter the behavior of the program,
-add new behavior or somehow alter code in a non-trivial way should **always** include tests.
+All pull requests which alter the behaviour of the program, add new behaviour or somehow alter code in a non-trivial way should **always** include tests.
-**IMPORTANT**: By submitting a patch, you agree to allow the project owners to license your work under the terms of the [MIT License](LICENSE).
+If you want to contribute a significant pull request (with a non-trivial workload for you) please **ask first**. We do not want you to spend
+a lot of time on something the project's developers might not want to merge into the project.
+
+**IMPORTANT**: By submitting a patch, you agree to allow the project
+owners to license your work under the terms of the [MIT License](LICENSE).
### How to create a pull request
Requirements:
-- `go` v1.24+
+- `go` v1.15+
- environment variable: `GO111MODULE=on`
First, you have to install [GoLang](https://golang.org/doc/install) and [golangci-lint](https://github.com/golangci/golangci-lint#install).
```bash
+# Create the root folder
+mkdir -p $GOPATH/src/github.com/go-acme
+cd $GOPATH/src/github.com/go-acme
+
# clone your fork
git clone git@github.com:YOUR_USERNAME/lego.git
cd lego
@@ -51,12 +56,14 @@ git fetch upstream
```bash
# Create your branch
-git switch -c my-feature
+git checkout -b my-feature
## Create your code ##
```
```bash
+# Format
+make fmt
# Linters
make checks
# Tests
diff --git a/Makefile b/Makefile
index 8536dfc40..28cb33908 100644
--- a/Makefile
+++ b/Makefile
@@ -54,10 +54,10 @@ detach:
.PHONY: docs-build docs-serve docs-themes
docs-build: generate-dns
- @make -C ./docs build
+ @make -C ./docs hugo-build
docs-serve: generate-dns
- @make -C ./docs serve
+ @make -C ./docs hugo
docs-themes:
@make -C ./docs hugo-themes
diff --git a/README.md b/README.md
index e90e94962..59b62a8de 100644
--- a/README.md
+++ b/README.md
@@ -5,26 +5,20 @@
# Lego
-[ACME](https://www.rfc-editor.org/rfc/rfc8555.html) client and library for Let's Encrypt and other ACME CAs written in Go.
+Let's Encrypt client and ACME library written in Go.
[](https://pkg.go.dev/github.com/go-acme/lego/v4)
[](https://github.com//go-acme/lego/actions)
[](https://hub.docker.com/r/goacme/lego/)
-lego is an independent, free, and open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
-
-Everybody thinks that the others will donate, but in the end, nobody does.
-
-So if you think that lego is worth it, please consider [donating](https://donate.ldez.dev).
-
## Features
- ACME v2 [RFC 8555](https://www.rfc-editor.org/rfc/rfc8555.html)
- Support [RFC 8737](https://www.rfc-editor.org/rfc/rfc8737.html): TLS Application‑Layer Protocol Negotiation (ALPN) Challenge Extension
- Support [RFC 8738](https://www.rfc-editor.org/rfc/rfc8738.html): certificates for IP addresses
- Support [RFC 9773](https://www.rfc-editor.org/rfc/rfc9773.html): Renewal Information (ARI) Extension
- - Support [draft-ietf-acme-profiles-00](https://datatracker.ietf.org/doc/draft-ietf-acme-profiles/): Profiles Extension
-- Comes with about [180 DNS providers](https://go-acme.github.io/lego/dns)
+ - Support [draft-aaron-acme-profiles-00](https://datatracker.ietf.org/doc/draft-aaron-acme-profiles/): Profiles Extension
+- Comes with about [150 DNS providers](https://go-acme.github.io/lego/dns)
- Register with CA
- Obtain certificates, both from scratch or with an existing CSR
- Renew certificates
@@ -56,72 +50,55 @@ Documentation is hosted live at https://go-acme.github.io/lego/.
Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
-If your DNS provider is not supported, please open an [issue](https://github.com/go-acme/lego/issues/new?assignees=&labels=enhancement%2C+new-provider&template=new_dns_provider.yml).
-
- | 35.com/三五互联 |
Active24 |
Akamai EdgeDNS |
Alibaba Cloud DNS |
-
- | AlibabaCloud ESA |
all-inkl |
- Alwaysdata |
+
| Amazon Lightsail |
-
| Amazon Route 53 |
- Anexia CloudDNS |
- ANS SafeDNS |
- ArtFiles |
-
| ArvanCloud |
Aurora DNS |
+
| Autodns |
Axelname |
-
| Azion |
Azure (deprecated) |
+
| Azure DNS |
Baidu Cloud |
-
- | Beget.com |
- Binary Lane |
Bindman |
Bluecat |
- | Bluecat v2 |
BookMyName |
Brandit (deprecated) |
Bunny |
-
| Checkdomain |
+
| Civo |
Cloud.ru |
CloudDNS |
-
| Cloudflare |
+
| ClouDNS |
CloudXNS (Deprecated) |
ConoHa v2 |
-
| ConoHa v3 |
+
| Constellix |
Core-Networks |
CPanel/WHM |
-
- | Czechia |
- DDnss (DynDNS Service) |
Derak Cloud |
- deSEC.io |
+ | deSEC.io |
Designate DNSaaS for Openstack |
Digital Ocean |
DirectAdmin |
- DNS Made Easy |
- | DNSExit |
+ DNS Made Easy |
dnsHome.de |
DNSimple |
DNSPod (deprecated) |
@@ -136,34 +113,24 @@ If your DNS provider is not supported, please open an [issue](https://github.com
Dynu |
EasyDNS |
- | EdgeCenter |
Efficient IP |
Epik |
- EuroDNS |
-
- | Excedo |
Exoscale |
External program |
- F5 XC |
+ | F5 XC |
freemyip.com |
- FusionLayer NameSurfer |
G-Core |
Gandi |
| Gandi Live DNS (v5) |
- Gigahost.no |
Glesys |
Go Daddy |
-
| Google Cloud |
- Google Domains |
- Gravity |
- Hetzner |
+ | Google Domains |
+ Hetzner |
Hosting.de |
- Hosting.nl |
- Hostinger |
Hosttech |
| HTTP request |
@@ -182,54 +149,44 @@ If your DNS provider is not supported, please open an [issue](https://github.com
INWX |
| Ionos |
- Ionos Cloud |
IPv64 |
- ISPConfig 3 |
-
- | ISPConfig 3 - Dynamic DNS (DDNS) Module |
- iwantmyname (Deprecated) |
- JD Cloud |
+ iwantmyname |
Joker |
| Joohoi's ACME-DNS |
- KeyHelp |
- Leaseweb |
Liara |
-
| Lima-City |
Linode (v4) |
+
| Liquid Web |
Loopia |
-
| LuaDNS |
Mail-in-a-Box |
+
| ManageEngine CloudDNS |
Manual |
-
| Metaname |
Metaregistrar |
+
| mijn.host |
Mittwald |
-
| myaddr.{tools,dev,io} |
MyDNS.jp |
+
| MythicBeasts |
Name.com |
-
| Namecheap |
Namesilo |
- NearlyFreeSpeech.NET |
- Neodigit |
+ | NearlyFreeSpeech.NET |
Netcup |
Netlify |
Nicmanager |
- NIFCloud |
+ | NIFCloud |
Njalla |
Nodion |
NS1 |
- Octenium |
| Open Telekom Cloud |
Oracle Cloud |
@@ -262,44 +219,39 @@ If your DNS provider is not supported, please open an [issue](https://github.com
Spaceship |
| Stackpath |
- Syse |
Technitium |
Tencent Cloud DNS |
-
- | Tencent EdgeOne |
Timeweb Cloud |
- TodayNIC/时代互联 |
+
| TransIP |
-
+ | UKFast SafeDNS |
Ultradns |
- United-Domains |
Variomedia |
- VegaDNS |
+ | VegaDNS |
Vercel |
Versio.[nl|eu|uk] |
VinylDNS |
- Virtualname |
| VK Cloud |
Volcano Engine/火山引擎 |
Vscale |
Vultr |
- | webnames.ca |
- webnames.ru |
+ Webnames |
Websupport |
WEDOS |
-
| West.cn/西部数码 |
+
| Yandex 360 |
Yandex Cloud |
Yandex PDD |
-
| Zone.ee |
+
| ZoneEdit |
Zonomi |
|
+ |
diff --git a/acme/api/account.go b/acme/api/account.go
index 62e5ef9a6..85de84ef3 100644
--- a/acme/api/account.go
+++ b/acme/api/account.go
@@ -13,7 +13,6 @@ type AccountService service
// New Creates a new account.
func (a *AccountService) New(req acme.Account) (acme.ExtendedAccount, error) {
var account acme.Account
-
resp, err := a.core.post(a.core.GetDirectory().NewAccountURL, req, &account)
location := getLocation(resp)
@@ -30,9 +29,9 @@ func (a *AccountService) New(req acme.Account) (acme.ExtendedAccount, error) {
// NewEAB Creates a new account with an External Account Binding.
func (a *AccountService) NewEAB(accMsg acme.Account, kid, hmacEncoded string) (acme.ExtendedAccount, error) {
- hmac, err := decodeEABHmac(hmacEncoded)
+ hmac, err := base64.RawURLEncoding.DecodeString(hmacEncoded)
if err != nil {
- return acme.ExtendedAccount{}, err
+ return acme.ExtendedAccount{}, fmt.Errorf("acme: could not decode hmac key: %w", err)
}
eabJWS, err := a.core.signEABContent(a.core.GetDirectory().NewAccountURL, kid, hmac)
@@ -52,12 +51,10 @@ func (a *AccountService) Get(accountURL string) (acme.Account, error) {
}
var account acme.Account
-
_, err := a.core.postAsGet(accountURL, &account)
if err != nil {
return acme.Account{}, err
}
-
return account, nil
}
@@ -68,7 +65,6 @@ func (a *AccountService) Update(accountURL string, req acme.Account) (acme.Accou
}
var account acme.Account
-
_, err := a.core.post(accountURL, req, &account)
if err != nil {
return acme.Account{}, err
@@ -85,20 +81,5 @@ func (a *AccountService) Deactivate(accountURL string) error {
req := acme.Account{Status: acme.StatusDeactivated}
_, err := a.core.post(accountURL, req, nil)
-
return err
}
-
-func decodeEABHmac(hmacEncoded string) ([]byte, error) {
- hmac, errRaw := base64.RawURLEncoding.DecodeString(hmacEncoded)
- if errRaw == nil {
- return hmac, nil
- }
-
- hmac, err := base64.URLEncoding.DecodeString(hmacEncoded)
- if err == nil {
- return hmac, nil
- }
-
- return nil, fmt.Errorf("acme: could not decode hmac key: %w", errors.Join(errRaw, err))
-}
diff --git a/acme/api/account_test.go b/acme/api/account_test.go
deleted file mode 100644
index 16bd80741..000000000
--- a/acme/api/account_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package api
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func Test_decodeEABHmac(t *testing.T) {
- testCases := []struct {
- desc string
- hmac string
- }{
- {
- desc: "RawURLEncoding",
- hmac: "BAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHx",
- },
- {
- desc: "URLEncoding",
- hmac: "nKTo9Hu8fpCqWPXx-25LVbZrJWxcHISsr4qHrRR0j5U=",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- v, err := decodeEABHmac(test.hmac)
- require.NoError(t, err)
-
- assert.NotEmpty(t, v)
- })
- }
-}
diff --git a/acme/api/api.go b/acme/api/api.go
index da1c94d1b..a4e6398ea 100644
--- a/acme/api/api.go
+++ b/acme/api/api.go
@@ -2,7 +2,6 @@ package api
import (
"bytes"
- "context"
"crypto"
"encoding/json"
"errors"
@@ -10,7 +9,7 @@ import (
"net/http"
"time"
- "github.com/cenkalti/backoff/v5"
+ "github.com/cenkalti/backoff/v4"
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/acme/api/internal/nonces"
"github.com/go-acme/lego/v4/acme/api/internal/secure"
@@ -77,36 +76,39 @@ func (a *Core) postAsGet(uri string, response any) (*http.Response, error) {
}
func (a *Core) retrievablePost(uri string, content []byte, response any) (*http.Response, error) {
- ctx := context.Background()
-
// during tests, allow to support ~90% of bad nonce with a minimum of attempts.
bo := backoff.NewExponentialBackOff()
bo.InitialInterval = 200 * time.Millisecond
bo.MaxInterval = 5 * time.Second
+ bo.MaxElapsedTime = 20 * time.Second
- operation := func() (*http.Response, error) {
- resp, err := a.signedPost(uri, content, response)
+ var resp *http.Response
+ operation := func() error {
+ var err error
+ resp, err = a.signedPost(uri, content, response)
if err != nil {
// Retry if the nonce was invalidated
var e *acme.NonceError
if errors.As(err, &e) {
- return resp, err
+ return err
}
- return resp, backoff.Permanent(err)
+ return backoff.Permanent(err)
}
- return resp, nil
+ return nil
}
notify := func(err error, duration time.Duration) {
log.Infof("retry due to: %v", err)
}
- return backoff.Retry(ctx, operation,
- backoff.WithBackOff(bo),
- backoff.WithMaxElapsedTime(20*time.Second),
- backoff.WithNotify(notify))
+ err := backoff.RetryNotify(operation, bo, notify)
+ if err != nil {
+ return resp, err
+ }
+
+ return resp, nil
}
func (a *Core) signedPost(uri string, content []byte, response any) (*http.Response, error) {
@@ -155,7 +157,6 @@ func getDirectory(do *sender.Doer, caDirURL string) (acme.Directory, error) {
if dir.NewAccountURL == "" {
return dir, errors.New("directory missing new registration URL")
}
-
if dir.NewOrderURL == "" {
return dir, errors.New("directory missing new order URL")
}
diff --git a/acme/api/authorization.go b/acme/api/authorization.go
index 4195bd1fe..a9972aa94 100644
--- a/acme/api/authorization.go
+++ b/acme/api/authorization.go
@@ -15,12 +15,10 @@ func (c *AuthorizationService) Get(authzURL string) (acme.Authorization, error)
}
var authz acme.Authorization
-
_, err := c.core.postAsGet(authzURL, &authz)
if err != nil {
return acme.Authorization{}, err
}
-
return authz, nil
}
@@ -31,8 +29,6 @@ func (c *AuthorizationService) Deactivate(authzURL string) error {
}
var disabledAuth acme.Authorization
-
_, err := c.core.post(authzURL, acme.Authorization{Status: acme.StatusDeactivated}, &disabledAuth)
-
return err
}
diff --git a/acme/api/certificate.go b/acme/api/certificate.go
index b42296768..5f31968cf 100644
--- a/acme/api/certificate.go
+++ b/acme/api/certificate.go
@@ -2,12 +2,15 @@ package api
import (
"bytes"
+ "crypto/x509"
"encoding/pem"
"errors"
"io"
"net/http"
"github.com/go-acme/lego/v4/acme"
+ "github.com/go-acme/lego/v4/certcrypto"
+ "github.com/go-acme/lego/v4/log"
)
// maxBodySize is the maximum size of body that we will read.
@@ -74,22 +77,62 @@ func (c *CertificateService) get(certURL string, bundle bool) (*acme.RawCertific
return nil, resp.Header, err
}
- cert := c.getCertificateChain(data, bundle)
+ cert := c.getCertificateChain(data, resp.Header, bundle, certURL)
return cert, resp.Header, err
}
// getCertificateChain Returns the certificate and the issuer certificate.
-func (c *CertificateService) getCertificateChain(cert []byte, bundle bool) *acme.RawCertificate {
+func (c *CertificateService) getCertificateChain(cert []byte, headers http.Header, bundle bool, certURL string) *acme.RawCertificate {
// Get issuerCert from bundled response from Let's Encrypt
// See https://community.letsencrypt.org/t/acme-v2-no-up-link-in-response/64962
_, issuer := pem.Decode(cert)
+ if issuer != nil {
+ // If bundle is false, we want to return a single certificate.
+ // To do this, we remove the issuer cert(s) from the issued cert.
+ if !bundle {
+ cert = bytes.TrimSuffix(cert, issuer)
+ }
+ return &acme.RawCertificate{Cert: cert, Issuer: issuer}
+ }
- // If bundle is false, we want to return a single certificate.
- // To do this, we remove the issuer cert(s) from the issued cert.
- if !bundle {
- cert = bytes.TrimSuffix(cert, issuer)
+ // The issuer certificate link may be supplied via an "up" link
+ // in the response headers of a new certificate.
+ // See https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4.2
+ up := getLink(headers, "up")
+
+ issuer, err := c.getIssuerFromLink(up)
+ if err != nil {
+ // If we fail to acquire the issuer cert, return the issued certificate - do not fail.
+ log.Warnf("acme: Could not bundle issuer certificate [%s]: %v", certURL, err)
+ } else if len(issuer) > 0 {
+ // If bundle is true, we want to return a certificate bundle.
+ // To do this, we append the issuer cert to the issued cert.
+ if bundle {
+ cert = append(cert, issuer...)
+ }
}
return &acme.RawCertificate{Cert: cert, Issuer: issuer}
}
+
+// getIssuerFromLink requests the issuer certificate.
+func (c *CertificateService) getIssuerFromLink(up string) ([]byte, error) {
+ if up == "" {
+ return nil, nil
+ }
+
+ log.Infof("acme: Requesting issuer cert from %s", up)
+
+ cert, _, err := c.get(up, false)
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = x509.ParseCertificate(cert.Cert)
+ if err != nil {
+ return nil, err
+ }
+
+ return certcrypto.PEMEncode(certcrypto.DERCertificateBytes(cert.Cert)), nil
+}
diff --git a/acme/api/certificate_test.go b/acme/api/certificate_test.go
index 7220ca1b9..9776cccc5 100644
--- a/acme/api/certificate_test.go
+++ b/acme/api/certificate_test.go
@@ -3,10 +3,11 @@ package api
import (
"crypto/rand"
"crypto/rsa"
+ "encoding/pem"
+ "net/http"
"testing"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -73,34 +74,56 @@ rzFL1KZfz+HZdnFwFW2T2gVW8L3ii1l9AJDuKzlvjUH3p6bgihVq02sjT8mx+GM2
`
func TestCertificateService_Get_issuerRelUp(t *testing.T) {
- server := tester.MockACMEServer().
- Route("POST /certificate", servermock.RawStringResponse(certResponseMock)).
- BuildHTTPS(t)
+ mux, apiURL := tester.SetupFakeAPI(t)
+
+ mux.HandleFunc("/certificate", func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Link", "<"+apiURL+`/issuer>; rel="up"`)
+ _, err := w.Write([]byte(certResponseMock))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
+
+ mux.HandleFunc("/issuer", func(w http.ResponseWriter, _ *http.Request) {
+ p, _ := pem.Decode([]byte(issuerMock))
+ _, err := w.Write(p.Bytes)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
- core, err := New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
- cert, issuer, err := core.Certificates.Get(server.URL+"/certificate", true)
+ cert, issuer, err := core.Certificates.Get(apiURL+"/certificate", true)
require.NoError(t, err)
assert.Equal(t, certResponseMock, string(cert), "Certificate")
assert.Equal(t, issuerMock, string(issuer), "IssuerCertificate")
}
func TestCertificateService_Get_embeddedIssuer(t *testing.T) {
- server := tester.MockACMEServer().
- Route("POST /certificate", servermock.RawStringResponse(certResponseMock)).
- BuildHTTPS(t)
+ mux, apiURL := tester.SetupFakeAPI(t)
+
+ mux.HandleFunc("/certificate", func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(certResponseMock))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
- core, err := New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
- cert, issuer, err := core.Certificates.Get(server.URL+"/certificate", true)
+ cert, issuer, err := core.Certificates.Get(apiURL+"/certificate", true)
require.NoError(t, err)
assert.Equal(t, certResponseMock, string(cert), "Certificate")
assert.Equal(t, issuerMock, string(issuer), "IssuerCertificate")
diff --git a/acme/api/challenge.go b/acme/api/challenge.go
index 2af55fc1a..875dede6e 100644
--- a/acme/api/challenge.go
+++ b/acme/api/challenge.go
@@ -17,7 +17,6 @@ func (c *ChallengeService) New(chlgURL string) (acme.ExtendedChallenge, error) {
// Challenge initiation is done by sending a JWS payload containing the trivial JSON object `{}`.
// We use an empty struct instance as the postJSON payload here to achieve this result.
var chlng acme.ExtendedChallenge
-
resp, err := c.core.post(chlgURL, struct{}{}, &chlng)
if err != nil {
return acme.ExtendedChallenge{}, err
@@ -25,7 +24,6 @@ func (c *ChallengeService) New(chlgURL string) (acme.ExtendedChallenge, error) {
chlng.AuthorizationURL = getLink(resp.Header, "up")
chlng.RetryAfter = getRetryAfter(resp)
-
return chlng, nil
}
@@ -36,7 +34,6 @@ func (c *ChallengeService) Get(chlgURL string) (acme.ExtendedChallenge, error) {
}
var chlng acme.ExtendedChallenge
-
resp, err := c.core.postAsGet(chlgURL, &chlng)
if err != nil {
return acme.ExtendedChallenge{}, err
@@ -44,6 +41,5 @@ func (c *ChallengeService) Get(chlgURL string) (acme.ExtendedChallenge, error) {
chlng.AuthorizationURL = getLink(resp.Header, "up")
chlng.RetryAfter = getRetryAfter(resp)
-
return chlng, nil
}
diff --git a/acme/api/identifier.go b/acme/api/identifier.go
index 245ed8515..27337ccba 100644
--- a/acme/api/identifier.go
+++ b/acme/api/identifier.go
@@ -2,36 +2,11 @@ package api
import (
"cmp"
- "net"
"slices"
"github.com/go-acme/lego/v4/acme"
)
-func createIdentifiers(domains []string) []acme.Identifier {
- uniqIdentifiers := make(map[string]struct{})
-
- var identifiers []acme.Identifier
-
- for _, domain := range domains {
- if _, ok := uniqIdentifiers[domain]; ok {
- continue
- }
-
- ident := acme.Identifier{Value: domain, Type: "dns"}
-
- if net.ParseIP(domain) != nil {
- ident.Type = "ip"
- }
-
- identifiers = append(identifiers, ident)
-
- uniqIdentifiers[domain] = struct{}{}
- }
-
- return identifiers
-}
-
// compareIdentifiers compares 2 slices of [acme.Identifier].
func compareIdentifiers(a, b []acme.Identifier) int {
// Clones slices to avoid modifying original slices.
diff --git a/acme/api/internal/nonces/nonce_manager.go b/acme/api/internal/nonces/nonce_manager.go
index 04a4ac620..d089cf07c 100644
--- a/acme/api/internal/nonces/nonce_manager.go
+++ b/acme/api/internal/nonces/nonce_manager.go
@@ -11,11 +11,10 @@ import (
// Manager Manages nonces.
type Manager struct {
- sync.Mutex
-
do *sender.Doer
nonceURL string
nonces []string
+ sync.Mutex
}
// NewManager Creates a new Manager.
@@ -37,7 +36,6 @@ func (n *Manager) Pop() (string, bool) {
nonce := n.nonces[len(n.nonces)-1]
n.nonces = n.nonces[:len(n.nonces)-1]
-
return nonce, true
}
@@ -45,7 +43,6 @@ func (n *Manager) Pop() (string, bool) {
func (n *Manager) Push(nonce string) {
n.Lock()
defer n.Unlock()
-
n.nonces = append(n.nonces, nonce)
}
@@ -54,7 +51,6 @@ func (n *Manager) Nonce() (string, error) {
if nonce, ok := n.Pop(); ok {
return nonce, nil
}
-
return n.getNonce()
}
diff --git a/acme/api/internal/nonces/nonce_manager_test.go b/acme/api/internal/nonces/nonce_manager_test.go
index 4490165df..a172a0b69 100644
--- a/acme/api/internal/nonces/nonce_manager_test.go
+++ b/acme/api/internal/nonces/nonce_manager_test.go
@@ -8,52 +8,45 @@ import (
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/acme/api/internal/sender"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
+ "github.com/go-acme/lego/v4/platform/tester"
)
func TestNotHoldingLockWhileMakingHTTPRequests(t *testing.T) {
- manager := servermock.NewBuilder(
- func(server *httptest.Server) (*Manager, error) {
- doer := sender.NewDoer(server.Client(), "lego-test")
-
- return NewManager(doer, server.URL), nil
- }).
- Route("HEAD /", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- time.Sleep(250 * time.Millisecond)
-
- rw.Header().Set("Replay-Nonce", "12345")
- rw.Header().Set("Retry-After", "0")
-
- servermock.JSONEncode(&acme.Challenge{Type: "http-01", Status: "Valid", URL: "https://example.com/", Token: "token"}).ServeHTTP(rw, req)
- })).
- BuildHTTPS(t)
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ time.Sleep(250 * time.Millisecond)
+ w.Header().Set("Replay-Nonce", "12345")
+ w.Header().Set("Retry-After", "0")
+ err := tester.WriteJSONResponse(w, &acme.Challenge{Type: "http-01", Status: "Valid", URL: "http://example.com/", Token: "token"})
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ }))
+ t.Cleanup(server.Close)
+ doer := sender.NewDoer(http.DefaultClient, "lego-test")
+ j := NewManager(doer, server.URL)
ch := make(chan bool)
resultCh := make(chan bool)
-
go func() {
- _, errN := manager.Nonce()
+ _, errN := j.Nonce()
if errN != nil {
t.Log(errN)
}
-
ch <- true
}()
go func() {
- _, errN := manager.Nonce()
+ _, errN := j.Nonce()
if errN != nil {
t.Log(errN)
}
-
ch <- true
}()
go func() {
<-ch
<-ch
-
resultCh <- true
}()
-
select {
case <-resultCh:
case <-time.After(500 * time.Millisecond):
diff --git a/acme/api/internal/secure/jws.go b/acme/api/internal/secure/jws.go
index 8cd598663..7aa6c4c46 100644
--- a/acme/api/internal/secure/jws.go
+++ b/acme/api/internal/secure/jws.go
@@ -36,7 +36,6 @@ func (j *JWS) SetKid(kid string) {
// SignContent Signs a content with the JWS.
func (j *JWS) SignContent(url string, content []byte) (*jose.JSONWebSignature, error) {
var alg jose.SignatureAlgorithm
-
switch k := j.privKey.(type) {
case *rsa.PrivateKey:
alg = jose.RS256
@@ -73,14 +72,12 @@ func (j *JWS) SignContent(url string, content []byte) (*jose.JSONWebSignature, e
if err != nil {
return nil, fmt.Errorf("failed to sign content: %w", err)
}
-
return signed, nil
}
// SignEABContent Signs an external account binding content with the JWS.
func (j *JWS) SignEABContent(url, kid string, hmac []byte) (*jose.JSONWebSignature, error) {
jwk := jose.JSONWebKey{Key: j.privKey}
-
jwkJSON, err := jwk.Public().MarshalJSON()
if err != nil {
return nil, fmt.Errorf("acme: error encoding eab jwk key: %w", err)
@@ -111,7 +108,6 @@ func (j *JWS) SignEABContent(url, kid string, hmac []byte) (*jose.JSONWebSignatu
// GetKeyAuthorization Gets the key authorization for a token.
func (j *JWS) GetKeyAuthorization(token string) (string, error) {
var publicKey crypto.PublicKey
-
switch k := j.privKey.(type) {
case *ecdsa.PrivateKey:
publicKey = k.Public()
diff --git a/acme/api/internal/secure/jws_test.go b/acme/api/internal/secure/jws_test.go
index d033cb0c4..2e625f24f 100644
--- a/acme/api/internal/secure/jws_test.go
+++ b/acme/api/internal/secure/jws_test.go
@@ -9,52 +9,45 @@ import (
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/acme/api/internal/nonces"
"github.com/go-acme/lego/v4/acme/api/internal/sender"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
+ "github.com/go-acme/lego/v4/platform/tester"
)
func TestNotHoldingLockWhileMakingHTTPRequests(t *testing.T) {
- manager := servermock.NewBuilder(
- func(server *httptest.Server) (*nonces.Manager, error) {
- doer := sender.NewDoer(server.Client(), "lego-test")
-
- return nonces.NewManager(doer, server.URL), nil
- }).
- Route("HEAD /", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- time.Sleep(250 * time.Millisecond)
-
- rw.Header().Set("Replay-Nonce", "12345")
- rw.Header().Set("Retry-After", "0")
-
- servermock.JSONEncode(&acme.Challenge{Type: "http-01", Status: "Valid", URL: "https://example.com/", Token: "token"}).ServeHTTP(rw, req)
- })).
- BuildHTTPS(t)
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ time.Sleep(250 * time.Millisecond)
+ w.Header().Set("Replay-Nonce", "12345")
+ w.Header().Set("Retry-After", "0")
+ err := tester.WriteJSONResponse(w, &acme.Challenge{Type: "http-01", Status: "Valid", URL: "http://example.com/", Token: "token"})
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ }))
+ t.Cleanup(server.Close)
+ doer := sender.NewDoer(http.DefaultClient, "lego-test")
+ j := nonces.NewManager(doer, server.URL)
ch := make(chan bool)
resultCh := make(chan bool)
-
go func() {
- _, errN := manager.Nonce()
+ _, errN := j.Nonce()
if errN != nil {
t.Log(errN)
}
-
ch <- true
}()
go func() {
- _, errN := manager.Nonce()
+ _, errN := j.Nonce()
if errN != nil {
t.Log(errN)
}
-
ch <- true
}()
go func() {
<-ch
<-ch
-
resultCh <- true
}()
-
select {
case <-resultCh:
case <-time.After(500 * time.Millisecond):
diff --git a/acme/api/internal/sender/sender.go b/acme/api/internal/sender/sender.go
index d8859edf4..2e1bbec8d 100644
--- a/acme/api/internal/sender/sender.go
+++ b/acme/api/internal/sender/sender.go
@@ -27,8 +27,6 @@ type Doer struct {
// NewDoer Creates a new Doer.
func NewDoer(client *http.Client, userAgent string) *Doer {
- client.Transport = newHTTPSOnly(client)
-
return &Doer{
httpClient: client,
userAgent: userAgent,
@@ -120,69 +118,35 @@ func (d *Doer) formatUserAgent() string {
}
func checkError(req *http.Request, resp *http.Response) error {
- if resp.StatusCode < http.StatusBadRequest {
- return nil
- }
-
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- return fmt.Errorf("%d :: %s :: %s :: %w", resp.StatusCode, req.Method, req.URL, err)
- }
-
- var errorDetails *acme.ProblemDetails
-
- err = json.Unmarshal(body, &errorDetails)
- if err != nil {
- return fmt.Errorf("%d ::%s :: %s :: %w :: %s", resp.StatusCode, req.Method, req.URL, err, string(body))
- }
-
- errorDetails.Method = req.Method
- errorDetails.URL = req.URL.String()
-
- if errorDetails.HTTPStatus == 0 {
- errorDetails.HTTPStatus = resp.StatusCode
- }
-
- // Check for errors we handle specifically
- switch {
- case errorDetails.HTTPStatus == http.StatusBadRequest && errorDetails.Type == acme.BadNonceErr:
- return &acme.NonceError{ProblemDetails: errorDetails}
-
- case errorDetails.HTTPStatus == http.StatusConflict && errorDetails.Type == acme.AlreadyReplacedErr:
- return &acme.AlreadyReplacedError{ProblemDetails: errorDetails}
-
- case errorDetails.HTTPStatus == http.StatusTooManyRequests && errorDetails.Type == acme.RateLimitedErr:
- return &acme.RateLimitedError{
- ProblemDetails: errorDetails,
- RetryAfter: resp.Header.Get("Retry-After"),
+ if resp.StatusCode >= http.StatusBadRequest {
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return fmt.Errorf("%d :: %s :: %s :: %w", resp.StatusCode, req.Method, req.URL, err)
+ }
+
+ var errorDetails *acme.ProblemDetails
+ err = json.Unmarshal(body, &errorDetails)
+ if err != nil {
+ return fmt.Errorf("%d ::%s :: %s :: %w :: %s", resp.StatusCode, req.Method, req.URL, err, string(body))
+ }
+
+ errorDetails.Method = req.Method
+ errorDetails.URL = req.URL.String()
+
+ if errorDetails.HTTPStatus == 0 {
+ errorDetails.HTTPStatus = resp.StatusCode
+ }
+
+ // Check for errors we handle specifically
+ if errorDetails.HTTPStatus == http.StatusBadRequest && errorDetails.Type == acme.BadNonceErr {
+ return &acme.NonceError{ProblemDetails: errorDetails}
+ }
+
+ if errorDetails.HTTPStatus == http.StatusConflict && errorDetails.Type == acme.AlreadyReplacedErr {
+ return &acme.AlreadyReplacedError{ProblemDetails: errorDetails}
}
- default:
return errorDetails
}
-}
-
-type httpsOnly struct {
- rt http.RoundTripper
-}
-
-func newHTTPSOnly(client *http.Client) *httpsOnly {
- if client.Transport == nil {
- return &httpsOnly{rt: http.DefaultTransport}
- }
-
- return &httpsOnly{rt: client.Transport}
-}
-
-// RoundTrip ensure HTTPS is used.
-// Each ACME function is accomplished by the client sending a sequence of HTTPS requests to the server [RFC2818],
-// carrying JSON messages [RFC8259].
-// Use of HTTPS is REQUIRED.
-// https://datatracker.ietf.org/doc/html/rfc8555#section-6.1
-func (r *httpsOnly) RoundTrip(req *http.Request) (*http.Response, error) {
- if req.URL.Scheme != "https" {
- return nil, fmt.Errorf("HTTPS is required: %s", req.URL)
- }
-
- return r.rt.RoundTrip(req)
+ return nil
}
diff --git a/acme/api/internal/sender/sender_test.go b/acme/api/internal/sender/sender_test.go
index 73701ab11..2fd43c878 100644
--- a/acme/api/internal/sender/sender_test.go
+++ b/acme/api/internal/sender/sender_test.go
@@ -1,28 +1,24 @@
package sender
import (
- "bytes"
- "io"
"net/http"
"net/http/httptest"
"strings"
"testing"
- "github.com/go-acme/lego/v4/acme"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDo_UserAgentOnAllHTTPMethod(t *testing.T) {
var ua, method string
-
- server := httptest.NewTLSServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
+ server := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
ua = r.Header.Get("User-Agent")
method = r.Method
}))
t.Cleanup(server.Close)
- doer := NewDoer(server.Client(), "")
+ doer := NewDoer(http.DefaultClient, "")
testCases := []struct {
method string
@@ -64,87 +60,8 @@ func TestDo_CustomUserAgent(t *testing.T) {
ua := doer.formatUserAgent()
assert.Contains(t, ua, ourUserAgent)
assert.Contains(t, ua, customUA)
-
if strings.HasSuffix(ua, " ") {
t.Errorf("UA should not have trailing spaces; got '%s'", ua)
}
-
assert.Len(t, strings.Split(ua, " "), 5)
}
-
-func TestDo_failWithHTTP(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}))
- t.Cleanup(server.Close)
-
- sender := NewDoer(server.Client(), "test")
-
- _, err := sender.Post(server.URL, strings.NewReader("data"), "text/plain", nil)
- require.ErrorContains(t, err, "HTTPS is required: http://")
-}
-
-func Test_checkError(t *testing.T) {
- testCases := []struct {
- desc string
- resp *http.Response
- assert func(t *testing.T, err error)
- }{
- {
- desc: "default",
- resp: &http.Response{
- StatusCode: http.StatusNotFound,
- Body: io.NopCloser(bytes.NewBufferString(`{"type":"urn:ietf:params:acme:error:example","detail":"message","status":404}`)),
- },
- assert: errorAs[*acme.ProblemDetails],
- },
- {
- desc: "badNonce",
- resp: &http.Response{
- StatusCode: http.StatusBadRequest,
- Body: io.NopCloser(bytes.NewBufferString(`{"type":"urn:ietf:params:acme:error:badNonce","detail":"message","status":400}`)),
- },
- assert: errorAs[*acme.NonceError],
- },
- {
- desc: "alreadyReplaced",
- resp: &http.Response{
- StatusCode: http.StatusConflict,
- Body: io.NopCloser(bytes.NewBufferString(`{"type":"urn:ietf:params:acme:error:alreadyReplaced","detail":"message","status":409}`)),
- },
- assert: errorAs[*acme.AlreadyReplacedError],
- },
- {
- desc: "rateLimited",
- resp: &http.Response{
- StatusCode: http.StatusConflict,
- Header: http.Header{
- "Retry-After": []string{"1"},
- },
- Body: io.NopCloser(bytes.NewBufferString(`{"type":"urn:ietf:params:acme:error:rateLimited","detail":"message","status":429}`)),
- },
- assert: errorAs[*acme.RateLimitedError],
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "https://example.com", nil)
-
- err := checkError(req, test.resp)
- require.Error(t, err)
-
- pb := &acme.ProblemDetails{}
- assert.ErrorAs(t, err, &pb)
-
- test.assert(t, err)
- })
- }
-}
-
-func errorAs[T error](t *testing.T, err error) {
- t.Helper()
-
- var zero T
- assert.ErrorAs(t, err, &zero)
-}
diff --git a/acme/api/internal/sender/useragent.go b/acme/api/internal/sender/useragent.go
index 51a1b4770..a4c287793 100644
--- a/acme/api/internal/sender/useragent.go
+++ b/acme/api/internal/sender/useragent.go
@@ -4,10 +4,10 @@ package sender
const (
// ourUserAgent is the User-Agent of this underlying library package.
- ourUserAgent = "xenolf-acme/4.32.0"
+ ourUserAgent = "xenolf-acme/4.25.1"
// ourUserAgentComment is part of the UA comment linked to the version status of this underlying library package.
// values: detach|release
// NOTE: Update this with each tagged release.
- ourUserAgentComment = "detach"
+ ourUserAgentComment = "release"
)
diff --git a/acme/api/order.go b/acme/api/order.go
index fad6be2b8..96cd4d287 100644
--- a/acme/api/order.go
+++ b/acme/api/order.go
@@ -4,6 +4,7 @@ import (
"encoding/base64"
"errors"
"fmt"
+ "net"
"slices"
"time"
@@ -17,7 +18,7 @@ type OrderOptions struct {
// A string uniquely identifying the profile
// which will be used to affect issuance of the certificate requested by this Order.
- // - https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-4
+ // - https://www.ietf.org/id/draft-aaron-acme-profiles-00.html#section-4
Profile string
// A string uniquely identifying a previously-issued certificate which this
@@ -35,7 +36,18 @@ func (o *OrderService) New(domains []string) (acme.ExtendedOrder, error) {
// NewWithOptions Creates a new order.
func (o *OrderService) NewWithOptions(domains []string, opts *OrderOptions) (acme.ExtendedOrder, error) {
- orderReq := acme.Order{Identifiers: createIdentifiers(domains)}
+ var identifiers []acme.Identifier
+ for _, domain := range domains {
+ ident := acme.Identifier{Value: domain, Type: "dns"}
+
+ if net.ParseIP(domain) != nil {
+ ident.Type = "ip"
+ }
+
+ identifiers = append(identifiers, ident)
+ }
+
+ orderReq := acme.Order{Identifiers: identifiers}
if opts != nil {
if !opts.NotAfter.IsZero() {
@@ -56,7 +68,6 @@ func (o *OrderService) NewWithOptions(domains []string, opts *OrderOptions) (acm
}
var order acme.Order
-
resp, err := o.core.post(o.core.GetDirectory().NewOrderURL, orderReq, &order)
if err != nil {
are := &acme.AlreadyReplacedError{}
@@ -75,23 +86,18 @@ func (o *OrderService) NewWithOptions(domains []string, opts *OrderOptions) (acm
}
}
- // The server MUST return an error if it cannot fulfill the request as specified,
- // and it MUST NOT issue a certificate with contents other than those requested.
- // If the server requires the request to be modified in a certain way,
- // it should indicate the required changes using an appropriate error type and description.
- // https://www.rfc-editor.org/rfc/rfc8555#section-7.4
- //
- // Some ACME servers don't return an error,
- // and/or change the order identifiers in the response,
- // so we need to ensure that the identifiers are the same as requested.
- // Deduplication by the server is allowed.
+ // The elements of the "authorizations" and "identifiers" arrays are immutable once set.
+ // The server MUST NOT change the contents of either array after they are created.
+ // If a client observes a change in the contents of either array,
+ // then it SHOULD consider the order invalid.
+ // https://www.rfc-editor.org/rfc/rfc8555#section-7.1.3
if compareIdentifiers(orderReq.Identifiers, order.Identifiers) != 0 {
// Sorts identifiers to avoid error message ambiguities about the order of the identifiers.
slices.SortStableFunc(orderReq.Identifiers, compareIdentifier)
slices.SortStableFunc(order.Identifiers, compareIdentifier)
return acme.ExtendedOrder{},
- fmt.Errorf("order identifiers have been modified by the ACME server (RFC8555 §7.4): %+v != %+v",
+ fmt.Errorf("order identifiers have been by the ACME server (RFC8555 §7.1.3): %+v != %+v",
orderReq.Identifiers, order.Identifiers)
}
@@ -108,7 +114,6 @@ func (o *OrderService) Get(orderURL string) (acme.ExtendedOrder, error) {
}
var order acme.Order
-
_, err := o.core.postAsGet(orderURL, &order)
if err != nil {
return acme.ExtendedOrder{}, err
@@ -124,7 +129,6 @@ func (o *OrderService) UpdateForCSR(orderURL string, csr []byte) (acme.ExtendedO
}
var order acme.Order
-
_, err := o.core.post(orderURL, csrMsg, &order)
if err != nil {
return acme.ExtendedOrder{}, err
diff --git a/acme/api/order_test.go b/acme/api/order_test.go
index f74f473d2..cf28e517b 100644
--- a/acme/api/order_test.go
+++ b/acme/api/order_test.go
@@ -11,51 +11,57 @@ import (
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/go-jose/go-jose/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOrderService_NewWithOptions(t *testing.T) {
+ mux, apiURL := tester.SetupFakeAPI(t)
+
// small value keeps test fast
privateKey, errK := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, errK, "Could not generate test key")
- server := tester.MockACMEServer().
- Route("POST /newOrder",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- body, err := readSignedBody(req, privateKey)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusBadRequest)
- return
- }
+ mux.HandleFunc("/newOrder", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
+ return
+ }
- order := acme.Order{}
+ body, err := readSignedBody(r, privateKey)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
- err = json.Unmarshal(body, &order)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusBadRequest)
- return
- }
+ order := acme.Order{}
+ err = json.Unmarshal(body, &order)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
- servermock.JSONEncode(acme.Order{
- Status: acme.StatusValid,
- Expires: order.Expires,
- Identifiers: order.Identifiers,
- Profile: order.Profile,
- NotBefore: order.NotBefore,
- NotAfter: order.NotAfter,
- Error: order.Error,
- Authorizations: order.Authorizations,
- Finalize: order.Finalize,
- Certificate: order.Certificate,
- Replaces: order.Replaces,
- }).ServeHTTP(rw, req)
- })).
- BuildHTTPS(t)
+ err = tester.WriteJSONResponse(w, acme.Order{
+ Status: acme.StatusValid,
+ Expires: order.Expires,
+ Identifiers: order.Identifiers,
+ Profile: order.Profile,
+ NotBefore: order.NotBefore,
+ NotAfter: order.NotAfter,
+ Error: order.Error,
+ Authorizations: order.Authorizations,
+ Finalize: order.Finalize,
+ Certificate: order.Certificate,
+ Replaces: order.Replaces,
+ })
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
- core, err := New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
testCases := []struct {
@@ -108,7 +114,6 @@ func readSignedBody(r *http.Request, privateKey *rsa.PrivateKey) ([]byte, error)
}
sigAlgs := []jose.SignatureAlgorithm{jose.RS256}
-
jws, err := jose.ParseSigned(string(reqBody), sigAlgs)
if err != nil {
return nil, err
diff --git a/acme/api/service.go b/acme/api/service.go
index 22ce05124..6f812ee03 100644
--- a/acme/api/service.go
+++ b/acme/api/service.go
@@ -1,11 +1,8 @@
package api
import (
- "fmt"
"net/http"
"regexp"
- "strconv"
- "time"
)
type service struct {
@@ -26,13 +23,11 @@ func getLinks(header http.Header, rel string) []string {
linkExpr := regexp.MustCompile(`<(.+?)>(?:;[^;]+)*?;\s*rel="(.+?)"`)
var links []string
-
for _, link := range header["Link"] {
for _, m := range linkExpr.FindAllStringSubmatch(link, -1) {
if len(m) != 3 {
continue
}
-
if m[2] == rel {
links = append(links, m[1])
}
@@ -59,29 +54,3 @@ func getRetryAfter(resp *http.Response) string {
return resp.Header.Get("Retry-After")
}
-
-// ParseRetryAfter parses the Retry-After header value according to RFC 7231.
-// The header can be either delay-seconds (numeric) or HTTP-date (RFC 1123 format).
-// https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3
-// Returns the duration until the retry time.
-// TODO(ldez): unexposed this function in v5.
-func ParseRetryAfter(value string) (time.Duration, error) {
- if value == "" {
- return 0, nil
- }
-
- if seconds, err := strconv.ParseInt(value, 10, 64); err == nil {
- return time.Duration(seconds) * time.Second, nil
- }
-
- if retryTime, err := time.Parse(time.RFC1123, value); err == nil {
- duration := time.Until(retryTime)
- if duration < 0 {
- return 0, nil
- }
-
- return duration, nil
- }
-
- return 0, fmt.Errorf("invalid Retry-After value: %q", value)
-}
diff --git a/acme/api/service_test.go b/acme/api/service_test.go
index 57ea45708..2dbd795c9 100644
--- a/acme/api/service_test.go
+++ b/acme/api/service_test.go
@@ -3,10 +3,8 @@ package api
import (
"net/http"
"testing"
- "time"
"github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
)
func Test_getLink(t *testing.T) {
@@ -55,38 +53,3 @@ func Test_getLink(t *testing.T) {
})
}
}
-
-func TestParseRetryAfter(t *testing.T) {
- testCases := []struct {
- desc string
- value string
- expected time.Duration
- }{
- {
- desc: "empty header value",
- value: "",
- expected: time.Duration(0),
- },
- {
- desc: "delay-seconds",
- value: "123",
- expected: 123 * time.Second,
- },
- {
- desc: "HTTP-date",
- value: time.Now().Add(3 * time.Second).Format(time.RFC1123),
- expected: 3 * time.Second,
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- rt, err := ParseRetryAfter(test.value)
- require.NoError(t, err)
-
- assert.InDelta(t, test.expected.Seconds(), rt.Seconds(), 1)
- })
- }
-}
diff --git a/acme/commons.go b/acme/commons.go
index 0af623e4e..489c74938 100644
--- a/acme/commons.go
+++ b/acme/commons.go
@@ -77,14 +77,13 @@ type Meta struct {
// profiles (optional, object):
// A map of profile names to human-readable descriptions of those profiles.
- // https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-3
+ // https://www.ietf.org/id/draft-aaron-acme-profiles-00.html#section-3
Profiles map[string]string `json:"profiles"`
}
// ExtendedAccount an extended Account.
type ExtendedAccount struct {
Account
-
// Contains the value of the response header `Location`
Location string `json:"-"`
}
@@ -157,7 +156,7 @@ type Order struct {
// profile (string, optional):
// A string uniquely identifying the profile
// which will be used to affect issuance of the certificate requested by this Order.
- // https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-4
+ // https://www.ietf.org/id/draft-aaron-acme-profiles-00.html#section-4
Profile string `json:"profile,omitempty"`
// notBefore (optional, string):
@@ -221,11 +220,11 @@ type Authorization struct {
// The timestamp after which the server will consider this authorization invalid,
// encoded in the format specified in RFC 3339 [RFC3339].
// This field is REQUIRED for objects with "valid" in the "status" field.
- Expires time.Time `json:"expires,omitzero"`
+ Expires time.Time `json:"expires,omitempty"`
// identifier (required, object):
// The identifier that the account is authorized to represent
- Identifier Identifier `json:"identifier"`
+ Identifier Identifier `json:"identifier,omitempty"`
// challenges (required, array of objects):
// For pending authorizations, the challenges that the client can fulfill in order to prove possession of the identifier.
@@ -245,7 +244,6 @@ type Authorization struct {
// ExtendedChallenge a extended Challenge.
type ExtendedChallenge struct {
Challenge
-
// Contains the value of the response header `Retry-After`
RetryAfter string `json:"-"`
// Contains the value of the response header `Link` rel="up"
@@ -272,7 +270,7 @@ type Challenge struct {
// The time at which the server validated this challenge,
// encoded in the format specified in RFC 3339 [RFC3339].
// This field is REQUIRED if the "status" field is "valid".
- Validated time.Time `json:"validated,omitzero"`
+ Validated time.Time `json:"validated,omitempty"`
// error (optional, object):
// Error that occurred while the server was validating the challenge, if any,
diff --git a/acme/errors.go b/acme/errors.go
index cd447d7b4..9a255468d 100644
--- a/acme/errors.go
+++ b/acme/errors.go
@@ -2,7 +2,6 @@ package acme
import (
"fmt"
- "strings"
)
// Errors types.
@@ -10,7 +9,6 @@ const (
errNS = "urn:ietf:params:acme:error:"
BadNonceErr = errNS + "badNonce"
AlreadyReplacedErr = errNS + "alreadyReplaced"
- RateLimitedErr = errNS + "rateLimited"
)
// ProblemDetails the problem details object.
@@ -29,25 +27,21 @@ type ProblemDetails struct {
}
func (p *ProblemDetails) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "acme: error: %d", p.HTTPStatus)
-
+ msg := fmt.Sprintf("acme: error: %d", p.HTTPStatus)
if p.Method != "" || p.URL != "" {
- _, _ = fmt.Fprintf(msg, " :: %s :: %s", p.Method, p.URL)
+ msg += fmt.Sprintf(" :: %s :: %s", p.Method, p.URL)
}
-
- _, _ = fmt.Fprintf(msg, " :: %s :: %s", p.Type, p.Detail)
+ msg += fmt.Sprintf(" :: %s :: %s", p.Type, p.Detail)
for _, sub := range p.SubProblems {
- _, _ = fmt.Fprintf(msg, ", problem: %q :: %s", sub.Type, sub.Detail)
+ msg += fmt.Sprintf(", problem: %q :: %s", sub.Type, sub.Detail)
}
if p.Instance != "" {
- msg.WriteString(", url: " + p.Instance)
+ msg += ", url: " + p.Instance
}
- return msg.String()
+ return msg
}
// SubProblem a "subproblems".
@@ -55,7 +49,7 @@ func (p *ProblemDetails) Error() string {
type SubProblem struct {
Type string `json:"type,omitempty"`
Detail string `json:"detail,omitempty"`
- Identifier Identifier `json:"identifier"`
+ Identifier Identifier `json:"identifier,omitempty"`
}
// NonceError represents the error which is returned
@@ -64,30 +58,9 @@ type NonceError struct {
*ProblemDetails
}
-func (e *NonceError) Unwrap() error {
- return e.ProblemDetails
-}
-
// AlreadyReplacedError represents the error which is returned
-// if the Server rejects the request because the identified certificate has already been marked as replaced.
+// If the Server rejects the request because the identified certificate has already been marked as replaced.
// - https://www.rfc-editor.org/rfc/rfc9773.html#section-5
type AlreadyReplacedError struct {
*ProblemDetails
}
-
-func (e *AlreadyReplacedError) Unwrap() error {
- return e.ProblemDetails
-}
-
-// RateLimitedError represents the error which is returned
-// if the server rejects the request because the client has exceeded the rate limit.
-// - https://www.rfc-editor.org/rfc/rfc8555.html#section-6.6
-type RateLimitedError struct {
- *ProblemDetails
-
- RetryAfter string
-}
-
-func (e *RateLimitedError) Unwrap() error {
- return e.ProblemDetails
-}
diff --git a/buildx.Dockerfile b/buildx.Dockerfile
index 37f1dde94..92a86dd3d 100644
--- a/buildx.Dockerfile
+++ b/buildx.Dockerfile
@@ -1,12 +1,10 @@
# syntax=docker/dockerfile:1.4
FROM alpine:3
-ARG TARGETPLATFORM
-
RUN apk --no-cache --no-progress add git ca-certificates tzdata \
&& rm -rf /var/cache/apk/*
-COPY $TARGETPLATFORM/lego /
+COPY lego /
ENTRYPOINT ["/lego"]
EXPOSE 80
diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go
index 800bb3f5b..d6f53c3a1 100644
--- a/certcrypto/crypto.go
+++ b/certcrypto/crypto.go
@@ -57,10 +57,8 @@ type DERCertificateBytes []byte
// ParsePEMBundle parses a certificate bundle from top to bottom and returns
// a slice of x509 certificates. This function will error if no certificates are found.
func ParsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
- var (
- certificates []*x509.Certificate
- certDERBlock *pem.Block
- )
+ var certificates []*x509.Certificate
+ var certDERBlock *pem.Block
for {
certDERBlock, bundle = pem.Decode(bundle)
@@ -73,7 +71,6 @@ func ParsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
if err != nil {
return nil, err
}
-
certificates = append(certificates, cert)
}
}
@@ -155,11 +152,8 @@ type CSROptions struct {
}
func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) {
- var (
- dnsNames []string
- ipAddresses []net.IP
- )
-
+ var dnsNames []string
+ var ipAddresses []net.IP
for _, altname := range opts.SAN {
if ip := net.ParseIP(altname); ip != nil {
ipAddresses = append(ipAddresses, ip)
@@ -191,7 +185,6 @@ func PEMEncode(data any) []byte {
func PEMBlock(data any) *pem.Block {
var pemBlock *pem.Block
-
switch key := data.(type) {
case *ecdsa.PrivateKey:
keyBytes, _ := x509.MarshalECPrivateKey(key)
@@ -242,15 +235,15 @@ func ParsePEMCertificate(cert []byte) (*x509.Certificate, error) {
}
func GetCertificateMainDomain(cert *x509.Certificate) (string, error) {
- return getMainDomain(cert.Subject, cert.DNSNames, cert.IPAddresses)
+ return getMainDomain(cert.Subject, cert.DNSNames)
}
func GetCSRMainDomain(cert *x509.CertificateRequest) (string, error) {
- return getMainDomain(cert.Subject, cert.DNSNames, cert.IPAddresses)
+ return getMainDomain(cert.Subject, cert.DNSNames)
}
-func getMainDomain(subject pkix.Name, dnsNames []string, ips []net.IP) (string, error) {
- if subject.CommonName == "" && len(dnsNames) == 0 && len(ips) == 0 {
+func getMainDomain(subject pkix.Name, dnsNames []string) (string, error) {
+ if subject.CommonName == "" && len(dnsNames) == 0 {
return "", errors.New("missing domain")
}
@@ -258,11 +251,7 @@ func getMainDomain(subject pkix.Name, dnsNames []string, ips []net.IP) (string,
return subject.CommonName, nil
}
- if len(dnsNames) > 0 {
- return dnsNames[0], nil
- }
-
- return ips[0].String(), nil
+ return dnsNames[0], nil
}
func ExtractDomains(cert *x509.Certificate) []string {
@@ -276,7 +265,6 @@ func ExtractDomains(cert *x509.Certificate) []string {
if sanDomain == cert.Subject.CommonName {
continue
}
-
domains = append(domains, sanDomain)
}
@@ -328,7 +316,6 @@ func GeneratePemCert(privateKey *rsa.PrivateKey, domain string, extensions []pki
func generateDerCert(privateKey *rsa.PrivateKey, expiration time.Time, domain string, extensions []pkix.Extension) ([]byte, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
-
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, err
diff --git a/certcrypto/crypto_test.go b/certcrypto/crypto_test.go
index f5609fdf4..0b0ce8f6f 100644
--- a/certcrypto/crypto_test.go
+++ b/certcrypto/crypto_test.go
@@ -13,13 +13,6 @@ import (
"github.com/stretchr/testify/require"
)
-const (
- testDomain1 = "lego.example"
- testDomain2 = "a.lego.example"
- testDomain3 = "b.lego.example"
- testDomain4 = "c.lego.example"
-)
-
func TestGeneratePrivateKey(t *testing.T) {
key, err := GeneratePrivateKey(RSA2048)
require.NoError(t, err, "Error generating private key")
@@ -46,30 +39,30 @@ func TestGenerateCSR(t *testing.T) {
desc: "without SAN (nil)",
privateKey: privateKey,
opts: CSROptions{
- Domain: testDomain1,
+ Domain: "lego.acme",
MustStaple: true,
},
- expected: expected{len: 382},
+ expected: expected{len: 379},
},
{
desc: "without SAN (empty)",
privateKey: privateKey,
opts: CSROptions{
- Domain: testDomain1,
+ Domain: "lego.acme",
SAN: []string{},
MustStaple: true,
},
- expected: expected{len: 382},
+ expected: expected{len: 379},
},
{
desc: "with SAN",
privateKey: privateKey,
opts: CSROptions{
- Domain: testDomain1,
- SAN: []string{testDomain2, testDomain3, testDomain4},
+ Domain: "lego.acme",
+ SAN: []string{"a.lego.acme", "b.lego.acme", "c.lego.acme"},
MustStaple: true,
},
- expected: expected{len: 442},
+ expected: expected{len: 430},
},
{
desc: "no domain",
@@ -85,16 +78,16 @@ func TestGenerateCSR(t *testing.T) {
privateKey: privateKey,
opts: CSROptions{
Domain: "",
- SAN: []string{testDomain2, testDomain3, testDomain4},
+ SAN: []string{"a.lego.acme", "b.lego.acme", "c.lego.acme"},
MustStaple: true,
},
- expected: expected{len: 419},
+ expected: expected{len: 409},
},
{
desc: "private key nil",
privateKey: nil,
opts: CSROptions{
- Domain: testDomain1,
+ Domain: "fizz.buzz",
MustStaple: true,
},
expected: expected{error: true},
@@ -179,7 +172,6 @@ func TestParsePEMPrivateKey(t *testing.T) {
// ignoring precomputed values.
decoded, err := ParsePEMPrivateKey(pemPrivateKey)
require.NoError(t, err)
-
decodedRsaPrivateKey := decoded.(*rsa.PrivateKey)
require.True(t, decodedRsaPrivateKey.Equal(privateKey))
diff --git a/certificate/authorization.go b/certificate/authorization.go
index 49f958776..c77bcbd5f 100644
--- a/certificate/authorization.go
+++ b/certificate/authorization.go
@@ -29,7 +29,6 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
var responses []acme.Authorization
failures := newObtainError()
-
for range len(order.Authorizations) {
select {
case res := <-resc:
@@ -63,7 +62,6 @@ func (c *Certifier) deactivateAuthorizations(order acme.ExtendedOrder, force boo
}
log.Infof("Deactivating auth: %s", authzURL)
-
if c.core.Authorizations.Deactivate(authzURL) != nil {
log.Infof("Unable to deactivate the authorization: %s", authzURL)
}
diff --git a/certificate/certificates.go b/certificate/certificates.go
index 04904e794..e5830722d 100644
--- a/certificate/certificates.go
+++ b/certificate/certificates.go
@@ -77,7 +77,7 @@ type ObtainRequest struct {
// A string uniquely identifying the profile
// which will be used to affect issuance of the certificate requested by this Order.
- // - https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-4
+ // - https://www.ietf.org/id/draft-aaron-acme-profiles-00.html#section-4
Profile string
AlwaysDeactivateAuthorizations bool
@@ -106,7 +106,7 @@ type ObtainForCSRRequest struct {
// A string uniquely identifying the profile
// which will be used to affect issuance of the certificate requested by this Order.
- // - https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-4
+ // - https://www.ietf.org/id/draft-aaron-acme-profiles-00.html#section-4
Profile string
AlwaysDeactivateAuthorizations bool
@@ -198,7 +198,6 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
log.Infof("[%s] acme: Validations succeeded; requesting certificates", strings.Join(domains, ", "))
failures := newObtainError()
-
cert, err := c.getForOrder(domains, order, request)
if err != nil {
for _, auth := range authz {
@@ -296,7 +295,6 @@ func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, requ
if privateKey == nil {
var err error
-
privateKey, err = certcrypto.GeneratePrivateKey(c.options.KeyType)
if err != nil {
return nil, err
@@ -492,7 +490,6 @@ type RenewOptions struct {
// If bundle is true, the []byte contains both the issuer certificate and your issued certificate as a bundle.
//
// For private key reuse the PrivateKey property of the passed in Resource should be non-nil.
-//
// Deprecated: use RenewWithOptions instead.
func (c *Certifier) Renew(certRes Resource, bundle, mustStaple bool, preferredChain string) (*Resource, error) {
return c.RenewWithOptions(certRes, &RenewOptions{
@@ -725,7 +722,6 @@ func checkOrderStatus(order acme.ExtendedOrder) (bool, error) {
// https://www.rfc-editor.org/rfc/rfc5280.html#section-7
func sanitizeDomain(domains []string) []string {
var sanitizedDomains []string
-
for _, domain := range domains {
sanitizedDomain, err := idna.ToASCII(domain)
if err != nil {
@@ -734,6 +730,5 @@ func sanitizeDomain(domains []string) []string {
sanitizedDomains = append(sanitizedDomains, sanitizedDomain)
}
}
-
return sanitizedDomains
}
diff --git a/certificate/certificates_test.go b/certificate/certificates_test.go
index c0e35e795..3be2d606a 100644
--- a/certificate/certificates_test.go
+++ b/certificate/certificates_test.go
@@ -3,6 +3,7 @@ package certificate
import (
"crypto/rand"
"crypto/rsa"
+ "encoding/pem"
"fmt"
"net/http"
"testing"
@@ -11,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/acme/api"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -175,14 +175,20 @@ Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
`
func Test_checkResponse(t *testing.T) {
- server := tester.MockACMEServer().
- Route("POST /certificate", servermock.RawStringResponse(certResponseMock)).
- BuildHTTPS(t)
+ mux, apiURL := tester.SetupFakeAPI(t)
+
+ mux.HandleFunc("/certificate", func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(certResponseMock))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
@@ -190,7 +196,7 @@ func Test_checkResponse(t *testing.T) {
order := acme.ExtendedOrder{
Order: acme.Order{
Status: acme.StatusValid,
- Certificate: server.URL + "/certificate",
+ Certificate: apiURL + "/certificate",
},
}
certRes := &Resource{}
@@ -209,14 +215,30 @@ func Test_checkResponse(t *testing.T) {
}
func Test_checkResponse_issuerRelUp(t *testing.T) {
- server := tester.MockACMEServer().
- Route("POST /certificate", servermock.RawStringResponse(certResponseMock)).
- BuildHTTPS(t)
+ mux, apiURL := tester.SetupFakeAPI(t)
+
+ mux.HandleFunc("/certificate", func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Link", "<"+apiURL+`/issuer>; rel="up"`)
+ _, err := w.Write([]byte(certResponseMock))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
+
+ mux.HandleFunc("/issuer", func(w http.ResponseWriter, _ *http.Request) {
+ p, _ := pem.Decode([]byte(issuerMock))
+ _, err := w.Write(p.Bytes)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
@@ -224,7 +246,7 @@ func Test_checkResponse_issuerRelUp(t *testing.T) {
order := acme.ExtendedOrder{
Order: acme.Order{
Status: acme.StatusValid,
- Certificate: server.URL + "/certificate",
+ Certificate: apiURL + "/certificate",
},
}
certRes := &Resource{}
@@ -243,14 +265,20 @@ func Test_checkResponse_issuerRelUp(t *testing.T) {
}
func Test_checkResponse_no_bundle(t *testing.T) {
- server := tester.MockACMEServer().
- Route("POST /certificate", servermock.RawStringResponse(certResponseMock)).
- BuildHTTPS(t)
+ mux, apiURL := tester.SetupFakeAPI(t)
+
+ mux.HandleFunc("/certificate", func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(certResponseMock))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
@@ -258,7 +286,7 @@ func Test_checkResponse_no_bundle(t *testing.T) {
order := acme.ExtendedOrder{
Order: acme.Order{
Status: acme.StatusValid,
- Certificate: server.URL + "/certificate",
+ Certificate: apiURL + "/certificate",
},
}
certRes := &Resource{}
@@ -277,21 +305,30 @@ func Test_checkResponse_no_bundle(t *testing.T) {
}
func Test_checkResponse_alternate(t *testing.T) {
- server := tester.MockACMEServer().
- Route("POST /certificate",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- rw.Header().Add("Link",
- fmt.Sprintf(`;title="foo";rel="alternate"`, req.Context().Value(http.LocalAddrContextKey)))
+ mux, apiURL := tester.SetupFakeAPI(t)
- servermock.RawStringResponse(certResponseMock).ServeHTTP(rw, req)
- })).
- Route("/certificate/1", servermock.RawStringResponse(certResponseMock2)).
- BuildHTTPS(t)
+ mux.HandleFunc("/certificate", func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Add("Link", fmt.Sprintf(`<%s/certificate/1>;title="foo";rel="alternate"`, apiURL))
+
+ _, err := w.Write([]byte(certResponseMock))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
+
+ mux.HandleFunc("/certificate/1", func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(certResponseMock2))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
@@ -299,7 +336,7 @@ func Test_checkResponse_alternate(t *testing.T) {
order := acme.ExtendedOrder{
Order: acme.Order{
Status: acme.StatusValid,
- Certificate: server.URL + "/certificate",
+ Certificate: apiURL + "/certificate",
},
}
certRes := &Resource{
@@ -321,25 +358,31 @@ func Test_checkResponse_alternate(t *testing.T) {
}
func Test_Get(t *testing.T) {
- server := tester.MockACMEServer().
- Route("POST /acme/cert/test-cert", servermock.RawStringResponse(certResponseMock)).
- BuildHTTPS(t)
+ mux, apiURL := tester.SetupFakeAPI(t)
+
+ mux.HandleFunc("/acme/cert/test-cert", func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(certResponseMock))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
- certRes, err := certifier.Get(server.URL+"/acme/cert/test-cert", true)
+ certRes, err := certifier.Get(apiURL+"/acme/cert/test-cert", true)
require.NoError(t, err)
assert.NotNil(t, certRes)
assert.Equal(t, "acme.wtf", certRes.Domain)
- assert.Equal(t, server.URL+"/acme/cert/test-cert", certRes.CertStableURL)
- assert.Equal(t, server.URL+"/acme/cert/test-cert", certRes.CertURL)
+ assert.Equal(t, apiURL+"/acme/cert/test-cert", certRes.CertStableURL)
+ assert.Equal(t, apiURL+"/acme/cert/test-cert", certRes.CertURL)
assert.Nil(t, certRes.CSR)
assert.Nil(t, certRes.PrivateKey)
assert.Equal(t, certResponseMock, string(certRes.Certificate), "Certificate")
diff --git a/certificate/renewal.go b/certificate/renewal.go
index 59d31cfb5..0a9059501 100644
--- a/certificate/renewal.go
+++ b/certificate/renewal.go
@@ -11,7 +11,6 @@ import (
"time"
"github.com/go-acme/lego/v4/acme"
- "github.com/go-acme/lego/v4/acme/api"
)
// RenewalInfoRequest contains the necessary renewal information.
@@ -86,16 +85,15 @@ func (c *Certifier) GetRenewalInfo(req RenewalInfoRequest) (*RenewalInfoResponse
defer resp.Body.Close()
var info RenewalInfoResponse
-
err = json.NewDecoder(resp.Body).Decode(&info)
if err != nil {
return nil, err
}
if retry := resp.Header.Get("Retry-After"); retry != "" {
- info.RetryAfter, err = api.ParseRetryAfter(retry)
+ info.RetryAfter, err = time.ParseDuration(retry + "s")
if err != nil {
- return nil, fmt.Errorf("failed to parse Retry-After header: %w", err)
+ return nil, err
}
}
diff --git a/certificate/renewal_test.go b/certificate/renewal_test.go
index 23209638a..9f20e374e 100644
--- a/certificate/renewal_test.go
+++ b/certificate/renewal_test.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/acme/api"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -43,24 +42,31 @@ func TestCertifier_GetRenewalInfo(t *testing.T) {
require.NoError(t, err)
// Test with a fake API.
- server := tester.MockACMEServer().
- Route("GET /renewalInfo/"+ariLeafCertID,
- servermock.RawStringResponse(`{
+ mux, apiURL := tester.SetupFakeAPI(t)
+ mux.HandleFunc("/renewalInfo/"+ariLeafCertID, func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.Header().Set("Retry-After", "21600")
+ w.WriteHeader(http.StatusOK)
+ _, wErr := w.Write([]byte(`{
"suggestedWindow": {
"start": "2020-03-17T17:51:09Z",
"end": "2020-03-17T18:21:09Z"
},
- "explanationUrl": "https://aricapable.ca.example/docs/renewal-advice/"
+ "explanationUrl": "https://aricapable.ca/docs/renewal-advice/"
}
- }`).
- WithHeader("Content-Type", "application/json").
- WithHeader("Retry-After", "21600")).
- BuildHTTPS(t)
+ }`))
+ require.NoError(t, wErr)
+ })
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
@@ -70,46 +76,10 @@ func TestCertifier_GetRenewalInfo(t *testing.T) {
require.NotNil(t, ri)
assert.Equal(t, "2020-03-17T17:51:09Z", ri.SuggestedWindow.Start.Format(time.RFC3339))
assert.Equal(t, "2020-03-17T18:21:09Z", ri.SuggestedWindow.End.Format(time.RFC3339))
- assert.Equal(t, "https://aricapable.ca.example/docs/renewal-advice/", ri.ExplanationURL)
+ assert.Equal(t, "https://aricapable.ca/docs/renewal-advice/", ri.ExplanationURL)
assert.Equal(t, time.Duration(21600000000000), ri.RetryAfter)
}
-func TestCertifier_GetRenewalInfo_retryAfter(t *testing.T) {
- leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
- require.NoError(t, err)
-
- server := tester.MockACMEServer().
- Route("GET /renewalInfo/"+ariLeafCertID,
- servermock.RawStringResponse(`{
- "suggestedWindow": {
- "start": "2020-03-17T17:51:09Z",
- "end": "2020-03-17T18:21:09Z"
- },
- "explanationUrl": "https://aricapable.ca.example/docs/renewal-advice/"
- }
- }`).
- WithHeader("Content-Type", "application/json").
- WithHeader("Retry-After", time.Now().UTC().Add(6*time.Hour).Format(time.RFC1123))).
- BuildHTTPS(t)
-
- key, err := rsa.GenerateKey(rand.Reader, 2048)
- require.NoError(t, err, "Could not generate test key")
-
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
- require.NoError(t, err)
-
- certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
-
- ri, err := certifier.GetRenewalInfo(RenewalInfoRequest{leaf})
- require.NoError(t, err)
- require.NotNil(t, ri)
- assert.Equal(t, "2020-03-17T17:51:09Z", ri.SuggestedWindow.Start.Format(time.RFC3339))
- assert.Equal(t, "2020-03-17T18:21:09Z", ri.SuggestedWindow.End.Format(time.RFC3339))
- assert.Equal(t, "https://aricapable.ca.example/docs/renewal-advice/", ri.ExplanationURL)
-
- assert.InDelta(t, 6, ri.RetryAfter.Hours(), 0.001)
-}
-
func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
require.NoError(t, err)
@@ -118,23 +88,24 @@ func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
require.NoError(t, err, "Could not generate test key")
testCases := []struct {
- desc string
- timeout time.Duration
- request RenewalInfoRequest
- handler http.HandlerFunc
+ desc string
+ httpClient *http.Client
+ request RenewalInfoRequest
+ handler http.HandlerFunc
}{
{
- desc: "API timeout",
- timeout: 500 * time.Millisecond, // HTTP client that times out after 500ms.
- request: RenewalInfoRequest{leaf},
+ desc: "API timeout",
+ httpClient: &http.Client{Timeout: 500 * time.Millisecond}, // HTTP client that times out after 500ms.
+ request: RenewalInfoRequest{leaf},
handler: func(w http.ResponseWriter, r *http.Request) {
// API that takes 2ms to respond.
time.Sleep(2 * time.Millisecond)
},
},
{
- desc: "API error",
- request: RenewalInfoRequest{leaf},
+ desc: "API error",
+ httpClient: http.DefaultClient,
+ request: RenewalInfoRequest{leaf},
handler: func(w http.ResponseWriter, r *http.Request) {
// API that responds with error instead of renewal info.
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
@@ -146,17 +117,10 @@ func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
- server := tester.MockACMEServer().
- Route("GET /renewalInfo/"+ariLeafCertID, test.handler).
- BuildHTTPS(t)
+ mux, apiURL := tester.SetupFakeAPI(t)
+ mux.HandleFunc("/renewalInfo/"+ariLeafCertID, test.handler)
- client := server.Client()
-
- if test.timeout != 0 {
- client.Timeout = test.timeout
- }
-
- core, err := api.New(client, "lego-test", server.URL+"/dir", "", key)
+ core, err := api.New(test.httpClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
diff --git a/challenge/challenges.go b/challenge/challenges.go
index f6d5cdb28..39bf3bee2 100644
--- a/challenge/challenges.go
+++ b/challenge/challenges.go
@@ -40,6 +40,5 @@ func GetTargetedDomain(authz acme.Authorization) string {
if authz.Wildcard {
return "*." + authz.Identifier.Value
}
-
return authz.Identifier.Value
}
diff --git a/challenge/dns01/dns_challenge.go b/challenge/dns01/dns_challenge.go
index 1d106d7b7..8594d2799 100644
--- a/challenge/dns01/dns_challenge.go
+++ b/challenge/dns01/dns_challenge.go
@@ -40,7 +40,6 @@ func CondOption(condition bool, opt ChallengeOption) ChallengeOption {
return nil
}
}
-
return opt
}
@@ -119,7 +118,6 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
info := GetChallengeInfo(authz.Identifier.Value, keyAuth)
var timeout, interval time.Duration
-
switch provider := c.provider.(type) {
case challenge.ProviderTimeout:
timeout, interval = provider.Timeout()
@@ -136,7 +134,6 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
if !stop || errP != nil {
log.Infof("[%s] acme: Waiting for DNS record propagation.", domain)
}
-
return stop, errP
})
if err != nil {
@@ -144,7 +141,6 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
}
chlng.KeyAuthorization = keyAuth
-
return c.validate(c.core, domain, chlng)
}
@@ -169,7 +165,6 @@ func (c *Challenge) Sequential() (bool, time.Duration) {
if p, ok := c.provider.(sequential); ok {
return ok, p.Sequential()
}
-
return false, 0
}
@@ -178,7 +173,6 @@ type sequential interface {
}
// GetRecord returns a DNS record which will fulfill the `dns-01` challenge.
-//
// Deprecated: use GetChallengeInfo instead.
func GetRecord(domain, keyAuth string) (fqdn, value string) {
info := GetChallengeInfo(domain, keyAuth)
diff --git a/challenge/dns01/dns_challenge_manual.go b/challenge/dns01/dns_challenge_manual.go
index 3821fc157..c00d64041 100644
--- a/challenge/dns01/dns_challenge_manual.go
+++ b/challenge/dns01/dns_challenge_manual.go
@@ -12,14 +12,9 @@ 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/providers/dns/manual/manual_test.go b/challenge/dns01/dns_challenge_manual_test.go
similarity index 94%
rename from providers/dns/manual/manual_test.go
rename to challenge/dns01/dns_challenge_manual_test.go
index 7badd4b8b..26a508d1c 100644
--- a/providers/dns/manual/manual_test.go
+++ b/challenge/dns01/dns_challenge_manual_test.go
@@ -1,4 +1,4 @@
-package manual
+package dns01
import (
"io"
@@ -10,7 +10,6 @@ import (
func TestDNSProviderManual(t *testing.T) {
backupStdin := os.Stdin
-
defer func() { os.Stdin = backupStdin }()
testCases := []struct {
@@ -44,7 +43,7 @@ func TestDNSProviderManual(t *testing.T) {
os.Stdin = file
- manualProvider, err := NewDNSProvider()
+ manualProvider, err := NewDNSProviderManual()
require.NoError(t, err)
err = manualProvider.Present("example.com", "", "")
diff --git a/challenge/dns01/dns_challenge_test.go b/challenge/dns01/dns_challenge_test.go
index 325f1656c..c09273c2a 100644
--- a/challenge/dns01/dns_challenge_test.go
+++ b/challenge/dns01/dns_challenge_test.go
@@ -4,6 +4,7 @@ import (
"crypto/rand"
"crypto/rsa"
"errors"
+ "net/http"
"testing"
"time"
@@ -11,8 +12,6 @@ import (
"github.com/go-acme/lego/v4/acme/api"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/dnsmock"
- "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -33,12 +32,12 @@ func (p *providerTimeoutMock) CleanUp(domain, token, keyAuth string) error { ret
func (p *providerTimeoutMock) Timeout() (time.Duration, time.Duration) { return p.timeout, p.interval }
func TestChallenge_PreSolve(t *testing.T) {
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err)
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
testCases := []struct {
@@ -115,16 +114,12 @@ func TestChallenge_PreSolve(t *testing.T) {
}
func TestChallenge_Solve(t *testing.T) {
- useAsNameserver(t, dnsmock.NewServer().
- Query("_acme-challenge.example.com. CNAME", dnsmock.Noop).
- Build(t))
-
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err)
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
testCases := []struct {
@@ -184,7 +179,6 @@ func TestChallenge_Solve(t *testing.T) {
if test.preCheck != nil {
options = append(options, WrapPreCheck(test.preCheck))
}
-
chlg := NewChallenge(core, test.validate, test.provider, options...)
authz := acme.Authorization{
@@ -207,12 +201,12 @@ func TestChallenge_Solve(t *testing.T) {
}
func TestChallenge_CleanUp(t *testing.T) {
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err)
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
testCases := []struct {
@@ -287,55 +281,3 @@ func TestChallenge_CleanUp(t *testing.T) {
})
}
}
-
-func TestGetChallengeInfo(t *testing.T) {
- useAsNameserver(t, dnsmock.NewServer().
- Query("_acme-challenge.example.com. CNAME", dnsmock.Noop).
- Build(t))
-
- info := GetChallengeInfo("example.com", "123")
-
- expected := ChallengeInfo{
- FQDN: "_acme-challenge.example.com.",
- EffectiveFQDN: "_acme-challenge.example.com.",
- Value: "pmWkWSBCL51Bfkhn79xPuKBKHz__H6B-mY6G9_eieuM",
- }
-
- assert.Equal(t, expected, info)
-}
-
-func TestGetChallengeInfo_CNAME(t *testing.T) {
- useAsNameserver(t, dnsmock.NewServer().
- Query("_acme-challenge.example.com. CNAME", dnsmock.CNAME("example.org.")).
- Query("example.org. CNAME", dnsmock.Noop).
- Build(t))
-
- info := GetChallengeInfo("example.com", "123")
-
- expected := ChallengeInfo{
- FQDN: "_acme-challenge.example.com.",
- EffectiveFQDN: "example.org.",
- Value: "pmWkWSBCL51Bfkhn79xPuKBKHz__H6B-mY6G9_eieuM",
- }
-
- assert.Equal(t, expected, info)
-}
-
-func TestGetChallengeInfo_CNAME_disabled(t *testing.T) {
- useAsNameserver(t, dnsmock.NewServer().
- // Never called when the env var works.
- Query("_acme-challenge.example.com. CNAME", dnsmock.CNAME("example.org.")).
- Build(t))
-
- t.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true")
-
- info := GetChallengeInfo("example.com", "123")
-
- expected := ChallengeInfo{
- FQDN: "_acme-challenge.example.com.",
- EffectiveFQDN: "_acme-challenge.example.com.",
- Value: "pmWkWSBCL51Bfkhn79xPuKBKHz__H6B-mY6G9_eieuM",
- }
-
- assert.Equal(t, expected, info)
-}
diff --git a/challenge/dns01/fixtures/resolv.conf.1 b/challenge/dns01/fixtures/resolv.conf.1
index bc2a3c1ac..3098f99b5 100644
--- a/challenge/dns01/fixtures/resolv.conf.1
+++ b/challenge/dns01/fixtures/resolv.conf.1
@@ -1,4 +1,4 @@
-domain example.com
+domain company.com
nameserver 10.200.3.249
nameserver 10.200.3.250:5353
nameserver 2001:4860:4860::8844
diff --git a/challenge/dns01/fqdn.go b/challenge/dns01/fqdn.go
index 11ac3d0c2..3b94a491a 100644
--- a/challenge/dns01/fqdn.go
+++ b/challenge/dns01/fqdn.go
@@ -7,10 +7,12 @@ import (
)
// ToFqdn converts the name into a fqdn appending a trailing dot.
-//
-// Deprecated: Use [github.com/miekg/dns.Fqdn] directly.
func ToFqdn(name string) string {
- return dns.Fqdn(name)
+ n := len(name)
+ if n == 0 || name[n-1] == '.' {
+ return name
+ }
+ return name + "."
}
// UnFqdn converts the fqdn into a name removing the trailing dot.
@@ -19,7 +21,6 @@ func UnFqdn(name string) string {
if n != 0 && name[n-1] == '.' {
return name[:n-1]
}
-
return name
}
diff --git a/challenge/dns01/fqdn_test.go b/challenge/dns01/fqdn_test.go
index 641e39081..7a6506d4e 100644
--- a/challenge/dns01/fqdn_test.go
+++ b/challenge/dns01/fqdn_test.go
@@ -7,6 +7,34 @@ import (
"github.com/stretchr/testify/assert"
)
+func TestToFqdn(t *testing.T) {
+ testCases := []struct {
+ desc string
+ domain string
+ expected string
+ }{
+ {
+ desc: "simple",
+ domain: "foo.example.com",
+ expected: "foo.example.com.",
+ },
+ {
+ desc: "already FQDN",
+ domain: "foo.example.com.",
+ expected: "foo.example.com.",
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.desc, func(t *testing.T) {
+ t.Parallel()
+
+ fqdn := ToFqdn(test.domain)
+ assert.Equal(t, test.expected, fqdn)
+ })
+ }
+}
+
func TestUnFqdn(t *testing.T) {
testCases := []struct {
desc string
diff --git a/challenge/dns01/mock_test.go b/challenge/dns01/mock_test.go
deleted file mode 100644
index 5dcad3013..000000000
--- a/challenge/dns01/mock_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package dns01
-
-import (
- "context"
- "net"
- "testing"
- "time"
-
- "github.com/miekg/dns"
- "github.com/stretchr/testify/require"
-)
-
-func fakeNS(name, ns string) *dns.NS {
- return &dns.NS{
- Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 172800},
- Ns: ns,
- }
-}
-
-func fakeA(name, ip string) *dns.A {
- return &dns.A{
- Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 10},
- A: net.ParseIP(ip),
- }
-}
-
-func fakeTXT(name, value string) *dns.TXT {
- return &dns.TXT{
- Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 10},
- Txt: []string{value},
- }
-}
-
-// mockResolver modifies the default DNS resolver to use a custom network address during the test execution.
-// IMPORTANT: it modifying global variables.
-func mockResolver(t *testing.T, addr net.Addr) {
- t.Helper()
-
- _, port, err := net.SplitHostPort(addr.String())
- require.NoError(t, err)
-
- originalDefaultNameserverPort := defaultNameserverPort
-
- t.Cleanup(func() {
- defaultNameserverPort = originalDefaultNameserverPort
- })
-
- defaultNameserverPort = port
-
- originalResolver := net.DefaultResolver
-
- t.Cleanup(func() {
- net.DefaultResolver = originalResolver
- })
-
- net.DefaultResolver = &net.Resolver{
- PreferGo: true,
- Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
- d := net.Dialer{Timeout: 1 * time.Second}
-
- return d.DialContext(ctx, network, addr.String())
- },
- }
-}
-
-func useAsNameserver(t *testing.T, addr net.Addr) {
- t.Helper()
-
- ClearFqdnCache()
- t.Cleanup(func() {
- ClearFqdnCache()
- })
-
- originalRecursiveNameservers := recursiveNameservers
-
- t.Cleanup(func() {
- recursiveNameservers = originalRecursiveNameservers
- })
-
- recursiveNameservers = ParseNameservers([]string{addr.String()})
-}
diff --git a/challenge/dns01/nameserver.go b/challenge/dns01/nameserver.go
index 554eb7cc2..bb6dc0841 100644
--- a/challenge/dns01/nameserver.go
+++ b/challenge/dns01/nameserver.go
@@ -81,7 +81,6 @@ func getNameservers(path string, defaults []string) []string {
func ParseNameservers(servers []string) []string {
var resolvers []string
-
for _, resolver := range servers {
// ensure all servers have a port number
if _, _, err := net.SplitHostPort(resolver); err != nil {
@@ -90,7 +89,6 @@ func ParseNameservers(servers []string) []string {
resolvers = append(resolvers, resolver)
}
}
-
return resolvers
}
@@ -134,7 +132,6 @@ func FindPrimaryNsByFqdnCustom(fqdn string, nameservers []string) (string, error
if err != nil {
return "", fmt.Errorf("[fqdn=%s] %w", fqdn, err)
}
-
return soa.primaryNs, nil
}
@@ -151,7 +148,6 @@ func FindZoneByFqdnCustom(fqdn string, nameservers []string) (string, error) {
if err != nil {
return "", fmt.Errorf("[fqdn=%s] %w", fqdn, err)
}
-
return soa.zone, nil
}
@@ -176,10 +172,8 @@ func lookupSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error)
}
func fetchSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error) {
- var (
- err error
- r *dns.Msg
- )
+ var err error
+ var r *dns.Msg
for domain := range DomainsSeq(fqdn) {
r, err = dnsQuery(domain, dns.TypeSOA, nameservers, true)
@@ -235,11 +229,9 @@ func dnsQuery(fqdn string, rtype uint16, nameservers []string, recursive bool) (
return nil, &DNSError{Message: "empty list of nameservers"}
}
- var (
- r *dns.Msg
- err error
- errAll error
- )
+ var r *dns.Msg
+ var err error
+ var errAll error
for _, ns := range nameservers {
r, err = sendDNSQuery(m, ns)
@@ -272,7 +264,6 @@ func createDNSMsg(fqdn string, rtype uint16, recursive bool) *dns.Msg {
func sendDNSQuery(m *dns.Msg, ns string) (*dns.Msg, error) {
if ok, _ := strconv.ParseBool(os.Getenv("LEGO_EXPERIMENTAL_DNS_TCP_ONLY")); ok {
tcp := &dns.Client{Net: "tcp", Timeout: dnsTimeout}
-
r, _, err := tcp.Exchange(m, ns)
if err != nil {
return r, &DNSError{Message: "DNS call error", MsgIn: m, NS: ns, Err: err}
diff --git a/challenge/dns01/nameserver_test.go b/challenge/dns01/nameserver_test.go
index dd4d66dcb..d5bb0c0a1 100644
--- a/challenge/dns01/nameserver_test.go
+++ b/challenge/dns01/nameserver_test.go
@@ -5,237 +5,138 @@ import (
"sort"
"testing"
- "github.com/go-acme/lego/v4/platform/tester/dnsmock"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func Test_lookupNameserversOK(t *testing.T) {
+func TestLookupNameserversOK(t *testing.T) {
testCases := []struct {
- desc string
- fakeDNSServer *dnsmock.Builder
- fqdn string
- expected []string
+ fqdn string
+ nss []string
}{
{
- fqdn: "en.wikipedia.org.localhost.",
- fakeDNSServer: dnsmock.NewServer().
- Query("en.wikipedia.org.localhost SOA", dnsmock.CNAME("dyna.wikimedia.org.localhost")).
- Query("wikipedia.org.localhost SOA", dnsmock.SOA("")).
- Query("wikipedia.org.localhost NS",
- dnsmock.Answer(
- fakeNS("wikipedia.org.localhost.", "ns0.wikimedia.org.localhost."),
- fakeNS("wikipedia.org.localhost.", "ns1.wikimedia.org.localhost."),
- fakeNS("wikipedia.org.localhost.", "ns2.wikimedia.org.localhost."),
- ),
- ),
- expected: []string{"ns0.wikimedia.org.localhost.", "ns1.wikimedia.org.localhost.", "ns2.wikimedia.org.localhost."},
+ fqdn: "en.wikipedia.org.",
+ nss: []string{"ns0.wikimedia.org.", "ns1.wikimedia.org.", "ns2.wikimedia.org."},
},
{
- fqdn: "www.google.com.localhost.",
- fakeDNSServer: dnsmock.NewServer().
- Query("www.google.com.localhost. SOA", dnsmock.Noop).
- Query("google.com.localhost. SOA", dnsmock.SOA("")).
- Query("google.com.localhost. NS",
- dnsmock.Answer(
- fakeNS("google.com.localhost.", "ns1.google.com.localhost."),
- fakeNS("google.com.localhost.", "ns2.google.com.localhost."),
- fakeNS("google.com.localhost.", "ns3.google.com.localhost."),
- fakeNS("google.com.localhost.", "ns4.google.com.localhost."),
- ),
- ),
- expected: []string{"ns1.google.com.localhost.", "ns2.google.com.localhost.", "ns3.google.com.localhost.", "ns4.google.com.localhost."},
+ fqdn: "www.google.com.",
+ nss: []string{"ns1.google.com.", "ns2.google.com.", "ns3.google.com.", "ns4.google.com."},
},
{
- fqdn: "mail.proton.me.localhost.",
- fakeDNSServer: dnsmock.NewServer().
- Query("mail.proton.me.localhost. SOA", dnsmock.Noop).
- Query("proton.me.localhost. SOA", dnsmock.SOA("")).
- Query("proton.me.localhost. NS",
- dnsmock.Answer(
- fakeNS("proton.me.localhost.", "ns1.proton.me.localhost."),
- fakeNS("proton.me.localhost.", "ns2.proton.me.localhost."),
- fakeNS("proton.me.localhost.", "ns3.proton.me.localhost."),
- ),
- ),
- expected: []string{"ns1.proton.me.localhost.", "ns2.proton.me.localhost.", "ns3.proton.me.localhost."},
+ fqdn: "mail.proton.me.",
+ nss: []string{"ns1.proton.me.", "ns2.proton.me.", "ns3.proton.me."},
},
}
for _, test := range testCases {
t.Run(test.fqdn, func(t *testing.T) {
- useAsNameserver(t, test.fakeDNSServer.Build(t))
+ t.Parallel()
nss, err := lookupNameservers(test.fqdn)
require.NoError(t, err)
sort.Strings(nss)
- sort.Strings(test.expected)
+ sort.Strings(test.nss)
- assert.Equal(t, test.expected, nss)
+ assert.Equal(t, test.nss, nss)
})
}
}
-func Test_lookupNameserversErr(t *testing.T) {
+func TestLookupNameserversErr(t *testing.T) {
testCases := []struct {
- desc string
- fqdn string
- fakeDNSServer *dnsmock.Builder
- error string
+ desc string
+ fqdn string
+ error string
}{
{
- desc: "NXDOMAIN",
- fqdn: "example.invalid.",
- fakeDNSServer: dnsmock.NewServer().
- Query(". SOA", dnsmock.Error(dns.RcodeNameError)),
- error: "could not find zone: [fqdn=example.invalid.] could not find the start of authority for 'example.invalid.' [question='invalid. IN SOA', code=NXDOMAIN]",
- },
- {
- desc: "NS error",
- fqdn: "example.com.",
- fakeDNSServer: dnsmock.NewServer().
- Query("example.com. SOA", dnsmock.SOA("")).
- Query("example.com. NS", dnsmock.Error(dns.RcodeServerFailure)),
- error: "[zone=example.com.] could not determine authoritative nameservers",
- },
- {
- desc: "empty NS",
- fqdn: "example.com.",
- fakeDNSServer: dnsmock.NewServer().
- Query("example.com. SOA", dnsmock.SOA("")).
- Query("example.me NS", dnsmock.Noop),
- error: "[zone=example.com.] could not determine authoritative nameservers",
+ desc: "invalid tld",
+ fqdn: "_null.n0n0.",
+ error: "could not find zone",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
- useAsNameserver(t, test.fakeDNSServer.Build(t))
+ t.Parallel()
_, err := lookupNameservers(test.fqdn)
require.Error(t, err)
- assert.EqualError(t, err, test.error)
+ assert.Contains(t, err.Error(), test.error)
})
}
}
-type lookupSoaByFqdnTestCase struct {
+var findXByFqdnTestCases = []struct {
desc string
fqdn string
zone string
primaryNs string
nameservers []string
expectedError string
-}
-
-func lookupSoaByFqdnTestCases(t *testing.T) []lookupSoaByFqdnTestCase {
- t.Helper()
-
- return []lookupSoaByFqdnTestCase{
- {
- desc: "domain is a CNAME",
- fqdn: "mail.example.com.",
- zone: "example.com.",
- primaryNs: "ns1.example.com.",
- nameservers: []string{
- dnsmock.NewServer().
- Query("mail.example.com. SOA", dnsmock.CNAME("example.com.")).
- Query("example.com. SOA", dnsmock.SOA("")).
- Build(t).
- String(),
- },
- },
- {
- desc: "domain is a non-existent subdomain",
- fqdn: "foo.example.com.",
- zone: "example.com.",
- primaryNs: "ns1.example.com.",
- nameservers: []string{
- dnsmock.NewServer().
- Query("foo.example.com. SOA", dnsmock.Error(dns.RcodeNameError)).
- Query("example.com. SOA", dnsmock.SOA("")).
- Build(t).
- String(),
- },
- },
- {
- desc: "domain is a eTLD",
- fqdn: "example.com.ac.",
- zone: "ac.",
- primaryNs: "ns1.nic.ac.",
- nameservers: []string{
- dnsmock.NewServer().
- Query("example.com.ac. SOA", dnsmock.Error(dns.RcodeNameError)).
- Query("com.ac. SOA", dnsmock.Error(dns.RcodeNameError)).
- Query("ac. SOA", dnsmock.SOA("")).
- Build(t).
- String(),
- },
- },
- {
- desc: "domain is a cross-zone CNAME",
- fqdn: "cross-zone-example.example.com.",
- zone: "example.com.",
- primaryNs: "ns1.example.com.",
- nameservers: []string{
- dnsmock.NewServer().
- Query("cross-zone-example.example.com. SOA", dnsmock.CNAME("example.org.")).
- Query("example.com. SOA", dnsmock.SOA("")).
- Build(t).
- String(),
- },
- },
- {
- desc: "NXDOMAIN",
- fqdn: "test.lego.invalid.",
- zone: "lego.invalid.",
- nameservers: []string{
- dnsmock.NewServer().
- Query("test.lego.invalid. SOA", dnsmock.Error(dns.RcodeNameError)).
- Query("lego.invalid. SOA", dnsmock.Error(dns.RcodeNameError)).
- Query("invalid. SOA", dnsmock.Error(dns.RcodeNameError)).
- Build(t).
- String(),
- },
- expectedError: `[fqdn=test.lego.invalid.] could not find the start of authority for 'test.lego.invalid.' [question='invalid. IN SOA', code=NXDOMAIN]`,
- },
- {
- desc: "several non existent nameservers",
- fqdn: "mail.example.com.",
- zone: "example.com.",
- primaryNs: "ns1.example.com.",
- nameservers: []string{
- ":7053",
- ":8053",
- dnsmock.NewServer().
- Query("mail.example.com. SOA", dnsmock.CNAME("example.com.")).
- Query("example.com. SOA", dnsmock.SOA("")).
- Build(t).
- String(),
- },
- },
- {
- desc: "only non-existent nameservers",
- fqdn: "mail.example.com.",
- zone: "example.com.",
- nameservers: []string{":7053", ":8053", ":9053"},
- // use only the start of the message because the port changes with each call: 127.0.0.1:XXXXX->127.0.0.1:7053.
- expectedError: "[fqdn=mail.example.com.] could not find the start of authority for 'mail.example.com.': DNS call error: read udp ",
- },
- {
- desc: "no nameservers",
- fqdn: "test.example.com.",
- zone: "example.com.",
- nameservers: []string{},
- expectedError: "[fqdn=test.example.com.] could not find the start of authority for 'test.example.com.': empty list of nameservers",
- },
- }
+}{
+ {
+ desc: "domain is a CNAME",
+ fqdn: "mail.google.com.",
+ zone: "google.com.",
+ primaryNs: "ns1.google.com.",
+ nameservers: recursiveNameservers,
+ },
+ {
+ desc: "domain is a non-existent subdomain",
+ fqdn: "foo.google.com.",
+ zone: "google.com.",
+ primaryNs: "ns1.google.com.",
+ nameservers: recursiveNameservers,
+ },
+ {
+ desc: "domain is a eTLD",
+ fqdn: "example.com.ac.",
+ zone: "ac.",
+ primaryNs: "a0.nic.ac.",
+ nameservers: recursiveNameservers,
+ },
+ {
+ desc: "domain is a cross-zone CNAME",
+ fqdn: "cross-zone-example.assets.sh.",
+ zone: "assets.sh.",
+ primaryNs: "gina.ns.cloudflare.com.",
+ nameservers: recursiveNameservers,
+ },
+ {
+ desc: "NXDOMAIN",
+ fqdn: "test.lego.zz.",
+ zone: "lego.zz.",
+ nameservers: []string{"8.8.8.8:53"},
+ expectedError: "[fqdn=test.lego.zz.] could not find the start of authority for 'test.lego.zz.' [question='zz. IN SOA', code=NXDOMAIN]",
+ },
+ {
+ desc: "several non existent nameservers",
+ fqdn: "mail.google.com.",
+ zone: "google.com.",
+ primaryNs: "ns1.google.com.",
+ nameservers: []string{":7053", ":8053", "8.8.8.8:53"},
+ },
+ {
+ desc: "only non-existent nameservers",
+ fqdn: "mail.google.com.",
+ zone: "google.com.",
+ nameservers: []string{":7053", ":8053", ":9053"},
+ // use only the start of the message because the port changes with each call: 127.0.0.1:XXXXX->127.0.0.1:7053.
+ expectedError: "[fqdn=mail.google.com.] could not find the start of authority for 'mail.google.com.': DNS call error: read udp ",
+ },
+ {
+ desc: "no nameservers",
+ fqdn: "test.ldez.com.",
+ zone: "ldez.com.",
+ nameservers: []string{},
+ expectedError: "[fqdn=test.ldez.com.] could not find the start of authority for 'test.ldez.com.': empty list of nameservers",
+ },
}
func TestFindZoneByFqdnCustom(t *testing.T) {
- for _, test := range lookupSoaByFqdnTestCases(t) {
+ for _, test := range findXByFqdnTestCases {
t.Run(test.desc, func(t *testing.T) {
ClearFqdnCache()
@@ -252,7 +153,7 @@ func TestFindZoneByFqdnCustom(t *testing.T) {
}
func TestFindPrimaryNsByFqdnCustom(t *testing.T) {
- for _, test := range lookupSoaByFqdnTestCases(t) {
+ for _, test := range findXByFqdnTestCases {
t.Run(test.desc, func(t *testing.T) {
ClearFqdnCache()
@@ -268,7 +169,7 @@ func TestFindPrimaryNsByFqdnCustom(t *testing.T) {
}
}
-func Test_getNameservers_ResolveConfServers(t *testing.T) {
+func TestResolveConfServers(t *testing.T) {
testCases := []struct {
fixture string
expected []string
diff --git a/challenge/dns01/precheck.go b/challenge/dns01/precheck.go
index 45e17e3ac..706e8dbec 100644
--- a/challenge/dns01/precheck.go
+++ b/challenge/dns01/precheck.go
@@ -9,10 +9,6 @@ import (
"github.com/miekg/dns"
)
-// defaultNameserverPort used by authoritative NS.
-// This is for tests only.
-var defaultNameserverPort = "53"
-
// PreCheckFunc checks DNS propagation before notifying ACME that the DNS challenge is ready.
type PreCheckFunc func(fqdn, value string) (bool, error)
@@ -29,7 +25,6 @@ func WrapPreCheck(wrap WrapPreCheckFunc) ChallengeOption {
}
// DisableCompletePropagationRequirement obsolete.
-//
// Deprecated: use DisableAuthoritativeNssPropagationRequirement instead.
func DisableCompletePropagationRequirement() ChallengeOption {
return DisableAuthoritativeNssPropagationRequirement()
@@ -126,7 +121,7 @@ func (p preCheck) checkDNSPropagation(fqdn, value string) (bool, error) {
func checkNameserversPropagation(fqdn, value string, nameservers []string, addPort bool) (bool, error) {
for _, ns := range nameservers {
if addPort {
- ns = net.JoinHostPort(ns, defaultNameserverPort)
+ ns = net.JoinHostPort(ns, "53")
}
r, err := dnsQuery(fqdn, dns.TypeTXT, []string{ns}, false)
@@ -141,11 +136,9 @@ func checkNameserversPropagation(fqdn, value string, nameservers []string, addPo
var records []string
var found bool
-
for _, rr := range r.Answer {
if txt, ok := rr.(*dns.TXT); ok {
record := strings.Join(txt.Txt, "")
-
records = append(records, record)
if record == value {
found = true
diff --git a/challenge/dns01/precheck_test.go b/challenge/dns01/precheck_test.go
index bda8c781e..1f3ecbf7e 100644
--- a/challenge/dns01/precheck_test.go
+++ b/challenge/dns01/precheck_test.go
@@ -3,73 +3,40 @@ package dns01
import (
"testing"
- "github.com/go-acme/lego/v4/platform/tester/dnsmock"
- "github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func Test_preCheck_checkDNSPropagation(t *testing.T) {
- mockResolver(t,
- dnsmock.NewServer().
- Query("ns0.lego.localhost. A",
- dnsmock.Answer(fakeA("ns0.lego.localhost.", "127.0.0.1"))).
- Query("ns1.lego.localhost. A",
- dnsmock.Answer(fakeA("ns1.lego.localhost.", "127.0.0.1"))).
- Query("example.com. TXT",
- dnsmock.Answer(
- fakeTXT("example.com.", "one"),
- fakeTXT("example.com.", "two"),
- fakeTXT("example.com.", "three"),
- fakeTXT("example.com.", "four"),
- fakeTXT("example.com.", "five"),
- ),
- ).
- Build(t),
- )
-
- useAsNameserver(t,
- dnsmock.NewServer().
- Query("acme-staging.api.example.com. SOA", dnsmock.Error(dns.RcodeNameError)).
- Query("api.example.com. SOA", dnsmock.Error(dns.RcodeNameError)).
- Query("example.com. SOA", dnsmock.SOA("")).
- Query("example.com. NS",
- dnsmock.Answer(
- fakeNS("example.com.", "ns0.lego.localhost."),
- fakeNS("example.com.", "ns1.lego.localhost."),
- ),
- ).
- Build(t),
- )
-
+func TestCheckDNSPropagation(t *testing.T) {
testCases := []struct {
- desc string
- fqdn string
- value string
- expectedError string
+ desc string
+ fqdn string
+ value string
+ expectError bool
}{
{
desc: "success",
- fqdn: "example.com.",
- value: "four",
+ fqdn: "postman-echo.com.",
+ value: "postman-domain-verification=c85de626cb79d941310696e06558e2e790223802f3697dfbdcaf65510152d52c",
},
{
- desc: "no matching TXT record",
- fqdn: "acme-staging.api.example.com.",
- value: "fe01=",
- expectedError: "did not return the expected TXT record [fqdn: acme-staging.api.example.com., value: fe01=]: one ,two ,three ,four ,five",
+ desc: "no TXT record",
+ fqdn: "acme-staging.api.letsencrypt.org.",
+ value: "fe01=",
+ expectError: true,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
+ t.Parallel()
ClearFqdnCache()
check := newPreCheck()
ok, err := check.checkDNSPropagation(test.fqdn, test.value)
- if test.expectedError != "" {
- assert.ErrorContainsf(t, err, test.expectedError, "PreCheckDNS must fail for %s", test.fqdn)
+ if test.expectError {
+ assert.Errorf(t, err, "PreCheckDNS must fail for %s", test.fqdn)
assert.False(t, ok, "PreCheckDNS must fail for %s", test.fqdn)
} else {
assert.NoErrorf(t, err, "PreCheckDNS failed for %s", test.fqdn)
@@ -79,67 +46,69 @@ func Test_preCheck_checkDNSPropagation(t *testing.T) {
}
}
-func Test_checkNameserversPropagation_authoritativeNss(t *testing.T) {
+func TestCheckAuthoritativeNss(t *testing.T) {
testCases := []struct {
- desc string
- fqdn, value string
- fakeDNSServer *dnsmock.Builder
- expectedError string
+ desc string
+ fqdn, value string
+ ns []string
+ expected bool
}{
{
- desc: "TXT RR w/ expected value",
- // NS: asnums.routeviews.org.
- fqdn: "8.8.8.8.asn.routeviews.org.",
- value: "151698.8.8.024",
- fakeDNSServer: dnsmock.NewServer().
- Query("8.8.8.8.asn.routeviews.org. TXT",
- dnsmock.Answer(
- fakeTXT("8.8.8.8.asn.routeviews.org.", "151698.8.8.024"),
- ),
- ),
- },
- {
- desc: "TXT RR w/ unexpected value",
- // NS: asnums.routeviews.org.
- fqdn: "8.8.8.8.asn.routeviews.org.",
- value: "fe01=",
- fakeDNSServer: dnsmock.NewServer().
- Query("8.8.8.8.asn.routeviews.org. TXT",
- dnsmock.Answer(
- fakeTXT("8.8.8.8.asn.routeviews.org.", "15169"),
- fakeTXT("8.8.8.8.asn.routeviews.org.", "8.8.8.0"),
- fakeTXT("8.8.8.8.asn.routeviews.org.", "24"),
- ),
- ),
- expectedError: "did not return the expected TXT record [fqdn: 8.8.8.8.asn.routeviews.org., value: fe01=]: 15169 ,8.8.8.0 ,24",
+ desc: "TXT RR w/ expected value",
+ fqdn: "8.8.8.8.asn.routeviews.org.",
+ value: "151698.8.8.024",
+ ns: []string{"asnums.routeviews.org."},
+ expected: true,
},
{
desc: "No TXT RR",
- // NS: ns2.google.com.
- fqdn: "ns1.google.com.",
- value: "fe01=",
- fakeDNSServer: dnsmock.NewServer().
- Query("ns1.google.com.", dnsmock.Noop),
- expectedError: "did not return the expected TXT record [fqdn: ns1.google.com., value: fe01=]: ",
+ fqdn: "ns1.google.com.",
+ ns: []string{"ns2.google.com."},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
+ t.Parallel()
ClearFqdnCache()
- addr := test.fakeDNSServer.Build(t)
-
- ok, err := checkNameserversPropagation(test.fqdn, test.value, []string{addr.String()}, false)
-
- if test.expectedError == "" {
- require.NoError(t, err)
- assert.True(t, ok)
- } else {
- require.Error(t, err)
- require.ErrorContains(t, err, test.expectedError)
- assert.False(t, ok)
- }
+ ok, _ := checkNameserversPropagation(test.fqdn, test.value, test.ns, true)
+ assert.Equal(t, test.expected, ok, test.fqdn)
+ })
+ }
+}
+
+func TestCheckAuthoritativeNssErr(t *testing.T) {
+ testCases := []struct {
+ desc string
+ fqdn, value string
+ ns []string
+ error string
+ }{
+ {
+ desc: "TXT RR /w unexpected value",
+ fqdn: "8.8.8.8.asn.routeviews.org.",
+ value: "fe01=",
+ ns: []string{"asnums.routeviews.org."},
+ error: "did not return the expected TXT record",
+ },
+ {
+ desc: "No TXT RR",
+ fqdn: "ns1.google.com.",
+ value: "fe01=",
+ ns: []string{"ns2.google.com."},
+ error: "did not return the expected TXT record",
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.desc, func(t *testing.T) {
+ t.Parallel()
+ ClearFqdnCache()
+
+ _, err := checkNameserversPropagation(test.fqdn, test.value, test.ns, true)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), test.error)
})
}
}
diff --git a/challenge/http01/domain_matcher.go b/challenge/http01/domain_matcher.go
index 058d1a314..c31aeed6a 100644
--- a/challenge/http01/domain_matcher.go
+++ b/challenge/http01/domain_matcher.go
@@ -88,7 +88,6 @@ func (m *forwardedMatcher) matches(r *http.Request, domain string) bool {
}
host := fwds[0]["host"]
-
return matchDomain(host, domain)
}
@@ -100,7 +99,6 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
inquote := false
pos := 0
-
l := len(s)
for i := 0; i < l; i++ {
r := rune(s[i])
@@ -112,7 +110,6 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
pos = i
inquote = false
}
-
continue
}
@@ -121,7 +118,6 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
if key == "" {
return nil, fmt.Errorf("unexpected quoted string as pos %d", i)
}
-
inquote = true
pos = i + 1
@@ -141,7 +137,6 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
val = s[pos:i]
cur[key] = val
}
-
elements = append(elements, cur)
cur = make(map[string]string)
key = ""
@@ -164,14 +159,11 @@ func parseForwardedHeader(s string) (elements []map[string]string, err error) {
if pos < len(s) {
val = s[pos:]
}
-
cur[key] = val
}
-
if len(cur) > 0 {
elements = append(elements, cur)
}
-
return elements, nil
}
@@ -186,7 +178,6 @@ func skipWS(s string, i int) int {
for isWS(rune(s[i+1])) {
i++
}
-
return i
}
diff --git a/challenge/http01/http_challenge.go b/challenge/http01/http_challenge.go
index a042979c2..79dbfb4d0 100644
--- a/challenge/http01/http_challenge.go
+++ b/challenge/http01/http_challenge.go
@@ -74,7 +74,6 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
if err != nil {
return fmt.Errorf("[%s] acme: error presenting token: %w", domain, err)
}
-
defer func() {
err := c.provider.CleanUp(authz.Identifier.Value, chlng.Token, keyAuth)
if err != nil {
@@ -87,6 +86,5 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
}
chlng.KeyAuthorization = keyAuth
-
return c.validate(c.core, domain, chlng)
}
diff --git a/challenge/http01/http_challenge_server.go b/challenge/http01/http_challenge_server.go
index ab962917e..009271cec 100644
--- a/challenge/http01/http_challenge_server.go
+++ b/challenge/http01/http_challenge_server.go
@@ -44,7 +44,6 @@ func NewUnixProviderServer(socketPath string, mode fs.FileMode) *ProviderServer
// Present starts a web server and makes the token available at `ChallengePath(token)` for web requests.
func (s *ProviderServer) Present(domain, token, keyAuth string) error {
var err error
-
s.listener, err = net.Listen(s.network, s.GetAddress())
if err != nil {
return fmt.Errorf("could not start HTTP server for challenge: %w", err)
@@ -121,7 +120,6 @@ func (s *ProviderServer) serve(domain, token, keyAuth string) {
}
log.Infof("[%s] Served key authentication", domain)
-
return
}
diff --git a/challenge/http01/http_challenge_test.go b/challenge/http01/http_challenge_test.go
index 06c555e42..c29c49068 100644
--- a/challenge/http01/http_challenge_test.go
+++ b/challenge/http01/http_challenge_test.go
@@ -67,7 +67,7 @@ func TestProviderServer_GetAddress(t *testing.T) {
}
func TestChallenge(t *testing.T) {
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
providerServer := NewProviderServer("", "23457")
@@ -88,7 +88,6 @@ func TestChallenge(t *testing.T) {
if err != nil {
return err
}
-
bodyStr := string(body)
if bodyStr != chlng.KeyAuthorization {
@@ -101,7 +100,7 @@ func TestChallenge(t *testing.T) {
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
solver := NewChallenge(core, validate, providerServer)
@@ -124,7 +123,7 @@ func TestChallengeUnix(t *testing.T) {
t.Skip("only for UNIX systems")
}
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
dir := t.TempDir()
t.Cleanup(func() { _ = os.RemoveAll(dir) })
@@ -158,7 +157,6 @@ func TestChallengeUnix(t *testing.T) {
if err != nil {
return err
}
-
bodyStr := string(body)
if bodyStr != chlng.KeyAuthorization {
@@ -171,7 +169,7 @@ func TestChallengeUnix(t *testing.T) {
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
solver := NewChallenge(core, validate, providerServer)
@@ -190,12 +188,12 @@ func TestChallengeUnix(t *testing.T) {
}
func TestChallengeInvalidPort(t *testing.T) {
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
validate := func(_ *api.Core, _ string, _ acme.Challenge) error { return nil }
@@ -226,7 +224,6 @@ func (h *testProxyHeader) update(r *http.Request) {
if h == nil || len(h.values) == 0 {
return
}
-
if h.name == "Host" {
r.Host = h.values[0]
} else if h.name != "" {
@@ -374,7 +371,7 @@ func TestChallengeWithProxy(t *testing.T) {
func testServeWithProxy(t *testing.T, header, extra *testProxyHeader, expectError bool) {
t.Helper()
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
providerServer := NewProviderServer("localhost", "23457")
if header != nil {
@@ -388,7 +385,6 @@ func testServeWithProxy(t *testing.T, header, extra *testProxyHeader, expectErro
if err != nil {
return err
}
-
header.update(req)
extra.update(req)
@@ -406,7 +402,6 @@ func testServeWithProxy(t *testing.T, header, extra *testProxyHeader, expectErro
if err != nil {
return err
}
-
bodyStr := string(body)
if bodyStr != chlng.KeyAuthorization {
@@ -419,7 +414,7 @@ func testServeWithProxy(t *testing.T, header, extra *testProxyHeader, expectErro
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
solver := NewChallenge(core, validate, providerServer)
diff --git a/challenge/resolver/errors.go b/challenge/resolver/errors.go
index 65a6ccdb7..94ccbd76a 100644
--- a/challenge/resolver/errors.go
+++ b/challenge/resolver/errors.go
@@ -3,8 +3,6 @@ package resolver
import (
"bytes"
"fmt"
- "maps"
- "slices"
"sort"
)
@@ -18,16 +16,10 @@ func (e obtainError) Error() string {
for domain := range e {
domains = append(domains, domain)
}
-
sort.Strings(domains)
for _, domain := range domains {
_, _ = fmt.Fprintf(buffer, "[%s] %s\n", domain, e[domain])
}
-
return buffer.String()
}
-
-func (e obtainError) Unwrap() []error {
- return slices.AppendSeq(make([]error, 0, len(e)), maps.Values(e))
-}
diff --git a/challenge/resolver/errors_test.go b/challenge/resolver/errors_test.go
deleted file mode 100644
index d4ab3c481..000000000
--- a/challenge/resolver/errors_test.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package resolver
-
-import (
- "errors"
- "testing"
-
- "github.com/go-acme/lego/v4/acme"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func Test_obtainError_Error(t *testing.T) {
- err := obtainError{
- "a": &acme.ProblemDetails{Type: "001"},
- "b": errors.New("oops"),
- "c": errors.New("I did it again"),
- }
-
- require.EqualError(t, err, `error: one or more domains had a problem:
-[a] acme: error: 0 :: 001 ::
-[b] oops
-[c] I did it again
-`)
-}
-
-func Test_obtainError_Unwrap(t *testing.T) {
- testCases := []struct {
- desc string
- err obtainError
- assert assert.BoolAssertionFunc
- }{
- {
- desc: "one ok",
- err: obtainError{
- "a": &acme.ProblemDetails{},
- "b": errors.New("oops"),
- "c": errors.New("I did it again"),
- },
- assert: assert.True,
- },
- {
- desc: "all ok",
- err: obtainError{
- "a": &acme.ProblemDetails{Type: "001"},
- "b": &acme.ProblemDetails{Type: "002"},
- "c": &acme.ProblemDetails{Type: "002"},
- },
- assert: assert.True,
- },
- {
- desc: "nope",
- err: obtainError{
- "a": errors.New("hello"),
- "b": errors.New("oops"),
- "c": errors.New("I did it again"),
- },
- assert: assert.False,
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- var pd *acme.ProblemDetails
-
- test.assert(t, errors.As(test.err, &pd))
- })
- }
-}
diff --git a/challenge/resolver/prober.go b/challenge/resolver/prober.go
index 66b12c7a7..021facbb5 100644
--- a/challenge/resolver/prober.go
+++ b/challenge/resolver/prober.go
@@ -50,14 +50,11 @@ func NewProber(solverManager *SolverManager) *Prober {
func (p *Prober) Solve(authorizations []acme.Authorization) error {
failures := make(obtainError)
- var (
- authSolvers []*selectedAuthSolver
- authSolversSequential []*selectedAuthSolver
- )
+ var authSolvers []*selectedAuthSolver
+ var authSolversSequential []*selectedAuthSolver
// Loop through the resources, basically through the domains.
// First pass just selects a solver for each authz.
-
for _, authz := range authorizations {
domain := challenge.GetTargetedDomain(authz)
if authz.Status == acme.StatusValid {
@@ -93,88 +90,47 @@ func (p *Prober) Solve(authorizations []acme.Authorization) error {
if len(failures) > 0 {
return failures
}
-
return nil
}
func sequentialSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
- // Some CA are using the same token,
- // this can be a problem with the DNS01 challenge when the DNS provider doesn't support duplicate TXT records.
- // In the sequential mode, this is not a problem because we can solve the challenges in order.
- // But it can reduce the number of call the DNS provider APIs.
- uniq := make(map[string]struct{})
-
for i, authSolver := range authSolvers {
// Submit the challenge
domain := challenge.GetTargetedDomain(authSolver.authz)
- chlg, _ := challenge.FindChallenge(challenge.DNS01, authSolver.authz)
-
if solvr, ok := authSolver.solver.(preSolver); ok {
- if _, ok := uniq[authSolver.authz.Identifier.Value+chlg.Token]; ok && chlg.Token != "" {
- log.Infof("acme: duplicate token for %q (DNS-01); skipping pre-solve.", authSolver.authz.Identifier.Value)
- continue
- }
-
err := solvr.PreSolve(authSolver.authz)
if err != nil {
failures[domain] = err
-
cleanUp(authSolver.solver, authSolver.authz)
-
continue
}
-
- uniq[authSolver.authz.Identifier.Value+chlg.Token] = struct{}{}
}
// Solve challenge
err := authSolver.solver.Solve(authSolver.authz)
if err != nil {
failures[domain] = err
-
cleanUp(authSolver.solver, authSolver.authz)
-
continue
}
- if _, ok := uniq[authSolver.authz.Identifier.Value+chlg.Token]; ok || chlg.Token == "" {
- // Clean challenge
- cleanUp(authSolver.solver, authSolver.authz)
+ // Clean challenge
+ cleanUp(authSolver.solver, authSolver.authz)
- if len(authSolvers)-1 > i {
- solvr := authSolver.solver.(sequential)
- _, interval := solvr.Sequential()
- log.Infof("sequence: wait for %s", interval)
- time.Sleep(interval)
- }
-
- delete(uniq, authSolver.authz.Identifier.Value+chlg.Token)
- } else {
- log.Infof("acme: duplicate token for %q (DNS-01); skipping cleanup.", authSolver.authz.Identifier.Value)
+ if len(authSolvers)-1 > i {
+ solvr := authSolver.solver.(sequential)
+ _, interval := solvr.Sequential()
+ log.Infof("sequence: wait for %s", interval)
+ time.Sleep(interval)
}
}
}
func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
- // Some CA are using the same token,
- // this can be a problem with the DNS01 challenge when the DNS provider doesn't support duplicate TXT records.
- uniq := make(map[string]struct{})
-
// For all valid preSolvers, first submit the challenges, so they have max time to propagate
for _, authSolver := range authSolvers {
authz := authSolver.authz
-
- chlg, err := challenge.FindChallenge(challenge.DNS01, authz)
- if err == nil {
- if _, ok := uniq[authz.Identifier.Value+chlg.Token]; ok {
- log.Infof("acme: duplicate token for %q (DNS-01); skipping pre-solve.", authSolver.authz.Identifier.Value)
- continue
- }
-
- uniq[authz.Identifier.Value+chlg.Token] = struct{}{}
- }
-
if solvr, ok := authSolver.solver.(preSolver); ok {
err := solvr.PreSolve(authz)
if err != nil {
@@ -186,16 +142,6 @@ func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
defer func() {
// Clean all created TXT records
for _, authSolver := range authSolvers {
- chlg, err := challenge.FindChallenge(challenge.DNS01, authSolver.authz)
- if err == nil {
- if _, ok := uniq[authSolver.authz.Identifier.Value+chlg.Token]; ok {
- delete(uniq, authSolver.authz.Identifier.Value+chlg.Token)
- } else {
- log.Infof("acme: duplicate token for %q (DNS-01); skipping cleanup.", authSolver.authz.Identifier.Value)
- continue
- }
- }
-
cleanUp(authSolver.solver, authSolver.authz)
}
}()
@@ -203,7 +149,6 @@ func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
// Finally solve all challenges for real
for _, authSolver := range authSolvers {
authz := authSolver.authz
-
domain := challenge.GetTargetedDomain(authz)
if failures[domain] != nil {
// already failed in previous loop
@@ -220,7 +165,6 @@ func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
func cleanUp(solvr solver, authz acme.Authorization) {
if solvr, ok := solvr.(cleanup); ok {
domain := challenge.GetTargetedDomain(authz)
-
err := solvr.CleanUp(authz)
if err != nil {
log.Warnf("[%s] acme: cleaning up failed: %v ", domain, err)
diff --git a/challenge/resolver/prober_mock_test.go b/challenge/resolver/prober_mock_test.go
index dc7ad8dec..5a91fe075 100644
--- a/challenge/resolver/prober_mock_test.go
+++ b/challenge/resolver/prober_mock_test.go
@@ -1,7 +1,6 @@
package resolver
import (
- "fmt"
"time"
"github.com/go-acme/lego/v4/acme"
@@ -12,68 +11,34 @@ type preSolverMock struct {
preSolve map[string]error
solve map[string]error
cleanUp map[string]error
-
- preSolveCounter int
- solveCounter int
- cleanUpCounter int
}
func (s *preSolverMock) PreSolve(authorization acme.Authorization) error {
- s.preSolveCounter++
-
return s.preSolve[authorization.Identifier.Value]
}
func (s *preSolverMock) Solve(authorization acme.Authorization) error {
- s.solveCounter++
-
return s.solve[authorization.Identifier.Value]
}
func (s *preSolverMock) CleanUp(authorization acme.Authorization) error {
- s.cleanUpCounter++
-
return s.cleanUp[authorization.Identifier.Value]
}
-func (s *preSolverMock) String() string {
- return fmt.Sprintf("PreSolve: %d, Solve: %d, CleanUp: %d", s.preSolveCounter, s.solveCounter, s.cleanUpCounter)
-}
-
func createStubAuthorizationHTTP01(domain, status string) acme.Authorization {
- return createStubAuthorization(domain, status, false, acme.Challenge{
- Type: challenge.HTTP01.String(),
- Validated: time.Now(),
- })
-}
-
-func createStubAuthorizationDNS01(domain string, wildcard bool) acme.Authorization {
- var chlgs []acme.Challenge
-
- if wildcard {
- chlgs = append(chlgs, acme.Challenge{
- Type: challenge.HTTP01.String(),
- Validated: time.Now(),
- })
- }
-
- chlgs = append(chlgs, acme.Challenge{
- Type: challenge.DNS01.String(),
- Validated: time.Now(),
- })
-
- return createStubAuthorization(domain, acme.StatusProcessing, wildcard, chlgs...)
-}
-
-func createStubAuthorization(domain, status string, wildcard bool, chlgs ...acme.Challenge) acme.Authorization {
return acme.Authorization{
- Wildcard: wildcard,
- Status: status,
- Expires: time.Now(),
+ Status: status,
+ Expires: time.Now(),
Identifier: acme.Identifier{
- Type: "dns",
+ Type: challenge.HTTP01.String(),
Value: domain,
},
- Challenges: chlgs,
+ Challenges: []acme.Challenge{
+ {
+ Type: challenge.HTTP01.String(),
+ Validated: time.Now(),
+ Error: nil,
+ },
+ },
}
}
diff --git a/challenge/resolver/prober_test.go b/challenge/resolver/prober_test.go
index 829b16883..4ee9b1b46 100644
--- a/challenge/resolver/prober_test.go
+++ b/challenge/resolver/prober_test.go
@@ -2,22 +2,19 @@ package resolver
import (
"errors"
- "fmt"
"testing"
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/challenge"
- "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestProber_Solve(t *testing.T) {
testCases := []struct {
- desc string
- solvers map[challenge.Type]solver
- authz []acme.Authorization
- expectedError string
- expectedCounters map[challenge.Type]string
+ desc string
+ solvers map[challenge.Type]solver
+ authz []acme.Authorization
+ expectedError string
}{
{
desc: "success",
@@ -29,33 +26,9 @@ func TestProber_Solve(t *testing.T) {
},
},
authz: []acme.Authorization{
- createStubAuthorizationHTTP01("example.com", acme.StatusProcessing),
- createStubAuthorizationHTTP01("example.org", acme.StatusProcessing),
- createStubAuthorizationHTTP01("example.net", acme.StatusProcessing),
- },
- expectedCounters: map[challenge.Type]string{
- challenge.HTTP01: "PreSolve: 3, Solve: 3, CleanUp: 3",
- },
- },
- {
- desc: "DNS-01 deduplicate",
- solvers: map[challenge.Type]solver{
- challenge.DNS01: &preSolverMock{
- preSolve: map[string]error{},
- solve: map[string]error{},
- cleanUp: map[string]error{},
- },
- },
- authz: []acme.Authorization{
- createStubAuthorizationDNS01("a.example", false),
- createStubAuthorizationDNS01("a.example", true),
- createStubAuthorizationDNS01("b.example", false),
- createStubAuthorizationDNS01("b.example", true),
- createStubAuthorizationDNS01("c.example", true),
- createStubAuthorizationDNS01("d.example", false),
- },
- expectedCounters: map[challenge.Type]string{
- challenge.DNS01: "PreSolve: 4, Solve: 6, CleanUp: 4",
+ createStubAuthorizationHTTP01("acme.wtf", acme.StatusProcessing),
+ createStubAuthorizationHTTP01("lego.wtf", acme.StatusProcessing),
+ createStubAuthorizationHTTP01("mydomain.wtf", acme.StatusProcessing),
},
},
{
@@ -68,12 +41,9 @@ func TestProber_Solve(t *testing.T) {
},
},
authz: []acme.Authorization{
- createStubAuthorizationHTTP01("example.com", acme.StatusValid),
- createStubAuthorizationHTTP01("example.org", acme.StatusValid),
- createStubAuthorizationHTTP01("example.net", acme.StatusValid),
- },
- expectedCounters: map[challenge.Type]string{
- challenge.HTTP01: "PreSolve: 0, Solve: 0, CleanUp: 0",
+ createStubAuthorizationHTTP01("acme.wtf", acme.StatusValid),
+ createStubAuthorizationHTTP01("lego.wtf", acme.StatusValid),
+ createStubAuthorizationHTTP01("mydomain.wtf", acme.StatusValid),
},
},
{
@@ -81,56 +51,50 @@ func TestProber_Solve(t *testing.T) {
solvers: map[challenge.Type]solver{
challenge.HTTP01: &preSolverMock{
preSolve: map[string]error{
- "example.com": errors.New("preSolve error example.com"),
+ "acme.wtf": errors.New("preSolve error acme.wtf"),
},
solve: map[string]error{
- "example.com": errors.New("solve error example.com"),
+ "acme.wtf": errors.New("solve error acme.wtf"),
},
cleanUp: map[string]error{
- "example.com": errors.New("clean error example.com"),
+ "acme.wtf": errors.New("clean error acme.wtf"),
},
},
},
authz: []acme.Authorization{
- createStubAuthorizationHTTP01("example.com", acme.StatusProcessing),
- createStubAuthorizationHTTP01("example.org", acme.StatusProcessing),
- createStubAuthorizationHTTP01("example.net", acme.StatusProcessing),
+ createStubAuthorizationHTTP01("acme.wtf", acme.StatusProcessing),
+ createStubAuthorizationHTTP01("lego.wtf", acme.StatusProcessing),
+ createStubAuthorizationHTTP01("mydomain.wtf", acme.StatusProcessing),
},
expectedError: `error: one or more domains had a problem:
-[example.com] preSolve error example.com
+[acme.wtf] preSolve error acme.wtf
`,
- expectedCounters: map[challenge.Type]string{
- challenge.HTTP01: "PreSolve: 3, Solve: 2, CleanUp: 3",
- },
},
{
desc: "errors at different stages",
solvers: map[challenge.Type]solver{
challenge.HTTP01: &preSolverMock{
preSolve: map[string]error{
- "example.com": errors.New("preSolve error example.com"),
+ "acme.wtf": errors.New("preSolve error acme.wtf"),
},
solve: map[string]error{
- "example.com": errors.New("solve error example.com"),
- "example.org": errors.New("solve error example.org"),
+ "acme.wtf": errors.New("solve error acme.wtf"),
+ "lego.wtf": errors.New("solve error lego.wtf"),
},
cleanUp: map[string]error{
- "example.net": errors.New("clean error example.net"),
+ "mydomain.wtf": errors.New("clean error mydomain.wtf"),
},
},
},
authz: []acme.Authorization{
- createStubAuthorizationHTTP01("example.com", acme.StatusProcessing),
- createStubAuthorizationHTTP01("example.org", acme.StatusProcessing),
- createStubAuthorizationHTTP01("example.net", acme.StatusProcessing),
+ createStubAuthorizationHTTP01("acme.wtf", acme.StatusProcessing),
+ createStubAuthorizationHTTP01("lego.wtf", acme.StatusProcessing),
+ createStubAuthorizationHTTP01("mydomain.wtf", acme.StatusProcessing),
},
expectedError: `error: one or more domains had a problem:
-[example.com] preSolve error example.com
-[example.org] solve error example.org
+[acme.wtf] preSolve error acme.wtf
+[lego.wtf] solve error lego.wtf
`,
- expectedCounters: map[challenge.Type]string{
- challenge.HTTP01: "PreSolve: 3, Solve: 2, CleanUp: 3",
- },
},
}
@@ -148,10 +112,6 @@ func TestProber_Solve(t *testing.T) {
} else {
require.NoError(t, err)
}
-
- for n, s := range test.solvers {
- assert.Equal(t, test.expectedCounters[n], fmt.Sprintf("%s", s))
- }
})
}
}
diff --git a/challenge/resolver/solver_manager.go b/challenge/resolver/solver_manager.go
index 87cf6e2d8..dcde3a3ed 100644
--- a/challenge/resolver/solver_manager.go
+++ b/challenge/resolver/solver_manager.go
@@ -1,13 +1,13 @@
package resolver
import (
- "context"
"errors"
"fmt"
"sort"
+ "strconv"
"time"
- "github.com/cenkalti/backoff/v5"
+ "github.com/cenkalti/backoff/v4"
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/acme/api"
"github.com/go-acme/lego/v4/challenge"
@@ -15,7 +15,6 @@ import (
"github.com/go-acme/lego/v4/challenge/http01"
"github.com/go-acme/lego/v4/challenge/tlsalpn01"
"github.com/go-acme/lego/v4/log"
- "github.com/go-acme/lego/v4/platform/wait"
)
type byType []acme.Challenge
@@ -70,7 +69,6 @@ func (c *SolverManager) chooseSolver(authz acme.Authorization) solver {
log.Infof("[%s] acme: use %s solver", domain, chlg.Type)
return solvr
}
-
log.Infof("[%s] acme: Could not find solver for: %s", domain, chlg.Type)
}
@@ -93,20 +91,20 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
return nil
}
- retryAfter, err := api.ParseRetryAfter(chlng.RetryAfter)
- if err != nil || retryAfter == 0 {
+ ra, err := strconv.Atoi(chlng.RetryAfter)
+ if err != nil {
// The ACME server MUST return a Retry-After.
- // If it doesn't, or if it's invalid, we'll just poll hard.
+ // If it doesn't, we'll just poll hard.
// Boulder does not implement the ability to retry challenges or the Retry-After header.
// https://github.com/letsencrypt/boulder/blob/master/docs/acme-divergences.md#section-82
- retryAfter = 5 * time.Second
+ ra = 5
}
-
- ctx := context.Background()
+ initialInterval := time.Duration(ra) * time.Second
bo := backoff.NewExponentialBackOff()
- bo.InitialInterval = retryAfter
- bo.MaxInterval = 10 * retryAfter
+ bo.InitialInterval = initialInterval
+ bo.MaxInterval = 10 * initialInterval
+ bo.MaxElapsedTime = 100 * initialInterval
// After the path is sent, the ACME server will access our server.
// Repeatedly check the server for an updated status on our request.
@@ -129,9 +127,7 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
return fmt.Errorf("the server didn't respond to our request (status=%s)", authz.Status)
}
- return wait.Retry(ctx, operation,
- backoff.WithBackOff(bo),
- backoff.WithMaxElapsedTime(100*retryAfter))
+ return backoff.Retry(operation, bo)
}
func checkChallengeStatus(chlng acme.ExtendedChallenge) (bool, error) {
@@ -161,7 +157,6 @@ func checkAuthorizationStatus(authz acme.Authorization) (bool, error) {
return false, fmt.Errorf("invalid authorization: %w", chlg.Err())
}
}
-
return false, errors.New("invalid authorization")
default:
return false, fmt.Errorf("the server returned an unexpected authorization status: %s", authz.Status)
diff --git a/challenge/resolver/solver_manager_test.go b/challenge/resolver/solver_manager_test.go
index 77149c73a..b1e198d3c 100644
--- a/challenge/resolver/solver_manager_test.go
+++ b/challenge/resolver/solver_manager_test.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/acme/api"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/go-jose/go-jose/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -33,50 +32,66 @@ func TestByType(t *testing.T) {
}
func TestValidate(t *testing.T) {
+ mux, apiURL := tester.SetupFakeAPI(t)
+
var statuses []string
privateKey, _ := rsa.GenerateKey(rand.Reader, 1024)
- server := tester.MockACMEServer().
- Route("POST /chlg",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- if err := validateNoBody(privateKey, req); err != nil {
- http.Error(rw, err.Error(), http.StatusBadRequest)
- return
- }
+ mux.HandleFunc("/chlg", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
+ return
+ }
- rw.Header().Set("Link",
- fmt.Sprintf(`; rel="up"`, req.Context().Value(http.LocalAddrContextKey)))
+ if err := validateNoBody(privateKey, r); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
- st := statuses[0]
- statuses = statuses[1:]
+ w.Header().Set("Link", "<"+apiURL+`/my-authz>; rel="up"`)
- chlg := &acme.Challenge{Type: "http-01", Status: st, URL: "http://example.com/", Token: "token"}
+ st := statuses[0]
+ statuses = statuses[1:]
- servermock.JSONEncode(chlg).ServeHTTP(rw, req)
- })).
- Route("POST /my-authz",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- st := statuses[0]
- statuses = statuses[1:]
+ chlg := &acme.Challenge{Type: "http-01", Status: st, URL: "http://example.com/", Token: "token"}
- authorization := acme.Authorization{
- Status: st,
- Challenges: []acme.Challenge{},
- }
+ err := tester.WriteJSONResponse(w, chlg)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
- if st == acme.StatusInvalid {
- chlg := acme.Challenge{
- Status: acme.StatusInvalid,
- }
- authorization.Challenges = append(authorization.Challenges, chlg)
- }
+ mux.HandleFunc("/my-authz", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
+ return
+ }
- servermock.JSONEncode(authorization).ServeHTTP(rw, req)
- })).
- BuildHTTPS(t)
+ st := statuses[0]
+ statuses = statuses[1:]
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ authorization := acme.Authorization{
+ Status: st,
+ Challenges: []acme.Challenge{},
+ }
+
+ if st == acme.StatusInvalid {
+ chlg := acme.Challenge{
+ Status: acme.StatusInvalid,
+ }
+ authorization.Challenges = append(authorization.Challenges, chlg)
+ }
+
+ err := tester.WriteJSONResponse(w, authorization)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
+
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
testCases := []struct {
@@ -118,7 +133,7 @@ func TestValidate(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
statuses = test.statuses
- err := validate(core, "example.com", acme.Challenge{Type: "http-01", Token: "token", URL: server.URL + "/chlg"})
+ err := validate(core, "example.com", acme.Challenge{Type: "http-01", Token: "token", URL: apiURL + "/chlg"})
if test.want == "" {
require.NoError(t, err)
} else {
@@ -260,7 +275,6 @@ func validateNoBody(privateKey *rsa.PrivateKey, r *http.Request) error {
}
sigAlgs := []jose.SignatureAlgorithm{jose.RS256}
-
jws, err := jose.ParseSigned(string(reqBody), sigAlgs)
if err != nil {
return err
@@ -277,6 +291,5 @@ func validateNoBody(privateKey *rsa.PrivateKey, r *http.Request) error {
if bodyStr := string(body); bodyStr != "{}" && bodyStr != "" {
return fmt.Errorf(`expected JWS POST body "{}" or "", got %q`, bodyStr)
}
-
return nil
}
diff --git a/challenge/tlsalpn01/tls_alpn_challenge.go b/challenge/tlsalpn01/tls_alpn_challenge.go
index d8e939106..559e1f905 100644
--- a/challenge/tlsalpn01/tls_alpn_challenge.go
+++ b/challenge/tlsalpn01/tls_alpn_challenge.go
@@ -80,7 +80,6 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
if err != nil {
return fmt.Errorf("[%s] acme: error presenting token: %w", challenge.GetTargetedDomain(authz), err)
}
-
defer func() {
err := c.provider.CleanUp(domain, chlng.Token, keyAuth)
if err != nil {
@@ -93,7 +92,6 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
}
chlng.KeyAuthorization = keyAuth
-
return c.validate(c.core, domain, chlng)
}
diff --git a/challenge/tlsalpn01/tls_alpn_challenge_test.go b/challenge/tlsalpn01/tls_alpn_challenge_test.go
index 59c2d61bc..9f65742f3 100644
--- a/challenge/tlsalpn01/tls_alpn_challenge_test.go
+++ b/challenge/tlsalpn01/tls_alpn_challenge_test.go
@@ -8,6 +8,7 @@ import (
"crypto/tls"
"encoding/asn1"
"net"
+ "net/http"
"testing"
"github.com/go-acme/lego/v4/acme"
@@ -20,7 +21,7 @@ import (
)
func TestChallenge(t *testing.T) {
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
domain := "localhost"
port := "24457"
@@ -42,7 +43,6 @@ func TestChallenge(t *testing.T) {
assert.NotEmpty(t, remoteCert.Extensions, "Expected the challenge certificate to contain extensions")
idx := -1
-
for i, ext := range remoteCert.Extensions {
if idPeAcmeIdentifierV1.Equal(ext.Id) {
idx = i
@@ -69,7 +69,7 @@ func TestChallenge(t *testing.T) {
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
solver := NewChallenge(
@@ -93,12 +93,12 @@ func TestChallenge(t *testing.T) {
}
func TestChallengeInvalidPort(t *testing.T) {
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
solver := NewChallenge(
@@ -123,7 +123,7 @@ func TestChallengeInvalidPort(t *testing.T) {
}
func TestChallengeIPaddress(t *testing.T) {
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
domain := "127.0.0.1"
port := "24457"
@@ -146,24 +146,18 @@ func TestChallengeIPaddress(t *testing.T) {
assert.True(t, net.ParseIP("127.0.0.1").Equal(remoteCert.IPAddresses[0]), "challenge certificate IPAddress ")
assert.NotEmpty(t, remoteCert.Extensions, "Expected the challenge certificate to contain extensions")
- var (
- foundAcmeIdentifier bool
- extValue []byte
- )
-
+ var foundAcmeIdentifier bool
+ var extValue []byte
for _, ext := range remoteCert.Extensions {
if idPeAcmeIdentifierV1.Equal(ext.Id) {
assert.True(t, ext.Critical, "Expected the challenge certificate id-pe-acmeIdentifier extension to be marked as critical")
-
foundAcmeIdentifier = true
extValue = ext.Value
-
break
}
}
require.True(t, foundAcmeIdentifier, "Expected the challenge certificate to contain an extension with the id-pe-acmeIdentifier id,")
-
zBytes := sha256.Sum256([]byte(chlng.KeyAuthorization))
value, err := asn1.Marshal(zBytes[:sha256.Size])
require.NoError(t, err, "Expected marshaling of the keyAuth to return no error")
@@ -176,7 +170,7 @@ func TestChallengeIPaddress(t *testing.T) {
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", privateKey)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", privateKey)
require.NoError(t, err)
solver := NewChallenge(
diff --git a/cmd/accounts_storage.go b/cmd/accounts_storage.go
index 01db2faf8..b3e4986dd 100644
--- a/cmd/accounts_storage.go
+++ b/cmd/accounts_storage.go
@@ -2,8 +2,10 @@ package cmd
import (
"crypto"
+ "crypto/x509"
"encoding/json"
"encoding/pem"
+ "errors"
"net/url"
"os"
"path/filepath"
@@ -16,8 +18,6 @@ import (
"github.com/urfave/cli/v2"
)
-const userIDPlaceholder = "noemail@example.com"
-
const (
baseAccountsRootFolderName = "accounts"
baseKeysFolderName = "keys"
@@ -34,7 +34,7 @@ const (
//
// rootUserPath:
//
-// ./.lego/accounts/localhost_14000/foo@example.com/
+// ./.lego/accounts/localhost_14000/hubert@hubert.com/
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
// │ └── root accounts directory
@@ -42,7 +42,7 @@ const (
//
// keysPath:
//
-// ./.lego/accounts/localhost_14000/foo@example.com/keys/
+// ./.lego/accounts/localhost_14000/hubert@hubert.com/keys/
// │ │ │ │ └── root keys directory
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
@@ -51,7 +51,7 @@ const (
//
// accountFilePath:
//
-// ./.lego/accounts/localhost_14000/foo@example.com/account.json
+// ./.lego/accounts/localhost_14000/hubert@hubert.com/account.json
// │ │ │ │ └── account file
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
@@ -59,7 +59,6 @@ const (
// └── "path" option
type AccountsStorage struct {
userID string
- email string
rootPath string
rootUserPath string
keysPath string
@@ -69,13 +68,8 @@ type AccountsStorage struct {
// NewAccountsStorage Creates a new AccountsStorage.
func NewAccountsStorage(ctx *cli.Context) *AccountsStorage {
- // TODO: move to account struct?
- email := ctx.String(flgEmail)
-
- userID := email
- if userID == "" {
- userID = userIDPlaceholder
- }
+ // TODO: move to account struct? Currently MUST pass email.
+ email := getEmail(ctx)
serverURL, err := url.Parse(ctx.String(flgServer))
if err != nil {
@@ -85,11 +79,10 @@ func NewAccountsStorage(ctx *cli.Context) *AccountsStorage {
rootPath := filepath.Join(ctx.String(flgPath), baseAccountsRootFolderName)
serverPath := strings.NewReplacer(":", "_", "/", string(os.PathSeparator)).Replace(serverURL.Host)
accountsPath := filepath.Join(rootPath, serverPath)
- rootUserPath := filepath.Join(accountsPath, userID)
+ rootUserPath := filepath.Join(accountsPath, email)
return &AccountsStorage{
- userID: userID,
- email: email,
+ userID: email,
rootPath: rootPath,
rootUserPath: rootUserPath,
keysPath: filepath.Join(rootUserPath, baseKeysFolderName),
@@ -105,7 +98,6 @@ func (s *AccountsStorage) ExistsAccountFilePath() bool {
} else if err != nil {
log.Fatal(err)
}
-
return true
}
@@ -121,10 +113,6 @@ func (s *AccountsStorage) GetUserID() string {
return s.userID
}
-func (s *AccountsStorage) GetEmail() string {
- return s.email
-}
-
func (s *AccountsStorage) Save(account *Account) error {
jsonBytes, err := json.MarshalIndent(account, "", "\t")
if err != nil {
@@ -137,14 +125,13 @@ func (s *AccountsStorage) Save(account *Account) error {
func (s *AccountsStorage) LoadAccount(privateKey crypto.PrivateKey) *Account {
fileBytes, err := os.ReadFile(s.accountFilePath)
if err != nil {
- log.Fatalf("Could not load file for account %s: %v", s.GetUserID(), err)
+ log.Fatalf("Could not load file for account %s: %v", s.userID, err)
}
var account Account
-
err = json.Unmarshal(fileBytes, &account)
if err != nil {
- log.Fatalf("Could not parse file for account %s: %v", s.GetUserID(), err)
+ log.Fatalf("Could not parse file for account %s: %v", s.userID, err)
}
account.key = privateKey
@@ -152,14 +139,13 @@ func (s *AccountsStorage) LoadAccount(privateKey crypto.PrivateKey) *Account {
if account.Registration == nil || account.Registration.Body.Status == "" {
reg, err := tryRecoverRegistration(s.ctx, privateKey)
if err != nil {
- log.Fatalf("Could not load account for %s. Registration is nil: %#v", s.GetUserID(), err)
+ log.Fatalf("Could not load account for %s. Registration is nil: %#v", s.userID, err)
}
account.Registration = reg
-
err = s.Save(&account)
if err != nil {
- log.Fatalf("Could not save account for %s. Registration is nil: %#v", s.GetUserID(), err)
+ log.Fatalf("Could not save account for %s. Registration is nil: %#v", s.userID, err)
}
}
@@ -167,19 +153,18 @@ func (s *AccountsStorage) LoadAccount(privateKey crypto.PrivateKey) *Account {
}
func (s *AccountsStorage) GetPrivateKey(keyType certcrypto.KeyType) crypto.PrivateKey {
- accKeyPath := filepath.Join(s.keysPath, s.GetUserID()+".key")
+ accKeyPath := filepath.Join(s.keysPath, s.userID+".key")
if _, err := os.Stat(accKeyPath); os.IsNotExist(err) {
- log.Printf("No key found for account %s. Generating a %s key.", s.GetUserID(), keyType)
+ log.Printf("No key found for account %s. Generating a %s key.", s.userID, keyType)
s.createKeysFolder()
privateKey, err := generatePrivateKey(accKeyPath, keyType)
if err != nil {
- log.Fatalf("Could not generate RSA private account key for account %s: %v", s.GetUserID(), err)
+ log.Fatalf("Could not generate RSA private account key for account %s: %v", s.userID, err)
}
log.Printf("Saved key to %s", accKeyPath)
-
return privateKey
}
@@ -193,7 +178,7 @@ func (s *AccountsStorage) GetPrivateKey(keyType certcrypto.KeyType) crypto.Priva
func (s *AccountsStorage) createKeysFolder() {
if err := createNonExistingFolder(s.keysPath); err != nil {
- log.Fatalf("Could not check/create directory for account %s: %v", s.GetUserID(), err)
+ log.Fatalf("Could not check/create directory for account %s: %v", s.userID, err)
}
}
@@ -210,7 +195,6 @@ func generatePrivateKey(file string, keyType certcrypto.KeyType) (crypto.Private
defer certOut.Close()
pemKey := certcrypto.PEMBlock(privateKey)
-
err = pem.Encode(certOut, pemKey)
if err != nil {
return nil, err
@@ -225,12 +209,16 @@ func loadPrivateKey(file string) (crypto.PrivateKey, error) {
return nil, err
}
- privateKey, err := certcrypto.ParsePEMPrivateKey(keyBytes)
- if err != nil {
- return nil, err
+ keyBlock, _ := pem.Decode(keyBytes)
+
+ switch keyBlock.Type {
+ case "RSA PRIVATE KEY":
+ return x509.ParsePKCS1PrivateKey(keyBlock.Bytes)
+ case "EC PRIVATE KEY":
+ return x509.ParseECPrivateKey(keyBlock.Bytes)
}
- return privateKey, nil
+ return nil, errors.New("unknown private key type")
}
func tryRecoverRegistration(ctx *cli.Context, privateKey crypto.PrivateKey) (*registration.Resource, error) {
@@ -248,6 +236,5 @@ func tryRecoverRegistration(ctx *cli.Context, privateKey crypto.PrivateKey) (*re
if err != nil {
return nil, err
}
-
return reg, nil
}
diff --git a/cmd/certs_storage.go b/cmd/certs_storage.go
index 25ef58075..f9bcdade8 100644
--- a/cmd/certs_storage.go
+++ b/cmd/certs_storage.go
@@ -2,6 +2,7 @@ package cmd
import (
"bytes"
+ "crypto"
"crypto/x509"
"encoding/json"
"encoding/pem"
@@ -158,7 +159,6 @@ func (s *CertificatesStorage) ExistsFile(domain, extension string) bool {
} else if err != nil {
log.Fatal(err)
}
-
return true
}
@@ -233,9 +233,27 @@ func (s *CertificatesStorage) WritePFXFile(domain string, certRes *certificate.R
return fmt.Errorf("unable to get certificate chain for domain %s: %w", domain, err)
}
- privateKey, err := certcrypto.ParsePEMPrivateKey(certRes.PrivateKey)
- if err != nil {
- return fmt.Errorf("unable to parse PrivateKey for domain %s: %w", domain, err)
+ keyPemBlock, _ := pem.Decode(certRes.PrivateKey)
+ if keyPemBlock == nil {
+ return fmt.Errorf("unable to parse PrivateKey for domain %s", domain)
+ }
+
+ var privateKey crypto.Signer
+ var keyErr error
+
+ switch keyPemBlock.Type {
+ case "RSA PRIVATE KEY":
+ privateKey, keyErr = x509.ParsePKCS1PrivateKey(keyPemBlock.Bytes)
+ if keyErr != nil {
+ return fmt.Errorf("unable to load RSA PrivateKey for domain %s: %w", domain, keyErr)
+ }
+ case "EC PRIVATE KEY":
+ privateKey, keyErr = x509.ParseECPrivateKey(keyPemBlock.Bytes)
+ if keyErr != nil {
+ return fmt.Errorf("unable to load EC PrivateKey for domain %s: %w", domain, keyErr)
+ }
+ default:
+ return fmt.Errorf("unsupported PrivateKey type '%s' for domain %s", keyPemBlock.Type, domain)
}
encoder, err := getPFXEncoder(s.pfxFormat)
@@ -284,7 +302,6 @@ func getCertificateChain(certRes *certificate.Resource) ([]*x509.Certificate, er
}
var certChain []*x509.Certificate
-
for chainCertPemBlock != nil {
chainCert, err := x509.ParseCertificate(chainCertPemBlock.Bytes)
if err != nil {
@@ -300,7 +317,6 @@ func getCertificateChain(certRes *certificate.Resource) ([]*x509.Certificate, er
func getPFXEncoder(pfxFormat string) (*pkcs12.Encoder, error) {
var encoder *pkcs12.Encoder
-
switch pfxFormat {
case "SHA256":
encoder = pkcs12.Modern2023
@@ -321,6 +337,5 @@ func sanitizedDomain(domain string) string {
if err != nil {
log.Fatal(err)
}
-
return safe
}
diff --git a/cmd/cmd_list.go b/cmd/cmd_list.go
index 53cd12c3c..bf7b232da 100644
--- a/cmd/cmd_list.go
+++ b/cmd/cmd_list.go
@@ -3,7 +3,6 @@ package cmd
import (
"encoding/json"
"fmt"
- "net"
"net/url"
"os"
"path/filepath"
@@ -37,7 +36,7 @@ func createList() *cli.Command {
// fake email, needed by NewAccountsStorage
&cli.StringFlag{
Name: flgEmail,
- Value: "",
+ Value: "unknown",
Hidden: true,
},
},
@@ -68,7 +67,6 @@ func listCertificates(ctx *cli.Context) error {
if !names {
fmt.Println("No certificates found.")
}
-
return nil
}
@@ -101,11 +99,6 @@ func listCertificates(ctx *cli.Context) error {
} else {
fmt.Println(" Certificate Name:", name)
fmt.Println(" Domains:", strings.Join(pCert.DNSNames, ", "))
-
- if len(pCert.IPAddresses) > 0 {
- fmt.Println(" IPs:", formatIPAddresses(pCert.IPAddresses))
- }
-
fmt.Println(" Expiry Date:", pCert.NotAfter)
fmt.Println(" Certificate Path:", filename)
fmt.Println()
@@ -129,7 +122,6 @@ func listAccount(ctx *cli.Context) error {
}
fmt.Println("Found the following accounts:")
-
for _, filename := range matches {
data, err := os.ReadFile(filename)
if err != nil {
@@ -137,7 +129,6 @@ func listAccount(ctx *cli.Context) error {
}
var account Account
-
err = json.Unmarshal(data, &account)
if err != nil {
return err
@@ -156,12 +147,3 @@ func listAccount(ctx *cli.Context) error {
return nil
}
-
-func formatIPAddresses(ipAddresses []net.IP) string {
- var ips []string
- for _, ip := range ipAddresses {
- ips = append(ips, ip.String())
- }
-
- return strings.Join(ips, ", ")
-}
diff --git a/cmd/cmd_renew.go b/cmd/cmd_renew.go
index 4b41ebc78..00bdf1b62 100644
--- a/cmd/cmd_renew.go
+++ b/cmd/cmd_renew.go
@@ -39,20 +39,16 @@ func createRenew() *cli.Command {
Before: func(ctx *cli.Context) error {
// we require either domains or csr, but not both
hasDomains := len(ctx.StringSlice(flgDomains)) > 0
-
hasCsr := ctx.String(flgCSR) != ""
if hasDomains && hasCsr {
log.Fatalf("Please specify either --%s/-d or --%s/-c, but not both", flgDomains, flgCSR)
}
-
if !hasDomains && !hasCsr {
log.Fatalf("Please specify --%s/-d (or --%s/-c if you already have a CSR)", flgDomains, flgCSR)
}
-
if ctx.Bool(flgForceCertDomains) && hasCsr {
log.Fatalf("--%s only works with --%s/-d, --%s/-c doesn't support this option.", flgForceCertDomains, flgDomains, flgCSR)
}
-
return nil
},
Flags: []cli.Flag{
@@ -105,7 +101,7 @@ func createRenew() *cli.Command {
},
&cli.StringFlag{
Name: flgProfile,
- Usage: "If the CA offers multiple certificate profiles (draft-ietf-acme-profiles), choose this one.",
+ Usage: "If the CA offers multiple certificate profiles (draft-aaron-acme-profiles), choose this one.",
},
&cli.StringFlag{
Name: flgAlwaysDeactivateAuthorizations,
@@ -144,9 +140,7 @@ func renew(ctx *cli.Context) error {
bundle := !ctx.Bool(flgNoBundle)
- meta := map[string]string{
- hookEnvAccountEmail: account.Email,
- }
+ meta := map[string]string{hookEnvAccountEmail: account.Email}
// CSR
if ctx.IsSet(flgCSR) {
@@ -171,10 +165,8 @@ func renewForDomains(ctx *cli.Context, account *Account, keyType certcrypto.KeyT
cert := certificates[0]
- var (
- ariRenewalTime *time.Time
- replacesCertID string
- )
+ var ariRenewalTime *time.Time
+ var replacesCertID string
var client *lego.Client
@@ -216,7 +208,6 @@ func renewForDomains(ctx *cli.Context, account *Account, keyType certcrypto.KeyT
log.Infof("[%s] acme: Trying renewal with %d hours remaining", domain, int(timeLeft.Hours()))
var privateKey crypto.PrivateKey
-
if ctx.Bool(flgReuseKey) {
keyBytes, errR := certsStorage.ReadFile(domain, keyExt)
if errR != nil {
@@ -234,7 +225,6 @@ func renewForDomains(ctx *cli.Context, account *Account, keyType certcrypto.KeyT
if !isatty.IsTerminal(os.Stdout.Fd()) && !ctx.Bool(flgNoRandomSleep) {
// https://github.com/certbot/certbot/blob/284023a1b7672be2bd4018dd7623b3b92197d4b0/certbot/certbot/_internal/renewal.py#L472
const jitter = 8 * time.Minute
-
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
sleepTime := time.Duration(rnd.Int63n(int64(jitter)))
@@ -298,10 +288,8 @@ func renewForCSR(ctx *cli.Context, account *Account, keyType certcrypto.KeyType,
cert := certificates[0]
- var (
- ariRenewalTime *time.Time
- replacesCertID string
- )
+ var ariRenewalTime *time.Time
+ var replacesCertID string
var client *lego.Client
@@ -369,7 +357,7 @@ func needRenewal(x509Cert *x509.Certificate, domain string, days int, dynamic bo
}
if dynamic {
- return needRenewalDynamic(x509Cert, domain, time.Now())
+ return needRenewalDynamic(x509Cert, time.Now())
}
if days < 0 {
@@ -387,7 +375,7 @@ func needRenewal(x509Cert *x509.Certificate, domain string, days int, dynamic bo
return false
}
-func needRenewalDynamic(x509Cert *x509.Certificate, domain string, now time.Time) bool {
+func needRenewalDynamic(x509Cert *x509.Certificate, now time.Time) bool {
lifetime := x509Cert.NotAfter.Sub(x509Cert.NotBefore)
var divisor int64 = 3
@@ -397,14 +385,7 @@ func needRenewalDynamic(x509Cert *x509.Certificate, domain string, now time.Time
dueDate := x509Cert.NotAfter.Add(-1 * time.Duration(lifetime.Nanoseconds()/divisor))
- if dueDate.Before(now) {
- return true
- }
-
- log.Infof("[%s] The certificate expires at %s, the renewal can be performed in %s: no renewal.",
- domain, x509Cert.NotAfter.Format(time.RFC3339), dueDate.Sub(now))
-
- return false
+ return dueDate.Before(now)
}
// getARIRenewalTime checks if the certificate needs to be renewed using the renewalInfo endpoint.
@@ -420,20 +401,16 @@ func getARIRenewalTime(ctx *cli.Context, cert *x509.Certificate, domain string,
log.Warnf("[%s] acme: %v", domain, err)
return nil
}
-
log.Warnf("[%s] acme: calling renewal info endpoint: %v", domain, err)
-
return nil
}
now := time.Now().UTC()
-
renewalTime := renewalInfo.ShouldRenewAt(now, ctx.Duration(flgARIWaitToRenewDuration))
if renewalTime == nil {
log.Infof("[%s] acme: renewalInfo endpoint indicates that renewal is not needed", domain)
return nil
}
-
log.Infof("[%s] acme: renewalInfo endpoint indicates that renewal is needed", domain)
if renewalInfo.ExplanationURL != "" {
diff --git a/cmd/cmd_renew_test.go b/cmd/cmd_renew_test.go
index 2485c5240..405dda5fa 100644
--- a/cmd/cmd_renew_test.go
+++ b/cmd/cmd_renew_test.go
@@ -161,7 +161,7 @@ func Test_needRenewalDynamic(t *testing.T) {
NotAfter: test.notAfter,
}
- ok := needRenewalDynamic(x509Cert, "example.com", test.now)
+ ok := needRenewalDynamic(x509Cert, test.now)
test.expected(t, ok)
})
diff --git a/cmd/cmd_run.go b/cmd/cmd_run.go
index 5924c4b66..8135e3546 100644
--- a/cmd/cmd_run.go
+++ b/cmd/cmd_run.go
@@ -35,16 +35,13 @@ func createRun() *cli.Command {
Before: func(ctx *cli.Context) error {
// we require either domains or csr, but not both
hasDomains := len(ctx.StringSlice(flgDomains)) > 0
-
hasCsr := ctx.String(flgCSR) != ""
if hasDomains && hasCsr {
log.Fatal("Please specify either --domains/-d or --csr/-c, but not both")
}
-
if !hasDomains && !hasCsr {
log.Fatal("Please specify --domains/-d (or --csr/-c if you already have a CSR)")
}
-
return nil
},
Action: run,
@@ -79,7 +76,7 @@ func createRun() *cli.Command {
},
&cli.StringFlag{
Name: flgProfile,
- Usage: "If the CA offers multiple certificate profiles (draft-ietf-acme-profiles), choose this one.",
+ Usage: "If the CA offers multiple certificate profiles (draft-aaron-acme-profiles), choose this one.",
},
&cli.StringFlag{
Name: flgAlwaysDeactivateAuthorizations,
@@ -104,9 +101,9 @@ Your account credentials have been saved in your
configuration directory at "%s".
You should make a secure backup of this folder now. This
-configuration directory will also contain private keys
-generated by lego and certificates obtained from the ACME
-server. Making regular backups of this folder is ideal.
+configuration directory will also contain certificates and
+private keys obtained from the ACME server so making regular
+backups of this folder is ideal.
`
func run(ctx *cli.Context) error {
@@ -158,12 +155,10 @@ func handleTOS(ctx *cli.Context, client *lego.Client) bool {
}
reader := bufio.NewReader(os.Stdin)
-
log.Printf("Please review the TOS at %s", client.GetToSURL())
for {
fmt.Println("Do you accept the TOS? Y/n")
-
text, err := reader.ReadString('\n')
if err != nil {
log.Fatalf("Could not read from console: %v", err)
@@ -224,7 +219,6 @@ func obtainCertificate(ctx *cli.Context, client *lego.Client) (*certificate.Reso
if ctx.IsSet(flgPrivateKey) {
var err error
-
request.PrivateKey, err = loadPrivateKey(ctx.String(flgPrivateKey))
if err != nil {
return nil, fmt.Errorf("load private key: %w", err)
@@ -253,7 +247,6 @@ func obtainCertificate(ctx *cli.Context, client *lego.Client) (*certificate.Reso
if ctx.IsSet(flgPrivateKey) {
var err error
-
request.PrivateKey, err = loadPrivateKey(ctx.String(flgPrivateKey))
if err != nil {
return nil, fmt.Errorf("load private key: %w", err)
diff --git a/cmd/flags.go b/cmd/flags.go
index c7e8371b6..4ceccbdd9 100644
--- a/cmd/flags.go
+++ b/cmd/flags.go
@@ -90,8 +90,9 @@ func CreateFlags(defaultPath string) []cli.Flag {
Usage: "Email used for registration and recovery contact.",
},
&cli.BoolFlag{
- Name: flgDisableCommonName,
- Usage: "Disable the use of the common name in the CSR.",
+ Name: flgDisableCommonName,
+ EnvVars: []string{flgDisableCommonName},
+ Usage: "Disable the use of the common name in the CSR.",
},
&cli.StringFlag{
Name: flgCSR,
@@ -258,6 +259,5 @@ func getTime(ctx *cli.Context, name string) time.Time {
if value == nil {
return time.Time{}
}
-
return *value
}
diff --git a/cmd/hook.go b/cmd/hook.go
index 7883108b6..c1de29c58 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -34,7 +34,6 @@ func launchHook(hook string, timeout time.Duration, meta map[string]string) erro
parts := strings.Fields(hook)
cmd := exec.CommandContext(ctxCmd, parts[0], parts[1:]...)
-
cmd.Env = append(os.Environ(), metaToEnv(meta)...)
stdout, err := cmd.StdoutPipe()
@@ -51,7 +50,6 @@ func launchHook(hook string, timeout time.Duration, meta map[string]string) erro
go func() {
<-ctxCmd.Done()
-
if ctxCmd.Err() != nil {
_ = cmd.Process.Kill()
_ = stdout.Close()
diff --git a/cmd/lego/main.go b/cmd/lego/main.go
index c301a51f1..61a3d532a 100644
--- a/cmd/lego/main.go
+++ b/cmd/lego/main.go
@@ -26,7 +26,6 @@ func main() {
}
var defaultPath string
-
cwd, err := os.Getwd()
if err == nil {
defaultPath = filepath.Join(cwd, ".lego")
diff --git a/cmd/lego/zz_gen_version.go b/cmd/lego/zz_gen_version.go
index cf9ad00ef..6b3086baa 100644
--- a/cmd/lego/zz_gen_version.go
+++ b/cmd/lego/zz_gen_version.go
@@ -2,7 +2,7 @@
package main
-const defaultVersion = "v4.32.0+dev-detach"
+const defaultVersion = "v4.25.1+dev-release"
var version = ""
diff --git a/cmd/setup.go b/cmd/setup.go
index 6d15adad3..fd8038464 100644
--- a/cmd/setup.go
+++ b/cmd/setup.go
@@ -1,18 +1,14 @@
package cmd
import (
- "context"
"crypto/x509"
- "encoding/json"
"encoding/pem"
"fmt"
- "io"
"net/http"
"os"
"strings"
"time"
- "github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/log"
@@ -40,7 +36,7 @@ func setupAccount(ctx *cli.Context, accountsStorage *AccountsStorage) (*Account,
if accountsStorage.ExistsAccountFilePath() {
account = accountsStorage.LoadAccount(privateKey)
} else {
- account = &Account{Email: accountsStorage.GetEmail(), key: privateKey}
+ account = &Account{Email: accountsStorage.GetUserID(), key: privateKey}
}
return account, keyType
@@ -74,7 +70,6 @@ func newClient(ctx *cli.Context, acc registration.User, keyType certcrypto.KeyTy
retryClient := retryablehttp.NewClient()
retryClient.RetryMax = 5
retryClient.HTTPClient = config.HTTPClient
- retryClient.CheckRetry = checkRetry
retryClient.Logger = nil
if _, v := os.LookupEnv("LEGO_DEBUG_ACME_HTTP_CLIENT"); v {
@@ -114,10 +109,17 @@ func getKeyType(ctx *cli.Context) certcrypto.KeyType {
}
log.Fatalf("Unsupported KeyType: %s", keyType)
-
return ""
}
+func getEmail(ctx *cli.Context) string {
+ email := ctx.String(flgEmail)
+ if email == "" {
+ log.Fatalf("You have to pass an account (email address) to the program using --%s or -m", flgEmail)
+ }
+ return email
+}
+
func getUserAgent(ctx *cli.Context) string {
return strings.TrimSpace(fmt.Sprintf("%s lego-cli/%s", ctx.String(flgUserAgent), ctx.App.Version))
}
@@ -128,7 +130,6 @@ func createNonExistingFolder(path string) error {
} else if err != nil {
return err
}
-
return nil
}
@@ -137,12 +138,10 @@ func readCSRFile(filename string) (*x509.CertificateRequest, error) {
if err != nil {
return nil, err
}
-
raw := bytes
// see if we can find a PEM-encoded CSR
var p *pem.Block
-
rest := bytes
for {
// decode a PEM block
@@ -164,49 +163,3 @@ func readCSRFile(filename string) (*x509.CertificateRequest, error) {
// (if this assumption is wrong, parsing these bytes will fail)
return x509.ParseCertificateRequest(raw)
}
-
-func checkRetry(ctx context.Context, resp *http.Response, err error) (bool, error) {
- rt, err := retryablehttp.ErrorPropagatedRetryPolicy(ctx, resp, err)
- if err != nil {
- return rt, err
- }
-
- if resp == nil {
- return rt, nil
- }
-
- if resp.StatusCode/100 == 2 {
- return rt, nil
- }
-
- all, err := io.ReadAll(resp.Body)
- if err == nil {
- var errorDetails *acme.ProblemDetails
-
- err = json.Unmarshal(all, &errorDetails)
- if err != nil {
- return rt, fmt.Errorf("%s %s: %s", resp.Request.Method, resp.Request.URL.Redacted(), string(all))
- }
-
- switch errorDetails.Type {
- case acme.BadNonceErr:
- return false, &acme.NonceError{
- ProblemDetails: errorDetails,
- }
-
- case acme.AlreadyReplacedErr:
- if errorDetails.HTTPStatus == http.StatusConflict {
- return false, &acme.AlreadyReplacedError{
- ProblemDetails: errorDetails,
- }
- }
-
- default:
- log.Warnf("retry: %v", errorDetails)
-
- return rt, errorDetails
- }
- }
-
- return rt, nil
-}
diff --git a/cmd/setup_challenges.go b/cmd/setup_challenges.go
index 6968c7ba3..c923fa004 100644
--- a/cmd/setup_challenges.go
+++ b/cmd/setup_challenges.go
@@ -54,21 +54,18 @@ func setupHTTPProvider(ctx *cli.Context) challenge.Provider {
if err != nil {
log.Fatal(err)
}
-
return ps
case ctx.IsSet(flgHTTPMemcachedHost):
ps, err := memcached.NewMemcachedProvider(ctx.StringSlice(flgHTTPMemcachedHost))
if err != nil {
log.Fatal(err)
}
-
return ps
case ctx.IsSet(flgHTTPS3Bucket):
ps, err := s3.NewHTTPProvider(ctx.String(flgHTTPS3Bucket))
if err != nil {
log.Fatal(err)
}
-
return ps
case ctx.IsSet(flgHTTPPort):
iface := ctx.String(flgHTTPPort)
@@ -85,14 +82,12 @@ func setupHTTPProvider(ctx *cli.Context) challenge.Provider {
if header := ctx.String(flgHTTPProxyHeader); header != "" {
srv.SetProxyHeader(header)
}
-
return srv
case ctx.Bool(flgHTTP):
srv := http01.NewProviderServer("", "")
if header := ctx.String(flgHTTPProxyHeader); header != "" {
srv.SetProxyHeader(header)
}
-
return srv
default:
log.Fatal("Invalid HTTP challenge options.")
diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go
index f73f3920b..b1772e863 100644
--- a/cmd/zz_gen_cmd_dnshelp.go
+++ b/cmd/zz_gen_cmd_dnshelp.go
@@ -12,14 +12,11 @@ import (
func allDNSCodes() string {
providers := []string{
+ "manual",
"acme-dns",
"active24",
"alidns",
- "aliesa",
"allinkl",
- "alwaysdata",
- "anexia",
- "artfiles",
"arvancloud",
"auroradns",
"autodns",
@@ -28,11 +25,8 @@ func allDNSCodes() string {
"azure",
"azuredns",
"baiducloud",
- "beget",
- "binarylane",
"bindman",
"bluecat",
- "bluecatv2",
"bookmyname",
"brandit",
"bunny",
@@ -43,20 +37,16 @@ func allDNSCodes() string {
"cloudns",
"cloudru",
"cloudxns",
- "com35",
"conoha",
"conohav3",
"constellix",
"corenetworks",
"cpanel",
- "czechia",
- "ddnss",
"derak",
"desec",
"designate",
"digitalocean",
"directadmin",
- "dnsexit",
"dnshomede",
"dnsimple",
"dnsmadeeasy",
@@ -69,13 +59,9 @@ func allDNSCodes() string {
"dyndnsfree",
"dynu",
"easydns",
- "edgecenter",
"edgedns",
- "edgeone",
"efficientip",
"epik",
- "eurodns",
- "excedo",
"exec",
"exoscale",
"f5xc",
@@ -84,15 +70,11 @@ func allDNSCodes() string {
"gandiv5",
"gcloud",
"gcore",
- "gigahostno",
"glesys",
"godaddy",
"googledomains",
- "gravity",
"hetzner",
"hostingde",
- "hostinger",
- "hostingnl",
"hosttech",
"httpnet",
"httpreq",
@@ -107,15 +89,9 @@ func allDNSCodes() string {
"internetbs",
"inwx",
"ionos",
- "ionoscloud",
"ipv64",
- "ispconfig",
- "ispconfigddns",
"iwantmyname",
- "jdcloud",
"joker",
- "keyhelp",
- "leaseweb",
"liara",
"lightsail",
"limacity",
@@ -125,7 +101,6 @@ func allDNSCodes() string {
"luadns",
"mailinabox",
"manageengine",
- "manual",
"metaname",
"metaregistrar",
"mijnhost",
@@ -136,9 +111,7 @@ func allDNSCodes() string {
"namecheap",
"namedotcom",
"namesilo",
- "namesurfer",
"nearlyfreespeech",
- "neodigit",
"netcup",
"netlify",
"nicmanager",
@@ -147,7 +120,6 @@ func allDNSCodes() string {
"njalla",
"nodion",
"ns1",
- "octenium",
"oraclecloud",
"otc",
"ovh",
@@ -174,26 +146,21 @@ func allDNSCodes() string {
"sonic",
"spaceship",
"stackpath",
- "syse",
"technitium",
"tencentcloud",
"timewebcloud",
- "todaynic",
"transip",
"ultradns",
- "uniteddomains",
"variomedia",
"vegadns",
"vercel",
"versio",
"vinyldns",
- "virtualname",
"vkcloud",
"volcengine",
"vscale",
"vultr",
"webnames",
- "webnamesca",
"websupport",
"wedos",
"westcn",
@@ -269,38 +236,13 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "ALICLOUD_HTTP_TIMEOUT": API request timeout in seconds (Default: 10)`)
- ew.writeln(` - "ALICLOUD_LINE": Line (Default: default)`)
ew.writeln(` - "ALICLOUD_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "ALICLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "ALICLOUD_REGION_ID": Region ID (Default: cn-hangzhou)`)
ew.writeln(` - "ALICLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/alidns`)
- case "aliesa":
- // generated from: providers/dns/aliesa/aliesa.toml
- ew.writeln(`Configuration for AlibabaCloud ESA.`)
- ew.writeln(`Code: 'aliesa'`)
- ew.writeln(`Since: 'v4.29.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "ALIESA_ACCESS_KEY": Access key ID`)
- ew.writeln(` - "ALIESA_RAM_ROLE": Your instance RAM role (https://www.alibabacloud.com/help/en/ecs/user-guide/attach-an-instance-ram-role-to-an-ecs-instance)`)
- ew.writeln(` - "ALIESA_SECRET_KEY": Access Key secret`)
- ew.writeln(` - "ALIESA_SECURITY_TOKEN": STS Security Token (optional)`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "ALIESA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "ALIESA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "ALIESA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "ALIESA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/aliesa`)
-
case "allinkl":
// generated from: providers/dns/allinkl/allinkl.toml
ew.writeln(`Configuration for all-inkl.`)
@@ -321,69 +263,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/allinkl`)
- case "alwaysdata":
- // generated from: providers/dns/alwaysdata/alwaysdata.toml
- ew.writeln(`Configuration for Alwaysdata.`)
- ew.writeln(`Code: 'alwaysdata'`)
- ew.writeln(`Since: 'v4.31.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "ALWAYSDATA_API_KEY": API Key`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "ALWAYSDATA_ACCOUNT": Account name`)
- ew.writeln(` - "ALWAYSDATA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "ALWAYSDATA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "ALWAYSDATA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "ALWAYSDATA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/alwaysdata`)
-
- case "anexia":
- // generated from: providers/dns/anexia/anexia.toml
- ew.writeln(`Configuration for Anexia CloudDNS.`)
- ew.writeln(`Code: 'anexia'`)
- ew.writeln(`Since: 'v4.28.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "ANEXIA_TOKEN": API token for Anexia Engine`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "ANEXIA_API_URL": API endpoint URL (default: https://engine.anexia-it.com)`)
- ew.writeln(` - "ANEXIA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "ANEXIA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "ANEXIA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
- ew.writeln(` - "ANEXIA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/anexia`)
-
- case "artfiles":
- // generated from: providers/dns/artfiles/artfiles.toml
- ew.writeln(`Configuration for ArtFiles.`)
- ew.writeln(`Code: 'artfiles'`)
- ew.writeln(`Since: 'v4.32.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "ARTFILES_PASSWORD": API password`)
- ew.writeln(` - "ARTFILES_USERNAME": API username`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "ARTFILES_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "ARTFILES_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "ARTFILES_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 360)`)
- ew.writeln(` - "ARTFILES_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/artfiles`)
-
case "arvancloud":
// generated from: providers/dns/arvancloud/arvancloud.toml
ew.writeln(`Configuration for ArvanCloud.`)
@@ -563,52 +442,11 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "BAIDUCLOUD_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "BAIDUCLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "BAIDUCLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
+ ew.writeln(` - "BAIDUCLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/baiducloud`)
- case "beget":
- // generated from: providers/dns/beget/beget.toml
- ew.writeln(`Configuration for Beget.com.`)
- ew.writeln(`Code: 'beget'`)
- ew.writeln(`Since: 'v4.27.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "BEGET_PASSWORD": API password`)
- ew.writeln(` - "BEGET_USERNAME": API username`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "BEGET_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "BEGET_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 30)`)
- ew.writeln(` - "BEGET_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
- ew.writeln(` - "BEGET_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/beget`)
-
- case "binarylane":
- // generated from: providers/dns/binarylane/binarylane.toml
- ew.writeln(`Configuration for Binary Lane.`)
- ew.writeln(`Code: 'binarylane'`)
- ew.writeln(`Since: 'v4.26.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "BINARYLANE_API_TOKEN": API token`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "BINARYLANE_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "BINARYLANE_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "BINARYLANE_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "BINARYLANE_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/binarylane`)
-
case "bindman":
// generated from: providers/dns/bindman/bindman.toml
ew.writeln(`Configuration for Bindman.`)
@@ -653,31 +491,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/bluecat`)
- case "bluecatv2":
- // generated from: providers/dns/bluecatv2/bluecatv2.toml
- ew.writeln(`Configuration for Bluecat v2.`)
- ew.writeln(`Code: 'bluecatv2'`)
- ew.writeln(`Since: 'v4.32.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "BLUECATV2_CONFIG_NAME": Configuration name`)
- ew.writeln(` - "BLUECATV2_PASSWORD": API password`)
- ew.writeln(` - "BLUECATV2_USERNAME": API username`)
- ew.writeln(` - "BLUECATV2_VIEW_NAME": DNS View Name`)
- ew.writeln(` - "BLUECAT_SERVER_URL": The server URL: it should have a scheme, hostname, and port (if required) of the authoritative Bluecat BAM serve`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "BLUECATV2_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "BLUECATV2_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "BLUECATV2_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "BLUECATV2_SKIP_DEPLOY": Skip quick deployements`)
- ew.writeln(` - "BLUECATV2_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/bluecatv2`)
-
case "bookmyname":
// generated from: providers/dns/bookmyname/bookmyname.toml
ew.writeln(`Configuration for BookMyName.`)
@@ -732,7 +545,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "BUNNY_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "BUNNY_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "BUNNY_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "BUNNY_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
@@ -896,27 +708,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/cloudxns`)
- case "com35":
- // generated from: providers/dns/com35/com35.toml
- ew.writeln(`Configuration for 35.com/三五互联.`)
- ew.writeln(`Code: 'com35'`)
- ew.writeln(`Since: 'v4.31.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "COM35_PASSWORD": API password`)
- ew.writeln(` - "COM35_USERNAME": Username`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "COM35_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "COM35_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
- ew.writeln(` - "COM35_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
- ew.writeln(` - "COM35_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/com35`)
-
case "conoha":
// generated from: providers/dns/conoha/conoha.toml
ew.writeln(`Configuration for ConoHa v2.`)
@@ -1029,47 +820,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/cpanel`)
- case "czechia":
- // generated from: providers/dns/czechia/czechia.toml
- ew.writeln(`Configuration for Czechia.`)
- ew.writeln(`Code: 'czechia'`)
- ew.writeln(`Since: 'v4.33.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "CZECHIA_TOKEN": Authorization token`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "CZECHIA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "CZECHIA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "CZECHIA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "CZECHIA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/czechia`)
-
- case "ddnss":
- // generated from: providers/dns/ddnss/ddnss.toml
- ew.writeln(`Configuration for DDnss (DynDNS Service).`)
- ew.writeln(`Code: 'ddnss'`)
- ew.writeln(`Since: 'v4.32.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "DDNSS_KEY": Update key`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "DDNSS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "DDNSS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "DDNSS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "DDNSS_SEQUENCE_INTERVAL": Time between sequential requests in seconds (Default: 60)`)
- ew.writeln(` - "DDNSS_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/ddnss`)
-
case "derak":
// generated from: providers/dns/derak/derak.toml
ew.writeln(`Configuration for Derak Cloud.`)
@@ -1185,26 +935,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/directadmin`)
- case "dnsexit":
- // generated from: providers/dns/dnsexit/dnsexit.toml
- ew.writeln(`Configuration for DNSExit.`)
- ew.writeln(`Code: 'dnsexit'`)
- ew.writeln(`Since: 'v4.32.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "DNSEXIT_API_KEY": API key`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "DNSEXIT_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "DNSEXIT_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
- ew.writeln(` - "DNSEXIT_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
- ew.writeln(` - "DNSEXIT_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/dnsexit`)
-
case "dnshomede":
// generated from: providers/dns/dnshomede/dnshomede.toml
ew.writeln(`Configuration for dnsHome.de.`)
@@ -1451,26 +1181,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/easydns`)
- case "edgecenter":
- // generated from: providers/dns/edgecenter/edgecenter.toml
- ew.writeln(`Configuration for EdgeCenter.`)
- ew.writeln(`Code: 'edgecenter'`)
- ew.writeln(`Since: 'v4.29.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "EDGECENTER_PERMANENT_API_TOKEN": Permanent API token (https://edgecenter.ru/blog/permanent-api-token-explained/)`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "EDGECENTER_HTTP_TIMEOUT": API request timeout in seconds (Default: 10)`)
- ew.writeln(` - "EDGECENTER_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 20)`)
- ew.writeln(` - "EDGECENTER_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 360)`)
- ew.writeln(` - "EDGECENTER_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/edgecenter`)
-
case "edgedns":
// generated from: providers/dns/edgedns/edgedns.toml
ew.writeln(`Configuration for Akamai EdgeDNS.`)
@@ -1496,30 +1206,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/edgedns`)
- case "edgeone":
- // generated from: providers/dns/edgeone/edgeone.toml
- ew.writeln(`Configuration for Tencent EdgeOne.`)
- ew.writeln(`Code: 'edgeone'`)
- ew.writeln(`Since: 'v4.26.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "EDGEONE_SECRET_ID": Access key ID`)
- ew.writeln(` - "EDGEONE_SECRET_KEY": Access Key secret`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "EDGEONE_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "EDGEONE_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 30)`)
- ew.writeln(` - "EDGEONE_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 1200)`)
- ew.writeln(` - "EDGEONE_REGION": Region`)
- ew.writeln(` - "EDGEONE_SESSION_TOKEN": Access Key token`)
- ew.writeln(` - "EDGEONE_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
- ew.writeln(` - "EDGEONE_ZONES_MAPPING": Mapping between DNS zones and site IDs. (ex: 'example.org:id1,example.com:id2')`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/edgeone`)
-
case "efficientip":
// generated from: providers/dns/efficientip/efficientip.toml
ew.writeln(`Configuration for Efficient IP.`)
@@ -1564,48 +1250,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/epik`)
- case "eurodns":
- // generated from: providers/dns/eurodns/eurodns.toml
- ew.writeln(`Configuration for EuroDNS.`)
- ew.writeln(`Code: 'eurodns'`)
- ew.writeln(`Since: 'v4.33.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "EURODNS_API_KEY": API key`)
- ew.writeln(` - "EURODNS_APP_ID": Application ID`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "EURODNS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "EURODNS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "EURODNS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "EURODNS_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/eurodns`)
-
- case "excedo":
- // generated from: providers/dns/excedo/excedo.toml
- ew.writeln(`Configuration for Excedo.`)
- ew.writeln(`Code: 'excedo'`)
- ew.writeln(`Since: 'v4.33.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "EXCEDO_API_KEY": API key`)
- ew.writeln(` - "EXCEDO_API_URL": API base URL`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "EXCEDO_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "EXCEDO_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
- ew.writeln(` - "EXCEDO_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
- ew.writeln(` - "EXCEDO_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/excedo`)
-
case "exec":
// generated from: providers/dns/exec/exec.toml
ew.writeln(`Configuration for External program.`)
@@ -1655,7 +1299,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(` - "F5XC_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "F5XC_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "F5XC_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "F5XC_SERVER": Server domain (Default: console.ves.volterra.io)`)
ew.writeln(` - "F5XC_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
@@ -1768,28 +1411,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/gcore`)
- case "gigahostno":
- // generated from: providers/dns/gigahostno/gigahostno.toml
- ew.writeln(`Configuration for Gigahost.no.`)
- ew.writeln(`Code: 'gigahostno'`)
- ew.writeln(`Since: 'v4.29.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "GIGAHOSTNO_PASSWORD": Password`)
- ew.writeln(` - "GIGAHOSTNO_USERNAME": Username`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "GIGAHOSTNO_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "GIGAHOSTNO_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "GIGAHOSTNO_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "GIGAHOSTNO_SECRET": TOTP secret`)
- ew.writeln(` - "GIGAHOSTNO_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/gigahostno`)
-
case "glesys":
// generated from: providers/dns/glesys/glesys.toml
ew.writeln(`Configuration for Glesys.`)
@@ -1851,28 +1472,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/googledomains`)
- case "gravity":
- // generated from: providers/dns/gravity/gravity.toml
- ew.writeln(`Configuration for Gravity.`)
- ew.writeln(`Code: 'gravity'`)
- ew.writeln(`Since: 'v4.30.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "GRAVITY_PASSWORD": Password`)
- ew.writeln(` - "GRAVITY_SERVER_URL": URL of the server`)
- ew.writeln(` - "GRAVITY_USERNAME": Username`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "GRAVITY_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "GRAVITY_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "GRAVITY_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "GRAVITY_SEQUENCE_INTERVAL": Time between sequential requests in seconds (Default: 1)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/gravity`)
-
case "hetzner":
// generated from: providers/dns/hetzner/hetzner.toml
ew.writeln(`Configuration for Hetzner.`)
@@ -1881,14 +1480,14 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Credentials:`)
- ew.writeln(` - "HETZNER_API_TOKEN": API token`)
+ ew.writeln(` - "HETZNER_API_KEY": API key`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "HETZNER_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "HETZNER_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "HETZNER_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "HETZNER_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
+ ew.writeln(` - "HETZNER_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
+ ew.writeln(` - "HETZNER_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/hetzner`)
@@ -1914,46 +1513,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/hostingde`)
- case "hostinger":
- // generated from: providers/dns/hostinger/hostinger.toml
- ew.writeln(`Configuration for Hostinger.`)
- ew.writeln(`Code: 'hostinger'`)
- ew.writeln(`Since: 'v4.27.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "HOSTINGER_API_TOKEN": API Token`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "HOSTINGER_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "HOSTINGER_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "HOSTINGER_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "HOSTINGER_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/hostinger`)
-
- case "hostingnl":
- // generated from: providers/dns/hostingnl/hostingnl.toml
- ew.writeln(`Configuration for Hosting.nl.`)
- ew.writeln(`Code: 'hostingnl'`)
- ew.writeln(`Since: 'v4.30.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "HOSTINGNL_API_KEY": The API key`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "HOSTINGNL_HTTP_TIMEOUT": API request timeout in seconds (Default: 10)`)
- ew.writeln(` - "HOSTINGNL_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "HOSTINGNL_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
- ew.writeln(` - "HOSTINGNL_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/hostingnl`)
-
case "hosttech":
// generated from: providers/dns/hosttech/hosttech.toml
ew.writeln(`Configuration for Hosttech.`)
@@ -2088,7 +1647,7 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Credentials:`)
ew.writeln(` - "SOFTLAYER_API_KEY": Classic Infrastructure API key`)
- ew.writeln(` - "SOFTLAYER_USERNAME": Username (IBM Cloud is {accountID}_{emailAddress})`)
+ ew.writeln(` - "SOFTLAYER_USERNAME": Username (IBM Cloud is _)`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
@@ -2253,26 +1812,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ionos`)
- case "ionoscloud":
- // generated from: providers/dns/ionoscloud/ionoscloud.toml
- ew.writeln(`Configuration for Ionos Cloud.`)
- ew.writeln(`Code: 'ionoscloud'`)
- ew.writeln(`Since: 'v4.30.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "IONOSCLOUD_API_TOKEN": API token`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "IONOSCLOUD_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "IONOSCLOUD_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "IONOSCLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
- ew.writeln(` - "IONOSCLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/ionoscloud`)
-
case "ipv64":
// generated from: providers/dns/ipv64/ipv64.toml
ew.writeln(`Configuration for IPv64.`)
@@ -2292,53 +1831,9 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ipv64`)
- case "ispconfig":
- // generated from: providers/dns/ispconfig/ispconfig.toml
- ew.writeln(`Configuration for ISPConfig 3.`)
- ew.writeln(`Code: 'ispconfig'`)
- ew.writeln(`Since: 'v4.31.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "ISPCONFIG_PASSWORD": Password`)
- ew.writeln(` - "ISPCONFIG_SERVER_URL": Server URL`)
- ew.writeln(` - "ISPCONFIG_USERNAME": Username`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "ISPCONFIG_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "ISPCONFIG_INSECURE_SKIP_VERIFY": Whether to verify the API certificate`)
- ew.writeln(` - "ISPCONFIG_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "ISPCONFIG_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "ISPCONFIG_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/ispconfig`)
-
- case "ispconfigddns":
- // generated from: providers/dns/ispconfigddns/ispconfigddns.toml
- ew.writeln(`Configuration for ISPConfig 3 - Dynamic DNS (DDNS) Module.`)
- ew.writeln(`Code: 'ispconfigddns'`)
- ew.writeln(`Since: 'v4.31.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "ISPCONFIG_DDNS_SERVER_URL": API server URL (ex: https://panel.example.com:8080)`)
- ew.writeln(` - "ISPCONFIG_DDNS_TOKEN": DDNS API token`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "ISPCONFIG_DDNS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "ISPCONFIG_DDNS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "ISPCONFIG_DDNS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "ISPCONFIG_DDNS_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 3600)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/ispconfigddns`)
-
case "iwantmyname":
// generated from: providers/dns/iwantmyname/iwantmyname.toml
- ew.writeln(`Configuration for iwantmyname (Deprecated).`)
+ ew.writeln(`Configuration for iwantmyname.`)
ew.writeln(`Code: 'iwantmyname'`)
ew.writeln(`Since: 'v4.7.0'`)
ew.writeln()
@@ -2357,28 +1852,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/iwantmyname`)
- case "jdcloud":
- // generated from: providers/dns/jdcloud/jdcloud.toml
- ew.writeln(`Configuration for JD Cloud.`)
- ew.writeln(`Code: 'jdcloud'`)
- ew.writeln(`Since: 'v4.31.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "JDCLOUD_ACCESS_KEY_ID": Access key ID`)
- ew.writeln(` - "JDCLOUD_ACCESS_KEY_SECRET": Access key secret`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "JDCLOUD_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "JDCLOUD_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "JDCLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "JDCLOUD_REGION_ID": Region ID (Default: cn-north-1)`)
- ew.writeln(` - "JDCLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/jdcloud`)
-
case "joker":
// generated from: providers/dns/joker/joker.toml
ew.writeln(`Configuration for Joker.`)
@@ -2403,47 +1876,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/joker`)
- case "keyhelp":
- // generated from: providers/dns/keyhelp/keyhelp.toml
- ew.writeln(`Configuration for KeyHelp.`)
- ew.writeln(`Code: 'keyhelp'`)
- ew.writeln(`Since: 'v4.26.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "KEYHELP_API_KEY": API key`)
- ew.writeln(` - "KEYHELP_BASE_URL": Server URL`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "KEYHELP_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "KEYHELP_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "KEYHELP_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "KEYHELP_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/keyhelp`)
-
- case "leaseweb":
- // generated from: providers/dns/leaseweb/leaseweb.toml
- ew.writeln(`Configuration for Leaseweb.`)
- ew.writeln(`Code: 'leaseweb'`)
- ew.writeln(`Since: 'v4.32.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "LEASEWEB_API_KEY": API key`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "LEASEWEB_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "LEASEWEB_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "LEASEWEB_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "LEASEWEB_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/leaseweb`)
-
case "liara":
// generated from: providers/dns/liara/liara.toml
ew.writeln(`Configuration for Liara.`)
@@ -2459,7 +1891,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(` - "LIARA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "LIARA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "LIARA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "LIARA_TEAM_ID": The team ID to access services in a team`)
ew.writeln(` - "LIARA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 3600)`)
ew.writeln()
@@ -2607,7 +2038,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "MAILINABOX_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "MAILINABOX_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 4)`)
ew.writeln(` - "MAILINABOX_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
@@ -2634,16 +2064,6 @@ 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.`)
@@ -2852,30 +2272,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/namesilo`)
- case "namesurfer":
- // generated from: providers/dns/namesurfer/namesurfer.toml
- ew.writeln(`Configuration for FusionLayer NameSurfer.`)
- ew.writeln(`Code: 'namesurfer'`)
- ew.writeln(`Since: 'v4.32.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "NAMESURFER_API_KEY": API key name`)
- ew.writeln(` - "NAMESURFER_API_SECRET": API secret`)
- ew.writeln(` - "NAMESURFER_BASE_URL": The base URL of NameSurfer API (jsonrpc10) endpoint URL (e.g., https://foo.example.com:8443/API/NSService_10)`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "NAMESURFER_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "NAMESURFER_INSECURE_SKIP_VERIFY": Whether to verify the API certificate`)
- ew.writeln(` - "NAMESURFER_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "NAMESURFER_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
- ew.writeln(` - "NAMESURFER_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
- ew.writeln(` - "NAMESURFER_VIEW": DNS view name (optional, default: empty string)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/namesurfer`)
-
case "nearlyfreespeech":
// generated from: providers/dns/nearlyfreespeech/nearlyfreespeech.toml
ew.writeln(`Configuration for NearlyFreeSpeech.NET.`)
@@ -2898,26 +2294,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/nearlyfreespeech`)
- case "neodigit":
- // generated from: providers/dns/neodigit/neodigit.toml
- ew.writeln(`Configuration for Neodigit.`)
- ew.writeln(`Code: 'neodigit'`)
- ew.writeln(`Since: 'v4.30.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "NEODIGIT_TOKEN": API token`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "NEODIGIT_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "NEODIGIT_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
- ew.writeln(` - "NEODIGIT_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
- ew.writeln(` - "NEODIGIT_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/neodigit`)
-
case "netcup":
// generated from: providers/dns/netcup/netcup.toml
ew.writeln(`Configuration for Netcup.`)
@@ -3088,26 +2464,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ns1`)
- case "octenium":
- // generated from: providers/dns/octenium/octenium.toml
- ew.writeln(`Configuration for Octenium.`)
- ew.writeln(`Code: 'octenium'`)
- ew.writeln(`Since: 'v4.27.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "OCTENIUM_API_KEY": API key`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "OCTENIUM_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "OCTENIUM_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "OCTENIUM_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "OCTENIUM_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/octenium`)
-
case "oraclecloud":
// generated from: providers/dns/oraclecloud/oraclecloud.toml
ew.writeln(`Configuration for Oracle Cloud.`)
@@ -3117,25 +2473,19 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Credentials:`)
ew.writeln(` - "OCI_COMPARTMENT_OCID": Compartment OCID`)
- ew.writeln(` - "OCI_FINGERPRINT": Public key fingerprint (ignored if 'OCI_AUTH_TYPE=instance_principal')`)
- ew.writeln(` - "OCI_PRIVATE_KEY_PASSWORD": Private key password (ignored if 'OCI_AUTH_TYPE=instance_principal')`)
- ew.writeln(` - "OCI_PRIVATE_KEY_PATH": Private key file (ignored if 'OCI_AUTH_TYPE=instance_principal')`)
- ew.writeln(` - "OCI_REGION": Region (it can be empty if 'OCI_AUTH_TYPE=instance_principal').`)
- ew.writeln(` - "OCI_TENANCY_OCID": Tenancy OCID (ignored if 'OCI_AUTH_TYPE=instance_principal')`)
- ew.writeln(` - "OCI_USER_OCID": User OCID (ignored if 'OCI_AUTH_TYPE=instance_principal')`)
+ ew.writeln(` - "OCI_PRIVKEY_FILE": Private key file`)
+ ew.writeln(` - "OCI_PRIVKEY_PASS": Private key password`)
+ ew.writeln(` - "OCI_PUBKEY_FINGERPRINT": Public key fingerprint`)
+ ew.writeln(` - "OCI_REGION": Region`)
+ ew.writeln(` - "OCI_TENANCY_OCID": Tenancy OCID`)
+ ew.writeln(` - "OCI_USER_OCID": User OCID`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "OCI_AUTH_TYPE": Authorization type. Possible values: 'instance_principal', '' (Default: '')`)
ew.writeln(` - "OCI_HTTP_TIMEOUT": API request timeout in seconds (Default: 60)`)
ew.writeln(` - "OCI_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "OCI_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "OCI_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
- ew.writeln(` - "TF_VAR_fingerprint": Alias on 'OCI_FINGERPRINT'`)
- ew.writeln(` - "TF_VAR_private_key_path": Alias on 'OCI_PRIVATE_KEY_PATH'`)
- ew.writeln(` - "TF_VAR_region": Alias on 'OCI_REGION'`)
- ew.writeln(` - "TF_VAR_tenancy_ocid": Alias on 'OCI_TENANCY_OCID'`)
- ew.writeln(` - "TF_VAR_user_ocid": Alias on 'OCI_USER_OCID'`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/oraclecloud`)
@@ -3149,6 +2499,7 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Credentials:`)
ew.writeln(` - "OTC_DOMAIN_NAME": Domain name`)
+ ew.writeln(` - "OTC_IDENTITY_ENDPOINT": Identity endpoint URL`)
ew.writeln(` - "OTC_PASSWORD": Password`)
ew.writeln(` - "OTC_PROJECT_NAME": Project name`)
ew.writeln(` - "OTC_USER_NAME": User name`)
@@ -3156,9 +2507,7 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "OTC_HTTP_TIMEOUT": API request timeout in seconds (Default: 10)`)
- ew.writeln(` - "OTC_IDENTITY_ENDPOINT": Identity endpoint URL (default: https://iam.eu-de.otc.t-systems.com:443/v3/auth/tokens)`)
ew.writeln(` - "OTC_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "OTC_PRIVATE_ZONE": Set to true to use private zones only (default: use public zones only)`)
ew.writeln(` - "OTC_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "OTC_SEQUENCE_INTERVAL": Time between sequential requests in seconds (Default: 60)`)
ew.writeln(` - "OTC_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
@@ -3439,7 +2788,7 @@ func displayDNSHelp(w io.Writer, name string) error {
case "safedns":
// generated from: providers/dns/safedns/safedns.toml
- ew.writeln(`Configuration for ANS SafeDNS.`)
+ ew.writeln(`Configuration for UKFast SafeDNS.`)
ew.writeln(`Code: 'safedns'`)
ew.writeln(`Since: 'v4.6.0'`)
ew.writeln()
@@ -3492,7 +2841,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "SCW_ACCESS_KEY": Access key`)
- ew.writeln(` - "SCW_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "SCW_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
ew.writeln(` - "SCW_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "SCW_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
@@ -3536,14 +2884,11 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "SELECTELV2_AUTH_REGION": Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1')`)
- ew.writeln(` - "SELECTELV2_AUTH_URL": Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/')`)
ew.writeln(` - "SELECTELV2_BASE_URL": API endpoint URL`)
ew.writeln(` - "SELECTELV2_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "SELECTELV2_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 5)`)
ew.writeln(` - "SELECTELV2_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "SELECTELV2_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
- ew.writeln(` - "SELECTELV2_USER_DOMAIN_NAME": To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/selectelv2`)
@@ -3697,26 +3042,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/stackpath`)
- case "syse":
- // generated from: providers/dns/syse/syse.toml
- ew.writeln(`Configuration for Syse.`)
- ew.writeln(`Code: 'syse'`)
- ew.writeln(`Since: 'v4.30.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "SYSE_CREDENTIALS": Comma-separated list of 'zone:password' credential pairs`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "SYSE_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "SYSE_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
- ew.writeln(` - "SYSE_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 1200)`)
- ew.writeln(` - "SYSE_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/syse`)
-
case "technitium":
// generated from: providers/dns/technitium/technitium.toml
ew.writeln(`Configuration for Technitium.`)
@@ -3780,27 +3105,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/timewebcloud`)
- case "todaynic":
- // generated from: providers/dns/todaynic/todaynic.toml
- ew.writeln(`Configuration for TodayNIC/时代互联.`)
- ew.writeln(`Code: 'todaynic'`)
- ew.writeln(`Since: 'v4.32.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "TODAYNIC_API_KEY": API key`)
- ew.writeln(` - "TODAYNIC_AUTH_USER_ID": account ID`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "TODAYNIC_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "TODAYNIC_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "TODAYNIC_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "TODAYNIC_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/todaynic`)
-
case "transip":
// generated from: providers/dns/transip/transip.toml
ew.writeln(`Configuration for TransIP.`)
@@ -3814,7 +3118,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "TRANSIP_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "TRANSIP_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
ew.writeln(` - "TRANSIP_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 600)`)
ew.writeln(` - "TRANSIP_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 10)`)
@@ -3843,26 +3146,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ultradns`)
- case "uniteddomains":
- // generated from: providers/dns/uniteddomains/uniteddomains.toml
- ew.writeln(`Configuration for United-Domains.`)
- ew.writeln(`Code: 'uniteddomains'`)
- ew.writeln(`Since: 'v4.29.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "UNITEDDOMAINS_API_KEY": API key '.' https://www.united-domains.de/help/faq-article/getting-started-with-the-united-domains-dns-api/`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "UNITEDDOMAINS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "UNITEDDOMAINS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "UNITEDDOMAINS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 900)`)
- ew.writeln(` - "UNITEDDOMAINS_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/uniteddomains`)
-
case "variomedia":
// generated from: providers/dns/variomedia/variomedia.toml
ew.writeln(`Configuration for Variomedia.`)
@@ -3963,7 +3246,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "VINYLDNS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "VINYLDNS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 4)`)
ew.writeln(` - "VINYLDNS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "VINYLDNS_QUOTE_VALUE": Adds quotes around the TXT record value (Default: false)`)
@@ -3972,26 +3254,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/vinyldns`)
- case "virtualname":
- // generated from: providers/dns/virtualname/virtualname.toml
- ew.writeln(`Configuration for Virtualname.`)
- ew.writeln(`Code: 'virtualname'`)
- ew.writeln(`Since: 'v4.30.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "VIRTUALNAME_TOKEN": API token`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "VIRTUALNAME_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "VIRTUALNAME_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
- ew.writeln(` - "VIRTUALNAME_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
- ew.writeln(` - "VIRTUALNAME_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/virtualname`)
-
case "vkcloud":
// generated from: providers/dns/vkcloud/vkcloud.toml
ew.writeln(`Configuration for VK Cloud.`)
@@ -4083,44 +3345,23 @@ func displayDNSHelp(w io.Writer, name string) error {
case "webnames":
// generated from: providers/dns/webnames/webnames.toml
- ew.writeln(`Configuration for webnames.ru.`)
+ ew.writeln(`Configuration for Webnames.`)
ew.writeln(`Code: 'webnames'`)
ew.writeln(`Since: 'v4.15.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
- ew.writeln(` - "WEBNAMESRU_API_KEY": Domain API key`)
+ ew.writeln(` - "WEBNAMES_API_KEY": Domain API key`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "WEBNAMESRU_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "WEBNAMESRU_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "WEBNAMESRU_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
+ ew.writeln(` - "WEBNAMES_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
+ ew.writeln(` - "WEBNAMES_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
+ ew.writeln(` - "WEBNAMES_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/webnames`)
- case "webnamesca":
- // generated from: providers/dns/webnamesca/webnamesca.toml
- ew.writeln(`Configuration for webnames.ca.`)
- ew.writeln(`Code: 'webnamesca'`)
- ew.writeln(`Since: 'v4.28.0'`)
- ew.writeln()
-
- ew.writeln(`Credentials:`)
- ew.writeln(` - "WEBNAMESCA_API_KEY": API key`)
- ew.writeln(` - "WEBNAMESCA_API_USER": API username`)
- ew.writeln()
-
- ew.writeln(`Additional Configuration:`)
- ew.writeln(` - "WEBNAMESCA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
- ew.writeln(` - "WEBNAMESCA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
- ew.writeln(` - "WEBNAMESCA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
- ew.writeln(` - "WEBNAMESCA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
-
- ew.writeln()
- ew.writeln(`More information: https://go-acme.github.io/lego/dns/webnamesca`)
-
case "websupport":
// generated from: providers/dns/websupport/websupport.toml
ew.writeln(`Configuration for Websupport.`)
@@ -4307,6 +3548,8 @@ 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/Makefile b/docs/Makefile
index 6c84c7d1d..8e32681d1 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,14 +1,14 @@
-.PHONY: default clean serve build
+.PHONY: default clean hugo hugo-build
-default: clean serve
+default: clean hugo
clean:
rm -rf public/
-build: clean
+hugo-build: clean
hugo --enableGitInfo --source .
-serve:
+hugo:
hugo server --disableFastRender --enableGitInfo --watch --source .
# hugo server -D
diff --git a/docs/content/_index.md b/docs/content/_index.md
index 95e411afc..a211c5d62 100644
--- a/docs/content/_index.md
+++ b/docs/content/_index.md
@@ -7,24 +7,14 @@ chapter: false
Let's Encrypt client and ACME library written in Go.
-{{% notice important %}}
-lego is an independent, free, and open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
-
-This project is not owned by a company. I'm not an employee of a company.
-
-I don't have gifted domains/accounts from DNS companies.
-
-I've been maintaining it for about 10 years.
-{{% /notice %}}
-
## Features
- ACME v2 [RFC 8555](https://www.rfc-editor.org/rfc/rfc8555.html)
- Support [RFC 8737](https://www.rfc-editor.org/rfc/rfc8737.html): TLS Application‑Layer Protocol Negotiation (ALPN) Challenge Extension
- Support [RFC 8738](https://www.rfc-editor.org/rfc/rfc8738.html): issues certificates for IP addresses
- Support [RFC 9773](https://www.rfc-editor.org/rfc/rfc9773.html): Renewal Information (ARI) Extension
- - Support [draft-ietf-acme-profiles-00](https://datatracker.ietf.org/doc/draft-ietf-acme-profiles/): Profiles Extension
-- Comes with about [180 DNS providers]({{% ref "dns" %}})
+ - Support [draft-aaron-acme-profiles-00](https://datatracker.ietf.org/doc/draft-aaron-acme-profiles/): Profiles Extension
+- Comes with about [150 DNS providers]({{% ref "dns" %}})
- Register with CA
- Obtain certificates, both from scratch or with an existing CSR
- Renew certificates
diff --git a/docs/content/dns/_index.md b/docs/content/dns/_index.md
index 2b6f0489c..7ccfeb53d 100644
--- a/docs/content/dns/_index.md
+++ b/docs/content/dns/_index.md
@@ -5,16 +5,6 @@ draft: false
weight: 3
---
-{{% notice important %}}
-lego is an independent, free, and open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
-
-This project is not owned by a company. I'm not an employee of a company.
-
-I don't have gifted domains/accounts from DNS companies.
-
-I've been maintaining it for about 10 years.
-{{% /notice %}}
-
## Configuration and Credentials
Credentials and DNS configuration for DNS providers must be passed through environment variables.
diff --git a/providers/dns/manual/manual.toml b/docs/content/dns/manual.md
similarity index 76%
rename from providers/dns/manual/manual.toml
rename to docs/content/dns/manual.md
index fc47a8fae..3f9cf0a8e 100644
--- a/providers/dns/manual/manual.toml
+++ b/docs/content/dns/manual.md
@@ -1,19 +1,24 @@
-Name = "Manual"
-Description = '''Solving the DNS-01 challenge using CLI prompt.'''
-Code = "manual"
-Since = "v0.3.0"
+---
+title: "Manual"
+date: 2019-03-03T16:39:46+01:00
+draft: false
+slug: manual
+dnsprovider:
+ since: v0.3.0
+ code: manual
+ url:
+---
-Example = '''
-lego --dns manual -d '*.example.com' -d example.com run
-'''
+Solving the DNS-01 challenge using CLI prompt.
+
+
-Additional = '''
## Example
To start using the CLI prompt "provider", start lego with `--dns manual`:
```console
-$ lego --dns manual -d example.com run
+$ 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:
@@ -31,13 +36,13 @@ If you accept the linked Terms of Service, hit `Enter`.
[INFO] acme: Registering account for you@example.com
!!!! HEADS UP !!!!
-Your account credentials have been saved in your
-configuration directory at "./.lego/accounts".
+ 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 private keys
-generated by lego and certificates obtained from the ACME
-server. Making regular backups of this folder is ideal.
+ 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
@@ -65,5 +70,3 @@ _acme-challenge.example.com. 120 IN TXT "hX0dPkG6Gfs9hUvBAchQclkyyoEKbShbpvJ9mY5
```
As mentioned, you can now remove the TXT record again.
-
-'''
diff --git a/docs/content/dns/zz_gen_acme-dns.md b/docs/content/dns/zz_gen_acme-dns.md
index 5564dba1b..cb3d24016 100644
--- a/docs/content/dns/zz_gen_acme-dns.md
+++ b/docs/content/dns/zz_gen_acme-dns.md
@@ -28,13 +28,13 @@ Here is an example bash command using the Joohoi's ACME-DNS provider:
```bash
ACME_DNS_API_BASE=http://10.0.0.8:4443 \
ACME_DNS_STORAGE_PATH=/root/.lego-acme-dns-accounts.json \
-lego --dns "acme-dns" -d '*.example.com' -d example.com run
+lego --email you@example.com --dns "acme-dns" -d '*.example.com' -d example.com run
# or
ACME_DNS_API_BASE=http://10.0.0.8:4443 \
ACME_DNS_STORAGE_BASE_URL=http://10.10.10.10:80 \
-lego --dns "acme-dns" -d '*.example.com' -d example.com run
+lego --email you@example.com --dns "acme-dns" -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_active24.md b/docs/content/dns/zz_gen_active24.md
index 6ec5c467a..cadc6660c 100644
--- a/docs/content/dns/zz_gen_active24.md
+++ b/docs/content/dns/zz_gen_active24.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Active24 provider:
```bash
ACTIVE24_API_KEY="xxx" \
ACTIVE24_SECRET="yyy" \
-lego --dns active24 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns active24 -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_alidns.md b/docs/content/dns/zz_gen_alidns.md
index 4ded782ab..7a7a36e8a 100644
--- a/docs/content/dns/zz_gen_alidns.md
+++ b/docs/content/dns/zz_gen_alidns.md
@@ -28,13 +28,13 @@ Here is an example bash command using the Alibaba Cloud DNS provider:
```bash
# Setup using instance RAM role
ALICLOUD_RAM_ROLE=lego \
-lego --dns alidns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns alidns -d '*.example.com' -d example.com run
# Or, using credentials
ALICLOUD_ACCESS_KEY=abcdefghijklmnopqrstuvwx \
ALICLOUD_SECRET_KEY=your-secret-key \
ALICLOUD_SECURITY_TOKEN=your-sts-token \
-lego --dns alidns - -d '*.example.com' -d example.com run
+lego --email you@example.com --dns alidns - -d '*.example.com' -d example.com run
```
@@ -58,10 +58,8 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `ALICLOUD_HTTP_TIMEOUT` | API request timeout in seconds (Default: 10) |
-| `ALICLOUD_LINE` | Line (Default: default) |
| `ALICLOUD_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `ALICLOUD_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `ALICLOUD_REGION_ID` | Region ID (Default: cn-hangzhou) |
| `ALICLOUD_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 600) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
diff --git a/docs/content/dns/zz_gen_aliesa.md b/docs/content/dns/zz_gen_aliesa.md
deleted file mode 100644
index af28f9a4e..000000000
--- a/docs/content/dns/zz_gen_aliesa.md
+++ /dev/null
@@ -1,78 +0,0 @@
----
-title: "AlibabaCloud ESA"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: aliesa
-dnsprovider:
- since: "v4.29.0"
- code: "aliesa"
- url: "https://www.alibabacloud.com/en/product/esa"
----
-
-
-
-
-
-
-Configuration for [AlibabaCloud ESA](https://www.alibabacloud.com/en/product/esa).
-
-
-
-
-- Code: `aliesa`
-- Since: v4.29.0
-
-
-Here is an example bash command using the AlibabaCloud ESA provider:
-
-```bash
-# Setup using instance RAM role
-ALIESA_RAM_ROLE=lego \
-lego --dns aliesa -d '*.example.com' -d example.com run
-
-# Or, using credentials
-ALIESA_ACCESS_KEY=abcdefghijklmnopqrstuvwx \
-ALIESA_SECRET_KEY=your-secret-key \
-ALIESA_SECURITY_TOKEN=your-sts-token \
-lego --dns aliesa - -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `ALIESA_ACCESS_KEY` | Access key ID |
-| `ALIESA_RAM_ROLE` | Your instance RAM role (https://www.alibabacloud.com/help/en/ecs/user-guide/attach-an-instance-ram-role-to-an-ecs-instance) |
-| `ALIESA_SECRET_KEY` | Access Key secret |
-| `ALIESA_SECURITY_TOKEN` | STS Security Token (optional) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `ALIESA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `ALIESA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `ALIESA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `ALIESA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://www.alibabacloud.com/help/en/edge-security-acceleration/esa/api-esa-2024-09-10-overview?spm=a2c63.p38356.help-menu-2673927.d_6_0_0.20b224c28PSZDc#:~:text=DNS-,DNS%20records,-DNS%20records)
-- [Go client](https://github.com/alibabacloud-go/esa-20240910)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_allinkl.md b/docs/content/dns/zz_gen_allinkl.md
index 2db6ae2c5..2415c812f 100644
--- a/docs/content/dns/zz_gen_allinkl.md
+++ b/docs/content/dns/zz_gen_allinkl.md
@@ -28,7 +28,7 @@ Here is an example bash command using the all-inkl provider:
```bash
ALL_INKL_LOGIN=xxxxxxxxxxxxxxxxxxxxxxxxxx \
ALL_INKL_PASSWORD=yyyyyyyyyyyyyyyyyyyyyyyyyy \
-lego --dns allinkl -d '*.example.com' -d example.com run
+lego --email you@example.com --dns allinkl -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_alwaysdata.md b/docs/content/dns/zz_gen_alwaysdata.md
deleted file mode 100644
index 6ec332d16..000000000
--- a/docs/content/dns/zz_gen_alwaysdata.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: "Alwaysdata"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: alwaysdata
-dnsprovider:
- since: "v4.31.0"
- code: "alwaysdata"
- url: "https://alwaysdata.com/"
----
-
-
-
-
-
-
-Configuration for [Alwaysdata](https://alwaysdata.com/).
-
-
-
-
-- Code: `alwaysdata`
-- Since: v4.31.0
-
-
-Here is an example bash command using the Alwaysdata provider:
-
-```bash
-ALWAYSDATA_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns alwaysdata -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `ALWAYSDATA_API_KEY` | API Key |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `ALWAYSDATA_ACCOUNT` | Account name |
-| `ALWAYSDATA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `ALWAYSDATA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `ALWAYSDATA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `ALWAYSDATA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://help.alwaysdata.com/en/api/resources/)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_anexia.md b/docs/content/dns/zz_gen_anexia.md
deleted file mode 100644
index e12ec7cfd..000000000
--- a/docs/content/dns/zz_gen_anexia.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: "Anexia CloudDNS"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: anexia
-dnsprovider:
- since: "v4.28.0"
- code: "anexia"
- url: "https://www.anexia-it.com/"
----
-
-
-
-
-
-
-Configuration for [Anexia CloudDNS](https://www.anexia-it.com/).
-
-
-
-
-- Code: `anexia`
-- Since: v4.28.0
-
-
-Here is an example bash command using the Anexia CloudDNS provider:
-
-```bash
-ANEXIA_TOKEN=xxx \
-lego --dns anexia -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `ANEXIA_TOKEN` | API token for Anexia Engine |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `ANEXIA_API_URL` | API endpoint URL (default: https://engine.anexia-it.com) |
-| `ANEXIA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `ANEXIA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `ANEXIA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 300) |
-| `ANEXIA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 300) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-## Description
-
-You need to create an API token in the [Anexia Engine](https://engine.anexia-it.com/).
-
-The token must have permissions to manage DNS zones and records.
-
-
-
-## More information
-
-- [API documentation](https://engine.anexia-it.com/docs/en/module/clouddns/api)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_artfiles.md b/docs/content/dns/zz_gen_artfiles.md
deleted file mode 100644
index 15ac2d964..000000000
--- a/docs/content/dns/zz_gen_artfiles.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "ArtFiles"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: artfiles
-dnsprovider:
- since: "v4.32.0"
- code: "artfiles"
- url: "https://www.artfiles.de/extras/domains/"
----
-
-
-
-
-
-
-Configuration for [ArtFiles](https://www.artfiles.de/extras/domains/).
-
-
-
-
-- Code: `artfiles`
-- Since: v4.32.0
-
-
-Here is an example bash command using the ArtFiles provider:
-
-```bash
-ARTFILES_USERNAME="xxx" \
-ARTFILES_PASSWORD="yyy" \
-lego --dns artfiles -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `ARTFILES_PASSWORD` | API password |
-| `ARTFILES_USERNAME` | API username |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `ARTFILES_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `ARTFILES_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `ARTFILES_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 360) |
-| `ARTFILES_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://support.artfiles.de/DCP-API#dns)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_arvancloud.md b/docs/content/dns/zz_gen_arvancloud.md
index 96d495f71..b9fa1af8d 100644
--- a/docs/content/dns/zz_gen_arvancloud.md
+++ b/docs/content/dns/zz_gen_arvancloud.md
@@ -27,7 +27,7 @@ Here is an example bash command using the ArvanCloud provider:
```bash
ARVANCLOUD_API_KEY="Apikey xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
-lego --dns arvancloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns arvancloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_auroradns.md b/docs/content/dns/zz_gen_auroradns.md
index d608c85bb..9fffe34bc 100644
--- a/docs/content/dns/zz_gen_auroradns.md
+++ b/docs/content/dns/zz_gen_auroradns.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Aurora DNS provider:
```bash
AURORA_API_KEY=xxxxx \
AURORA_SECRET=yyyyyy \
-lego --dns auroradns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns auroradns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_autodns.md b/docs/content/dns/zz_gen_autodns.md
index f1f25e916..73f41b980 100644
--- a/docs/content/dns/zz_gen_autodns.md
+++ b/docs/content/dns/zz_gen_autodns.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Autodns provider:
```bash
AUTODNS_API_USER=username \
AUTODNS_API_PASSWORD=supersecretpassword \
-lego --dns autodns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns autodns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_axelname.md b/docs/content/dns/zz_gen_axelname.md
index 91476e521..b1bb3e166 100644
--- a/docs/content/dns/zz_gen_axelname.md
+++ b/docs/content/dns/zz_gen_axelname.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Axelname provider:
```bash
AXELNAME_NICKNAME="yyy" \
AXELNAME_TOKEN="xxx" \
-lego --dns axelname -d '*.example.com' -d example.com run
+lego --email you@example.com --dns axelname -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_azion.md b/docs/content/dns/zz_gen_azion.md
index c5ca33552..af2a281b0 100644
--- a/docs/content/dns/zz_gen_azion.md
+++ b/docs/content/dns/zz_gen_azion.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Azion provider:
```bash
AZION_PERSONAL_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns azion -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azion -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_azuredns.md b/docs/content/dns/zz_gen_azuredns.md
index 3b2586711..f9e7d3844 100644
--- a/docs/content/dns/zz_gen_azuredns.md
+++ b/docs/content/dns/zz_gen_azuredns.md
@@ -31,32 +31,32 @@ Here is an example bash command using the Azure DNS provider:
AZURE_CLIENT_ID= \
AZURE_TENANT_ID= \
AZURE_CLIENT_SECRET= \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using client certificate
AZURE_CLIENT_ID= \
AZURE_TENANT_ID= \
AZURE_CLIENT_CERTIFICATE_PATH= \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Azure CLI
az login \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Managed Identity (Azure VM)
AZURE_TENANT_ID= \
AZURE_RESOURCE_GROUP= \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Managed Identity (Azure Arc)
AZURE_TENANT_ID= \
IMDS_ENDPOINT=http://localhost:40342 \
IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
```
@@ -229,10 +229,6 @@ This authentication method can be specifically used by setting the `AZURE_AUTH_M
Open ID Connect is a mechanism that establish a trust relationship between a running environment and the Azure AD identity provider.
It can be enabled by setting the `AZURE_AUTH_METHOD` environment variable to `oidc`.
-### Azure DevOps Pipelines
-
-It can be enabled by setting the `AZURE_AUTH_METHOD` environment variable to `pipeline`.
-
diff --git a/docs/content/dns/zz_gen_baiducloud.md b/docs/content/dns/zz_gen_baiducloud.md
index 59a2f9a2d..11a71c1ab 100644
--- a/docs/content/dns/zz_gen_baiducloud.md
+++ b/docs/content/dns/zz_gen_baiducloud.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Baidu Cloud provider:
```bash
BAIDUCLOUD_ACCESS_KEY_ID="xxx" \
BAIDUCLOUD_SECRET_ACCESS_KEY="yyy" \
-lego --dns baiducloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns baiducloud -d '*.example.com' -d example.com run
```
@@ -51,7 +51,7 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
|--------------------------------|-------------|
| `BAIDUCLOUD_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `BAIDUCLOUD_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `BAIDUCLOUD_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 300) |
+| `BAIDUCLOUD_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
diff --git a/docs/content/dns/zz_gen_beget.md b/docs/content/dns/zz_gen_beget.md
deleted file mode 100644
index 3f03a2ac5..000000000
--- a/docs/content/dns/zz_gen_beget.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "Beget.com"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: beget
-dnsprovider:
- since: "v4.27.0"
- code: "beget"
- url: "https://beget.com/"
----
-
-
-
-
-
-
-Configuration for [Beget.com](https://beget.com/).
-
-
-
-
-- Code: `beget`
-- Since: v4.27.0
-
-
-Here is an example bash command using the Beget.com provider:
-
-```bash
-BEGET_USERNAME=xxxxxx \
-BEGET_PASSWORD=yyyyyy \
-lego --dns beget -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `BEGET_PASSWORD` | API password |
-| `BEGET_USERNAME` | API username |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `BEGET_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `BEGET_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 30) |
-| `BEGET_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 300) |
-| `BEGET_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://beget.com/ru/kb/api/funkczii-upravleniya-dns)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_binarylane.md b/docs/content/dns/zz_gen_binarylane.md
deleted file mode 100644
index eebf3c54e..000000000
--- a/docs/content/dns/zz_gen_binarylane.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Binary Lane"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: binarylane
-dnsprovider:
- since: "v4.26.0"
- code: "binarylane"
- url: "https://www.binarylane.com.au/"
----
-
-
-
-
-
-
-Configuration for [Binary Lane](https://www.binarylane.com.au/).
-
-
-
-
-- Code: `binarylane`
-- Since: v4.26.0
-
-
-Here is an example bash command using the Binary Lane provider:
-
-```bash
-BINARYLANE_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns binarylane -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `BINARYLANE_API_TOKEN` | API token |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `BINARYLANE_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `BINARYLANE_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `BINARYLANE_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `BINARYLANE_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://api.binarylane.com.au/reference/#tag/Domains)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_bindman.md b/docs/content/dns/zz_gen_bindman.md
index fcceb8962..e12f25b7a 100644
--- a/docs/content/dns/zz_gen_bindman.md
+++ b/docs/content/dns/zz_gen_bindman.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Bindman provider:
```bash
BINDMAN_MANAGER_ADDRESS= \
-lego --dns bindman -d '*.example.com' -d example.com run
+lego --email you@example.com --dns bindman -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_bluecat.md b/docs/content/dns/zz_gen_bluecat.md
index 2d9eb5b48..ee45c7f8b 100644
--- a/docs/content/dns/zz_gen_bluecat.md
+++ b/docs/content/dns/zz_gen_bluecat.md
@@ -32,7 +32,7 @@ BLUECAT_USER_NAME=myusername \
BLUECAT_CONFIG_NAME=myconfig \
BLUECAT_SERVER_URL=https://bam.example.com \
BLUECAT_TTL=30 \
-lego --dns bluecat -d '*.example.com' -d example.com run
+lego --email you@example.com --dns bluecat -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_bluecatv2.md b/docs/content/dns/zz_gen_bluecatv2.md
deleted file mode 100644
index 7d748df99..000000000
--- a/docs/content/dns/zz_gen_bluecatv2.md
+++ /dev/null
@@ -1,76 +0,0 @@
----
-title: "Bluecat v2"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: bluecatv2
-dnsprovider:
- since: "v4.32.0"
- code: "bluecatv2"
- url: "https://www.bluecatnetworks.com"
----
-
-
-
-
-
-
-Configuration for [Bluecat v2](https://www.bluecatnetworks.com).
-
-
-
-
-- Code: `bluecatv2`
-- Since: v4.32.0
-
-
-Here is an example bash command using the Bluecat v2 provider:
-
-```bash
-BLUECATV2_SERVER_URL="https://example.com" \
-BLUECATV2_USERNAME="xxx" \
-BLUECATV2_PASSWORD="yyy" \
-BLUECATV2_CONFIG_NAME="myConfiguration" \
-BLUECATV2_VIEW_NAME="myView" \
-lego --dns bluecatv2 -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `BLUECATV2_CONFIG_NAME` | Configuration name |
-| `BLUECATV2_PASSWORD` | API password |
-| `BLUECATV2_USERNAME` | API username |
-| `BLUECATV2_VIEW_NAME` | DNS View Name |
-| `BLUECAT_SERVER_URL` | The server URL: it should have a scheme, hostname, and port (if required) of the authoritative Bluecat BAM serve |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `BLUECATV2_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `BLUECATV2_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `BLUECATV2_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `BLUECATV2_SKIP_DEPLOY` | Skip quick deployements |
-| `BLUECATV2_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Introduction/9.6.0)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_bookmyname.md b/docs/content/dns/zz_gen_bookmyname.md
index cb7e1d3a1..3f5d1f2c3 100644
--- a/docs/content/dns/zz_gen_bookmyname.md
+++ b/docs/content/dns/zz_gen_bookmyname.md
@@ -28,7 +28,7 @@ Here is an example bash command using the BookMyName provider:
```bash
BOOKMYNAME_USERNAME="xxx" \
BOOKMYNAME_PASSWORD="yyy" \
-lego --dns bookmyname -d '*.example.com' -d example.com run
+lego --email you@example.com --dns bookmyname -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_brandit.md b/docs/content/dns/zz_gen_brandit.md
index fdb538684..5d1f91214 100644
--- a/docs/content/dns/zz_gen_brandit.md
+++ b/docs/content/dns/zz_gen_brandit.md
@@ -31,7 +31,7 @@ Here is an example bash command using the Brandit (deprecated) provider:
```bash
BRANDIT_API_KEY=xxxxxxxxxxxxxxxxxxxxx \
BRANDIT_API_USERNAME=yyyyyyyyyyyyyyyyyyyy \
-lego --dns brandit -d '*.example.com' -d example.com run
+lego --email you@example.com --dns brandit -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_bunny.md b/docs/content/dns/zz_gen_bunny.md
index 63c30782a..7b4db2020 100644
--- a/docs/content/dns/zz_gen_bunny.md
+++ b/docs/content/dns/zz_gen_bunny.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Bunny provider:
```bash
BUNNY_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
-lego --dns bunny -d '*.example.com' -d example.com run
+lego --email you@example.com --dns bunny -d '*.example.com' -d example.com run
```
@@ -47,7 +47,6 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
-| `BUNNY_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `BUNNY_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `BUNNY_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
| `BUNNY_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
diff --git a/docs/content/dns/zz_gen_checkdomain.md b/docs/content/dns/zz_gen_checkdomain.md
index e0275f6c9..516d87880 100644
--- a/docs/content/dns/zz_gen_checkdomain.md
+++ b/docs/content/dns/zz_gen_checkdomain.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Checkdomain provider:
```bash
CHECKDOMAIN_TOKEN=yoursecrettoken \
-lego --dns checkdomain -d '*.example.com' -d example.com run
+lego --email you@example.com --dns checkdomain -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_civo.md b/docs/content/dns/zz_gen_civo.md
index 61303b539..a2cffe27c 100644
--- a/docs/content/dns/zz_gen_civo.md
+++ b/docs/content/dns/zz_gen_civo.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Civo provider:
```bash
CIVO_TOKEN=xxxxxx \
-lego --dns civo -d '*.example.com' -d example.com run
+lego --email you@example.com --dns civo -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_clouddns.md b/docs/content/dns/zz_gen_clouddns.md
index d10d1d6a1..27a254873 100644
--- a/docs/content/dns/zz_gen_clouddns.md
+++ b/docs/content/dns/zz_gen_clouddns.md
@@ -29,7 +29,7 @@ Here is an example bash command using the CloudDNS provider:
CLOUDDNS_CLIENT_ID=bLsdFAks23429841238feb177a572aX \
CLOUDDNS_EMAIL=you@example.com \
CLOUDDNS_PASSWORD=b9841238feb177a84330f \
-lego --dns clouddns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns clouddns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_cloudflare.md b/docs/content/dns/zz_gen_cloudflare.md
index f3390a5fd..0fd1d440e 100644
--- a/docs/content/dns/zz_gen_cloudflare.md
+++ b/docs/content/dns/zz_gen_cloudflare.md
@@ -28,12 +28,12 @@ Here is an example bash command using the Cloudflare provider:
```bash
CLOUDFLARE_EMAIL=you@example.com \
CLOUDFLARE_API_KEY=b9841238feb177a84330febba8a83208921177bffe733 \
-lego --dns cloudflare -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudflare -d '*.example.com' -d example.com run
# or
CLOUDFLARE_DNS_API_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz \
-lego --dns cloudflare -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudflare -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_cloudns.md b/docs/content/dns/zz_gen_cloudns.md
index 26bd838f2..01d4b7815 100644
--- a/docs/content/dns/zz_gen_cloudns.md
+++ b/docs/content/dns/zz_gen_cloudns.md
@@ -28,7 +28,7 @@ Here is an example bash command using the ClouDNS provider:
```bash
CLOUDNS_AUTH_ID=xxxx \
CLOUDNS_AUTH_PASSWORD=yyyy \
-lego --dns cloudns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_cloudru.md b/docs/content/dns/zz_gen_cloudru.md
index 6dc3b0030..52190b031 100644
--- a/docs/content/dns/zz_gen_cloudru.md
+++ b/docs/content/dns/zz_gen_cloudru.md
@@ -29,7 +29,7 @@ Here is an example bash command using the Cloud.ru provider:
CLOUDRU_SERVICE_INSTANCE_ID=ppp \
CLOUDRU_KEY_ID=xxx \
CLOUDRU_SECRET=yyy \
-lego --dns cloudru -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudru -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_cloudxns.md b/docs/content/dns/zz_gen_cloudxns.md
index b26e5ddb5..0b290b693 100644
--- a/docs/content/dns/zz_gen_cloudxns.md
+++ b/docs/content/dns/zz_gen_cloudxns.md
@@ -28,7 +28,7 @@ Here is an example bash command using the CloudXNS (Deprecated) provider:
```bash
CLOUDXNS_API_KEY=xxxx \
CLOUDXNS_SECRET_KEY=yyyy \
-lego --dns cloudxns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudxns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_com35.md b/docs/content/dns/zz_gen_com35.md
deleted file mode 100644
index e2552e57c..000000000
--- a/docs/content/dns/zz_gen_com35.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "35.com/三五互联"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: com35
-dnsprovider:
- since: "v4.31.0"
- code: "com35"
- url: "https://www.35.cn/"
----
-
-
-
-
-
-
-Configuration for [35.com/三五互联](https://www.35.cn/).
-
-
-
-
-- Code: `com35`
-- Since: v4.31.0
-
-
-Here is an example bash command using the 35.com/三五互联 provider:
-
-```bash
-COM35_USERNAME="xxx" \
-COM35_PASSWORD="yyy" \
-lego --dns com35 -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `COM35_PASSWORD` | API password |
-| `COM35_USERNAME` | Username |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `COM35_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `COM35_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
-| `COM35_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
-| `COM35_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://api.35.cn/CustomerCenter/doc/domain_v2.html)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_conoha.md b/docs/content/dns/zz_gen_conoha.md
index 08a979b31..4d5f84660 100644
--- a/docs/content/dns/zz_gen_conoha.md
+++ b/docs/content/dns/zz_gen_conoha.md
@@ -29,7 +29,7 @@ Here is an example bash command using the ConoHa v2 provider:
CONOHA_TENANT_ID=487727e3921d44e3bfe7ebb337bf085e \
CONOHA_API_USERNAME=xxxx \
CONOHA_API_PASSWORD=yyyy \
-lego --dns conoha -d '*.example.com' -d example.com run
+lego --email you@example.com --dns conoha -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_conohav3.md b/docs/content/dns/zz_gen_conohav3.md
index e473f9434..208f2f91b 100644
--- a/docs/content/dns/zz_gen_conohav3.md
+++ b/docs/content/dns/zz_gen_conohav3.md
@@ -29,7 +29,7 @@ Here is an example bash command using the ConoHa v3 provider:
CONOHAV3_TENANT_ID=487727e3921d44e3bfe7ebb337bf085e \
CONOHAV3_API_USER_ID=xxxx \
CONOHAV3_API_PASSWORD=yyyy \
-lego --dns conohav3 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns conohav3 -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_constellix.md b/docs/content/dns/zz_gen_constellix.md
index d4ce02bac..23628e001 100644
--- a/docs/content/dns/zz_gen_constellix.md
+++ b/docs/content/dns/zz_gen_constellix.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Constellix provider:
```bash
CONSTELLIX_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
CONSTELLIX_SECRET_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
-lego --dns constellix -d '*.example.com' -d example.com run
+lego --email you@example.com --dns constellix -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_corenetworks.md b/docs/content/dns/zz_gen_corenetworks.md
index 05468b1a3..dc756647e 100644
--- a/docs/content/dns/zz_gen_corenetworks.md
+++ b/docs/content/dns/zz_gen_corenetworks.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Core-Networks provider:
```bash
CORENETWORKS_LOGIN="xxxx" \
CORENETWORKS_PASSWORD="yyyy" \
-lego --dns corenetworks -d '*.example.com' -d example.com run
+lego --email you@example.com --dns corenetworks -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_cpanel.md b/docs/content/dns/zz_gen_cpanel.md
index e5c0cc047..48cb229e7 100644
--- a/docs/content/dns/zz_gen_cpanel.md
+++ b/docs/content/dns/zz_gen_cpanel.md
@@ -31,7 +31,7 @@ Here is an example bash command using the CPanel/WHM provider:
CPANEL_USERNAME="yyyy" \
CPANEL_TOKEN="xxxx" \
CPANEL_BASE_URL="https://example.com:2083" \
-lego --dns cpanel -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cpanel -d '*.example.com' -d example.com run
## WHM
@@ -39,7 +39,7 @@ CPANEL_MODE=whm \
CPANEL_USERNAME="yyyy" \
CPANEL_TOKEN="xxxx" \
CPANEL_BASE_URL="https://example.com:2087" \
-lego --dns cpanel -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cpanel -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_czechia.md b/docs/content/dns/zz_gen_czechia.md
deleted file mode 100644
index 7b1cdd1ae..000000000
--- a/docs/content/dns/zz_gen_czechia.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Czechia"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: czechia
-dnsprovider:
- since: "v4.33.0"
- code: "czechia"
- url: "https://www.czechia.com/"
----
-
-
-
-
-
-
-Configuration for [Czechia](https://www.czechia.com/).
-
-
-
-
-- Code: `czechia`
-- Since: v4.33.0
-
-
-Here is an example bash command using the Czechia provider:
-
-```bash
-CZECHIA_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns czechia -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `CZECHIA_TOKEN` | Authorization token |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `CZECHIA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `CZECHIA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `CZECHIA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `CZECHIA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://api.czechia.com/swagger/index.html)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_ddnss.md b/docs/content/dns/zz_gen_ddnss.md
deleted file mode 100644
index e159d58b4..000000000
--- a/docs/content/dns/zz_gen_ddnss.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: "DDnss (DynDNS Service)"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: ddnss
-dnsprovider:
- since: "v4.32.0"
- code: "ddnss"
- url: "https://ddnss.de/"
----
-
-
-
-
-
-
-Configuration for [DDnss (DynDNS Service)](https://ddnss.de/).
-
-
-
-
-- Code: `ddnss`
-- Since: v4.32.0
-
-
-Here is an example bash command using the DDnss (DynDNS Service) provider:
-
-```bash
-DDNSS_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns ddnss -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `DDNSS_KEY` | Update key |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `DDNSS_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `DDNSS_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `DDNSS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `DDNSS_SEQUENCE_INTERVAL` | Time between sequential requests in seconds (Default: 60) |
-| `DDNSS_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://ddnss.de/info.php)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_derak.md b/docs/content/dns/zz_gen_derak.md
index c5c8c7bc6..fedbf4683 100644
--- a/docs/content/dns/zz_gen_derak.md
+++ b/docs/content/dns/zz_gen_derak.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Derak Cloud provider:
```bash
DERAK_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns derak -d '*.example.com' -d example.com run
+lego --email you@example.com --dns derak -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_desec.md b/docs/content/dns/zz_gen_desec.md
index 4dbc713d6..977a00e06 100644
--- a/docs/content/dns/zz_gen_desec.md
+++ b/docs/content/dns/zz_gen_desec.md
@@ -27,7 +27,7 @@ Here is an example bash command using the deSEC.io provider:
```bash
DESEC_TOKEN=x-xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns desec -d '*.example.com' -d example.com run
+lego --email you@example.com --dns desec -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_designate.md b/docs/content/dns/zz_gen_designate.md
index 9703f094d..74cd04920 100644
--- a/docs/content/dns/zz_gen_designate.md
+++ b/docs/content/dns/zz_gen_designate.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Designate DNSaaS for Openstack provide
```bash
# With a `clouds.yaml`
OS_CLOUD=my_openstack \
-lego --dns designate -d '*.example.com' -d example.com run
+lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
# or
@@ -37,7 +37,7 @@ OS_REGION_NAME=RegionOne \
OS_PROJECT_ID=23d4522a987d4ab529f722a007c27846
OS_USERNAME=myuser \
OS_PASSWORD=passw0rd \
-lego --dns designate -d '*.example.com' -d example.com run
+lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
# or
@@ -46,7 +46,7 @@ OS_REGION_NAME=RegionOne \
OS_AUTH_TYPE=v3applicationcredential \
OS_APPLICATION_CREDENTIAL_ID=imn74uq0or7dyzz20dwo1ytls4me8dry \
OS_APPLICATION_CREDENTIAL_SECRET=68FuSPSdQqkFQYH5X1OoriEIJOwyLtQ8QSqXZOc9XxFK1A9tzZT6He2PfPw0OMja \
-lego --dns designate -d '*.example.com' -d example.com run
+lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_digitalocean.md b/docs/content/dns/zz_gen_digitalocean.md
index 4dc43886d..24307cfb0 100644
--- a/docs/content/dns/zz_gen_digitalocean.md
+++ b/docs/content/dns/zz_gen_digitalocean.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Digital Ocean provider:
```bash
DO_AUTH_TOKEN=xxxxxx \
-lego --dns digitalocean -d '*.example.com' -d example.com run
+lego --email you@example.com --dns digitalocean -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_directadmin.md b/docs/content/dns/zz_gen_directadmin.md
index 1d03dcc4e..006cb87d6 100644
--- a/docs/content/dns/zz_gen_directadmin.md
+++ b/docs/content/dns/zz_gen_directadmin.md
@@ -29,7 +29,7 @@ Here is an example bash command using the DirectAdmin provider:
DIRECTADMIN_API_URL="http://example.com:2222" \
DIRECTADMIN_USERNAME=xxxx \
DIRECTADMIN_PASSWORD=yyy \
-lego --dns directadmin -d '*.example.com' -d example.com run
+lego --email you@example.com --dns directadmin -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_dnsexit.md b/docs/content/dns/zz_gen_dnsexit.md
deleted file mode 100644
index aca5357e8..000000000
--- a/docs/content/dns/zz_gen_dnsexit.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "DNSExit"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: dnsexit
-dnsprovider:
- since: "v4.32.0"
- code: "dnsexit"
- url: "https://dnsexit.com"
----
-
-
-
-
-
-
-Configuration for [DNSExit](https://dnsexit.com).
-
-
-
-
-- Code: `dnsexit`
-- Since: v4.32.0
-
-
-Here is an example bash command using the DNSExit provider:
-
-```bash
-DNSEXIT_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns dnsexit -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `DNSEXIT_API_KEY` | API key |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `DNSEXIT_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `DNSEXIT_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
-| `DNSEXIT_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 300) |
-| `DNSEXIT_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://dnsexit.com/dns/dns-api/)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_dnshomede.md b/docs/content/dns/zz_gen_dnshomede.md
index ca7f83523..b865578e6 100644
--- a/docs/content/dns/zz_gen_dnshomede.md
+++ b/docs/content/dns/zz_gen_dnshomede.md
@@ -27,10 +27,10 @@ Here is an example bash command using the dnsHome.de provider:
```bash
DNSHOMEDE_CREDENTIALS=example.org:password \
-lego --dns dnshomede -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dnshomede -d '*.example.com' -d example.com run
DNSHOMEDE_CREDENTIALS=my.example.org:password1,demo.example.org:password2 \
-lego --dns dnshomede -d my.example.org -d demo.example.org
+lego --email you@example.com --dns dnshomede -d my.example.org -d demo.example.org
```
diff --git a/docs/content/dns/zz_gen_dnsimple.md b/docs/content/dns/zz_gen_dnsimple.md
index 7799ece88..d73122273 100644
--- a/docs/content/dns/zz_gen_dnsimple.md
+++ b/docs/content/dns/zz_gen_dnsimple.md
@@ -27,7 +27,7 @@ Here is an example bash command using the DNSimple provider:
```bash
DNSIMPLE_OAUTH_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz \
-lego --dns dnsimple -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dnsimple -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_dnsmadeeasy.md b/docs/content/dns/zz_gen_dnsmadeeasy.md
index e7f260889..572676fbd 100644
--- a/docs/content/dns/zz_gen_dnsmadeeasy.md
+++ b/docs/content/dns/zz_gen_dnsmadeeasy.md
@@ -28,7 +28,7 @@ Here is an example bash command using the DNS Made Easy provider:
```bash
DNSMADEEASY_API_KEY=xxxxxx \
DNSMADEEASY_API_SECRET=yyyyy \
-lego --dns dnsmadeeasy -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dnsmadeeasy -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_dnspod.md b/docs/content/dns/zz_gen_dnspod.md
index 86112a5ce..b9e906052 100644
--- a/docs/content/dns/zz_gen_dnspod.md
+++ b/docs/content/dns/zz_gen_dnspod.md
@@ -27,7 +27,7 @@ Here is an example bash command using the DNSPod (deprecated) provider:
```bash
DNSPOD_API_KEY=xxxxxx \
-lego --dns dnspod -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dnspod -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_dode.md b/docs/content/dns/zz_gen_dode.md
index 28eebe5fa..153650406 100644
--- a/docs/content/dns/zz_gen_dode.md
+++ b/docs/content/dns/zz_gen_dode.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Domain Offensive (do.de) provider:
```bash
DODE_TOKEN=xxxxxx \
-lego --dns dode -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dode -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_domeneshop.md b/docs/content/dns/zz_gen_domeneshop.md
index 0530ab365..a519cfbef 100644
--- a/docs/content/dns/zz_gen_domeneshop.md
+++ b/docs/content/dns/zz_gen_domeneshop.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Domeneshop provider:
```bash
DOMENESHOP_API_TOKEN= \
DOMENESHOP_API_SECRET= \
-lego --dns domeneshop -d '*.example.com' -d example.com run
+lego --email example@example.com --dns domeneshop -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_dreamhost.md b/docs/content/dns/zz_gen_dreamhost.md
index b9d273099..e713b8ad2 100644
--- a/docs/content/dns/zz_gen_dreamhost.md
+++ b/docs/content/dns/zz_gen_dreamhost.md
@@ -27,7 +27,7 @@ Here is an example bash command using the DreamHost provider:
```bash
DREAMHOST_API_KEY="YOURAPIKEY" \
-lego --dns dreamhost -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dreamhost -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_duckdns.md b/docs/content/dns/zz_gen_duckdns.md
index 8b60780d2..1290b82fd 100644
--- a/docs/content/dns/zz_gen_duckdns.md
+++ b/docs/content/dns/zz_gen_duckdns.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Duck DNS provider:
```bash
DUCKDNS_TOKEN=xxxxxx \
-lego --dns duckdns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns duckdns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_dyn.md b/docs/content/dns/zz_gen_dyn.md
index e31a90e45..f241ea930 100644
--- a/docs/content/dns/zz_gen_dyn.md
+++ b/docs/content/dns/zz_gen_dyn.md
@@ -29,7 +29,7 @@ Here is an example bash command using the Dyn provider:
DYN_CUSTOMER_NAME=xxxxxx \
DYN_USER_NAME=yyyyy \
DYN_PASSWORD=zzzz \
-lego --dns dyn -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dyn -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_dyndnsfree.md b/docs/content/dns/zz_gen_dyndnsfree.md
index ea549b4e2..6f4cf46ff 100644
--- a/docs/content/dns/zz_gen_dyndnsfree.md
+++ b/docs/content/dns/zz_gen_dyndnsfree.md
@@ -28,7 +28,7 @@ Here is an example bash command using the DynDnsFree.de provider:
```bash
DYNDNSFREE_USERNAME="xxx" \
DYNDNSFREE_PASSWORD="yyy" \
-lego --dns dyndnsfree -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dyndnsfree -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_dynu.md b/docs/content/dns/zz_gen_dynu.md
index a1f3e762e..4db76456f 100644
--- a/docs/content/dns/zz_gen_dynu.md
+++ b/docs/content/dns/zz_gen_dynu.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Dynu provider:
```bash
DYNU_API_KEY=1234567890abcdefghijklmnopqrstuvwxyz \
-lego --dns dynu -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dynu -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_easydns.md b/docs/content/dns/zz_gen_easydns.md
index 12f69e09c..196e6ab7c 100644
--- a/docs/content/dns/zz_gen_easydns.md
+++ b/docs/content/dns/zz_gen_easydns.md
@@ -28,7 +28,7 @@ Here is an example bash command using the EasyDNS provider:
```bash
EASYDNS_TOKEN=xxx \
EASYDNS_KEY=yyy \
-lego --dns easydns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns easydns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_edgecenter.md b/docs/content/dns/zz_gen_edgecenter.md
deleted file mode 100644
index 1fd9fe5fa..000000000
--- a/docs/content/dns/zz_gen_edgecenter.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "EdgeCenter"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: edgecenter
-dnsprovider:
- since: "v4.29.0"
- code: "edgecenter"
- url: "https://edgecenter.ru/dns"
----
-
-
-
-
-
-
-Configuration for [EdgeCenter](https://edgecenter.ru/dns).
-
-
-
-
-- Code: `edgecenter`
-- Since: v4.29.0
-
-
-Here is an example bash command using the EdgeCenter provider:
-
-```bash
-EDGECENTER_PERMANENT_API_TOKEN=xxxxx \
-lego --dns edgecenter -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `EDGECENTER_PERMANENT_API_TOKEN` | Permanent API token (https://edgecenter.ru/blog/permanent-api-token-explained/) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `EDGECENTER_HTTP_TIMEOUT` | API request timeout in seconds (Default: 10) |
-| `EDGECENTER_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 20) |
-| `EDGECENTER_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 360) |
-| `EDGECENTER_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://apidocs.edgecenter.ru/dns)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_edgedns.md b/docs/content/dns/zz_gen_edgedns.md
index 31b191168..21d819d2c 100644
--- a/docs/content/dns/zz_gen_edgedns.md
+++ b/docs/content/dns/zz_gen_edgedns.md
@@ -30,7 +30,7 @@ AKAMAI_CLIENT_SECRET=abcdefghijklmnopqrstuvwxyz1234567890ABCDEFG= \
AKAMAI_CLIENT_TOKEN=akab-mnbvcxzlkjhgfdsapoiuytrewq1234567 \
AKAMAI_HOST=akab-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.luna.akamaiapis.net \
AKAMAI_ACCESS_TOKEN=akab-1234567890qwerty-asdfghjklzxcvtnu \
-lego --dns edgedns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns edgedns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_edgeone.md b/docs/content/dns/zz_gen_edgeone.md
deleted file mode 100644
index ba5de5ba2..000000000
--- a/docs/content/dns/zz_gen_edgeone.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: "Tencent EdgeOne"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: edgeone
-dnsprovider:
- since: "v4.26.0"
- code: "edgeone"
- url: "https://edgeone.ai"
----
-
-
-
-
-
-
-Configuration for [Tencent EdgeOne](https://edgeone.ai).
-
-
-
-
-- Code: `edgeone`
-- Since: v4.26.0
-
-
-Here is an example bash command using the Tencent EdgeOne provider:
-
-```bash
-EDGEONE_SECRET_ID=abcdefghijklmnopqrstuvwx \
-EDGEONE_SECRET_KEY=your-secret-key \
-lego --dns edgeone -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `EDGEONE_SECRET_ID` | Access key ID |
-| `EDGEONE_SECRET_KEY` | Access Key secret |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `EDGEONE_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `EDGEONE_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 30) |
-| `EDGEONE_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 1200) |
-| `EDGEONE_REGION` | Region |
-| `EDGEONE_SESSION_TOKEN` | Access Key token |
-| `EDGEONE_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
-| `EDGEONE_ZONES_MAPPING` | Mapping between DNS zones and site IDs. (ex: 'example.org:id1,example.com:id2') |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://edgeone.ai/document/50454#dns-record-apis)
-- [Go client](https://github.com/tencentcloud/tencentcloud-sdk-go)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_efficientip.md b/docs/content/dns/zz_gen_efficientip.md
index acca3ebb7..7c151e67a 100644
--- a/docs/content/dns/zz_gen_efficientip.md
+++ b/docs/content/dns/zz_gen_efficientip.md
@@ -30,7 +30,7 @@ EFFICIENTIP_USERNAME="user" \
EFFICIENTIP_PASSWORD="secret" \
EFFICIENTIP_HOSTNAME="ipam.example.org" \
EFFICIENTIP_DNS_NAME="dns.smart" \
-lego --dns efficientip -d '*.example.com' -d example.com run
+lego --email you@example.com --dns efficientip -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_epik.md b/docs/content/dns/zz_gen_epik.md
index a7fc029d3..50f66e8da 100644
--- a/docs/content/dns/zz_gen_epik.md
+++ b/docs/content/dns/zz_gen_epik.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Epik provider:
```bash
EPIK_SIGNATURE=xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns epik -d '*.example.com' -d example.com run
+lego --email you@example.com --dns epik -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_eurodns.md b/docs/content/dns/zz_gen_eurodns.md
deleted file mode 100644
index cb5a0418d..000000000
--- a/docs/content/dns/zz_gen_eurodns.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "EuroDNS"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: eurodns
-dnsprovider:
- since: "v4.33.0"
- code: "eurodns"
- url: "https://www.eurodns.com/"
----
-
-
-
-
-
-
-Configuration for [EuroDNS](https://www.eurodns.com/).
-
-
-
-
-- Code: `eurodns`
-- Since: v4.33.0
-
-
-Here is an example bash command using the EuroDNS provider:
-
-```bash
-EURODNS_APP_ID="xxx" \
-EURODNS_API_KEY="yyy" \
-lego --dns eurodns -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `EURODNS_API_KEY` | API key |
-| `EURODNS_APP_ID` | Application ID |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `EURODNS_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `EURODNS_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `EURODNS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `EURODNS_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 600) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://docapi.eurodns.com/)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_excedo.md b/docs/content/dns/zz_gen_excedo.md
deleted file mode 100644
index 456e6f60a..000000000
--- a/docs/content/dns/zz_gen_excedo.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "Excedo"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: excedo
-dnsprovider:
- since: "v4.33.0"
- code: "excedo"
- url: "https://excedo.se/"
----
-
-
-
-
-
-
-Configuration for [Excedo](https://excedo.se/).
-
-
-
-
-- Code: `excedo`
-- Since: v4.33.0
-
-
-Here is an example bash command using the Excedo provider:
-
-```bash
-EXCEDO_API_KEY=your-api-key \
-EXCEDO_API_URL=your-base-url \
-lego --dns excedo -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `EXCEDO_API_KEY` | API key |
-| `EXCEDO_API_URL` | API base URL |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `EXCEDO_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `EXCEDO_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
-| `EXCEDO_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 300) |
-| `EXCEDO_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](none)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_exec.md b/docs/content/dns/zz_gen_exec.md
index ad2e6906e..fb2b17e3d 100644
--- a/docs/content/dns/zz_gen_exec.md
+++ b/docs/content/dns/zz_gen_exec.md
@@ -26,7 +26,7 @@ Here is an example bash command using the External program provider:
```bash
EXEC_PATH=/the/path/to/myscript.sh \
-lego --dns exec -d '*.example.com' -d example.com run
+lego --email you@example.com --dns exec -d '*.example.com' -d example.com run
```
@@ -61,7 +61,7 @@ For example, requesting a certificate for the domain 'my.example.org' can be ach
```bash
EXEC_PATH=./update-dns.sh \
-lego --dns exec --d my.example.org run
+lego --email you@example.com --dns exec --d my.example.org run
```
It will then call the program './update-dns.sh' with like this:
@@ -81,7 +81,7 @@ If you want to use the raw domain, token, and keyAuth values with your program,
```bash
EXEC_MODE=RAW \
EXEC_PATH=./update-dns.sh \
-lego --dns exec -d my.example.org run
+lego --email you@example.com --dns exec -d my.example.org run
```
It will then call the program `./update-dns.sh` like this:
diff --git a/docs/content/dns/zz_gen_exoscale.md b/docs/content/dns/zz_gen_exoscale.md
index e599d6487..5392ff573 100644
--- a/docs/content/dns/zz_gen_exoscale.md
+++ b/docs/content/dns/zz_gen_exoscale.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Exoscale provider:
```bash
EXOSCALE_API_KEY=abcdefghijklmnopqrstuvwx \
EXOSCALE_API_SECRET=xxxxxxx \
-lego --dns exoscale -d '*.example.com' -d example.com run
+lego --email you@example.com --dns exoscale -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_f5xc.md b/docs/content/dns/zz_gen_f5xc.md
index 0fd8fe58a..c8a664a00 100644
--- a/docs/content/dns/zz_gen_f5xc.md
+++ b/docs/content/dns/zz_gen_f5xc.md
@@ -29,7 +29,7 @@ Here is an example bash command using the F5 XC provider:
F5XC_API_TOKEN="xxx" \
F5XC_TENANT_NAME="yyy" \
F5XC_GROUP_NAME="zzz" \
-lego --dns f5xc -d '*.example.com' -d example.com run
+lego --email you@example.com --dns f5xc -d '*.example.com' -d example.com run
```
@@ -54,7 +54,6 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| `F5XC_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `F5XC_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `F5XC_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `F5XC_SERVER` | Server domain (Default: console.ves.volterra.io) |
| `F5XC_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
diff --git a/docs/content/dns/zz_gen_freemyip.md b/docs/content/dns/zz_gen_freemyip.md
index 215f8eb84..d89e17c27 100644
--- a/docs/content/dns/zz_gen_freemyip.md
+++ b/docs/content/dns/zz_gen_freemyip.md
@@ -27,7 +27,7 @@ Here is an example bash command using the freemyip.com provider:
```bash
FREEMYIP_TOKEN=xxxxxx \
-lego --dns freemyip -d '*.example.com' -d example.com run
+lego --email you@example.com --dns freemyip -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_gandi.md b/docs/content/dns/zz_gen_gandi.md
index b02d97819..961ed6873 100644
--- a/docs/content/dns/zz_gen_gandi.md
+++ b/docs/content/dns/zz_gen_gandi.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Gandi provider:
```bash
GANDI_API_KEY=abcdefghijklmnopqrstuvwx \
-lego --dns gandi -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gandi -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_gandiv5.md b/docs/content/dns/zz_gen_gandiv5.md
index 78824abbe..773bd3b08 100644
--- a/docs/content/dns/zz_gen_gandiv5.md
+++ b/docs/content/dns/zz_gen_gandiv5.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Gandi Live DNS (v5) provider:
```bash
GANDIV5_PERSONAL_ACCESS_TOKEN=abcdefghijklmnopqrstuvwx \
-lego --dns gandiv5 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gandiv5 -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_gcloud.md b/docs/content/dns/zz_gen_gcloud.md
index 64acc1d1e..ff228a1c8 100644
--- a/docs/content/dns/zz_gen_gcloud.md
+++ b/docs/content/dns/zz_gen_gcloud.md
@@ -29,18 +29,18 @@ Here is an example bash command using the Google Cloud provider:
# Using a service account file
GCE_PROJECT="gc-project-id" \
GCE_SERVICE_ACCOUNT_FILE="/path/to/svc/account/file.json" \
-lego --dns gcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gcloud -d '*.example.com' -d example.com run
# Using default credentials with impersonation
GCE_PROJECT="gc-project-id" \
GCE_IMPERSONATE_SERVICE_ACCOUNT="target-sa@gc-project-id.iam.gserviceaccount.com" \
-lego --dns gcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gcloud -d '*.example.com' -d example.com run
# Using service account key with impersonation
GCE_PROJECT="gc-project-id" \
GCE_SERVICE_ACCOUNT_FILE="/path/to/svc/account/file.json" \
GCE_IMPERSONATE_SERVICE_ACCOUNT="target-sa@gc-project-id.iam.gserviceaccount.com" \
-lego --dns gcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gcloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_gcore.md b/docs/content/dns/zz_gen_gcore.md
index 21a7ee9b1..f2a17c3fb 100644
--- a/docs/content/dns/zz_gen_gcore.md
+++ b/docs/content/dns/zz_gen_gcore.md
@@ -27,7 +27,7 @@ Here is an example bash command using the G-Core provider:
```bash
GCORE_PERMANENT_API_TOKEN=xxxxx \
-lego --dns gcore -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gcore -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_gigahostno.md b/docs/content/dns/zz_gen_gigahostno.md
deleted file mode 100644
index a59ffc401..000000000
--- a/docs/content/dns/zz_gen_gigahostno.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: "Gigahost.no"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: gigahostno
-dnsprovider:
- since: "v4.29.0"
- code: "gigahostno"
- url: "https://gigahost.no/"
----
-
-
-
-
-
-
-Configuration for [Gigahost.no](https://gigahost.no/).
-
-
-
-
-- Code: `gigahostno`
-- Since: v4.29.0
-
-
-Here is an example bash command using the Gigahost.no provider:
-
-```bash
-GIGAHOSTNO_USERNAME="xxxxxxxxxxxxxxxxxxxxx" \
-GIGAHOSTNO_PASSWORD="yyyyyyyyyyyyyyyyyyyyy" \
-lego --dns gigahostno -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `GIGAHOSTNO_PASSWORD` | Password |
-| `GIGAHOSTNO_USERNAME` | Username |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `GIGAHOSTNO_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `GIGAHOSTNO_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `GIGAHOSTNO_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `GIGAHOSTNO_SECRET` | TOTP secret |
-| `GIGAHOSTNO_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://gigahost.no/api-dokumentasjon)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_glesys.md b/docs/content/dns/zz_gen_glesys.md
index 2d2608330..ff43cfe9a 100644
--- a/docs/content/dns/zz_gen_glesys.md
+++ b/docs/content/dns/zz_gen_glesys.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Glesys provider:
```bash
GLESYS_API_USER=xxxxx \
GLESYS_API_KEY=yyyyy \
-lego --dns glesys -d '*.example.com' -d example.com run
+lego --email you@example.com --dns glesys -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_godaddy.md b/docs/content/dns/zz_gen_godaddy.md
index bc51cd69b..c5392a878 100644
--- a/docs/content/dns/zz_gen_godaddy.md
+++ b/docs/content/dns/zz_gen_godaddy.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Go Daddy provider:
```bash
GODADDY_API_KEY=xxxxxxxx \
GODADDY_API_SECRET=yyyyyyyy \
-lego --dns godaddy -d '*.example.com' -d example.com run
+lego --email you@example.com --dns godaddy -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_googledomains.md b/docs/content/dns/zz_gen_googledomains.md
index 2421184c0..c6f6d0577 100644
--- a/docs/content/dns/zz_gen_googledomains.md
+++ b/docs/content/dns/zz_gen_googledomains.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Google Domains provider:
```bash
GOOGLE_DOMAINS_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns googledomains -d '*.example.com' -d example.com run
+lego --email you@example.com --dns googledomains -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_gravity.md b/docs/content/dns/zz_gen_gravity.md
deleted file mode 100644
index 654ad8424..000000000
--- a/docs/content/dns/zz_gen_gravity.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: "Gravity"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: gravity
-dnsprovider:
- since: "v4.30.0"
- code: "gravity"
- url: "https://gravity.beryju.io/"
----
-
-
-
-
-
-
-Configuration for [Gravity](https://gravity.beryju.io/).
-
-
-
-
-- Code: `gravity`
-- Since: v4.30.0
-
-
-Here is an example bash command using the Gravity provider:
-
-```bash
-GRAVITY_SERVER_URL="https://example.org:1234" \
-GRAVITY_USERNAME="xxxxxxxxxxxxxxxxxxxxx" \
-GRAVITY_PASSWORD="yyyyyyyyyyyyyyyyyyyyy" \
-lego --dns gravity -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `GRAVITY_PASSWORD` | Password |
-| `GRAVITY_SERVER_URL` | URL of the server |
-| `GRAVITY_USERNAME` | Username |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `GRAVITY_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `GRAVITY_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `GRAVITY_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `GRAVITY_SEQUENCE_INTERVAL` | Time between sequential requests in seconds (Default: 1) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://gravity.beryju.io/docs/api/reference/)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_hetzner.md b/docs/content/dns/zz_gen_hetzner.md
index 4e81bd4d9..a42175e8d 100644
--- a/docs/content/dns/zz_gen_hetzner.md
+++ b/docs/content/dns/zz_gen_hetzner.md
@@ -26,8 +26,8 @@ Configuration for [Hetzner](https://hetzner.com).
Here is an example bash command using the Hetzner provider:
```bash
-HETZNER_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns hetzner -d '*.example.com' -d example.com run
+HETZNER_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
+lego --email you@example.com --dns hetzner -d '*.example.com' -d example.com run
```
@@ -37,7 +37,7 @@ lego --dns hetzner -d '*.example.com' -d example.com run
| Environment Variable Name | Description |
|-----------------------|-------------|
-| `HETZNER_API_TOKEN` | API token |
+| `HETZNER_API_KEY` | API key |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
@@ -49,8 +49,8 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
|--------------------------------|-------------|
| `HETZNER_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `HETZNER_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `HETZNER_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `HETZNER_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
+| `HETZNER_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
+| `HETZNER_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
@@ -60,7 +60,7 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
-- [API documentation](https://docs.hetzner.cloud/reference/cloud#dns)
+- [API documentation](https://dns.hetzner.com/api-docs)
diff --git a/docs/content/dns/zz_gen_hostingde.md b/docs/content/dns/zz_gen_hostingde.md
index 4a66fe0f1..cc86116e1 100644
--- a/docs/content/dns/zz_gen_hostingde.md
+++ b/docs/content/dns/zz_gen_hostingde.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Hosting.de provider:
```bash
HOSTINGDE_API_KEY=xxxxxxxx \
-lego --dns hostingde -d '*.example.com' -d example.com run
+lego --email you@example.com --dns hostingde -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_hostinger.md b/docs/content/dns/zz_gen_hostinger.md
deleted file mode 100644
index c05b3f003..000000000
--- a/docs/content/dns/zz_gen_hostinger.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Hostinger"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: hostinger
-dnsprovider:
- since: "v4.27.0"
- code: "hostinger"
- url: "https://www.hostinger.com/"
----
-
-
-
-
-
-
-Configuration for [Hostinger](https://www.hostinger.com/).
-
-
-
-
-- Code: `hostinger`
-- Since: v4.27.0
-
-
-Here is an example bash command using the Hostinger provider:
-
-```bash
-HOSTINGER_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns hostinger -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `HOSTINGER_API_TOKEN` | API Token |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `HOSTINGER_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `HOSTINGER_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `HOSTINGER_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `HOSTINGER_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://developers.hostinger.com/#tag/dns-zone)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_hostingnl.md b/docs/content/dns/zz_gen_hostingnl.md
deleted file mode 100644
index 09cb69b47..000000000
--- a/docs/content/dns/zz_gen_hostingnl.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Hosting.nl"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: hostingnl
-dnsprovider:
- since: "v4.30.0"
- code: "hostingnl"
- url: "https://hosting.nl"
----
-
-
-
-
-
-
-Configuration for [Hosting.nl](https://hosting.nl).
-
-
-
-
-- Code: `hostingnl`
-- Since: v4.30.0
-
-
-Here is an example bash command using the Hosting.nl provider:
-
-```bash
-HOSTINGNL_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns hostingnl -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `HOSTINGNL_API_KEY` | The API key |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `HOSTINGNL_HTTP_TIMEOUT` | API request timeout in seconds (Default: 10) |
-| `HOSTINGNL_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `HOSTINGNL_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
-| `HOSTINGNL_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://api.hosting.nl/api/documentation)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_hosttech.md b/docs/content/dns/zz_gen_hosttech.md
index 9435cc562..4f9f117ba 100644
--- a/docs/content/dns/zz_gen_hosttech.md
+++ b/docs/content/dns/zz_gen_hosttech.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Hosttech provider:
```bash
HOSTTECH_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns hosttech -d '*.example.com' -d example.com run
+lego --email you@example.com --dns hosttech -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_httpnet.md b/docs/content/dns/zz_gen_httpnet.md
index 862909697..06883b3f8 100644
--- a/docs/content/dns/zz_gen_httpnet.md
+++ b/docs/content/dns/zz_gen_httpnet.md
@@ -27,7 +27,7 @@ Here is an example bash command using the http.net provider:
```bash
HTTPNET_API_KEY=xxxxxxxx \
-lego --dns httpnet -d '*.example.com' -d example.com run
+lego --email you@example.com --dns httpnet -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_httpreq.md b/docs/content/dns/zz_gen_httpreq.md
index 7f6a8d576..9c6476802 100644
--- a/docs/content/dns/zz_gen_httpreq.md
+++ b/docs/content/dns/zz_gen_httpreq.md
@@ -27,7 +27,7 @@ Here is an example bash command using the HTTP request provider:
```bash
HTTPREQ_ENDPOINT=http://my.server.com:9090 \
-lego --dns httpreq -d '*.example.com' -d example.com run
+lego --email you@example.com --dns httpreq -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_huaweicloud.md b/docs/content/dns/zz_gen_huaweicloud.md
index 46d121265..9a37a8878 100644
--- a/docs/content/dns/zz_gen_huaweicloud.md
+++ b/docs/content/dns/zz_gen_huaweicloud.md
@@ -29,7 +29,7 @@ Here is an example bash command using the Huawei Cloud provider:
HUAWEICLOUD_ACCESS_KEY_ID=your-access-key-id \
HUAWEICLOUD_SECRET_ACCESS_KEY=your-secret-access-key \
HUAWEICLOUD_REGION=cn-south-1 \
-lego --dns huaweicloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns huaweicloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_hurricane.md b/docs/content/dns/zz_gen_hurricane.md
index 0c195d19c..da78630d4 100644
--- a/docs/content/dns/zz_gen_hurricane.md
+++ b/docs/content/dns/zz_gen_hurricane.md
@@ -27,10 +27,10 @@ Here is an example bash command using the Hurricane Electric DNS provider:
```bash
HURRICANE_TOKENS=example.org:token \
-lego --dns hurricane -d '*.example.com' -d example.com run
+lego --email you@example.com --dns hurricane -d '*.example.com' -d example.com run
HURRICANE_TOKENS=my.example.org:token1,demo.example.org:token2 \
-lego --dns hurricane -d my.example.org -d demo.example.org
+lego --email you@example.com --dns hurricane -d my.example.org -d demo.example.org
```
diff --git a/docs/content/dns/zz_gen_hyperone.md b/docs/content/dns/zz_gen_hyperone.md
index bc496f7bc..83dfdb111 100644
--- a/docs/content/dns/zz_gen_hyperone.md
+++ b/docs/content/dns/zz_gen_hyperone.md
@@ -26,7 +26,7 @@ Configuration for [HyperOne](https://www.hyperone.com).
Here is an example bash command using the HyperOne provider:
```bash
-lego --dns hyperone -d '*.example.com' -d example.com run
+lego --email you@example.com --dns hyperone -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_ibmcloud.md b/docs/content/dns/zz_gen_ibmcloud.md
index c5a48d2ad..c2f9f4fe1 100644
--- a/docs/content/dns/zz_gen_ibmcloud.md
+++ b/docs/content/dns/zz_gen_ibmcloud.md
@@ -28,7 +28,7 @@ Here is an example bash command using the IBM Cloud (SoftLayer) provider:
```bash
SOFTLAYER_USERNAME=xxxxx \
SOFTLAYER_API_KEY=yyyyy \
-lego --dns ibmcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ibmcloud -d '*.example.com' -d example.com run
```
@@ -39,7 +39,7 @@ lego --dns ibmcloud -d '*.example.com' -d example.com run
| Environment Variable Name | Description |
|-----------------------|-------------|
| `SOFTLAYER_API_KEY` | Classic Infrastructure API key |
-| `SOFTLAYER_USERNAME` | Username (IBM Cloud is {accountID}_{emailAddress}) |
+| `SOFTLAYER_USERNAME` | Username (IBM Cloud is _) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
diff --git a/docs/content/dns/zz_gen_iij.md b/docs/content/dns/zz_gen_iij.md
index c7acfe3a0..8c73f58a5 100644
--- a/docs/content/dns/zz_gen_iij.md
+++ b/docs/content/dns/zz_gen_iij.md
@@ -29,7 +29,7 @@ Here is an example bash command using the Internet Initiative Japan provider:
IIJ_API_ACCESS_KEY=xxxxxxxx \
IIJ_API_SECRET_KEY=yyyyyy \
IIJ_DO_SERVICE_CODE=zzzzzz \
-lego --dns iij -d '*.example.com' -d example.com run
+lego --email you@example.com --dns iij -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_iijdpf.md b/docs/content/dns/zz_gen_iijdpf.md
index 12e126f49..7c694fc32 100644
--- a/docs/content/dns/zz_gen_iijdpf.md
+++ b/docs/content/dns/zz_gen_iijdpf.md
@@ -28,7 +28,7 @@ Here is an example bash command using the IIJ DNS Platform Service provider:
```bash
IIJ_DPF_API_TOKEN=xxxxxxxx \
IIJ_DPF_DPM_SERVICE_CODE=yyyyyy \
-lego --dns iijdpf -d '*.example.com' -d example.com run
+lego --email you@example.com --dns iijdpf -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_infoblox.md b/docs/content/dns/zz_gen_infoblox.md
index 74b80b2d1..2d07628f3 100644
--- a/docs/content/dns/zz_gen_infoblox.md
+++ b/docs/content/dns/zz_gen_infoblox.md
@@ -29,7 +29,7 @@ Here is an example bash command using the Infoblox provider:
INFOBLOX_USERNAME=api-user-529 \
INFOBLOX_PASSWORD=b9841238feb177a84330febba8a83208921177bffe733 \
INFOBLOX_HOST=infoblox.example.org
-lego --dns infoblox -d '*.example.com' -d example.com run
+lego --email you@example.com --dns infoblox -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_infomaniak.md b/docs/content/dns/zz_gen_infomaniak.md
index 7254241b1..be02d8ee8 100644
--- a/docs/content/dns/zz_gen_infomaniak.md
+++ b/docs/content/dns/zz_gen_infomaniak.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Infomaniak provider:
```bash
INFOMANIAK_ACCESS_TOKEN=1234567898765432 \
-lego --dns infomaniak -d '*.example.com' -d example.com run
+lego --email you@example.com --dns infomaniak -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_internetbs.md b/docs/content/dns/zz_gen_internetbs.md
index f0d9df3c1..e98fbf4b9 100644
--- a/docs/content/dns/zz_gen_internetbs.md
+++ b/docs/content/dns/zz_gen_internetbs.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Internet.bs provider:
```bash
INTERNET_BS_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx \
INTERNET_BS_PASSWORD=yyyyyyyyyyyyyyyyyyyyyyyyyy \
-lego --dns internetbs -d '*.example.com' -d example.com run
+lego --email you@example.com --dns internetbs -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_inwx.md b/docs/content/dns/zz_gen_inwx.md
index 3e7d999e9..a46ff061e 100644
--- a/docs/content/dns/zz_gen_inwx.md
+++ b/docs/content/dns/zz_gen_inwx.md
@@ -28,13 +28,13 @@ Here is an example bash command using the INWX provider:
```bash
INWX_USERNAME=xxxxxxxxxx \
INWX_PASSWORD=yyyyyyyyyy \
-lego --dns inwx -d '*.example.com' -d example.com run
+lego --email you@example.com --dns inwx -d '*.example.com' -d example.com run
# 2FA
INWX_USERNAME=xxxxxxxxxx \
INWX_PASSWORD=yyyyyyyyyy \
INWX_SHARED_SECRET=zzzzzzzzzz \
-lego --dns inwx -d '*.example.com' -d example.com run
+lego --email you@example.com --dns inwx -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_ionos.md b/docs/content/dns/zz_gen_ionos.md
index 78bd3ffb1..60a2ede03 100644
--- a/docs/content/dns/zz_gen_ionos.md
+++ b/docs/content/dns/zz_gen_ionos.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Ionos provider:
```bash
IONOS_API_KEY=xxxxxxxx \
-lego --dns ionos -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ionos -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_ionoscloud.md b/docs/content/dns/zz_gen_ionoscloud.md
deleted file mode 100644
index 6007670a7..000000000
--- a/docs/content/dns/zz_gen_ionoscloud.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Ionos Cloud"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: ionoscloud
-dnsprovider:
- since: "v4.30.0"
- code: "ionoscloud"
- url: "https://cloud.ionos.de/network/cloud-dns"
----
-
-
-
-
-
-
-Configuration for [Ionos Cloud](https://cloud.ionos.de/network/cloud-dns).
-
-
-
-
-- Code: `ionoscloud`
-- Since: v4.30.0
-
-
-Here is an example bash command using the Ionos Cloud provider:
-
-```bash
-IONOSCLOUD_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns ionoscloud -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `IONOSCLOUD_API_TOKEN` | API token |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `IONOSCLOUD_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `IONOSCLOUD_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `IONOSCLOUD_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
-| `IONOSCLOUD_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://api.ionos.com/docs/dns/v1/)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_ipv64.md b/docs/content/dns/zz_gen_ipv64.md
index 00a0292a6..21327caaf 100644
--- a/docs/content/dns/zz_gen_ipv64.md
+++ b/docs/content/dns/zz_gen_ipv64.md
@@ -27,7 +27,7 @@ Here is an example bash command using the IPv64 provider:
```bash
IPV64_API_KEY=xxxxxx \
-lego --dns ipv64 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ipv64 -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_ispconfig.md b/docs/content/dns/zz_gen_ispconfig.md
deleted file mode 100644
index e56f1f0b1..000000000
--- a/docs/content/dns/zz_gen_ispconfig.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-title: "ISPConfig 3"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: ispconfig
-dnsprovider:
- since: "v4.31.0"
- code: "ispconfig"
- url: "https://www.ispconfig.org/"
----
-
-
-
-
-
-
-Configuration for [ISPConfig 3](https://www.ispconfig.org/).
-
-
-
-
-- Code: `ispconfig`
-- Since: v4.31.0
-
-
-Here is an example bash command using the ISPConfig 3 provider:
-
-```bash
-ISPCONFIG_SERVER_URL="https://example.com:8080/remote/json.php" \
-ISPCONFIG_USERNAME="xxx" \
-ISPCONFIG_PASSWORD="yyy" \
-lego --dns ispconfig -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `ISPCONFIG_PASSWORD` | Password |
-| `ISPCONFIG_SERVER_URL` | Server URL |
-| `ISPCONFIG_USERNAME` | Username |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `ISPCONFIG_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `ISPCONFIG_INSECURE_SKIP_VERIFY` | Whether to verify the API certificate |
-| `ISPCONFIG_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `ISPCONFIG_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `ISPCONFIG_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/API-docs/index.html)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_ispconfigddns.md b/docs/content/dns/zz_gen_ispconfigddns.md
deleted file mode 100644
index 3d1dd83c3..000000000
--- a/docs/content/dns/zz_gen_ispconfigddns.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-title: "ISPConfig 3 - Dynamic DNS (DDNS) Module"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: ispconfigddns
-dnsprovider:
- since: "v4.31.0"
- code: "ispconfigddns"
- url: "https://www.ispconfig.org/"
----
-
-
-
-
-
-
-Configuration for [ISPConfig 3 - Dynamic DNS (DDNS) Module](https://www.ispconfig.org/).
-
-
-
-
-- Code: `ispconfigddns`
-- Since: v4.31.0
-
-
-Here is an example bash command using the ISPConfig 3 - Dynamic DNS (DDNS) Module provider:
-
-```bash
-ISPCONFIG_DDNS_SERVER_URL="https://panel.example.com:8080" \
-ISPCONFIG_DDNS_TOKEN=xxxxxx \
-lego --dns ispconfigddns -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `ISPCONFIG_DDNS_SERVER_URL` | API server URL (ex: https://panel.example.com:8080) |
-| `ISPCONFIG_DDNS_TOKEN` | DDNS API token |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `ISPCONFIG_DDNS_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `ISPCONFIG_DDNS_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `ISPCONFIG_DDNS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `ISPCONFIG_DDNS_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 3600) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-ISPConfig DNS provider supports leveraging the [ISPConfig 3 Dynamic DNS (DDNS) Module](https://github.com/mhofer117/ispconfig-ddns-module).
-
-Requires the DDNS module described at https://www.ispconfig.org/ispconfig/download/
-
-See https://www.howtoforge.com/community/threads/ispconfig-3-danymic-dns-ddns-module.87967/ for additional details.
-
-
-
-## More information
-
-- [API documentation](https://github.com/mhofer117/ispconfig-ddns-module/tree/master/lib/updater)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_iwantmyname.md b/docs/content/dns/zz_gen_iwantmyname.md
index 4638e1379..251bf2096 100644
--- a/docs/content/dns/zz_gen_iwantmyname.md
+++ b/docs/content/dns/zz_gen_iwantmyname.md
@@ -1,5 +1,5 @@
---
-title: "iwantmyname (Deprecated)"
+title: "iwantmyname"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: iwantmyname
@@ -13,10 +13,8 @@ dnsprovider:
-The iwantmyname API has shut down.
-
-https://github.com/go-acme/lego/issues/2563
+Configuration for [iwantmyname](https://iwantmyname.com).
@@ -25,12 +23,12 @@ https://github.com/go-acme/lego/issues/2563
- Since: v4.7.0
-Here is an example bash command using the iwantmyname (Deprecated) provider:
+Here is an example bash command using the iwantmyname provider:
```bash
IWANTMYNAME_USERNAME=xxxxxxxx \
IWANTMYNAME_PASSWORD=xxxxxxxx \
-lego --dns iwantmyname -d '*.example.com' -d example.com run
+lego --email you@example.com --dns iwantmyname -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_jdcloud.md b/docs/content/dns/zz_gen_jdcloud.md
deleted file mode 100644
index a37cc3520..000000000
--- a/docs/content/dns/zz_gen_jdcloud.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: "JD Cloud"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: jdcloud
-dnsprovider:
- since: "v4.31.0"
- code: "jdcloud"
- url: "https://www.jdcloud.com/"
----
-
-
-
-
-
-
-Configuration for [JD Cloud](https://www.jdcloud.com/).
-
-
-
-
-- Code: `jdcloud`
-- Since: v4.31.0
-
-
-Here is an example bash command using the JD Cloud provider:
-
-```bash
-JDCLOUD_ACCESS_KEY_ID="xxx" \
-JDCLOUD_ACCESS_KEY_SECRET="yyy" \
-lego --dns jdcloud -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `JDCLOUD_ACCESS_KEY_ID` | Access key ID |
-| `JDCLOUD_ACCESS_KEY_SECRET` | Access key secret |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `JDCLOUD_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `JDCLOUD_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `JDCLOUD_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `JDCLOUD_REGION_ID` | Region ID (Default: cn-north-1) |
-| `JDCLOUD_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://docs.jdcloud.com/cn/jd-cloud-dns/api/overview)
-- [Go client](https://github.com/jdcloud-api/jdcloud-sdk-go)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_joker.md b/docs/content/dns/zz_gen_joker.md
index a5ecd47de..c8d55b2f7 100644
--- a/docs/content/dns/zz_gen_joker.md
+++ b/docs/content/dns/zz_gen_joker.md
@@ -30,17 +30,17 @@ Here is an example bash command using the Joker provider:
JOKER_API_MODE=SVC \
JOKER_USERNAME= \
JOKER_PASSWORD= \
-lego --dns joker -d '*.example.com' -d example.com run
+lego --email you@example.com --dns joker -d '*.example.com' -d example.com run
# DMAPI
JOKER_API_MODE=DMAPI \
JOKER_USERNAME= \
JOKER_PASSWORD= \
-lego --dns joker -d '*.example.com' -d example.com run
+lego --email you@example.com --dns joker -d '*.example.com' -d example.com run
## or
JOKER_API_MODE=DMAPI \
JOKER_API_KEY= \
-lego --dns joker -d '*.example.com' -d example.com run
+lego --email you@example.com --dns joker -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_keyhelp.md b/docs/content/dns/zz_gen_keyhelp.md
deleted file mode 100644
index e39d3ce82..000000000
--- a/docs/content/dns/zz_gen_keyhelp.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "KeyHelp"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: keyhelp
-dnsprovider:
- since: "v4.26.0"
- code: "keyhelp"
- url: "https://www.keyweb.de/en/keyhelp/keyhelp/"
----
-
-
-
-
-
-
-Configuration for [KeyHelp](https://www.keyweb.de/en/keyhelp/keyhelp/).
-
-
-
-
-- Code: `keyhelp`
-- Since: v4.26.0
-
-
-Here is an example bash command using the KeyHelp provider:
-
-```bash
-KEYHELP_BASE_URL="https://keyhelp.example.com" \
-KEYHELP_API_KEY="xxx" \
-lego --dns keyhelp -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `KEYHELP_API_KEY` | API key |
-| `KEYHELP_BASE_URL` | Server URL |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `KEYHELP_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `KEYHELP_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `KEYHELP_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `KEYHELP_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://app.swaggerhub.com/apis-docs/keyhelp/api/)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_leaseweb.md b/docs/content/dns/zz_gen_leaseweb.md
deleted file mode 100644
index 13ded490a..000000000
--- a/docs/content/dns/zz_gen_leaseweb.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Leaseweb"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: leaseweb
-dnsprovider:
- since: "v4.32.0"
- code: "leaseweb"
- url: "https://www.leaseweb.com/en/"
----
-
-
-
-
-
-
-Configuration for [Leaseweb](https://www.leaseweb.com/en/).
-
-
-
-
-- Code: `leaseweb`
-- Since: v4.32.0
-
-
-Here is an example bash command using the Leaseweb provider:
-
-```bash
-LEASEWEB_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns leaseweb -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `LEASEWEB_API_KEY` | API key |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `LEASEWEB_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `LEASEWEB_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `LEASEWEB_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `LEASEWEB_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://developer.leaseweb.com/docs/#tag/DNS)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_liara.md b/docs/content/dns/zz_gen_liara.md
index 658ce8077..2c3d59ae0 100644
--- a/docs/content/dns/zz_gen_liara.md
+++ b/docs/content/dns/zz_gen_liara.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Liara provider:
```bash
LIARA_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns liara -d '*.example.com' -d example.com run
+lego --email you@example.com --dns liara -d '*.example.com' -d example.com run
```
@@ -50,7 +50,6 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| `LIARA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `LIARA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `LIARA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `LIARA_TEAM_ID` | The team ID to access services in a team |
| `LIARA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 3600) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
diff --git a/docs/content/dns/zz_gen_limacity.md b/docs/content/dns/zz_gen_limacity.md
index 29bc6e0a7..2a01814e5 100644
--- a/docs/content/dns/zz_gen_limacity.md
+++ b/docs/content/dns/zz_gen_limacity.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Lima-City provider:
```bash
LIMACITY_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns limacity -d '*.example.com' -d example.com run
+lego --email you@example.com --dns limacity -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_linode.md b/docs/content/dns/zz_gen_linode.md
index e41ba7cd9..8c8487541 100644
--- a/docs/content/dns/zz_gen_linode.md
+++ b/docs/content/dns/zz_gen_linode.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Linode (v4) provider:
```bash
LINODE_TOKEN=xxxxx \
-lego --dns linode -d '*.example.com' -d example.com run
+lego --email you@example.com --dns linode -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_liquidweb.md b/docs/content/dns/zz_gen_liquidweb.md
index bd2ce63b6..9d8fe8c9c 100644
--- a/docs/content/dns/zz_gen_liquidweb.md
+++ b/docs/content/dns/zz_gen_liquidweb.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Liquid Web provider:
```bash
LWAPI_USERNAME=someuser \
LWAPI_PASSWORD=somepass \
-lego --dns liquidweb -d '*.example.com' -d example.com run
+lego --email you@example.com --dns liquidweb -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_loopia.md b/docs/content/dns/zz_gen_loopia.md
index bb3120c00..3951de8e1 100644
--- a/docs/content/dns/zz_gen_loopia.md
+++ b/docs/content/dns/zz_gen_loopia.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Loopia provider:
```bash
LOOPIA_API_USER=xxxxxxxx \
LOOPIA_API_PASSWORD=yyyyyyyy \
-lego --dns loopia -d '*.example.com' -d example.com run
+lego --email you@example.com --dns loopia -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_luadns.md b/docs/content/dns/zz_gen_luadns.md
index 8bf718ba3..c987cc9bf 100644
--- a/docs/content/dns/zz_gen_luadns.md
+++ b/docs/content/dns/zz_gen_luadns.md
@@ -28,7 +28,7 @@ Here is an example bash command using the LuaDNS provider:
```bash
LUADNS_API_USERNAME=youremail \
LUADNS_API_TOKEN=xxxxxxxx \
-lego --dns luadns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns luadns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_mailinabox.md b/docs/content/dns/zz_gen_mailinabox.md
index 62a6bdb57..8b5048c60 100644
--- a/docs/content/dns/zz_gen_mailinabox.md
+++ b/docs/content/dns/zz_gen_mailinabox.md
@@ -29,7 +29,7 @@ Here is an example bash command using the Mail-in-a-Box provider:
MAILINABOX_EMAIL=user@example.com \
MAILINABOX_PASSWORD=yyyy \
MAILINABOX_BASE_URL=https://box.example.com \
-lego --dns mailinabox -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mailinabox -d '*.example.com' -d example.com run
```
@@ -51,7 +51,6 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
-| `MAILINABOX_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `MAILINABOX_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 4) |
| `MAILINABOX_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
diff --git a/docs/content/dns/zz_gen_manageengine.md b/docs/content/dns/zz_gen_manageengine.md
index a39db8208..32b3a3aeb 100644
--- a/docs/content/dns/zz_gen_manageengine.md
+++ b/docs/content/dns/zz_gen_manageengine.md
@@ -28,7 +28,7 @@ Here is an example bash command using the ManageEngine CloudDNS provider:
```bash
MANAGEENGINE_CLIENT_ID="xxx" \
MANAGEENGINE_CLIENT_SECRET="yyy" \
-lego --dns manageengine -d '*.example.com' -d example.com run
+lego --email you@example.com --dns manageengine -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_manual.md b/docs/content/dns/zz_gen_manual.md
deleted file mode 100644
index 832ccaf58..000000000
--- a/docs/content/dns/zz_gen_manual.md
+++ /dev/null
@@ -1,98 +0,0 @@
----
-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 --dns manual -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Example
-
-To start using the CLI prompt "provider", start lego with `--dns manual`:
-
-```console
-$ lego --dns manual -d example.com 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
-configuration directory at "./.lego/accounts".
-
-You should make a secure backup of this folder now. This
-configuration directory will also contain private keys
-generated by lego and certificates obtained from the ACME
-server. 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/docs/content/dns/zz_gen_metaname.md b/docs/content/dns/zz_gen_metaname.md
index 156cf15eb..a90d0170b 100644
--- a/docs/content/dns/zz_gen_metaname.md
+++ b/docs/content/dns/zz_gen_metaname.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Metaname provider:
```bash
METANAME_ACCOUNT_REFERENCE=xxxx \
METANAME_API_KEY=yyyyyyy \
-lego --dns metaname -d '*.example.com' -d example.com run
+lego --email you@example.com --dns metaname -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_metaregistrar.md b/docs/content/dns/zz_gen_metaregistrar.md
index 22de046e2..63cc2bebc 100644
--- a/docs/content/dns/zz_gen_metaregistrar.md
+++ b/docs/content/dns/zz_gen_metaregistrar.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Metaregistrar provider:
```bash
METAREGISTRAR_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns metaregistrar -d '*.example.com' -d example.com run
+lego --email you@example.com --dns metaregistrar -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_mijnhost.md b/docs/content/dns/zz_gen_mijnhost.md
index 3d8f71aff..42abc6558 100644
--- a/docs/content/dns/zz_gen_mijnhost.md
+++ b/docs/content/dns/zz_gen_mijnhost.md
@@ -27,7 +27,7 @@ Here is an example bash command using the mijn.host provider:
```bash
MIJNHOST_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns mijnhost -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mijnhost -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_mittwald.md b/docs/content/dns/zz_gen_mittwald.md
index 7714ef54f..943397ee9 100644
--- a/docs/content/dns/zz_gen_mittwald.md
+++ b/docs/content/dns/zz_gen_mittwald.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Mittwald provider:
```bash
MITTWALD_TOKEN=my-token \
-lego --dns mittwald -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mittwald -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_myaddr.md b/docs/content/dns/zz_gen_myaddr.md
index 4a52a058b..277a0bf06 100644
--- a/docs/content/dns/zz_gen_myaddr.md
+++ b/docs/content/dns/zz_gen_myaddr.md
@@ -27,7 +27,7 @@ Here is an example bash command using the myaddr.{tools,dev,io} provider:
```bash
MYADDR_PRIVATE_KEYS_MAPPING="example:123,test:456" \
-lego --dns myaddr -d '*.example.com' -d example.com run
+lego --email you@example.com --dns myaddr -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_mydnsjp.md b/docs/content/dns/zz_gen_mydnsjp.md
index 0a49404bb..5b29266db 100644
--- a/docs/content/dns/zz_gen_mydnsjp.md
+++ b/docs/content/dns/zz_gen_mydnsjp.md
@@ -28,7 +28,7 @@ Here is an example bash command using the MyDNS.jp provider:
```bash
MYDNSJP_MASTER_ID=xxxxx \
MYDNSJP_PASSWORD=xxxxx \
-lego --dns mydnsjp -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mydnsjp -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_mythicbeasts.md b/docs/content/dns/zz_gen_mythicbeasts.md
index 70e38d249..37feebf8c 100644
--- a/docs/content/dns/zz_gen_mythicbeasts.md
+++ b/docs/content/dns/zz_gen_mythicbeasts.md
@@ -28,7 +28,7 @@ Here is an example bash command using the MythicBeasts provider:
```bash
MYTHICBEASTS_USERNAME=myuser \
MYTHICBEASTS_PASSWORD=mypass \
-lego --dns mythicbeasts -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mythicbeasts -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_namecheap.md b/docs/content/dns/zz_gen_namecheap.md
index 9d7143d84..706651660 100644
--- a/docs/content/dns/zz_gen_namecheap.md
+++ b/docs/content/dns/zz_gen_namecheap.md
@@ -33,7 +33,7 @@ Here is an example bash command using the Namecheap provider:
```bash
NAMECHEAP_API_USER=user \
NAMECHEAP_API_KEY=key \
-lego --dns namecheap -d '*.example.com' -d example.com run
+lego --email you@example.com --dns namecheap -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_namedotcom.md b/docs/content/dns/zz_gen_namedotcom.md
index 2860ff0ae..36a423faa 100644
--- a/docs/content/dns/zz_gen_namedotcom.md
+++ b/docs/content/dns/zz_gen_namedotcom.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Name.com provider:
```bash
NAMECOM_USERNAME=foo.bar \
NAMECOM_API_TOKEN=a379a6f6eeafb9a55e378c118034e2751e682fab \
-lego --dns namedotcom -d '*.example.com' -d example.com run
+lego --email you@example.com --dns namedotcom -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_namesilo.md b/docs/content/dns/zz_gen_namesilo.md
index 207a1603f..397a1a3ca 100644
--- a/docs/content/dns/zz_gen_namesilo.md
+++ b/docs/content/dns/zz_gen_namesilo.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Namesilo provider:
```bash
NAMESILO_API_KEY=b9841238feb177a84330febba8a83208921177bffe733 \
-lego --dns namesilo -d '*.example.com' -d example.com run
+lego --email you@example.com --dns namesilo -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_namesurfer.md b/docs/content/dns/zz_gen_namesurfer.md
deleted file mode 100644
index 9a2802d0e..000000000
--- a/docs/content/dns/zz_gen_namesurfer.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: "FusionLayer NameSurfer"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: namesurfer
-dnsprovider:
- since: "v4.32.0"
- code: "namesurfer"
- url: "https://www.fusionlayer.com/"
----
-
-
-
-
-
-
-Configuration for [FusionLayer NameSurfer](https://www.fusionlayer.com/).
-
-
-
-
-- Code: `namesurfer`
-- Since: v4.32.0
-
-
-Here is an example bash command using the FusionLayer NameSurfer provider:
-
-```bash
-NAMESURFER_BASE_URL=https://foo.example.com:8443/API/NSService_10 \
-NAMESURFER_API_KEY=xxx \
-NAMESURFER_API_SECRET=yyy \
-lego --dns namesurfer -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `NAMESURFER_API_KEY` | API key name |
-| `NAMESURFER_API_SECRET` | API secret |
-| `NAMESURFER_BASE_URL` | The base URL of NameSurfer API (jsonrpc10) endpoint URL (e.g., https://foo.example.com:8443/API/NSService_10) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `NAMESURFER_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `NAMESURFER_INSECURE_SKIP_VERIFY` | Whether to verify the API certificate |
-| `NAMESURFER_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `NAMESURFER_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
-| `NAMESURFER_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 300) |
-| `NAMESURFER_VIEW` | DNS view name (optional, default: empty string) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://web.archive.org/web/20260213170737/http://95.128.3.201:8053/API/NSService_10)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_nearlyfreespeech.md b/docs/content/dns/zz_gen_nearlyfreespeech.md
index 31402d2d2..86f6152f9 100644
--- a/docs/content/dns/zz_gen_nearlyfreespeech.md
+++ b/docs/content/dns/zz_gen_nearlyfreespeech.md
@@ -28,7 +28,7 @@ Here is an example bash command using the NearlyFreeSpeech.NET provider:
```bash
NEARLYFREESPEECH_API_KEY=xxxxxx \
NEARLYFREESPEECH_LOGIN=xxxx \
-lego --dns nearlyfreespeech -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nearlyfreespeech -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_neodigit.md b/docs/content/dns/zz_gen_neodigit.md
deleted file mode 100644
index aefeef4bf..000000000
--- a/docs/content/dns/zz_gen_neodigit.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Neodigit"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: neodigit
-dnsprovider:
- since: "v4.30.0"
- code: "neodigit"
- url: "https://www.neodigit.net"
----
-
-
-
-
-
-
-Configuration for [Neodigit](https://www.neodigit.net).
-
-
-
-
-- Code: `neodigit`
-- Since: v4.30.0
-
-
-Here is an example bash command using the Neodigit provider:
-
-```bash
-NEODIGIT_TOKEN=xxxxxx \
-lego --dns neodigit -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `NEODIGIT_TOKEN` | API token |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `NEODIGIT_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `NEODIGIT_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
-| `NEODIGIT_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 300) |
-| `NEODIGIT_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://developers.neodigit.net/#dns)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_netcup.md b/docs/content/dns/zz_gen_netcup.md
index 29def3285..337baf59d 100644
--- a/docs/content/dns/zz_gen_netcup.md
+++ b/docs/content/dns/zz_gen_netcup.md
@@ -29,7 +29,7 @@ Here is an example bash command using the Netcup provider:
NETCUP_CUSTOMER_NUMBER=xxxx \
NETCUP_API_KEY=yyyy \
NETCUP_API_PASSWORD=zzzz \
-lego --dns netcup -d '*.example.com' -d example.com run
+lego --email you@example.com --dns netcup -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_netlify.md b/docs/content/dns/zz_gen_netlify.md
index 76651d9ef..b08f650f0 100644
--- a/docs/content/dns/zz_gen_netlify.md
+++ b/docs/content/dns/zz_gen_netlify.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Netlify provider:
```bash
NETLIFY_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns netlify -d '*.example.com' -d example.com run
+lego --email you@example.com --dns netlify -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_nicmanager.md b/docs/content/dns/zz_gen_nicmanager.md
index a29d72120..0b6e1b2cb 100644
--- a/docs/content/dns/zz_gen_nicmanager.md
+++ b/docs/content/dns/zz_gen_nicmanager.md
@@ -34,7 +34,7 @@ NICMANAGER_API_PASSWORD = "password" \
# Optionally, if your account has TOTP enabled, set the secret here
NICMANAGER_API_OTP = "long-secret" \
-lego --dns nicmanager -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nicmanager -d '*.example.com' -d example.com run
## Login using account name + username
@@ -45,7 +45,7 @@ NICMANAGER_API_PASSWORD = "password" \
# Optionally, if your account has TOTP enabled, set the secret here
NICMANAGER_API_OTP = "long-secret" \
-lego --dns nicmanager -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nicmanager -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_nicru.md b/docs/content/dns/zz_gen_nicru.md
index 3ac8d99cf..d55477a32 100644
--- a/docs/content/dns/zz_gen_nicru.md
+++ b/docs/content/dns/zz_gen_nicru.md
@@ -30,7 +30,7 @@ NICRU_USER="" \
NICRU_PASSWORD="" \
NICRU_SERVICE_ID="" \
NICRU_SECRET="" \
-lego --dns nicru -d '*.example.com' -d example.com run
+lego --dns nicru --domains "*.example.com" --email you@example.com run
```
diff --git a/docs/content/dns/zz_gen_nifcloud.md b/docs/content/dns/zz_gen_nifcloud.md
index 66f38223b..9b9929ce2 100644
--- a/docs/content/dns/zz_gen_nifcloud.md
+++ b/docs/content/dns/zz_gen_nifcloud.md
@@ -28,7 +28,7 @@ Here is an example bash command using the NIFCloud provider:
```bash
NIFCLOUD_ACCESS_KEY_ID=xxxx \
NIFCLOUD_SECRET_ACCESS_KEY=yyyy \
-lego --dns nifcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nifcloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_njalla.md b/docs/content/dns/zz_gen_njalla.md
index 9a312df8b..cf268041c 100644
--- a/docs/content/dns/zz_gen_njalla.md
+++ b/docs/content/dns/zz_gen_njalla.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Njalla provider:
```bash
NJALLA_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns njalla -d '*.example.com' -d example.com run
+lego --email you@example.com --dns njalla -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_nodion.md b/docs/content/dns/zz_gen_nodion.md
index 8d61eb834..c11759e8e 100644
--- a/docs/content/dns/zz_gen_nodion.md
+++ b/docs/content/dns/zz_gen_nodion.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Nodion provider:
```bash
NODION_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns nodion -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nodion -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_ns1.md b/docs/content/dns/zz_gen_ns1.md
index b2262169d..547a51c1c 100644
--- a/docs/content/dns/zz_gen_ns1.md
+++ b/docs/content/dns/zz_gen_ns1.md
@@ -27,7 +27,7 @@ Here is an example bash command using the NS1 provider:
```bash
NS1_API_KEY=xxxx \
-lego --dns ns1 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ns1 -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_octenium.md b/docs/content/dns/zz_gen_octenium.md
deleted file mode 100644
index f25da4f44..000000000
--- a/docs/content/dns/zz_gen_octenium.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Octenium"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: octenium
-dnsprovider:
- since: "v4.27.0"
- code: "octenium"
- url: "https://octenium.com/"
----
-
-
-
-
-
-
-Configuration for [Octenium](https://octenium.com/).
-
-
-
-
-- Code: `octenium`
-- Since: v4.27.0
-
-
-Here is an example bash command using the Octenium provider:
-
-```bash
-OCTENIUM_API_KEY="xxx" \
-lego --dns octenium -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `OCTENIUM_API_KEY` | API key |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `OCTENIUM_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `OCTENIUM_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `OCTENIUM_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `OCTENIUM_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://octenium.com/api#tag/Domains-DNS)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_oraclecloud.md b/docs/content/dns/zz_gen_oraclecloud.md
index b7192f380..1adf58088 100644
--- a/docs/content/dns/zz_gen_oraclecloud.md
+++ b/docs/content/dns/zz_gen_oraclecloud.md
@@ -26,21 +26,14 @@ Configuration for [Oracle Cloud](https://cloud.oracle.com/home).
Here is an example bash command using the Oracle Cloud provider:
```bash
-# Using API Key authentication:
-OCI_PRIVATE_KEY_PATH="~/.oci/oci_api_key.pem" \
-OCI_PRIVATE_KEY_PASSWORD="secret" \
+OCI_PRIVKEY_FILE="~/.oci/oci_api_key.pem" \
+OCI_PRIVKEY_PASS="secret" \
OCI_TENANCY_OCID="ocid1.tenancy.oc1..secret" \
OCI_USER_OCID="ocid1.user.oc1..secret" \
-OCI_FINGERPRINT="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" \
+OCI_PUBKEY_FINGERPRINT="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" \
OCI_REGION="us-phoenix-1" \
OCI_COMPARTMENT_OCID="ocid1.tenancy.oc1..secret" \
-lego --dns oraclecloud -d '*.example.com' -d example.com run
-
-# Using Instance Principal authentication (when running on OCI compute instances):
-# https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm
-OCI_AUTH_TYPE="instance_principal" \
-OCI_COMPARTMENT_OCID="ocid1.tenancy.oc1..secret" \
-lego --dns oraclecloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns oraclecloud -d '*.example.com' -d example.com run
```
@@ -51,12 +44,12 @@ lego --dns oraclecloud -d '*.example.com' -d example.com run
| Environment Variable Name | Description |
|-----------------------|-------------|
| `OCI_COMPARTMENT_OCID` | Compartment OCID |
-| `OCI_FINGERPRINT` | Public key fingerprint (ignored if `OCI_AUTH_TYPE=instance_principal`) |
-| `OCI_PRIVATE_KEY_PASSWORD` | Private key password (ignored if `OCI_AUTH_TYPE=instance_principal`) |
-| `OCI_PRIVATE_KEY_PATH` | Private key file (ignored if `OCI_AUTH_TYPE=instance_principal`) |
-| `OCI_REGION` | Region (it can be empty if `OCI_AUTH_TYPE=instance_principal`). |
-| `OCI_TENANCY_OCID` | Tenancy OCID (ignored if `OCI_AUTH_TYPE=instance_principal`) |
-| `OCI_USER_OCID` | User OCID (ignored if `OCI_AUTH_TYPE=instance_principal`) |
+| `OCI_PRIVKEY_FILE` | Private key file |
+| `OCI_PRIVKEY_PASS` | Private key password |
+| `OCI_PUBKEY_FINGERPRINT` | Public key fingerprint |
+| `OCI_REGION` | Region |
+| `OCI_TENANCY_OCID` | Tenancy OCID |
+| `OCI_USER_OCID` | User OCID |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
@@ -66,16 +59,10 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
-| `OCI_AUTH_TYPE` | Authorization type. Possible values: 'instance_principal', '' (Default: '') |
| `OCI_HTTP_TIMEOUT` | API request timeout in seconds (Default: 60) |
| `OCI_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `OCI_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `OCI_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-| `TF_VAR_fingerprint` | Alias on `OCI_FINGERPRINT` |
-| `TF_VAR_private_key_path` | Alias on `OCI_PRIVATE_KEY_PATH` |
-| `TF_VAR_region` | Alias on `OCI_REGION` |
-| `TF_VAR_tenancy_ocid` | Alias on `OCI_TENANCY_OCID` |
-| `TF_VAR_user_ocid` | Alias on `OCI_USER_OCID` |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
diff --git a/docs/content/dns/zz_gen_otc.md b/docs/content/dns/zz_gen_otc.md
index 9da69c694..fe92f3001 100644
--- a/docs/content/dns/zz_gen_otc.md
+++ b/docs/content/dns/zz_gen_otc.md
@@ -23,15 +23,9 @@ Configuration for [Open Telekom Cloud](https://cloud.telekom.de/en).
- Since: v0.4.1
-Here is an example bash command using the Open Telekom Cloud provider:
-
-```bash
-OTC_DOMAIN_NAME=domain_name \
-OTC_USER_NAME=user_name \
-OTC_PASSWORD=password \
-OTC_PROJECT_NAME=project_name \
-lego --dns otc -d '*.example.com' -d example.com run
-```
+{{% notice note %}}
+_Please contribute by adding a CLI example._
+{{% /notice %}}
@@ -41,6 +35,7 @@ lego --dns otc -d '*.example.com' -d example.com run
| Environment Variable Name | Description |
|-----------------------|-------------|
| `OTC_DOMAIN_NAME` | Domain name |
+| `OTC_IDENTITY_ENDPOINT` | Identity endpoint URL |
| `OTC_PASSWORD` | Password |
| `OTC_PROJECT_NAME` | Project name |
| `OTC_USER_NAME` | User name |
@@ -54,9 +49,7 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `OTC_HTTP_TIMEOUT` | API request timeout in seconds (Default: 10) |
-| `OTC_IDENTITY_ENDPOINT` | Identity endpoint URL (default: https://iam.eu-de.otc.t-systems.com:443/v3/auth/tokens) |
| `OTC_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `OTC_PRIVATE_ZONE` | Set to true to use private zones only (default: use public zones only) |
| `OTC_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `OTC_SEQUENCE_INTERVAL` | Time between sequential requests in seconds (Default: 60) |
| `OTC_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 300) |
diff --git a/docs/content/dns/zz_gen_ovh.md b/docs/content/dns/zz_gen_ovh.md
index aaafded85..7abc01b92 100644
--- a/docs/content/dns/zz_gen_ovh.md
+++ b/docs/content/dns/zz_gen_ovh.md
@@ -32,20 +32,20 @@ OVH_APPLICATION_KEY=1234567898765432 \
OVH_APPLICATION_SECRET=b9841238feb177a84330febba8a832089 \
OVH_CONSUMER_KEY=256vfsd347245sdfg \
OVH_ENDPOINT=ovh-eu \
-lego --dns ovh -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ovh -d '*.example.com' -d example.com run
# Or Access Token:
OVH_ACCESS_TOKEN=xxx \
OVH_ENDPOINT=ovh-eu \
-lego --dns ovh -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ovh -d '*.example.com' -d example.com run
# Or OAuth2:
OVH_CLIENT_ID=yyy \
OVH_CLIENT_SECRET=xxx \
OVH_ENDPOINT=ovh-eu \
-lego --dns ovh -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ovh -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_pdns.md b/docs/content/dns/zz_gen_pdns.md
index 7c2a8c663..34a22cf84 100644
--- a/docs/content/dns/zz_gen_pdns.md
+++ b/docs/content/dns/zz_gen_pdns.md
@@ -28,7 +28,7 @@ Here is an example bash command using the PowerDNS provider:
```bash
PDNS_API_URL=http://pdns-server:80/ \
PDNS_API_KEY=xxxx \
-lego --dns pdns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns pdns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_plesk.md b/docs/content/dns/zz_gen_plesk.md
index 73ec9a55d..b18b2656a 100644
--- a/docs/content/dns/zz_gen_plesk.md
+++ b/docs/content/dns/zz_gen_plesk.md
@@ -29,7 +29,7 @@ Here is an example bash command using the plesk.com provider:
PLESK_SERVER_BASE_URL="https://plesk.myserver.com:8443" \
PLESK_USERNAME=xxxxxx \
PLESK_PASSWORD=yyyyyy \
-lego --dns plesk -d '*.example.com' -d example.com run
+lego --email you@example.com --dns plesk -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_porkbun.md b/docs/content/dns/zz_gen_porkbun.md
index f54e6f688..9fd230d0d 100644
--- a/docs/content/dns/zz_gen_porkbun.md
+++ b/docs/content/dns/zz_gen_porkbun.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Porkbun provider:
```bash
PORKBUN_SECRET_API_KEY=xxxxxx \
PORKBUN_API_KEY=yyyyyy \
-lego --dns porkbun -d '*.example.com' -d example.com run
+lego --email you@example.com --dns porkbun -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_rackspace.md b/docs/content/dns/zz_gen_rackspace.md
index b9a2ab710..6dcf6b2b2 100644
--- a/docs/content/dns/zz_gen_rackspace.md
+++ b/docs/content/dns/zz_gen_rackspace.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Rackspace provider:
```bash
RACKSPACE_USER=xxxx \
RACKSPACE_API_KEY=yyyy \
-lego --dns rackspace -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rackspace -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_rainyun.md b/docs/content/dns/zz_gen_rainyun.md
index 680eb845a..74ced9f54 100644
--- a/docs/content/dns/zz_gen_rainyun.md
+++ b/docs/content/dns/zz_gen_rainyun.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Rain Yun/雨云 provider:
```bash
RAINYUN_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns rainyun -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rainyun -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_rcodezero.md b/docs/content/dns/zz_gen_rcodezero.md
index a544df420..98eaea9ca 100644
--- a/docs/content/dns/zz_gen_rcodezero.md
+++ b/docs/content/dns/zz_gen_rcodezero.md
@@ -27,7 +27,7 @@ Here is an example bash command using the RcodeZero provider:
```bash
RCODEZERO_API_TOKEN= \
-lego --dns rcodezero -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rcodezero -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_regfish.md b/docs/content/dns/zz_gen_regfish.md
index 357ce0764..149338e5e 100644
--- a/docs/content/dns/zz_gen_regfish.md
+++ b/docs/content/dns/zz_gen_regfish.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Regfish provider:
```bash
REGFISH_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns regfish -d '*.example.com' -d example.com run
+lego --email you@example.com --dns regfish -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_regru.md b/docs/content/dns/zz_gen_regru.md
index eaf163a13..1d0e0053d 100644
--- a/docs/content/dns/zz_gen_regru.md
+++ b/docs/content/dns/zz_gen_regru.md
@@ -28,7 +28,7 @@ Here is an example bash command using the reg.ru provider:
```bash
REGRU_USERNAME=xxxxxx \
REGRU_PASSWORD=yyyyyy \
-lego --dns regru -d '*.example.com' -d example.com run
+lego --email you@example.com --dns regru -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_rfc2136.md b/docs/content/dns/zz_gen_rfc2136.md
index 1b1d43dd5..ffdbc4b54 100644
--- a/docs/content/dns/zz_gen_rfc2136.md
+++ b/docs/content/dns/zz_gen_rfc2136.md
@@ -30,7 +30,7 @@ RFC2136_NAMESERVER=127.0.0.1 \
RFC2136_TSIG_KEY=example.com \
RFC2136_TSIG_ALGORITHM=hmac-sha256. \
RFC2136_TSIG_SECRET=YWJjZGVmZGdoaWprbG1ub3BxcnN0dXZ3eHl6MTIzNDU= \
-lego --dns rfc2136 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rfc2136 -d '*.example.com' -d example.com run
## ---
@@ -38,7 +38,7 @@ keyname=example.com; keyfile=example.com.key; tsig-keygen $keyname > $keyfile
RFC2136_NAMESERVER=127.0.0.1 \
RFC2136_TSIG_FILE="$keyfile" \
-lego --dns rfc2136 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rfc2136 -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_rimuhosting.md b/docs/content/dns/zz_gen_rimuhosting.md
index acb829e93..2a703dec7 100644
--- a/docs/content/dns/zz_gen_rimuhosting.md
+++ b/docs/content/dns/zz_gen_rimuhosting.md
@@ -27,7 +27,7 @@ Here is an example bash command using the RimuHosting provider:
```bash
RIMUHOSTING_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns rimuhosting -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rimuhosting -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_route53.md b/docs/content/dns/zz_gen_route53.md
index 59e489d6a..a0967a57e 100644
--- a/docs/content/dns/zz_gen_route53.md
+++ b/docs/content/dns/zz_gen_route53.md
@@ -30,7 +30,7 @@ AWS_ACCESS_KEY_ID=your_key_id \
AWS_SECRET_ACCESS_KEY=your_secret_access_key \
AWS_REGION=aws-region \
AWS_HOSTED_ZONE_ID=your_hosted_zone_id \
-lego --dns route53 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns route53 -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_safedns.md b/docs/content/dns/zz_gen_safedns.md
index 4c20fca6a..2a9e179f5 100644
--- a/docs/content/dns/zz_gen_safedns.md
+++ b/docs/content/dns/zz_gen_safedns.md
@@ -1,12 +1,12 @@
---
-title: "ANS SafeDNS"
+title: "UKFast SafeDNS"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: safedns
dnsprovider:
since: "v4.6.0"
code: "safedns"
- url: "https://www.ans.co.uk/"
+ url: "https://www.ukfast.co.uk/dns-hosting.html"
---
@@ -14,7 +14,7 @@ dnsprovider:
-Configuration for [ANS SafeDNS](https://www.ans.co.uk/).
+Configuration for [UKFast SafeDNS](https://www.ukfast.co.uk/dns-hosting.html).
@@ -23,11 +23,11 @@ Configuration for [ANS SafeDNS](https://www.ans.co.uk/).
- Since: v4.6.0
-Here is an example bash command using the ANS SafeDNS provider:
+Here is an example bash command using the UKFast SafeDNS provider:
```bash
SAFEDNS_AUTH_TOKEN=xxxxxx \
-lego --dns safedns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns safedns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_sakuracloud.md b/docs/content/dns/zz_gen_sakuracloud.md
index b43f83ef4..e08e73e70 100644
--- a/docs/content/dns/zz_gen_sakuracloud.md
+++ b/docs/content/dns/zz_gen_sakuracloud.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Sakura Cloud provider:
```bash
SAKURACLOUD_ACCESS_TOKEN=xxxxx \
SAKURACLOUD_ACCESS_TOKEN_SECRET=yyyyy \
-lego --dns sakuracloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns sakuracloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_scaleway.md b/docs/content/dns/zz_gen_scaleway.md
index 4033a9bd6..7f9d6b7c7 100644
--- a/docs/content/dns/zz_gen_scaleway.md
+++ b/docs/content/dns/zz_gen_scaleway.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Scaleway provider:
```bash
SCW_SECRET_KEY=xxxxxxx-xxxxx-xxxx-xxx-xxxxxx \
-lego --dns scaleway -d '*.example.com' -d example.com run
+lego --email you@example.com --dns scaleway -d '*.example.com' -d example.com run
```
@@ -49,7 +49,6 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `SCW_ACCESS_KEY` | Access key |
-| `SCW_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `SCW_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
| `SCW_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
| `SCW_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
diff --git a/docs/content/dns/zz_gen_selectel.md b/docs/content/dns/zz_gen_selectel.md
index d994d6633..33dc859bb 100644
--- a/docs/content/dns/zz_gen_selectel.md
+++ b/docs/content/dns/zz_gen_selectel.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Selectel provider:
```bash
SELECTEL_API_TOKEN=xxxxx \
-lego --dns selectel -d '*.example.com' -d example.com run
+lego --email you@example.com --dns selectel -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_selectelv2.md b/docs/content/dns/zz_gen_selectelv2.md
index 0873d810c..24dd67d1e 100644
--- a/docs/content/dns/zz_gen_selectelv2.md
+++ b/docs/content/dns/zz_gen_selectelv2.md
@@ -30,7 +30,7 @@ SELECTELV2_USERNAME=trex \
SELECTELV2_PASSWORD=xxxxx \
SELECTELV2_ACCOUNT_ID=1234567 \
SELECTELV2_PROJECT_ID=111a11111aaa11aa1a11aaa11111aa1a \
-lego --dns selectelv2 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns selectelv2 -d '*.example.com' -d example.com run
```
@@ -53,14 +53,11 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
-| `SELECTELV2_AUTH_REGION` | Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1') |
-| `SELECTELV2_AUTH_URL` | Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/') |
| `SELECTELV2_BASE_URL` | API endpoint URL |
| `SELECTELV2_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `SELECTELV2_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 5) |
| `SELECTELV2_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
| `SELECTELV2_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
-| `SELECTELV2_USER_DOMAIN_NAME` | To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
diff --git a/docs/content/dns/zz_gen_selfhostde.md b/docs/content/dns/zz_gen_selfhostde.md
index 363f782e0..12df0c10d 100644
--- a/docs/content/dns/zz_gen_selfhostde.md
+++ b/docs/content/dns/zz_gen_selfhostde.md
@@ -29,7 +29,7 @@ Here is an example bash command using the SelfHost.(de|eu) provider:
SELFHOSTDE_USERNAME=xxx \
SELFHOSTDE_PASSWORD=yyy \
SELFHOSTDE_RECORDS_MAPPING=my.example.com:123 \
-lego --dns selfhostde -d '*.example.com' -d example.com run
+lego --email you@example.com --dns selfhostde -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_servercow.md b/docs/content/dns/zz_gen_servercow.md
index 7d00a6306..3214b0ca5 100644
--- a/docs/content/dns/zz_gen_servercow.md
+++ b/docs/content/dns/zz_gen_servercow.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Servercow provider:
```bash
SERVERCOW_USERNAME=xxxxxxxx \
SERVERCOW_PASSWORD=xxxxxxxx \
-lego --dns servercow -d '*.example.com' -d example.com run
+lego --email you@example.com --dns servercow -d '*.example.com' -d example.com run
```
@@ -62,7 +62,7 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
-- [API documentation](https://wiki.servercow.de/en/domains/dns_api/api-syntax/)
+- [API documentation](https://cp.servercow.de/client/plugin/support_manager/knowledgebase/view/34/dns-api-v1/7/)
diff --git a/docs/content/dns/zz_gen_shellrent.md b/docs/content/dns/zz_gen_shellrent.md
index cbbc172e2..6c1365b7e 100644
--- a/docs/content/dns/zz_gen_shellrent.md
+++ b/docs/content/dns/zz_gen_shellrent.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Shellrent provider:
```bash
SHELLRENT_USERNAME=xxxx \
SHELLRENT_TOKEN=yyyy \
-lego --dns shellrent -d '*.example.com' -d example.com run
+lego --email you@example.com --dns shellrent -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_simply.md b/docs/content/dns/zz_gen_simply.md
index edfa14380..32df66f05 100644
--- a/docs/content/dns/zz_gen_simply.md
+++ b/docs/content/dns/zz_gen_simply.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Simply.com provider:
```bash
SIMPLY_ACCOUNT_NAME=xxxxxx \
SIMPLY_API_KEY=yyyyyy \
-lego --dns simply -d '*.example.com' -d example.com run
+lego --email you@example.com --dns simply -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_sonic.md b/docs/content/dns/zz_gen_sonic.md
index 20729bc1a..f56a23151 100644
--- a/docs/content/dns/zz_gen_sonic.md
+++ b/docs/content/dns/zz_gen_sonic.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Sonic provider:
```bash
SONIC_USER_ID=12345 \
SONIC_API_KEY=4d6fbf2f9ab0fa11697470918d37625851fc0c51 \
-lego --dns sonic -d '*.example.com' -d example.com run
+lego --email you@example.com --dns sonic -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_spaceship.md b/docs/content/dns/zz_gen_spaceship.md
index 9f3b51e43..4594fe217 100644
--- a/docs/content/dns/zz_gen_spaceship.md
+++ b/docs/content/dns/zz_gen_spaceship.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Spaceship provider:
```bash
SPACESHIP_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
SPACESHIP_API_SECRET="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns spaceship -d '*.example.com' -d example.com run
+lego --email you@example.com --dns spaceship -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_stackpath.md b/docs/content/dns/zz_gen_stackpath.md
index b881176f4..ce0a02eac 100644
--- a/docs/content/dns/zz_gen_stackpath.md
+++ b/docs/content/dns/zz_gen_stackpath.md
@@ -29,7 +29,7 @@ Here is an example bash command using the Stackpath provider:
STACKPATH_CLIENT_ID=xxxxx \
STACKPATH_CLIENT_SECRET=yyyyy \
STACKPATH_STACK_ID=zzzzz \
-lego --dns stackpath -d '*.example.com' -d example.com run
+lego --email you@example.com --dns stackpath -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_syse.md b/docs/content/dns/zz_gen_syse.md
deleted file mode 100644
index a1a952bc5..000000000
--- a/docs/content/dns/zz_gen_syse.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: "Syse"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: syse
-dnsprovider:
- since: "v4.30.0"
- code: "syse"
- url: "https://www.syse.no/"
----
-
-
-
-
-
-
-Configuration for [Syse](https://www.syse.no/).
-
-
-
-
-- Code: `syse`
-- Since: v4.30.0
-
-
-Here is an example bash command using the Syse provider:
-
-```bash
-SYSE_CREDENTIALS=example.com:password \
-lego --dns syse -d '*.example.com' -d example.com run
-
-SYSE_CREDENTIALS=example.org:password1,example.com:password2 \
-lego --dns syse -d '*.example.org' -d example.org -d '*.example.com' -d example.com
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `SYSE_CREDENTIALS` | Comma-separated list of `zone:password` credential pairs |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `SYSE_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `SYSE_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
-| `SYSE_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 1200) |
-| `SYSE_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://www.syse.no/api/dns)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_technitium.md b/docs/content/dns/zz_gen_technitium.md
index ff7f2e6ed..80f7c6a1f 100644
--- a/docs/content/dns/zz_gen_technitium.md
+++ b/docs/content/dns/zz_gen_technitium.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Technitium provider:
```bash
TECHNITIUM_SERVER_BASE_URL="https://localhost:5380" \
TECHNITIUM_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns technitium -d '*.example.com' -d example.com run
+lego --email you@example.com --dns technitium -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_tencentcloud.md b/docs/content/dns/zz_gen_tencentcloud.md
index 178ffcf43..bc08c43ce 100644
--- a/docs/content/dns/zz_gen_tencentcloud.md
+++ b/docs/content/dns/zz_gen_tencentcloud.md
@@ -6,7 +6,7 @@ slug: tencentcloud
dnsprovider:
since: "v4.6.0"
code: "tencentcloud"
- url: "https://cloud.tencent.com/product/dns"
+ url: "https://cloud.tencent.com/product/cns"
---
@@ -14,7 +14,7 @@ dnsprovider:
-Configuration for [Tencent Cloud DNS](https://cloud.tencent.com/product/dns).
+Configuration for [Tencent Cloud DNS](https://cloud.tencent.com/product/cns).
@@ -28,7 +28,7 @@ Here is an example bash command using the Tencent Cloud DNS provider:
```bash
TENCENTCLOUD_SECRET_ID=abcdefghijklmnopqrstuvwx \
TENCENTCLOUD_SECRET_KEY=your-secret-key \
-lego --dns tencentcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns tencentcloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_timewebcloud.md b/docs/content/dns/zz_gen_timewebcloud.md
index 83d5b831b..af218ddce 100644
--- a/docs/content/dns/zz_gen_timewebcloud.md
+++ b/docs/content/dns/zz_gen_timewebcloud.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Timeweb Cloud provider:
```bash
TIMEWEBCLOUD_AUTH_TOKEN=xxxxxx \
-lego --dns timewebcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns timewebcloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_todaynic.md b/docs/content/dns/zz_gen_todaynic.md
deleted file mode 100644
index 7b06c012d..000000000
--- a/docs/content/dns/zz_gen_todaynic.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "TodayNIC/时代互联"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: todaynic
-dnsprovider:
- since: "v4.32.0"
- code: "todaynic"
- url: "https://www.todaynic.com/"
----
-
-
-
-
-
-
-Configuration for [TodayNIC/时代互联](https://www.todaynic.com/).
-
-
-
-
-- Code: `todaynic`
-- Since: v4.32.0
-
-
-Here is an example bash command using the TodayNIC/时代互联 provider:
-
-```bash
-TODAYNIC_AUTH_USER_ID="xxx" \
-TODAYNIC_API_KEY="yyy" \
-lego --dns todaynic -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `TODAYNIC_API_KEY` | API key |
-| `TODAYNIC_AUTH_USER_ID` | account ID |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `TODAYNIC_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `TODAYNIC_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `TODAYNIC_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `TODAYNIC_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 600) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://www.todaynic.com/partner/mode_Http_Api_detail.php)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_transip.md b/docs/content/dns/zz_gen_transip.md
index a66a25879..68b0f7acf 100644
--- a/docs/content/dns/zz_gen_transip.md
+++ b/docs/content/dns/zz_gen_transip.md
@@ -28,7 +28,7 @@ Here is an example bash command using the TransIP provider:
```bash
TRANSIP_ACCOUNT_NAME = "Account name" \
TRANSIP_PRIVATE_KEY_PATH = "transip.key" \
-lego --dns transip -d '*.example.com' -d example.com run
+lego --email you@example.com --dns transip -d '*.example.com' -d example.com run
```
@@ -49,7 +49,6 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
-| `TRANSIP_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `TRANSIP_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
| `TRANSIP_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 600) |
| `TRANSIP_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 10) |
diff --git a/docs/content/dns/zz_gen_ultradns.md b/docs/content/dns/zz_gen_ultradns.md
index d6d89c77b..8e0fa9b20 100644
--- a/docs/content/dns/zz_gen_ultradns.md
+++ b/docs/content/dns/zz_gen_ultradns.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Ultradns provider:
```bash
ULTRADNS_USERNAME=username \
ULTRADNS_PASSWORD=password \
-lego --dns ultradns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ultradns -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_uniteddomains.md b/docs/content/dns/zz_gen_uniteddomains.md
deleted file mode 100644
index e837644d5..000000000
--- a/docs/content/dns/zz_gen_uniteddomains.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "United-Domains"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: uniteddomains
-dnsprovider:
- since: "v4.29.0"
- code: "uniteddomains"
- url: "https://www.united-domains.de/"
----
-
-
-
-
-
-
-Configuration for [United-Domains](https://www.united-domains.de/).
-
-
-
-
-- Code: `uniteddomains`
-- Since: v4.29.0
-
-
-Here is an example bash command using the United-Domains provider:
-
-```bash
-UNITEDDOMAINS_API_KEY=xxxxxxxx \
-lego --dns uniteddomains -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `UNITEDDOMAINS_API_KEY` | API key `.` https://www.united-domains.de/help/faq-article/getting-started-with-the-united-domains-dns-api/ |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `UNITEDDOMAINS_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `UNITEDDOMAINS_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `UNITEDDOMAINS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 900) |
-| `UNITEDDOMAINS_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 300) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://www.united-domains.de/dns-apidoc/)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_variomedia.md b/docs/content/dns/zz_gen_variomedia.md
index f9771c867..282ec9da3 100644
--- a/docs/content/dns/zz_gen_variomedia.md
+++ b/docs/content/dns/zz_gen_variomedia.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Variomedia provider:
```bash
VARIOMEDIA_API_TOKEN=xxxx \
-lego --dns variomedia -d '*.example.com' -d example.com run
+lego --email you@example.com --dns variomedia -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_vercel.md b/docs/content/dns/zz_gen_vercel.md
index 71f2eeed5..d9e24eee3 100644
--- a/docs/content/dns/zz_gen_vercel.md
+++ b/docs/content/dns/zz_gen_vercel.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Vercel provider:
```bash
VERCEL_API_TOKEN=xxxxxx \
-lego --dns vercel -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vercel -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_versio.md b/docs/content/dns/zz_gen_versio.md
index 5d2cc0118..0e2edfa1e 100644
--- a/docs/content/dns/zz_gen_versio.md
+++ b/docs/content/dns/zz_gen_versio.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Versio.[nl|eu|uk] provider:
```bash
VERSIO_USERNAME= \
VERSIO_PASSWORD= \
-lego --dns versio -d '*.example.com' -d example.com run
+lego --email you@example.com --dns versio -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_vinyldns.md b/docs/content/dns/zz_gen_vinyldns.md
index 3280d6f0a..9a9c4bef0 100644
--- a/docs/content/dns/zz_gen_vinyldns.md
+++ b/docs/content/dns/zz_gen_vinyldns.md
@@ -29,7 +29,7 @@ Here is an example bash command using the VinylDNS provider:
VINYLDNS_ACCESS_KEY=xxxxxx \
VINYLDNS_SECRET_KEY=yyyyy \
VINYLDNS_HOST=https://api.vinyldns.example.org:9443 \
-lego --dns vinyldns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vinyldns -d '*.example.com' -d example.com run
```
@@ -51,7 +51,6 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
-| `VINYLDNS_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `VINYLDNS_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 4) |
| `VINYLDNS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
| `VINYLDNS_QUOTE_VALUE` | Adds quotes around the TXT record value (Default: false) |
diff --git a/docs/content/dns/zz_gen_virtualname.md b/docs/content/dns/zz_gen_virtualname.md
deleted file mode 100644
index a00e5105f..000000000
--- a/docs/content/dns/zz_gen_virtualname.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Virtualname"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: virtualname
-dnsprovider:
- since: "v4.30.0"
- code: "virtualname"
- url: "https://www.virtualname.es/"
----
-
-
-
-
-
-
-Configuration for [Virtualname](https://www.virtualname.es/).
-
-
-
-
-- Code: `virtualname`
-- Since: v4.30.0
-
-
-Here is an example bash command using the Virtualname provider:
-
-```bash
-VIRTUALNAME_TOKEN=xxxxxx \
-lego --dns virtualname -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `VIRTUALNAME_TOKEN` | API token |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `VIRTUALNAME_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `VIRTUALNAME_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
-| `VIRTUALNAME_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 300) |
-| `VIRTUALNAME_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://developers.virtualname.net/#dns)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_vkcloud.md b/docs/content/dns/zz_gen_vkcloud.md
index 76fd557a5..eede62cf5 100644
--- a/docs/content/dns/zz_gen_vkcloud.md
+++ b/docs/content/dns/zz_gen_vkcloud.md
@@ -29,7 +29,7 @@ Here is an example bash command using the VK Cloud provider:
VK_CLOUD_PROJECT_ID="" \
VK_CLOUD_USERNAME="" \
VK_CLOUD_PASSWORD="" \
-lego --dns vkcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vkcloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_volcengine.md b/docs/content/dns/zz_gen_volcengine.md
index 587ce1e74..9d3c92d0d 100644
--- a/docs/content/dns/zz_gen_volcengine.md
+++ b/docs/content/dns/zz_gen_volcengine.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Volcano Engine/火山引擎 provider:
```bash
VOLC_ACCESSKEY=xxx \
VOLC_SECRETKEY=yyy \
-lego --dns volcengine -d '*.example.com' -d example.com run
+lego --email you@example.com --dns volcengine -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_vscale.md b/docs/content/dns/zz_gen_vscale.md
index c33e2f7b5..660542d61 100644
--- a/docs/content/dns/zz_gen_vscale.md
+++ b/docs/content/dns/zz_gen_vscale.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Vscale provider:
```bash
VSCALE_API_TOKEN=xxxxx \
-lego --dns vscale -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vscale -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_vultr.md b/docs/content/dns/zz_gen_vultr.md
index 4160fbcf3..a3807c1a1 100644
--- a/docs/content/dns/zz_gen_vultr.md
+++ b/docs/content/dns/zz_gen_vultr.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Vultr provider:
```bash
VULTR_API_KEY=xxxxx \
-lego --dns vultr -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vultr -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_webnames.md b/docs/content/dns/zz_gen_webnames.md
index cad02c287..d721466b3 100644
--- a/docs/content/dns/zz_gen_webnames.md
+++ b/docs/content/dns/zz_gen_webnames.md
@@ -1,5 +1,5 @@
---
-title: "webnames.ru"
+title: "Webnames"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: webnames
@@ -14,7 +14,7 @@ dnsprovider:
-Configuration for [webnames.ru](https://www.webnames.ru/).
+Configuration for [Webnames](https://www.webnames.ru/).
@@ -23,11 +23,11 @@ Configuration for [webnames.ru](https://www.webnames.ru/).
- Since: v4.15.0
-Here is an example bash command using the webnames.ru provider:
+Here is an example bash command using the Webnames provider:
```bash
-WEBNAMESRU_API_KEY=xxxxxx \
-lego --dns webnamesru -d '*.example.com' -d example.com run
+WEBNAMES_API_KEY=xxxxxx \
+lego --email you@example.com --dns webnames -d '*.example.com' -d example.com run
```
@@ -37,7 +37,7 @@ lego --dns webnamesru -d '*.example.com' -d example.com run
| Environment Variable Name | Description |
|-----------------------|-------------|
-| `WEBNAMESRU_API_KEY` | Domain API key |
+| `WEBNAMES_API_KEY` | Domain API key |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
@@ -47,9 +47,9 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
-| `WEBNAMESRU_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `WEBNAMESRU_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `WEBNAMESRU_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
+| `WEBNAMES_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
+| `WEBNAMES_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
+| `WEBNAMES_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
diff --git a/docs/content/dns/zz_gen_webnamesca.md b/docs/content/dns/zz_gen_webnamesca.md
deleted file mode 100644
index 4a7d3794f..000000000
--- a/docs/content/dns/zz_gen_webnamesca.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "webnames.ca"
-date: 2019-03-03T16:39:46+01:00
-draft: false
-slug: webnamesca
-dnsprovider:
- since: "v4.28.0"
- code: "webnamesca"
- url: "https://www.webnames.ca/"
----
-
-
-
-
-
-
-Configuration for [webnames.ca](https://www.webnames.ca/).
-
-
-
-
-- Code: `webnamesca`
-- Since: v4.28.0
-
-
-Here is an example bash command using the webnames.ca provider:
-
-```bash
-WEBNAMESCA_API_USER="xxx" \
-WEBNAMESCA_API_KEY="yyy" \
-lego --dns webnamesca -d '*.example.com' -d example.com run
-```
-
-
-
-
-## Credentials
-
-| Environment Variable Name | Description |
-|-----------------------|-------------|
-| `WEBNAMESCA_API_KEY` | API key |
-| `WEBNAMESCA_API_USER` | API username |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-## Additional Configuration
-
-| Environment Variable Name | Description |
-|--------------------------------|-------------|
-| `WEBNAMESCA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
-| `WEBNAMESCA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
-| `WEBNAMESCA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
-| `WEBNAMESCA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
-
-The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
-More information [here]({{% ref "dns#configuration-and-credentials" %}}).
-
-
-
-
-## More information
-
-- [API documentation](https://www.webnames.ca/_/swagger/index.html)
-
-
-
-
diff --git a/docs/content/dns/zz_gen_websupport.md b/docs/content/dns/zz_gen_websupport.md
index 67ae394d7..5fe44a860 100644
--- a/docs/content/dns/zz_gen_websupport.md
+++ b/docs/content/dns/zz_gen_websupport.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Websupport provider:
```bash
WEBSUPPORT_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
WEBSUPPORT_SECRET="yyyyyyyyyyyyyyyyyyyyy" \
-lego --dns websupport -d '*.example.com' -d example.com run
+lego --email you@example.com --dns websupport -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_wedos.md b/docs/content/dns/zz_gen_wedos.md
index 16139f4d4..8fe6ba00d 100644
--- a/docs/content/dns/zz_gen_wedos.md
+++ b/docs/content/dns/zz_gen_wedos.md
@@ -28,7 +28,7 @@ Here is an example bash command using the WEDOS provider:
```bash
WEDOS_USERNAME=xxxxxxxx \
WEDOS_WAPI_PASSWORD=xxxxxxxx \
-lego --dns wedos -d '*.example.com' -d example.com run
+lego --email you@example.com --dns wedos -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_westcn.md b/docs/content/dns/zz_gen_westcn.md
index a5523b955..434e5b601 100644
--- a/docs/content/dns/zz_gen_westcn.md
+++ b/docs/content/dns/zz_gen_westcn.md
@@ -28,7 +28,7 @@ Here is an example bash command using the West.cn/西部数码 provider:
```bash
WESTCN_USERNAME="xxx" \
WESTCN_PASSWORD="yyy" \
-lego --dns westcn -d '*.example.com' -d example.com run
+lego --email you@example.com --dns westcn -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_yandex.md b/docs/content/dns/zz_gen_yandex.md
index 4a1cf1f99..6100c02fe 100644
--- a/docs/content/dns/zz_gen_yandex.md
+++ b/docs/content/dns/zz_gen_yandex.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Yandex PDD provider:
```bash
YANDEX_PDD_TOKEN= \
-lego --dns yandex -d '*.example.com' -d example.com run
+lego --email you@example.com --dns yandex -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_yandex360.md b/docs/content/dns/zz_gen_yandex360.md
index d831fdfc2..66b90e049 100644
--- a/docs/content/dns/zz_gen_yandex360.md
+++ b/docs/content/dns/zz_gen_yandex360.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Yandex 360 provider:
```bash
YANDEX360_OAUTH_TOKEN= \
YANDEX360_ORG_ID= \
-lego --dns yandex360 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns yandex360 -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_yandexcloud.md b/docs/content/dns/zz_gen_yandexcloud.md
index 0564e93d2..f5aeba09d 100644
--- a/docs/content/dns/zz_gen_yandexcloud.md
+++ b/docs/content/dns/zz_gen_yandexcloud.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Yandex Cloud provider:
```bash
YANDEX_CLOUD_IAM_TOKEN= \
YANDEX_CLOUD_FOLDER_ID= \
-lego --dns yandexcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns yandexcloud -d '*.example.com' -d example.com run
# ---
@@ -41,7 +41,7 @@ YANDEX_CLOUD_IAM_TOKEN=$(echo '{ \
"private_key": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----" \
}' | base64) \
YANDEX_CLOUD_FOLDER_ID= \
-lego --dns yandexcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns yandexcloud -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_zoneedit.md b/docs/content/dns/zz_gen_zoneedit.md
index c7f88b3fe..e259a2a04 100644
--- a/docs/content/dns/zz_gen_zoneedit.md
+++ b/docs/content/dns/zz_gen_zoneedit.md
@@ -28,7 +28,7 @@ Here is an example bash command using the ZoneEdit provider:
```bash
ZONEEDIT_USER="xxxxxxxxxxxxxxxxxxxxx" \
ZONEEDIT_AUTH_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns zoneedit -d '*.example.com' -d example.com run
+lego --email you@example.com --dns zoneedit -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_zoneee.md b/docs/content/dns/zz_gen_zoneee.md
index 65678a3dc..cfc6be692 100644
--- a/docs/content/dns/zz_gen_zoneee.md
+++ b/docs/content/dns/zz_gen_zoneee.md
@@ -28,7 +28,7 @@ Here is an example bash command using the Zone.ee provider:
```bash
ZONEEE_API_USER=xxxxx \
ZONEEE_API_KEY=yyyyy \
-lego --dns zoneee -d '*.example.com' -d example.com run
+lego --email you@example.com --dns zoneee -d '*.example.com' -d example.com run
```
diff --git a/docs/content/dns/zz_gen_zonomi.md b/docs/content/dns/zz_gen_zonomi.md
index fd8757f82..1e90a7285 100644
--- a/docs/content/dns/zz_gen_zonomi.md
+++ b/docs/content/dns/zz_gen_zonomi.md
@@ -27,7 +27,7 @@ Here is an example bash command using the Zonomi provider:
```bash
ZONOMI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns zonomi -d '*.example.com' -d example.com run
+lego --email you@example.com --dns zonomi -d '*.example.com' -d example.com run
```
diff --git a/docs/content/usage/cli/Options.md b/docs/content/usage/cli/Options.md
index 7b5df027a..25ba7e593 100644
--- a/docs/content/usage/cli/Options.md
+++ b/docs/content/usage/cli/Options.md
@@ -143,25 +143,6 @@ Example:
LEGO_DEBUG_CLIENT_VERBOSE_ERROR=true
```
-### LEGO_DEBUG_DNS_API_HTTP_CLIENT
-
-> **⚠️ WARNING: This will expose credentials in the log output! ⚠️**
->
-> Do not run this in production environments, or if you can't be sure that logs aren't accessed by third parties or tools (like log collectors).
->
-> You have been warned. Here be dragons.
-
-The environment variable `LEGO_DEBUG_DNS_API_HTTP_CLIENT` allows debugging the DNS API interaction.
-It will dump the full request and response to the log output.
-
-Some DNS providers don't support this option.
-
-Example:
-
-```bash
-LEGO_DEBUG_DNS_API_HTTP_CLIENT=true
-```
-
### LEGO_DEBUG_ACME_HTTP_CLIENT
The environment variable `LEGO_DEBUG_ACME_HTTP_CLIENT` allows debug the calls to the ACME server.
diff --git a/docs/data/zz_cli_help.toml b/docs/data/zz_cli_help.toml
index 139143b17..95ff0770a 100644
--- a/docs/data/zz_cli_help.toml
+++ b/docs/data/zz_cli_help.toml
@@ -23,7 +23,7 @@ GLOBAL OPTIONS:
--server value, -s value CA hostname (and optionally :port). The server certificate must be trusted in order to avoid further modifications to the client. (default: "https://acme-v02.api.letsencrypt.org/directory") [$LEGO_SERVER]
--accept-tos, -a By setting this flag to true you indicate that you accept the current Let's Encrypt terms of service. (default: false)
--email value, -m value Email used for registration and recovery contact. [$LEGO_EMAIL]
- --disable-cn Disable the use of the common name in the CSR. (default: false)
+ --disable-cn Disable the use of the common name in the CSR. (default: false) [$disable-cn]
--csr value, -c value Certificate signing request filename, if an external CSR is to be used.
--eab Use External Account Binding for account registration. Requires --kid and --hmac. (default: false) [$LEGO_EAB]
--kid value Key identifier from External CA. Used for External Account Binding. [$LEGO_EAB_KID]
@@ -76,7 +76,7 @@ OPTIONS:
--not-after value Set the notAfter field in the certificate (RFC3339 format)
--private-key value Path to private key (in PEM encoding) for the certificate. By default, the private key is generated.
--preferred-chain value If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used.
- --profile value If the CA offers multiple certificate profiles (draft-ietf-acme-profiles), choose this one.
+ --profile value If the CA offers multiple certificate profiles (draft-aaron-acme-profiles), choose this one.
--always-deactivate-authorizations value Force the authorizations to be relinquished even if the certificate request was successful.
--run-hook value Define a hook. The hook is executed when the certificates are effectively created.
--run-hook-timeout value Define the timeout for the hook execution. (default: 2m0s)
@@ -103,7 +103,7 @@ OPTIONS:
--not-before value Set the notBefore field in the certificate (RFC3339 format)
--not-after value Set the notAfter field in the certificate (RFC3339 format)
--preferred-chain value If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. If no match, the default offered chain will be used.
- --profile value If the CA offers multiple certificate profiles (draft-ietf-acme-profiles), choose this one.
+ --profile value If the CA offers multiple certificate profiles (draft-aaron-acme-profiles), choose this one.
--always-deactivate-authorizations value Force the authorizations to be relinquished even if the certificate request was successful.
--renew-hook value Define a hook. The hook is executed only when the certificates are effectively renewed.
--renew-hook-timeout value Define the timeout for the hook execution. (default: 2m0s)
@@ -152,7 +152,7 @@ To display the documentation for a specific DNS provider, run:
$ lego dnshelp -c code
Supported DNS providers:
- acme-dns, active24, alidns, aliesa, allinkl, alwaysdata, anexia, artfiles, arvancloud, auroradns, autodns, axelname, azion, azure, azuredns, baiducloud, beget, binarylane, bindman, bluecat, bluecatv2, bookmyname, brandit, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudru, cloudxns, com35, conoha, conohav3, constellix, corenetworks, cpanel, czechia, ddnss, derak, desec, designate, digitalocean, directadmin, dnsexit, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dyndnsfree, dynu, easydns, edgecenter, edgedns, edgeone, efficientip, epik, eurodns, excedo, exec, exoscale, f5xc, freemyip, gandi, gandiv5, gcloud, gcore, gigahostno, glesys, godaddy, googledomains, gravity, hetzner, hostingde, hostinger, hostingnl, hosttech, httpnet, httpreq, huaweicloud, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, ionoscloud, ipv64, ispconfig, ispconfigddns, iwantmyname, jdcloud, joker, keyhelp, leaseweb, liara, lightsail, limacity, linode, liquidweb, loopia, luadns, mailinabox, manageengine, manual, metaname, metaregistrar, mijnhost, mittwald, myaddr, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, namesurfer, nearlyfreespeech, neodigit, netcup, netlify, nicmanager, nicru, nifcloud, njalla, nodion, ns1, octenium, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, rainyun, rcodezero, regfish, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, selectelv2, selfhostde, servercow, shellrent, simply, sonic, spaceship, stackpath, syse, technitium, tencentcloud, timewebcloud, todaynic, transip, ultradns, uniteddomains, variomedia, vegadns, vercel, versio, vinyldns, virtualname, vkcloud, volcengine, vscale, vultr, webnames, webnamesca, websupport, wedos, westcn, yandex, yandex360, yandexcloud, zoneedit, zoneee, zonomi
+ acme-dns, active24, alidns, allinkl, arvancloud, auroradns, autodns, axelname, azion, azure, azuredns, baiducloud, bindman, bluecat, bookmyname, brandit, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudru, cloudxns, conoha, conohav3, constellix, corenetworks, cpanel, derak, desec, designate, digitalocean, directadmin, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dyndnsfree, dynu, easydns, edgedns, efficientip, epik, exec, exoscale, f5xc, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, hostingde, hosttech, httpnet, httpreq, huaweicloud, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, ipv64, iwantmyname, joker, liara, lightsail, limacity, linode, liquidweb, loopia, luadns, mailinabox, manageengine, manual, metaname, metaregistrar, mijnhost, mittwald, myaddr, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nicru, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, rainyun, rcodezero, regfish, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, selectelv2, selfhostde, servercow, shellrent, simply, sonic, spaceship, stackpath, technitium, tencentcloud, timewebcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, volcengine, vscale, vultr, webnames, websupport, wedos, westcn, yandex, yandex360, yandexcloud, zoneedit, zoneee, zonomi
More information: https://go-acme.github.io/lego/dns
"""
diff --git a/docs/go.mod b/docs/go.mod
index 2240eb1e6..5cb2add45 100644
--- a/docs/go.mod
+++ b/docs/go.mod
@@ -2,4 +2,4 @@ module github.com/go-acme/lego/docs
go 1.20
-require github.com/McShelby/hugo-theme-relearn v0.0.0-20250707094454-9803d5122ebb
+require github.com/McShelby/hugo-theme-relearn v0.0.0-20240802145348-259f21f89851
diff --git a/docs/go.sum b/docs/go.sum
index b62d5c809..1ed963e87 100644
--- a/docs/go.sum
+++ b/docs/go.sum
@@ -1,2 +1,2 @@
-github.com/McShelby/hugo-theme-relearn v0.0.0-20250707094454-9803d5122ebb h1:iTGWOs8uKUaYmd7+wHRyPGXxt+SS5Bhvx2RRboYRXlI=
-github.com/McShelby/hugo-theme-relearn v0.0.0-20250707094454-9803d5122ebb/go.mod h1:mKQQdxZNIlLvAj8X3tMq+RzntIJSr9z7XdzuMomt0IM=
+github.com/McShelby/hugo-theme-relearn v0.0.0-20240802145348-259f21f89851 h1:JpmKIb1bRzuAcgnphwSb35Xz9rk/Alq19uRWVGSwScA=
+github.com/McShelby/hugo-theme-relearn v0.0.0-20240802145348-259f21f89851/go.mod h1:mKQQdxZNIlLvAj8X3tMq+RzntIJSr9z7XdzuMomt0IM=
diff --git a/docs/hugo.toml b/docs/hugo.toml
index fe076a306..a974cea73 100644
--- a/docs/hugo.toml
+++ b/docs/hugo.toml
@@ -2,20 +2,47 @@ baseURL = "https://go-acme.github.io/lego/"
languageCode = "en-us"
title = "Lego"
+# Code highlighting settings
+pygmentsCodefences = true
+pygmentsCodeFencesGuesSsyntax = false
+pygmentsOptions = ""
+pygmentsStyle = "monokai"
+# The monokai stylesheet is included in the base template.
+pygmentsUseClasses = true
+
[permalinks]
dns = "/dns/:slug/"
[params]
+ # Prefix URL to edit current page. Will display an "Edit this page" button on top right hand corner of every page.
+ # Useful to give opportunity to people to create merge request for your doc.
+ # See the config.toml file from this documentation site to have an example.
+# editURL = ""
# Description of the site, will be used in meta information
# description = ""
# Shows a checkmark for visited pages on the menu
showVisitedLinks = true
+ # Disable search function. It will hide search bar
+# disableSearch = false
+ # Javascript and CSS cache are automatically busted when new version of site is generated.
+ # Set this to true to disable this behavior (some proxies don't handle well this optimization)
+# disableAssetsBusting = false
+ # Set this to true to disable copy-to-clipboard button for inline code.
+# disableInlineCopyToClipBoard = true
+ # A title for shortcuts in menu is set by default. Set this to true to disable it.
+# disableShortcutsTitle = false
+ # When using mulitlingual website, disable the switch language button.
+# disableLanguageSwitchingButton = false
+ # Hide breadcrumbs in the header and only show the current page title
+# disableBreadcrumb = true
+ # Hide Next and Previous page buttons normally displayed full height beside content
+# disableNextPrev = true
+ # Order sections in menu by "weight" or "title". Default to "weight"
+# ordersectionsby = "weight"
# Change default color scheme with a variant one. Can be "red", "blue", "green".
themeVariant = "blue"
custom_css = ["css/theme-custom.css"]
disableLandingPageButton = true
- hideAuthorEmail = true
- hideAuthorName = true
# Author of the site, will be used in meta information
[params.author]
@@ -44,7 +71,7 @@ title = "Lego"
weight = 12
[outputs]
- home = ['html', 'rss', 'print']
+ home = [ "html", "rss", "search", "searchpage"]
[module]
[[module.imports]]
diff --git a/docs/static/.nojekyll b/docs/static/.nojekyll
deleted file mode 100644
index e69de29bb..000000000
diff --git a/e2e/challenges_test.go b/e2e/challenges_test.go
index be1d23131..59930923b 100644
--- a/e2e/challenges_test.go
+++ b/e2e/challenges_test.go
@@ -5,10 +5,8 @@ import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
- "encoding/pem"
"fmt"
"os"
- "path/filepath"
"testing"
"time"
@@ -23,18 +21,6 @@ import (
"github.com/stretchr/testify/require"
)
-const (
- testDomain1 = "acme.localhost"
- testDomain2 = "lego.localhost"
- testDomain3 = "acme.lego.localhost"
- testDomain4 = "légô.localhost"
-)
-
-const (
- testEmail1 = "lego@example.com"
- testEmail2 = "acme@example.com"
-)
-
var load = loader.EnvLoader{
PebbleOptions: &loader.CmdOption{
HealthCheckURL: "https://localhost:14000/dir",
@@ -65,10 +51,10 @@ func TestChallengeHTTP_Run(t *testing.T) {
loader.CleanLegoFiles()
err := load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
- "-d", testDomain1,
+ "-d", "acme.wtf",
"--http",
"--http.port", ":5002",
"run")
@@ -81,10 +67,10 @@ func TestChallengeTLS_Run_Domains(t *testing.T) {
loader.CleanLegoFiles()
err := load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
- "-d", testDomain1,
+ "-d", "acme.wtf",
"--tls",
"--tls.port", ":5001",
"run")
@@ -97,7 +83,7 @@ func TestChallengeTLS_Run_IP(t *testing.T) {
loader.CleanLegoFiles()
err := load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
"-d", "127.0.0.1",
@@ -112,13 +98,11 @@ func TestChallengeTLS_Run_IP(t *testing.T) {
func TestChallengeTLS_Run_CSR(t *testing.T) {
loader.CleanLegoFiles()
- csrPath := createTestCSRFile(t, true)
-
err := load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
- "-csr", csrPath,
+ "-csr", "./fixtures/csr.raw",
"--tls",
"--tls.port", ":5001",
"run")
@@ -130,13 +114,11 @@ func TestChallengeTLS_Run_CSR(t *testing.T) {
func TestChallengeTLS_Run_CSR_PEM(t *testing.T) {
loader.CleanLegoFiles()
- csrPath := createTestCSRFile(t, false)
-
err := load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
- "-csr", csrPath,
+ "-csr", "./fixtures/csr.cert",
"--tls",
"--tls.port", ":5001",
"run")
@@ -149,11 +131,11 @@ func TestChallengeTLS_Run_Revoke(t *testing.T) {
loader.CleanLegoFiles()
err := load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
- "-d", testDomain2,
- "-d", testDomain3,
+ "-d", "lego.wtf",
+ "-d", "acme.lego.wtf",
"--tls",
"--tls.port", ":5001",
"run")
@@ -162,10 +144,10 @@ func TestChallengeTLS_Run_Revoke(t *testing.T) {
}
err = load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
- "-d", testDomain2,
+ "-d", "lego.wtf",
"--tls",
"--tls.port", ":5001",
"revoke")
@@ -178,10 +160,10 @@ func TestChallengeTLS_Run_Revoke_Non_ASCII(t *testing.T) {
loader.CleanLegoFiles()
err := load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
- "-d", testDomain4,
+ "-d", "légô.wtf",
"--tls",
"--tls.port", ":5001",
"run")
@@ -190,10 +172,10 @@ func TestChallengeTLS_Run_Revoke_Non_ASCII(t *testing.T) {
}
err = load.RunLego(
- "-m", testEmail1,
+ "-m", "hubert@hubert.com",
"--accept-tos",
"-s", "https://localhost:14000/dir",
- "-d", testDomain4,
+ "-d", "légô.wtf",
"--tls",
"--tls.port", ":5001",
"revoke")
@@ -205,7 +187,6 @@ func TestChallengeTLS_Run_Revoke_Non_ASCII(t *testing.T) {
func TestChallengeHTTP_Client_Obtain(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -223,18 +204,17 @@ func TestChallengeHTTP_Client_Obtain(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
request := certificate.ObtainRequest{
- Domains: []string{testDomain1},
+ Domains: []string{"acme.wtf"},
Bundle: true,
}
resource, err := client.Certificate.Obtain(request)
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, testDomain1, resource.Domain)
+ assert.Equal(t, "acme.wtf", resource.Domain)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
@@ -245,7 +225,6 @@ func TestChallengeHTTP_Client_Obtain(t *testing.T) {
func TestChallengeHTTP_Client_Obtain_profile(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -263,11 +242,10 @@ func TestChallengeHTTP_Client_Obtain_profile(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
request := certificate.ObtainRequest{
- Domains: []string{testDomain1},
+ Domains: []string{"acme.wtf"},
Bundle: true,
Profile: "shortlived",
}
@@ -275,7 +253,7 @@ func TestChallengeHTTP_Client_Obtain_profile(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, testDomain1, resource.Domain)
+ assert.Equal(t, "acme.wtf", resource.Domain)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
@@ -286,7 +264,6 @@ func TestChallengeHTTP_Client_Obtain_profile(t *testing.T) {
func TestChallengeHTTP_Client_Obtain_emails_csr(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -304,19 +281,18 @@ func TestChallengeHTTP_Client_Obtain_emails_csr(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
request := certificate.ObtainRequest{
- Domains: []string{testDomain1},
+ Domains: []string{"acme.wtf"},
Bundle: true,
- EmailAddresses: []string{testEmail1},
+ EmailAddresses: []string{"foo@example.com"},
}
resource, err := client.Certificate.Obtain(request)
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, testDomain1, resource.Domain)
+ assert.Equal(t, "acme.wtf", resource.Domain)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
@@ -327,7 +303,6 @@ func TestChallengeHTTP_Client_Obtain_emails_csr(t *testing.T) {
func TestChallengeHTTP_Client_Obtain_notBefore_notAfter(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -345,13 +320,12 @@ func TestChallengeHTTP_Client_Obtain_notBefore_notAfter(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
now := time.Now().UTC()
request := certificate.ObtainRequest{
- Domains: []string{testDomain1},
+ Domains: []string{"acme.wtf"},
NotBefore: now.Add(1 * time.Hour),
NotAfter: now.Add(2 * time.Hour),
Bundle: true,
@@ -360,7 +334,7 @@ func TestChallengeHTTP_Client_Obtain_notBefore_notAfter(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, testDomain1, resource.Domain)
+ assert.Equal(t, "acme.wtf", resource.Domain)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
@@ -376,7 +350,6 @@ func TestChallengeHTTP_Client_Obtain_notBefore_notAfter(t *testing.T) {
func TestChallengeHTTP_Client_Registration_QueryRegistration(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -394,7 +367,6 @@ func TestChallengeHTTP_Client_Registration_QueryRegistration(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
resource, err := client.Registration.QueryRegistration()
@@ -410,7 +382,6 @@ func TestChallengeHTTP_Client_Registration_QueryRegistration(t *testing.T) {
func TestChallengeTLS_Client_Obtain(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -428,7 +399,6 @@ func TestChallengeTLS_Client_Obtain(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
// https://github.com/letsencrypt/pebble/issues/285
@@ -436,7 +406,7 @@ func TestChallengeTLS_Client_Obtain(t *testing.T) {
require.NoError(t, err, "Could not generate test key")
request := certificate.ObtainRequest{
- Domains: []string{testDomain1},
+ Domains: []string{"acme.wtf"},
Bundle: true,
PrivateKey: privateKeyCSR,
}
@@ -444,7 +414,7 @@ func TestChallengeTLS_Client_Obtain(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, testDomain1, resource.Domain)
+ assert.Equal(t, "acme.wtf", resource.Domain)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
@@ -455,7 +425,6 @@ func TestChallengeTLS_Client_Obtain(t *testing.T) {
func TestChallengeTLS_Client_ObtainForCSR(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -473,10 +442,12 @@ func TestChallengeTLS_Client_ObtainForCSR(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
- csr, err := x509.ParseCertificateRequest(createTestCSR(t))
+ csrRaw, err := os.ReadFile("./fixtures/csr.raw")
+ require.NoError(t, err)
+
+ csr, err := x509.ParseCertificateRequest(csrRaw)
require.NoError(t, err)
resource, err := client.Certificate.ObtainForCSR(certificate.ObtainForCSRRequest{
@@ -486,7 +457,7 @@ func TestChallengeTLS_Client_ObtainForCSR(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, testDomain1, resource.Domain)
+ assert.Equal(t, "acme.wtf", resource.Domain)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
@@ -497,7 +468,6 @@ func TestChallengeTLS_Client_ObtainForCSR(t *testing.T) {
func TestChallengeTLS_Client_ObtainForCSR_profile(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -515,10 +485,12 @@ func TestChallengeTLS_Client_ObtainForCSR_profile(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
- csr, err := x509.ParseCertificateRequest(createTestCSR(t))
+ csrRaw, err := os.ReadFile("./fixtures/csr.raw")
+ require.NoError(t, err)
+
+ csr, err := x509.ParseCertificateRequest(csrRaw)
require.NoError(t, err)
resource, err := client.Certificate.ObtainForCSR(certificate.ObtainForCSRRequest{
@@ -529,7 +501,7 @@ func TestChallengeTLS_Client_ObtainForCSR_profile(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, testDomain1, resource.Domain)
+ assert.Equal(t, "acme.wtf", resource.Domain)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:14000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
@@ -540,7 +512,6 @@ func TestChallengeTLS_Client_ObtainForCSR_profile(t *testing.T) {
func TestRegistrar_UpdateAccount(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "./fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -548,7 +519,7 @@ func TestRegistrar_UpdateAccount(t *testing.T) {
user := &fakeUser{
privateKey: privateKey,
- email: testEmail1,
+ email: "foo@example.com",
}
config := lego.NewConfig(user)
config.CADirURL = load.PebbleOptions.HealthCheckURL
@@ -559,13 +530,13 @@ func TestRegistrar_UpdateAccount(t *testing.T) {
regOptions := registration.RegisterOptions{TermsOfServiceAgreed: true}
reg, err := client.Registration.Register(regOptions)
require.NoError(t, err)
- require.Equal(t, []string{"mailto:" + testEmail1}, reg.Body.Contact)
+ require.Equal(t, []string{"mailto:foo@example.com"}, reg.Body.Contact)
user.registration = reg
- user.email = testEmail2
+ user.email = "bar@example.com"
resource, err := client.Registration.UpdateRegistration(regOptions)
require.NoError(t, err)
- require.Equal(t, []string{"mailto:" + testEmail2}, resource.Body.Contact)
+ require.Equal(t, []string{"mailto:bar@example.com"}, resource.Body.Contact)
require.Equal(t, reg.URI, resource.URI)
}
@@ -578,53 +549,3 @@ type fakeUser struct {
func (f *fakeUser) GetEmail() string { return f.email }
func (f *fakeUser) GetRegistration() *registration.Resource { return f.registration }
func (f *fakeUser) GetPrivateKey() crypto.PrivateKey { return f.privateKey }
-
-func createTestCSRFile(t *testing.T, raw bool) string {
- t.Helper()
-
- csr := createTestCSR(t)
-
- if raw {
- filename := filepath.Join(t.TempDir(), "csr.raw")
-
- fileRaw, err := os.Create(filename)
- require.NoError(t, err)
-
- defer fileRaw.Close()
-
- _, err = fileRaw.Write(csr)
- require.NoError(t, err)
-
- return filename
- }
-
- filename := filepath.Join(t.TempDir(), "csr.cert")
-
- file, err := os.Create(filename)
- require.NoError(t, err)
-
- defer file.Close()
-
- _, err = file.Write(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csr}))
- require.NoError(t, err)
-
- return filename
-}
-
-func createTestCSR(t *testing.T) []byte {
- t.Helper()
-
- privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
- require.NoError(t, err)
-
- csr, err := certcrypto.CreateCSR(privateKey, certcrypto.CSROptions{
- Domain: testDomain1,
- SAN: []string{
- testDomain1,
- testDomain2,
- },
- })
- require.NoError(t, err)
-
- return csr
-}
diff --git a/e2e/dnschallenge/dns_challenges_test.go b/e2e/dnschallenge/dns_challenges_test.go
index 9dd9ab0d6..9ae07d46a 100644
--- a/e2e/dnschallenge/dns_challenges_test.go
+++ b/e2e/dnschallenge/dns_challenges_test.go
@@ -18,11 +18,6 @@ import (
"github.com/stretchr/testify/require"
)
-const (
- testDomain1 = "légo.localhost"
- testDomain2 = "*.légo.localhost"
-)
-
var load = loader.EnvLoader{
PebbleOptions: &loader.CmdOption{
HealthCheckURL: "https://localhost:15000/dir",
@@ -58,13 +53,14 @@ func TestChallengeDNS_Run(t *testing.T) {
loader.CleanLegoFiles()
err := load.RunLego(
+ "-m", "hubert@hubert.com",
"--accept-tos",
"--dns", "exec",
"--dns.resolvers", ":8053",
"--dns.disable-cp",
"-s", "https://localhost:15000/dir",
- "-d", testDomain2,
- "-d", testDomain1,
+ "-d", "*.légo.acme",
+ "-d", "légo.acme",
"run")
if err != nil {
t.Fatal(err)
@@ -74,12 +70,10 @@ func TestChallengeDNS_Run(t *testing.T) {
func TestChallengeDNS_Client_Obtain(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "../fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
err = os.Setenv("EXEC_PATH", "../fixtures/update-dns.sh")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("EXEC_PATH") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -102,10 +96,9 @@ func TestChallengeDNS_Client_Obtain(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
- domains := []string{testDomain2, testDomain1}
+ domains := []string{"*.légo.acme", "légo.acme"}
// https://github.com/letsencrypt/pebble/issues/285
privateKeyCSR, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -120,7 +113,7 @@ func TestChallengeDNS_Client_Obtain(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, "*.xn--lgo-bma.localhost", resource.Domain)
+ assert.Equal(t, "*.xn--lgo-bma.acme", resource.Domain)
assert.Regexp(t, `https://localhost:15000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:15000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
@@ -131,12 +124,10 @@ func TestChallengeDNS_Client_Obtain(t *testing.T) {
func TestChallengeDNS_Client_Obtain_profile(t *testing.T) {
err := os.Setenv("LEGO_CA_CERTIFICATES", "../fixtures/certs/pebble.minica.pem")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("LEGO_CA_CERTIFICATES") }()
err = os.Setenv("EXEC_PATH", "../fixtures/update-dns.sh")
require.NoError(t, err)
-
defer func() { _ = os.Unsetenv("EXEC_PATH") }()
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -159,10 +150,9 @@ func TestChallengeDNS_Client_Obtain_profile(t *testing.T) {
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
require.NoError(t, err)
-
user.registration = reg
- domains := []string{testDomain2, testDomain1}
+ domains := []string{"*.légo.acme", "légo.acme"}
// https://github.com/letsencrypt/pebble/issues/285
privateKeyCSR, err := rsa.GenerateKey(rand.Reader, 2048)
@@ -178,7 +168,7 @@ func TestChallengeDNS_Client_Obtain_profile(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resource)
- assert.Equal(t, "*.xn--lgo-bma.localhost", resource.Domain)
+ assert.Equal(t, "*.xn--lgo-bma.acme", resource.Domain)
assert.Regexp(t, `https://localhost:15000/certZ/[\w\d]{14,}`, resource.CertURL)
assert.Regexp(t, `https://localhost:15000/certZ/[\w\d]{14,}`, resource.CertStableURL)
assert.NotEmpty(t, resource.Certificate)
diff --git a/e2e/fixtures/certs/localhost/cert.pem b/e2e/fixtures/certs/localhost/cert.pem
index d81d29e70..2866a2b48 100644
--- a/e2e/fixtures/certs/localhost/cert.pem
+++ b/e2e/fixtures/certs/localhost/cert.pem
@@ -1,20 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDMDCCAhigAwIBAgIILDt8c2fMw2IwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
-AxMVbWluaWNhIHJvb3QgY2EgNTM0NWU2MB4XDTI1MDkwMzIzNDAwNVoXDTI3MTAw
-MzIzNDAwNVowFDESMBAGA1UEAxMJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAmxTFtw113RK70H9pQmdKs9AxhFmnQ6BdDtp3jOZlWlUO
-0BltMXOUML5905etgtCbcC6RdKRtgSAiDfgx3VWiFMJH++4gUtnaB9SN8GhNSPBp
-FfSa2JhWPo9HQNUsAZqlGTV4SzcGRqtWvdZxUiOfQ2TcvyXIqsaD19ivvqI1NhT6
-bl3tredTZlzLLM6Wvkw6hfyHrJAPQP8LOlCIeDM4YIce6Gstv6qo9iCD4wJiY4u9
-5HVL7RK8t8JpZAb7VR+dPhbHEvVpjwuYd5Q05OZ280gFyrhbrKLbqst104GOQT4k
-QMJGWxGONyTX6np0Dx6O5jU7dvYvjVVawbJwGuaL6wIDAQABo3oweDAOBgNVHQ8B
-Af8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAfBgNV
-HSMEGDAWgBSu8RGpErgYUoYnQuwCq+/ggTiEjDAiBgNVHREEGzAZgglsb2NhbGhv
-c3SCBnBlYmJsZYcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAAB0gkekXCNOwqWmY
-vQ2lLJ8Zk2WzQ9B+VOC27IgxEEuskZyCpyXAbJB9sCGQWZhAARyaI4SPRGGagcug
-d1SwDWdPGeSJzF3aDnXDYoP9Zw2KqiqVZTngeoiw8Yn0F8PNriANwRLybouX7mMc
-4V7T5+2k4SUs7pFH4KO0a0XBCcjXDjdKuBljftRTXCHzJzfRtmieCCuZlpnp5sHx
-hKa/uxKGyyZB+4Y3MrzsiQSCBOr9G4TH9RofmNcawl+tsVe08zLV/XVhrbakKEs7
-Y7MGHSj3BkPFF32NObc0znqWzTaUD9hU+rXWGANM4sXd4dagdnxfrb7i0WYhcUFj
-9Try8Q==
+MIIDGzCCAgOgAwIBAgIIbEfayDFsBtwwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
+AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMDcx
+MjA2MTk0MjEwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCbFMW3DXXdErvQf2lCZ0qz0DGEWadDoF0O2neM5mVa
+VQ7QGW0xc5Qwvn3Tl62C0JtwLpF0pG2BICIN+DHdVaIUwkf77iBS2doH1I3waE1I
+8GkV9JrYmFY+j0dA1SwBmqUZNXhLNwZGq1a91nFSI59DZNy/JciqxoPX2K++ojU2
+FPpuXe2t51NmXMsszpa+TDqF/IeskA9A/ws6UIh4Mzhghx7oay2/qqj2IIPjAmJj
+i73kdUvtEry3wmlkBvtVH50+FscS9WmPC5h3lDTk5nbzSAXKuFusotuqy3XTgY5B
+PiRAwkZbEY43JNfqenQPHo7mNTt29i+NVVrBsnAa5ovrAgMBAAGjYzBhMA4GA1Ud
+DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
+AQH/BAIwADAiBgNVHREEGzAZgglsb2NhbGhvc3SCBnBlYmJsZYcEfwAAATANBgkq
+hkiG9w0BAQsFAAOCAQEAYIkXff8H28KS0KyLHtbbSOGU4sujHHVwiVXSATACsNAE
+D0Qa8hdtTQ6AUqA6/n8/u1tk0O4rPE/cTpsM3IJFX9S3rZMRsguBP7BSr1Lq/XAB
+7JP/CNHt+Z9aKCKcg11wIX9/B9F7pyKM3TdKgOpqXGV6TMuLjg5PlYWI/07lVGFW
+/mSJDRs8bSCFmbRtEqc4lpwlrpz+kTTnX6G7JDLfLWYw/xXVqwFfdengcDTHCc8K
+wtgGq/Gu6vcoBxIO3jaca+OIkMfxxXmGrcNdseuUCa3RMZ8Qy03DqGu6Y6XQyK4B
+W8zIG6H9SVKkAznM2yfYhW8v2ktcaZ95/OBHY97ZIw==
-----END CERTIFICATE-----
diff --git a/e2e/fixtures/certs/pebble.minica.pem b/e2e/fixtures/certs/pebble.minica.pem
index 5578b5b55..a69a4c419 100644
--- a/e2e/fixtures/certs/pebble.minica.pem
+++ b/e2e/fixtures/certs/pebble.minica.pem
@@ -1,20 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDPzCCAiegAwIBAgIIU0Xm9UFdQxUwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
-AxMVbWluaWNhIHJvb3QgY2EgNTM0NWU2MCAXDTI1MDkwMzIzNDAwNVoYDzIxMjUw
-OTAzMjM0MDA1WjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSA1MzQ1ZTYwggEi
+MIIDCTCCAfGgAwIBAgIIJOLbes8sTr4wDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
+AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMTcx
+MjA2MTk0MjEwWjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSAyNGUyZGIwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5WgZNoVJandj43kkLyU50vzCZ
alozvdRo3OFiKoDtmqKPNWRNO2hC9AUNxTDJco51Yc42u/WV3fPbbhSznTiOOVtn
Ajm6iq4I5nZYltGGZetGDOQWr78y2gWY+SG078MuOO2hyDIiKtVc3xiXYA+8Hluu
9F8KbqSS1h55yxZ9b87eKR+B0zu2ahzBCIHKmKWgc6N13l7aDxxY3D6uq8gtJRU0
toumyLbdzGcupVvjbjDP11nl07RESDWBLG1/g3ktJvqIa4BWgU2HMh4rND6y8OD3
Hy3H8MY6CElL+MOCbFJjWqhtOxeFyZZV9q3kYnk9CAuQJKMEGuN4GU6tzhW1AgMB
-AAGjezB5MA4GA1UdDwEB/wQEAwIChDATBgNVHSUEDDAKBggrBgEFBQcDATASBgNV
-HRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSu8RGpErgYUoYnQuwCq+/ggTiEjDAf
-BgNVHSMEGDAWgBSu8RGpErgYUoYnQuwCq+/ggTiEjDANBgkqhkiG9w0BAQsFAAOC
-AQEAXDVYov1+f6EL7S41LhYQkEX/GyNNzsEvqxE9U0+3Iri5JfkcNOiA9O9L6Z+Y
-bqcsXV93s3vi4r4WSWuc//wHyJYrVe5+tK4nlFpbJOvfBUtnoBDyKNxXzZCxFJVh
-f9uc8UejRfQMFbDbhWY/x83y9BDufJHHq32OjCIN7gp2UR8rnfYvlz7Zg4qkJBsn
-DG4dwd+pRTCFWJOVIG0JoNhK3ZmE7oJ1N4H38XkZ31NPcMksKxpsLLIS9+mosZtg
-4olL7tMPJklx5ZaeMFaKRDq4Gdxkbw4+O4vRgNm3Z8AXWKknOdfgdpqLUPPhRcP4
-v1lhy71EhBuXXwRQJry0lTdF+w==
+AAGjRTBDMA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
+BQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAF85v
+d40HK1ouDAtWeO1PbnWfGEmC5Xa478s9ddOd9Clvp2McYzNlAFfM7kdcj6xeiNhF
+WPIfaGAi/QdURSL/6C1KsVDqlFBlTs9zYfh2g0UXGvJtj1maeih7zxFLvet+fqll
+xseM4P9EVJaQxwuK/F78YBt0tCNfivC6JNZMgxKF59h0FBpH70ytUSHXdz7FKwix
+Mfn3qEb9BXSk0Q3prNV5sOV3vgjEtB4THfDxSz9z3+DepVnW3vbbqwEbkXdk3j82
+2muVldgOUgTwK8eT+XdofVdntzU/kzygSAtAQwLJfn51fS1GvEcYGBc1bDryIqmF
+p9BI7gVKtWSZYegicA==
-----END CERTIFICATE-----
diff --git a/e2e/fixtures/csr.cert b/e2e/fixtures/csr.cert
new file mode 100644
index 000000000..cece7ddec
--- /dev/null
+++ b/e2e/fixtures/csr.cert
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICfjCCAWYCAQAwEzERMA8GA1UEAxMIYWNtZS53dGYwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDAhXnho1w9OPHWs4YSMahYbG4Ui1K6hsHytBZfhsz0
+09igSWzHMEFZYHZJVuSr60enuJSZRhgwDjfhQWSUgHgKItLPnlNVYM6RhVaW0WfT
+w6CpmE2AuH3WuQbrR2he1Nt0xfUJla+VWOFZuW7GhgBiV5iWBvdLv6Ztgh8eATjo
+2vG2R+KuSUzrm6h+sb3nUR28OYunZ3vESjNwnL3/D/1th2rFpe3EA3em1HArJdXN
+F4eclciun5Js17AS9tdoHEEZMMBWyViiuz3CQlh+YD2qAvqaubanWNa+r+iijMvd
+4HlDHC99LTk6TJoSKoL+E/OGKmntLqmBJ1UrCFgvnw3DAgMBAAGgJjAkBgkqhkiG
+9w0BCQ4xFzAVMBMGA1UdEQQMMAqCCGFjbWUud3RmMA0GCSqGSIb3DQEBCwUAA4IB
+AQAfBLR8njftxf15V49szNsgNaG7Y5UQFwgl8pyiIaanGvX1DE0BtU1RB/w7itzX
+wW5W/wjielEbs1XkI2uz3hkebvHVA1QpA7bbrX01WonS18xCkiRDj8ZqFEG4vEGa
+HswzGUfq2v0gCOIPpVGE+8Q2Y7In5zwEfev+5DkHox4/vgwMhyPMI+y7jKtdG/dV
+U58SFnt/F1raoSmR6vfDcAFXm/L8LXEkxqqefFbhiRHRqQar1Wr15BH//swmNzEW
+5SVCCHcyIqreSua8uPjBcJ8aYVLniX6DMRyYv4ij/PSvSQy9xJDewLqR235WfTd/
+tk4hhJaqizKDpsvB+UFod5o5
+-----END CERTIFICATE REQUEST-----
diff --git a/e2e/fixtures/csr.raw b/e2e/fixtures/csr.raw
new file mode 100644
index 000000000..f4bb701cd
Binary files /dev/null and b/e2e/fixtures/csr.raw differ
diff --git a/e2e/loader/loader.go b/e2e/loader/loader.go
index 3e63302a3..b5ac9cef8 100644
--- a/e2e/loader/loader.go
+++ b/e2e/loader/loader.go
@@ -43,14 +43,12 @@ func (l *EnvLoader) MainTest(m *testing.M) int {
if _, e2e := os.LookupEnv("LEGO_E2E_TESTS"); !e2e {
fmt.Fprintln(os.Stderr, "skipping test: e2e tests are disabled. (no 'LEGO_E2E_TESTS' env var)")
fmt.Println("PASS")
-
return 0
}
if _, err := exec.LookPath("git"); err != nil {
fmt.Fprintln(os.Stderr, "skipping because git command not found")
fmt.Println("PASS")
-
return 0
}
@@ -58,7 +56,6 @@ func (l *EnvLoader) MainTest(m *testing.M) int {
if _, err := exec.LookPath(cmdNamePebble); err != nil {
fmt.Fprintln(os.Stderr, "skipping because pebble binary not found")
fmt.Println("PASS")
-
return 0
}
}
@@ -67,7 +64,6 @@ func (l *EnvLoader) MainTest(m *testing.M) int {
if _, err := exec.LookPath(cmdNameChallSrv); err != nil {
fmt.Fprintln(os.Stderr, "skipping because challtestsrv binary not found")
fmt.Println("PASS")
-
return 0
}
}
@@ -80,7 +76,6 @@ func (l *EnvLoader) MainTest(m *testing.M) int {
legoBinary, tearDown, err := buildLego()
defer tearDown()
-
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
@@ -141,7 +136,6 @@ func (l *EnvLoader) launchPebble() func() {
}
pebble, outPebble := l.cmdPebble()
-
go func() {
err := pebble.Run()
if err != nil {
@@ -154,7 +148,6 @@ func (l *EnvLoader) launchPebble() func() {
if err != nil {
fmt.Println(err)
}
-
fmt.Println(outPebble.String())
}
}
@@ -167,13 +160,11 @@ func (l *EnvLoader) cmdPebble() (*exec.Cmd, *bytes.Buffer) {
if err != nil {
panic(err)
}
-
cmd.Dir = dir
fmt.Printf("$ %s\n", strings.Join(cmd.Args, " "))
var b bytes.Buffer
-
cmd.Stdout = &b
cmd.Stderr = &b
@@ -182,7 +173,6 @@ func (l *EnvLoader) cmdPebble() (*exec.Cmd, *bytes.Buffer) {
func pebbleHealthCheck(options *CmdOption) {
client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
-
err := wait.For("pebble", 10*time.Second, 500*time.Millisecond, func() (bool, error) {
resp, err := client.Get(options.HealthCheckURL)
if err != nil {
@@ -206,7 +196,6 @@ func (l *EnvLoader) launchChallSrv() func() {
}
challtestsrv, outChalSrv := l.cmdChallSrv()
-
go func() {
err := challtestsrv.Run()
if err != nil {
@@ -219,7 +208,6 @@ func (l *EnvLoader) launchChallSrv() func() {
if err != nil {
fmt.Println(err)
}
-
fmt.Println(outChalSrv.String())
}
}
@@ -230,7 +218,6 @@ func (l *EnvLoader) cmdChallSrv() (*exec.Cmd, *bytes.Buffer) {
fmt.Printf("$ %s\n", strings.Join(cmd.Args, " "))
var b bytes.Buffer
-
cmd.Stdout = &b
cmd.Stderr = &b
@@ -242,7 +229,6 @@ func buildLego() (string, func(), error) {
if err != nil {
return "", func() {}, err
}
-
defer func() { _ = os.Chdir(here) }()
buildPath, err := os.MkdirTemp("", "lego_test")
@@ -276,7 +262,6 @@ func buildLego() (string, func(), error) {
return binary, func() {
_ = os.RemoveAll(buildPath)
-
CleanLegoFiles()
}, nil
}
@@ -298,7 +283,6 @@ func build(binary string) error {
if err != nil {
return err
}
-
cmd := exec.Command(toolPath, "build", "-o", binary)
output, err := cmd.CombinedOutput()
@@ -350,7 +334,6 @@ func goTool() (string, error) {
func CleanLegoFiles() {
cmd := exec.Command("rm", "-rf", ".lego")
fmt.Printf("$ %s\n", strings.Join(cmd.Args, " "))
-
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(string(output))
diff --git a/e2e/readme.md b/e2e/readme.md
index 171170507..746b9d726 100644
--- a/e2e/readme.md
+++ b/e2e/readme.md
@@ -1,9 +1,20 @@
# E2E tests
+How to run:
+
+- Add the following entries to your `/etc/hosts`:
+```
+127.0.0.1 acme.wtf
+127.0.0.1 lego.wtf
+127.0.0.1 acme.lego.wtf
+127.0.0.1 légô.wtf
+127.0.0.1 xn--lg-bja9b.wtf
+```
+
- Install [Pebble](https://github.com/letsencrypt/pebble):
```bash
-go install github.com/letsencrypt/pebble/v2/cmd/pebble@v2.9.0
-go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@v2.9.0
+go install github.com/letsencrypt/pebble/v2/cmd/pebble@main
+go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@main
```
- Launch tests:
diff --git a/go.mod b/go.mod
index b8e88428e..f2c6a71d0 100644
--- a/go.mod
+++ b/go.mod
@@ -3,170 +3,161 @@ module github.com/go-acme/lego/v4
go 1.24.0
require (
- cloud.google.com/go/compute/metadata v0.9.0
+ cloud.google.com/go/compute/metadata v0.7.0
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
- github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0
- github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1
+ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0
github.com/Azure/go-autorest/autorest v0.11.30
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13
github.com/Azure/go-autorest/autorest/to v0.4.1
- github.com/BurntSushi/toml v1.6.0
- github.com/akamai/AkamaiOPEN-edgegrid-golang/v11 v11.1.0
- github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.15
- github.com/alibabacloud-go/tea v1.4.0
- github.com/aliyun/credentials-go v1.4.7
- github.com/aws/aws-sdk-go-v2 v1.41.1
- github.com/aws/aws-sdk-go-v2/config v1.32.8
- github.com/aws/aws-sdk-go-v2/credentials v1.19.8
- github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.11
- github.com/aws/aws-sdk-go-v2/service/route53 v1.62.1
- github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0
- github.com/aws/aws-sdk-go-v2/service/sts v1.41.6
- github.com/aziontech/azionapi-go-sdk v0.144.0
- github.com/baidubce/bce-sdk-go v0.9.260
- github.com/cenkalti/backoff/v5 v5.0.3
+ github.com/BurntSushi/toml v1.5.0
+ github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87
+ github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2
+ github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.8
+ github.com/aliyun/credentials-go v1.4.6
+ github.com/aws/aws-sdk-go-v2 v1.36.6
+ github.com/aws/aws-sdk-go-v2/config v1.29.18
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.71
+ github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.5
+ github.com/aws/aws-sdk-go-v2/service/route53 v1.53.1
+ github.com/aws/aws-sdk-go-v2/service/s3 v1.84.1
+ github.com/aws/aws-sdk-go-v2/service/sts v1.34.1
+ github.com/aziontech/azionapi-go-sdk v0.142.0
+ github.com/baidubce/bce-sdk-go v0.9.235
+ github.com/cenkalti/backoff/v4 v4.3.0
github.com/dnsimple/dnsimple-go/v4 v4.0.0
- github.com/exoscale/egoscale/v3 v3.1.33
- github.com/go-acme/alidns-20150109/v4 v4.7.0
- github.com/go-acme/esa-20240910/v2 v2.48.0
- github.com/go-acme/jdcloud-sdk-go v1.64.0
- github.com/go-acme/tencentclouddnspod v1.3.24
- github.com/go-acme/tencentedgdeone v1.3.38
- github.com/go-jose/go-jose/v4 v4.1.3
- github.com/go-viper/mapstructure/v2 v2.5.0
+ github.com/exoscale/egoscale/v3 v3.1.24
+ github.com/go-acme/alidns-20150109/v4 v4.5.10
+ github.com/go-acme/tencentclouddnspod v1.0.1208
+ github.com/go-jose/go-jose/v4 v4.1.1
+ github.com/go-viper/mapstructure/v2 v2.4.0
github.com/google/go-cmp v0.7.0
- github.com/google/go-querystring v1.2.0
- github.com/google/uuid v1.6.0
+ github.com/google/go-querystring v1.1.0
github.com/gophercloud/gophercloud v1.14.1
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56
github.com/hashicorp/go-retryablehttp v0.7.8
- github.com/hashicorp/go-version v1.8.0
- github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.187
+ github.com/hashicorp/go-version v1.7.0
+ github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.159
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0
github.com/labbsr0x/bindman-dns-webhook v1.0.2
- github.com/ldez/grignotin v0.10.1
- github.com/linode/linodego v1.65.0
+ github.com/ldez/grignotin v0.9.0
+ github.com/linode/linodego v1.53.0
github.com/liquidweb/liquidweb-go v1.6.4
github.com/mattn/go-isatty v0.0.20
- github.com/miekg/dns v1.1.72
+ github.com/miekg/dns v1.1.67
github.com/mimuret/golang-iij-dpf v0.9.1
github.com/namedotcom/go/v4 v4.0.2
- github.com/nrdcg/auroradns v1.2.0
- github.com/nrdcg/bunny-go v0.1.0
- github.com/nrdcg/desec v0.11.1
+ github.com/nrdcg/auroradns v1.1.0
+ github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea
+ github.com/nrdcg/desec v0.11.0
github.com/nrdcg/dnspod-go v0.4.0
github.com/nrdcg/freemyip v0.3.0
github.com/nrdcg/goacmedns v0.2.0
- github.com/nrdcg/goinwx v0.12.0
- github.com/nrdcg/mailinabox v0.3.0
- github.com/nrdcg/namesilo v0.5.0
+ github.com/nrdcg/goinwx v0.11.0
+ github.com/nrdcg/mailinabox v0.2.0
+ github.com/nrdcg/namesilo v0.2.1
github.com/nrdcg/nodion v0.1.0
- github.com/nrdcg/oci-go-sdk/common/v1065 v1065.108.2
- github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.108.2
+ github.com/nrdcg/oci-go-sdk/common/v1065 v1065.95.2
+ github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.95.2
github.com/nrdcg/porkbun v0.4.0
- github.com/nrdcg/vegadns v0.3.0
github.com/nzdjb/go-metaname v1.0.0
github.com/ovh/go-ovh v1.9.0
github.com/pquerna/otp v1.5.0
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2
github.com/regfish/regfish-dnsapi-go v0.1.1
- github.com/sacloud/api-client-go v0.3.3
- github.com/sacloud/iaas-api-go v1.23.1
- github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36
+ github.com/sacloud/api-client-go v0.3.2
+ github.com/sacloud/iaas-api-go v1.16.1
+ github.com/scaleway/scaleway-sdk-go v1.0.0-beta.34
github.com/selectel/domains-go v1.1.0
github.com/selectel/go-selvpcclient/v4 v4.1.0
- github.com/softlayer/softlayer-go v1.2.1
- github.com/stretchr/testify v1.11.1
- github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.48
- github.com/transip/gotransip/v6 v6.26.1
- github.com/ultradns/ultradns-go-sdk v1.8.1-20250722213956-faef419
+ github.com/softlayer/softlayer-go v1.1.7
+ github.com/stretchr/testify v1.10.0
+ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1210
+ github.com/transip/gotransip/v6 v6.26.0
+ github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec
github.com/urfave/cli/v2 v2.27.7
- github.com/vinyldns/go-vinyldns v0.9.17
- github.com/volcengine/volc-sdk-golang v1.0.237
- github.com/vultr/govultr/v3 v3.27.0
- github.com/yandex-cloud/go-genproto v0.54.0
- github.com/yandex-cloud/go-sdk/services/dns v0.0.36
- github.com/yandex-cloud/go-sdk/v2 v2.56.0
- golang.org/x/crypto v0.48.0
- golang.org/x/net v0.50.0
- golang.org/x/oauth2 v0.35.0
- golang.org/x/text v0.34.0
- golang.org/x/time v0.14.0
- google.golang.org/api v0.267.0
- gopkg.in/ns1/ns1-go.v2 v2.17.2
+ github.com/vinyldns/go-vinyldns v0.9.16
+ github.com/volcengine/volc-sdk-golang v1.0.216
+ github.com/vultr/govultr/v3 v3.21.1
+ github.com/yandex-cloud/go-genproto v0.14.0
+ github.com/yandex-cloud/go-sdk/services/dns v0.0.3
+ github.com/yandex-cloud/go-sdk/v2 v2.0.8
+ golang.org/x/crypto v0.40.0
+ golang.org/x/net v0.42.0
+ golang.org/x/oauth2 v0.30.0
+ golang.org/x/text v0.27.0
+ golang.org/x/time v0.12.0
+ google.golang.org/api v0.242.0
+ gopkg.in/ns1/ns1-go.v2 v2.14.4
gopkg.in/yaml.v2 v2.4.0
- software.sslmate.com/src/go-pkcs12 v0.7.0
+ software.sslmate.com/src/go-pkcs12 v0.5.0
)
require (
- cloud.google.com/go/auth v0.18.1 // indirect
+ cloud.google.com/go/auth v0.16.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
- github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
+ github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
+ github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
+ github.com/alibabacloud-go/tea v1.3.9 // indirect
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
- github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
- github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
- github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
- github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
- github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
- github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
- github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
- github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 // indirect
- github.com/aws/smithy-go v1.24.0 // indirect
- github.com/benbjohnson/clock v1.3.5 // indirect
+ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.18 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.25.6 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4 // indirect
+ github.com/aws/smithy-go v1.22.4 // indirect
+ github.com/benbjohnson/clock v1.3.0 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
- github.com/cenkalti/backoff/v4 v4.3.0 // indirect
- github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
- github.com/fatih/color v1.16.0 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.0.1 // indirect
- github.com/go-logr/logr v1.4.3 // indirect
+ github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.23.0 // indirect
- github.com/go-resty/resty/v2 v2.17.1 // indirect
- github.com/goccy/go-yaml v1.9.8 // indirect
- github.com/gofrs/flock v0.13.0 // indirect
- github.com/gofrs/uuid v4.4.0+incompatible // indirect
+ github.com/go-resty/resty/v2 v2.16.5 // indirect
+ github.com/gofrs/flock v0.12.1 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
- github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
+ github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/s2a-go v0.1.9 // indirect
- github.com/googleapis/enterprise-certificate-proxy v0.3.11 // indirect
- github.com/googleapis/gax-go/v2 v2.17.0 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
+ github.com/googleapis/gax-go/v2 v2.14.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
- github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
@@ -174,11 +165,11 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/liquidweb/liquidweb-cli v0.6.9 // indirect
github.com/magiconair/properties v1.8.7 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/peterhellberg/link v1.2.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
@@ -186,17 +177,18 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sacloud/go-http v0.1.9 // indirect
- github.com/sacloud/packages-go v0.0.12 // indirect
+ github.com/sacloud/packages-go v0.0.11 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/sony/gobreaker v1.0.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
- github.com/spf13/cast v1.7.0 // indirect
- github.com/spf13/pflag v1.0.7 // indirect
+ github.com/spf13/cast v1.6.0 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
@@ -204,26 +196,23 @@ require (
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.mongodb.org/mongo-driver v1.13.1 // indirect
- go.opentelemetry.io/auto/sdk v1.2.1 // indirect
+ go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
- go.opentelemetry.io/otel v1.39.0 // indirect
- go.opentelemetry.io/otel/metric v1.39.0 // indirect
- go.opentelemetry.io/otel/trace v1.39.0 // indirect
+ go.opentelemetry.io/otel v1.36.0 // indirect
+ go.opentelemetry.io/otel/metric v1.36.0 // indirect
+ go.opentelemetry.io/otel/trace v1.36.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/ratelimit v0.3.1 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
- golang.org/x/mod v0.32.0 // indirect
- golang.org/x/sync v0.19.0 // indirect
- golang.org/x/sys v0.41.0 // indirect
- golang.org/x/tools v0.41.0 // indirect
- golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect
- google.golang.org/grpc v1.78.0 // indirect
- google.golang.org/protobuf v1.36.11 // indirect
- gopkg.in/ini.v1 v1.67.1 // indirect
+ golang.org/x/mod v0.25.0 // indirect
+ golang.org/x/sync v0.16.0 // indirect
+ golang.org/x/sys v0.34.0 // indirect
+ golang.org/x/tools v0.34.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
+ google.golang.org/grpc v1.73.0 // indirect
+ google.golang.org/protobuf v1.36.6 // indirect
+ gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
-
-retract v4.30.0 // Problem related to misuse of sycalls by aliyun/credentials-go
diff --git a/go.sum b/go.sum
index f5b87c9fe..6ed16ca42 100644
--- a/go.sum
+++ b/go.sum
@@ -13,8 +13,8 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go/auth v0.18.1 h1:IwTEx92GFUo2pJ6Qea0EU3zYvKnTAeRCODxfA/G5UWs=
-cloud.google.com/go/auth v0.18.1/go.mod h1:GfTYoS9G3CWpRA3Va9doKN9mjPGRS+v41jmZAhBzbrA=
+cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
+cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
@@ -23,8 +23,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
-cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
+cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
+cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
@@ -42,14 +42,14 @@ github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 h1:Dy3M9aegiI7d7PF1LUdjbVigJReo+QOceYs
github.com/AdamSLevy/jsonrpc2/v14 v14.1.0/go.mod h1:ZakZtbCXxCz82NJvq7MoREtiQesnDfrtF6RFUGzQfLo=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw=
@@ -85,17 +85,19 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
-github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
+github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
+github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/sarama v1.30.1/go.mod h1:hGgx05L/DiW8XYBXeJdKIN6V2QUy2H6JqME5VT1NLRw=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@@ -103,8 +105,8 @@ github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
-github.com/akamai/AkamaiOPEN-edgegrid-golang/v11 v11.1.0 h1:h/33OxYLqBk0BYmEbSUy7MlvgQR/m1w1/7OJFKoPL1I=
-github.com/akamai/AkamaiOPEN-edgegrid-golang/v11 v11.1.0/go.mod h1:rvh3imDA6EaQi+oM/GQHkQAOHbXPKJ7EWJvfjuw141Q=
+github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 h1:F1j7z+/DKEsYqZNoxC6wvfmaiDneLsQOFQmuq9NADSY=
+github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2/go.mod h1:QlXr/TrICfQ/ANa76sLeQyhAJyNR9sEcfNuZBkY9jgY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -121,10 +123,9 @@ github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.14/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.15 h1:Mubp9hXZMTPWZK+WxrR+kKOVFp4Q/PDZrIIM7ByXI9Y=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.15/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.8 h1:AL+nH363NJFS1NXIjCdmj5MOElgKEqgFeoq7vjje350=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.8/go.mod h1:d+z3ScRqc7PFzg4h9oqE3h8yunRZvAvU7u+iuPYEhpU=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
@@ -145,83 +146,78 @@ github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/Ke
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
-github.com/alibabacloud-go/tea v1.3.13/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
-github.com/alibabacloud-go/tea v1.4.0 h1:MSKhu/kWLPX7mplWMngki8nNt+CyUZ+kfkzaR5VpMhA=
-github.com/alibabacloud-go/tea v1.4.0/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
+github.com/alibabacloud-go/tea v1.3.9 h1:bjgt1bvdY780vz/17iWNNtbXl4A77HWntWMeaUF3So0=
+github.com/alibabacloud-go/tea v1.3.9/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
+github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
-github.com/aliyun/credentials-go v1.4.7 h1:T17dLqEtPUFvjDRRb5giVvLh6dFT8IcNFJJb7MeyCxw=
-github.com/aliyun/credentials-go v1.4.7/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
+github.com/aliyun/credentials-go v1.4.6 h1:CG8rc/nxCNKfXbZWpWDzI9GjF4Tuu3Es14qT8Y0ClOk=
+github.com/aliyun/credentials-go v1.4.6/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
-github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
-github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
-github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
-github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
-github.com/aws/aws-sdk-go-v2/config v1.32.8 h1:iu+64gwDKEoKnyTQskSku72dAwggKI5sV6rNvgSMpMs=
-github.com/aws/aws-sdk-go-v2/config v1.32.8/go.mod h1:MI2XvA+qDi3i9AJxX1E2fu730syEBzp/jnXrjxuHwgI=
-github.com/aws/aws-sdk-go-v2/credentials v1.19.8 h1:Jp2JYH1lRT3KhX4mshHPvVYsR5qqRec3hGvEarNYoR0=
-github.com/aws/aws-sdk-go-v2/credentials v1.19.8/go.mod h1:fZG9tuvyVfxknv1rKibIz3DobRaFw1Poe8IKtXB3XYY=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=
-github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=
+github.com/aws/aws-sdk-go-v2 v1.36.6 h1:zJqGjVbRdTPojeCGWn5IR5pbJwSQSBh5RWFTQcEQGdU=
+github.com/aws/aws-sdk-go-v2 v1.36.6/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY=
+github.com/aws/aws-sdk-go-v2/config v1.29.18 h1:x4T1GRPnqKV8HMJOMtNktbpQMl3bIsfx8KbqmveUO2I=
+github.com/aws/aws-sdk-go-v2/config v1.29.18/go.mod h1:bvz8oXugIsH8K7HLhBv06vDqnFv3NsGDt2Znpk7zmOU=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.71 h1:r2w4mQWnrTMJjOyIsZtGp3R3XGY3nqHn8C26C2lQWgA=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.71/go.mod h1:E7VF3acIup4GB5ckzbKFrCK0vTvEQxOxgdq4U3vcMCY=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33 h1:D9ixiWSG4lyUBL2DDNK924Px9V/NBVpML90MHqyTADY=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33/go.mod h1:caS/m4DI+cij2paz3rtProRBI4s/+TCiWoaWZuQ9010=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37 h1:osMWfm/sC/L4tvEdQ65Gri5ZZDCUpuYJZbTTDrsn4I0=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37/go.mod h1:ZV2/1fbjOPr4G4v38G3Ww5TBT4+hmsK45s/rxu1fGy0=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37 h1:v+X21AvTb2wZ+ycg1gx+orkB/9U6L7AOp93R7qYxsxM=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37/go.mod h1:G0uM1kyssELxmJ2VZEfG0q2npObR3BAkF3c1VsfVnfs=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37 h1:XTZZ0I3SZUHAtBLBU6395ad+VOblE0DwQP6MuaNeics=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.37/go.mod h1:Pi6ksbniAWVwu2S8pEzcYPyhUkAcLaufxN7PfAUQjBk=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=
-github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.11 h1:VM5e5M39zRSs+aT0O9SoxHjUXqXxhbw3Yi0FdMQWPIc=
-github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.11/go.mod h1:0jvzYPIQGCpnY/dmdaotTk2JH4QuBlnW0oeyrcGLWJ4=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.62.1 h1:1jIdwWOulae7bBLIgB36OZ0DINACb1wxM6wdGlx4eHE=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.62.1/go.mod h1:tE2zGlMIlxWv+7Otap7ctRp3qeKqtnja7DZguj3Vu/Y=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
-github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
-github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
-github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk=
-github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14 h1:0jbJeuEHlwKJ9PfXtpSFc4MF+WIWORdhN1n30ITZGFM=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.14/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
-github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
-github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5 h1:M5/B8JUaCI8+9QD+u3S/f4YHpvqE9RpSkV3rf0Iks2w=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.5/go.mod h1:Bktzci1bwdbpuLiu3AOksiNPMl/LLKmX1TWmqp2xbvs=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18 h1:vvbXsA2TVO80/KT7ZqCbx934dt6PY+vQ8hZpUZ/cpYg=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18/go.mod h1:m2JJHledjBGNMsLOF1g9gbAxprzq3KjC8e4lxtn+eWg=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.18 h1:OS2e0SKqsU2LiJPqL8u9x41tKc6MMEHrWjLVLn3oysg=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.18/go.mod h1:+Yrk+MDGzlNGxCXieljNeWpoZTCQUQVL+Jk9hGGJ8qM=
+github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.5 h1:DYQbfSAWcMwRM0LbCDyQkPB1AcaZcLzLoaFrYcpyMag=
+github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.5/go.mod h1:Lav4KLgncVjjrwLWutOccjEgJ4T/RAdY+Ic0hmNIgI0=
+github.com/aws/aws-sdk-go-v2/service/route53 v1.53.1 h1:R3nSX1hguRy6MnknHiepSvqnnL8ansFwK2hidPesAYU=
+github.com/aws/aws-sdk-go-v2/service/route53 v1.53.1/go.mod h1:fmSiB4OAghn85lQgk7XN9l9bpFg5Bm1v3HuaXKytPEw=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.84.1 h1:RkHXU9jP0DptGy7qKI8CBGsUJruWz0v5IgwBa2DwWcU=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.84.1/go.mod h1:3xAOf7tdKF+qbb+XpU+EPhNXAdun3Lu1RcDrj8KC24I=
+github.com/aws/aws-sdk-go-v2/service/sso v1.25.6 h1:rGtWqkQbPk7Bkwuv3NzpE/scwwL9sC1Ul3tn9x83DUI=
+github.com/aws/aws-sdk-go-v2/service/sso v1.25.6/go.mod h1:u4ku9OLv4TO4bCPdxf4fA1upaMaJmP9ZijGk3AAOC6Q=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4 h1:OV/pxyXh+eMA0TExHEC4jyWdumLxNbzz1P0zJoezkJc=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4/go.mod h1:8Mm5VGYwtm+r305FfPSuc+aFkrypeylGYhFim6XEPoc=
+github.com/aws/aws-sdk-go-v2/service/sts v1.34.1 h1:aUrLQwJfZtwv3/ZNG2xRtEen+NqI3iesuacjP51Mv1s=
+github.com/aws/aws-sdk-go-v2/service/sts v1.34.1/go.mod h1:3wFBZKoWnX3r+Sm7in79i54fBmNfwhdNdQuscCw7QIk=
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
-github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
-github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
-github.com/aziontech/azionapi-go-sdk v0.144.0 h1:T+/w18o+FCiZsk3Z0ACBVVe7c/5EGLG15S3P8JfuPfo=
-github.com/aziontech/azionapi-go-sdk v0.144.0/go.mod h1:OKxP/R0iVXnJJakYwMhh2BGAXnud8Ruy55Ak9ANuWoU=
-github.com/baidubce/bce-sdk-go v0.9.260 h1:1v1+2GTP+NGK3L24rJ+bnoiTaDaIy2YoaUM+ot2GTcw=
-github.com/baidubce/bce-sdk-go v0.9.260/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
+github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
+github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
+github.com/aziontech/azionapi-go-sdk v0.142.0 h1:1NOHXlC0/7VgbfbTIGVpsYn1THCugM4/SCOXVdUHQ+A=
+github.com/aziontech/azionapi-go-sdk v0.142.0/go.mod h1:cA5DY/VP4X5Eu11LpQNzNn83ziKjja7QVMIl4J45feA=
+github.com/baidubce/bce-sdk-go v0.9.235 h1:iAi+seH9w1Go2szFNzyGumahLGDsuYZ3i8hduX3qiM8=
+github.com/baidubce/bce-sdk-go v0.9.235/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
-github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
-github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
+github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
@@ -235,9 +231,8 @@ github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
-github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -249,6 +244,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -271,6 +267,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
@@ -289,11 +287,10 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/exoscale/egoscale/v3 v3.1.33 h1:5Lk/pwZ+K0sjNu9obS0VYPfhZQffRkvvO0BpdPoir4o=
-github.com/exoscale/egoscale/v3 v3.1.33/go.mod h1:0iY8OxgHJCS5TKqDNhwOW95JBKCnBZl3YGU4Yt+NqkU=
+github.com/exoscale/egoscale/v3 v3.1.24 h1:EUWmjw/JgMj1faX5ojosjrJE5eY0QEWP0KBmLyFU6aE=
+github.com/exoscale/egoscale/v3 v3.1.24/go.mod h1:A53enXfm8nhVMpIYw0QxiwQ2P6AdCF4F/nVYChNEzdE=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
-github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
@@ -317,24 +314,18 @@ github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uq
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-acme/alidns-20150109/v4 v4.7.0 h1:PqJ/wR0JTpL4v0Owu1uM7bPQ1Yww0eQLAuuSdLjjQaQ=
-github.com/go-acme/alidns-20150109/v4 v4.7.0/go.mod h1:btQvB6xZoN6ykKB74cPhiR+uvhrEE2AFVXm6RDmCHm0=
-github.com/go-acme/esa-20240910/v2 v2.48.0 h1:muSDyhjDTejxUGe3FTthCPCqRaEdYY9cG3N/AmU52Lc=
-github.com/go-acme/esa-20240910/v2 v2.48.0/go.mod h1:shPb6hzc1rJL15IJBY8HQ4GZk4E8RC52+52twutEwIg=
-github.com/go-acme/jdcloud-sdk-go v1.64.0 h1:AW9j5khk8tRYbpBJPxKmqdwIqgLs2Fz3HUK3hn2YXjs=
-github.com/go-acme/jdcloud-sdk-go v1.64.0/go.mod h1:qc/m8HNX1Zgd7GAv2DSEinup8fwy3Ted3/VVx7LB5bU=
-github.com/go-acme/tencentclouddnspod v1.3.24 h1:uCSiOW1EJttcnOON+MVVyVDJguFL/Q4NIGkq1CrT9p8=
-github.com/go-acme/tencentclouddnspod v1.3.24/go.mod h1:RKcB2wSoZncjBA0OEFj59s1ko1XDy+ZsAtk+9uMxUF0=
-github.com/go-acme/tencentedgdeone v1.3.38 h1:5YsVl0H4A+cwtiUqR1eZbKFdr4OWfYp2KYJopifzKyQ=
-github.com/go-acme/tencentedgdeone v1.3.38/go.mod h1:yyjTKVmGpMtFv5HqGODqehHnZJ4KWAbG6dAiwWDgCDY=
+github.com/go-acme/alidns-20150109/v4 v4.5.10 h1:epLD0VaHR5XUpiM6mjm4MzQFICrk+zpuqDz2aO1/R/k=
+github.com/go-acme/alidns-20150109/v4 v4.5.10/go.mod h1:qGRq8kD0xVgn82qRSQmhHwh/oWxKRjF4Db5OI4ScV5g=
+github.com/go-acme/tencentclouddnspod v1.0.1208 h1:xAVy1lmg2KcKKeYmFSBQUttwc1o1S++9QTjAotGC+BM=
+github.com/go-acme/tencentclouddnspod v1.0.1208/go.mod h1:yxG02mkbbVd7lTb97nOn7oj09djhm7hAwxNQw4B9dpQ=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
-github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
+github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI=
+github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
@@ -345,43 +336,33 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
-github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
-github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
-github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
-github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
-github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
-github.com/go-resty/resty/v2 v2.17.1 h1:x3aMpHK1YM9e4va/TMDRlusDDoZiQ+ViDu/WpA6xTM4=
-github.com/go-resty/resty/v2 v2.17.1/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
+github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
+github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
-github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
-github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
+github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA=
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
-github.com/goccy/go-yaml v1.9.8 h1:5gMyLUeU1/6zl+WFfR1hN7D2kf+1/eRGa7DFtToiBvQ=
-github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
-github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
-github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
-github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
+github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -390,8 +371,8 @@ github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
-github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
+github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
+github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -448,9 +429,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
-github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=
-github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -462,21 +442,22 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
-github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
+github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/enterprise-certificate-proxy v0.3.11 h1:vAe81Msw+8tKUxi2Dqh/NZMz7475yUvmRIkXr4oN2ao=
-github.com/googleapis/enterprise-certificate-proxy v0.3.11/go.mod h1:RFV7MUdlb7AgEq2v7FmMCfeSMCllAzWxFgRdusoGks8=
+github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
+github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc=
-github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY=
+github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
+github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/gophercloud/gophercloud v1.14.1 h1:DTCNaTVGl8/cFu58O1JwWgis9gtISAFONqpMKNg/Vpw=
github.com/gophercloud/gophercloud v1.14.1/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
@@ -495,6 +476,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@@ -525,8 +508,8 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=
-github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -541,8 +524,8 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.187 h1:J+U6+eUjIsBhefolFdZW5hQNJbkMj+7msxZrv56Cg2g=
-github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.187/go.mod h1:M+yna96Fx9o5GbIUnF3OvVvQGjgfVSyeJbV9Yb1z/wI=
+github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.159 h1:6LZysc4iyO4cHB1aJsRklWfSEJr8CEhW7BmcM0SkYcU=
+github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.159/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -553,8 +536,8 @@ github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0 h1:AKsihjFT/t6Y0keEv3p59DACcOuh0inWXdUB0ZOzYH0=
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0/go.mod h1:NeNJpz09efw/edzqkVivGv1bWqBXTomqYBRFbP+XBqg=
github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
-github.com/jarcoal/httpmock v1.4.1 h1:0Ju+VCFuARfFlhVXFc2HxlcQkfB+Xq12/EotHko+x2A=
-github.com/jarcoal/httpmock v1.4.1/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
+github.com/jarcoal/httpmock v1.4.0 h1:BvhqnH0JAYbNudL2GMJKgOHe2CtKlzJ/5rWKyp+hc2k=
+github.com/jarcoal/httpmock v1.4.0/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
@@ -572,9 +555,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU=
-github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
@@ -611,13 +593,12 @@ github.com/labbsr0x/bindman-dns-webhook v1.0.2 h1:I7ITbmQPAVwrDdhd6dHKi+MYJTJqPC
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
github.com/labbsr0x/goh v1.0.1 h1:97aBJkDjpyBZGPbQuOK5/gHcSFbcr5aRsq3RSRJFpPk=
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
-github.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o=
-github.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas=
-github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/ldez/grignotin v0.9.0 h1:MgOEmjZIVNn6p5wPaGp/0OKWyvq42KnzAt/DAb8O4Ow=
+github.com/ldez/grignotin v0.9.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
-github.com/linode/linodego v1.65.0 h1:SdsuGD8VSsPWeShXpE7ihl5vec+fD3MgwhnfYC/rj7k=
-github.com/linode/linodego v1.65.0/go.mod h1:tOFiTErdjkbVnV+4S0+NmIE9dqqZUEM2HsJaGu8wMh8=
+github.com/linode/linodego v1.53.0 h1:UWr7bUUVMtcfsuapC+6blm6+jJLPd7Tf9MZUpdOERnI=
+github.com/linode/linodego v1.53.0/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA=
github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
github.com/liquidweb/liquidweb-cli v0.6.9 h1:acbIvdRauiwbxIsOCEMXGwF75aSJDbDiyAWPjVnwoYM=
github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
@@ -640,7 +621,6 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -653,8 +633,8 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
-github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
-github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
+github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
+github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/mimuret/golang-iij-dpf v0.9.1 h1:Gj6EhHJkOhr+q2RnvRPJsPMcjuVnWPSccEHyoEehU34=
github.com/mimuret/golang-iij-dpf v0.9.1/go.mod h1:sl9KyOkESib9+KRD3HaGpgi1xk7eoN2+d96LCLsME2M=
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
@@ -694,35 +674,34 @@ github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/
github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nrdcg/auroradns v1.2.0 h1:Jg407vTdXZvZKsART9CNWMp8rQOyhBk04q0MsOf0YR4=
-github.com/nrdcg/auroradns v1.2.0/go.mod h1:hnByA4Z7MOmV4EPRw5eOmEaNRFavcCIz6kONpNxp9LI=
-github.com/nrdcg/bunny-go v0.1.0 h1:GAHTRpHaG/TxfLZlqoJ8OJFzw8rI74+jOTkzxWh0uHA=
-github.com/nrdcg/bunny-go v0.1.0/go.mod h1:u+C9dgsspgtWVaAz6QkyV17s9fxD8viwwKoxb9XMz1A=
-github.com/nrdcg/desec v0.11.1 h1:ilpKmCr4gGsLcyq3RHfHNmlRzm9fzT2XbWxoVaUCS0s=
-github.com/nrdcg/desec v0.11.1/go.mod h1:2LuxHlOcwML/7cntu0eimONmA1U+ZxFDAonoSXr4igQ=
+github.com/nrdcg/auroradns v1.1.0 h1:KekGh8kmf2MNwqZVVYo/fw/ZONt8QMEmbMFOeljteWo=
+github.com/nrdcg/auroradns v1.1.0/go.mod h1:O7tViUZbAcnykVnrGkXzIJTHoQCHcgalgAe6X1mzHfk=
+github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea h1:OSgRS4kqOs/WuxuFOObP2gwrenL4/qiKXQbQugr/Two=
+github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea/go.mod h1:IDRRngAngb2eTEaWgpO0hukQFI/vJId46fT1KErMytA=
+github.com/nrdcg/desec v0.11.0 h1:XZVHy07sg12y8FozMp+l7XvzPsdzog0AYXuQMaHBsfs=
+github.com/nrdcg/desec v0.11.0/go.mod h1:5+4vyhMRTs49V9CNoODF/HwT8Mwxv9DJ6j+7NekUnBs=
github.com/nrdcg/dnspod-go v0.4.0 h1:c/jn1mLZNKF3/osJ6mz3QPxTudvPArXTjpkmYj0uK6U=
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
github.com/nrdcg/freemyip v0.3.0 h1:0D2rXgvLwe2RRaVIjyUcQ4S26+cIS2iFwnhzDsEuuwc=
github.com/nrdcg/freemyip v0.3.0/go.mod h1:c1PscDvA0ukBF0dwelU/IwOakNKnVxetpAQ863RMJoM=
github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0=
github.com/nrdcg/goacmedns v0.2.0/go.mod h1:T5o6+xvSLrQpugmwHvrSNkzWht0UGAwj2ACBMhh73Cg=
-github.com/nrdcg/goinwx v0.12.0 h1:ujdUqDBnaRSFwzVnImvPHYw3w3m9XgmGImNUw1GyMb4=
-github.com/nrdcg/goinwx v0.12.0/go.mod h1:IrVKd3ZDbFiMjdPgML4CSxZAY9wOoqLvH44zv3NodJ0=
-github.com/nrdcg/mailinabox v0.3.0 h1:PHkC1elKXKAjEvdx2HHFMgcEGZFqudAl7aU3L2JDhM4=
-github.com/nrdcg/mailinabox v0.3.0/go.mod h1:1eFIGcM4lI+AfFOUpbs548SFGz1ZWoMOGbECBmkghw4=
-github.com/nrdcg/namesilo v0.5.0 h1:6QNxT/XxE+f5B+7QlfWorthNzOzcGlBLRQxqi6YeBrE=
-github.com/nrdcg/namesilo v0.5.0/go.mod h1:4UkwlwQfDt74kSGmhLaDylnBrD94IfflnpoEaj6T2qw=
+github.com/nrdcg/goinwx v0.11.0 h1:GER0SE3POub7rxARt3Y3jRy1OON1hwF1LRxHz5xsFBw=
+github.com/nrdcg/goinwx v0.11.0/go.mod h1:0BXSC0FxVtU4aTjX0Zw3x0DK32tjugLzeNIAGtwXvPQ=
+github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CFk=
+github.com/nrdcg/mailinabox v0.2.0/go.mod h1:0yxqeYOiGyxAu7Sb94eMxHPIOsPYXAjTeA9ZhePhGnc=
+github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
+github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
github.com/nrdcg/nodion v0.1.0 h1:zLKaqTn2X0aDuBHHfyA1zFgeZfiCpmu/O9DM73okavw=
github.com/nrdcg/nodion v0.1.0/go.mod h1:inbuh3neCtIWlMPZHtEpe43TmRXxHV6+hk97iCZicms=
-github.com/nrdcg/oci-go-sdk/common/v1065 v1065.108.2 h1:OWijzl3nHUApvTivl+3+78dbBwmyEHOnb+W9m6ixGbk=
-github.com/nrdcg/oci-go-sdk/common/v1065 v1065.108.2/go.mod h1:Gcs8GCaZXL3FdiDWgdnMxlOLEdRprJJnPYB22TX1jw8=
-github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.108.2 h1:9LsjN/zaIN7H8JE61NHpbWhxF0UGY96+kMlk3g8OvGU=
-github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.108.2/go.mod h1:32vZH06TuwZSn+IDMO1qcDvC2vHVlzUALCwXGWPA+dc=
+github.com/nrdcg/oci-go-sdk/common/v1065 v1065.95.2 h1:a7QUZD5c+NkrFrdkdyJUO9cOUo8VQJyRkcIzk9Wh+DI=
+github.com/nrdcg/oci-go-sdk/common/v1065 v1065.95.2/go.mod h1:O6osg9dPzXq7H2ib/1qzimzG5oXSJFgccR7iawg7SwA=
+github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.95.2 h1:yflYnbQu4ciWH/GEztqlAccLPw4k5mp11uhW++al5ow=
+github.com/nrdcg/oci-go-sdk/dns/v1065 v1065.95.2/go.mod h1:atPDu37gu8HT7TtPpovrkgNmDAgOGM6TVEJ7ANTblMs=
github.com/nrdcg/porkbun v0.4.0 h1:rWweKlwo1PToQ3H+tEO9gPRW0wzzgmI/Ob3n2Guticw=
github.com/nrdcg/porkbun v0.4.0/go.mod h1:/QMskrHEIM0IhC/wY7iTCUgINsxdT2WcOphktJ9+Q54=
-github.com/nrdcg/vegadns v0.3.0 h1:11FQMw7xVIRUWO9o5+Z/5YZhmPWlm4oxUUH3F6EVqQU=
-github.com/nrdcg/vegadns v0.3.0/go.mod h1:NqSyRKZuJlAsv8VI/7rSubfPXN68NwaJ0aG9KxQVFVo=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@@ -737,16 +716,16 @@ github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
-github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0=
-github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
+github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo=
+github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
-github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
-github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
+github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
+github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
@@ -754,6 +733,8 @@ github.com/ovh/go-ovh v1.9.0 h1:6K8VoL3BYjVV3In9tPJUdT7qMx9h0GExN9EXx1r2kKE=
github.com/ovh/go-ovh v1.9.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
@@ -811,31 +792,33 @@ github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2 h1:dq90+d51/hQR
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
+github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/regfish/regfish-dnsapi-go v0.1.1 h1:TJFtbePHkd47q5GZwYl1h3DIYXmoxdLjW/SBsPtB5IE=
github.com/regfish/regfish-dnsapi-go v0.1.1/go.mod h1:ubIgXSfqarSnl3XHSn8hIFwFF3h0yrq0ZiWD93Y2VjY=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
-github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/sacloud/api-client-go v0.3.3 h1:ZpSAyGpITA8UFO3Hq4qMHZLGuNI1FgxAxo4sqBnCKDs=
-github.com/sacloud/api-client-go v0.3.3/go.mod h1:0p3ukcWYXRCc2AUWTl1aA+3sXLvurvvDqhRaLZRLBwo=
+github.com/sacloud/api-client-go v0.3.2 h1:INbdSpQbyGN9Ai4hQ+Gbv3UQcgtRPG2tJrOmqT7HGl0=
+github.com/sacloud/api-client-go v0.3.2/go.mod h1:0p3ukcWYXRCc2AUWTl1aA+3sXLvurvvDqhRaLZRLBwo=
github.com/sacloud/go-http v0.1.9 h1:Xa5PY8/pb7XWhwG9nAeXSrYXPbtfBWqawgzxD5co3VE=
github.com/sacloud/go-http v0.1.9/go.mod h1:DpDG+MSyxYaBwPJ7l3aKLMzwYdTVtC5Bo63HActcgoE=
-github.com/sacloud/iaas-api-go v1.23.1 h1:rjYG0vVoxWyETiwc7R8YdD7CIzs9vVNEOzu7w6dgGzc=
-github.com/sacloud/iaas-api-go v1.23.1/go.mod h1:EGIHOWRB9azOv7HPCVM8WpOEl28WIV9TNRbnEVg+Q3U=
-github.com/sacloud/packages-go v0.0.12 h1:MKeZNN3FQn1heqUSRBrbZw89YusZA1n4kammjMFZYvQ=
-github.com/sacloud/packages-go v0.0.12/go.mod h1:XNF5MCTWcHo9NiqWnYctVbASSSZR3ZOmmQORIzcurJ8=
+github.com/sacloud/iaas-api-go v1.16.1 h1:B5Lec9WyZkrOCjtGkVuPn5RxDm/zCzazVsHh7BQIjYQ=
+github.com/sacloud/iaas-api-go v1.16.1/go.mod h1:QVPHLwYzpECMsuml55I3FWAggsb4XSuzYGE9re/SkrQ=
+github.com/sacloud/packages-go v0.0.11 h1:hrRWLmfPM9w7GBs6xb5/ue6pEMl8t1UuDKyR/KfteHo=
+github.com/sacloud/packages-go v0.0.11/go.mod h1:XNF5MCTWcHo9NiqWnYctVbASSSZR3ZOmmQORIzcurJ8=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
-github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 h1:ObX9hZmK+VmijreZO/8x9pQ8/P/ToHD/bdSb4Eg4tUo=
-github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36/go.mod h1:LEsDu4BubxK7/cWhtlQWfuxwL4rf/2UEpxXz1o1EMtM=
+github.com/scaleway/scaleway-sdk-go v1.0.0-beta.34 h1:48+VFHsyVcAHIN2v1Ao9v1/RkjJS5AwctFucBrfYNIA=
+github.com/scaleway/scaleway-sdk-go v1.0.0-beta.34/go.mod h1:zFWiHphneiey3s8HOtAEnGrRlWivNaxW5T6d5Xfco7g=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/selectel/domains-go v1.1.0 h1:futG50J43ALLKQAnZk9H9yOtLGnSUh7c5hSvuC5gSHo=
github.com/selectel/domains-go v1.1.0/go.mod h1:SugRKfq4sTpnOHquslCpzda72wV8u0cMBHx0C0l+bzA=
@@ -851,10 +834,15 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 h1:hp2CYQUINdZMHdvTdXtPOY2ainKl4IoMcpAXEf2xj3Q=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/softlayer/softlayer-go v1.2.1 h1:8ucHxn5laVsVPb0/aMGnr6tOMt1I9BgEtU5mn70OGKw=
-github.com/softlayer/softlayer-go v1.2.1/go.mod h1:Gz9/ktcmB7Z8EJlu+QEJJpkv8lAmnhYdB9Tc6gedjmo=
+github.com/smartystreets/gunit v1.0.4 h1:tpTjnuH7MLlqhoD21vRoMZbMIi5GmBsAJDFyF67GhZA=
+github.com/smartystreets/gunit v1.0.4/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ=
+github.com/softlayer/softlayer-go v1.1.7 h1:SgTL+pQZt1h+5QkAhVmHORM/7N9c1X0sljJhuOIHxWE=
+github.com/softlayer/softlayer-go v1.1.7/go.mod h1:WeJrBLoTJcaT8nO1azeyHyNpo/fDLtbpbvh+pzts+Qw=
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e h1:3OgWYFw7jxCZPcvAg+4R8A50GZ+CCkARF10lxu2qDsQ=
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e/go.mod h1:fKZCUVdirrxrBpwd9wb+lSoVixvpwAu8eHzbQB2tums=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@@ -870,15 +858,14 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
-github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
-github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
@@ -900,50 +887,52 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
-github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.24/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.38/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.48 h1:bCs+z6dxRaHWm/C1D/XkSOcCZ0+W2+/6HmIXjpAj+fY=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.48/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1208/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1210 h1:waSk2KyI2VvXtR+XQJm0v1lWfgbJg51iSWJh4hWnyeo=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1210/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/transip/gotransip/v6 v6.26.1 h1:MeqIjkTBBsZwWAK6giZyMkqLmKMclVHEuTNmoBdx4MA=
-github.com/transip/gotransip/v6 v6.26.1/go.mod h1:x0/RWGRK/zob817O3tfO2xhFoP1vu8YOHORx6Jpk80s=
+github.com/transip/gotransip/v6 v6.26.0 h1:Aejfvh8rSp8Mj2GX/RpdBjMCv+Iy/DmgfNgczPDP550=
+github.com/transip/gotransip/v6 v6.26.0/go.mod h1:x0/RWGRK/zob817O3tfO2xhFoP1vu8YOHORx6Jpk80s=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
-github.com/ultradns/ultradns-go-sdk v1.8.1-20250722213956-faef419 h1:/VaznPrb/b68e3iMvkr27fU7JqPKU4j7tIITZnjQX1k=
-github.com/ultradns/ultradns-go-sdk v1.8.1-20250722213956-faef419/go.mod h1:QN0/PdenvYWB0GRMz6JJbPeZz2Lph2iys1p8AFVHm2c=
+github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec h1:2s/ghQ8wKE+UzD/hf3P4Gd1j0JI9ncbxv+nsypPoUYI=
+github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
-github.com/vinyldns/go-vinyldns v0.9.17 h1:hfPZfCaxcRBX6Gsgl42rLCeoal58/BH8kkvJShzjjdI=
-github.com/vinyldns/go-vinyldns v0.9.17/go.mod h1:pwWhE9K/leGDOIduVhRGvQ3ecVMHWRfEnKYUTEU3gB4=
-github.com/volcengine/volc-sdk-golang v1.0.237 h1:hpLKiS2BwDcSBtZWSz034foCbd0h3FrHTKlUMqHIdc4=
-github.com/volcengine/volc-sdk-golang v1.0.237/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
-github.com/vultr/govultr/v3 v3.27.0 h1:J8etMyu/Jh5+idMsu2YZpOWmDXXHeW4VZnkYXmJYHx8=
-github.com/vultr/govultr/v3 v3.27.0/go.mod h1:9WwnWGCKnwDlNjHjtt+j+nP+0QWq6hQXzaHgddqrLWY=
+github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
+github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
+github.com/volcengine/volc-sdk-golang v1.0.216 h1:+wAq8RvxpGECveRJaAXZFpzrZoQ33WjMuRyd9iY2Oc0=
+github.com/volcengine/volc-sdk-golang v1.0.216/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
+github.com/vultr/govultr/v3 v3.21.1 h1:0cnA8fXiqayPGbAlNHaW+5oCQjpDNkkAm3Nt3LOHplM=
+github.com/vultr/govultr/v3 v3.21.1/go.mod h1:9WwnWGCKnwDlNjHjtt+j+nP+0QWq6hQXzaHgddqrLWY=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
-github.com/yandex-cloud/go-genproto v0.54.0 h1:LjEwDPBAtF39HvcPQe8I+ImCnFasCPCOVh2b2Sr2eAg=
-github.com/yandex-cloud/go-genproto v0.54.0/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
-github.com/yandex-cloud/go-sdk/services/dns v0.0.36 h1:sD622+baDvJ2ujhCfoFsCH0XeNsaZNW6loRqvRavjtE=
-github.com/yandex-cloud/go-sdk/services/dns v0.0.36/go.mod h1:Hh7IKJxULaRzmyM19lQZw+yUDyMM8M3Qrk1LbWqhCkc=
-github.com/yandex-cloud/go-sdk/v2 v2.56.0 h1:rihPAZbPbHU/BKTLuT64nU1uhbBrO20HhdlLR3Hyoz0=
-github.com/yandex-cloud/go-sdk/v2 v2.56.0/go.mod h1:jzVBQgamNHoiDsmjog2dPZHMXuGZqmxf/epH+Qb7Emc=
+github.com/yandex-cloud/go-genproto v0.14.0 h1:yDqD260mICkjodXyAaDhESfrLr6gIGwwRc9MYE0jvW0=
+github.com/yandex-cloud/go-genproto v0.14.0/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
+github.com/yandex-cloud/go-sdk/services/dns v0.0.3 h1:erphTBXKSpm/tETa6FXrw4niSHjhySzAKHUc2/BZKx0=
+github.com/yandex-cloud/go-sdk/services/dns v0.0.3/go.mod h1:lbBaFJVouETfVnd3YzNF5vW6vgYR2FVfGLUzLexyGlI=
+github.com/yandex-cloud/go-sdk/v2 v2.0.8 h1:wQNIzEZYnClSQyo2fjEgnGEErWjJNBpSAinaKcP+VSg=
+github.com/yandex-cloud/go-sdk/v2 v2.0.8/go.mod h1:9Gqpq7d0EUAS+H2OunILtMi3hmMPav+fYoy9rmydM4s=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
@@ -967,22 +956,22 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
-go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
-go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
+go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
-go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
-go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
-go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
-go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
-go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
-go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
-go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
-go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
-go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
-go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
+go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
+go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
+go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
+go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
+go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
+go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
+go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
+go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
+go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
+go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -1035,8 +1024,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
-golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
-golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
+golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
+golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1080,8 +1069,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
+golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
+golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1139,16 +1128,17 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
-golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
-golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
+golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
+golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
-golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
+golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
+golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1165,8 +1155,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
+golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1233,11 +1223,9 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1252,8 +1240,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
-golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
+golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1268,8 +1256,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
-golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
-golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
+golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
+golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1288,16 +1276,16 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
-golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
-golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
+golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
+golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
-golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
+golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
+golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1355,18 +1343,14 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
-golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
+golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
+golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
-golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
-gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
-gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@@ -1385,8 +1369,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.267.0 h1:w+vfWPMPYeRs8qH1aYYsFX68jMls5acWl/jocfLomwE=
-google.golang.org/api v0.267.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0=
+google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg=
+google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1425,12 +1409,12 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM=
-google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM=
-google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M=
-google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 h1:Jr5R2J6F6qWyzINc+4AM8t5pfUz6beZpHp678GNrMbE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
+google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
+google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
+google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU=
+google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1448,8 +1432,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
-google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
+google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
+google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1464,8 +1448,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
-google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1476,15 +1460,17 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=
+gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k=
-gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/ns1/ns1-go.v2 v2.17.2 h1:x8YKHqCJWkC/hddfUhw7FRqTG0x3fr/0ZnWYN+i4THs=
-gopkg.in/ns1/ns1-go.v2 v2.17.2/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
+gopkg.in/ns1/ns1-go.v2 v2.14.4 h1:77eP71rZ24I+9k1gITgjJXRyJzzmflA9oPUkYPB/wyc=
+gopkg.in/ns1/ns1-go.v2 v2.14.4/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -1515,5 +1501,5 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-software.sslmate.com/src/go-pkcs12 v0.7.0 h1:Db8W44cB54TWD7stUFFSWxdfpdn6fZVcDl0w3R4RVM0=
-software.sslmate.com/src/go-pkcs12 v0.7.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
+software.sslmate.com/src/go-pkcs12 v0.5.0 h1:EC6R394xgENTpZ4RltKydeDUjtlM5drOYIG9c6TVj2M=
+software.sslmate.com/src/go-pkcs12 v0.5.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
diff --git a/internal/clihelp/generator.go b/internal/clihelp/generator.go
index fcabde015..2d256b4d7 100644
--- a/internal/clihelp/generator.go
+++ b/internal/clihelp/generator.go
@@ -50,7 +50,6 @@ func generate() error {
// collect output of various help pages
var help []commandHelp
-
for _, args := range [][]string{
{"lego", "help"},
{"lego", "help", "run"},
@@ -73,9 +72,7 @@ func generate() error {
}
err = outputTpl.Execute(f, help)
-
defer func() { _ = f.Close() }()
-
if err != nil {
return fmt.Errorf("failed to write cli_help.toml: %w", err)
}
@@ -101,11 +98,9 @@ func createStubApp() *cli.App {
func run(app *cli.App, args []string) (h commandHelp, err error) {
w := app.Writer
-
defer func() { app.Writer = w }()
var buf bytes.Buffer
-
app.Writer = &buf
if err := app.Run(args); err != nil {
diff --git a/internal/dns/docs/generator.go b/internal/dns/docs/generator.go
index 9355d0d1b..d618ce568 100644
--- a/internal/dns/docs/generator.go
+++ b/internal/dns/docs/generator.go
@@ -48,11 +48,6 @@ func main() {
log.Fatal(err)
}
- err = cleanDocumentation()
- if err != nil {
- log.Fatal(err)
- }
-
for _, m := range models.Providers {
// generate documentation
err = generateDocumentation(m)
@@ -76,22 +71,6 @@ func main() {
fmt.Printf("Documentation for %d DNS providers has been generated.\n", len(models.Providers)+1)
}
-func cleanDocumentation() error {
- paths, err := filepath.Glob(filepath.Join(docOutput, "zz_gen_*.md"))
- if err != nil {
- return err
- }
-
- for _, p := range paths {
- err = os.RemoveAll(p)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
func generateDocumentation(m descriptors.Provider) error {
filename := filepath.Join(docOutput, "zz_gen_"+m.Code+".md")
@@ -116,7 +95,6 @@ func generateCLIHelp(models *descriptors.Providers) error {
defer func() { _ = file.Close() }()
b := &bytes.Buffer{}
-
err = template.Must(
template.New(filepath.Base(cliTemplate)).Funcs(map[string]any{
"safe": func(src string) string {
@@ -135,7 +113,6 @@ func generateCLIHelp(models *descriptors.Providers) error {
}
_, err = file.Write(source)
-
return err
}
@@ -163,7 +140,6 @@ func generateReadMe(models *descriptors.Providers) error {
if err = tpl.Execute(buffer, providers); err != nil {
return err
}
-
skip = true
}
@@ -190,29 +166,31 @@ 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(models.Providers, func(a, b descriptors.Provider) int {
+ slices.SortFunc(providers, func(a, b descriptors.Provider) int {
return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name))
})
- var (
- matrix [][]descriptors.Provider
- row []descriptors.Provider
- )
+ var matrix [][]descriptors.Provider
+ var row []descriptors.Provider
- for i, p := range models.Providers {
+ for i, p := range providers {
switch {
case len(row) == nbCol:
matrix = append(matrix, row)
row = []descriptors.Provider{p}
- case i == len(models.Providers)-1:
+ case i == len(providers)-1:
row = append(row, p)
for j := len(row); j < nbCol; j++ {
row = append(row, descriptors.Provider{})
}
-
matrix = append(matrix, row)
default:
@@ -224,7 +202,6 @@ func orderProviders(models *descriptors.Providers) [][]descriptors.Provider {
for j := len(row); j < nbCol; j++ {
row = append(row, descriptors.Provider{})
}
-
matrix = append(matrix, row)
}
diff --git a/internal/dns/docs/templates/dns.go.tmpl b/internal/dns/docs/templates/dns.go.tmpl
index c1896c91a..e8b336254 100644
--- a/internal/dns/docs/templates/dns.go.tmpl
+++ b/internal/dns/docs/templates/dns.go.tmpl
@@ -12,6 +12,7 @@ import (
func allDNSCodes() string {
providers := []string{
+ "manual",
{{- range $provider := .Providers }}
"{{ $provider.Code }}",
{{- end}}
@@ -47,6 +48,8 @@ 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 c974ef6a9..2030a3ed0 100644
--- a/internal/dns/providers/dns_providers.go.tmpl
+++ b/internal/dns/providers/dns_providers.go.tmpl
@@ -6,6 +6,7 @@ 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}}
@@ -14,6 +15,8 @@ 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/internal/dns/providers/generator.go b/internal/dns/providers/generator.go
index df3f8a2e6..8f133a765 100644
--- a/internal/dns/providers/generator.go
+++ b/internal/dns/providers/generator.go
@@ -46,7 +46,6 @@ func generate() error {
defer func() { _ = file.Close() }()
b := &bytes.Buffer{}
-
err = template.Must(
template.New("").Funcs(map[string]any{
"cleanName": func(src string) string {
diff --git a/internal/releaser/releaser.go b/internal/releaser/releaser.go
index 57b463933..6047c427c 100644
--- a/internal/releaser/releaser.go
+++ b/internal/releaser/releaser.go
@@ -108,7 +108,6 @@ func detach(_ *cli.Context) error {
func readCurrentVersion(filename string) (*hcversion.Version, error) {
fset := token.NewFileSet()
-
file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
if err != nil {
return nil, err
@@ -142,7 +141,6 @@ func (v visitor) Visit(n ast.Node) ast.Visitor {
if !ok {
continue
}
-
if len(valueSpec.Names) != 1 || len(valueSpec.Values) != 1 {
continue
}
@@ -151,7 +149,6 @@ func (v visitor) Visit(n ast.Node) ast.Visitor {
if !ok {
continue
}
-
if va.Kind != token.STRING {
continue
}
@@ -167,7 +164,6 @@ func (v visitor) Visit(n ast.Node) ast.Visitor {
default:
// noop
}
-
return v
}
diff --git a/lego/client_test.go b/lego/client_test.go
index 63d3b0ad1..4f07eb1ea 100644
--- a/lego/client_test.go
+++ b/lego/client_test.go
@@ -13,7 +13,7 @@ import (
)
func TestNewClient(t *testing.T) {
- server := tester.MockACMEServer().BuildHTTPS(t)
+ _, apiURL := tester.SetupFakeAPI(t)
key, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
@@ -25,8 +25,7 @@ func TestNewClient(t *testing.T) {
}
config := NewConfig(user)
- config.CADirURL = server.URL + "/dir"
- config.HTTPClient = server.Client()
+ config.CADirURL = apiURL + "/dir"
client, err := NewClient(config)
require.NoError(t, err, "Could not create client")
diff --git a/platform/config/env/env.go b/platform/config/env/env.go
index 33a0d6caa..b74a65cd9 100644
--- a/platform/config/env/env.go
+++ b/platform/config/env/env.go
@@ -16,13 +16,11 @@ func Get(names ...string) (map[string]string, error) {
values := map[string]string{}
var missingEnvVars []string
-
for _, envVar := range names {
value := GetOrFile(envVar)
if value == "" {
missingEnvVars = append(missingEnvVars, envVar)
}
-
values[envVar] = value
}
@@ -60,7 +58,6 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
values := map[string]string{}
var missingEnvVars []string
-
for _, names := range groups {
if len(names) == 0 {
return nil, errors.New("undefined environment variable names")
@@ -71,7 +68,6 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
missingEnvVars = append(missingEnvVars, envVar)
continue
}
-
values[envVar] = value
}
@@ -152,7 +148,6 @@ func GetOrFile(envVar string) string {
}
fileVar := envVar + "_FILE"
-
fileVarValue := os.Getenv(fileVar)
if fileVarValue == "" {
return envVarValue
diff --git a/platform/tester/api.go b/platform/tester/api.go
index 8343b487f..2084cf1bb 100644
--- a/platform/tester/api.go
+++ b/platform/tester/api.go
@@ -2,36 +2,53 @@ package tester
import (
"encoding/json"
- "fmt"
"net/http"
"net/http/httptest"
+ "testing"
"github.com/go-acme/lego/v4/acme"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
)
-// MockACMEServer Minimal stub ACME server for validation.
-func MockACMEServer() *servermock.Builder[*httptest.Server] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*httptest.Server, error) {
- return server, nil
- }).
- Route("GET /dir", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- serverURL := fmt.Sprintf("https://%s", req.Context().Value(http.LocalAddrContextKey))
+// SetupFakeAPI Minimal stub ACME server for validation.
+func SetupFakeAPI(t *testing.T) (*http.ServeMux, string) {
+ t.Helper()
- servermock.JSONEncode(acme.Directory{
- NewNonceURL: serverURL + "/nonce",
- NewAccountURL: serverURL + "/account",
- NewOrderURL: serverURL + "/newOrder",
- RevokeCertURL: serverURL + "/revokeCert",
- KeyChangeURL: serverURL + "/keyChange",
- RenewalInfo: serverURL + "/renewalInfo",
- }).ServeHTTP(rw, req)
- })).
- Route("HEAD /nonce", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- rw.Header().Set("Replay-Nonce", "12345")
- rw.Header().Set("Retry-After", "0")
- }))
+ mux := http.NewServeMux()
+ server := httptest.NewServer(mux)
+ t.Cleanup(server.Close)
+
+ mux.HandleFunc("/dir", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
+ return
+ }
+
+ err := WriteJSONResponse(w, acme.Directory{
+ NewNonceURL: server.URL + "/nonce",
+ NewAccountURL: server.URL + "/account",
+ NewOrderURL: server.URL + "/newOrder",
+ RevokeCertURL: server.URL + "/revokeCert",
+ KeyChangeURL: server.URL + "/keyChange",
+ RenewalInfo: server.URL + "/renewalInfo",
+ })
+
+ mux.HandleFunc("/nonce", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodHead {
+ http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
+ return
+ }
+
+ w.Header().Set("Replay-Nonce", "12345")
+ w.Header().Set("Retry-After", "0")
+ })
+
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
+
+ return mux, server.URL
}
// WriteJSONResponse marshals the body as JSON and writes it to the response.
@@ -42,7 +59,6 @@ func WriteJSONResponse(w http.ResponseWriter, body any) error {
}
w.Header().Set("Content-Type", "application/json")
-
if _, err := w.Write(bs); err != nil {
return err
}
diff --git a/platform/tester/dnsmock/dnsmock.go b/platform/tester/dnsmock/dnsmock.go
deleted file mode 100644
index 6cb4f45b8..000000000
--- a/platform/tester/dnsmock/dnsmock.go
+++ /dev/null
@@ -1,191 +0,0 @@
-package dnsmock
-
-import (
- "fmt"
- "math"
- "net"
- "strings"
- "sync"
- "testing"
- "time"
-
- "github.com/miekg/dns"
- "github.com/stretchr/testify/require"
-)
-
-const noType uint16 = math.MaxUint16
-
-type Option func(*dns.Server) error
-
-type Builder struct {
- // domain -> op -> type
- routes map[string]map[int]map[uint16]dns.Handler
-
- stringToType map[string]uint16
-}
-
-func NewServer() *Builder {
- stringToType := make(map[string]uint16)
- for typ, str := range dns.TypeToString {
- stringToType[str] = typ
- }
-
- return &Builder{
- routes: make(map[string]map[int]map[uint16]dns.Handler),
- stringToType: stringToType,
- }
-}
-
-func (b *Builder) Query(pattern string, handler dns.HandlerFunc) *Builder {
- route, err := b.route(pattern, dns.OpcodeQuery, handler)
- if err != nil {
- panic(err.Error())
- }
-
- return route
-}
-
-func (b *Builder) Update(pattern string, handler dns.HandlerFunc) *Builder {
- route, err := b.route(pattern, dns.OpcodeUpdate, handler)
- if err != nil {
- panic(err.Error())
- }
-
- return route
-}
-
-func (b *Builder) route(pattern string, op int, handler dns.HandlerFunc) (*Builder, error) {
- parts := strings.Fields(pattern)
-
- domain := parts[0]
-
- _, ok := dns.IsDomainName(domain)
- if !ok {
- return nil, fmt.Errorf("%s: invalid domain: %s", dns.OpcodeToString[op], domain)
- }
-
- if _, ok := b.routes[domain]; !ok {
- b.routes[domain] = make(map[int]map[uint16]dns.Handler)
- }
-
- if _, ok := b.routes[domain][op]; !ok {
- b.routes[domain][op] = make(map[uint16]dns.Handler)
- }
-
- if _, ok := b.routes[domain][op][noType]; ok {
- return nil, fmt.Errorf("%s: a global route already exists for the domain: %s", dns.OpcodeToString[op], domain)
- }
-
- switch len(parts) {
- case 1:
- if len(b.routes[domain][op]) > 0 {
- return nil, fmt.Errorf("%s: global route and specific routes cannot be mixed for the same domain: %s", dns.OpcodeToString[op], domain)
- }
-
- b.routes[domain][op][noType] = handler
-
- return b, nil
-
- case 2:
- raw := parts[1]
-
- qType, ok := b.stringToType[raw]
- if !ok {
- return nil, fmt.Errorf("%s: unknown type: %s", dns.OpcodeToString[op], raw)
- }
-
- if _, ok := b.routes[domain][op][qType]; ok {
- return nil, fmt.Errorf("%s: duplicate route: %s", dns.OpcodeToString[op], pattern)
- }
-
- b.routes[domain][op][qType] = handler
-
- return b, nil
-
- default:
- return nil, fmt.Errorf("%s: invalid pattern: %s", dns.OpcodeToString[op], pattern)
- }
-}
-
-func (b *Builder) Build(t *testing.T, options ...Option) net.Addr {
- t.Helper()
-
- mux := dns.NewServeMux()
-
- server := &dns.Server{
- Addr: "127.0.0.1:0",
- Net: "udp",
- ReadTimeout: time.Hour,
- WriteTimeout: time.Hour,
- Handler: mux,
- MsgAcceptFunc: func(dh dns.Header) dns.MsgAcceptAction {
- // bypass defaultMsgAcceptFunc to allow dynamic update (https://github.com/miekg/dns/pull/830)
- return dns.MsgAccept
- },
- }
-
- for _, option := range options {
- require.NoError(t, option(server))
- }
-
- for pattern, ops := range b.routes {
- mux.HandleFunc(pattern, func(w dns.ResponseWriter, req *dns.Msg) {
- mTypes, ok := ops[req.Opcode]
- if !ok {
- _ = w.WriteMsg(new(dns.Msg).SetRcode(req, dns.RcodeNotImplemented))
-
- return
- }
-
- if h, found := mTypes[noType]; found {
- h.ServeDNS(w, req)
-
- return
- }
-
- // For safety but it doesn't happen.
- if len(req.Question) == 0 {
- _ = w.WriteMsg(new(dns.Msg).SetRcode(req, dns.RcodeRefused))
-
- return
- }
-
- // For safety but it doesn't happen.
- if req.Question[0].Qclass != dns.ClassINET {
- _ = w.WriteMsg(new(dns.Msg).SetRcode(req, dns.RcodeRefused))
-
- return
- }
-
- // Works only for [Query].
- h, ok := mTypes[req.Question[0].Qtype]
- if !ok {
- _ = w.WriteMsg(new(dns.Msg).SetRcode(req, dns.RcodeNotImplemented))
-
- return
- }
-
- h.ServeDNS(w, req)
- })
- }
-
- t.Cleanup(func() {
- _ = server.Shutdown()
- })
-
- waitLock := sync.Mutex{}
- waitLock.Lock()
-
- server.NotifyStartedFunc = waitLock.Unlock
-
- go func() {
- err := server.ListenAndServe()
- if err != nil {
- t.Log(err)
- }
- }()
-
- waitLock.Lock()
-
- return server.PacketConn.LocalAddr()
-}
diff --git a/platform/tester/dnsmock/dnsmock_test.go b/platform/tester/dnsmock/dnsmock_test.go
deleted file mode 100644
index 77a67a402..000000000
--- a/platform/tester/dnsmock/dnsmock_test.go
+++ /dev/null
@@ -1,240 +0,0 @@
-package dnsmock
-
-import (
- "testing"
- "time"
-
- "github.com/miekg/dns"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestServer_Query_matchType(t *testing.T) {
- addr := NewServer().
- Query("example.com. SOA", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeSOA)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeSuccess, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeSuccess], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestServer_Query_noType(t *testing.T) {
- addr := NewServer().
- Query("example.com.", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeSOA)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeSuccess, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeSuccess], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestServer_Query_noMatch_domain(t *testing.T) {
- addr := NewServer().
- Query("example.com. SOA", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.org.", dns.TypeSOA)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeRefused, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeRefused], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestServer_Query_noMatch_type(t *testing.T) {
- addr := NewServer().
- Query("example.com. SOA", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeTXT)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeNotImplemented, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeNotImplemented], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestServer_Query_noMatch_opType(t *testing.T) {
- addr := NewServer().
- Query("example.com.", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetUpdate("example.com.")
- m.Insert([]dns.RR{
- &dns.TXT{
- Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 1},
- Txt: []string{"foo"},
- },
- })
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeNotImplemented, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeNotImplemented], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestServer_Query_unknownType(t *testing.T) {
- assert.PanicsWithValue(t, "QUERY: unknown type: ABC", func() {
- NewServer().
- Query("example.com. ABC", Noop).
- Build(t)
- })
-}
-
-func TestServer_Query_duplicate(t *testing.T) {
- assert.PanicsWithValue(t, "QUERY: duplicate route: example.com. SOA", func() {
- NewServer().
- Query("example.com. SOA", Noop).
- Query("example.com. SOA", Noop).
- Build(t)
- })
-}
-
-func TestServer_Query_duplicateGlobal(t *testing.T) {
- assert.PanicsWithValue(t, "QUERY: a global route already exists for the domain: example.com.", func() {
- NewServer().
- Query("example.com.", Noop).
- Query("example.com.", Noop).
- Build(t)
- })
-}
-
-func TestServer_Query_mixed(t *testing.T) {
- assert.PanicsWithValue(t, "QUERY: global route and specific routes cannot be mixed for the same domain: example.com.", func() {
- NewServer().
- Query("example.com. SOA", Noop).
- Query("example.com.", Noop).
- Build(t)
- })
-}
-
-func TestServer_Query_invalidDomain(t *testing.T) {
- assert.PanicsWithValue(t, "QUERY: invalid domain: .example.com.", func() {
- NewServer().
- Query(".example.com. SOA", Noop).
- Build(t)
- })
-}
-
-func TestServer_Query_invalidPattern(t *testing.T) {
- assert.PanicsWithValue(t, "QUERY: invalid pattern: example.com. SOA 13", func() {
- NewServer().
- Query("example.com. SOA 13", Noop).
- Build(t)
- })
-}
-
-func TestServer_Update(t *testing.T) {
- addr := NewServer().
- Update("example.com.", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetUpdate("example.com.")
- m.Insert([]dns.RR{
- &dns.TXT{
- Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 1},
- Txt: []string{"foo"},
- },
- })
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeSuccess, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeSuccess], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestServer_Update_noMatch_domain(t *testing.T) {
- addr := NewServer().
- Update("example.com.", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetUpdate("example.org.")
- m.Insert([]dns.RR{
- &dns.TXT{
- Hdr: dns.RR_Header{Name: "example.org.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 1},
- Txt: []string{"foo"},
- },
- })
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeRefused, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeRefused], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestServer_Update_noMatch_opType(t *testing.T) {
- addr := NewServer().
- Update("example.com.", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeTXT)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeNotImplemented, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeNotImplemented], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestServer_Update_duplicate(t *testing.T) {
- assert.PanicsWithValue(t, "UPDATE: a global route already exists for the domain: example.com.", func() {
- NewServer().
- Update("example.com.", Noop).
- Update("example.com.", Noop).
- Build(t)
- })
-}
-
-func TestServer_Update_invalidDomain(t *testing.T) {
- assert.PanicsWithValue(t, "UPDATE: invalid domain: .example.com.", func() {
- NewServer().
- Update(".example.com.", Noop).
- Build(t)
- })
-}
-
-func TestServer_Update_invalidPattern(t *testing.T) {
- assert.PanicsWithValue(t, "UPDATE: invalid pattern: example.com. SOA 13", func() {
- NewServer().
- Update("example.com. SOA 13", Noop).
- Build(t)
- })
-}
diff --git a/platform/tester/dnsmock/handlers.go b/platform/tester/dnsmock/handlers.go
deleted file mode 100644
index e1b047318..000000000
--- a/platform/tester/dnsmock/handlers.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package dnsmock
-
-import (
- "fmt"
-
- "github.com/miekg/dns"
-)
-
-func DumpRequest() dns.HandlerFunc {
- return func(w dns.ResponseWriter, req *dns.Msg) {
- fmt.Println(req)
-
- Noop(w, req)
- }
-}
-
-func SOA(name string) dns.HandlerFunc {
- return func(w dns.ResponseWriter, req *dns.Msg) {
- if name == "" {
- name = req.Question[0].Name
- }
-
- // Handle TLD
- base := name
- if dns.CountLabel(req.Question[0].Name) == 1 {
- base = "nic." + req.Question[0].Name
- }
-
- answer := &dns.SOA{
- Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 120},
- Ns: "ns1." + base,
- Mbox: "admin." + base,
- Serial: 2016022801,
- Refresh: 28800,
- Retry: 7200,
- Expire: 2419200,
- Minttl: 1200,
- }
-
- Answer(answer)(w, req)
- }
-}
-
-func CNAME(target string) dns.HandlerFunc {
- return func(w dns.ResponseWriter, req *dns.Msg) {
- answer := &dns.CNAME{
- Hdr: dns.RR_Header{Name: req.Question[0].Name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 1},
- Target: dns.Fqdn(target),
- }
-
- Answer(answer)(w, req)
- }
-}
-
-func Noop(w dns.ResponseWriter, req *dns.Msg) {
- _ = w.WriteMsg(new(dns.Msg).SetReply(req))
-}
-
-func Error(rcode int) dns.HandlerFunc {
- return func(w dns.ResponseWriter, req *dns.Msg) {
- _ = w.WriteMsg(new(dns.Msg).SetRcode(req, rcode))
- }
-}
-
-func Answer(answer ...dns.RR) func(w dns.ResponseWriter, req *dns.Msg) {
- return func(w dns.ResponseWriter, req *dns.Msg) {
- m := new(dns.Msg).SetReply(req)
-
- m.Answer = answer
-
- err := w.WriteMsg(m)
- if err != nil {
- panic(err.Error())
- }
- }
-}
diff --git a/platform/tester/dnsmock/handlers_test.go b/platform/tester/dnsmock/handlers_test.go
deleted file mode 100644
index 13cdc0e2d..000000000
--- a/platform/tester/dnsmock/handlers_test.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package dnsmock
-
-import (
- "testing"
- "time"
-
- "github.com/miekg/dns"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestSOA_self(t *testing.T) {
- addr := NewServer().
- Query("example.com. SOA", SOA("")).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeSOA)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- expectedSOA := []dns.RR{&dns.SOA{
- Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 120, Rdlength: 56},
- Ns: "ns1.example.com.",
- Mbox: "admin.example.com.",
- Serial: 2016022801,
- Refresh: 28800,
- Retry: 7200,
- Expire: 2419200,
- Minttl: 1200,
- }}
-
- require.Equal(t, dns.RcodeSuccess, r.Rcode)
- assert.Equal(t, expectedSOA, r.Answer)
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestSOA_differentDomain(t *testing.T) {
- addr := NewServer().
- Query("example.com. SOA", SOA("example.org.")).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeSOA)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeSuccess, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeSuccess], dns.RcodeToString[r.Rcode])
-
- expectedSOA := []dns.RR{&dns.SOA{
- Hdr: dns.RR_Header{Name: "example.org.", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 120, Rdlength: 56},
- Ns: "ns1.example.org.",
- Mbox: "admin.example.org.",
- Serial: 2016022801,
- Refresh: 28800,
- Retry: 7200,
- Expire: 2419200,
- Minttl: 1200,
- }}
-
- assert.Equal(t, expectedSOA, r.Answer)
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestSOA_tld(t *testing.T) {
- addr := NewServer().
- Query("com. SOA", SOA("")).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("com.", dns.TypeSOA)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeSuccess, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeSuccess], dns.RcodeToString[r.Rcode])
-
- expectedSOA := []dns.RR{&dns.SOA{
- Hdr: dns.RR_Header{Name: "com.", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 120, Rdlength: 48},
- Ns: "ns1.nic.com.",
- Mbox: "admin.nic.com.",
- Serial: 2016022801,
- Refresh: 28800,
- Retry: 7200,
- Expire: 2419200,
- Minttl: 1200,
- }}
-
- assert.Equal(t, expectedSOA, r.Answer)
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestCNAME(t *testing.T) {
- addr := NewServer().
- Query("example.com. CNAME", CNAME("example.org.")).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeCNAME)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeSuccess, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeSuccess], dns.RcodeToString[r.Rcode])
-
- expectedCNAME := []dns.RR{&dns.CNAME{
- Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 1, Rdlength: 13},
- Target: "example.org.",
- }}
-
- assert.Equal(t, expectedCNAME, r.Answer)
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestNoop(t *testing.T) {
- addr := NewServer().
- Query("example.com. CNAME", Noop).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeCNAME)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeSuccess, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeSuccess], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
-
-func TestError(t *testing.T) {
- addr := NewServer().
- Query("example.com. CNAME", Error(dns.RcodeNameError)).
- Build(t)
-
- client := &dns.Client{Timeout: 1 * time.Second}
-
- m := new(dns.Msg).SetQuestion("example.com.", dns.TypeCNAME)
-
- r, _, err := client.Exchange(m, addr.String())
- require.NoError(t, err)
-
- require.Equalf(t, dns.RcodeNameError, r.Rcode,
- "expected %s, got %s", dns.RcodeToString[dns.RcodeNameError], dns.RcodeToString[r.Rcode])
- assert.Equal(t, m.Question, r.Question)
-}
diff --git a/platform/tester/env.go b/platform/tester/env.go
index a12c32ef8..26788be3b 100644
--- a/platform/tester/env.go
+++ b/platform/tester/env.go
@@ -21,7 +21,6 @@ type EnvTest struct {
// NewEnvTest Creates an EnvTest.
func NewEnvTest(keys ...string) *EnvTest {
values := make(map[string]string)
-
for _, key := range keys {
value := os.Getenv(key)
if value != "" {
@@ -40,7 +39,6 @@ func NewEnvTest(keys ...string) *EnvTest {
func (e *EnvTest) WithDomain(key string) *EnvTest {
e.domainKey = key
e.domain = os.Getenv(key)
-
return e
}
diff --git a/platform/tester/env_test.go b/platform/tester/env_test.go
index 4d9e4e7d1..d5084056f 100644
--- a/platform/tester/env_test.go
+++ b/platform/tester/env_test.go
@@ -18,7 +18,6 @@ const (
func TestMain(m *testing.M) {
exitCode := m.Run()
-
clearEnv()
os.Exit(exitCode)
}
@@ -40,7 +39,6 @@ func clearEnv() {
os.Unsetenv(strings.Split(key, "=")[0])
}
}
-
os.Unsetenv("EXTRA_LEGO_TEST")
}
@@ -327,7 +325,6 @@ func TestEnvTest(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer clearEnv()
-
applyEnv(test.envVars)
envTest := test.envTestSetup()
diff --git a/platform/tester/servermock/builder.go b/platform/tester/servermock/builder.go
index b5a9d909b..e3b41e5c3 100644
--- a/platform/tester/servermock/builder.go
+++ b/platform/tester/servermock/builder.go
@@ -70,15 +70,3 @@ func (b *Builder[T]) Build(t *testing.T) T {
return client
}
-
-func (b *Builder[T]) BuildHTTPS(t *testing.T) T {
- t.Helper()
-
- server := httptest.NewTLSServer(b.mux)
- t.Cleanup(server.Close)
-
- client, err := b.clientBuilder(server)
- require.NoError(t, err)
-
- return client
-}
diff --git a/platform/tester/servermock/link_form.go b/platform/tester/servermock/link_form.go
index 581e27d66..e7541cefa 100644
--- a/platform/tester/servermock/link_form.go
+++ b/platform/tester/servermock/link_form.go
@@ -43,7 +43,6 @@ func (l *FormLink) Bind(next http.Handler) http.Handler {
if len(form) != len(l.values)+len(l.regexes) {
msg := fmt.Sprintf("invalid query parameters, got %v, want %v", req.Form, l.values)
http.Error(rw, msg, l.statusCode)
-
return
}
}
@@ -53,7 +52,6 @@ func (l *FormLink) Bind(next http.Handler) http.Handler {
if !slices.Equal(v, value) {
msg := fmt.Sprintf("invalid %q form value, got %q, want %q", k, value, v)
http.Error(rw, msg, l.statusCode)
-
return
}
}
@@ -63,7 +61,6 @@ func (l *FormLink) Bind(next http.Handler) http.Handler {
if !exp.MatchString(value) {
msg := fmt.Sprintf("invalid %q form value, %q doesn't match to %q", k, value, exp)
http.Error(rw, msg, l.statusCode)
-
return
}
}
diff --git a/platform/tester/servermock/link_headers.go b/platform/tester/servermock/link_headers.go
index 0ca519958..821c737fe 100644
--- a/platform/tester/servermock/link_headers.go
+++ b/platform/tester/servermock/link_headers.go
@@ -55,7 +55,6 @@ func (l *HeaderLink) Bind(next http.Handler) http.Handler {
if !exp.MatchString(value) {
msg := fmt.Sprintf("invalid %q header value, %q doesn't match to %q", k, value, exp)
http.Error(rw, msg, l.statusCode)
-
return
}
}
diff --git a/platform/tester/servermock/link_query.go b/platform/tester/servermock/link_query.go
index 14f776515..00d7450ae 100644
--- a/platform/tester/servermock/link_query.go
+++ b/platform/tester/servermock/link_query.go
@@ -32,7 +32,6 @@ func (l *QueryParameterLink) Bind(next http.Handler) http.Handler {
if len(query) != len(l.values)+len(l.regexes) {
msg := fmt.Sprintf("invalid query parameters, got %v, want %v", query, l.values)
http.Error(rw, msg, l.statusCode)
-
return
}
}
@@ -42,7 +41,6 @@ func (l *QueryParameterLink) Bind(next http.Handler) http.Handler {
if p != v {
msg := fmt.Sprintf("invalid %q query parameter value, got %q, want %q", k, p, v)
http.Error(rw, msg, l.statusCode)
-
return
}
}
@@ -52,7 +50,6 @@ func (l *QueryParameterLink) Bind(next http.Handler) http.Handler {
if !exp.MatchString(value) {
msg := fmt.Sprintf("invalid %q query parameter value, %q doesn't match to %q", k, value, exp)
http.Error(rw, msg, l.statusCode)
-
return
}
}
diff --git a/platform/tester/servermock/link_request_body.go b/platform/tester/servermock/link_request_body.go
index d6b2d9efd..b58c3cc79 100644
--- a/platform/tester/servermock/link_request_body.go
+++ b/platform/tester/servermock/link_request_body.go
@@ -76,7 +76,6 @@ func (l *RequestBodyLink) Bind(next http.Handler) http.Handler {
msg := fmt.Sprintf("%s: request body differences: got: %s, want: %s", req.URL.Path,
string(bytes.TrimSpace(body)), string(bytes.TrimSpace(expectedRaw)))
http.Error(rw, msg, http.StatusBadRequest)
-
return
}
diff --git a/platform/tester/servermock/link_request_body_json.go b/platform/tester/servermock/link_request_body_json.go
index ed5a117ba..3dc2f0cfa 100644
--- a/platform/tester/servermock/link_request_body_json.go
+++ b/platform/tester/servermock/link_request_body_json.go
@@ -90,7 +90,6 @@ func (l *RequestBodyJSONLink) Bind(next http.Handler) http.Handler {
if err != nil {
msg := fmt.Sprintf("%s: the expected request body is not valid JSON: %v", req.URL.Path, err)
http.Error(rw, msg, http.StatusBadRequest)
-
return
}
@@ -98,14 +97,12 @@ func (l *RequestBodyJSONLink) Bind(next http.Handler) http.Handler {
if err != nil {
msg := fmt.Sprintf("%s: request body is not valid JSON: %v", req.URL.Path, err)
http.Error(rw, msg, http.StatusBadRequest)
-
return
}
if !cmp.Equal(actual, expected) {
msg := fmt.Sprintf("%s: request body differences: %s", req.URL.Path, cmp.Diff(actual, expected))
http.Error(rw, msg, http.StatusBadRequest)
-
return
}
diff --git a/platform/wait/wait.go b/platform/wait/wait.go
index c66f57446..6ad817b26 100644
--- a/platform/wait/wait.go
+++ b/platform/wait/wait.go
@@ -1,11 +1,9 @@
package wait
import (
- "context"
"fmt"
"time"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/log"
)
@@ -14,25 +12,21 @@ func For(msg string, timeout, interval time.Duration, f func() (bool, error)) er
log.Infof("Wait for %s [timeout: %s, interval: %s]", msg, timeout, interval)
var lastErr error
-
timeUp := time.After(timeout)
-
for {
select {
case <-timeUp:
if lastErr == nil {
return fmt.Errorf("%s: time limit exceeded", msg)
}
-
return fmt.Errorf("%s: time limit exceeded: last error: %w", msg, lastErr)
default:
}
stop, err := f()
if stop {
- return err
+ return nil
}
-
if err != nil {
lastErr = err
}
@@ -40,13 +34,3 @@ func For(msg string, timeout, interval time.Duration, f func() (bool, error)) er
time.Sleep(interval)
}
}
-
-// Retry retries the given operation until it succeeds or the context is canceled.
-// Similar to [backoff.Retry] but with a different signature.
-func Retry(ctx context.Context, operation func() error, opts ...backoff.RetryOption) error {
- _, err := backoff.Retry(ctx, func() (any, error) {
- return nil, operation()
- }, opts...)
-
- return err
-}
diff --git a/platform/wait/wait_test.go b/platform/wait/wait_test.go
index 36dbffe69..9722e6f2e 100644
--- a/platform/wait/wait_test.go
+++ b/platform/wait/wait_test.go
@@ -1,121 +1,26 @@
package wait
import (
- "errors"
- "sync/atomic"
"testing"
"time"
-
- "github.com/stretchr/testify/require"
)
-// TODO(ldez): rewrite those tests when upgrading to go1.25 as minimum Go version.
-
-func TestFor_timeout(t *testing.T) {
- var io atomic.Int64
-
+func TestForTimeout(t *testing.T) {
c := make(chan error)
-
go func() {
- c <- For("test", 3*time.Second, 1*time.Second, func() (bool, error) {
- io.Add(1)
-
- if io.Load() == 1 {
- return false, nil
- }
-
+ c <- For("", 3*time.Second, 1*time.Second, func() (bool, error) {
return false, nil
})
}()
timeout := time.After(6 * time.Second)
-
select {
case <-timeout:
t.Fatal("timeout exceeded")
case err := <-c:
- require.EqualError(t, err, "test: time limit exceeded")
+ if err == nil {
+ t.Errorf("expected timeout error; got %v", err)
+ }
+ t.Logf("%v", err)
}
-
- require.EqualValues(t, 3, io.Load())
-}
-
-func TestFor_timeout_with_error(t *testing.T) {
- var io atomic.Int64
-
- c := make(chan error)
-
- go func() {
- c <- For("test", 3*time.Second, 1*time.Second, func() (bool, error) {
- io.Add(1)
-
- // This allows be sure that the latest previous error is returned.
- if io.Load() == 1 {
- return false, errors.New("oops")
- }
-
- return false, nil
- })
- }()
-
- timeout := time.After(6 * time.Second)
-
- select {
- case <-timeout:
- t.Fatal("timeout exceeded")
- case err := <-c:
- require.EqualError(t, err, "test: time limit exceeded: last error: oops")
- }
-
- require.EqualValues(t, 3, io.Load())
-}
-
-func TestFor_stop(t *testing.T) {
- var io atomic.Int64
-
- c := make(chan error)
-
- go func() {
- c <- For("test", 3*time.Second, 1*time.Second, func() (bool, error) {
- io.Add(1)
-
- return true, nil
- })
- }()
-
- timeout := time.After(6 * time.Second)
-
- select {
- case <-timeout:
- t.Fatal("timeout exceeded")
- case err := <-c:
- require.NoError(t, err)
- }
-
- require.EqualValues(t, 1, io.Load())
-}
-
-func TestFor_stop_with_error(t *testing.T) {
- var io atomic.Int64
-
- c := make(chan error)
-
- go func() {
- c <- For("test", 3*time.Second, 1*time.Second, func() (bool, error) {
- io.Add(1)
-
- return true, errors.New("oops")
- })
- }()
-
- timeout := time.After(6 * time.Second)
-
- select {
- case <-timeout:
- t.Fatal("timeout exceeded")
- case err := <-c:
- require.EqualError(t, err, "oops")
- }
-
- require.EqualValues(t, 1, io.Load())
}
diff --git a/providers/dns/acmedns/acmedns.go b/providers/dns/acmedns/acmedns.go
index 8f1f16842..9663a656b 100644
--- a/providers/dns/acmedns/acmedns.go
+++ b/providers/dns/acmedns/acmedns.go
@@ -114,7 +114,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}
// NewDNSProviderClient creates an ACME-DNS DNSProvider with the given acmeDNSClient and [goacmedns.Storage].
-//
// Deprecated: use [NewDNSProviderConfig] instead.
func NewDNSProviderClient(client acmeDNSClient, store goacmedns.Storage) (*DNSProvider, error) {
if client == nil {
diff --git a/providers/dns/acmedns/acmedns.toml b/providers/dns/acmedns/acmedns.toml
index e491569b0..6d68a013d 100644
--- a/providers/dns/acmedns/acmedns.toml
+++ b/providers/dns/acmedns/acmedns.toml
@@ -8,13 +8,13 @@ Since = "v1.1.0"
Example = '''
ACME_DNS_API_BASE=http://10.0.0.8:4443 \
ACME_DNS_STORAGE_PATH=/root/.lego-acme-dns-accounts.json \
-lego --dns "acme-dns" -d '*.example.com' -d example.com run
+lego --email you@example.com --dns "acme-dns" -d '*.example.com' -d example.com run
# or
ACME_DNS_API_BASE=http://10.0.0.8:4443 \
ACME_DNS_STORAGE_BASE_URL=http://10.10.10.10:80 \
-lego --dns "acme-dns" -d '*.example.com' -d example.com run
+lego --email you@example.com --dns "acme-dns" -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/acmedns/acmedns_test.go b/providers/dns/acmedns/acmedns_test.go
index a3ab59d59..e50c89d56 100644
--- a/providers/dns/acmedns/acmedns_test.go
+++ b/providers/dns/acmedns/acmedns_test.go
@@ -167,11 +167,11 @@ func TestPresent_httpStorage(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
- provider := servermock.NewBuilder(func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.StorageBaseURL = server.URL
+ config := servermock.NewBuilder(func(server *httptest.Server) (*Config, error) {
+ cfg := NewDefaultConfig()
+ cfg.StorageBaseURL = server.URL
- return NewDNSProviderConfig(config)
+ return cfg, nil
}).
// Fetch
Route("GET /example.com", servermock.Noop().WithStatusCode(http.StatusNotFound)).
@@ -179,12 +179,15 @@ func TestPresent_httpStorage(t *testing.T) {
Route("POST /example.com", servermock.Noop().WithStatusCode(test.StatusCode)).
Build(t)
- client := newMockClient().WithRegisterAccount(egTestAccount)
- provider.client = client
+ p, err := NewDNSProviderConfig(config)
+ require.NoError(t, err)
- err := provider.Present(egDomain, "foo", egKeyAuth)
+ client := newMockClient().WithRegisterAccount(egTestAccount)
+ p.client = client
+
+ err = p.Present(egDomain, "foo", egKeyAuth)
if test.ExpectedError != nil {
- assert.EqualError(t, err, test.ExpectedError.Error())
+ assert.Equal(t, test.ExpectedError, err)
assert.True(t, client.registerAccountCalled)
assert.False(t, client.updateTXTRecordCalled)
} else {
@@ -219,19 +222,22 @@ func TestRegister_httpStorage(t *testing.T) {
for _, test := range testCases {
t.Run(test.Name, func(t *testing.T) {
- provider := servermock.NewBuilder(func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.StorageBaseURL = server.URL
+ config := servermock.NewBuilder(func(server *httptest.Server) (*Config, error) {
+ cfg := NewDefaultConfig()
+ cfg.StorageBaseURL = server.URL
- return NewDNSProviderConfig(config)
+ return cfg, nil
}).
// Put
Route("POST /example.com", servermock.Noop().WithStatusCode(test.StatusCode)).
Build(t)
- provider.client = newMockClient().WithRegisterAccount(egTestAccount)
+ p, err := NewDNSProviderConfig(config)
+ require.NoError(t, err)
- acc, err := provider.register(t.Context(), egDomain, egFQDN)
+ p.client = newMockClient().WithRegisterAccount(egTestAccount)
+
+ acc, err := p.register(t.Context(), egDomain, egFQDN)
if test.ExpectedError != nil {
assert.Equal(t, test.ExpectedError, err)
} else {
diff --git a/providers/dns/acmedns/internal/fixtures/fetch_all.json b/providers/dns/acmedns/internal/fixtures/fetch-all.json
similarity index 100%
rename from providers/dns/acmedns/internal/fixtures/fetch_all.json
rename to providers/dns/acmedns/internal/fixtures/fetch-all.json
diff --git a/providers/dns/acmedns/internal/fixtures/fetch-request.json b/providers/dns/acmedns/internal/fixtures/request-body.json
similarity index 100%
rename from providers/dns/acmedns/internal/fixtures/fetch-request.json
rename to providers/dns/acmedns/internal/fixtures/request-body.json
diff --git a/providers/dns/acmedns/internal/http_storage_test.go b/providers/dns/acmedns/internal/http_storage_test.go
index 5c166b47f..abc3c0cde 100644
--- a/providers/dns/acmedns/internal/http_storage_test.go
+++ b/providers/dns/acmedns/internal/http_storage_test.go
@@ -58,7 +58,7 @@ func TestHTTPStorage_Fetch_error(t *testing.T) {
func TestHTTPStorage_FetchAll(t *testing.T) {
storage := mockBuilder().
- Route("GET /", servermock.ResponseFromFixture("fetch_all.json")).
+ Route("GET /", servermock.ResponseFromFixture("fetch-all.json")).
Build(t)
account, err := storage.FetchAll(t.Context())
@@ -98,7 +98,7 @@ func TestHTTPStorage_FetchAll_error(t *testing.T) {
func TestHTTPStorage_Put(t *testing.T) {
storage := mockBuilder().
Route("POST /example.com", nil,
- servermock.CheckRequestJSONBodyFromFixture("fetch-request.json")).
+ servermock.CheckRequestJSONBodyFromFixture("request-body.json")).
Build(t)
account := goacmedns.Account{
@@ -137,7 +137,7 @@ func TestHTTPStorage_Put_CNAME_created(t *testing.T) {
Route("POST /example.com",
servermock.Noop().
WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBodyFromFixture("fetch-request.json")).
+ servermock.CheckRequestJSONBodyFromFixture("request-body.json")).
Build(t)
account := goacmedns.Account{
diff --git a/providers/dns/acmedns/mock_test.go b/providers/dns/acmedns/mock_test.go
index a09a3ca91..629f25a0c 100644
--- a/providers/dns/acmedns/mock_test.go
+++ b/providers/dns/acmedns/mock_test.go
@@ -107,7 +107,6 @@ func newMockStorage() *mockStorage {
if acct, ok := m.accounts[domain]; ok {
return acct, nil
}
-
return goacmedns.Account{}, storage.ErrDomainNotFound
}
diff --git a/providers/dns/active24/active24.go b/providers/dns/active24/active24.go
index 0b925de6a..1acd72f61 100644
--- a/providers/dns/active24/active24.go
+++ b/providers/dns/active24/active24.go
@@ -2,12 +2,13 @@
package active24
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "strconv"
"time"
- "github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/internal/active24"
@@ -29,7 +30,15 @@ const (
)
// Config is used to configure the creation of the DNSProvider.
-type Config = active24.Config
+type Config struct {
+ APIKey string
+ Secret string
+
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
@@ -45,7 +54,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *active24.Client
}
// NewDNSProvider returns a DNSProvider instance configured for Active24.
@@ -68,29 +78,81 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("active24: the configuration of the DNS provider is nil")
}
- provider, err := active24.NewDNSProviderConfig(config, baseAPIDomain)
+ client, err := active24.NewClient(baseAPIDomain, config.APIKey, config.Secret)
if err != nil {
return nil, fmt.Errorf("active24: %w", err)
}
- return &DNSProvider{prv: provider}, nil
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{
+ config: config,
+ client: client,
+ }, nil
}
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+ ctx := context.Background()
+
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("active24: could not find zone for domain %q: %w", domain, err)
+ }
+
+ subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
return fmt.Errorf("active24: %w", err)
}
+ serviceID, err := d.findServiceID(ctx, dns01.UnFqdn(authZone))
+ if err != nil {
+ return fmt.Errorf("active24: find service ID: %w", err)
+ }
+
+ record := active24.Record{
+ Type: "TXT",
+ Name: subDomain,
+ Content: info.Value,
+ TTL: d.config.TTL,
+ }
+
+ err = d.client.CreateRecord(ctx, strconv.Itoa(serviceID), record)
+ if err != nil {
+ return fmt.Errorf("active24: create record: %w", err)
+ }
+
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+ ctx := context.Background()
+
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil {
- return fmt.Errorf("active24: %w", err)
+ return fmt.Errorf("active24: could not find zone for domain %q: %w", domain, err)
+ }
+
+ serviceID, err := d.findServiceID(ctx, dns01.UnFqdn(authZone))
+ if err != nil {
+ return fmt.Errorf("active24: find service ID: %w", err)
+ }
+
+ recordID, err := d.findRecordID(ctx, strconv.Itoa(serviceID), info)
+ if err != nil {
+ return fmt.Errorf("active24: find record ID: %w", err)
+ }
+
+ err = d.client.DeleteRecord(ctx, strconv.Itoa(serviceID), strconv.Itoa(recordID))
+ if err != nil {
+ return fmt.Errorf("active24: delete record %w", err)
}
return nil
@@ -99,5 +161,58 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+ return d.config.PropagationTimeout, d.config.PollingInterval
+}
+
+func (d *DNSProvider) findServiceID(ctx context.Context, domain string) (int, error) {
+ services, err := d.client.GetServices(ctx)
+ if err != nil {
+ return 0, fmt.Errorf("get services: %w", err)
+ }
+
+ for _, service := range services {
+ if service.ServiceName != "domain" {
+ continue
+ }
+
+ if service.Name != domain {
+ continue
+ }
+
+ return service.ID, nil
+ }
+
+ return 0, fmt.Errorf("service not found for domain: %s", domain)
+}
+
+func (d *DNSProvider) findRecordID(ctx context.Context, serviceID string, info dns01.ChallengeInfo) (int, error) {
+ // NOTE(ldez): Despite the API documentation, the filter doesn't seem to work.
+ filter := active24.RecordFilter{
+ Name: dns01.UnFqdn(info.EffectiveFQDN),
+ Type: []string{"TXT"},
+ Content: info.Value,
+ }
+
+ records, err := d.client.GetRecords(ctx, serviceID, filter)
+ if err != nil {
+ return 0, fmt.Errorf("get records: %w", err)
+ }
+
+ for _, record := range records {
+ if record.Type != "TXT" {
+ continue
+ }
+
+ if record.Name != dns01.UnFqdn(info.EffectiveFQDN) {
+ continue
+ }
+
+ if record.Content != info.Value {
+ continue
+ }
+
+ return record.ID, nil
+ }
+
+ return 0, errors.New("no record found")
}
diff --git a/providers/dns/active24/active24.toml b/providers/dns/active24/active24.toml
index b0eaabab8..6a54d4695 100644
--- a/providers/dns/active24/active24.toml
+++ b/providers/dns/active24/active24.toml
@@ -7,7 +7,7 @@ Since = "v4.23.0"
Example = '''
ACTIVE24_API_KEY="xxx" \
ACTIVE24_SECRET="yyy" \
-lego --dns active24 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns active24 -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/active24/active24_test.go b/providers/dns/active24/active24_test.go
index 2987fb27b..d7d2c5535 100644
--- a/providers/dns/active24/active24_test.go
+++ b/providers/dns/active24/active24_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -60,7 +59,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -109,7 +109,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -123,7 +124,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +137,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/alidns/alidns.go b/providers/dns/alidns/alidns.go
index cdd8e75e0..660098d4a 100644
--- a/providers/dns/alidns/alidns.go
+++ b/providers/dns/alidns/alidns.go
@@ -2,13 +2,11 @@
package alidns
import (
- "context"
"errors"
"fmt"
"time"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
- "github.com/alibabacloud-go/tea/dara"
"github.com/aliyun/credentials-go/credentials"
alidns "github.com/go-acme/alidns-20150109/v4/client"
"github.com/go-acme/lego/v4/challenge"
@@ -27,7 +25,6 @@ const (
EnvSecretKey = envNamespace + "SECRET_KEY"
EnvSecurityToken = envNamespace + "SECURITY_TOKEN"
EnvRegionID = envNamespace + "REGION_ID"
- EnvLine = envNamespace + "LINE"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@@ -46,7 +43,6 @@ type Config struct {
SecretKey string
SecurityToken string
RegionID string
- Line string
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
@@ -76,7 +72,6 @@ type DNSProvider struct {
func NewDNSProvider() (*DNSProvider, error) {
config := NewDefaultConfig()
config.RegionID = env.GetOrFile(EnvRegionID)
- config.Line = env.GetOrFile(EnvLine)
values, err := env.Get(EnvRAMRole)
if err == nil {
@@ -155,11 +150,9 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- zoneName, err := d.getHostedZone(ctx, info.EffectiveFQDN)
+ zoneName, err := d.getHostedZone(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("alicloud: %w", err)
}
@@ -169,26 +162,23 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return err
}
- _, err = alidns.AddDomainRecordWithContext(ctx, d.client, recordRequest, &dara.RuntimeOptions{})
+ _, err = alidns.AddDomainRecord(d.client, recordRequest)
if err != nil {
return fmt.Errorf("alicloud: API call failed: %w", err)
}
-
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- records, err := d.findTxtRecords(ctx, info.EffectiveFQDN)
+ records, err := d.findTxtRecords(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("alicloud: %w", err)
}
- _, err = d.getHostedZone(ctx, info.EffectiveFQDN)
+ _, err = d.getHostedZone(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("alicloud: %w", err)
}
@@ -198,16 +188,15 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
RecordId: rec.RecordId,
}
- _, err = alidns.DeleteDomainRecordWithContext(ctx, d.client, request, &dara.RuntimeOptions{})
+ _, err = alidns.DeleteDomainRecord(d.client, request)
if err != nil {
return fmt.Errorf("alicloud: %w", err)
}
}
-
return nil
}
-func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (string, error) {
+func (d *DNSProvider) getHostedZone(domain string) (string, error) {
request := new(alidns.DescribeDomainsRequest)
var domains []*alidns.DescribeDomainsResponseBodyDomainsDomain
@@ -217,7 +206,7 @@ func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (string,
for {
request.SetPageNumber(startPage)
- response, err := alidns.DescribeDomainsWithContext(ctx, d.client, request, &dara.RuntimeOptions{})
+ response, err := alidns.DescribeDomains(d.client, request)
if err != nil {
return "", fmt.Errorf("API call failed: %w", err)
}
@@ -237,7 +226,6 @@ func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (string,
}
var hostedZone *alidns.DescribeDomainsResponseBodyDomainsDomain
-
for _, zone := range domains {
if ptr.Deref(zone.DomainName) == dns01.UnFqdn(authZone) || ptr.Deref(zone.PunyCode) == dns01.UnFqdn(authZone) {
hostedZone = zone
@@ -257,22 +245,16 @@ func (d *DNSProvider) newTxtRecord(zone, fqdn, value string) (*alidns.AddDomainR
return nil, err
}
- adrr := new(alidns.AddDomainRecordRequest).
+ return new(alidns.AddDomainRecordRequest).
SetType("TXT").
SetDomainName(zone).
SetRR(rr).
SetValue(value).
- SetTTL(int64(d.config.TTL))
-
- if d.config.Line != "" {
- adrr.SetLine(d.config.Line)
- }
-
- return adrr, nil
+ SetTTL(int64(d.config.TTL)), nil
}
-func (d *DNSProvider) findTxtRecords(ctx context.Context, fqdn string) ([]*alidns.DescribeDomainRecordsResponseBodyDomainRecordsRecord, error) {
- zoneName, err := d.getHostedZone(ctx, fqdn)
+func (d *DNSProvider) findTxtRecords(fqdn string) ([]*alidns.DescribeDomainRecordsResponseBodyDomainRecordsRecord, error) {
+ zoneName, err := d.getHostedZone(fqdn)
if err != nil {
return nil, err
}
@@ -283,7 +265,7 @@ func (d *DNSProvider) findTxtRecords(ctx context.Context, fqdn string) ([]*alidn
var records []*alidns.DescribeDomainRecordsResponseBodyDomainRecordsRecord
- result, err := alidns.DescribeDomainRecordsWithContext(ctx, d.client, request, &dara.RuntimeOptions{})
+ result, err := alidns.DescribeDomainRecords(d.client, request)
if err != nil {
return records, fmt.Errorf("API call has failed: %w", err)
}
@@ -298,7 +280,6 @@ func (d *DNSProvider) findTxtRecords(ctx context.Context, fqdn string) ([]*alidn
records = append(records, record)
}
}
-
return records, nil
}
diff --git a/providers/dns/alidns/alidns.toml b/providers/dns/alidns/alidns.toml
index b78e1859d..49a9aeeab 100644
--- a/providers/dns/alidns/alidns.toml
+++ b/providers/dns/alidns/alidns.toml
@@ -7,13 +7,13 @@ Since = "v1.1.0"
Example = '''
# Setup using instance RAM role
ALICLOUD_RAM_ROLE=lego \
-lego --dns alidns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns alidns -d '*.example.com' -d example.com run
# Or, using credentials
ALICLOUD_ACCESS_KEY=abcdefghijklmnopqrstuvwx \
ALICLOUD_SECRET_KEY=your-secret-key \
ALICLOUD_SECURITY_TOKEN=your-sts-token \
-lego --dns alidns - -d '*.example.com' -d example.com run
+lego --email you@example.com --dns alidns - -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -23,8 +23,6 @@ lego --dns alidns - -d '*.example.com' -d example.com run
ALICLOUD_SECRET_KEY = "Access Key secret"
ALICLOUD_SECURITY_TOKEN = "STS Security Token (optional)"
[Configuration.Additional]
- ALICLOUD_REGION_ID = "Region ID (Default: cn-hangzhou)"
- ALICLOUD_LINE = "Line (Default: default)"
ALICLOUD_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
ALICLOUD_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
ALICLOUD_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)"
diff --git a/providers/dns/alidns/alidns_test.go b/providers/dns/alidns/alidns_test.go
index b1e482d2d..487997813 100644
--- a/providers/dns/alidns/alidns_test.go
+++ b/providers/dns/alidns/alidns_test.go
@@ -64,7 +64,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -143,7 +142,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -157,7 +155,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/aliesa/aliesa.go b/providers/dns/aliesa/aliesa.go
deleted file mode 100644
index 2a38389be..000000000
--- a/providers/dns/aliesa/aliesa.go
+++ /dev/null
@@ -1,255 +0,0 @@
-// Package aliesa implements a DNS provider for solving the DNS-01 challenge using AlibabaCloud ESA.
-package aliesa
-
-import (
- "context"
- "errors"
- "fmt"
- "sync"
- "time"
-
- openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
- "github.com/alibabacloud-go/tea/dara"
- "github.com/aliyun/credentials-go/credentials"
- esa "github.com/go-acme/esa-20240910/v2/client"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/ptr"
-)
-
-// Environment variables names.
-const (
- envNamespace = "ALIESA_"
-
- EnvRAMRole = envNamespace + "RAM_ROLE"
- EnvAccessKey = envNamespace + "ACCESS_KEY"
- EnvSecretKey = envNamespace + "SECRET_KEY"
- EnvSecurityToken = envNamespace + "SECURITY_TOKEN"
- EnvRegionID = envNamespace + "REGION_ID"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-const defaultRegionID = "cn-hangzhou"
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- RAMRole string
- APIKey string
- SecretKey string
- SecurityToken string
- RegionID string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPTimeout time.Duration
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *esa.Client
-
- recordIDs map[string]int64
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for AlibabaCloud ESA.
-func NewDNSProvider() (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.RegionID = env.GetOrFile(EnvRegionID)
-
- values, err := env.Get(EnvRAMRole)
- if err == nil {
- config.RAMRole = values[EnvRAMRole]
- return NewDNSProviderConfig(config)
- }
-
- values, err = env.Get(EnvAccessKey, EnvSecretKey)
- if err != nil {
- return nil, fmt.Errorf("aliesa: %w", err)
- }
-
- config.APIKey = values[EnvAccessKey]
- config.SecretKey = values[EnvSecretKey]
- config.SecurityToken = env.GetOrFile(EnvSecurityToken)
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for AlibabaCloud ESA.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("aliesa: the configuration of the DNS provider is nil")
- }
-
- if config.RegionID == "" {
- config.RegionID = defaultRegionID
- }
-
- cfg := new(openapi.Config).
- SetRegionId(config.RegionID).
- SetReadTimeout(int(config.HTTPTimeout.Milliseconds()))
-
- switch {
- case config.RAMRole != "":
- // https://www.alibabacloud.com/help/en/ecs/user-guide/attach-an-instance-ram-role-to-an-ecs-instance
- credentialsCfg := new(credentials.Config).
- SetType("ecs_ram_role").
- SetRoleName(config.RAMRole)
-
- credentialClient, err := credentials.NewCredential(credentialsCfg)
- if err != nil {
- return nil, fmt.Errorf("aliesa: new credential: %w", err)
- }
-
- cfg = cfg.SetCredential(credentialClient)
-
- case config.APIKey != "" && config.SecretKey != "" && config.SecurityToken != "":
- cfg = cfg.
- SetAccessKeyId(config.APIKey).
- SetAccessKeySecret(config.SecretKey).
- SetSecurityToken(config.SecurityToken)
-
- case config.APIKey != "" && config.SecretKey != "":
- cfg = cfg.
- SetAccessKeyId(config.APIKey).
- SetAccessKeySecret(config.SecretKey)
-
- default:
- return nil, errors.New("aliesa: ram role or credentials missing")
- }
-
- client, err := esa.NewClient(cfg)
- if err != nil {
- return nil, fmt.Errorf("aliesa: new client: %w", err)
- }
-
- // Workaround to get a regional URL.
- // https://github.com/alibabacloud-go/esa-20240910/blame/7660e3aab2045d4820e4b83427a154efe0c79319/client/client.go#L27
- // The `EndpointRule` is hardcoded with an empty string, so the region is ignored.
- client.Endpoint = nil
- client.EndpointRule = ptr.Pointer("regional")
-
- client.Endpoint, err = esa.GetEndpoint(client, dara.String("esa"), client.RegionId, client.EndpointRule, client.Network, client.Suffix, client.EndpointMap, client.Endpoint)
- if err != nil {
- return nil, fmt.Errorf("aliesa: get endpoint: %w", err)
- }
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]int64),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- siteID, err := d.getSiteID(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("aliesa: %w", err)
- }
-
- crReq := new(esa.CreateRecordRequest).
- SetSiteId(siteID).
- SetType("TXT").
- SetRecordName(dns01.UnFqdn(info.EffectiveFQDN)).
- SetTtl(int32(d.config.TTL)).
- SetData(new(esa.CreateRecordRequestData).SetValue(info.Value))
-
- // https://www.alibabacloud.com/help/en/edge-security-acceleration/esa/api-esa-2024-09-10-createrecord
- crResp, err := esa.CreateRecordWithContext(ctx, d.client, crReq, &dara.RuntimeOptions{})
- if err != nil {
- return fmt.Errorf("aliesa: create record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.recordIDs[token] = ptr.Deref(crResp.Body.GetRecordId())
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- // gets the record's unique ID
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("aliesa: unknown record ID for '%s'", info.EffectiveFQDN)
- }
-
- drReq := new(esa.DeleteRecordRequest).
- SetRecordId(recordID)
-
- // https://www.alibabacloud.com/help/en/edge-security-acceleration/esa/api-esa-2024-09-10-deleterecord
- _, err := esa.DeleteRecordWithContext(ctx, d.client, drReq, &dara.RuntimeOptions{})
- if err != nil {
- return fmt.Errorf("aliesa: delete record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) getSiteID(ctx context.Context, fqdn string) (int64, error) {
- authZone, err := dns01.FindZoneByFqdn(fqdn)
- if err != nil {
- return 0, fmt.Errorf("aliesa: could not find zone for domain %q: %w", fqdn, err)
- }
-
- lsReq := new(esa.ListSitesRequest).
- SetSiteName(dns01.UnFqdn(authZone)).
- SetSiteSearchType("suffix")
-
- // https://www.alibabacloud.com/help/en/edge-security-acceleration/esa/api-esa-2024-09-10-listsites
- lsResp, err := esa.ListSitesWithContext(ctx, d.client, lsReq, &dara.RuntimeOptions{})
- if err != nil {
- return 0, fmt.Errorf("list sites: %w", err)
- }
-
- for f := range dns01.UnFqdnDomainsSeq(fqdn) {
- domain := dns01.UnFqdn(f)
-
- for _, site := range lsResp.Body.GetSites() {
- if ptr.Deref(site.GetSiteName()) == domain {
- return ptr.Deref(site.GetSiteId()), nil
- }
- }
- }
-
- return 0, fmt.Errorf("site not found (fqdn: %q)", fqdn)
-}
diff --git a/providers/dns/aliesa/aliesa.toml b/providers/dns/aliesa/aliesa.toml
deleted file mode 100644
index 5e7345e40..000000000
--- a/providers/dns/aliesa/aliesa.toml
+++ /dev/null
@@ -1,33 +0,0 @@
-Name = "AlibabaCloud ESA"
-Description = ''''''
-URL = "https://www.alibabacloud.com/en/product/esa"
-Code = "aliesa"
-Since = "v4.29.0"
-
-Example = '''
-# Setup using instance RAM role
-ALIESA_RAM_ROLE=lego \
-lego --dns aliesa -d '*.example.com' -d example.com run
-
-# Or, using credentials
-ALIESA_ACCESS_KEY=abcdefghijklmnopqrstuvwx \
-ALIESA_SECRET_KEY=your-secret-key \
-ALIESA_SECURITY_TOKEN=your-sts-token \
-lego --dns aliesa - -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- ALIESA_RAM_ROLE = "Your instance RAM role (https://www.alibabacloud.com/help/en/ecs/user-guide/attach-an-instance-ram-role-to-an-ecs-instance)"
- ALIESA_ACCESS_KEY = "Access key ID"
- ALIESA_SECRET_KEY = "Access Key secret"
- ALIESA_SECURITY_TOKEN = "STS Security Token (optional)"
- [Configuration.Additional]
- ALIESA_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- ALIESA_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- ALIESA_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- ALIESA_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://www.alibabacloud.com/help/en/edge-security-acceleration/esa/api-esa-2024-09-10-overview?spm=a2c63.p38356.help-menu-2673927.d_6_0_0.20b224c28PSZDc#:~:text=DNS-,DNS%20records,-DNS%20records"
- GoClient = "https://github.com/alibabacloud-go/esa-20240910"
diff --git a/providers/dns/aliesa/aliesa_test.go b/providers/dns/aliesa/aliesa_test.go
deleted file mode 100644
index 025529409..000000000
--- a/providers/dns/aliesa/aliesa_test.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package aliesa
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvAccessKey,
- EnvSecretKey,
- EnvRAMRole).
- WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAccessKey: "123",
- EnvSecretKey: "456",
- },
- },
- {
- desc: "success (RAM role)",
- envVars: map[string]string{
- EnvRAMRole: "LegoInstanceRole",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{
- EnvAccessKey: "",
- EnvSecretKey: "",
- },
- expected: "aliesa: some credentials information are missing: ALIESA_ACCESS_KEY,ALIESA_SECRET_KEY",
- },
- {
- desc: "missing access key",
- envVars: map[string]string{
- EnvAccessKey: "",
- EnvSecretKey: "456",
- },
- expected: "aliesa: some credentials information are missing: ALIESA_ACCESS_KEY",
- },
- {
- desc: "missing secret key",
- envVars: map[string]string{
- EnvAccessKey: "123",
- EnvSecretKey: "",
- },
- expected: "aliesa: some credentials information are missing: ALIESA_SECRET_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- ramRole string
- apiKey string
- secretKey string
- expected string
- }{
- {
- desc: "success",
- apiKey: "123",
- secretKey: "456",
- },
- {
- desc: "success",
- ramRole: "LegoInstanceRole",
- },
- {
- desc: "missing credentials",
- expected: "aliesa: ram role or credentials missing",
- },
- {
- desc: "missing api key",
- secretKey: "456",
- expected: "aliesa: ram role or credentials missing",
- },
- {
- desc: "missing secret key",
- apiKey: "123",
- expected: "aliesa: ram role or credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIKey = test.apiKey
- config.SecretKey = test.secretKey
- config.RAMRole = test.ramRole
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/allinkl/allinkl.go b/providers/dns/allinkl/allinkl.go
index 376b0903c..b1a40ae64 100644
--- a/providers/dns/allinkl/allinkl.go
+++ b/providers/dns/allinkl/allinkl.go
@@ -11,10 +11,8 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/allinkl/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -94,16 +92,12 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
identifier.HTTPClient = config.HTTPClient
}
- identifier.HTTPClient = clientdebug.Wrap(identifier.HTTPClient)
-
client := internal.NewClient(config.Login)
if config.HTTPClient != nil {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
identifier: identifier,
@@ -122,20 +116,20 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("allinkl: could not find zone for domain %q: %w", domain, err)
+ }
+
ctx := context.Background()
credential, err := d.identifier.Authentication(ctx, 60, true)
if err != nil {
- return fmt.Errorf("allinkl: authentication: %w", err)
+ return fmt.Errorf("allinkl: %w", err)
}
ctx = internal.WithContext(ctx, credential)
- authZone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("allinkl: %w", err)
- }
-
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
return fmt.Errorf("allinkl: %w", err)
@@ -150,7 +144,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
recordID, err := d.client.AddDNSSettings(ctx, record)
if err != nil {
- return fmt.Errorf("allinkl: add DNS settings: %w", err)
+ return fmt.Errorf("allinkl: %w", err)
}
d.recordIDsMu.Lock()
@@ -168,7 +162,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
credential, err := d.identifier.Authentication(ctx, 60, true)
if err != nil {
- return fmt.Errorf("allinkl: authentication: %w", err)
+ return fmt.Errorf("allinkl: %w", err)
}
ctx = internal.WithContext(ctx, credential)
@@ -177,33 +171,14 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("allinkl: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
_, err = d.client.DeleteDNSSettings(ctx, recordID)
if err != nil {
- return fmt.Errorf("allinkl: delete DNS settings: %w", err)
+ return fmt.Errorf("allinkl: %w", err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
-
-func (d *DNSProvider) findZone(ctx context.Context, fqdn string) (string, error) {
- for z := range dns01.DomainsSeq(fqdn) {
- _, errG := d.client.GetDNSSettings(ctx, z, "")
- if errG != nil {
- log.Infof("get DNS settings zone[%q] %v", z, errG)
- continue
- }
-
- return z, nil
- }
-
- return "", fmt.Errorf("unable to find auth zone for '%s'", fqdn)
-}
diff --git a/providers/dns/allinkl/allinkl.toml b/providers/dns/allinkl/allinkl.toml
index 774f8fb9f..d9c937ee1 100644
--- a/providers/dns/allinkl/allinkl.toml
+++ b/providers/dns/allinkl/allinkl.toml
@@ -7,7 +7,7 @@ Since = "v4.5.0"
Example = '''
ALL_INKL_LOGIN=xxxxxxxxxxxxxxxxxxxxxxxxxx \
ALL_INKL_PASSWORD=yyyyyyyyyyyyyyyyyyyyyyyyyy \
-lego --dns allinkl -d '*.example.com' -d example.com run
+lego --email you@example.com --dns allinkl -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/allinkl/allinkl_test.go b/providers/dns/allinkl/allinkl_test.go
index 7da47aee4..af85f8c54 100644
--- a/providers/dns/allinkl/allinkl_test.go
+++ b/providers/dns/allinkl/allinkl_test.go
@@ -1,18 +1,9 @@
package allinkl
import (
- "encoding/json"
- "encoding/xml"
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
- "net/url"
"testing"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/allinkl/internal"
"github.com/stretchr/testify/require"
)
@@ -62,7 +53,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -131,7 +121,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -145,115 +134,9 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
require.NoError(t, err)
}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.Login = "user"
- config.Password = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
- p.identifier.BaseURL, _ = url.Parse(server.URL)
-
- return p, err
- },
- ).Route("POST /KasAuth.php",
- servermock.ResponseFromInternal("auth.xml"),
- servermock.CheckRequestBodyFromInternal("auth-request.xml").
- IgnoreWhitespace(),
- )
-}
-
-func extractKasRequest(reader io.Reader) (*internal.KasRequest, error) {
- type ReqEnvelope struct {
- XMLName xml.Name `xml:"Envelope"`
- Body struct {
- KasAPI struct {
- Params string `xml:"Params"`
- } `xml:"KasApi"`
- } `xml:"Body"`
- }
-
- raw, err := io.ReadAll(reader)
- if err != nil {
- return nil, err
- }
-
- reqEnvelope := ReqEnvelope{}
-
- err = xml.Unmarshal(raw, &reqEnvelope)
- if err != nil {
- return nil, err
- }
-
- var kReq internal.KasRequest
-
- err = json.Unmarshal([]byte(reqEnvelope.Body.KasAPI.Params), &kReq)
- if err != nil {
- return nil, err
- }
-
- return &kReq, nil
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /KasApi.php",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- kReq, err := extractKasRequest(req.Body)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusBadRequest)
- return
- }
-
- switch kReq.Action {
- case "get_dns_settings":
- params := kReq.RequestParams.(map[string]any)
-
- if params["zone_host"] == "_acme-challenge.example.com." {
- servermock.ResponseFromInternal("get_dns_settings_not_found.xml").ServeHTTP(rw, req)
- } else {
- servermock.ResponseFromInternal("get_dns_settings.xml").ServeHTTP(rw, req)
- }
-
- case "add_dns_settings":
- servermock.ResponseFromInternal("add_dns_settings.xml").ServeHTTP(rw, req)
-
- default:
- http.Error(rw, fmt.Sprintf("unknown action: %v", kReq.Action), http.StatusBadRequest)
- }
- }),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("POST /KasApi.php",
- servermock.ResponseFromInternal("delete_dns_settings.xml"),
- servermock.CheckRequestBodyFromInternal("delete_dns_settings-request.xml").
- IgnoreWhitespace()).
- Build(t)
-
- provider.recordIDs["abc"] = "57347450"
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/allinkl/internal/client.go b/providers/dns/allinkl/internal/client.go
index d4403cac5..02a5a2c8f 100644
--- a/providers/dns/allinkl/internal/client.go
+++ b/providers/dns/allinkl/internal/client.go
@@ -6,21 +6,16 @@ import (
"encoding/json"
"fmt"
"net/http"
- "net/url"
"strconv"
"strings"
"sync"
"time"
- "github.com/cenkalti/backoff/v5"
- "github.com/go-acme/lego/v4/platform/wait"
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
"github.com/go-viper/mapstructure/v2"
)
-const defaultBaseURL = "https://kasapi.kasserver.com/soap/"
-
-const apiPath = "KasApi.php"
+const apiEndpoint = "https://kasapi.kasserver.com/soap/KasApi.php"
type Authentication interface {
Authentication(ctx context.Context, sessionLifetime int, sessionUpdateLifetime bool) (string, error)
@@ -33,21 +28,16 @@ type Client struct {
floodTime time.Time
muFloodTime sync.Mutex
- maxElapsedTime time.Duration
-
- BaseURL *url.URL
+ baseURL string
HTTPClient *http.Client
}
// NewClient creates a new Client.
func NewClient(login string) *Client {
- baseURL, _ := url.Parse(defaultBaseURL)
-
return &Client{
- login: login,
- BaseURL: baseURL,
- maxElapsedTime: 3 * time.Minute,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
+ login: login,
+ baseURL: apiEndpoint,
+ HTTPClient: &http.Client{Timeout: 10 * time.Second},
}
}
@@ -61,9 +51,13 @@ func (c *Client) GetDNSSettings(ctx context.Context, zone, recordID string) ([]R
requestParams["record_id"] = recordID
}
- var g APIResponse[GetDNSSettingsResponse]
+ req, err := c.newRequest(ctx, "get_dns_settings", requestParams)
+ if err != nil {
+ return nil, err
+ }
- err := c.doRequest(ctx, "get_dns_settings", requestParams, &g)
+ var g GetDNSSettingsAPIResponse
+ err = c.do(req, &g)
if err != nil {
return nil, err
}
@@ -75,9 +69,13 @@ func (c *Client) GetDNSSettings(ctx context.Context, zone, recordID string) ([]R
// AddDNSSettings Creation of a DNS resource record.
func (c *Client) AddDNSSettings(ctx context.Context, record DNSRequest) (string, error) {
- var g APIResponse[AddDNSSettingsResponse]
+ req, err := c.newRequest(ctx, "add_dns_settings", record)
+ if err != nil {
+ return "", err
+ }
- err := c.doRequest(ctx, "add_dns_settings", record, &g)
+ var g AddDNSSettingsAPIResponse
+ err = c.do(req, &g)
if err != nil {
return "", err
}
@@ -91,9 +89,13 @@ func (c *Client) AddDNSSettings(ctx context.Context, record DNSRequest) (string,
func (c *Client) DeleteDNSSettings(ctx context.Context, recordID string) (string, error) {
requestParams := map[string]string{"record_id": recordID}
- var g APIResponse[DeleteDNSSettingsResponse]
+ req, err := c.newRequest(ctx, "delete_dns_settings", requestParams)
+ if err != nil {
+ return "", err
+ }
- err := c.doRequest(ctx, "delete_dns_settings", requestParams, &g)
+ var g DeleteDNSSettingsAPIResponse
+ err = c.do(req, &g)
if err != nil {
return "", err
}
@@ -119,9 +121,7 @@ func (c *Client) newRequest(ctx context.Context, action string, requestParams an
payload := []byte(strings.TrimSpace(fmt.Sprintf(kasAPIEnvelope, body)))
- endpoint := c.BaseURL.JoinPath(apiPath)
-
- req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), bytes.NewReader(payload))
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, bytes.NewReader(payload))
if err != nil {
return nil, fmt.Errorf("unable to create request: %w", err)
}
@@ -129,21 +129,6 @@ func (c *Client) newRequest(ctx context.Context, action string, requestParams an
return req, nil
}
-func (c *Client) doRequest(ctx context.Context, action string, requestParams, result any) error {
- return wait.Retry(ctx,
- func() error {
- req, err := c.newRequest(ctx, action, requestParams)
- if err != nil {
- return backoff.Permanent(err)
- }
-
- return c.do(req, result)
- },
- backoff.WithBackOff(&backoff.ZeroBackOff{}),
- backoff.WithMaxElapsedTime(c.maxElapsedTime),
- )
-}
-
func (c *Client) do(req *http.Request, result any) error {
c.muFloodTime.Lock()
time.Sleep(time.Until(c.floodTime))
@@ -151,40 +136,29 @@ func (c *Client) do(req *http.Request, result any) error {
resp, err := c.HTTPClient.Do(req)
if err != nil {
- return backoff.Permanent(errutils.NewHTTPDoError(req, err))
+ return errutils.NewHTTPDoError(req, err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
- return backoff.Permanent(errutils.NewUnexpectedResponseStatusCodeError(req, resp))
+ return errutils.NewUnexpectedResponseStatusCodeError(req, resp)
}
envlp, err := decodeXML[KasAPIResponseEnvelope](resp.Body)
if err != nil {
- return backoff.Permanent(err)
+ return err
}
if envlp.Body.Fault != nil {
- if envlp.Body.Fault.Message == "flood_protection" {
- ft, errP := strconv.ParseFloat(envlp.Body.Fault.Detail, 64)
- if errP != nil {
- return fmt.Errorf("parse flood protection delay: %w", envlp.Body.Fault)
- }
-
- c.updateFloodTime(ft)
-
- return envlp.Body.Fault
- }
-
- return backoff.Permanent(envlp.Body.Fault)
+ return envlp.Body.Fault
}
raw := getValue(envlp.Body.KasAPIResponse.Return)
err = mapstructure.Decode(raw, result)
if err != nil {
- return backoff.Permanent(fmt.Errorf("response struct decode: %w", err))
+ return fmt.Errorf("response struct decode: %w", err)
}
return nil
diff --git a/providers/dns/allinkl/internal/client_test.go b/providers/dns/allinkl/internal/client_test.go
index 949f45bf9..4b111e31c 100644
--- a/providers/dns/allinkl/internal/client_test.go
+++ b/providers/dns/allinkl/internal/client_test.go
@@ -2,9 +2,7 @@ package internal
import (
"net/http/httptest"
- "net/url"
"testing"
- "time"
"github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/stretchr/testify/assert"
@@ -13,17 +11,15 @@ import (
func setupClient(server *httptest.Server) (*Client, error) {
client := NewClient("user")
- client.BaseURL, _ = url.Parse(server.URL)
+ client.baseURL = server.URL
client.HTTPClient = server.Client()
- client.maxElapsedTime = 1 * time.Second
-
return client, nil
}
func TestClient_GetDNSSettings(t *testing.T) {
client := servermock.NewBuilder[*Client](setupClient).
- Route("POST /KasApi.php", servermock.ResponseFromFixture("get_dns_settings.xml"),
+ Route("POST /", servermock.ResponseFromFixture("get_dns_settings.xml"),
servermock.CheckRequestBodyFromFixture("get_dns_settings-request.xml").
IgnoreWhitespace()).
Build(t)
@@ -100,24 +96,9 @@ func TestClient_GetDNSSettings(t *testing.T) {
assert.Equal(t, expected, records)
}
-func TestClient_GetDNSSettings_error_flood_protection(t *testing.T) {
- client := servermock.NewBuilder[*Client](setupClient).
- Route("POST /KasApi.php",
- servermock.ResponseFromFixture("flood_protection.xml"),
- ).
- Build(t)
-
- assert.Zero(t, client.floodTime)
-
- _, err := client.GetDNSSettings(mockContext(t), "example.com", "")
- require.EqualError(t, err, "KasApi: SOAP-ENV:Server: flood_protection: 0.0688529014587")
-
- assert.NotZero(t, client.floodTime)
-}
-
func TestClient_AddDNSSettings(t *testing.T) {
client := servermock.NewBuilder[*Client](setupClient).
- Route("POST /KasApi.php", servermock.ResponseFromFixture("add_dns_settings.xml"),
+ Route("POST /", servermock.ResponseFromFixture("add_dns_settings.xml"),
servermock.CheckRequestBodyFromFixture("add_dns_settings-request.xml").
IgnoreWhitespace()).
Build(t)
@@ -137,7 +118,7 @@ func TestClient_AddDNSSettings(t *testing.T) {
func TestClient_DeleteDNSSettings(t *testing.T) {
client := servermock.NewBuilder[*Client](setupClient).
- Route("POST /KasApi.php", servermock.ResponseFromFixture("delete_dns_settings.xml"),
+ Route("POST /", servermock.ResponseFromFixture("delete_dns_settings.xml"),
servermock.CheckRequestBodyFromFixture("delete_dns_settings-request.xml").
IgnoreWhitespace()).
Build(t)
diff --git a/providers/dns/allinkl/internal/fixtures/auth-request.xml b/providers/dns/allinkl/internal/fixtures/auth-request.xml
deleted file mode 100644
index 1cba86f10..000000000
--- a/providers/dns/allinkl/internal/fixtures/auth-request.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- {"kas_login":"user","kas_auth_data":"secret","kas_auth_type":"plain","session_lifetime":60,"session_update_lifetime":"Y"}
-
-
-
diff --git a/providers/dns/allinkl/internal/fixtures/flood_protection.xml b/providers/dns/allinkl/internal/fixtures/flood_protection.xml
deleted file mode 100644
index b8da10fab..000000000
--- a/providers/dns/allinkl/internal/fixtures/flood_protection.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- SOAP-ENV:Server
- flood_protection
- KasApi
- 0.0688529014587
-
-
-
diff --git a/providers/dns/allinkl/internal/fixtures/get_dns_settings-zone_not_found.xml b/providers/dns/allinkl/internal/fixtures/get_dns_settings-zone_not_found.xml
deleted file mode 100644
index 478d07a3a..000000000
--- a/providers/dns/allinkl/internal/fixtures/get_dns_settings-zone_not_found.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- SOAP-ENV:Server
- zone_not_found
- KasApi
- example.com
-
-
-
diff --git a/providers/dns/allinkl/internal/fixtures/get_dns_settings-zone_syntax_incorrect.xml b/providers/dns/allinkl/internal/fixtures/get_dns_settings-zone_syntax_incorrect.xml
deleted file mode 100644
index c77d733db..000000000
--- a/providers/dns/allinkl/internal/fixtures/get_dns_settings-zone_syntax_incorrect.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- SOAP-ENV:Server
- zone_syntax_incorrect
- KasApi
- _acme-challenge.example.com
-
-
-
diff --git a/providers/dns/allinkl/internal/identity.go b/providers/dns/allinkl/internal/identity.go
index e95e78899..ba8d4d90e 100644
--- a/providers/dns/allinkl/internal/identity.go
+++ b/providers/dns/allinkl/internal/identity.go
@@ -6,14 +6,14 @@ import (
"encoding/json"
"fmt"
"net/http"
- "net/url"
"strings"
"time"
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
)
-const authPath = "KasAuth.php"
+// authEndpoint represents the Identity API endpoint to call.
+const authEndpoint = "https://kasapi.kasserver.com/soap/KasAuth.php"
type token string
@@ -24,19 +24,17 @@ type Identifier struct {
login string
password string
- BaseURL *url.URL
- HTTPClient *http.Client
+ authEndpoint string
+ HTTPClient *http.Client
}
// NewIdentifier creates a new Identifier.
func NewIdentifier(login, password string) *Identifier {
- baseURL, _ := url.Parse(defaultBaseURL)
-
return &Identifier{
- login: login,
- password: password,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
+ login: login,
+ password: password,
+ authEndpoint: authEndpoint,
+ HTTPClient: &http.Client{Timeout: 10 * time.Second},
}
}
@@ -64,9 +62,7 @@ func (c *Identifier) Authentication(ctx context.Context, sessionLifetime int, se
payload := []byte(strings.TrimSpace(fmt.Sprintf(kasAuthEnvelope, body)))
- endpoint := c.BaseURL.JoinPath(authPath)
-
- req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), bytes.NewReader(payload))
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.authEndpoint, bytes.NewReader(payload))
if err != nil {
return "", fmt.Errorf("unable to create request: %w", err)
}
diff --git a/providers/dns/allinkl/internal/identity_test.go b/providers/dns/allinkl/internal/identity_test.go
index 41d092b13..dc55506f2 100644
--- a/providers/dns/allinkl/internal/identity_test.go
+++ b/providers/dns/allinkl/internal/identity_test.go
@@ -3,7 +3,6 @@ package internal
import (
"context"
"net/http/httptest"
- "net/url"
"testing"
"github.com/go-acme/lego/v4/platform/tester/servermock"
@@ -13,8 +12,7 @@ import (
func setupIdentifierClient(server *httptest.Server) (*Identifier, error) {
client := NewIdentifier("user", "secret")
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
+ client.authEndpoint = server.URL
return client, nil
}
@@ -27,13 +25,10 @@ func mockContext(t *testing.T) context.Context {
func TestIdentifier_Authentication(t *testing.T) {
client := servermock.NewBuilder[*Identifier](setupIdentifierClient).
- Route("POST /KasAuth.php",
- servermock.ResponseFromFixture("auth.xml"),
- servermock.CheckRequestBodyFromFixture("auth-request.xml").
- IgnoreWhitespace()).
+ Route("POST /", servermock.ResponseFromFixture("auth.xml")).
Build(t)
- credentialToken, err := client.Authentication(t.Context(), 60, true)
+ credentialToken, err := client.Authentication(t.Context(), 60, false)
require.NoError(t, err)
assert.Equal(t, "593959ca04f0de9689b586c6a647d15d", credentialToken)
@@ -41,7 +36,7 @@ func TestIdentifier_Authentication(t *testing.T) {
func TestIdentifier_Authentication_error(t *testing.T) {
client := servermock.NewBuilder[*Identifier](setupIdentifierClient).
- Route("POST /KasAuth.php", servermock.ResponseFromFixture("auth_fault.xml")).
+ Route("POST /", servermock.ResponseFromFixture("auth_fault.xml")).
Build(t)
_, err := client.Authentication(t.Context(), 60, false)
diff --git a/providers/dns/allinkl/internal/types.go b/providers/dns/allinkl/internal/types.go
index 51f7065b5..b5c6ba0d1 100644
--- a/providers/dns/allinkl/internal/types.go
+++ b/providers/dns/allinkl/internal/types.go
@@ -17,7 +17,6 @@ func (tr Trimmer) Token() (xml.Token, error) {
if cd, ok := t.(xml.CharData); ok {
t = xml.CharData(bytes.TrimSpace(cd))
}
-
return t, err
}
@@ -26,11 +25,10 @@ type Fault struct {
Code string `xml:"faultcode"`
Message string `xml:"faultstring"`
Actor string `xml:"faultactor"`
- Detail string `xml:"detail"`
}
-func (f *Fault) Error() string {
- return fmt.Sprintf("%s: %s: %s: %s", f.Actor, f.Code, f.Message, f.Detail)
+func (f Fault) Error() string {
+ return fmt.Sprintf("%s: %s: %s", f.Actor, f.Code, f.Message)
}
// KasResponse a KAS SOAP response.
@@ -55,7 +53,6 @@ func decodeXML[T any](reader io.Reader) (*T, error) {
}
var result T
-
err = xml.NewTokenDecoder(Trimmer{decoder: xml.NewDecoder(bytes.NewReader(raw))}).Decode(&result)
if err != nil {
return nil, fmt.Errorf("decode XML response: %w", err)
diff --git a/providers/dns/allinkl/internal/types_api.go b/providers/dns/allinkl/internal/types_api.go
index a11f3aac0..22f2c32ed 100644
--- a/providers/dns/allinkl/internal/types_api.go
+++ b/providers/dns/allinkl/internal/types_api.go
@@ -53,8 +53,8 @@ type DNSRequest struct {
// ---
-type APIResponse[T any] struct {
- Response T `json:"Response" mapstructure:"Response"`
+type GetDNSSettingsAPIResponse struct {
+ Response GetDNSSettingsResponse `json:"Response" mapstructure:"Response"`
}
type GetDNSSettingsResponse struct {
@@ -73,12 +73,20 @@ type ReturnInfo struct {
Aux int `json:"record_aux,omitempty" mapstructure:"record_aux"`
}
+type AddDNSSettingsAPIResponse struct {
+ Response AddDNSSettingsResponse `json:"Response" mapstructure:"Response"`
+}
+
type AddDNSSettingsResponse struct {
KasFloodDelay float64 `json:"KasFloodDelay" mapstructure:"KasFloodDelay"`
ReturnInfo string `json:"ReturnInfo" mapstructure:"ReturnInfo"`
ReturnString string `json:"ReturnString" mapstructure:"ReturnString"`
}
+type DeleteDNSSettingsAPIResponse struct {
+ Response DeleteDNSSettingsResponse `json:"Response"`
+}
+
type DeleteDNSSettingsResponse struct {
KasFloodDelay float64 `json:"KasFloodDelay"`
ReturnString string `json:"ReturnString"`
diff --git a/providers/dns/alwaysdata/alwaysdata.go b/providers/dns/alwaysdata/alwaysdata.go
deleted file mode 100644
index b2e0f3957..000000000
--- a/providers/dns/alwaysdata/alwaysdata.go
+++ /dev/null
@@ -1,185 +0,0 @@
-// Package alwaysdata implements a DNS provider for solving the DNS-01 challenge using Alwaysdata.
-package alwaysdata
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/alwaysdata/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "ALWAYSDATA_"
-
- EnvAPIKey = envNamespace + "API_KEY"
- EnvAccount = envNamespace + "ACCOUNT"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
- Account string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Alwaysdata.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("alwaysdata: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIKey = values[EnvAPIKey]
- config.Account = env.GetOrFile(EnvAccount)
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Alwaysdata.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("alwaysdata: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIKey, config.Account)
- if err != nil {
- return nil, fmt.Errorf("alwaysdata: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("alwaysdata: %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.Name)
- if err != nil {
- return fmt.Errorf("alwaysdata: %w", err)
- }
-
- record := internal.RecordRequest{
- DomainID: zone.ID,
- Name: subDomain,
- Type: "TXT",
- Value: info.Value,
- TTL: d.config.TTL,
- Annotation: "lego",
- }
-
- err = d.client.AddRecord(ctx, record)
- if err != nil {
- return fmt.Errorf("alwaysdata: add TXT record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("alwaysdata: %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.Name)
- if err != nil {
- return fmt.Errorf("alwaysdata: %w", err)
- }
-
- records, err := d.client.ListRecords(ctx, zone.ID, subDomain)
- if err != nil {
- return fmt.Errorf("alwaysdata: list records: %w", err)
- }
-
- for _, record := range records {
- if record.Type != "TXT" || record.Value != info.Value {
- continue
- }
-
- err = d.client.DeleteRecord(ctx, record.ID)
- if err != nil {
- return fmt.Errorf("alwaysdata: delete TXT record: %w", err)
- }
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findZone(ctx context.Context, fqdn string) (*internal.Domain, error) {
- domains, err := d.client.ListDomains(ctx)
- if err != nil {
- return nil, fmt.Errorf("list domains: %w", err)
- }
-
- for a := range dns01.UnFqdnDomainsSeq(fqdn) {
- for _, domain := range domains {
- if a == domain.Name {
- return &domain, nil
- }
- }
- }
-
- return nil, errors.New("domain not found")
-}
diff --git a/providers/dns/alwaysdata/alwaysdata.toml b/providers/dns/alwaysdata/alwaysdata.toml
deleted file mode 100644
index d00c6f032..000000000
--- a/providers/dns/alwaysdata/alwaysdata.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-Name = "Alwaysdata"
-Description = ''''''
-URL = "https://alwaysdata.com/"
-Code = "alwaysdata"
-Since = "v4.31.0"
-
-Example = '''
-ALWAYSDATA_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns alwaysdata -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- ALWAYSDATA_API_KEY = "API Key"
- [Configuration.Additional]
- ALWAYSDATA_ACCOUNT = "Account name"
- ALWAYSDATA_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- ALWAYSDATA_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- ALWAYSDATA_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- ALWAYSDATA_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://help.alwaysdata.com/en/api/resources/"
- APIDocDomains = "https://api.alwaysdata.com/v1/domain/doc/"
- APIDocRecords = "https://api.alwaysdata.com/v1/record/doc/"
- APIExamples = "https://help.alwaysdata.com/en/api/examples/"
diff --git a/providers/dns/alwaysdata/alwaysdata_test.go b/providers/dns/alwaysdata/alwaysdata_test.go
deleted file mode 100644
index 6084c2ae4..000000000
--- a/providers/dns/alwaysdata/alwaysdata_test.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package alwaysdata
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIKey, EnvAccount).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIKey: "secret",
- },
- },
- {
- desc: "success with an account",
- envVars: map[string]string{
- EnvAPIKey: "secret",
- EnvAccount: "foo",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "alwaysdata: some credentials information are missing: ALWAYSDATA_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- account string
- expected string
- }{
- {
- desc: "success",
- apiKey: "secret",
- },
- {
- desc: "success with an account",
- apiKey: "secret",
- account: "foo",
- },
- {
- desc: "missing credentials",
- expected: "alwaysdata: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIKey = test.apiKey
- config.Account = test.account
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIKey = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- WithBasicAuth("secret", ""),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domain/",
- servermock.ResponseFromInternal("domains.json")).
- Route("POST /record/",
- servermock.Noop().WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBodyFromInternal("record_add-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domain/",
- servermock.ResponseFromInternal("domains.json")).
- Route("GET /record/",
- servermock.ResponseFromInternal("records.json"),
- servermock.CheckQueryParameter().Strict().
- With("domain", "132").
- With("name", "_acme-challenge"),
- ).
- Route("DELETE /record/789/",
- servermock.Noop()).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/alwaysdata/internal/client.go b/providers/dns/alwaysdata/internal/client.go
deleted file mode 100644
index 5db11dcd1..000000000
--- a/providers/dns/alwaysdata/internal/client.go
+++ /dev/null
@@ -1,177 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://api.alwaysdata.com/v1"
-
-// Client the Alwaysdata API client.
-type Client struct {
- apiKey string
- account string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(apiKey, account string) (*Client, error) {
- if apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- apiKey: apiKey,
- account: account,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) ListDomains(ctx context.Context) ([]Domain, error) {
- endpoint := c.BaseURL.JoinPath("domain", "/")
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result []Domain
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-func (c *Client) AddRecord(ctx context.Context, record RecordRequest) error {
- endpoint := c.BaseURL.JoinPath("record", "/")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
- if err != nil {
- return err
- }
-
- err = c.do(req, nil)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func (c *Client) DeleteRecord(ctx context.Context, recordID int64) error {
- endpoint := c.BaseURL.JoinPath("record", strconv.FormatInt(recordID, 10), "/")
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) ListRecords(ctx context.Context, domainID int64, name string) ([]Record, error) {
- endpoint := c.BaseURL.JoinPath("record", "/")
-
- query := endpoint.Query()
- query.Set("domain", strconv.FormatInt(domainID, 10))
- query.Set("name", name)
- endpoint.RawQuery = query.Encode()
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result []Record
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- user := c.apiKey
-
- if c.account != "" {
- user += "account=" + c.account
- }
-
- req.SetBasicAuth(user, "")
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- return req, nil
-}
diff --git a/providers/dns/alwaysdata/internal/client_test.go b/providers/dns/alwaysdata/internal/client_test.go
deleted file mode 100644
index e6a349662..000000000
--- a/providers/dns/alwaysdata/internal/client_test.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret", "")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = clientdebug.Wrap(server.Client())
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- WithBasicAuth("secret", ""),
- )
-}
-
-func TestClient_ListDomains(t *testing.T) {
- client := mockBuilder().
- Route("GET /domain/",
- servermock.ResponseFromFixture("domains.json")).
- Build(t)
-
- result, err := client.ListDomains(t.Context())
- require.NoError(t, err)
-
- expected := []Domain{
- {ID: 132, Name: "example.com", Annotation: "test"},
- {ID: 133, Name: "example.net", IsInternal: true},
- {ID: 134, Name: "example.org"},
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_AddRecord(t *testing.T) {
- t.Setenv("LEGO_DEBUG_DNS_API_HTTP_CLIENT", "true")
-
- client := mockBuilder().
- Route("POST /record/",
- servermock.Noop().WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBodyFromFixture("record_add-request.json")).
- Build(t)
-
- record := RecordRequest{
- DomainID: 132,
- Name: "_acme-challenge",
- Type: "TXT",
- Value: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- Annotation: "lego",
- }
-
- err := client.AddRecord(t.Context(), record)
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /record/789/",
- servermock.Noop()).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), 789)
- require.NoError(t, err)
-}
-
-func TestClient_ListRecords(t *testing.T) {
- client := mockBuilder().
- Route("GET /record/",
- servermock.ResponseFromFixture("records.json"),
- servermock.CheckQueryParameter().Strict().
- With("domain", "132").
- With("name", "_acme-challenge"),
- ).
- Build(t)
-
- result, err := client.ListRecords(t.Context(), 132, "_acme-challenge")
- require.NoError(t, err)
-
- expected := []Record{
- {
- ID: 789,
- Domain: &Domain{
- Href: "/v1/domain/132/",
- },
- Type: "TXT",
- Name: "_acme-challenge",
- Value: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- Annotation: "lego",
- },
- {
- ID: 11619270,
- Domain: &Domain{
- Href: "/v1/domain/118935/",
- },
- Name: "home",
- Type: "A",
- Value: "149.202.90.65",
- TTL: 300,
- IsUserDefined: true,
- IsActive: true,
- },
- }
-
- assert.Equal(t, expected, result)
-}
diff --git a/providers/dns/alwaysdata/internal/fixtures/domains.json b/providers/dns/alwaysdata/internal/fixtures/domains.json
deleted file mode 100644
index dc34a948f..000000000
--- a/providers/dns/alwaysdata/internal/fixtures/domains.json
+++ /dev/null
@@ -1,16 +0,0 @@
-[
- {
- "id": 132,
- "name": "example.com",
- "annotation": "test"
- },
- {
- "id": 133,
- "name": "example.net",
- "is_internal": true
- },
- {
- "id": 134,
- "name": "example.org"
- }
-]
diff --git a/providers/dns/alwaysdata/internal/fixtures/record_add-request.json b/providers/dns/alwaysdata/internal/fixtures/record_add-request.json
deleted file mode 100644
index 5b6db2646..000000000
--- a/providers/dns/alwaysdata/internal/fixtures/record_add-request.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "domain": 132,
- "name": "_acme-challenge",
- "type": "TXT",
- "value": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 120,
- "annotation": "lego"
-}
diff --git a/providers/dns/alwaysdata/internal/fixtures/records.json b/providers/dns/alwaysdata/internal/fixtures/records.json
deleted file mode 100644
index fa207395a..000000000
--- a/providers/dns/alwaysdata/internal/fixtures/records.json
+++ /dev/null
@@ -1,28 +0,0 @@
-[
- {
- "id": 789,
- "domain": {
- "href": "/v1/domain/132/"
- },
- "name": "_acme-challenge",
- "type": "TXT",
- "value": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 120,
- "annotation": "lego"
- },
- {
- "id": 11619270,
- "domain": {
- "href": "/v1/domain/118935/"
- },
- "type": "A",
- "name": "home",
- "value": "149.202.90.65",
- "priority": null,
- "ttl": 300,
- "href": "/v1/record/11619270/",
- "annotation": "",
- "is_user_defined": true,
- "is_active": true
- }
-]
diff --git a/providers/dns/alwaysdata/internal/types.go b/providers/dns/alwaysdata/internal/types.go
deleted file mode 100644
index b1e66fa5b..000000000
--- a/providers/dns/alwaysdata/internal/types.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package internal
-
-type RecordRequest struct {
- ID int64 `json:"id,omitempty"`
- DomainID int64 `json:"domain,omitempty"`
- Name string `json:"name,omitempty"`
- Type string `json:"type,omitempty"`
- Value string `json:"value,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Annotation string `json:"annotation,omitempty"`
- IsUserDefined bool `json:"is_user_defined,omitempty"`
- IsActive bool `json:"is_active,omitempty"`
-}
-
-type Record struct {
- ID int64 `json:"id,omitempty"`
- Domain *Domain `json:"domain,omitempty"`
- Type string `json:"type,omitempty"`
- Name string `json:"name,omitempty"`
- Value string `json:"value,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Annotation string `json:"annotation,omitempty"`
- IsUserDefined bool `json:"is_user_defined,omitempty"`
- IsActive bool `json:"is_active,omitempty"`
-}
-
-type Domain struct {
- ID int64 `json:"id,omitempty"`
- Href string `json:"href,omitempty"`
- Name string `json:"name,omitempty"`
- IsInternal bool `json:"is_internal,omitempty"`
- Annotation string `json:"annotation,omitempty"`
-}
diff --git a/providers/dns/anexia/anexia.go b/providers/dns/anexia/anexia.go
deleted file mode 100644
index 3ce7e2208..000000000
--- a/providers/dns/anexia/anexia.go
+++ /dev/null
@@ -1,237 +0,0 @@
-// Package anexia implements a DNS provider for solving the DNS-01 challenge using Anexia CloudDNS.
-package anexia
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/cenkalti/backoff/v5"
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/anexia/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "ANEXIA_"
-
- EnvToken = envNamespace + "TOKEN"
- EnvAPIURL = envNamespace + "API_URL"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-const defaultTTL = 300
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Token string
- APIURL string
-
- TTL int
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, defaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 5*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Anexia CloudDNS.
-// Credentials must be passed in the environment variable: ANEXIA_TOKEN.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvToken)
- if err != nil {
- return nil, fmt.Errorf("anexia: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Token = values[EnvToken]
- config.APIURL = env.GetOrFile(EnvAPIURL)
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Anexia CloudDNS.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("anexia: the configuration of the DNS provider is nil")
- }
-
- if config.Token == "" {
- return nil, errors.New("anexia: incomplete credentials, missing token")
- }
-
- client, err := internal.NewClient(config.Token)
- if err != nil {
- return nil, fmt.Errorf("anexia: %w", err)
- }
-
- if config.APIURL != "" {
- var err error
-
- client.BaseURL, err = url.Parse(config.APIURL)
- if err != nil {
- return nil, fmt.Errorf("anexia: %w", err)
- }
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record to fulfill the dns-01 challenge.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("anexia: could not find zone for domain %q: %w", domain, err)
- }
-
- recordName, err := extractRecordName(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("anexia: %w", err)
- }
-
- zoneName := dns01.UnFqdn(authZone)
-
- recordReq := internal.Record{
- Name: recordName,
- Type: "TXT",
- RData: info.Value,
- TTL: d.config.TTL,
- }
-
- // Ignores returned zone, because of UUID unstability.
- // https://github.com/go-acme/lego/pull/2675#issuecomment-3418678194
- _, err = d.client.CreateRecord(ctx, zoneName, recordReq)
- if err != nil {
- return fmt.Errorf("anexia: new record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("anexia: could not find zone for domain %q: %w", domain, err)
- }
-
- recordName, err := extractRecordName(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("anexia: %w", err)
- }
-
- recordID, err := d.findRecordID(ctx, dns01.UnFqdn(authZone), recordName, info.Value)
- if err != nil {
- return fmt.Errorf("anexia: %w", err)
- }
-
- err = d.client.DeleteRecord(ctx, dns01.UnFqdn(authZone), recordID)
- if err != nil {
- return fmt.Errorf("anexia: delete TXT record: %w", err)
- }
-
- return nil
-}
-
-// findRecordID attempts to find the record ID from the zone response.
-// If the record is not immediately available in the response, it retries by querying the zone.
-func (d *DNSProvider) findRecordID(ctx context.Context, zoneName, recordName, rdata string) (string, error) {
- return backoff.Retry(ctx,
- func() (string, error) {
- currentZone, err := d.client.GetZone(ctx, zoneName)
- if err != nil {
- return "", backoff.Permanent(fmt.Errorf("get zone: %w", err))
- }
-
- recordID := findRecordIdentifier(currentZone, recordName, rdata)
- if recordID == "" {
- return "", fmt.Errorf("get record identifier: %w", err)
- }
-
- return recordID, nil
- },
- backoff.WithBackOff(backoff.NewConstantBackOff(5*time.Second)),
- backoff.WithMaxElapsedTime(300*time.Second),
- )
-}
-
-func findRecordIdentifier(zone *internal.Zone, recordName, rdata string) string {
- if len(zone.Revisions) == 0 {
- return ""
- }
-
- // Check the first revision (index 0) which should be the current one
-
- for _, record := range zone.Revisions[0].Records {
- if record.Name != recordName || record.Type != "TXT" {
- continue
- }
-
- if record.RData == rdata || record.RData == strconv.Quote(rdata) {
- return record.Identifier
- }
- }
-
- return ""
-}
-
-func extractRecordName(fqdn, authZone string) (string, error) {
- if dns01.UnFqdn(fqdn) == dns01.UnFqdn(authZone) {
- // "@" for the root domain instead of an empty string.
- return "@", nil
- }
-
- return dns01.ExtractSubDomain(fqdn, authZone)
-}
diff --git a/providers/dns/anexia/anexia.toml b/providers/dns/anexia/anexia.toml
deleted file mode 100644
index 332f0b8b1..000000000
--- a/providers/dns/anexia/anexia.toml
+++ /dev/null
@@ -1,31 +0,0 @@
-Name = "Anexia CloudDNS"
-Description = ''''''
-URL = "https://www.anexia-it.com/"
-Code = "anexia"
-Since = "v4.28.0"
-
-Example = '''
-ANEXIA_TOKEN=xxx \
-lego --dns anexia -d '*.example.com' -d example.com run
-'''
-
-Additional = '''
-## Description
-
-You need to create an API token in the [Anexia Engine](https://engine.anexia-it.com/).
-
-The token must have permissions to manage DNS zones and records.
-'''
-
-[Configuration]
- [Configuration.Credentials]
- ANEXIA_TOKEN = "API token for Anexia Engine"
- [Configuration.Additional]
- ANEXIA_API_URL = "API endpoint URL (default: https://engine.anexia-it.com)"
- ANEXIA_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- ANEXIA_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 300)"
- ANEXIA_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)"
- ANEXIA_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://engine.anexia-it.com/docs/en/module/clouddns/api"
diff --git a/providers/dns/anexia/anexia_test.go b/providers/dns/anexia/anexia_test.go
deleted file mode 100644
index 9960c14d1..000000000
--- a/providers/dns/anexia/anexia_test.go
+++ /dev/null
@@ -1,168 +0,0 @@
-package anexia
-
-import (
- "net/http/httptest"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvToken,
- EnvAPIURL).
- WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success with token",
- envVars: map[string]string{
- EnvToken: "secret",
- },
- },
- {
- desc: "missing token",
- envVars: map[string]string{
- EnvToken: "",
- },
- expected: "anexia: some credentials information are missing: ANEXIA_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- assert.NotNil(t, p.config)
- assert.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- token string
- expected string
- }{
- {
- desc: "success with token",
- token: "secret",
- },
- {
- desc: "missing token",
- token: "",
- expected: "anexia: incomplete credentials, missing token",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Token = test.token
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- assert.NotNil(t, p.config)
- assert.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- time.Sleep(2 * time.Second)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.Token = "secret"
- config.APIURL = server.URL
- config.HTTPClient = server.Client()
-
- return NewDNSProviderConfig(config)
- },
- servermock.CheckHeader().
- WithAuthorization("Token secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /api/clouddns/v1/zone.json/example.com/records",
- servermock.ResponseFromInternal("create_record.json"),
- servermock.CheckHeader().
- WithContentType("application/json; charset=utf-8"),
- servermock.CheckRequestJSONBodyFromInternal("create_record-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /api/clouddns/v1/zone.json/example.com",
- servermock.ResponseFromInternal("get_zone.json")).
- Route("DELETE /api/clouddns/v1/zone.json/example.com/records/12345678-1234-1234-1234-123456789abc",
- servermock.Noop()).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/anexia/internal/client.go b/providers/dns/anexia/internal/client.go
deleted file mode 100644
index 1a4159be0..000000000
--- a/providers/dns/anexia/internal/client.go
+++ /dev/null
@@ -1,158 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://engine.anexia-it.com"
-
-// Client the Anexia CloudDNS API client.
-type Client struct {
- token string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(token string) (*Client, error) {
- if token == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- token: token,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) CreateRecord(ctx context.Context, zoneName string, record Record) (*Zone, error) {
- endpoint := c.BaseURL.JoinPath("api", "clouddns", "v1", "zone.json", zoneName, "records")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
- if err != nil {
- return nil, err
- }
-
- var zone Zone
-
- err = c.do(req, &zone)
- if err != nil {
- return nil, err
- }
-
- return &zone, nil
-}
-
-func (c *Client) DeleteRecord(ctx context.Context, zoneName, recordID string) error {
- endpoint := c.BaseURL.JoinPath("api", "clouddns", "v1", "zone.json", zoneName, "records", recordID)
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) GetZone(ctx context.Context, zoneName string) (*Zone, error) {
- endpoint := c.BaseURL.JoinPath("api", "clouddns", "v1", "zone.json", zoneName)
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var zone Zone
-
- err = c.do(req, &zone)
- if err != nil {
- return nil, err
- }
-
- return &zone, nil
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Add("Authorization", fmt.Sprintf("Token %s", c.token))
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json; charset=utf-8")
- }
-
- 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
-}
diff --git a/providers/dns/anexia/internal/client_test.go b/providers/dns/anexia/internal/client_test.go
deleted file mode 100644
index be33d6f88..000000000
--- a/providers/dns/anexia/internal/client_test.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithAuthorization("Token secret"),
- )
-}
-
-func TestClient_CreateRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /api/clouddns/v1/zone.json/example.com/records",
- servermock.ResponseFromFixture("create_record.json"),
- servermock.CheckHeader().
- WithContentType("application/json; charset=utf-8"),
- servermock.CheckRequestJSONBodyFromFixture("create_record-request.json")).
- Build(t)
-
- record := Record{
- Name: "_acme-challenge",
- RData: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 300,
- Type: "TXT",
- }
-
- zone, err := client.CreateRecord(t.Context(), "example.com", record)
- require.NoError(t, err)
-
- expected := &Zone{
- Name: "example.com",
- TTL: 86400,
- ZoneName: "example.com",
- Revisions: []Revision{{
- Identifier: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- Records: []Record{{
- Identifier: "12345678-1234-1234-1234-123456789abc",
- Name: "_acme-challenge",
- RData: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 300,
- Type: "TXT",
- }},
- State: "deployed",
- }},
- }
-
- assert.Equal(t, expected, zone)
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /api/clouddns/v1/zone.json/example.com/records/12345678-1234-1234-1234-123456789abc",
- servermock.Noop()).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), "example.com", "12345678-1234-1234-1234-123456789abc")
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /api/clouddns/v1/zone.json/example.com/records/12345678-1234-1234-1234-123456789abc",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), "example.com", "12345678-1234-1234-1234-123456789abc")
- require.EqualError(t, err, "401: Unauthorized")
-}
-
-func TestClient_GetZone(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/clouddns/v1/zone.json/example.com",
- servermock.ResponseFromFixture("get_zone.json")).
- Build(t)
-
- zone, err := client.GetZone(t.Context(), "example.com")
- require.NoError(t, err)
-
- expected := &Zone{
- Identifier: "fdb355ffd07c48aba3d4f6bf6a116296",
- Name: "example.com",
- TTL: 3600,
- ZoneName: "",
- Revisions: []Revision{{
- Identifier: "eeed7e08-f1ad-442b-9e75-369a0958c7d8",
- Records: []Record{
- {
- Identifier: "5ced498b-c89d-4487-824d-c03ded84f849",
- Immutable: true,
- Name: "@",
- RData: "acns02.xaas.systems.",
- Region: "9a1609af9dae4ce1a4ef63f51d305321",
- TTL: 3600,
- Type: "NS",
- },
- {
- Identifier: "12345678-1234-1234-1234-123456789abc",
- Immutable: false,
- Name: "_acme-challenge",
- RData: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- Region: "",
- TTL: 300,
- Type: "TXT",
- },
- },
- State: "active",
- }},
- }
-
- assert.Equal(t, expected, zone)
-}
diff --git a/providers/dns/anexia/internal/fixtures/create_record-request.json b/providers/dns/anexia/internal/fixtures/create_record-request.json
deleted file mode 100644
index e82add260..000000000
--- a/providers/dns/anexia/internal/fixtures/create_record-request.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "_acme-challenge",
- "type": "TXT",
- "rdata": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "region": "",
- "ttl": 300
-}
diff --git a/providers/dns/anexia/internal/fixtures/create_record.json b/providers/dns/anexia/internal/fixtures/create_record.json
deleted file mode 100644
index 8c4f2c149..000000000
--- a/providers/dns/anexia/internal/fixtures/create_record.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "name": "example.com",
- "zone_name": "example.com",
- "master": true,
- "dnssec_mode": "managed",
- "admin_email": "admin@example.com",
- "refresh": 10800,
- "retry": 3600,
- "expire": 604800,
- "ttl": 86400,
- "customer": "ANX12345",
- "created_at": "0001-01-01T00:00:00Z",
- "updated_at": "0001-01-01T00:00:00Z",
- "published_at": "0001-01-01T00:00:00Z",
- "is_editable": true,
- "validation_level": 0,
- "deployment_level": 0,
- "revisions": [
- {
- "created_at": "0001-01-01T00:00:00Z",
- "identifier": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "modified_at": "0001-01-01T00:00:00Z",
- "records": [
- {
- "identifier": "12345678-1234-1234-1234-123456789abc",
- "immutable": false,
- "name": "_acme-challenge",
- "rdata": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "region": "",
- "ttl": 300,
- "type": "TXT"
- }
- ],
- "serial": 1,
- "state": "deployed"
- }
- ]
-}
diff --git a/providers/dns/anexia/internal/fixtures/create_record_incomplete.json b/providers/dns/anexia/internal/fixtures/create_record_incomplete.json
deleted file mode 100644
index 0515fcde3..000000000
--- a/providers/dns/anexia/internal/fixtures/create_record_incomplete.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "example.com",
- "zone_name": "example.com",
- "master": true,
- "dnssec_mode": "managed",
- "admin_email": "admin@example.com",
- "refresh": 10800,
- "retry": 3600,
- "expire": 604800,
- "ttl": 86400,
- "customer": "ANX12345",
- "created_at": "0001-01-01T00:00:00Z",
- "updated_at": "0001-01-01T00:00:00Z",
- "published_at": "0001-01-01T00:00:00Z",
- "is_editable": true,
- "validation_level": 0,
- "deployment_level": 0,
- "revisions": [
- {
- "created_at": "0001-01-01T00:00:00Z",
- "identifier": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "modified_at": "0001-01-01T00:00:00Z",
- "records": [
- {
- "immutable": false,
- "name": "_acme-challenge",
- "rdata": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "region": "",
- "ttl": 300,
- "type": "TXT"
- }
- ],
- "serial": 1,
- "state": "deployed"
- }
- ]
-}
diff --git a/providers/dns/anexia/internal/fixtures/error.json b/providers/dns/anexia/internal/fixtures/error.json
deleted file mode 100644
index afed571fa..000000000
--- a/providers/dns/anexia/internal/fixtures/error.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "error": {
- "code": 401,
- "message": "Unauthorized"
- }
-}
diff --git a/providers/dns/anexia/internal/fixtures/get_zone.json b/providers/dns/anexia/internal/fixtures/get_zone.json
deleted file mode 100644
index 6e54594ff..000000000
--- a/providers/dns/anexia/internal/fixtures/get_zone.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "identifier": "fdb355ffd07c48aba3d4f6bf6a116296",
- "admin_email": "admin@example.com",
- "created_at": "2019-02-06T10:02:07.000Z",
- "current_revision": "eeed7e08-f1ad-442b-9e75-369a0958c7d8",
- "deployment_level": 100,
- "dns_servers": [
- {
- "server": "acns01.xaas.systems",
- "alias": null
- },
- {
- "server": "acns04.xaas.systems",
- "alias": null
- },
- {
- "server": "acns02.xaas.systems",
- "alias": null
- },
- {
- "server": "acns03.xaas.systems",
- "alias": null
- },
- {
- "server": "acns05.xaas.systems",
- "alias": null
- }
- ],
- "dnsCluster": null,
- "dnssec_ksk": null,
- "dnssec_mode": "unvalidated",
- "dnssec_sig_expires_at": null,
- "dnssec_zsk": null,
- "expire": 604800,
- "inherit_ns_from": null,
- "nameserver_set": null,
- "master": true,
- "master_ns": "acns02.xaas.systems.",
- "name": "example.com",
- "notify_allowed_ips": [
- "127.0.0.1"
- ],
- "published_at": "2023-06-20T08:41:06.000Z",
- "refresh": 14400,
- "revisions": [
- {
- "created_at": "2023-06-20T08:41:06.000000Z",
- "identifier": "eeed7e08-f1ad-442b-9e75-369a0958c7d8",
- "modified_at": "2023-06-20T08:41:06.000000Z",
- "records": [
- {
- "identifier": "5ced498b-c89d-4487-824d-c03ded84f849",
- "immutable": true,
- "name": "@",
- "rdata": "acns02.xaas.systems.",
- "region": "9a1609af9dae4ce1a4ef63f51d305321",
- "ttl": 3600,
- "type": "NS",
- "options": null
- },
- {
- "identifier": "12345678-1234-1234-1234-123456789abc",
- "immutable": false,
- "name": "_acme-challenge",
- "rdata": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "region": "",
- "ttl": 300,
- "Type": "TXT"
- }
- ],
- "serial": 14,
- "state": "active"
- }
- ],
- "retry": 3600,
- "ttl": 3600,
- "updated_at": "2020-06-04T18:34:22.000Z",
- "validation_level": 100,
- "whitelabel_config": null,
- "is_editable": true,
- "deploy_zone": "49459f420f614eb2a979fc7e961f83e6"
-}
diff --git a/providers/dns/anexia/internal/types.go b/providers/dns/anexia/internal/types.go
deleted file mode 100644
index f5546ca98..000000000
--- a/providers/dns/anexia/internal/types.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package internal
-
-import "fmt"
-
-type APIError struct {
- Details struct {
- Code int `json:"code"`
- Message string `json:"message"`
- } `json:"error"`
-}
-
-func (a *APIError) Error() string {
- return fmt.Sprintf("%d: %s", a.Details.Code, a.Details.Message)
-}
-
-type Zone struct {
- Identifier string `json:"identifier,omitempty"`
- Name string `json:"name,omitempty"`
- TTL int `json:"ttl,omitempty"`
- ZoneName string `json:"zone_name,omitempty"`
- Revisions []Revision `json:"revisions,omitempty"`
-}
-
-type Revision struct {
- Identifier string `json:"identifier,omitempty"`
- Records []Record `json:"records,omitempty"`
- State string `json:"state,omitempty"`
-}
-
-type Record struct {
- Identifier string `json:"identifier,omitempty"`
- Immutable bool `json:"immutable,omitempty"`
- Name string `json:"name,omitempty"`
- RData string `json:"rdata,omitempty"`
- Region string `json:"region"`
- TTL int `json:"ttl,omitempty"`
- Type string `json:"type,omitempty"`
-}
diff --git a/providers/dns/artfiles/artfiles.go b/providers/dns/artfiles/artfiles.go
deleted file mode 100644
index c918d77f6..000000000
--- a/providers/dns/artfiles/artfiles.go
+++ /dev/null
@@ -1,204 +0,0 @@
-// Package artfiles implements a DNS provider for solving the DNS-01 challenge using ArtFiles.
-package artfiles
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
- "slices"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/artfiles/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "ARTFILES_"
-
- EnvUsername = envNamespace + "USERNAME"
- EnvPassword = envNamespace + "PASSWORD"
-
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Username string
- Password string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 6*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for ArtFiles.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvUsername, EnvPassword)
- if err != nil {
- return nil, fmt.Errorf("artfiles: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Username = values[EnvUsername]
- config.Password = values[EnvPassword]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for ArtFiles.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("artfiles: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.Username, config.Password)
- if err != nil {
- return nil, fmt.Errorf("artfiles: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("artfiles: %w", err)
- }
-
- records, err := d.client.GetRecords(ctx, zone)
- if err != nil {
- return fmt.Errorf("artfiles: get records: %w", err)
- }
-
- rv := internal.RecordValue{}
-
- if len(records["TXT"]) > 0 {
- var raw string
-
- err = json.Unmarshal(records["TXT"], &raw)
- if err != nil {
- return fmt.Errorf("artfiles: unmarshal TXT records: %w", err)
- }
-
- rv = internal.ParseRecordValue(raw)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
- if err != nil {
- return fmt.Errorf("artfiles: %w", err)
- }
-
- rv.Add(subDomain, info.Value)
-
- err = d.client.SetRecords(ctx, zone, "TXT", rv)
- if err != nil {
- return fmt.Errorf("artfiles: set TXT records: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("artfiles: %w", err)
- }
-
- records, err := d.client.GetRecords(ctx, zone)
- if err != nil {
- return fmt.Errorf("artfiles: get records: %w", err)
- }
-
- var raw string
-
- err = json.Unmarshal(records["TXT"], &raw)
- if err != nil {
- return fmt.Errorf("artfiles: unmarshal TXT records: %w", err)
- }
-
- rv := internal.ParseRecordValue(raw)
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
- if err != nil {
- return fmt.Errorf("artfiles: %w", err)
- }
-
- rv.RemoveValue(subDomain, info.Value)
-
- err = d.client.SetRecords(ctx, zone, "TXT", rv)
- if err != nil {
- return fmt.Errorf("artfiles: set TXT records: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findZone(ctx context.Context, fqdn string) (string, error) {
- domains, err := d.client.GetDomains(ctx)
- if err != nil {
- return "", fmt.Errorf("artfiles: get domains: %w", err)
- }
-
- var zone string
-
- for s := range dns01.UnFqdnDomainsSeq(fqdn) {
- if slices.Contains(domains, s) {
- zone = s
- }
- }
-
- if zone == "" {
- return "", fmt.Errorf("artfiles: could not find the zone for domain %q", fqdn)
- }
-
- return zone, nil
-}
diff --git a/providers/dns/artfiles/artfiles.toml b/providers/dns/artfiles/artfiles.toml
deleted file mode 100644
index 00ff12342..000000000
--- a/providers/dns/artfiles/artfiles.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-Name = "ArtFiles"
-Description = ''''''
-URL = "https://www.artfiles.de/extras/domains/"
-Code = "artfiles"
-Since = "v4.32.0"
-
-Example = '''
-ARTFILES_USERNAME="xxx" \
-ARTFILES_PASSWORD="yyy" \
-lego --dns artfiles -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- ARTFILES_USERNAME = "API username"
- ARTFILES_PASSWORD = "API password"
- [Configuration.Additional]
- ARTFILES_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- ARTFILES_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 360)"
- ARTFILES_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- ARTFILES_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://support.artfiles.de/DCP-API#dns"
diff --git a/providers/dns/artfiles/artfiles_test.go b/providers/dns/artfiles/artfiles_test.go
deleted file mode 100644
index 42490f10d..000000000
--- a/providers/dns/artfiles/artfiles_test.go
+++ /dev/null
@@ -1,228 +0,0 @@
-package artfiles
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvUsername, EnvPassword).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvUsername: "user",
- EnvPassword: "secret",
- },
- },
- {
- desc: "missing username",
- envVars: map[string]string{
- EnvUsername: "",
- EnvPassword: "secret",
- },
- expected: "artfiles: some credentials information are missing: ARTFILES_USERNAME",
- },
- {
- desc: "missing password",
- envVars: map[string]string{
- EnvUsername: "user",
- EnvPassword: "",
- },
- expected: "artfiles: some credentials information are missing: ARTFILES_PASSWORD",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "artfiles: some credentials information are missing: ARTFILES_USERNAME,ARTFILES_PASSWORD",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- username string
- password string
- expected string
- }{
- {
- desc: "success",
- username: "user",
- password: "secret",
- },
- {
- desc: "missing username",
- password: "secret",
- expected: "artfiles: credentials missing",
- },
- {
- desc: "missing Example",
- username: "user",
- expected: "artfiles: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "artfiles: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Username = test.username
- config.Password = test.password
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.Username = "user"
- config.Password = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithBasicAuth("user", "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domain/get_domains.html",
- servermock.ResponseFromInternal("domains.txt"),
- ).
- Route("GET /dns/get_dns.html",
- servermock.ResponseFromInternal("get_dns.json"),
- servermock.CheckQueryParameter().Strict().
- With("domain", "example.com"),
- ).
- Route("POST /dns/set_dns.html",
- servermock.ResponseFromInternal("set_dns.json"),
- servermock.CheckQueryParameter().Strict().
- With("TXT", `@ "v=spf1 a mx ~all"
-_acme-challenge "TheAcmeChallenge"
-_acme-challenge "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
-_dmarc "v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;pct=100;rua=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;ri=86400;ruf=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;fo=1;rf=afrf"
-_mta-sts "v=STSv1;id=yyyymmddTHHMMSS;"
-_smtp._tls "v=TLSRPTv1;rua=mailto:someone@in.mailhardener.com"
-selector._domainkey "v=DKIM1;k=rsa;p=Base64Stuff" "MoreBase64Stuff" "Even++MoreBase64Stuff" "YesMoreBase64Stuff" "And+Yes+Even+MoreBase64Stuff" "Sure++MoreBase64Stuff" "LastBase64Stuff"
-selectorecc._domainkey "v=DKIM1;k=ed25519;p=Base64Stuff"`).
- With("domain", "example.com"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domain/get_domains.html",
- servermock.ResponseFromInternal("domains.txt"),
- ).
- Route("GET /dns/get_dns.html",
- servermock.ResponseFromInternal("get_dns.json"),
- servermock.CheckQueryParameter().Strict().
- With("domain", "example.com"),
- ).
- Route("POST /dns/set_dns.html",
- servermock.ResponseFromInternal("set_dns.json"),
- servermock.CheckQueryParameter().Strict().
- With("TXT", `@ "v=spf1 a mx ~all"
-_acme-challenge "TheAcmeChallenge"
-_dmarc "v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;pct=100;rua=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;ri=86400;ruf=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;fo=1;rf=afrf"
-_mta-sts "v=STSv1;id=yyyymmddTHHMMSS;"
-_smtp._tls "v=TLSRPTv1;rua=mailto:someone@in.mailhardener.com"
-selector._domainkey "v=DKIM1;k=rsa;p=Base64Stuff" "MoreBase64Stuff" "Even++MoreBase64Stuff" "YesMoreBase64Stuff" "And+Yes+Even+MoreBase64Stuff" "Sure++MoreBase64Stuff" "LastBase64Stuff"
-selectorecc._domainkey "v=DKIM1;k=ed25519;p=Base64Stuff"`).
- With("domain", "example.com"),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/artfiles/internal/client.go b/providers/dns/artfiles/internal/client.go
deleted file mode 100644
index 61b350511..000000000
--- a/providers/dns/artfiles/internal/client.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package internal
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://dcp.c.artfiles.de/api/"
-
-// Client the ArtFiles API client.
-type Client struct {
- username string
- password string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(username, password string) (*Client, error) {
- if username == "" || password == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- username: username,
- password: password,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) GetDomains(ctx context.Context) ([]string, error) {
- endpoint := c.BaseURL.JoinPath("domain", "get_domains.html")
-
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- raw, err := c.do(req)
- if err != nil {
- return nil, err
- }
-
- return parseDomains(string(raw))
-}
-
-func (c *Client) GetRecords(ctx context.Context, domain string) (map[string]json.RawMessage, error) {
- endpoint := c.BaseURL.JoinPath("dns", "get_dns.html")
-
- query := endpoint.Query()
- query.Set("domain", domain)
-
- endpoint.RawQuery = query.Encode()
-
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- raw, err := c.do(req)
- if err != nil {
- return nil, err
- }
-
- var result Records
-
- err = json.Unmarshal(raw, &result)
- if err != nil {
- return nil, errutils.NewUnmarshalError(req, http.StatusOK, raw, err)
- }
-
- return result.Data, nil
-}
-
-func (c *Client) SetRecords(ctx context.Context, domain, rType string, value RecordValue) error {
- endpoint := c.BaseURL.JoinPath("dns", "set_dns.html")
-
- query := endpoint.Query()
- query.Set("domain", domain)
- query.Set(rType, value.String())
-
- endpoint.RawQuery = query.Encode()
-
- req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), nil)
- if err != nil {
- return fmt.Errorf("unable to create request: %w", err)
- }
-
- _, err = c.do(req)
-
- return err
-}
-
-func (c *Client) do(req *http.Request) ([]byte, error) {
- useragent.SetHeader(req.Header)
-
- req.SetBasicAuth(c.username, c.password)
-
- if req.Method == http.MethodPost {
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- }
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return nil, errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return nil, errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- if resp.StatusCode/100 != 2 {
- return nil, errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- return raw, nil
-}
diff --git a/providers/dns/artfiles/internal/client_test.go b/providers/dns/artfiles/internal/client_test.go
deleted file mode 100644
index cc76f06f5..000000000
--- a/providers/dns/artfiles/internal/client_test.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "net/http/httptest"
- "net/url"
- "strconv"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("user", "secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithBasicAuth("user", "secret"),
- )
-}
-
-func TestClient_GetDomains(t *testing.T) {
- client := mockBuilder().
- Route("GET /domain/get_domains.html",
- servermock.ResponseFromFixture("domains.txt"),
- ).
- Build(t)
-
- zones, err := client.GetDomains(t.Context())
- require.NoError(t, err)
-
- expected := []string{"example.com", "example.org", "example.net"}
-
- assert.Equal(t, expected, zones)
-}
-
-func TestClient_GetRecords(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/get_dns.html",
- servermock.ResponseFromFixture("get_dns.json"),
- servermock.CheckQueryParameter().Strict().
- With("domain", "example.com"),
- ).
- Build(t)
-
- records, err := client.GetRecords(t.Context(), "example.com")
- require.NoError(t, err)
-
- expected := map[string]json.RawMessage{
- "A": json.RawMessage(strconv.Quote("sub1 1.2.3.4\nsub2 1.2.3.4\nsub3 1.2.3.4\nsub4 1.2.3.4\nsub5 1.2.3.4\nsub6 1.2.3.4\nsub7 1.2.3.4\nsub8 1.2.3.4\nsub9 1.2.3.4\nsub10 1.2.3.4\nsub11 1.2.3.4\nsub12 1.2.3.4\nsub13 1.2.3.4\nsub14 1.2.3.4\nsub15 1.2.3.4\nsub16 1.2.3.4\nsub17 1.2.3.4\nsub18 1.2.3.4\n@ 1.2.3.4")),
- "AAAA": json.RawMessage(strconv.Quote("")),
- "CAA": json.RawMessage(strconv.Quote("@ 128 iodef \"mailto:someone@example.tld\"\n@ 128 issue \"letsencrypt.org\"\n@ 128 issuewild \"letsencrypt.org\"")),
- "CName": json.RawMessage(strconv.Quote("some cname.to.example.tld.")),
- "MX": json.RawMessage(strconv.Quote("10 mail.example.tld.")),
- "SRV": json.RawMessage(strconv.Quote("_imap._tcp 0 0 0 .\n_imaps._tcp 0 1 993 mail.example.tld.\n_pop3._tcp 0 0 0 .\n_pop3s._tcp 0 0 0 .")),
- "TLSA": json.RawMessage(strconv.Quote("_25._tcp.mail.example.tld. 2 1 1 CBBC559B44D524D6A132BDAC672744DA3407F12AAE5D5F722C5F6C7913871C75\n_25._tcp.mail.example.tld. 2 1 1 885BF0572252C6741DC9A52F5044487FEF2A93B811CDEDFAD7624CC283B7CDD5\n_25._tcp.mail.example.tld. 2 1 1 F1440A9B76E1E41E53A4CB461329BF6337B419726BE513E42E19F1C691C5D4B2\n_465._tcp.mail.example.tld. 2 1 1 CBBC559B44D524D6A132BDAC672744DA3407F12AAE5D5F722C5F6C7913871C75\n_465._tcp.mail.example.tld. 2 1 1 885BF0572252C6741DC9A52F5044487FEF2A93B811CDEDFAD7624CC283B7CDD5\n_465._tcp.mail.example.tld. 2 1 1 F1440A9B76E1E41E53A4CB461329BF6337B419726BE513E42E19F1C691C5D4B2\n_587._tcp.mail.example.tld. 2 1 1 CBBC559B44D524D6A132BDAC672744DA3407F12AAE5D5F722C5F6C7913871C75\n_587._tcp.mail.example.tld. 2 1 1 885BF0572252C6741DC9A52F5044487FEF2A93B811CDEDFAD7624CC283B7CDD5\n_587._tcp.mail.example.tld. 2 1 1 F1440A9B76E1E41E53A4CB461329BF6337B419726BE513E42E19F1C691C5D4B2")),
- "TXT": json.RawMessage(strconv.Quote("_dmarc \"v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;pct=100;rua=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;ri=86400;ruf=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;fo=1;rf=afrf\"\n_mta-sts \"v=STSv1;id=yyyymmddTHHMMSS;\"\n_smtp._tls \"v=TLSRPTv1;rua=mailto:someone@in.mailhardener.com\"\n@ \"v=spf1 a mx ~all\"\nselector._domainkey \"v=DKIM1;k=rsa;p=Base64Stuff\" \"MoreBase64Stuff\" \"Even++MoreBase64Stuff\" \"YesMoreBase64Stuff\" \"And+Yes+Even+MoreBase64Stuff\" \"Sure++MoreBase64Stuff\" \"LastBase64Stuff\"\nselectorecc._domainkey \"v=DKIM1;k=ed25519;p=Base64Stuff\"\n_acme-challenge \"TheAcmeChallenge\"")),
- "TTL": json.RawMessage("3600"),
- "comment": json.RawMessage(strconv.Quote("TLSA RR:\nInfo -> https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html\nTest 1 -> https://stats.dnssec-tools.org/explore/?example.tld\nTest 2 -> https://dane.sys4.de/smtp/example.tld\n\nSMIMEA RR:\nGenerator -> https://www.smimea.info/smimea-generator.php\nTest -> https://www.smimea.info/smimea-test.php")),
- "nameserver": json.RawMessage(strconv.Quote("auth1.artfiles.de.\nauth2.artfiles.de.")),
- }
-
- assert.Equal(t, expected, records)
-}
-
-func TestClient_SetRecords(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/set_dns.html",
- servermock.ResponseFromFixture("set_dns.json"),
- servermock.CheckQueryParameter().Strict().
- With("TXT", "a b\nc \"d\"").
- With("domain", "example.com"),
- ).
- Build(t)
-
- err := client.SetRecords(t.Context(), "example.com", "TXT", RecordValue{"c": []string{`"d"`}, "a": []string{"b"}})
- require.NoError(t, err)
-}
diff --git a/providers/dns/artfiles/internal/fixtures/domains.txt b/providers/dns/artfiles/internal/fixtures/domains.txt
deleted file mode 100644
index b8a1247d2..000000000
--- a/providers/dns/artfiles/internal/fixtures/domains.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-example.com normal 2026-10-01 2017-09-18 163477
-example.org normal 2026-08-01 2016-07-07 156216
-example.net normal 2026-07-01 2017-06-06 162462
diff --git a/providers/dns/artfiles/internal/fixtures/get_dns.json b/providers/dns/artfiles/internal/fixtures/get_dns.json
deleted file mode 100644
index fa672e0e1..000000000
--- a/providers/dns/artfiles/internal/fixtures/get_dns.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "data": {
- "SRV": "_imap._tcp 0 0 0 .\n_imaps._tcp 0 1 993 mail.example.tld.\n_pop3._tcp 0 0 0 .\n_pop3s._tcp 0 0 0 .",
- "AAAA": "",
- "MX": "10 mail.example.tld.",
- "CAA": "@ 128 iodef \"mailto:someone@example.tld\"\n@ 128 issue \"letsencrypt.org\"\n@ 128 issuewild \"letsencrypt.org\"",
- "TTL": 3600,
- "comment": "TLSA RR:\nInfo -> https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html\nTest 1 -> https://stats.dnssec-tools.org/explore/?example.tld\nTest 2 -> https://dane.sys4.de/smtp/example.tld\n\nSMIMEA RR:\nGenerator -> https://www.smimea.info/smimea-generator.php\nTest -> https://www.smimea.info/smimea-test.php",
- "TXT": "_dmarc \"v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;pct=100;rua=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;ri=86400;ruf=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;fo=1;rf=afrf\"\n_mta-sts \"v=STSv1;id=yyyymmddTHHMMSS;\"\n_smtp._tls \"v=TLSRPTv1;rua=mailto:someone@in.mailhardener.com\"\n@ \"v=spf1 a mx ~all\"\nselector._domainkey \"v=DKIM1;k=rsa;p=Base64Stuff\" \"MoreBase64Stuff\" \"Even++MoreBase64Stuff\" \"YesMoreBase64Stuff\" \"And+Yes+Even+MoreBase64Stuff\" \"Sure++MoreBase64Stuff\" \"LastBase64Stuff\"\nselectorecc._domainkey \"v=DKIM1;k=ed25519;p=Base64Stuff\"\n_acme-challenge \"TheAcmeChallenge\"",
- "A": "sub1 1.2.3.4\nsub2 1.2.3.4\nsub3 1.2.3.4\nsub4 1.2.3.4\nsub5 1.2.3.4\nsub6 1.2.3.4\nsub7 1.2.3.4\nsub8 1.2.3.4\nsub9 1.2.3.4\nsub10 1.2.3.4\nsub11 1.2.3.4\nsub12 1.2.3.4\nsub13 1.2.3.4\nsub14 1.2.3.4\nsub15 1.2.3.4\nsub16 1.2.3.4\nsub17 1.2.3.4\nsub18 1.2.3.4\n@ 1.2.3.4",
- "nameserver": "auth1.artfiles.de.\nauth2.artfiles.de.",
- "CName": "some cname.to.example.tld.",
- "TLSA": "_25._tcp.mail.example.tld. 2 1 1 CBBC559B44D524D6A132BDAC672744DA3407F12AAE5D5F722C5F6C7913871C75\n_25._tcp.mail.example.tld. 2 1 1 885BF0572252C6741DC9A52F5044487FEF2A93B811CDEDFAD7624CC283B7CDD5\n_25._tcp.mail.example.tld. 2 1 1 F1440A9B76E1E41E53A4CB461329BF6337B419726BE513E42E19F1C691C5D4B2\n_465._tcp.mail.example.tld. 2 1 1 CBBC559B44D524D6A132BDAC672744DA3407F12AAE5D5F722C5F6C7913871C75\n_465._tcp.mail.example.tld. 2 1 1 885BF0572252C6741DC9A52F5044487FEF2A93B811CDEDFAD7624CC283B7CDD5\n_465._tcp.mail.example.tld. 2 1 1 F1440A9B76E1E41E53A4CB461329BF6337B419726BE513E42E19F1C691C5D4B2\n_587._tcp.mail.example.tld. 2 1 1 CBBC559B44D524D6A132BDAC672744DA3407F12AAE5D5F722C5F6C7913871C75\n_587._tcp.mail.example.tld. 2 1 1 885BF0572252C6741DC9A52F5044487FEF2A93B811CDEDFAD7624CC283B7CDD5\n_587._tcp.mail.example.tld. 2 1 1 F1440A9B76E1E41E53A4CB461329BF6337B419726BE513E42E19F1C691C5D4B2"
- },
- "status": "OK"
-}
diff --git a/providers/dns/artfiles/internal/fixtures/set_dns.json b/providers/dns/artfiles/internal/fixtures/set_dns.json
deleted file mode 100644
index 7cacb33e5..000000000
--- a/providers/dns/artfiles/internal/fixtures/set_dns.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "status": "OK",
- "error": ""
-}
diff --git a/providers/dns/artfiles/internal/fixtures/txt_record-multiple.txt b/providers/dns/artfiles/internal/fixtures/txt_record-multiple.txt
deleted file mode 100644
index 461489c77..000000000
--- a/providers/dns/artfiles/internal/fixtures/txt_record-multiple.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-_dmarc "v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;pct=100;rua=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;ri=86400;ruf=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;fo=1;rf=afrf"
-_mta-sts "v=STSv1;id=yyyymmddTHHMMSS;"
-_smtp._tls "v=TLSRPTv1;rua=mailto:someone@in.mailhardener.com"
-@ "v=spf1 a mx ~all"
-selector._domainkey "v=DKIM1;k=rsa;p=Base64Stuff" "MoreBase64Stuff" "Even++MoreBase64Stuff" "YesMoreBase64Stuff" "And+Yes+Even+MoreBase64Stuff" "Sure++MoreBase64Stuff" "LastBase64Stuff"
-selectorecc._domainkey "v=DKIM1;k=ed25519;p=Base64Stuff"
-_acme-challenge "xxx"
-_acme-challenge "yyy"
diff --git a/providers/dns/artfiles/internal/fixtures/txt_record.txt b/providers/dns/artfiles/internal/fixtures/txt_record.txt
deleted file mode 100644
index 5a6259b14..000000000
--- a/providers/dns/artfiles/internal/fixtures/txt_record.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-_dmarc "v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;pct=100;rua=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;ri=86400;ruf=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;fo=1;rf=afrf"
-_mta-sts "v=STSv1;id=yyyymmddTHHMMSS;"
-_smtp._tls "v=TLSRPTv1;rua=mailto:someone@in.mailhardener.com"
-@ "v=spf1 a mx ~all"
-selector._domainkey "v=DKIM1;k=rsa;p=Base64Stuff" "MoreBase64Stuff" "Even++MoreBase64Stuff" "YesMoreBase64Stuff" "And+Yes+Even+MoreBase64Stuff" "Sure++MoreBase64Stuff" "LastBase64Stuff"
-selectorecc._domainkey "v=DKIM1;k=ed25519;p=Base64Stuff"
-_acme-challenge "TheAcmeChallenge"
diff --git a/providers/dns/artfiles/internal/types.go b/providers/dns/artfiles/internal/types.go
deleted file mode 100644
index c70ab34da..000000000
--- a/providers/dns/artfiles/internal/types.go
+++ /dev/null
@@ -1,109 +0,0 @@
-package internal
-
-import (
- "encoding/csv"
- "encoding/json"
- "errors"
- "io"
- "maps"
- "slices"
- "strconv"
- "strings"
- "unicode"
-)
-
-type Records struct {
- Data map[string]json.RawMessage `json:"data"`
- Status string `json:"status"`
-}
-
-type RecordValue map[string][]string
-
-func (r RecordValue) Set(key, value string) {
- r[key] = []string{strconv.Quote(value)}
-}
-
-func (r RecordValue) Add(key, value string) {
- r[key] = append(r[key], strconv.Quote(value))
-}
-
-func (r RecordValue) Delete(key string) {
- delete(r, key)
-}
-
-func (r RecordValue) RemoveValue(key, value string) {
- if len(r[key]) == 0 {
- return
- }
-
- quotedValue := strconv.Quote(value)
-
- var data []string
-
- for _, s := range r[key] {
- if s != quotedValue {
- data = append(data, s)
- }
- }
-
- r[key] = data
-
- if len(r[key]) == 0 {
- r.Delete(key)
- }
-}
-
-func (r RecordValue) String() string {
- var parts []string
-
- for _, key := range slices.Sorted(maps.Keys(r)) {
- for _, s := range r[key] {
- parts = append(parts, key+" "+s)
- }
- }
-
- return strings.Join(parts, "\n")
-}
-
-func ParseRecordValue(lines string) RecordValue {
- data := make(RecordValue)
-
- for line := range strings.Lines(lines) {
- line = strings.TrimSpace(line)
-
- idx := strings.IndexFunc(line, unicode.IsSpace)
-
- data[line[:idx]] = append(data[line[:idx]], line[idx+1:])
- }
-
- return data
-}
-
-func parseDomains(input string) ([]string, error) {
- reader := csv.NewReader(strings.NewReader(input))
- reader.Comma = '\t'
- reader.TrimLeadingSpace = true
- reader.LazyQuotes = true
-
- var data []string
-
- for {
- record, err := reader.Read()
- if errors.Is(err, io.EOF) {
- break
- }
-
- if err != nil {
- return nil, err
- }
-
- if len(record) < 1 {
- // Malformed line
- continue
- }
-
- data = append(data, record[0])
- }
-
- return data, nil
-}
diff --git a/providers/dns/artfiles/internal/types_test.go b/providers/dns/artfiles/internal/types_test.go
deleted file mode 100644
index 3b219f39f..000000000
--- a/providers/dns/artfiles/internal/types_test.go
+++ /dev/null
@@ -1,183 +0,0 @@
-package internal
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestRecordValue_Set(t *testing.T) {
- rv := make(RecordValue)
-
- rv.Set("a", "1")
- rv.Set("b", "2")
- rv.Set("b", "3")
-
- assert.Equal(t, "a \"1\"\nb \"3\"", rv.String())
-}
-
-func TestRecordValue_Add(t *testing.T) {
- rv := make(RecordValue)
-
- rv.Add("a", "1")
- rv.Add("b", "2")
- rv.Add("b", "3")
-
- assert.Equal(t, "a \"1\"\nb \"2\"\nb \"3\"", rv.String())
-}
-
-func TestRecordValue_Delete(t *testing.T) {
- rv := make(RecordValue)
-
- rv.Set("a", "1")
- rv.Add("b", "2")
-
- rv.Delete("b")
-
- assert.Equal(t, "a \"1\"", rv.String())
-}
-
-func TestRecordValue_RemoveValue(t *testing.T) {
- testCases := []struct {
- desc string
- data map[string][]string
- toRemove map[string][]string
- expected string
- }{
- {
- desc: "remove the only value",
- data: map[string][]string{
- "a": {"1"},
- },
- toRemove: map[string][]string{
- "a": {"1"},
- },
- expected: ``,
- },
- {
- desc: "remove value in the middle",
- data: map[string][]string{
- "a": {"1", "2", "3"},
- },
- toRemove: map[string][]string{
- "a": {"2"},
- },
- expected: "a \"1\"\na \"3\"",
- },
- {
- desc: "remove value at the beginning",
- data: map[string][]string{
- "a": {"1", "2", "3"},
- },
- toRemove: map[string][]string{
- "a": {"1"},
- },
- expected: "a \"2\"\na \"3\"",
- },
- {
- desc: "remove value at the end",
- data: map[string][]string{
- "a": {"1", "2", "3"},
- },
- toRemove: map[string][]string{
- "a": {"3"},
- },
- expected: "a \"1\"\na \"2\"",
- },
- {
- desc: "remove all (delete)",
- data: map[string][]string{
- "a": {"1", "2", "3"},
- },
- toRemove: map[string][]string{
- "a": {"1", "2", "3"},
- },
- expected: ``,
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- rv := make(RecordValue)
-
- for k, values := range test.data {
- for _, v := range values {
- rv.Add(k, v)
- }
- }
-
- for k, values := range test.toRemove {
- for _, v := range values {
- rv.RemoveValue(k, v)
- }
- }
-
- assert.Equal(t, test.expected, rv.String())
- })
- }
-}
-
-func TestParseRecordValue(t *testing.T) {
- testCases := []struct {
- desc string
- filename string
- expected RecordValue
- }{
- {
- desc: "simple",
- filename: "txt_record.txt",
- expected: RecordValue{
- "@": []string{"\"v=spf1 a mx ~all\""},
- "_acme-challenge": []string{"\"TheAcmeChallenge\""},
- "_dmarc": []string{"\"v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;pct=100;rua=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;ri=86400;ruf=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;fo=1;rf=afrf\""},
- "_mta-sts": []string{"\"v=STSv1;id=yyyymmddTHHMMSS;\""},
- "_smtp._tls": []string{"\"v=TLSRPTv1;rua=mailto:someone@in.mailhardener.com\""},
- "selector._domainkey": []string{"\"v=DKIM1;k=rsa;p=Base64Stuff\" \"MoreBase64Stuff\" \"Even++MoreBase64Stuff\" \"YesMoreBase64Stuff\" \"And+Yes+Even+MoreBase64Stuff\" \"Sure++MoreBase64Stuff\" \"LastBase64Stuff\""},
- "selectorecc._domainkey": []string{"\"v=DKIM1;k=ed25519;p=Base64Stuff\""},
- },
- },
- {
- desc: "multiple values with the same key",
- filename: "txt_record-multiple.txt",
- expected: RecordValue{
- "@": []string{"\"v=spf1 a mx ~all\""},
- "_acme-challenge": []string{"\"xxx\"", "\"yyy\""},
- "_dmarc": []string{"\"v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;pct=100;rua=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;ri=86400;ruf=mailto:someone@in.mailhardener.com,mailto:postmaster@example.tld;fo=1;rf=afrf\""},
- "_mta-sts": []string{"\"v=STSv1;id=yyyymmddTHHMMSS;\""},
- "_smtp._tls": []string{"\"v=TLSRPTv1;rua=mailto:someone@in.mailhardener.com\""},
- "selector._domainkey": []string{"\"v=DKIM1;k=rsa;p=Base64Stuff\" \"MoreBase64Stuff\" \"Even++MoreBase64Stuff\" \"YesMoreBase64Stuff\" \"And+Yes+Even+MoreBase64Stuff\" \"Sure++MoreBase64Stuff\" \"LastBase64Stuff\""},
- "selectorecc._domainkey": []string{"\"v=DKIM1;k=ed25519;p=Base64Stuff\""},
- },
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- file, err := os.ReadFile(filepath.Join("fixtures", test.filename))
- require.NoError(t, err)
-
- data := ParseRecordValue(string(file))
-
- assert.Equal(t, test.expected, data)
- })
- }
-}
-
-func Test_parseDomains(t *testing.T) {
- file, err := os.ReadFile(filepath.FromSlash("./fixtures/domains.txt"))
- require.NoError(t, err)
-
- domains, err := parseDomains(string(file))
- require.NoError(t, err)
-
- expected := []string{"example.com", "example.org", "example.net"}
-
- assert.Equal(t, expected, domains)
-}
diff --git a/providers/dns/arvancloud/arvancloud.go b/providers/dns/arvancloud/arvancloud.go
index ed1d5ff7a..3dd4eee70 100644
--- a/providers/dns/arvancloud/arvancloud.go
+++ b/providers/dns/arvancloud/arvancloud.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/arvancloud/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -96,8 +95,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -167,7 +164,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("arvancloud: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
diff --git a/providers/dns/arvancloud/arvancloud.toml b/providers/dns/arvancloud/arvancloud.toml
index aa5cafb51..e94452a8b 100644
--- a/providers/dns/arvancloud/arvancloud.toml
+++ b/providers/dns/arvancloud/arvancloud.toml
@@ -6,7 +6,7 @@ Since = "v3.8.0"
Example = '''
ARVANCLOUD_API_KEY="Apikey xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
-lego --dns arvancloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns arvancloud -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/arvancloud/arvancloud_test.go b/providers/dns/arvancloud/arvancloud_test.go
index 24013c437..c31edf021 100644
--- a/providers/dns/arvancloud/arvancloud_test.go
+++ b/providers/dns/arvancloud/arvancloud_test.go
@@ -37,7 +37,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -105,7 +104,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -119,7 +117,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/arvancloud/internal/client.go b/providers/dns/arvancloud/internal/client.go
index b447d97c4..3caff392a 100644
--- a/providers/dns/arvancloud/internal/client.go
+++ b/providers/dns/arvancloud/internal/client.go
@@ -70,7 +70,6 @@ func (c *Client) getRecords(ctx context.Context, domain, search string) ([]DNSRe
}
response := &apiResponse[[]DNSRecord]{}
-
err = c.do(req, http.StatusOK, response)
if err != nil {
return nil, fmt.Errorf("could not get records %s: Domain: %s: %w", search, domain, err)
@@ -90,7 +89,6 @@ func (c *Client) CreateRecord(ctx context.Context, domain string, record DNSReco
}
response := &apiResponse[*DNSRecord]{}
-
err = c.do(req, http.StatusCreated, response)
if err != nil {
return nil, fmt.Errorf("could not create record; Domain: %s: %w", domain, err)
diff --git a/providers/dns/arvancloud/internal/client_test.go b/providers/dns/arvancloud/internal/client_test.go
index 183a8acfd..d13bc6f34 100644
--- a/providers/dns/arvancloud/internal/client_test.go
+++ b/providers/dns/arvancloud/internal/client_test.go
@@ -81,10 +81,8 @@ func TestClient_CreateRecord(t *testing.T) {
func TestClient_DeleteRecord(t *testing.T) {
const apiKey = "myKeyC"
- const (
- domain = "example.com"
- recordID = "recordId"
- )
+ const domain = "example.com"
+ const recordID = "recordId"
client := mockBuilder(apiKey).
Route("DELETE /cdn/4.0/domains/"+domain+"/dns-records/"+recordID, nil).
diff --git a/providers/dns/auroradns/auroradns.go b/providers/dns/auroradns/auroradns.go
index 50d2fbc25..8a497ffa4 100644
--- a/providers/dns/auroradns/auroradns.go
+++ b/providers/dns/auroradns/auroradns.go
@@ -10,8 +10,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/miekg/dns"
"github.com/nrdcg/auroradns"
)
@@ -53,11 +51,10 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- config *Config
- client *auroradns.Client
-
recordIDs map[string]string
recordIDsMu sync.Mutex
+ config *Config
+ client *auroradns.Client
}
// NewDNSProvider returns a DNSProvider instance configured for AuroraDNS.
@@ -96,7 +93,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("aurora: %w", err)
}
- client, err := auroradns.NewClient(clientdebug.Wrap(tr.Client()), auroradns.WithBaseURL(config.BaseURL))
+ client, err := auroradns.NewClient(tr.Client(), auroradns.WithBaseURL(config.BaseURL))
if err != nil {
return nil, fmt.Errorf("aurora: %w", err)
}
@@ -164,7 +161,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("aurora: unknown recordID for %q", info.EffectiveFQDN)
}
- authZone, err := dns01.FindZoneByFqdn(dns.Fqdn(info.EffectiveFQDN))
+ authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(info.EffectiveFQDN))
if err != nil {
return fmt.Errorf("aurora: could not find zone for domain %q: %w", domain, err)
}
diff --git a/providers/dns/auroradns/auroradns.toml b/providers/dns/auroradns/auroradns.toml
index 59b5e7ab1..e000e015e 100644
--- a/providers/dns/auroradns/auroradns.toml
+++ b/providers/dns/auroradns/auroradns.toml
@@ -7,7 +7,7 @@ Since = "v0.4.0"
Example = '''
AURORA_API_KEY=xxxxx \
AURORA_SECRET=yyyyyy \
-lego --dns auroradns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns auroradns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/auroradns/auroradns_test.go b/providers/dns/auroradns/auroradns_test.go
index 8a9835d9c..1619ee586 100644
--- a/providers/dns/auroradns/auroradns_test.go
+++ b/providers/dns/auroradns/auroradns_test.go
@@ -71,7 +71,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -161,7 +160,7 @@ func TestDNSProvider_Present(t *testing.T) {
Build(t)
err := provider.Present("example.com", "", "foobar")
- require.NoError(t, err)
+ require.NoError(t, err, "fail to create TXT record")
}
func TestDNSProvider_CleanUp(t *testing.T) {
@@ -186,8 +185,8 @@ func TestDNSProvider_CleanUp(t *testing.T) {
Build(t)
err := provider.Present("example.com", "", "foobar")
- require.NoError(t, err)
+ require.NoError(t, err, "fail to create TXT record")
err = provider.CleanUp("example.com", "", "foobar")
- require.NoError(t, err)
+ require.NoError(t, err, "fail to remove TXT record")
}
diff --git a/providers/dns/autodns/autodns.go b/providers/dns/autodns/autodns.go
index 8a9361bc0..61f3005f1 100644
--- a/providers/dns/autodns/autodns.go
+++ b/providers/dns/autodns/autodns.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/autodns/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -106,8 +105,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
@@ -128,9 +125,9 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
Value: info.Value,
}}
- _, err := d.client.AddRecords(context.Background(), info.EffectiveFQDN, records)
+ _, err := d.client.AddTxtRecords(context.Background(), info.EffectiveFQDN, records)
if err != nil {
- return fmt.Errorf("autodns: add record: %w", err)
+ return fmt.Errorf("autodns: %w", err)
}
return nil
@@ -147,9 +144,8 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
Value: info.Value,
}}
- _, err := d.client.RemoveRecords(context.Background(), info.EffectiveFQDN, records)
- if err != nil {
- return fmt.Errorf("autodns: remove record: %w", err)
+ if err := d.client.RemoveTXTRecords(context.Background(), info.EffectiveFQDN, records); err != nil {
+ return fmt.Errorf("autodns: %w", err)
}
return nil
diff --git a/providers/dns/autodns/autodns.toml b/providers/dns/autodns/autodns.toml
index 2798d4cee..78015e431 100644
--- a/providers/dns/autodns/autodns.toml
+++ b/providers/dns/autodns/autodns.toml
@@ -7,7 +7,7 @@ Since = "v3.2.0"
Example = '''
AUTODNS_API_USER=username \
AUTODNS_API_PASSWORD=supersecretpassword \
-lego --dns autodns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns autodns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/autodns/autodns_test.go b/providers/dns/autodns/autodns_test.go
index 632d24705..bc9f3067e 100644
--- a/providers/dns/autodns/autodns_test.go
+++ b/providers/dns/autodns/autodns_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -132,7 +131,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -146,7 +144,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/autodns/internal/client.go b/providers/dns/autodns/internal/client.go
index d92490a60..1fc9589ea 100644
--- a/providers/dns/autodns/internal/client.go
+++ b/providers/dns/autodns/internal/client.go
@@ -43,22 +43,23 @@ func NewClient(username, password string, clientContext int) *Client {
}
}
-// AddRecords adds records.
-func (c *Client) AddRecords(ctx context.Context, domain string, records []*ResourceRecord) (*DataZoneResponse, error) {
+// AddTxtRecords adds TXT records.
+func (c *Client) AddTxtRecords(ctx context.Context, domain string, records []*ResourceRecord) (*Zone, error) {
zoneStream := &ZoneStream{Adds: records}
return c.updateZone(ctx, domain, zoneStream)
}
-// RemoveRecords removes records.
-func (c *Client) RemoveRecords(ctx context.Context, domain string, records []*ResourceRecord) (*DataZoneResponse, error) {
+// RemoveTXTRecords removes TXT records.
+func (c *Client) RemoveTXTRecords(ctx context.Context, domain string, records []*ResourceRecord) error {
zoneStream := &ZoneStream{Removes: records}
- return c.updateZone(ctx, domain, zoneStream)
+ _, err := c.updateZone(ctx, domain, zoneStream)
+ return err
}
// https://github.com/InterNetX/domainrobot-api/blob/bdc8fe92a2f32fcbdb29e30bf6006ab446f81223/src/domainrobot.json#L21090
-func (c *Client) updateZone(ctx context.Context, domain string, zoneStream *ZoneStream) (*DataZoneResponse, error) {
+func (c *Client) updateZone(ctx context.Context, domain string, zoneStream *ZoneStream) (*Zone, error) {
endpoint := c.BaseURL.JoinPath("zone", domain, "_stream")
req, err := newJSONRequest(ctx, http.MethodPost, endpoint, zoneStream)
@@ -66,12 +67,12 @@ func (c *Client) updateZone(ctx context.Context, domain string, zoneStream *Zone
return nil, err
}
- var resp *DataZoneResponse
- if err := c.do(req, &resp); err != nil {
+ var zone *Zone
+ if err := c.do(req, &zone); err != nil {
return nil, err
}
- return resp, nil
+ return zone, nil
}
func (c *Client) do(req *http.Request, result any) error {
@@ -86,7 +87,7 @@ func (c *Client) do(req *http.Request, result any) error {
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
+ return errutils.NewUnexpectedResponseStatusCodeError(req, resp)
}
if result == nil {
@@ -129,16 +130,3 @@ 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
-}
diff --git a/providers/dns/autodns/internal/client_test.go b/providers/dns/autodns/internal/client_test.go
index 9b0968fdc..6fc31ca34 100644
--- a/providers/dns/autodns/internal/client_test.go
+++ b/providers/dns/autodns/internal/client_test.go
@@ -1,7 +1,6 @@
package internal
import (
- "net/http"
"net/http/httptest"
"net/url"
"testing"
@@ -25,7 +24,7 @@ func mockBuilder() *servermock.Builder[*Client] {
WithJSONHeaders())
}
-func TestClient_AddRecords(t *testing.T) {
+func TestClient_AddTxtRecords(t *testing.T) {
client := mockBuilder().
Route("POST /zone/example.com/_stream",
servermock.ResponseFromFixture("add_record.json"),
@@ -34,81 +33,28 @@ func TestClient_AddRecords(t *testing.T) {
With("X-Domainrobot-Context", "123")).
Build(t)
- records := []*ResourceRecord{{
- Name: "example.com",
- TTL: 600,
- Type: "TXT",
- Value: "txtTXTtxt",
- }}
+ records := []*ResourceRecord{{}}
- resp, err := client.AddRecords(t.Context(), "example.com", records)
+ zone, err := client.AddTxtRecords(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",
- },
- },
+ expected := &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)
+ assert.Equal(t, expected, zone)
}
-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) {
+func TestClient_RemoveTXTRecords(t *testing.T) {
client := mockBuilder().
Route("POST /zone/example.com/_stream",
servermock.ResponseFromFixture("remove_record.json"),
@@ -117,58 +63,8 @@ func TestClient_RemoveRecords(t *testing.T) {
With("X-Domainrobot-Context", "123")).
Build(t)
- records := []*ResourceRecord{{
- Name: "example.com",
- TTL: 600,
- Type: "TXT",
- Value: "txtTXTtxt",
- }}
+ records := []*ResourceRecord{{}}
- resp, err := client.RemoveRecords(t.Context(), "example.com", records)
+ err := client.RemoveTXTRecords(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)
}
diff --git a/providers/dns/autodns/internal/fixtures/add_record-request.json b/providers/dns/autodns/internal/fixtures/add_record-request.json
index 6105c77ac..b798b4fbd 100644
--- a/providers/dns/autodns/internal/fixtures/add_record-request.json
+++ b/providers/dns/autodns/internal/fixtures/add_record-request.json
@@ -1,10 +1,10 @@
{
"adds": [
{
- "name": "example.com",
- "ttl": 600,
- "type": "TXT",
- "value": "txtTXTtxt"
+ "name": "",
+ "ttl": 0,
+ "type": "",
+ "value": ""
}
],
"rems": null
diff --git a/providers/dns/autodns/internal/fixtures/add_record.json b/providers/dns/autodns/internal/fixtures/add_record.json
index a0ce66ba6..4a95f0784 100644
--- a/providers/dns/autodns/internal/fixtures/add_record.json
+++ b/providers/dns/autodns/internal/fixtures/add_record.json
@@ -1,41 +1,14 @@
{
- "stid": "20251121-appf4923-126284",
- "messages": [
+ "origin": "example.com",
+ "resourceRecords": [
{
- "text": "string",
- "notice": "string",
- "messages": [
- "string"
- ],
- "objects": [
- {
- "type": "string",
- "value": "string"
- }
- ],
- "code": "string",
- "status": "SUCCESS"
+ "name": "example.com",
+ "ttl": 120,
+ "type": "TXT",
+ "value": "txt",
+ "pref": 1
}
],
- "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"
- }
- ]
+ "action": "xxx",
+ "virtualNameServer": "yyy"
}
diff --git a/providers/dns/autodns/internal/fixtures/error.json b/providers/dns/autodns/internal/fixtures/error.json
deleted file mode 100644
index 2ed635d58..000000000
--- a/providers/dns/autodns/internal/fixtures/error.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "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"
- }
-}
diff --git a/providers/dns/autodns/internal/fixtures/remove_record-request.json b/providers/dns/autodns/internal/fixtures/remove_record-request.json
index 92361403e..0702c7367 100644
--- a/providers/dns/autodns/internal/fixtures/remove_record-request.json
+++ b/providers/dns/autodns/internal/fixtures/remove_record-request.json
@@ -2,10 +2,10 @@
"adds": null,
"rems": [
{
- "name": "example.com",
- "ttl": 600,
- "type": "TXT",
- "value": "txtTXTtxt"
+ "name": "",
+ "ttl": 0,
+ "type": "",
+ "value": ""
}
]
}
diff --git a/providers/dns/autodns/internal/fixtures/remove_record.json b/providers/dns/autodns/internal/fixtures/remove_record.json
index a0ce66ba6..4a95f0784 100644
--- a/providers/dns/autodns/internal/fixtures/remove_record.json
+++ b/providers/dns/autodns/internal/fixtures/remove_record.json
@@ -1,41 +1,14 @@
{
- "stid": "20251121-appf4923-126284",
- "messages": [
+ "origin": "example.com",
+ "resourceRecords": [
{
- "text": "string",
- "notice": "string",
- "messages": [
- "string"
- ],
- "objects": [
- {
- "type": "string",
- "value": "string"
- }
- ],
- "code": "string",
- "status": "SUCCESS"
+ "name": "example.com",
+ "ttl": 120,
+ "type": "TXT",
+ "value": "txt",
+ "pref": 1
}
],
- "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"
- }
- ]
+ "action": "xxx",
+ "virtualNameServer": "yyy"
}
diff --git a/providers/dns/autodns/internal/types.go b/providers/dns/autodns/internal/types.go
index 8a06f4889..93fd678ca 100644
--- a/providers/dns/autodns/internal/types.go
+++ b/providers/dns/autodns/internal/types.go
@@ -1,133 +1,33 @@
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"`
- 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
+ Text string `json:"text"`
+ Messages []string `json:"messages"`
+ Objects []string `json:"objects"`
+ Code string `json:"code"`
+ Status string `json:"status"`
}
type ResponseStatus struct {
Code string `json:"code"`
Text string `json:"text"`
- 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 string `json:"type"`
}
type ResponseObject struct {
- Type string `json:"type"`
- Value string `json:"value"`
- Summary int32 `json:"summary"`
- Data *ResponseObjectData `json:"data"`
+ Type string `json:"type"`
+ Value string `json:"value"`
+ Summary int32 `json:"summary"`
+ Data string
}
-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"`
+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"`
}
// ResourceRecord holds a resource record.
@@ -143,10 +43,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.
diff --git a/providers/dns/axelname/axelname.go b/providers/dns/axelname/axelname.go
index 96d26236e..033ccc92b 100644
--- a/providers/dns/axelname/axelname.go
+++ b/providers/dns/axelname/axelname.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/axelname/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -85,8 +84,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/axelname/axelname.toml b/providers/dns/axelname/axelname.toml
index 1e2ad6e72..ee348d5d8 100644
--- a/providers/dns/axelname/axelname.toml
+++ b/providers/dns/axelname/axelname.toml
@@ -7,7 +7,7 @@ Since = "v4.23.0"
Example = '''
AXELNAME_NICKNAME="yyy" \
AXELNAME_TOKEN="xxx" \
-lego --dns axelname -d '*.example.com' -d example.com run
+lego --email you@example.com --dns axelname -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/axelname/axelname_test.go b/providers/dns/axelname/axelname_test.go
index 1a8bac971..52c4f38b9 100644
--- a/providers/dns/axelname/axelname_test.go
+++ b/providers/dns/axelname/axelname_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -121,7 +120,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -135,7 +133,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/axelname/internal/client.go b/providers/dns/axelname/internal/client.go
index f2defec87..f6cf079e6 100644
--- a/providers/dns/axelname/internal/client.go
+++ b/providers/dns/axelname/internal/client.go
@@ -174,7 +174,6 @@ 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)
diff --git a/providers/dns/azion/azion.go b/providers/dns/azion/azion.go
index 5584ece0b..b319e1779 100644
--- a/providers/dns/azion/azion.go
+++ b/providers/dns/azion/azion.go
@@ -6,12 +6,12 @@ import (
"errors"
"fmt"
"net/http"
+ "sync"
"time"
"github.com/aziontech/azionapi-go-sdk/idns"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -55,6 +55,9 @@ func NewDefaultConfig() *Config {
type DNSProvider struct {
config *Config
client *idns.APIClient
+
+ recordIDs map[string]int32
+ recordIDsMu sync.Mutex
}
// NewDNSProvider returns a DNSProvider instance configured for Azion.
@@ -89,13 +92,12 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
clientConfig.HTTPClient = config.HTTPClient
}
- clientConfig.HTTPClient = clientdebug.Wrap(clientConfig.HTTPClient)
-
client := idns.NewAPIClient(clientConfig)
return &DNSProvider{
- config: config,
- client: client,
+ config: config,
+ client: client,
+ recordIDs: make(map[string]int32),
}, nil
}
@@ -132,7 +134,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
record.SetTtl(int32(d.config.TTL))
var resp *idns.PostOrPutRecordResponse
-
if existingRecord != nil {
// Update existing record by adding the new value to the existing ones
record.SetAnswersList(append(existingRecord.GetAnswersList(), info.Value))
@@ -156,6 +157,11 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return errors.New("azion: create zone record error")
}
+ results := resp.GetResults()
+ d.recordIDsMu.Lock()
+ d.recordIDs[token] = results.GetId()
+ d.recordIDsMu.Unlock()
+
return nil
}
@@ -175,6 +181,13 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("azion: %w", err)
}
+ defer func() {
+ // Cleans the record ID.
+ d.recordIDsMu.Lock()
+ delete(d.recordIDs, token)
+ d.recordIDsMu.Unlock()
+ }()
+
existingRecord, err := d.findExistingTXTRecord(ctxAuth, zone.GetId(), subDomain)
if err != nil {
return fmt.Errorf("azion: find existing record: %w", err)
@@ -187,7 +200,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
currentAnswers := existingRecord.GetAnswersList()
var updatedAnswers []string
-
for _, answer := range currentAnswers {
if answer != info.Value {
updatedAnswers = append(updatedAnswers, answer)
diff --git a/providers/dns/azion/azion.toml b/providers/dns/azion/azion.toml
index 52df20ab5..eacfe74a6 100644
--- a/providers/dns/azion/azion.toml
+++ b/providers/dns/azion/azion.toml
@@ -6,7 +6,7 @@ URL = "https://www.azion.com/en/products/edge-dns/"
Example = '''
AZION_PERSONAL_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns azion -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azion -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/azion/azion_test.go b/providers/dns/azion/azion_test.go
index 517594cdc..b3b553114 100644
--- a/providers/dns/azion/azion_test.go
+++ b/providers/dns/azion/azion_test.go
@@ -40,7 +40,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -100,7 +99,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -114,7 +112,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/azure/azure.go b/providers/dns/azure/azure.go
index 8bfc6cfe1..5702acd8a 100644
--- a/providers/dns/azure/azure.go
+++ b/providers/dns/azure/azure.go
@@ -8,7 +8,6 @@ import (
"io"
"net/http"
"net/url"
- "strings"
"time"
"github.com/Azure/go-autorest/autorest"
@@ -38,8 +37,6 @@ const (
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
)
-const EnvLegoAzureBypassDeprecation = "LEGO_AZURE_BYPASS_DEPRECATION"
-
const defaultMetadataEndpoint = "http://169.254.169.254"
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
@@ -92,7 +89,6 @@ type DNSProvider struct {
// If the credentials are _not_ set via the environment,
// then it will attempt to get a bearer token via the instance metadata service.
// see: https://github.com/Azure/go-autorest/blob/v10.14.0/autorest/azure/auth/auth.go#L38-L42
-//
// Deprecated: use azuredns instead.
func NewDNSProvider() (*DNSProvider, error) {
config := NewDefaultConfig()
@@ -100,7 +96,6 @@ func NewDNSProvider() (*DNSProvider, error) {
environmentName := env.GetOrFile(EnvEnvironment)
if environmentName != "" {
var environment aazure.Environment
-
switch environmentName {
case "china":
environment = aazure.ChinaCloud
@@ -129,25 +124,12 @@ func NewDNSProvider() (*DNSProvider, error) {
}
// NewDNSProviderConfig return a DNSProvider instance configured for Azure.
-//
// Deprecated: use azuredns instead.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
return nil, errors.New("azure: the configuration of the DNS provider is nil")
}
- if !env.GetOrDefaultBool(EnvLegoAzureBypassDeprecation, false) {
- var msg strings.Builder
-
- msg.WriteString("azure: ")
- msg.WriteString("The `azure` provider has been deprecated since 2023, and replaced by `azuredns` provider. ")
- msg.WriteString("It can be TEMPORARILY reactivated by using the environment variable `LEGO_AZURE_BYPASS_DEPRECATION=true`. ")
- msg.WriteString("The `azure` provider will be removed in a future release, please migrate to the `azuredns` provider. ")
- msg.WriteString("The documentation of the `azuredns` provider can be found at https://go-acme.github.io/lego/dns/azuredns/")
-
- return nil, errors.New(msg.String())
- }
-
if config.HTTPClient == nil {
config.HTTPClient = &http.Client{Timeout: 5 * time.Second}
}
@@ -166,7 +148,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if subsID == "" {
return nil, errors.New("azure: SubscriptionID is missing")
}
-
config.SubscriptionID = subsID
}
@@ -179,7 +160,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if resGroup == "" {
return nil, errors.New("azure: ResourceGroup is missing")
}
-
config.ResourceGroup = resGroup
}
diff --git a/providers/dns/azure/azure_test.go b/providers/dns/azure/azure_test.go
index c4fec4359..496168362 100644
--- a/providers/dns/azure/azure_test.go
+++ b/providers/dns/azure/azure_test.go
@@ -14,7 +14,6 @@ import (
const envDomain = envNamespace + "DOMAIN"
var envTest = tester.NewEnvTest(
- EnvLegoAzureBypassDeprecation,
EnvEnvironment,
EnvClientID,
EnvClientSecret,
@@ -55,11 +54,8 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
- test.envVars[EnvLegoAzureBypassDeprecation] = "true"
-
envTest.Apply(test.envVars)
p, err := NewDNSProvider()
@@ -143,11 +139,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
},
}
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
- envTest.Apply(map[string]string{EnvLegoAzureBypassDeprecation: "true"})
-
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
config := NewDefaultConfig()
@@ -167,7 +158,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
} else {
mux.HandleFunc("/", test.handler)
}
-
config.MetadataEndpoint = server.URL
p, err := NewDNSProviderConfig(config)
@@ -196,7 +186,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -210,7 +199,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/azure/private.go b/providers/dns/azure/private.go
index f7c6a75b7..d6c9fc7bd 100644
--- a/providers/dns/azure/private.go
+++ b/providers/dns/azure/private.go
@@ -54,7 +54,6 @@ func (d *dnsProviderPrivate) Present(domain, token, keyAuth string) error {
// Construct unique TXT records using map
uniqRecords := map[string]struct{}{info.Value: {}}
-
if rset.RecordSetProperties != nil && rset.TxtRecords != nil {
for _, txtRecord := range *rset.TxtRecords {
// Assume Value doesn't contain multiple strings
@@ -82,7 +81,6 @@ func (d *dnsProviderPrivate) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("azure: %w", err)
}
-
return nil
}
@@ -108,7 +106,6 @@ func (d *dnsProviderPrivate) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("azure: %w", err)
}
-
return nil
}
diff --git a/providers/dns/azure/public.go b/providers/dns/azure/public.go
index 194956c9c..8e6fa182a 100644
--- a/providers/dns/azure/public.go
+++ b/providers/dns/azure/public.go
@@ -54,7 +54,6 @@ func (d *dnsProviderPublic) Present(domain, token, keyAuth string) error {
// Construct unique TXT records using map
uniqRecords := map[string]struct{}{info.Value: {}}
-
if rset.RecordSetProperties != nil && rset.TxtRecords != nil {
for _, txtRecord := range *rset.TxtRecords {
// Assume Value doesn't contain multiple strings
@@ -82,7 +81,6 @@ func (d *dnsProviderPublic) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("azure: %w", err)
}
-
return nil
}
@@ -108,7 +106,6 @@ func (d *dnsProviderPublic) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("azure: %w", err)
}
-
return nil
}
diff --git a/providers/dns/azuredns/azuredns.go b/providers/dns/azuredns/azuredns.go
index b8effadea..860d19691 100644
--- a/providers/dns/azuredns/azuredns.go
+++ b/providers/dns/azuredns/azuredns.go
@@ -3,15 +3,20 @@
package azuredns
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "strings"
"time"
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
+ "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/go-acme/lego/v4/challenge"
+ "github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -28,21 +33,10 @@ const (
EnvClientID = envNamespace + "CLIENT_ID"
EnvClientSecret = envNamespace + "CLIENT_SECRET"
- EnvOIDCToken = envNamespace + "OIDC_TOKEN"
- EnvOIDCTokenFilePath = envNamespace + "OIDC_TOKEN_FILE_PATH"
- EnvOIDCRequestURL = envNamespace + "OIDC_REQUEST_URL"
- EnvGitHubOIDCRequestURL = "ACTIONS_ID_TOKEN_REQUEST_URL"
- altEnvArmOIDCRequestURL = "ARM_OIDC_REQUEST_URL"
- EnvOIDCRequestToken = envNamespace + "OIDC_REQUEST_TOKEN"
- EnvGitHubOIDCRequestToken = "ACTIONS_ID_TOKEN_REQUEST_TOKEN"
- altEnvArmOIDCRequestToken = "ARM_OIDC_REQUEST_TOKEN"
-
- EnvServiceConnectionID = envNamespace + "SERVICE_CONNECTION_ID"
- altEnvServiceConnectionID = "SERVICE_CONNECTION_ID"
- altEnvArmAdoPipelineServiceConnectionID = "ARM_ADO_PIPELINE_SERVICE_CONNECTION_ID"
- altEnvArmOIDCAzureServiceConnectionID = "ARM_OIDC_AZURE_SERVICE_CONNECTION_ID"
- EnvSystemAccessToken = envNamespace + "SYSTEM_ACCESS_TOKEN"
- altEnvSystemAccessToken = "SYSTEM_ACCESSTOKEN"
+ EnvOIDCToken = envNamespace + "OIDC_TOKEN"
+ EnvOIDCTokenFilePath = envNamespace + "OIDC_TOKEN_FILE_PATH"
+ EnvOIDCRequestURL = envNamespace + "OIDC_REQUEST_URL"
+ EnvOIDCRequestToken = envNamespace + "OIDC_REQUEST_TOKEN"
EnvAuthMethod = envNamespace + "AUTH_METHOD"
EnvAuthMSITimeout = envNamespace + "AUTH_MSI_TIMEOUT"
@@ -52,6 +46,9 @@ const (
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
+
+ EnvGitHubOIDCRequestURL = "ACTIONS_ID_TOKEN_REQUEST_URL"
+ EnvGitHubOIDCRequestToken = "ACTIONS_ID_TOKEN_REQUEST_TOKEN"
)
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
@@ -76,9 +73,6 @@ type Config struct {
OIDCRequestURL string
OIDCRequestToken string
- ServiceConnectionID string
- SystemAccessToken string
-
AuthMethod string
AuthMSITimeout time.Duration
@@ -140,22 +134,13 @@ func NewDNSProvider() (*DNSProvider, error) {
config.ServiceDiscoveryFilter = env.GetOrFile(EnvServiceDiscoveryFilter)
oidcValues, _ := env.GetWithFallback(
- []string{EnvOIDCRequestURL, EnvGitHubOIDCRequestURL, altEnvArmOIDCRequestURL},
- []string{EnvOIDCRequestToken, EnvGitHubOIDCRequestToken, altEnvArmOIDCRequestToken},
+ []string{EnvOIDCRequestURL, EnvGitHubOIDCRequestURL},
+ []string{EnvOIDCRequestToken, EnvGitHubOIDCRequestToken},
)
config.OIDCRequestURL = oidcValues[EnvOIDCRequestURL]
config.OIDCRequestToken = oidcValues[EnvOIDCRequestToken]
- // https://registry.terraform.io/providers/hashicorp/Azurerm/latest/docs/guides/service_principal_oidc
- pipelineValues, _ := env.GetWithFallback(
- []string{EnvServiceConnectionID, altEnvServiceConnectionID, altEnvArmAdoPipelineServiceConnectionID, altEnvArmOIDCAzureServiceConnectionID},
- []string{EnvSystemAccessToken, altEnvArmOIDCRequestToken, altEnvSystemAccessToken},
- )
-
- config.ServiceConnectionID = pipelineValues[EnvServiceConnectionID]
- config.SystemAccessToken = pipelineValues[EnvSystemAccessToken]
-
config.AuthMethod = env.GetOrFile(EnvAuthMethod)
config.AuthMSITimeout = env.GetOrDefaultSecond(EnvAuthMSITimeout, 2*time.Second)
@@ -172,8 +157,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
config.HTTPClient = &http.Client{Timeout: 5 * time.Second}
}
- config.HTTPClient = clientdebug.Wrap(config.HTTPClient)
-
credentials, err := getCredentials(config)
if err != nil {
return nil, fmt.Errorf("azuredns: Unable to retrieve valid credentials: %w", err)
@@ -210,3 +193,88 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return d.provider.CleanUp(domain, token, keyAuth)
}
+
+func getCredentials(config *Config) (azcore.TokenCredential, error) {
+ clientOptions := azcore.ClientOptions{Cloud: config.Environment}
+
+ switch strings.ToLower(config.AuthMethod) {
+ case "env":
+ if config.ClientID != "" && config.ClientSecret != "" && config.TenantID != "" {
+ return azidentity.NewClientSecretCredential(config.TenantID, config.ClientID, config.ClientSecret,
+ &azidentity.ClientSecretCredentialOptions{ClientOptions: clientOptions})
+ }
+
+ return azidentity.NewEnvironmentCredential(&azidentity.EnvironmentCredentialOptions{ClientOptions: clientOptions})
+
+ case "wli":
+ return azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{ClientOptions: clientOptions})
+
+ case "msi":
+ cred, err := azidentity.NewManagedIdentityCredential(&azidentity.ManagedIdentityCredentialOptions{ClientOptions: clientOptions})
+ if err != nil {
+ return nil, err
+ }
+
+ return &timeoutTokenCredential{cred: cred, timeout: config.AuthMSITimeout}, nil
+
+ case "cli":
+ var credOptions *azidentity.AzureCLICredentialOptions
+ if config.TenantID != "" {
+ credOptions = &azidentity.AzureCLICredentialOptions{TenantID: config.TenantID}
+ }
+ return azidentity.NewAzureCLICredential(credOptions)
+
+ case "oidc":
+ err := checkOIDCConfig(config)
+ if err != nil {
+ return nil, err
+ }
+
+ return azidentity.NewClientAssertionCredential(config.TenantID, config.ClientID, getOIDCAssertion(config), &azidentity.ClientAssertionCredentialOptions{ClientOptions: clientOptions})
+
+ default:
+ return azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ClientOptions: clientOptions})
+ }
+}
+
+// timeoutTokenCredential wraps a TokenCredential to add a timeout.
+type timeoutTokenCredential struct {
+ cred azcore.TokenCredential
+ timeout time.Duration
+}
+
+// GetToken implements the azcore.TokenCredential interface.
+func (w *timeoutTokenCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
+ if w.timeout <= 0 {
+ return w.cred.GetToken(ctx, opts)
+ }
+
+ ctxTimeout, cancel := context.WithTimeout(ctx, w.timeout)
+ defer cancel()
+
+ tk, err := w.cred.GetToken(ctxTimeout, opts)
+ if ce := ctxTimeout.Err(); errors.Is(ce, context.DeadlineExceeded) {
+ return tk, azidentity.NewCredentialUnavailableError("managed identity timed out")
+ }
+
+ w.timeout = 0
+
+ return tk, err
+}
+
+func getZoneName(config *Config, fqdn string) (string, error) {
+ if config.ZoneName != "" {
+ return config.ZoneName, nil
+ }
+
+ authZone, err := dns01.FindZoneByFqdn(fqdn)
+ if err != nil {
+ return "", fmt.Errorf("could not find zone for %s: %w", fqdn, err)
+ }
+
+ if authZone == "" {
+ return "", errors.New("empty zone name")
+ }
+
+ return authZone, nil
+}
diff --git a/providers/dns/azuredns/azuredns.toml b/providers/dns/azuredns/azuredns.toml
index 7c800ce7e..8d14105cb 100644
--- a/providers/dns/azuredns/azuredns.toml
+++ b/providers/dns/azuredns/azuredns.toml
@@ -10,32 +10,32 @@ Example = '''
AZURE_CLIENT_ID= \
AZURE_TENANT_ID= \
AZURE_CLIENT_SECRET= \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using client certificate
AZURE_CLIENT_ID= \
AZURE_TENANT_ID= \
AZURE_CLIENT_CERTIFICATE_PATH= \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Azure CLI
az login \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Managed Identity (Azure VM)
AZURE_TENANT_ID= \
AZURE_RESOURCE_GROUP= \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Managed Identity (Azure Arc)
AZURE_TENANT_ID= \
IMDS_ENDPOINT=http://localhost:40342 \
IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token \
-lego --dns azuredns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
'''
@@ -174,10 +174,6 @@ This authentication method can be specifically used by setting the `AZURE_AUTH_M
Open ID Connect is a mechanism that establish a trust relationship between a running environment and the Azure AD identity provider.
It can be enabled by setting the `AZURE_AUTH_METHOD` environment variable to `oidc`.
-### Azure DevOps Pipelines
-
-It can be enabled by setting the `AZURE_AUTH_METHOD` environment variable to `pipeline`.
-
'''
[Configuration]
diff --git a/providers/dns/azuredns/azuredns_test.go b/providers/dns/azuredns/azuredns_test.go
index 594a0d6a3..7ddb4de45 100644
--- a/providers/dns/azuredns/azuredns_test.go
+++ b/providers/dns/azuredns/azuredns_test.go
@@ -35,7 +35,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -62,7 +61,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -76,7 +74,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/azuredns/credentials.go b/providers/dns/azuredns/credentials.go
deleted file mode 100644
index a38b3f7dd..000000000
--- a/providers/dns/azuredns/credentials.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package azuredns
-
-import (
- "context"
- "errors"
- "fmt"
- "strings"
- "time"
-
- "github.com/Azure/azure-sdk-for-go/sdk/azcore"
- "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
- "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
- "github.com/go-acme/lego/v4/challenge/dns01"
-)
-
-const (
- authMethodEnv = "env"
- authMethodWLI = "wli"
- authMethodMSI = "msi"
- authMethodCLI = "cli"
- authMethodOIDC = "oidc"
- authMethodPipeline = "pipeline"
-)
-
-//nolint:gocyclo // The complexity is related to the number of possible configurations.
-func getCredentials(config *Config) (azcore.TokenCredential, error) {
- clientOptions := azcore.ClientOptions{Cloud: config.Environment}
-
- switch strings.ToLower(config.AuthMethod) {
- case authMethodEnv:
- if config.ClientID != "" && config.ClientSecret != "" && config.TenantID != "" {
- return azidentity.NewClientSecretCredential(config.TenantID, config.ClientID, config.ClientSecret,
- &azidentity.ClientSecretCredentialOptions{ClientOptions: clientOptions})
- }
-
- return azidentity.NewEnvironmentCredential(&azidentity.EnvironmentCredentialOptions{ClientOptions: clientOptions})
-
- case authMethodWLI:
- return azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{ClientOptions: clientOptions})
-
- case authMethodMSI:
- cred, err := azidentity.NewManagedIdentityCredential(&azidentity.ManagedIdentityCredentialOptions{ClientOptions: clientOptions})
- if err != nil {
- return nil, err
- }
-
- return &timeoutTokenCredential{cred: cred, timeout: config.AuthMSITimeout}, nil
-
- case authMethodCLI:
- var credOptions *azidentity.AzureCLICredentialOptions
- if config.TenantID != "" {
- credOptions = &azidentity.AzureCLICredentialOptions{TenantID: config.TenantID}
- }
-
- return azidentity.NewAzureCLICredential(credOptions)
-
- case authMethodOIDC:
- err := checkOIDCConfig(config)
- if err != nil {
- return nil, err
- }
-
- return azidentity.NewClientAssertionCredential(config.TenantID, config.ClientID, getOIDCAssertion(config), &azidentity.ClientAssertionCredentialOptions{ClientOptions: clientOptions})
-
- case authMethodPipeline:
- err := checkPipelineConfig(config)
- if err != nil {
- return nil, err
- }
-
- // Uses the env var `SYSTEM_OIDCREQUESTURI`,
- // but the constant is not exported,
- // and there is no way to set it programmatically.
- // https://github.com/Azure/azure-sdk-for-go/blob/aae2fb75ffccafc669db72bebc3c1a66332f48d7/sdk/azidentity/azure_pipelines_credential.go#L22
- // https://github.com/Azure/azure-sdk-for-go/blob/aae2fb75ffccafc669db72bebc3c1a66332f48d7/sdk/azidentity/azure_pipelines_credential.go#L79
-
- return azidentity.NewAzurePipelinesCredential(config.TenantID, config.ClientID, config.ServiceConnectionID, config.SystemAccessToken, &azidentity.AzurePipelinesCredentialOptions{ClientOptions: clientOptions})
-
- default:
- return azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ClientOptions: clientOptions})
- }
-}
-
-// timeoutTokenCredential wraps a TokenCredential to add a timeout.
-type timeoutTokenCredential struct {
- cred azcore.TokenCredential
- timeout time.Duration
-}
-
-// GetToken implements the azcore.TokenCredential interface.
-func (w *timeoutTokenCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
- if w.timeout <= 0 {
- return w.cred.GetToken(ctx, opts)
- }
-
- ctxTimeout, cancel := context.WithTimeout(ctx, w.timeout)
- defer cancel()
-
- tk, err := w.cred.GetToken(ctxTimeout, opts)
- if ce := ctxTimeout.Err(); errors.Is(ce, context.DeadlineExceeded) {
- return tk, azidentity.NewCredentialUnavailableError("managed identity timed out")
- }
-
- w.timeout = 0
-
- return tk, err
-}
-
-func getZoneName(config *Config, fqdn string) (string, error) {
- if config.ZoneName != "" {
- return config.ZoneName, nil
- }
-
- authZone, err := dns01.FindZoneByFqdn(fqdn)
- if err != nil {
- return "", fmt.Errorf("could not find zone for %s: %w", fqdn, err)
- }
-
- if authZone == "" {
- return "", errors.New("empty zone name")
- }
-
- return authZone, nil
-}
-
-func checkPipelineConfig(config *Config) error {
- if config.ServiceConnectionID == "" {
- return errors.New("azuredns: ServiceConnectionID is missing")
- }
-
- if config.SystemAccessToken == "" {
- return errors.New("azuredns: SystemAccessToken is missing")
- }
-
- return nil
-}
diff --git a/providers/dns/azuredns/private.go b/providers/dns/azuredns/private.go
index 43b39ed14..24fb3d5ee 100644
--- a/providers/dns/azuredns/private.go
+++ b/providers/dns/azuredns/private.go
@@ -181,7 +181,6 @@ func (c privateZoneClient) Delete(ctx context.Context, subDomain string) (armpri
func privateUniqueRecords(recordSet armprivatedns.RecordSet, value string) map[string]struct{} {
uniqRecords := map[string]struct{}{value: {}}
-
if recordSet.Properties != nil && recordSet.Properties.TxtRecords != nil {
for _, txtRecord := range recordSet.Properties.TxtRecords {
// Assume Value doesn't contain multiple strings
diff --git a/providers/dns/azuredns/public.go b/providers/dns/azuredns/public.go
index 79b6e783f..f7e46150d 100644
--- a/providers/dns/azuredns/public.go
+++ b/providers/dns/azuredns/public.go
@@ -179,7 +179,6 @@ func (c publicZoneClient) Delete(ctx context.Context, subDomain string) (armdns.
func publicUniqueRecords(recordSet armdns.RecordSet, value string) map[string]struct{} {
uniqRecords := map[string]struct{}{value: {}}
-
if recordSet.Properties != nil && recordSet.Properties.TxtRecords != nil {
for _, txtRecord := range recordSet.Properties.TxtRecords {
// Assume Value doesn't contain multiple strings
diff --git a/providers/dns/azuredns/servicediscovery.go b/providers/dns/azuredns/servicediscovery.go
index 50a41da37..882e19241 100644
--- a/providers/dns/azuredns/servicediscovery.go
+++ b/providers/dns/azuredns/servicediscovery.go
@@ -46,7 +46,6 @@ func discoverDNSZones(ctx context.Context, config *Config, credentials azcore.To
}
zones := map[string]ServiceDiscoveryZone{}
-
for {
// create the query request
request := armresourcegraph.QueryRequest{
diff --git a/providers/dns/baiducloud/baiducloud.go b/providers/dns/baiducloud/baiducloud.go
index 1dc8d90ed..fc317904a 100644
--- a/providers/dns/baiducloud/baiducloud.go
+++ b/providers/dns/baiducloud/baiducloud.go
@@ -24,9 +24,6 @@ const (
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
)
-// 300 is the minimum TTL for free users.
-const defaultTTL = 300
-
// Config is used to configure the creation of the DNSProvider.
type Config struct {
AccessKeyID string
@@ -40,7 +37,7 @@ type Config struct {
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, defaultTTL),
+ TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
}
@@ -106,7 +103,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
Rr: subDomain,
Type: "TXT",
Value: info.Value,
- Ttl: ptr.Pointer(int32(d.config.TTL)),
}
err = d.client.CreateRecord(dns01.UnFqdn(authZone), crr, "")
@@ -126,7 +122,14 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("baiducloud: could not find zone for domain %q: %w", domain, err)
}
- recordID, err := d.findRecordID(dns01.UnFqdn(authZone), info.Value)
+ lrr := &baidudns.ListRecordRequest{}
+
+ recordResponse, err := d.client.ListRecord(dns01.UnFqdn(authZone), lrr)
+ if err != nil {
+ return fmt.Errorf("baiducloud: list record: %w", err)
+ }
+
+ recordID, err := findRecordID(recordResponse, info)
if err != nil {
return fmt.Errorf("baiducloud: find record: %w", err)
}
@@ -139,26 +142,11 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return nil
}
-func (d *DNSProvider) findRecordID(zoneName, tokenValue string) (string, error) {
- lrr := &baidudns.ListRecordRequest{}
-
- for {
- recordResponse, err := d.client.ListRecord(zoneName, lrr)
- if err != nil {
- return "", fmt.Errorf("baiducloud: list record: %w", err)
+func findRecordID(recordResponse *baidudns.ListRecordResponse, info dns01.ChallengeInfo) (string, error) {
+ for _, record := range recordResponse.Records {
+ if record.Type == "TXT" && record.Value == info.Value {
+ return record.Id, nil
}
-
- for _, record := range recordResponse.Records {
- if record.Type == "TXT" && record.Value == tokenValue {
- return record.Id, nil
- }
- }
-
- if !recordResponse.IsTruncated {
- break
- }
-
- lrr.Marker = recordResponse.NextMarker
}
return "", errors.New("record not found")
diff --git a/providers/dns/baiducloud/baiducloud.toml b/providers/dns/baiducloud/baiducloud.toml
index 54f1f6312..941d90b2c 100644
--- a/providers/dns/baiducloud/baiducloud.toml
+++ b/providers/dns/baiducloud/baiducloud.toml
@@ -7,7 +7,7 @@ Since = "v4.23.0"
Example = '''
BAIDUCLOUD_ACCESS_KEY_ID="xxx" \
BAIDUCLOUD_SECRET_ACCESS_KEY="yyy" \
-lego --dns baiducloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns baiducloud -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -17,7 +17,7 @@ lego --dns baiducloud -d '*.example.com' -d example.com run
[Configuration.Additional]
BAIDUCLOUD_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
BAIDUCLOUD_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- BAIDUCLOUD_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)"
+ BAIDUCLOUD_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
[Links]
API = "https://cloud.baidu.com/doc/DNS/s/El4s7lssr"
diff --git a/providers/dns/baiducloud/baiducloud_test.go b/providers/dns/baiducloud/baiducloud_test.go
index 483bfaf5e..3cc411323 100644
--- a/providers/dns/baiducloud/baiducloud_test.go
+++ b/providers/dns/baiducloud/baiducloud_test.go
@@ -48,7 +48,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -123,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/beget/beget.go b/providers/dns/beget/beget.go
deleted file mode 100644
index d4449deb8..000000000
--- a/providers/dns/beget/beget.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Package beget implements a DNS provider for solving the DNS-01 challenge using beget.com DNS.
-package beget
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/beget/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "BEGET_"
-
- EnvUsername = envNamespace + "USERNAME"
- EnvPassword = envNamespace + "PASSWORD"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Username string
- Password string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, 300),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 5*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 30*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for beget.com.
-// Credentials must be passed in the environment variables:
-// BEGET_USERNAME and BEGET_PASSWORD.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvUsername, EnvPassword)
- if err != nil {
- return nil, fmt.Errorf("beget: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Username = values[EnvUsername]
- config.Password = values[EnvPassword]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for beget.com.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("beget: the configuration of the DNS provider is nil")
- }
-
- if config.Username == "" || config.Password == "" {
- return nil, errors.New("beget: incomplete credentials, missing username and/or password")
- }
-
- client := internal.NewClient(config.Username, config.Password)
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{config: config, client: client}, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- records, err := d.client.GetTXTRecords(ctx, dns01.UnFqdn(info.EffectiveFQDN))
- if err != nil {
- return fmt.Errorf("beget: get TXT records: %w", err)
- }
-
- records = append(records, internal.Record{
- Value: info.Value,
- Data: "", // NOTE: there are 2 fields in the API for the same thing.
- Priority: 10,
- TTL: d.config.TTL,
- })
-
- err = d.client.ChangeTXTRecord(ctx, dns01.UnFqdn(info.EffectiveFQDN), records)
- if err != nil {
- return fmt.Errorf("beget: failed to create TXT records [domain: %s]: %w",
- dns01.UnFqdn(info.EffectiveFQDN), err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- records, err := d.client.GetTXTRecords(ctx, dns01.UnFqdn(info.EffectiveFQDN))
- if err != nil {
- return fmt.Errorf("beget: get TXT records: %w", err)
- }
-
- if len(records) == 0 {
- return nil
- }
-
- var updatedRecords []internal.Record
-
- for _, record := range records {
- if record.Data == info.Value {
- continue
- }
-
- updatedRecords = append(updatedRecords, record)
- }
-
- err = d.client.ChangeTXTRecord(ctx, dns01.UnFqdn(info.EffectiveFQDN), updatedRecords)
- if err != nil {
- return fmt.Errorf("beget: failed to remove TXT records [domain: %s]: %w",
- dns01.UnFqdn(info.EffectiveFQDN), err)
- }
-
- return nil
-}
diff --git a/providers/dns/beget/beget.toml b/providers/dns/beget/beget.toml
deleted file mode 100644
index 4ed26d850..000000000
--- a/providers/dns/beget/beget.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-Name = "Beget.com"
-Description = ''''''
-URL = "https://beget.com/"
-Code = "beget"
-Since = "v4.27.0"
-
-Example = '''
-BEGET_USERNAME=xxxxxx \
-BEGET_PASSWORD=yyyyyy \
-lego --dns beget -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- BEGET_USERNAME = "API username"
- BEGET_PASSWORD = "API password"
- [Configuration.Additional]
- BEGET_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 30)"
- BEGET_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 300)"
- BEGET_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- BEGET_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://beget.com/ru/kb/api/funkczii-upravleniya-dns"
diff --git a/providers/dns/beget/beget_test.go b/providers/dns/beget/beget_test.go
deleted file mode 100644
index 3cfb3c0b4..000000000
--- a/providers/dns/beget/beget_test.go
+++ /dev/null
@@ -1,232 +0,0 @@
-package beget
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvUsername, EnvPassword).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvUsername: "123",
- EnvPassword: "456",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{
- EnvUsername: "",
- EnvPassword: "",
- },
- expected: "beget: some credentials information are missing: BEGET_USERNAME,BEGET_PASSWORD",
- },
- {
- desc: "missing username",
- envVars: map[string]string{
- EnvUsername: "",
- EnvPassword: "456",
- },
- expected: "beget: some credentials information are missing: BEGET_USERNAME",
- },
- {
- desc: "missing password",
- envVars: map[string]string{
- EnvUsername: "123",
- EnvPassword: "",
- },
- expected: "beget: some credentials information are missing: BEGET_PASSWORD",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- username string
- password string
- expected string
- }{
- {
- desc: "success",
- username: "123",
- password: "456",
- },
- {
- desc: "missing credentials",
- username: "",
- password: "",
- expected: "beget: incomplete credentials, missing username and/or password",
- },
- {
- desc: "missing username",
- username: "",
- password: "456",
- expected: "beget: incomplete credentials, missing username and/or password",
- },
- {
- desc: "missing password",
- username: "123",
- password: "",
- expected: "beget: incomplete credentials, missing username and/or password",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Username = test.username
- config.Password = test.password
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- assert.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- assert.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- assert.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- assert.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.Username = "user"
- config.Password = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckQueryParameter().
- With("login", "user").
- With("passwd", "secret").
- With("input_format", "json").
- With("output_format", "json"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /dns/getData",
- servermock.ResponseFromInternal("getData-real.json"),
- servermock.CheckQueryParameter().
- With("input_data", `{"fqdn":"_acme-challenge.example.com"}`),
- ).
- Route("GET /dns/changeRecords",
- servermock.ResponseFromInternal("changeRecords-doc.json"),
- servermock.CheckQueryParameter().
- With("input_data", `{"fqdn":"_acme-challenge.example.com","records":{"TXT":[{"txtdata":"v=spf1 redirect=beget.com","ttl":300},{"value":"ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY","priority":10,"ttl":300}]}}`),
- ).
- Build(t)
-
- err := provider.Present("example.com", "", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /dns/getData",
- servermock.ResponseFromInternal("getData.json"),
- servermock.CheckQueryParameter().
- With("input_data", `{"fqdn":"_acme-challenge.example.com"}`),
- ).
- Route("GET /dns/changeRecords",
- servermock.ResponseFromInternal("changeRecords-doc.json"),
- servermock.CheckQueryParameter().
- With("input_data", `{"fqdn":"_acme-challenge.example.com","records":{"TXT":[{"txtdata":"foo","ttl":300}]}}`),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp_empty(t *testing.T) {
- provider := mockBuilder().
- Route("GET /dns/getData",
- servermock.ResponseFromInternal("getData_empty.json"),
- servermock.CheckQueryParameter().
- With("input_data", `{"fqdn":"_acme-challenge.example.com"}`),
- ).
- Route("/",
- servermock.Noop().WithStatusCode(http.StatusInternalServerError)).
- Build(t)
-
- err := provider.CleanUp("example.com", "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/beget/internal/client.go b/providers/dns/beget/internal/client.go
deleted file mode 100644
index 9b9746ba2..000000000
--- a/providers/dns/beget/internal/client.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package internal
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
-)
-
-const defaultBaseURL = "https://api.beget.com/api/"
-
-// Client the beget.com client.
-type Client struct {
- login string
- password string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient Creates a beget.com client.
-func NewClient(login, password string) *Client {
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- login: login,
- password: password,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 5 * time.Second},
- }
-}
-
-// GetTXTRecords returns TXT records.
-// https://beget.com/ru/kb/api/funkczii-upravleniya-dns#getdata
-func (c *Client) GetTXTRecords(ctx context.Context, domain string) ([]Record, error) {
- request := GetRecordsRequest{Fqdn: domain}
-
- resp, err := c.doRequest(ctx, request, "dns", "getData")
- if err != nil {
- return nil, err
- }
-
- err = resp.HasError()
- if err != nil {
- return nil, err
- }
-
- result := GetRecordsResult{}
-
- err = json.Unmarshal(resp.Answer.Result, &result)
- if err != nil {
- return nil, fmt.Errorf("unmarshal result: %s: %w", string(resp.Answer.Result), err)
- }
-
- return result.Records.TXT, nil
-}
-
-// ChangeTXTRecord changes TXT records.
-// https://beget.com/ru/kb/api/funkczii-upravleniya-dns#changerecords
-func (c *Client) ChangeTXTRecord(ctx context.Context, domain string, records []Record) error {
- request := ChangeRecordsRequest{
- Fqdn: domain,
- Records: RecordList{TXT: records},
- }
-
- resp, err := c.doRequest(ctx, request, "dns", "changeRecords")
- if err != nil {
- return err
- }
-
- return resp.HasError()
-}
-
-func (c *Client) doRequest(ctx context.Context, data any, fragments ...string) (*APIResponse, error) {
- endpoint := c.BaseURL.JoinPath(fragments...)
-
- inputData, err := json.Marshal(data)
- if err != nil {
- return nil, fmt.Errorf("failed to mashall input data: %w", err)
- }
-
- query := endpoint.Query()
- query.Add("input_data", string(inputData))
- query.Add("login", c.login)
- query.Add("passwd", c.password)
- query.Add("input_format", "json")
- query.Add("output_format", "json")
- endpoint.RawQuery = query.Encode()
-
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return nil, errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return nil, parseError(req, resp)
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return nil, errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- var apiResp APIResponse
-
- err = json.Unmarshal(raw, &apiResp)
- if err != nil {
- return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return &apiResp, nil
-}
-
-func parseError(req *http.Request, resp *http.Response) error {
- raw, _ := io.ReadAll(resp.Body)
-
- var apiResp APIResponse
-
- err := json.Unmarshal(raw, &apiResp)
- if err != nil {
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- return fmt.Errorf("[status code %d] %w", resp.StatusCode, apiResp)
-}
diff --git a/providers/dns/beget/internal/client_test.go b/providers/dns/beget/internal/client_test.go
deleted file mode 100644
index 4c127abf1..000000000
--- a/providers/dns/beget/internal/client_test.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package internal
-
-import (
- "context"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client := NewClient("user", "secret")
-
- client.HTTPClient = server.Client()
- client.BaseURL, _ = url.Parse(server.URL)
-
- return client, nil
- },
- servermock.CheckQueryParameter().
- With("login", "user").
- With("passwd", "secret").
- With("input_format", "json").
- With("output_format", "json"),
- )
-}
-
-func TestClient_GetTXTRecords(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/getData",
- servermock.ResponseFromFixture("getData-real.json"),
- servermock.CheckQueryParameter().
- With("input_data", `{"fqdn":"example.com"}`),
- ).
- Build(t)
-
- data, err := client.GetTXTRecords(context.Background(), "example.com")
- require.NoError(t, err)
-
- expected := []Record{{Data: "v=spf1 redirect=beget.com", TTL: 300}}
-
- assert.Equal(t, expected, data)
-}
-
-func TestClient_ChangeTXTRecord(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/changeRecords",
- servermock.ResponseFromFixture("changeRecords-doc.json"),
- servermock.CheckQueryParameter().
- With("input_data", `{"fqdn":"sub.example.com","records":{"TXT":[{"value":"txtTXTtxt","priority":10,"ttl":300}]}}`),
- ).
- Build(t)
-
- records := []Record{{Value: "txtTXTtxt", TTL: 300, Priority: 10}}
-
- err := client.ChangeTXTRecord(context.Background(), "sub.example.com", records)
- require.NoError(t, err)
-}
-
-func TestClient_ChangeTXTRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/changeRecords",
- servermock.ResponseFromFixture("error.json")).
- Build(t)
-
- records := []Record{{Data: "txtTXTtxt", TTL: 300}}
-
- err := client.ChangeTXTRecord(context.Background(), "sub.example.com", records)
- require.Error(t, err)
-
- require.EqualError(t, err, "API error: NO_SUCH_METHOD: No such method")
-}
-
-func TestClient_ChangeTXTRecord_answer_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/changeRecords",
- servermock.ResponseFromFixture("answer_error.json")).
- Build(t)
-
- records := []Record{{Data: "txtTXTtxt", TTL: 300}}
-
- err := client.ChangeTXTRecord(context.Background(), "sub.example.com", records)
- require.Error(t, err)
-
- require.EqualError(t, err, "API answer error: INVALID_DATA: Login length cannot be greater than 12 characters")
-}
-
-func TestClient_ChangeTXTRecord_remove(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/changeRecords",
- servermock.ResponseFromFixture("changeRecords-doc.json"),
- servermock.CheckQueryParameter().
- With("input_data", `{"fqdn":"sub.example.com","records":{}}`),
- ).
- Build(t)
-
- err := client.ChangeTXTRecord(context.Background(), "sub.example.com", nil)
- require.NoError(t, err)
-}
diff --git a/providers/dns/beget/internal/fixtures/answer_error.json b/providers/dns/beget/internal/fixtures/answer_error.json
deleted file mode 100644
index 12f5fdda7..000000000
--- a/providers/dns/beget/internal/fixtures/answer_error.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "status": "success",
- "answer": {
- "status": "error",
- "errors": [
- {
- "error_code": "INVALID_DATA",
- "error_text": "Login length cannot be greater than 12 characters"
- }
- ]
- }
-}
diff --git a/providers/dns/beget/internal/fixtures/changeRecords-doc.json b/providers/dns/beget/internal/fixtures/changeRecords-doc.json
deleted file mode 100644
index 4c182d4e6..000000000
--- a/providers/dns/beget/internal/fixtures/changeRecords-doc.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "status": "success",
- "answer": {
- "status": "success",
- "result": {
- "A": [
- {
- "priority": 10,
- "value": "127.0.0.1"
- }
- ],
- "MX": [
- {
- "priority": 10,
- "value": "mx1.beget.ru"
- },
- {
- "priority": 20,
- "value": "mx2.beget.ru"
- }
- ],
- "TXT": [
- {
- "priority": 10,
- "value": "TXT record"
- }
- ]
- }
- }
-}
-
diff --git a/providers/dns/beget/internal/fixtures/error.json b/providers/dns/beget/internal/fixtures/error.json
deleted file mode 100644
index 1dd2a111e..000000000
--- a/providers/dns/beget/internal/fixtures/error.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "status": "error",
- "error_text": "No such method",
- "error_code": "NO_SUCH_METHOD"
-}
diff --git a/providers/dns/beget/internal/fixtures/getData-doc.json b/providers/dns/beget/internal/fixtures/getData-doc.json
deleted file mode 100644
index bed5b7461..000000000
--- a/providers/dns/beget/internal/fixtures/getData-doc.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "status": "success",
- "answer": {
- "status": "success",
- "result": {
- "is_under_control": 1,
- "is_beget_dns": 1,
- "is_subdomain": 0,
- "fqdn": "beget.ru",
- "records": {
- "DNS": [
- {
- "value": "ns1.beget.ru",
- "priority": 10
- },
- {
- "value": "ns2.beget.ru",
- "priority": 20
- }
- ],
- "DNS_IP": [
- {
- "value": null,
- "priority": 10
- },
- {
- "value": null,
- "priority": 20
- }
- ],
- "A": [
- {
- "value": "91.106.201.65",
- "priority": "0"
- }
- ],
- "MX": [
- {
- "value": "mx1.beget.ru",
- "priority": "10"
- },
- {
- "value": "mx2.beget.ru",
- "priority": "20"
- }
- ],
- "TXT": [
- {
- "value": "",
- "priority": 0
- }
- ]
- },
- "set_type": 1
- }
- }
-}
-
diff --git a/providers/dns/beget/internal/fixtures/getData-real.json b/providers/dns/beget/internal/fixtures/getData-real.json
deleted file mode 100644
index 700c756e8..000000000
--- a/providers/dns/beget/internal/fixtures/getData-real.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "status": "success",
- "answer": {
- "status": "success",
- "result": {
- "is_under_control": true,
- "is_beget_dns": true,
- "is_subdomain": false,
- "fqdn": "example.com",
- "records": {
- "MX": [
- {
- "ttl": 300,
- "exchange": "mx2.beget.com.",
- "preference": 20
- },
- {
- "ttl": 300,
- "exchange": "mx1.beget.com.",
- "preference": 10
- }
- ],
- "TXT": [
- {
- "ttl": 300,
- "txtdata": "v=spf1 redirect=beget.com"
- }
- ],
- "A": [
- {
- "ttl": 300,
- "address": "1.2.3.4"
- }
- ],
- "DNS": [
- {
- "value": "ns1.beget.pro"
- },
- {
- "value": "ns2.beget.pro"
- },
- {
- "value": "ns1.beget.com"
- },
- {
- "value": "ns2.beget.com"
- }
- ],
- "DNS_IP": [
- {
- "value": ""
- },
- {
- "value": ""
- },
- {
- "value": ""
- },
- {
- "value": ""
- }
- ]
- },
- "set_type": 1
- }
- }
-}
diff --git a/providers/dns/beget/internal/fixtures/getData.json b/providers/dns/beget/internal/fixtures/getData.json
deleted file mode 100644
index 571b6ac31..000000000
--- a/providers/dns/beget/internal/fixtures/getData.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "status": "success",
- "answer": {
- "status": "success",
- "result": {
- "is_under_control": true,
- "is_beget_dns": true,
- "is_subdomain": false,
- "fqdn": "_acme-challenge.example.com",
- "records": {
- "MX": [
- {
- "ttl": 300,
- "exchange": "mx2.beget.com.",
- "preference": 20
- },
- {
- "ttl": 300,
- "exchange": "mx1.beget.com.",
- "preference": 10
- }
- ],
- "TXT": [
- {
- "ttl": 300,
- "txtdata": "foo"
- }
- ],
- "A": [
- {
- "ttl": 300,
- "address": "1.2.3.4"
- }
- ],
- "DNS": [
- {
- "value": "ns1.beget.pro"
- },
- {
- "value": "ns2.beget.pro"
- },
- {
- "value": "ns1.beget.com"
- },
- {
- "value": "ns2.beget.com"
- }
- ],
- "DNS_IP": [
- {
- "value": ""
- },
- {
- "value": ""
- },
- {
- "value": ""
- },
- {
- "value": ""
- }
- ]
- },
- "set_type": 1
- }
- }
-}
diff --git a/providers/dns/beget/internal/fixtures/getData_empty.json b/providers/dns/beget/internal/fixtures/getData_empty.json
deleted file mode 100644
index ea819eeca..000000000
--- a/providers/dns/beget/internal/fixtures/getData_empty.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "status": "success",
- "answer": {
- "status": "success",
- "result": {
- "is_under_control": true,
- "is_beget_dns": true,
- "is_subdomain": false,
- "fqdn": "_acme-challenge.example.com",
- "set_type": 1
- }
- }
-}
diff --git a/providers/dns/beget/internal/types.go b/providers/dns/beget/internal/types.go
deleted file mode 100644
index f453bf628..000000000
--- a/providers/dns/beget/internal/types.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-)
-
-const successResult = "success"
-
-// APIResponse is the representation of an API response.
-type APIResponse struct {
- Status string `json:"status"`
-
- Answer *Answer `json:"answer,omitempty"`
-
- ErrorCode string `json:"error_code,omitempty"`
- ErrorText string `json:"error_text,omitempty"`
-}
-
-func (a APIResponse) Error() string {
- return fmt.Sprintf("API %s: %s: %s", a.Status, a.ErrorCode, a.ErrorText)
-}
-
-// HasError returns an error is the response contains an error.
-func (a APIResponse) HasError() error {
- if a.Status != successResult {
- return a
- }
-
- if a.Answer == nil || a.Status != successResult || a.Answer.Status != successResult {
- return a.Answer
- }
-
- return nil
-}
-
-// Answer is the representation of an API response answer.
-type Answer struct {
- Status string `json:"status,omitempty"`
- Result json.RawMessage `json:"result,omitempty"`
-
- Errors []AnswerError `json:"errors,omitempty"`
- ErrorCode string `json:"error_code,omitempty"`
- ErrorText string `json:"error_text,omitempty"`
-}
-
-type AnswerError struct {
- ErrorCode string `json:"error_code,omitempty"`
- ErrorText string `json:"error_text,omitempty"`
-}
-
-func (a Answer) Error() string {
- parts := []string{fmt.Sprintf("API answer %s", a.Status)}
-
- if a.ErrorCode != "" {
- parts = append(parts, a.ErrorCode)
- }
-
- if a.ErrorText != "" {
- parts = append(parts, a.ErrorText)
- }
-
- if len(a.Errors) > 0 {
- for _, e := range a.Errors {
- parts = append(parts, e.ErrorCode, e.ErrorText)
- }
- }
-
- return strings.Join(parts, ": ")
-}
-
-// GetRecordsRequest data representation for data get request.
-type GetRecordsRequest struct {
- Fqdn string `json:"fqdn,omitempty"`
-}
-
-// ChangeRecordsRequest data representation for data change request.
-type ChangeRecordsRequest struct {
- Fqdn string `json:"fqdn,omitempty"`
- Records RecordList `json:"records"`
-}
-
-// RecordList List of entries (in this case only described TXT).
-type RecordList struct {
- TXT []Record `json:"TXT,omitempty"`
-}
-
-// Record data representation for TXT record.
-type Record struct {
- Value string `json:"value,omitempty"`
- Data string `json:"txtdata,omitempty"`
- Priority int `json:"priority,omitempty"`
- TTL int `json:"ttl,omitempty"`
-}
-
-type GetRecordsResult struct {
- Fqdn string `json:"fqdn"`
- Records RecordList `json:"records"`
-}
diff --git a/providers/dns/binarylane/binarylane.go b/providers/dns/binarylane/binarylane.go
deleted file mode 100644
index 5bbb7a16a..000000000
--- a/providers/dns/binarylane/binarylane.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Package binarylane implements a DNS provider for solving the DNS-01 challenge using Binary Lane.
-package binarylane
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/binarylane/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "BINARYLANE_"
-
- EnvAPIToken = envNamespace + "API_TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIToken string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, 3600),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- recordIDs map[string]int64
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Binary Lane.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIToken)
- if err != nil {
- return nil, fmt.Errorf("binarylane: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIToken = values[EnvAPIToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Binary Lane.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("binarylane: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIToken)
- if err != nil {
- return nil, fmt.Errorf("binarylane: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]int64),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("binarylane: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("binarylane: %w", err)
- }
-
- record := internal.Record{
- Type: "TXT",
- Name: subDomain,
- Data: info.Value,
- TTL: d.config.TTL,
- }
-
- response, err := d.client.CreateRecord(context.Background(), dns01.UnFqdn(authZone), record)
- if err != nil {
- return fmt.Errorf("binarylane: create record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.recordIDs[token] = response.ID
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("binarylane: could not find zone for domain %q: %w", domain, err)
- }
-
- // get the record's unique ID from when we created it
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("binarylane: unknown record ID for '%s'", info.EffectiveFQDN)
- }
-
- err = d.client.DeleteRecord(context.Background(), dns01.UnFqdn(authZone), recordID)
- if err != nil {
- return fmt.Errorf("binarylane: delete record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/binarylane/binarylane.toml b/providers/dns/binarylane/binarylane.toml
deleted file mode 100644
index 8b382f3b2..000000000
--- a/providers/dns/binarylane/binarylane.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Binary Lane"
-Description = ''''''
-URL = "https://www.binarylane.com.au/"
-Code = "binarylane"
-Since = "v4.26.0"
-
-Example = '''
-BINARYLANE_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns binarylane -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- BINARYLANE_API_TOKEN = "API token"
- [Configuration.Additional]
- BINARYLANE_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- BINARYLANE_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- BINARYLANE_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- BINARYLANE_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://api.binarylane.com.au/reference/#tag/Domains"
diff --git a/providers/dns/binarylane/binarylane_test.go b/providers/dns/binarylane/binarylane_test.go
deleted file mode 100644
index 4f2cfd230..000000000
--- a/providers/dns/binarylane/binarylane_test.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package binarylane
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIToken).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIToken: "secret",
- },
- },
- {
- desc: "missing API token",
- envVars: map[string]string{
- EnvAPIToken: "",
- },
- expected: "binarylane: some credentials information are missing: BINARYLANE_API_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiToken string
- expected string
- }{
- {
- desc: "success",
- apiToken: "secret",
- },
- {
- desc: "missing API token",
- expected: "binarylane: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIToken = test.apiToken
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/binarylane/internal/client.go b/providers/dns/binarylane/internal/client.go
deleted file mode 100644
index 3f10e9f8b..000000000
--- a/providers/dns/binarylane/internal/client.go
+++ /dev/null
@@ -1,148 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
-)
-
-const defaultBaseURL = "https://api.binarylane.com.au/v2/"
-
-const authorizationHeader = "Authorization"
-
-// Client the Binary Lane API client.
-type Client struct {
- apiToken string
-
- baseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(apiToken string) (*Client, error) {
- if apiToken == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- apiToken: apiToken,
- baseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-// CreateRecord Creates a new domain record.
-// https://api.binarylane.com.au/reference/#tag/Domains/paths/~1v2~1domains~1%7Bdomain_name%7D~1records/post
-func (c *Client) CreateRecord(ctx context.Context, domain string, record Record) (*Record, error) {
- endpoint := c.baseURL.JoinPath("domains", domain, "records")
-
- if record.Name == "" {
- record.Name = "@"
- }
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
- if err != nil {
- return nil, err
- }
-
- var result APIResponse
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.DomainRecord, nil
-}
-
-// DeleteRecord Deletes an existing domain record.
-// https://api.binarylane.com.au/reference/#tag/Domains/paths/~1v2~1domains~1%7Bdomain_name%7D~1records~1%7Brecord_id%7D/delete
-func (c *Client) DeleteRecord(ctx context.Context, domainName string, recordID int64) error {
- endpoint := c.baseURL.JoinPath("domains", domainName, "records", strconv.FormatInt(recordID, 10))
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- req.Header.Set(authorizationHeader, "Bearer "+c.apiToken)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
diff --git a/providers/dns/binarylane/internal/client_test.go b/providers/dns/binarylane/internal/client_test.go
deleted file mode 100644
index 0398d5adf..000000000
--- a/providers/dns/binarylane/internal/client_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.baseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().WithJSONHeaders().
- WithAuthorization("Bearer secret"),
- )
-}
-
-func TestClient_CreateRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/example.com/records",
- servermock.ResponseFromFixture("create_record.json"),
- servermock.CheckRequestJSONBodyFromFixture("create_record-request.json")).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "foo",
- Data: "txtTXTtxt",
- TTL: 300,
- }
-
- rec, err := client.CreateRecord(t.Context(), "example.com", record)
- require.NoError(t, err)
-
- expected := &Record{
- ID: 123,
- Type: "TXT",
- Name: "foo",
- Data: "txtTXTtxt",
- TTL: 300,
- }
-
- require.Equal(t, expected, rec)
-}
-
-func TestClient_CreateRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/example.com/records",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "foo",
- Data: "txtTXTtxt",
- TTL: 300,
- }
-
- _, err := client.CreateRecord(t.Context(), "example.com", record)
- require.EqualError(t, err, "400: type: title: detail: instance: property1: a")
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/records/123",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent)).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), "example.com", 123)
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/records/123",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), "example.com", 123)
- require.EqualError(t, err, "400: type: title: detail: instance: property1: a")
-}
diff --git a/providers/dns/binarylane/internal/fixtures/create_record-request.json b/providers/dns/binarylane/internal/fixtures/create_record-request.json
deleted file mode 100644
index 98a349650..000000000
--- a/providers/dns/binarylane/internal/fixtures/create_record-request.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "type": "TXT",
- "name": "foo",
- "data": "txtTXTtxt",
- "ttl": 300
-}
diff --git a/providers/dns/binarylane/internal/fixtures/create_record.json b/providers/dns/binarylane/internal/fixtures/create_record.json
deleted file mode 100644
index 709bef23e..000000000
--- a/providers/dns/binarylane/internal/fixtures/create_record.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "domain_record": {
- "id": 123,
- "type": "TXT",
- "name": "foo",
- "data": "txtTXTtxt",
- "ttl": 300
- }
-}
diff --git a/providers/dns/binarylane/internal/fixtures/error.json b/providers/dns/binarylane/internal/fixtures/error.json
deleted file mode 100644
index 79d115f74..000000000
--- a/providers/dns/binarylane/internal/fixtures/error.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "type": "type",
- "title": "title",
- "status": 400,
- "detail": "detail",
- "instance": "instance",
- "errors": {
- "property1": [
- "a"
- ]
- },
- "property1": null,
- "property2": null
-}
diff --git a/providers/dns/binarylane/internal/types.go b/providers/dns/binarylane/internal/types.go
deleted file mode 100644
index 06d4be5c0..000000000
--- a/providers/dns/binarylane/internal/types.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strings"
-)
-
-type APIError struct {
- Type string `json:"type"`
- Title string `json:"title"`
- Status int `json:"status"`
- Detail string `json:"detail"`
- Instance string `json:"instance"`
- Errors map[string][]string `json:"errors"`
-}
-
-func (a *APIError) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "%d: %s: %s: %s: %s", a.Status, a.Type, a.Title, a.Detail, a.Instance)
-
- for s, values := range a.Errors {
- _, _ = fmt.Fprintf(msg, ": %s: %s", s, strings.Join(values, ", "))
- }
-
- return msg.String()
-}
-
-type Record struct {
- ID int64 `json:"id,omitempty"`
- Type string `json:"type,omitempty"`
- Name string `json:"name,omitempty"`
- Data string `json:"data,omitempty"`
- Priority int `json:"priority,omitempty"`
- Port int `json:"port,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Weight int `json:"weight,omitempty"`
- Flags int `json:"flags,omitempty"`
- Tag string `json:"tag,omitempty"`
-}
-
-type APIResponse struct {
- DomainRecord *Record `json:"domain_record"`
-}
diff --git a/providers/dns/bindman/bindman.go b/providers/dns/bindman/bindman.go
index c529cb63c..fbaddcbec 100644
--- a/providers/dns/bindman/bindman.go
+++ b/providers/dns/bindman/bindman.go
@@ -10,8 +10,7 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- bindman "github.com/labbsr0x/bindman-dns-webhook/src/client"
+ "github.com/labbsr0x/bindman-dns-webhook/src/client"
)
// Environment variables names.
@@ -49,7 +48,7 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
config *Config
- client *bindman.DNSWebhookClient
+ client *client.DNSWebhookClient
}
// NewDNSProvider returns a DNSProvider instance configured for Bindman.
@@ -76,17 +75,12 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("bindman: bindman manager address missing")
}
- // Because the client.New uses the http.DefaultClient.
- if config.HTTPClient == nil {
- config.HTTPClient = &http.Client{Timeout: time.Minute}
- }
-
- client, err := bindman.New(config.BaseURL, clientdebug.Wrap(config.HTTPClient))
+ bClient, err := client.New(config.BaseURL, config.HTTPClient)
if err != nil {
return nil, fmt.Errorf("bindman: %w", err)
}
- return &DNSProvider{config: config, client: client}, nil
+ return &DNSProvider{config: config, client: bClient}, nil
}
// Present creates a TXT record using the specified parameters.
@@ -98,7 +92,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err := d.client.AddRecord(info.EffectiveFQDN, "TXT", info.Value); err != nil {
return fmt.Errorf("bindman: %w", err)
}
-
return nil
}
@@ -109,7 +102,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err := d.client.RemoveRecord(info.EffectiveFQDN, "TXT"); err != nil {
return fmt.Errorf("bindman: %w", err)
}
-
return nil
}
diff --git a/providers/dns/bindman/bindman.toml b/providers/dns/bindman/bindman.toml
index 768601588..5c69e18ff 100644
--- a/providers/dns/bindman/bindman.toml
+++ b/providers/dns/bindman/bindman.toml
@@ -6,7 +6,7 @@ Since = "v2.6.0"
Example = '''
BINDMAN_MANAGER_ADDRESS= \
-lego --dns bindman -d '*.example.com' -d example.com run
+lego --email you@example.com --dns bindman -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/bindman/bindman_test.go b/providers/dns/bindman/bindman_test.go
index 978a1d006..a0db025e7 100644
--- a/providers/dns/bindman/bindman_test.go
+++ b/providers/dns/bindman/bindman_test.go
@@ -1,13 +1,14 @@
+// Package bindman implements a DNS provider for solving the DNS-01 challenge.
package bindman
import (
+ "errors"
"net/http"
- "net/http/httptest"
"testing"
"time"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
+ bindmanClient "github.com/labbsr0x/bindman-dns-webhook/src/client"
"github.com/stretchr/testify/require"
)
@@ -46,7 +47,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -106,24 +106,10 @@ func TestNewDNSProviderConfig(t *testing.T) {
}
}
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.BaseURL = server.URL
- config.HTTPClient = server.Client()
-
- return NewDNSProviderConfig(config)
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With("User-Agent", "bindman-dns-webhook-client"))
-}
-
func TestDNSProvider_Present(t *testing.T) {
testCases := []struct {
name string
- mock *servermock.Builder[*DNSProvider]
+ client *bindmanClient.DNSWebhookClient
domain string
token string
keyAuth string
@@ -131,31 +117,28 @@ func TestDNSProvider_Present(t *testing.T) {
}{
{
name: "success when add record function return no error",
- mock: mockBuilder().
- Route("POST /records",
- servermock.Noop().WithStatusCode(http.StatusNoContent),
- servermock.CheckRequestJSONBodyFromFixture("add_record-request.json"),
- ),
- domain: "example.com",
+ client: &bindmanClient.DNSWebhookClient{
+ ClientAPI: &MockHTTPClientAPI{Status: http.StatusNoContent},
+ },
+ domain: "hello.test.com",
keyAuth: "szDTG4zmM0GsKG91QAGO2M4UYOJMwU8oFpWOP7eTjCw",
expectError: false,
},
{
name: "error when add record function return an error",
- mock: mockBuilder().
- Route("POST /records",
- servermock.ResponseFromFixture("error.json"),
- ),
- domain: "example.com",
+ client: &bindmanClient.DNSWebhookClient{
+ ClientAPI: &MockHTTPClientAPI{Error: errors.New("error adding record")},
+ },
+ domain: "hello.test.com",
keyAuth: "szDTG4zmM0GsKG91QAGO2M4UYOJMwU8oFpWOP7eTjCw",
expectError: true,
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
- provider := test.mock.Build(t)
+ d := &DNSProvider{client: test.client}
- err := provider.Present(test.domain, test.token, test.keyAuth)
+ err := d.Present(test.domain, test.token, test.keyAuth)
if test.expectError {
require.Error(t, err)
} else {
@@ -168,7 +151,7 @@ func TestDNSProvider_Present(t *testing.T) {
func TestDNSProvider_CleanUp(t *testing.T) {
testCases := []struct {
name string
- mock *servermock.Builder[*DNSProvider]
+ client *bindmanClient.DNSWebhookClient
domain string
token string
keyAuth string
@@ -176,33 +159,30 @@ func TestDNSProvider_CleanUp(t *testing.T) {
}{
{
name: "success when remove record function return no error",
- mock: mockBuilder().
- Route("DELETE /records/_acme-challenge.example.com./TXT",
- servermock.Noop().WithStatusCode(http.StatusNoContent),
- ),
- domain: "example.com",
+ client: &bindmanClient.DNSWebhookClient{
+ ClientAPI: &MockHTTPClientAPI{Status: http.StatusNoContent},
+ },
+ domain: "hello.test.com",
keyAuth: "szDTG4zmM0GsKG91QAGO2M4UYOJMwU8oFpWOP7eTjCw",
expectError: false,
},
{
name: "error when remove record function return an error",
- mock: mockBuilder().
- Route("DELETE /records/_acme-challenge.example.com./TXT",
- servermock.ResponseFromFixture("error.json"),
- ),
- domain: "example.com",
+ client: &bindmanClient.DNSWebhookClient{
+ ClientAPI: &MockHTTPClientAPI{Error: errors.New("error adding record")},
+ },
+ domain: "hello.test.com",
keyAuth: "szDTG4zmM0GsKG91QAGO2M4UYOJMwU8oFpWOP7eTjCw",
expectError: true,
},
}
-
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
- provider := test.mock.Build(t)
+ d := &DNSProvider{client: test.client}
- err := provider.CleanUp(test.domain, test.token, test.keyAuth)
+ err := d.CleanUp(test.domain, test.token, test.keyAuth)
if test.expectError {
- require.ErrorContains(t, err, "bindman: ERROR (400): bar; ")
+ require.Error(t, err)
} else {
require.NoError(t, err)
}
@@ -216,7 +196,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -230,7 +209,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -239,3 +217,25 @@ func TestLiveCleanUp(t *testing.T) {
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
require.NoError(t, err)
}
+
+type MockHTTPClientAPI struct {
+ Data []byte
+ Status int
+ Error error
+}
+
+func (m *MockHTTPClientAPI) Put(url string, data []byte) (*http.Response, []byte, error) {
+ return &http.Response{StatusCode: m.Status}, m.Data, m.Error
+}
+
+func (m *MockHTTPClientAPI) Post(url string, data []byte) (*http.Response, []byte, error) {
+ return &http.Response{StatusCode: m.Status}, m.Data, m.Error
+}
+
+func (m *MockHTTPClientAPI) Get(url string) (*http.Response, []byte, error) {
+ return &http.Response{StatusCode: m.Status}, m.Data, m.Error
+}
+
+func (m *MockHTTPClientAPI) Delete(url string) (*http.Response, []byte, error) {
+ return &http.Response{StatusCode: m.Status}, m.Data, m.Error
+}
diff --git a/providers/dns/bindman/fixtures/add_record-request.json b/providers/dns/bindman/fixtures/add_record-request.json
deleted file mode 100644
index 9585565b8..000000000
--- a/providers/dns/bindman/fixtures/add_record-request.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "name": "_acme-challenge.example.com.",
- "value": "_EYMkjukXEMcXbnvpT6WLESzfYhxH190NKTBo3cpu-E",
- "type": "TXT"
-}
diff --git a/providers/dns/bindman/fixtures/error.json b/providers/dns/bindman/fixtures/error.json
deleted file mode 100644
index c8a014510..000000000
--- a/providers/dns/bindman/fixtures/error.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "message": "bar",
- "code": 400,
- "details": ["foo"]
-}
diff --git a/providers/dns/bluecat/bluecat.go b/providers/dns/bluecat/bluecat.go
index b26fab8be..8ba026f49 100644
--- a/providers/dns/bluecat/bluecat.go
+++ b/providers/dns/bluecat/bluecat.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/bluecat/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -111,8 +110,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/bluecat/bluecat.toml b/providers/dns/bluecat/bluecat.toml
index 15df6ed34..a01a5918d 100644
--- a/providers/dns/bluecat/bluecat.toml
+++ b/providers/dns/bluecat/bluecat.toml
@@ -11,7 +11,7 @@ BLUECAT_USER_NAME=myusername \
BLUECAT_CONFIG_NAME=myconfig \
BLUECAT_SERVER_URL=https://bam.example.com \
BLUECAT_TTL=30 \
-lego --dns bluecat -d '*.example.com' -d example.com run
+lego --email you@example.com --dns bluecat -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/bluecat/bluecat_test.go b/providers/dns/bluecat/bluecat_test.go
index 38b110470..5a3670e3a 100644
--- a/providers/dns/bluecat/bluecat_test.go
+++ b/providers/dns/bluecat/bluecat_test.go
@@ -105,7 +105,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -220,7 +219,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -234,7 +232,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/bluecat/internal/client.go b/providers/dns/bluecat/internal/client.go
index d517ea857..de31579ea 100644
--- a/providers/dns/bluecat/internal/client.go
+++ b/providers/dns/bluecat/internal/client.go
@@ -106,7 +106,6 @@ func (c *Client) AddEntity(ctx context.Context, parentID uint, entity Entity) (u
// addEntity responds only with body text containing the ID of the created record
addTxtResp := string(raw)
-
id, err := strconv.ParseUint(addTxtResp, 10, 64)
if err != nil {
return 0, fmt.Errorf("addEntity request failed: %s", addTxtResp)
@@ -148,7 +147,6 @@ func (c *Client) GetEntityByName(ctx context.Context, parentID uint, name, objTy
}
var entity EntityResponse
-
err = json.Unmarshal(raw, &entity)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/bluecat/internal/client_test.go b/providers/dns/bluecat/internal/client_test.go
index d4776b8a1..9d79f46b3 100644
--- a/providers/dns/bluecat/internal/client_test.go
+++ b/providers/dns/bluecat/internal/client_test.go
@@ -31,7 +31,6 @@ func TestClient_LookupParentZoneID(t *testing.T) {
Type: ZoneType,
Properties: "test",
})
-
return
}
diff --git a/providers/dns/bluecatv2/bluecatv2.go b/providers/dns/bluecatv2/bluecatv2.go
deleted file mode 100644
index 0efe99661..000000000
--- a/providers/dns/bluecatv2/bluecatv2.go
+++ /dev/null
@@ -1,249 +0,0 @@
-// Package bluecatv2 implements a DNS provider for solving the DNS-01 challenge using Bluecat v2.
-package bluecatv2
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/bluecatv2/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "BLUECATV2_"
-
- EnvServerURL = envNamespace + "SERVER_URL"
- EnvUsername = envNamespace + "USERNAME"
- EnvPassword = envNamespace + "PASSWORD"
- EnvConfigName = envNamespace + "CONFIG_NAME"
- EnvViewName = envNamespace + "VIEW_NAME"
- EnvSkipDeploy = envNamespace + "SKIP_DEPLOY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- ServerURL string
- Username string
- Password string
- ConfigName string
- ViewName string
- SkipDeploy bool
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- SkipDeploy: env.GetOrDefaultBool(EnvSkipDeploy, false),
-
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- zoneIDs map[string]int64
- recordIDs map[string]int64
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Bluecat v2.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvServerURL, EnvUsername, EnvPassword, EnvConfigName, EnvViewName)
- if err != nil {
- return nil, fmt.Errorf("bluecatv2: %w", err)
- }
-
- config := NewDefaultConfig()
- config.ServerURL = values[EnvServerURL]
- config.Username = values[EnvUsername]
- config.Password = values[EnvPassword]
- config.ConfigName = values[EnvConfigName]
- config.ViewName = values[EnvViewName]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Bluecat v2.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("bluecatv2: the configuration of the DNS provider is nil")
- }
-
- if config.ServerURL == "" {
- return nil, errors.New("bluecatv2: missing server URL")
- }
-
- if config.ConfigName == "" {
- return nil, errors.New("bluecatv2: missing configuration name")
- }
-
- if config.ViewName == "" {
- return nil, errors.New("bluecatv2: missing view name")
- }
-
- client, err := internal.NewClient(config.ServerURL, config.Username, config.Password)
- if err != nil {
- return nil, fmt.Errorf("bluecatv2: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]int64),
- zoneIDs: make(map[string]int64),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx, err := d.client.CreateAuthenticatedContext(context.Background())
- if err != nil {
- return fmt.Errorf("bluecatv2: %w", err)
- }
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("bluecatv2: %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.AbsoluteName)
- if err != nil {
- return fmt.Errorf("bluecatv2: %w", err)
- }
-
- record := internal.RecordTXT{
- CommonResource: internal.CommonResource{
- Type: "TXTRecord",
- Name: subDomain,
- },
- Text: info.Value,
- TTL: d.config.TTL,
- RecordType: "TXT",
- }
-
- newRecord, err := d.client.CreateZoneResourceRecord(ctx, zone.ID, record)
- if err != nil {
- return fmt.Errorf("bluecatv2: create resource record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.zoneIDs[token] = zone.ID
- d.recordIDs[token] = newRecord.ID
- d.recordIDsMu.Unlock()
-
- if d.config.SkipDeploy {
- return nil
- }
-
- _, err = d.client.CreateZoneDeployment(ctx, zone.ID)
- if err != nil {
- return fmt.Errorf("bluecat: deploy zone: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- d.recordIDsMu.Lock()
- recordID, recordOK := d.recordIDs[token]
- zoneID, zoneOK := d.zoneIDs[token]
- d.recordIDsMu.Unlock()
-
- if !recordOK {
- return fmt.Errorf("bluecatv2: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- if !zoneOK {
- return fmt.Errorf("bluecatv2: unknown zone ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- ctx, err := d.client.CreateAuthenticatedContext(context.Background())
- if err != nil {
- return fmt.Errorf("bluecatv2: %w", err)
- }
-
- err = d.client.DeleteResourceRecord(ctx, recordID)
- if err != nil {
- return fmt.Errorf("bluecatv2: delete resource record: %w", err)
- }
-
- if d.config.SkipDeploy {
- return nil
- }
-
- _, err = d.client.CreateZoneDeployment(ctx, zoneID)
- if err != nil {
- return fmt.Errorf("bluecat: deploy zone: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findZone(ctx context.Context, fqdn string) (*internal.ZoneResource, error) {
- for name := range dns01.UnFqdnDomainsSeq(fqdn) {
- opts := &internal.CollectionOptions{
- Fields: "id,absoluteName,configuration.id,configuration.name,view.id,view.name",
- Filter: internal.And(
- internal.Eq("absoluteName", name),
- internal.Eq("configuration.name", d.config.ConfigName),
- internal.Eq("view.name", d.config.ViewName),
- ).String(),
- }
-
- zones, err := d.client.RetrieveZones(ctx, opts)
- if err != nil {
- // TODO(ldez) maybe add a log in v5.
- continue
- }
-
- for _, zone := range zones {
- if zone.AbsoluteName == name {
- return &zone, nil
- }
- }
- }
-
- return nil, fmt.Errorf("no zone found for fqdn: %s", fqdn)
-}
diff --git a/providers/dns/bluecatv2/bluecatv2.toml b/providers/dns/bluecatv2/bluecatv2.toml
deleted file mode 100644
index 6ec3781c6..000000000
--- a/providers/dns/bluecatv2/bluecatv2.toml
+++ /dev/null
@@ -1,33 +0,0 @@
-Name = "Bluecat v2"
-Description = ''''''
-URL = "https://www.bluecatnetworks.com"
-Code = "bluecatv2"
-Since = "v4.32.0"
-
-Example = '''
-BLUECATV2_SERVER_URL="https://example.com" \
-BLUECATV2_USERNAME="xxx" \
-BLUECATV2_PASSWORD="yyy" \
-BLUECATV2_CONFIG_NAME="myConfiguration" \
-BLUECATV2_VIEW_NAME="myView" \
-lego --dns bluecatv2 -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- BLUECAT_SERVER_URL = "The server URL: it should have a scheme, hostname, and port (if required) of the authoritative Bluecat BAM serve"
- BLUECATV2_USERNAME = "API username"
- BLUECATV2_PASSWORD = "API password"
- BLUECATV2_CONFIG_NAME = "Configuration name"
- BLUECATV2_VIEW_NAME = "DNS View Name"
- [Configuration.Additional]
- BLUECATV2_SKIP_DEPLOY = "Skip quick deployements"
- BLUECATV2_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- BLUECATV2_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- BLUECATV2_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- BLUECATV2_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Introduction/9.6.0"
- Swagger = "http://{Address_Manager_IP}/api/openapi.json"
- SwaggerDump = "https://github.com/go-acme/lego/discussions/2218#discussioncomment-13060545"
diff --git a/providers/dns/bluecatv2/bluecatv2_test.go b/providers/dns/bluecatv2/bluecatv2_test.go
deleted file mode 100644
index d852f0e18..000000000
--- a/providers/dns/bluecatv2/bluecatv2_test.go
+++ /dev/null
@@ -1,414 +0,0 @@
-package bluecatv2
-
-import (
- "net/http"
- "net/http/httptest"
- "strings"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/bluecatv2/internal"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvServerURL,
- EnvUsername,
- EnvPassword,
- EnvConfigName,
- EnvViewName,
- EnvSkipDeploy,
-).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvServerURL: "https://example.com/",
- EnvUsername: "userA",
- EnvPassword: "secret",
- EnvConfigName: "myConfig",
- EnvViewName: "myView",
- },
- },
- {
- desc: "missing server URL",
- envVars: map[string]string{
- EnvServerURL: "",
- EnvUsername: "userA",
- EnvPassword: "secret",
- EnvConfigName: "myConfig",
- EnvViewName: "myView",
- },
- expected: "bluecatv2: some credentials information are missing: BLUECATV2_SERVER_URL",
- },
- {
- desc: "missing username",
- envVars: map[string]string{
- EnvServerURL: "https://example.com/",
- EnvUsername: "",
- EnvPassword: "secret",
- EnvConfigName: "myConfig",
- EnvViewName: "myView",
- },
- expected: "bluecatv2: some credentials information are missing: BLUECATV2_USERNAME",
- },
- {
- desc: "missing password",
- envVars: map[string]string{
- EnvServerURL: "https://example.com/",
- EnvUsername: "userA",
- EnvPassword: "",
- EnvConfigName: "myConfig",
- EnvViewName: "myView",
- },
- expected: "bluecatv2: some credentials information are missing: BLUECATV2_PASSWORD",
- },
- {
- desc: "missing configuration name",
- envVars: map[string]string{
- EnvServerURL: "https://example.com/",
- EnvUsername: "userA",
- EnvPassword: "secret",
- EnvConfigName: "",
- EnvViewName: "myView",
- },
- expected: "bluecatv2: some credentials information are missing: BLUECATV2_CONFIG_NAME",
- },
- {
- desc: "missing view name",
- envVars: map[string]string{
- EnvServerURL: "https://example.com/",
- EnvUsername: "userA",
- EnvPassword: "secret",
- EnvConfigName: "myConfig",
- EnvViewName: "",
- },
- expected: "bluecatv2: some credentials information are missing: BLUECATV2_VIEW_NAME",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "bluecatv2: some credentials information are missing: BLUECATV2_SERVER_URL,BLUECATV2_USERNAME,BLUECATV2_PASSWORD,BLUECATV2_CONFIG_NAME,BLUECATV2_VIEW_NAME",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- serverURL string
- username string
- password string
- configName string
- viewName string
- expected string
- }{
- {
- desc: "success",
- serverURL: "https://example.com/",
- username: "userA",
- password: "secret",
- configName: "myConfig",
- viewName: "myView",
- },
- {
- desc: "missing server URL",
- username: "userA",
- password: "secret",
- configName: "myConfig",
- viewName: "myView",
- expected: "bluecatv2: missing server URL",
- },
- {
- desc: "missing username",
- serverURL: "https://example.com/",
- password: "secret",
- configName: "myConfig",
- viewName: "myView",
- expected: "bluecatv2: credentials missing",
- },
- {
- desc: "missing password",
- serverURL: "https://example.com/",
- username: "userA",
- configName: "myConfig",
- viewName: "myView",
- expected: "bluecatv2: credentials missing",
- },
- {
- desc: "missing configuration name",
- serverURL: "https://example.com/",
- username: "userA",
- password: "secret",
- viewName: "myView",
- expected: "bluecatv2: missing configuration name",
- },
- {
- desc: "missing view name",
- serverURL: "https://example.com/",
- username: "userA",
- password: "secret",
- configName: "myConfig",
- expected: "bluecatv2: missing view name",
- },
- {
- desc: "missing credentials",
- expected: "bluecatv2: missing server URL",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.ServerURL = test.serverURL
- config.Username = test.username
- config.Password = test.password
- config.ConfigName = test.configName
- config.ViewName = test.viewName
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
-
- config.ServerURL = server.URL
- config.Username = "userA"
- config.Password = "secret"
- config.ConfigName = "myConfiguration"
- config.ViewName = "myView"
-
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /api/v2/sessions",
- servermock.ResponseFromInternal("postSession.json"),
- servermock.CheckRequestJSONBodyFromInternal("postSession-request.json"),
- ).
- Route("GET /api/v2/configurations",
- servermock.ResponseFromInternal("configurations.json"),
- servermock.CheckQueryParameter().Strict().
- With("filter", "name:eq('myConfiguration')"),
- ).
- Route("GET /api/v2/configurations/12345/views",
- servermock.ResponseFromInternal("views.json"),
- servermock.CheckQueryParameter().Strict().
- With("filter", "name:eq('myView')"),
- ).
- Route("GET /api/v2/zones",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- filter := req.URL.Query().Get("filter")
-
- if strings.Contains(filter, internal.Eq("absoluteName", "example.com").String()) {
- servermock.ResponseFromInternal("zones.json").ServeHTTP(rw, req)
-
- return
- }
-
- servermock.ResponseFromInternal("error.json").
- WithStatusCode(http.StatusNotFound).ServeHTTP(rw, req)
- }),
- ).
- Route("POST /api/v2/zones/12345/resourceRecords",
- servermock.ResponseFromInternal("postZoneResourceRecord.json"),
- servermock.CheckRequestJSONBodyFromInternal("postZoneResourceRecord-request.json"),
- ).
- Route("POST /api/v2/zones/12345/deployments",
- servermock.ResponseFromInternal("postZoneDeployment.json").
- WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBodyFromInternal("postZoneDeployment-request.json"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_Present_skipDeploy(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(map[string]string{
- EnvSkipDeploy: "true",
- })
-
- provider := mockBuilder().
- Route("POST /api/v2/sessions",
- servermock.ResponseFromInternal("postSession.json"),
- servermock.CheckRequestJSONBodyFromInternal("postSession-request.json"),
- ).
- Route("GET /api/v2/configurations",
- servermock.ResponseFromInternal("configurations.json"),
- servermock.CheckQueryParameter().Strict().
- With("filter", "name:eq('myConfiguration')"),
- ).
- Route("GET /api/v2/configurations/12345/views",
- servermock.ResponseFromInternal("views.json"),
- servermock.CheckQueryParameter().Strict().
- With("filter", "name:eq('myView')"),
- ).
- Route("GET /api/v2/zones",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- filter := req.URL.Query().Get("filter")
-
- if strings.Contains(filter, internal.Eq("absoluteName", "example.com").String()) {
- servermock.ResponseFromInternal("zones.json").ServeHTTP(rw, req)
-
- return
- }
-
- servermock.ResponseFromInternal("error.json").
- WithStatusCode(http.StatusNotFound).ServeHTTP(rw, req)
- }),
- ).
- Route("POST /api/v2/zones/12345/resourceRecords",
- servermock.ResponseFromInternal("postZoneResourceRecord.json"),
- servermock.CheckRequestJSONBodyFromInternal("postZoneResourceRecord-request.json"),
- ).
- Route("POST /api/v2/zones/456789/deployments",
- servermock.Noop().
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("POST /api/v2/sessions",
- servermock.ResponseFromInternal("postSession.json"),
- servermock.CheckRequestJSONBodyFromInternal("postSession-request.json"),
- ).
- Route("DELETE /api/v2/resourceRecords/12345",
- servermock.ResponseFromInternal("deleteResourceRecord.json"),
- ).
- Route("POST /api/v2/zones/456789/deployments",
- servermock.ResponseFromInternal("postZoneDeployment.json").
- WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBodyFromInternal("postZoneDeployment-request.json"),
- ).
- Build(t)
-
- provider.zoneIDs["abc"] = 456789
- provider.recordIDs["abc"] = 12345
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp_skipDeploy(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(map[string]string{
- EnvSkipDeploy: "true",
- })
-
- provider := mockBuilder().
- Route("POST /api/v2/sessions",
- servermock.ResponseFromInternal("postSession.json"),
- servermock.CheckRequestJSONBodyFromInternal("postSession-request.json"),
- ).
- Route("DELETE /api/v2/resourceRecords/12345",
- servermock.ResponseFromInternal("deleteResourceRecord.json"),
- ).
- Route("POST /api/v2/zones/456789/deployments",
- servermock.Noop().
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- provider.zoneIDs["abc"] = 456789
- provider.recordIDs["abc"] = 12345
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/bluecatv2/internal/client.go b/providers/dns/bluecatv2/internal/client.go
deleted file mode 100644
index d3c801154..000000000
--- a/providers/dns/bluecatv2/internal/client.go
+++ /dev/null
@@ -1,221 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
- querystring "github.com/google/go-querystring/query"
-)
-
-// Client the Bluecat v2 API client.
-type Client struct {
- username string
- password string
-
- baseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(serverURL, username, password string) (*Client, error) {
- if serverURL == "" {
- return nil, errors.New("server URL missing")
- }
-
- if username == "" || password == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, err := url.Parse(serverURL)
- if err != nil {
- return nil, err
- }
-
- return &Client{
- username: username,
- password: password,
- baseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-// RetrieveZones retrieves all zones.
-func (c *Client) RetrieveZones(ctx context.Context, opts *CollectionOptions) ([]ZoneResource, error) {
- endpoint := c.baseURL.JoinPath("api", "v2", "zones")
-
- collection, err := retrieveCollection[ZoneResource](ctx, c, endpoint, opts)
- if err != nil {
- return nil, err
- }
-
- return collection.Data, nil
-}
-
-// RetrieveZoneDeployments retrieves all deployments for a zone.
-func (c *Client) RetrieveZoneDeployments(ctx context.Context, zoneID int64, opts *CollectionOptions) ([]QuickDeployment, error) {
- endpoint := c.baseURL.JoinPath("api", "v2", "zones", strconv.FormatInt(zoneID, 10), "deployments")
-
- collection, err := retrieveCollection[QuickDeployment](ctx, c, endpoint, opts)
- if err != nil {
- return nil, err
- }
-
- return collection.Data, nil
-}
-
-// CreateZoneDeployment creates a new deployment for a zone.
-func (c *Client) CreateZoneDeployment(ctx context.Context, zoneID int64) (*QuickDeployment, error) {
- endpoint := c.baseURL.JoinPath("api", "v2", "zones", strconv.FormatInt(zoneID, 10), "deployments")
-
- payload := CommonResource{
- Type: "QuickDeployment",
- }
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, payload)
- if err != nil {
- return nil, err
- }
-
- result := new(QuickDeployment)
-
- err = c.doAuthenticated(ctx, req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// CreateZoneResourceRecord creates a new TXT record in a zone.
-func (c *Client) CreateZoneResourceRecord(ctx context.Context, zoneID int64, record RecordTXT) (*RecordTXT, error) {
- endpoint := c.baseURL.JoinPath("api", "v2", "zones", strconv.FormatInt(zoneID, 10), "resourceRecords")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
- if err != nil {
- return nil, err
- }
-
- result := new(RecordTXT)
-
- err = c.doAuthenticated(ctx, req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// DeleteResourceRecord deletes a resource record.
-func (c *Client) DeleteResourceRecord(ctx context.Context, recordID int64) error {
- endpoint := c.baseURL.JoinPath("api", "v2", "resourceRecords", strconv.FormatInt(recordID, 10))
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.doAuthenticated(ctx, req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func retrieveCollection[T any](ctx context.Context, client *Client, endpoint *url.URL, opts *CollectionOptions) (*Collection[T], error) {
- if opts != nil {
- values, err := querystring.Values(opts)
- if err != nil {
- return nil, err
- }
-
- endpoint.RawQuery = values.Encode()
- }
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- result := &Collection[T]{}
-
- err = client.doAuthenticated(ctx, req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
diff --git a/providers/dns/bluecatv2/internal/client_test.go b/providers/dns/bluecatv2/internal/client_test.go
deleted file mode 100644
index 2559af66e..000000000
--- a/providers/dns/bluecatv2/internal/client_test.go
+++ /dev/null
@@ -1,208 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilderAuthenticated() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(server.URL, "userA", "secret")
- if err != nil {
- return nil, err
- }
-
- client.baseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- servermock.CheckHeader().
- WithAuthorization("Basic secretToken"),
- )
-}
-
-func TestClient_RetrieveZones(t *testing.T) {
- client := mockBuilderAuthenticated().
- Route("GET /api/v2/zones",
- servermock.ResponseFromFixture("zones.json"),
- servermock.CheckQueryParameter().Strict().
- With(
- "filter",
- "absoluteName:eq('example.com') and configuration.name:eq('myConfiguration') and view.name:eq('myView')",
- ),
- ).
- Build(t)
-
- opts := &CollectionOptions{
- Filter: And(
- Eq("absoluteName", "example.com"),
- Eq("configuration.name", "myConfiguration"),
- Eq("view.name", "myView"),
- ).String(),
- }
-
- result, err := client.RetrieveZones(mockToken(t.Context()), opts)
- require.NoError(t, err)
-
- expected := []ZoneResource{
- {
- CommonResource: CommonResource{ID: 12345, Type: "ENUMZone", Name: "5678"},
- AbsoluteName: "string",
- },
- {
- CommonResource: CommonResource{ID: 12345, Type: "ExternalHostsZone", Name: "name"},
- },
- {
- CommonResource: CommonResource{ID: 12345, Type: "InternalRootZone", Name: "name"},
- },
- {
- CommonResource: CommonResource{ID: 12345, Type: "ResponsePolicyZone", Name: "name"},
- },
- {
- CommonResource: CommonResource{ID: 12345, Type: "Zone", Name: "example.com"},
- AbsoluteName: "example.com",
- },
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_RetrieveZones_error(t *testing.T) {
- client := mockBuilderAuthenticated().
- Route("GET /api/v2/zones",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- opts := &CollectionOptions{
- Filter: And(
- Eq("absoluteName", "example.com"),
- Eq("configuration.name", "myConfiguration"),
- Eq("view.name", "myView"),
- ).String(),
- }
-
- _, err := client.RetrieveZones(mockToken(t.Context()), opts)
- require.EqualError(t, err, "401: Unauthorized: InvalidAuthorizationToken: The provided authorization token is invalid")
-}
-
-func TestClient_RetrieveZoneDeployments(t *testing.T) {
- client := mockBuilderAuthenticated().
- Route("GET /api/v2/zones/456789/deployments",
- servermock.ResponseFromFixture("getZoneDeployments.json"),
- servermock.CheckQueryParameter().Strict().
- With("filter", "id:eq('12345')"),
- ).
- Build(t)
-
- opts := &CollectionOptions{
- Filter: Eq("id", "12345").String(),
- }
-
- result, err := client.RetrieveZoneDeployments(mockToken(t.Context()), 456789, opts)
- require.NoError(t, err)
-
- expected := []QuickDeployment{
- {
- CommonResource: CommonResource{ID: 12345, Type: "QuickDeployment", Name: ""},
- State: "PENDING",
- Status: "CANCEL",
- Message: "string",
- PercentComplete: 50,
- CreationDateTime: time.Date(2022, time.November, 23, 2, 53, 0, 0, time.UTC),
- StartDateTime: time.Date(2022, time.November, 23, 2, 53, 3, 0, time.UTC),
- CompletionDateTime: time.Date(2022, time.November, 23, 2, 54, 5, 0, time.UTC),
- Method: "SCHEDULED",
- },
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_CreateZoneDeployment(t *testing.T) {
- client := mockBuilderAuthenticated().
- Route("POST /api/v2/zones/12345/deployments",
- servermock.ResponseFromFixture("postZoneDeployment.json").
- WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBodyFromFixture("postZoneDeployment-request.json"),
- ).
- Build(t)
-
- quickDeployment, err := client.CreateZoneDeployment(mockToken(t.Context()), 12345)
- require.NoError(t, err)
-
- expected := &QuickDeployment{
- CommonResource: CommonResource{ID: 12345, Type: "QuickDeployment"},
- State: "PENDING",
- Status: "CANCEL",
- Message: "string",
- PercentComplete: 50,
- CreationDateTime: time.Date(2022, time.November, 23, 2, 53, 0, 0, time.UTC),
- StartDateTime: time.Date(2022, time.November, 23, 2, 53, 3, 0, time.UTC),
- CompletionDateTime: time.Date(2022, time.November, 23, 2, 54, 5, 0, time.UTC),
- Method: "SCHEDULED",
- }
-
- assert.Equal(t, expected, quickDeployment)
-}
-
-func TestClient_CreateZoneResourceRecord(t *testing.T) {
- client := mockBuilderAuthenticated().
- Route("POST /api/v2/zones/12345/resourceRecords",
- servermock.ResponseFromFixture("postZoneResourceRecord.json"),
- servermock.CheckRequestJSONBodyFromFixture("postZoneResourceRecord-request.json"),
- ).
- Build(t)
-
- record := RecordTXT{
- CommonResource: CommonResource{
- Type: "TXTRecord",
- Name: "_acme-challenge",
- },
- Text: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- RecordType: "TXT",
- }
-
- result, err := client.CreateZoneResourceRecord(mockToken(t.Context()), 12345, record)
- require.NoError(t, err)
-
- expected := &RecordTXT{
- CommonResource: CommonResource{
- ID: 12345,
- Type: "ResourceRecord",
- Name: "name",
- },
- TTL: 3600,
- AbsoluteName: "host1.example.com",
- Comment: "Sample comment.",
- Dynamic: true,
- RecordType: "CNAME",
- Text: "",
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_DeleteResourceRecord(t *testing.T) {
- client := mockBuilderAuthenticated().
- Route("DELETE /api/v2/resourceRecords/12345",
- servermock.ResponseFromFixture("deleteResourceRecord.json"),
- ).
- Build(t)
-
- err := client.DeleteResourceRecord(mockToken(t.Context()), 12345)
- require.NoError(t, err)
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/deleteResourceRecord.json b/providers/dns/bluecatv2/internal/fixtures/deleteResourceRecord.json
deleted file mode 100644
index 38ae2db6e..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/deleteResourceRecord.json
+++ /dev/null
@@ -1,75 +0,0 @@
-{
- "id": 12345,
- "type": "WorkflowRequest",
- "state": "APPROVED",
- "operation": "ADD_ALIAS_RECORD",
- "creator": {
- "id": 103307,
- "type": "User",
- "name": "admin",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "authenticator": {
- "id": 12345,
- "type": "Authenticator",
- "name": "LDAP authenticator"
- },
- "email": "user@example.com",
- "phoneNumber": "555-1234",
- "securityPrivilege": "NO_ACCESS",
- "historyPrivilege": "HIDE",
- "accessType": "GUI",
- "passwordResetRequired": true,
- "accountLocked": true,
- "x509Required": true,
- "administrativeAccessRights": [
- {
- "resourceType": "Event",
- "accessLevel": "HIDE"
- }
- ]
- },
- "resourceId": 0,
- "resourceType": "ACL",
- "fieldUpdates": [
- {
- "name": "string",
- "value": {},
- "previousValue": {}
- }
- ],
- "dependentRequest": "string",
- "modifier": {
- "id": 103307,
- "type": "User",
- "name": "admin",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "authenticator": {
- "id": 12345,
- "type": "Authenticator",
- "name": "LDAP authenticator"
- },
- "email": "user@example.com",
- "phoneNumber": "555-1234",
- "securityPrivilege": "NO_ACCESS",
- "historyPrivilege": "HIDE",
- "accessType": "GUI",
- "passwordResetRequired": true,
- "accountLocked": true,
- "x509Required": true,
- "administrativeAccessRights": [
- {
- "resourceType": "Event",
- "accessLevel": "HIDE"
- }
- ]
- },
- "creationDateTime": "2022-10-17T19:11:45Z",
- "modificationDateTime": "2022-10-18T19:11:45Z",
- "comment": "Sample comment."
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/error.json b/providers/dns/bluecatv2/internal/fixtures/error.json
deleted file mode 100644
index d3d2b8b5f..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/error.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "status": 401,
- "reason": "Unauthorized",
- "code": "InvalidAuthorizationToken",
- "message": "The provided authorization token is invalid"
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/getZoneDeployments.json b/providers/dns/bluecatv2/internal/fixtures/getZoneDeployments.json
deleted file mode 100644
index b1a4938ad..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/getZoneDeployments.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "count": 0,
- "totalCount": 0,
- "data": [
- {
- "id": 12345,
- "type": "QuickDeployment",
- "state": "PENDING",
- "status": "CANCEL",
- "message": "string",
- "percentComplete": 50,
- "creationDateTime": "2022-11-23T02:53:00Z",
- "startDateTime": "2022-11-23T02:53:03Z",
- "completionDateTime": "2022-11-23T02:54:05Z",
- "user": {
- "id": 103307,
- "type": "User",
- "name": "admin",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "authenticator": {
- "id": 12345,
- "type": "Authenticator",
- "name": "LDAP authenticator"
- },
- "email": "user@example.com",
- "phoneNumber": "555-1234",
- "securityPrivilege": "NO_ACCESS",
- "historyPrivilege": "HIDE",
- "accessType": "GUI",
- "passwordResetRequired": true,
- "accountLocked": true,
- "x509Required": true,
- "administrativeAccessRights": [
- {
- "resourceType": "Event",
- "accessLevel": "HIDE"
- }
- ]
- },
- "method": "SCHEDULED"
- }
- ]
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/postSession-request.json b/providers/dns/bluecatv2/internal/fixtures/postSession-request.json
deleted file mode 100644
index e62048eb9..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/postSession-request.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "username": "userA",
- "password": "secret"
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/postSession.json b/providers/dns/bluecatv2/internal/fixtures/postSession.json
deleted file mode 100644
index 4599ad0ad..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/postSession.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "id": 12345,
- "type": "UserSession",
- "apiToken": "VZoO2Z0BjBaJyvuhE4vNJRWqI9upwDHk70UNi0Ez",
- "apiTokenExpirationDateTime": "2022-09-15T17:52:07Z",
- "basicAuthenticationCredentials": "YXBpOlQ0OExOT3VIRGhDcnVBNEo1bGFES3JuS3hTZC9QK3pjczZXTzBJMDY=",
- "remoteAddress": "192.168.1.1",
- "readOnly": true,
- "loginDateTime": "2022-09-14T17:45:03Z",
- "logoutDateTime": "2022-09-14T19:45:03Z",
- "state": "LOGGED_IN",
- "response": "Authentication Error: Ensure that your username and password are correct.",
- "user": {
- "id": 103307,
- "type": "User",
- "name": "admin",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "authenticator": {
- "id": 12345,
- "type": "Authenticator",
- "name": "LDAP authenticator"
- },
- "email": "user@example.com",
- "phoneNumber": "555-1234",
- "securityPrivilege": "NO_ACCESS",
- "historyPrivilege": "HIDE",
- "accessType": "GUI",
- "passwordResetRequired": true,
- "accountLocked": true,
- "x509Required": true,
- "administrativeAccessRights": [
- {
- "resourceType": "Event",
- "accessLevel": "HIDE"
- }
- ]
- },
- "authenticator": {
- "id": 12345,
- "type": "Authenticator",
- "name": "LDAP authenticator",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- }
- }
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/postZoneDeployment-request.json b/providers/dns/bluecatv2/internal/fixtures/postZoneDeployment-request.json
deleted file mode 100644
index 099573a84..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/postZoneDeployment-request.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "type": "QuickDeployment"
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/postZoneDeployment.json b/providers/dns/bluecatv2/internal/fixtures/postZoneDeployment.json
deleted file mode 100644
index fd26781fb..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/postZoneDeployment.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "id": 12345,
- "type": "QuickDeployment",
- "state": "PENDING",
- "status": "CANCEL",
- "message": "string",
- "percentComplete": 50,
- "creationDateTime": "2022-11-23T02:53:00Z",
- "startDateTime": "2022-11-23T02:53:03Z",
- "completionDateTime": "2022-11-23T02:54:05Z",
- "user": {
- "id": 103307,
- "type": "User",
- "name": "admin",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "authenticator": {
- "id": 12345,
- "type": "Authenticator",
- "name": "LDAP authenticator"
- },
- "email": "user@example.com",
- "phoneNumber": "555-1234",
- "securityPrivilege": "NO_ACCESS",
- "historyPrivilege": "HIDE",
- "accessType": "GUI",
- "passwordResetRequired": true,
- "accountLocked": true,
- "x509Required": true,
- "administrativeAccessRights": [
- {
- "resourceType": "Event",
- "accessLevel": "HIDE"
- }
- ]
- },
- "method": "SCHEDULED"
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/postZoneResourceRecord-request.json b/providers/dns/bluecatv2/internal/fixtures/postZoneResourceRecord-request.json
deleted file mode 100644
index 2de733c71..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/postZoneResourceRecord-request.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "TXTRecord",
- "name": "_acme-challenge",
- "ttl": 120,
- "recordType": "TXT",
- "text": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/postZoneResourceRecord.json b/providers/dns/bluecatv2/internal/fixtures/postZoneResourceRecord.json
deleted file mode 100644
index 78d028ee3..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/postZoneResourceRecord.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "id": 12345,
- "type": "ResourceRecord",
- "name": "name",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "ttl": 3600,
- "absoluteName": "host1.example.com",
- "comment": "Sample comment.",
- "dynamic": true,
- "recordType": "CNAME",
- "linkedRecord": {
- "id": 12345,
- "type": "ResourceRecord",
- "name": "name",
- "absoluteName": "host1.example.com"
- }
-}
diff --git a/providers/dns/bluecatv2/internal/fixtures/zones.json b/providers/dns/bluecatv2/internal/fixtures/zones.json
deleted file mode 100644
index b9f2dfa8f..000000000
--- a/providers/dns/bluecatv2/internal/fixtures/zones.json
+++ /dev/null
@@ -1,185 +0,0 @@
-{
- "count": 0,
- "totalCount": 0,
- "data": [
- {
- "id": 12345,
- "type": "ENUMZone",
- "name": "5678",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "view": {
- "id": 12345,
- "type": "View",
- "name": "default",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "deviceRegistrationEnabled": true,
- "deviceRegistrationPortalAddress": "10.10.10.10"
- },
- "deploymentEnabled": true,
- "absoluteName": "string"
- },
- {
- "id": 12345,
- "type": "ExternalHostsZone",
- "name": "name",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "view": {
- "id": 12345,
- "type": "View",
- "name": "default",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "deviceRegistrationEnabled": true,
- "deviceRegistrationPortalAddress": "10.10.10.10"
- }
- },
- {
- "id": 12345,
- "type": "InternalRootZone",
- "name": "name",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "view": {
- "id": 12345,
- "type": "View",
- "name": "default",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "deviceRegistrationEnabled": true,
- "deviceRegistrationPortalAddress": "10.10.10.10"
- },
- "deploymentEnabled": true
- },
- {
- "id": 12345,
- "type": "ResponsePolicyZone",
- "name": "name",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "view": {
- "id": 12345,
- "type": "View",
- "name": "default",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "deviceRegistrationEnabled": true,
- "deviceRegistrationPortalAddress": "10.10.10.10"
- },
- "responsePolicyZoneType": "LOCAL",
- "responsePolicy": {
- "id": 12345,
- "type": "ResponsePolicy",
- "name": "Block Response Policy"
- },
- "overridePolicyType": "ALLOWLIST",
- "overrideRefreshTime": "string",
- "redirectTarget": "string",
- "feedCategories": [
- "string"
- ]
- },
- {
- "id": 12345,
- "type": "Zone",
- "name": "example.com",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "view": {
- "id": 12345,
- "type": "View",
- "name": "default",
- "userDefinedFields": {
- "udf1": "value1",
- "udf2": "value2"
- },
- "configuration": {
- "id": 12345,
- "type": "Configuration",
- "name": "name"
- },
- "deviceRegistrationEnabled": true,
- "deviceRegistrationPortalAddress": "10.10.10.10"
- },
- "deploymentEnabled": true,
- "dynamicUpdateEnabled": true,
- "template": {
- "id": 12345,
- "type": "ZoneTemplate",
- "name": "name"
- },
- "signed": true,
- "signingPolicy": {
- "id": 12345,
- "type": "DNSSECSigningPolicy",
- "name": "name"
- },
- "absoluteName": "example.com"
- }
- ]
-}
diff --git a/providers/dns/bluecatv2/internal/identity.go b/providers/dns/bluecatv2/internal/identity.go
deleted file mode 100644
index af9355ab2..000000000
--- a/providers/dns/bluecatv2/internal/identity.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package internal
-
-import (
- "context"
- "fmt"
- "net/http"
-)
-
-type token string
-
-const tokenKey token = "token"
-
-const authorizationHeader = "Authorization"
-
-// CreateSession creates a new session.
-func (c *Client) CreateSession(ctx context.Context, info LoginInfo) (*Session, error) {
- endpoint := c.baseURL.JoinPath("api", "v2", "sessions")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, info)
- if err != nil {
- return nil, err
- }
-
- result := new(Session)
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// CreateAuthenticatedContext creates a new authenticated context.
-func (c *Client) CreateAuthenticatedContext(ctx context.Context) (context.Context, error) {
- tok, err := c.CreateSession(ctx, LoginInfo{Username: c.username, Password: c.password})
- if err != nil {
- return nil, fmt.Errorf("create session: %w", err)
- }
-
- return context.WithValue(ctx, tokenKey, tok.BasicAuthenticationCredentials), nil
-}
-
-func (c *Client) doAuthenticated(ctx context.Context, req *http.Request, result any) error {
- tok := getToken(ctx)
- if tok != "" {
- req.Header.Set(authorizationHeader, "Basic "+tok)
- }
-
- return c.do(req, result)
-}
-
-func getToken(ctx context.Context) string {
- tok, ok := ctx.Value(tokenKey).(string)
- if !ok {
- return ""
- }
-
- return tok
-}
diff --git a/providers/dns/bluecatv2/internal/identity_test.go b/providers/dns/bluecatv2/internal/identity_test.go
deleted file mode 100644
index 3a1c4d2a2..000000000
--- a/providers/dns/bluecatv2/internal/identity_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package internal
-
-import (
- "context"
- "net/http/httptest"
- "net/url"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(server.URL, "userA", "secret")
- if err != nil {
- return nil, err
- }
-
- client.baseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func mockToken(ctx context.Context) context.Context {
- return context.WithValue(ctx, tokenKey, "secretToken")
-}
-
-func TestClient_CreateSession(t *testing.T) {
- client := mockBuilder().
- Route("POST /api/v2/sessions",
- servermock.ResponseFromFixture("postSession.json"),
- servermock.CheckRequestJSONBodyFromFixture("postSession-request.json"),
- ).
- Build(t)
-
- info := LoginInfo{
- Username: "userA",
- Password: "secret",
- }
-
- result, err := client.CreateSession(mockToken(t.Context()), info)
- require.NoError(t, err)
-
- expected := &Session{
- ID: 12345,
- Type: "UserSession",
- APIToken: "VZoO2Z0BjBaJyvuhE4vNJRWqI9upwDHk70UNi0Ez",
- APITokenExpirationDateTime: time.Date(2022, time.September, 15, 17, 52, 7, 0, time.UTC),
- BasicAuthenticationCredentials: "YXBpOlQ0OExOT3VIRGhDcnVBNEo1bGFES3JuS3hTZC9QK3pjczZXTzBJMDY=",
- RemoteAddress: "192.168.1.1",
- ReadOnly: true,
- LoginDateTime: time.Date(2022, time.September, 14, 17, 45, 3, 0, time.UTC),
- LogoutDateTime: time.Date(2022, time.September, 14, 19, 45, 3, 0, time.UTC),
- State: "LOGGED_IN",
- Response: "Authentication Error: Ensure that your username and password are correct.",
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_CreateAuthenticatedContext(t *testing.T) {
- client := mockBuilder().
- Route("POST /api/v2/sessions",
- servermock.ResponseFromFixture("postSession.json"),
- servermock.CheckRequestJSONBodyFromFixture("postSession-request.json"),
- ).
- Build(t)
-
- ctx, err := client.CreateAuthenticatedContext(t.Context())
- require.NoError(t, err)
-
- assert.Equal(t, "YXBpOlQ0OExOT3VIRGhDcnVBNEo1bGFES3JuS3hTZC9QK3pjczZXTzBJMDY=", getToken(ctx))
-}
diff --git a/providers/dns/bluecatv2/internal/predicates.go b/providers/dns/bluecatv2/internal/predicates.go
deleted file mode 100644
index 8ed6f714b..000000000
--- a/providers/dns/bluecatv2/internal/predicates.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strings"
-)
-
-type Predicate struct {
- field string
- operator string
- values []string
-}
-
-func (p *Predicate) String() string {
- var values []string
- for _, v := range p.values {
- values = append(values, fmt.Sprintf("'%s'", v))
- }
-
- return fmt.Sprintf("%s:%s(%s)", p.field, p.operator, strings.Join(values, ", "))
-}
-
-func Eq(field, value string) *Predicate {
- return &Predicate{field: field, operator: "eq", values: []string{value}}
-}
-
-func Contains(field, value string) *Predicate {
- return &Predicate{field: field, operator: "contains", values: []string{value}}
-}
-
-func StartsWith(field, value string) *Predicate {
- return &Predicate{field: field, operator: "startsWith", values: []string{value}}
-}
-
-func EndsWith(field, value string) *Predicate {
- return &Predicate{field: field, operator: "endsWith", values: []string{value}}
-}
-
-func In(field string, values ...string) *Predicate {
- return &Predicate{field: field, operator: "in", values: values}
-}
-
-type Combined struct {
- predicates []*Predicate
- operator string
-}
-
-func (o *Combined) String() string {
- var parts []string
-
- for _, predicate := range o.predicates {
- parts = append(parts, predicate.String())
- }
-
- return strings.Join(parts, " "+o.operator+" ")
-}
-
-func And(predicates ...*Predicate) *Combined {
- return &Combined{predicates: predicates, operator: "and"}
-}
-
-func Or(predicates ...*Predicate) *Combined {
- return &Combined{predicates: predicates, operator: "or"}
-}
diff --git a/providers/dns/bluecatv2/internal/predicates_test.go b/providers/dns/bluecatv2/internal/predicates_test.go
deleted file mode 100644
index 6913e8729..000000000
--- a/providers/dns/bluecatv2/internal/predicates_test.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package internal
-
-import (
- "fmt"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestPredicate(t *testing.T) {
- testCases := []struct {
- desc string
- predicate fmt.Stringer
- expected string
- }{
- {
- desc: "Equals",
- predicate: Eq("foo", "bar"),
- expected: "foo:eq('bar')",
- },
- {
- desc: "Contains",
- predicate: Contains("foo", "bar"),
- expected: "foo:contains('bar')",
- },
- {
- desc: "Starts with",
- predicate: StartsWith("foo", "bar"),
- expected: "foo:startsWith('bar')",
- },
- {
- desc: "Ends with",
- predicate: EndsWith("foo", "bar"),
- expected: "foo:endsWith('bar')",
- },
- {
- desc: "Match a list of values",
- predicate: In("foo", "bar", "bir"),
- expected: "foo:in('bar', 'bir')",
- },
- {
- desc: "Combined: and",
- predicate: And(Eq("foo", "bar"), Eq("fii", "bir")),
- expected: "foo:eq('bar') and fii:eq('bir')",
- },
- {
- desc: "Combined: multiple and",
- predicate: And(
- Eq("foo", "bar"),
- Eq("fii", "bir"),
- Eq("fuu", "bur"),
- ),
- expected: "foo:eq('bar') and fii:eq('bir') and fuu:eq('bur')",
- },
- {
- desc: "Combined: or",
- predicate: Or(Eq("foo", "bar"), Eq("foo", "bir")),
- expected: "foo:eq('bar') or foo:eq('bir')",
- },
- {
- desc: "Combined: multiple or",
- predicate: Or(
- Eq("foo", "bar"),
- Eq("foo", "bir"),
- Eq("foo", "bur"),
- ),
- expected: "foo:eq('bar') or foo:eq('bir') or foo:eq('bur')",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- assert.Equal(t, test.expected, test.predicate.String())
- })
- }
-}
diff --git a/providers/dns/bluecatv2/internal/types.go b/providers/dns/bluecatv2/internal/types.go
deleted file mode 100644
index 562fd60b0..000000000
--- a/providers/dns/bluecatv2/internal/types.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package internal
-
-import (
- "fmt"
- "time"
-)
-
-// Quick deployment states.
-//
-//nolint:misspell // US vs UK
-const (
- QDStatePending = "PENDING"
- QDStateQueued = "QUEUED"
- QDStateRunning = "RUNNING"
- QDStateCancelled = "CANCELLED"
- QDStateCancelling = "CANCELLING"
- QDStateCompleted = "COMPLETED"
- QDStateCompletedWithErrors = "COMPLETED_WITH_ERRORS"
- QDStateCompletedWithWarnings = "COMPLETED_WITH_WARNINGS"
- QDStateFailed = "FAILED"
- QDStateUnknown = "UNKNOWN"
-)
-
-// APIError represents an error.
-// https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Errors/9.6.0
-type APIError struct {
- Status int `json:"status"`
- Reason string `json:"reason"`
- Code string `json:"code"`
- Message string `json:"message"`
-}
-
-func (a *APIError) Error() string {
- return fmt.Sprintf("%d: %s: %s: %s", a.Status, a.Reason, a.Code, a.Message)
-}
-
-// CommonResource represents the common resource fields.
-// https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Resources/9.6.0
-type CommonResource struct {
- ID int64 `json:"id,omitempty"`
- Type string `json:"type,omitempty"`
- Name string `json:"name,omitempty"`
-}
-
-// Collection represents a collection of resources.
-// https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Collections/9.6.0
-type Collection[T any] struct {
- Count int64 `json:"count"`
- TotalCount int64 `json:"totalCount"`
- Data []T `json:"data"`
-}
-
-type CollectionOptions struct {
- // https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Fields/9.6.0
- Fields string `url:"fields,omitempty"`
-
- // https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Pagination/9.6.0
- Limit int `url:"limit,omitempty"`
- Offset int `url:"offset,omitempty"`
-
- // https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Filter/9.6.0
- Filter string `url:"filter,omitempty"`
-
- // https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Ordering/9.6.0
- OrderBy string `url:"orderBy,omitempty"`
-
- // Should return or not the total number of resources matching the query.
- Total bool `url:"total,omitempty"`
-}
-
-type RecordTXT struct {
- CommonResource
-
- TTL int `json:"ttl,omitempty"`
- AbsoluteName string `json:"absoluteName,omitempty"`
- Comment string `json:"comment,omitempty"`
- Dynamic bool `json:"dynamic,omitempty"`
- RecordType string `json:"recordType,omitempty"`
- Text string `json:"text,omitempty"`
-}
-
-type ZoneResource struct {
- CommonResource
-
- AbsoluteName string `json:"absoluteName,omitempty"`
-}
-
-type QuickDeployment struct {
- CommonResource
-
- State string `json:"state,omitempty"`
- Status string `json:"status,omitempty"`
- Message string `json:"message,omitempty"`
- PercentComplete int `json:"percentComplete,omitempty"`
- CreationDateTime time.Time `json:"creationDateTime,omitzero"`
- StartDateTime time.Time `json:"startDateTime,omitzero"`
- CompletionDateTime time.Time `json:"completionDateTime,omitzero"`
- Method string `json:"method,omitempty"`
-}
-
-// LoginInfo represents the login information.
-// https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Creating-an-API-session/9.6.0
-type LoginInfo struct {
- Username string `json:"username"`
- Password string `json:"password"`
-}
-
-// Session represents the session.
-// https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Creating-an-API-session/9.6.0
-type Session struct {
- ID int `json:"id"`
- Type string `json:"type"`
- APIToken string `json:"apiToken"`
- APITokenExpirationDateTime time.Time `json:"apiTokenExpirationDateTime"`
- BasicAuthenticationCredentials string `json:"basicAuthenticationCredentials"`
- RemoteAddress string `json:"remoteAddress"`
- ReadOnly bool `json:"readOnly"`
- LoginDateTime time.Time `json:"loginDateTime"`
- LogoutDateTime time.Time `json:"logoutDateTime"`
- State string `json:"state"`
- Response string `json:"response"`
-}
diff --git a/providers/dns/bookmyname/bookmyname.go b/providers/dns/bookmyname/bookmyname.go
index 6f42dfd78..991420619 100644
--- a/providers/dns/bookmyname/bookmyname.go
+++ b/providers/dns/bookmyname/bookmyname.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/bookmyname/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -88,8 +87,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/bookmyname/bookmyname.toml b/providers/dns/bookmyname/bookmyname.toml
index 76fcb85e7..5111c4fbd 100644
--- a/providers/dns/bookmyname/bookmyname.toml
+++ b/providers/dns/bookmyname/bookmyname.toml
@@ -7,7 +7,7 @@ Since = "v4.23.0"
Example = '''
BOOKMYNAME_USERNAME="xxx" \
BOOKMYNAME_PASSWORD="yyy" \
-lego --dns bookmyname -d '*.example.com' -d example.com run
+lego --email you@example.com --dns bookmyname -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/bookmyname/bookmyname_test.go b/providers/dns/bookmyname/bookmyname_test.go
index 8b3fa21e6..dd02d63d7 100644
--- a/providers/dns/bookmyname/bookmyname_test.go
+++ b/providers/dns/bookmyname/bookmyname_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -123,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/brandit/brandit.go b/providers/dns/brandit/brandit.go
index fe3b52239..437d1642a 100644
--- a/providers/dns/brandit/brandit.go
+++ b/providers/dns/brandit/brandit.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/brandit/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -93,8 +92,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -168,7 +165,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordsMu.Lock()
dnsRecord, ok := d.records[token]
d.recordsMu.Unlock()
-
if !ok {
return fmt.Errorf("brandit: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
@@ -187,7 +183,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var recordID int
-
for i, r := range records.RR {
if r == dnsRecord {
recordID = i
diff --git a/providers/dns/brandit/brandit.toml b/providers/dns/brandit/brandit.toml
index 4c43e27a9..32d15c15c 100644
--- a/providers/dns/brandit/brandit.toml
+++ b/providers/dns/brandit/brandit.toml
@@ -12,7 +12,7 @@ Since = "v4.11.0"
Example = '''
BRANDIT_API_KEY=xxxxxxxxxxxxxxxxxxxxx \
BRANDIT_API_USERNAME=yyyyyyyyyyyyyyyyyyyy \
-lego --dns brandit -d '*.example.com' -d example.com run
+lego --email you@example.com --dns brandit -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/brandit/brandit_test.go b/providers/dns/brandit/brandit_test.go
index 40abdd3d0..156e7c3f4 100644
--- a/providers/dns/brandit/brandit_test.go
+++ b/providers/dns/brandit/brandit_test.go
@@ -48,7 +48,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -121,7 +120,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -135,7 +133,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/brandit/internal/client.go b/providers/dns/brandit/internal/client.go
index cda3be5a2..59c57419a 100644
--- a/providers/dns/brandit/internal/client.go
+++ b/providers/dns/brandit/internal/client.go
@@ -62,7 +62,6 @@ func (c *Client) ListRecords(ctx context.Context, account, dnsZone string) (*Lis
query.Add("first", strconv.Itoa(result.Response.Last[0]+1))
tmp := &Response[*ListRecordsResponse]{}
-
err := c.do(ctx, query, tmp)
if err != nil {
return nil, err
@@ -157,7 +156,6 @@ func (c *Client) do(ctx context.Context, query url.Values, result any) error {
// Unmarshal the error response, because the API returns a 200 OK even if there is an error.
var apiError APIError
-
err = json.Unmarshal(raw, &apiError)
if err != nil {
return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -185,7 +183,6 @@ func sign(apiUsername, apiKey string, query url.Values) (url.Values, error) {
canonicalRequest := fmt.Sprintf("%s%s%s", apiUsername, timestamp, defaultBaseURL)
mac := hmac.New(sha256.New, []byte(apiKey))
-
_, err := mac.Write([]byte(canonicalRequest))
if err != nil {
return nil, err
diff --git a/providers/dns/bunny/bunny.go b/providers/dns/bunny/bunny.go
index 29949608b..1489d1c5e 100644
--- a/providers/dns/bunny/bunny.go
+++ b/providers/dns/bunny/bunny.go
@@ -5,16 +5,13 @@ import (
"context"
"errors"
"fmt"
- "net/http"
"slices"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/ptr"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
"github.com/nrdcg/bunny-go"
"golang.org/x/net/publicsuffix"
)
@@ -28,7 +25,6 @@ const (
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
const minTTL = 60
@@ -37,12 +33,10 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- APIKey string
-
+ APIKey string
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
- HTTPClient *http.Client
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
@@ -51,9 +45,6 @@ func NewDefaultConfig() *Config {
TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
}
}
@@ -91,19 +82,9 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("bunny: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
}
- if config.HTTPClient == nil {
- config.HTTPClient = &http.Client{Timeout: 30 * time.Second}
- }
+ client := bunny.NewClient(config.APIKey)
- config.HTTPClient = clientdebug.Wrap(config.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: bunny.NewClient(config.APIKey,
- bunny.WithUserAgent(useragent.Get()),
- bunny.WithHTTPClient(config.HTTPClient),
- ),
- }, nil
+ return &DNSProvider{config: config, client: client}, nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
@@ -159,12 +140,10 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var record *bunny.DNSRecord
-
for _, r := range zone.Records {
if ptr.Deref(r.Name) == subDomain && ptr.Deref(r.Type) == bunny.DNSRecordTypeTXT {
r := r
record = &r
-
break
}
}
@@ -200,7 +179,6 @@ func findZone(zones *bunny.DNSZones, domain string) *bunny.DNSZone {
var domainLength int
var zone *bunny.DNSZone
-
for _, item := range zones.Items {
if item == nil {
continue
diff --git a/providers/dns/bunny/bunny.toml b/providers/dns/bunny/bunny.toml
index 758c4f202..bdbbf3177 100644
--- a/providers/dns/bunny/bunny.toml
+++ b/providers/dns/bunny/bunny.toml
@@ -6,7 +6,7 @@ Since = "v4.11.0"
Example = '''
BUNNY_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
-lego --dns bunny -d '*.example.com' -d example.com run
+lego --email you@example.com --dns bunny -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -16,7 +16,6 @@ lego --dns bunny -d '*.example.com' -d example.com run
BUNNY_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
BUNNY_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
BUNNY_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"
- BUNNY_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
[Links]
API = "https://docs.bunny.net/reference/dnszonepublic_index"
diff --git a/providers/dns/bunny/bunny_test.go b/providers/dns/bunny/bunny_test.go
index ca4e821e0..4cf0f6b01 100644
--- a/providers/dns/bunny/bunny_test.go
+++ b/providers/dns/bunny/bunny_test.go
@@ -40,7 +40,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -108,7 +107,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -122,7 +120,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/checkdomain/checkdomain.go b/providers/dns/checkdomain/checkdomain.go
index 4bc926ed9..e2d7a05aa 100644
--- a/providers/dns/checkdomain/checkdomain.go
+++ b/providers/dns/checkdomain/checkdomain.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/checkdomain/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -73,7 +72,6 @@ func NewDNSProvider() (*DNSProvider, error) {
if err != nil {
return nil, fmt.Errorf("checkdomain: invalid %s: %w", EnvEndpoint, err)
}
-
config.Endpoint = endpoint
return NewDNSProviderConfig(config)
@@ -88,11 +86,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("checkdomain: missing token")
}
- client := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.Token),
- ),
- )
+ client := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.Token))
if config.Endpoint != nil {
client.BaseURL = config.Endpoint
diff --git a/providers/dns/checkdomain/checkdomain.toml b/providers/dns/checkdomain/checkdomain.toml
index 0b93058ba..c3ac14e36 100644
--- a/providers/dns/checkdomain/checkdomain.toml
+++ b/providers/dns/checkdomain/checkdomain.toml
@@ -6,7 +6,7 @@ Since = "v3.3.0"
Example = '''
CHECKDOMAIN_TOKEN=yoursecrettoken \
-lego --dns checkdomain -d '*.example.com' -d example.com run
+lego --email you@example.com --dns checkdomain -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/checkdomain/checkdomain_test.go b/providers/dns/checkdomain/checkdomain_test.go
index b2c940f7a..d9d0b62a6 100644
--- a/providers/dns/checkdomain/checkdomain_test.go
+++ b/providers/dns/checkdomain/checkdomain_test.go
@@ -46,7 +46,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -109,7 +108,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -123,7 +121,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/checkdomain/internal/client.go b/providers/dns/checkdomain/internal/client.go
index 68d090755..74189dee4 100644
--- a/providers/dns/checkdomain/internal/client.go
+++ b/providers/dns/checkdomain/internal/client.go
@@ -36,11 +36,11 @@ const maxInt = int((^uint(0)) >> 1)
// Client the Autodns API client.
type Client struct {
- BaseURL *url.URL
- httpClient *http.Client
-
domainIDMapping map[string]int
domainIDMu sync.Mutex
+
+ BaseURL *url.URL
+ httpClient *http.Client
}
// NewClient creates a new Client.
@@ -63,7 +63,6 @@ func (c *Client) GetDomainIDByName(ctx context.Context, name string) (int, error
c.domainIDMu.Lock()
id, ok := c.domainIDMapping[name]
c.domainIDMu.Unlock()
-
if ok {
return id, nil
}
@@ -101,7 +100,6 @@ func (c *Client) listDomains(ctx context.Context) ([]*Domain, error) {
totalPages := maxInt
var domainList []*Domain
-
for currentPage <= totalPages {
q.Set("page", strconv.Itoa(currentPage))
endpoint.RawQuery = q.Encode()
@@ -153,7 +151,6 @@ func (c *Client) CheckNameservers(ctx context.Context, domainID int) error {
}
var found1, found2 bool
-
for _, item := range info.Nameservers {
switch item.Name {
case ns1:
@@ -232,7 +229,6 @@ func (c *Client) getDomainInfo(ctx context.Context, domainID int) (*DomainRespon
}
var res DomainResponse
-
err = c.do(req, &res)
if err != nil {
return nil, err
@@ -246,7 +242,6 @@ func (c *Client) listRecords(ctx context.Context, domainID int, recordType strin
q := endpoint.Query()
q.Set("limit", strconv.Itoa(maxLimit))
-
if recordType != "" {
q.Set("type", recordType)
}
@@ -255,7 +250,6 @@ func (c *Client) listRecords(ctx context.Context, domainID int, recordType strin
totalPages := maxInt
var recordList []*Record
-
for currentPage <= totalPages {
q.Set("page", strconv.Itoa(currentPage))
endpoint.RawQuery = q.Encode()
diff --git a/providers/dns/civo/civo.go b/providers/dns/civo/civo.go
index dfb7c307f..46c474b52 100644
--- a/providers/dns/civo/civo.go
+++ b/providers/dns/civo/civo.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/civo/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -92,11 +91,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}
// Create a Civo client - DNS is region independent, we can use any region
- client, err := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.Token),
- ),
- "LON1")
+ client, err := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.Token), "LON1")
if err != nil {
return nil, fmt.Errorf("civo: %w", err)
}
@@ -169,7 +164,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var dnsRecord internal.Record
-
for _, entry := range dnsRecords {
if entry.Name == subDomain && entry.Value == info.Value {
dnsRecord = entry
diff --git a/providers/dns/civo/civo.toml b/providers/dns/civo/civo.toml
index b525712c8..9458f01c3 100644
--- a/providers/dns/civo/civo.toml
+++ b/providers/dns/civo/civo.toml
@@ -6,7 +6,7 @@ Since = "v4.9.0"
Example = '''
CIVO_TOKEN=xxxxxx \
-lego --dns civo -d '*.example.com' -d example.com run
+lego --email you@example.com --dns civo -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/civo/civo_test.go b/providers/dns/civo/civo_test.go
index 416dbac1d..eb215fbcb 100644
--- a/providers/dns/civo/civo_test.go
+++ b/providers/dns/civo/civo_test.go
@@ -42,7 +42,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -107,7 +106,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -121,7 +119,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -135,7 +132,6 @@ func mockBuilder() *servermock.Builder[*DNSProvider] {
return servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
config.Token = "secret"
p, err := NewDNSProviderConfig(config)
diff --git a/providers/dns/civo/internal/client.go b/providers/dns/civo/internal/client.go
index dc1d57793..25a11ef60 100644
--- a/providers/dns/civo/internal/client.go
+++ b/providers/dns/civo/internal/client.go
@@ -188,7 +188,6 @@ 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)
diff --git a/providers/dns/civo/internal/client_test.go b/providers/dns/civo/internal/client_test.go
index ad56b75de..5b47c185e 100644
--- a/providers/dns/civo/internal/client_test.go
+++ b/providers/dns/civo/internal/client_test.go
@@ -93,6 +93,7 @@ func TestClient_ListDNSRecords_error_raw(t *testing.T) {
// > So, for example, 404 Not Found pages are a standard page of text
// > but 403 Unauthorized requests may have a reason attribute available in the JSON object.
// https://www.civo.com/api#parameters-and-responses
+
client := mockBuilder().
Route("GET /dns/7088fcea-7658-43e6-97fa-273f901978fd/records",
servermock.RawStringResponse(http.StatusText(http.StatusNotFound)).
diff --git a/providers/dns/clouddns/clouddns.go b/providers/dns/clouddns/clouddns.go
index 77b673738..379dd3cf2 100644
--- a/providers/dns/clouddns/clouddns.go
+++ b/providers/dns/clouddns/clouddns.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/clouddns/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -94,8 +93,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{client: client, config: config}, nil
}
diff --git a/providers/dns/clouddns/clouddns.toml b/providers/dns/clouddns/clouddns.toml
index 6f516e834..154d4da67 100644
--- a/providers/dns/clouddns/clouddns.toml
+++ b/providers/dns/clouddns/clouddns.toml
@@ -8,7 +8,7 @@ Example = '''
CLOUDDNS_CLIENT_ID=bLsdFAks23429841238feb177a572aX \
CLOUDDNS_EMAIL=you@example.com \
CLOUDDNS_PASSWORD=b9841238feb177a84330f \
-lego --dns clouddns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns clouddns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/clouddns/clouddns_test.go b/providers/dns/clouddns/clouddns_test.go
index f1e2a196e..d7bfc4a1f 100644
--- a/providers/dns/clouddns/clouddns_test.go
+++ b/providers/dns/clouddns/clouddns_test.go
@@ -63,7 +63,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -149,7 +148,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -163,7 +161,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/clouddns/internal/client.go b/providers/dns/clouddns/internal/client.go
index 9fb6902de..cd3da50c7 100644
--- a/providers/dns/clouddns/internal/client.go
+++ b/providers/dns/clouddns/internal/client.go
@@ -122,7 +122,6 @@ func (c *Client) getDomain(ctx context.Context, zone string) (Domain, error) {
}
var result SearchResponse
-
err = c.do(req, &result)
if err != nil {
return Domain{}, err
@@ -144,7 +143,6 @@ func (c *Client) getRecord(ctx context.Context, domainID, recordName string) (Re
}
var result DomainInfo
-
err = c.do(req, &result)
if err != nil {
return Record{}, err
@@ -234,7 +232,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var response APIError
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/clouddns/internal/identity.go b/providers/dns/clouddns/internal/identity.go
index 6b20ad814..4ea5c5049 100644
--- a/providers/dns/clouddns/internal/identity.go
+++ b/providers/dns/clouddns/internal/identity.go
@@ -20,7 +20,6 @@ func (c *Client) login(ctx context.Context) (*AuthResponse, error) {
}
var result AuthResponse
-
err = c.do(req, &result)
if err != nil {
return nil, err
diff --git a/providers/dns/clouddns/internal/types.go b/providers/dns/clouddns/internal/types.go
index 9de11d848..a53c958a7 100644
--- a/providers/dns/clouddns/internal/types.go
+++ b/providers/dns/clouddns/internal/types.go
@@ -21,7 +21,7 @@ type Authorization struct {
}
type AuthResponse struct {
- Auth Auth `json:"auth"`
+ Auth Auth `json:"auth,omitempty"`
}
type Auth struct {
diff --git a/providers/dns/cloudflare/cloudflare.go b/providers/dns/cloudflare/cloudflare.go
index 98b3495bb..5fd350925 100644
--- a/providers/dns/cloudflare/cloudflare.go
+++ b/providers/dns/cloudflare/cloudflare.go
@@ -104,7 +104,6 @@ func NewDNSProvider() (*DNSProvider, error) {
)
if err != nil {
var errT error
-
values, errT = env.GetWithFallback(
[]string{EnvDNSAPIToken, altEnvName(EnvDNSAPIToken)},
[]string{EnvZoneAPIToken, altEnvName(EnvZoneAPIToken), EnvDNSAPIToken, altEnvName(EnvDNSAPIToken)},
@@ -155,10 +154,10 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
+ ctx := context.Background()
+
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("cloudflare: could not find zone for domain %q: %w", domain, err)
@@ -192,8 +191,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
@@ -201,7 +198,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("cloudflare: could not find zone for domain %q: %w", domain, err)
}
- zoneID, err := d.client.ZoneIDByName(ctx, authZone)
+ zoneID, err := d.client.ZoneIDByName(context.Background(), authZone)
if err != nil {
return fmt.Errorf("cloudflare: failed to find zone %s: %w", authZone, err)
}
@@ -210,12 +207,11 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("cloudflare: unknown record ID for '%s'", info.EffectiveFQDN)
}
- err = d.client.DeleteDNSRecord(ctx, zoneID, recordID)
+ err = d.client.DeleteDNSRecord(context.Background(), zoneID, recordID)
if err != nil {
log.Printf("cloudflare: failed to delete TXT record: %v", err)
}
diff --git a/providers/dns/cloudflare/cloudflare.toml b/providers/dns/cloudflare/cloudflare.toml
index c46130fe6..caf132bb4 100644
--- a/providers/dns/cloudflare/cloudflare.toml
+++ b/providers/dns/cloudflare/cloudflare.toml
@@ -7,12 +7,12 @@ Since = "v0.3.0"
Example = '''
CLOUDFLARE_EMAIL=you@example.com \
CLOUDFLARE_API_KEY=b9841238feb177a84330febba8a83208921177bffe733 \
-lego --dns cloudflare -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudflare -d '*.example.com' -d example.com run
# or
CLOUDFLARE_DNS_API_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz \
-lego --dns cloudflare -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudflare -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/cloudflare/cloudflare_test.go b/providers/dns/cloudflare/cloudflare_test.go
index 8de9dd848..10e96503a 100644
--- a/providers/dns/cloudflare/cloudflare_test.go
+++ b/providers/dns/cloudflare/cloudflare_test.go
@@ -81,7 +81,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -178,18 +177,15 @@ func TestNewDNSProviderWithToken(t *testing.T) {
}
defer envTest.RestoreEnv()
-
localEnvTest := tester.NewEnvTest(
EnvDNSAPIToken, altEnvName(EnvDNSAPIToken),
EnvZoneAPIToken, altEnvName(EnvZoneAPIToken),
).WithDomain(envDomain)
-
envTest.ClearEnv()
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer localEnvTest.RestoreEnv()
-
localEnvTest.ClearEnv()
localEnvTest.Apply(test.envVars)
@@ -204,7 +200,6 @@ func TestNewDNSProviderWithToken(t *testing.T) {
require.NotNil(t, p)
assert.Equal(t, test.expected.dnsToken, p.config.AuthToken)
assert.Equal(t, test.expected.zoneToken, p.config.ZoneToken)
-
if test.expected.sameClient {
assert.Equal(t, p.client.clientRead, p.client.clientEdit)
} else {
@@ -280,7 +275,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -294,7 +288,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -311,7 +304,6 @@ func mockBuilder() *servermock.Builder[*DNSProvider] {
config.AuthEmail = "foo@example.com"
config.AuthKey = "secret"
config.BaseURL = server.URL
- config.HTTPClient = server.Client()
return NewDNSProviderConfig(config)
},
diff --git a/providers/dns/cloudflare/internal/client.go b/providers/dns/cloudflare/internal/client.go
index b63612ce2..495ba5618 100644
--- a/providers/dns/cloudflare/internal/client.go
+++ b/providers/dns/cloudflare/internal/client.go
@@ -17,7 +17,6 @@ import (
"net/url"
"time"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
)
@@ -62,8 +61,6 @@ func NewClient(opts ...Option) (*Client, error) {
return nil, errors.New("invalid credentials: authEmail and authKey must be set together")
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return client, nil
}
@@ -87,7 +84,7 @@ func (c *Client) CreateDNSRecord(ctx context.Context, zoneID string, record Reco
return &result.Result, nil
}
-// DeleteDNSRecord deletes DNS record.
+// DeleteDNSRecord Delete DNS record.
// https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/delete/
func (c *Client) DeleteDNSRecord(ctx context.Context, zoneID, recordID string) error {
endpoint := c.baseURL.JoinPath("zones", zoneID, "dns_records", recordID)
@@ -100,7 +97,6 @@ func (c *Client) DeleteDNSRecord(ctx context.Context, zoneID, recordID string) e
return c.do(req, nil)
}
-// ZonesByName returns a list of zones matching the given name.
// https://developers.cloudflare.com/api/resources/zones/methods/list/
func (c *Client) ZonesByName(ctx context.Context, name string) ([]Zone, error) {
endpoint := c.baseURL.JoinPath("zones")
@@ -192,7 +188,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var response APIResponse[any]
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/cloudflare/internal/types.go b/providers/dns/cloudflare/internal/types.go
index 50a7bbbf9..2b6d2e2b6 100644
--- a/providers/dns/cloudflare/internal/types.go
+++ b/providers/dns/cloudflare/internal/types.go
@@ -1,9 +1,6 @@
package internal
-import (
- "fmt"
- "strings"
-)
+import "fmt"
type Record struct {
ID string `json:"id,omitempty"`
@@ -42,17 +39,17 @@ type ErrorChain struct {
type Errors []Message
func (e Errors) Error() string {
- msg := new(strings.Builder)
+ var msg string
for _, item := range e {
- _, _ = fmt.Fprintf(msg, "%d: %s", item.Code, item.Message)
+ msg = fmt.Sprintf("%d: %s", item.Code, item.Message)
for _, link := range item.ErrorChain {
- _, _ = fmt.Fprintf(msg, "; %d: %s", link.Code, link.Message)
+ msg += fmt.Sprintf("; %d: %s", link.Code, link.Message)
}
}
- return msg.String()
+ return msg
}
type ResultInfo struct {
diff --git a/providers/dns/cloudflare/wrapper.go b/providers/dns/cloudflare/wrapper.go
index 286c20ecd..1ab36800d 100644
--- a/providers/dns/cloudflare/wrapper.go
+++ b/providers/dns/cloudflare/wrapper.go
@@ -99,7 +99,6 @@ func (m *metaClient) ZoneIDByName(ctx context.Context, fdqn string) (string, err
m.zonesMu.Lock()
m.zones[fdqn] = id
m.zonesMu.Unlock()
-
return id, nil
}
diff --git a/providers/dns/cloudns/cloudns.go b/providers/dns/cloudns/cloudns.go
index 916d73bde..ef6524c4d 100644
--- a/providers/dns/cloudns/cloudns.go
+++ b/providers/dns/cloudns/cloudns.go
@@ -8,14 +8,12 @@ import (
"net/http"
"time"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/platform/wait"
"github.com/go-acme/lego/v4/providers/dns/cloudns/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -68,7 +66,6 @@ type DNSProvider struct {
// CLOUDNS_AUTH_ID and CLOUDNS_AUTH_PASSWORD.
func NewDNSProvider() (*DNSProvider, error) {
var subAuthID string
-
authID := env.GetOrFile(EnvAuthID)
if authID == "" {
subAuthID = env.GetOrFile(EnvSubAuthID)
@@ -102,11 +99,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("ClouDNS: %w", err)
}
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
+ client.HTTPClient = config.HTTPClient
return &DNSProvider{client: client, config: config}, nil
}
@@ -169,22 +162,14 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
// waitNameservers At the time of writing 4 servers are found as authoritative, but 8 are reported during the sync.
// If this is not done, the secondary verification done by Let's Encrypt server will fail quire a bit.
func (d *DNSProvider) waitNameservers(ctx context.Context, domain string, zone *internal.Zone) error {
- return wait.Retry(ctx,
- func() error {
- syncProgress, err := d.client.GetUpdateStatus(ctx, zone.Name)
- if err != nil {
- return fmt.Errorf("nameserver sync on %s: %w", domain, err)
- }
+ return wait.For("Nameserver sync on "+domain, d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
+ syncProgress, err := d.client.GetUpdateStatus(ctx, zone.Name)
+ if err != nil {
+ return false, err
+ }
- log.Infof("[%s] Sync %d/%d complete", domain, syncProgress.Updated, syncProgress.Total)
+ log.Infof("[%s] Sync %d/%d complete", domain, syncProgress.Updated, syncProgress.Total)
- if !syncProgress.Complete {
- return fmt.Errorf("nameserver sync on %s not complete", domain)
- }
-
- return nil
- },
- backoff.WithBackOff(backoff.NewConstantBackOff(d.config.PollingInterval)),
- backoff.WithMaxElapsedTime(d.config.PropagationTimeout),
- )
+ return syncProgress.Complete, nil
+ })
}
diff --git a/providers/dns/cloudns/cloudns.toml b/providers/dns/cloudns/cloudns.toml
index ad52ef5b1..dd191f06a 100644
--- a/providers/dns/cloudns/cloudns.toml
+++ b/providers/dns/cloudns/cloudns.toml
@@ -7,7 +7,7 @@ Since = "v2.3.0"
Example = '''
CLOUDNS_AUTH_ID=xxxx \
CLOUDNS_AUTH_PASSWORD=yyyy \
-lego --dns cloudns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/cloudns/cloudns_test.go b/providers/dns/cloudns/cloudns_test.go
index 024bd93d8..ea4f25c95 100644
--- a/providers/dns/cloudns/cloudns_test.go
+++ b/providers/dns/cloudns/cloudns_test.go
@@ -79,7 +79,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -170,7 +169,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -184,7 +182,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/cloudns/internal/client.go b/providers/dns/cloudns/internal/client.go
index 278b8de49..60d7e6bbe 100644
--- a/providers/dns/cloudns/internal/client.go
+++ b/providers/dns/cloudns/internal/client.go
@@ -171,7 +171,6 @@ func (c *Client) ListTxtRecords(ctx context.Context, zoneName, fqdn string) ([]T
}
var records []TXTRecord
-
for _, record := range raw {
if record.Host == subDomain && record.Type == "TXT" {
records = append(records, record)
@@ -280,7 +279,6 @@ func (c *Client) GetUpdateStatus(ctx context.Context, zoneName string) (*SyncPro
}
updatedCount := 0
-
for _, record := range records {
if record.Updated {
updatedCount++
diff --git a/providers/dns/cloudns/internal/client_test.go b/providers/dns/cloudns/internal/client_test.go
index b9f6c5431..dbfa32aee 100644
--- a/providers/dns/cloudns/internal/client_test.go
+++ b/providers/dns/cloudns/internal/client_test.go
@@ -19,7 +19,6 @@ func setupClient(subAuthID string) func(server *httptest.Server) (*Client, error
client.BaseURL, _ = url.Parse(server.URL)
client.HTTPClient = server.Client()
-
return client, nil
}
}
diff --git a/providers/dns/cloudru/cloudru.go b/providers/dns/cloudru/cloudru.go
index dd597952a..314c20445 100644
--- a/providers/dns/cloudru/cloudru.go
+++ b/providers/dns/cloudru/cloudru.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/cloudru/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -61,9 +60,8 @@ func NewDefaultConfig() *Config {
}
type DNSProvider struct {
- config *Config
- client *internal.Client
-
+ config *Config
+ client *internal.Client
records map[string]*internal.Record
recordsMu sync.Mutex
}
@@ -101,8 +99,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/cloudru/cloudru.toml b/providers/dns/cloudru/cloudru.toml
index b74098a72..a6563a3df 100644
--- a/providers/dns/cloudru/cloudru.toml
+++ b/providers/dns/cloudru/cloudru.toml
@@ -8,7 +8,7 @@ Example = '''
CLOUDRU_SERVICE_INSTANCE_ID=ppp \
CLOUDRU_KEY_ID=xxx \
CLOUDRU_SECRET=yyy \
-lego --dns cloudru -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudru -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/cloudru/cloudru_test.go b/providers/dns/cloudru/cloudru_test.go
index 3e506cb1c..88addde93 100644
--- a/providers/dns/cloudru/cloudru_test.go
+++ b/providers/dns/cloudru/cloudru_test.go
@@ -67,7 +67,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -154,7 +153,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -168,7 +166,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/cloudru/internal/client.go b/providers/dns/cloudru/internal/client.go
index a00ae6ea8..cb62c5bca 100644
--- a/providers/dns/cloudru/internal/client.go
+++ b/providers/dns/cloudru/internal/client.go
@@ -61,7 +61,6 @@ func (c *Client) GetZones(ctx context.Context, parentID string) ([]Zone, error)
}
var zones APIResponse[Zone]
-
err = c.do(req, &zones)
if err != nil {
return nil, err
@@ -79,7 +78,6 @@ func (c *Client) GetRecords(ctx context.Context, zoneID string) ([]Record, error
}
var records APIResponse[Record]
-
err = c.do(req, &records)
if err != nil {
return nil, err
@@ -97,7 +95,6 @@ func (c *Client) CreateRecord(ctx context.Context, zoneID string, record Record)
}
var result Record
-
err = c.do(req, &result)
if err != nil {
return nil, err
diff --git a/providers/dns/cloudru/internal/identity.go b/providers/dns/cloudru/internal/identity.go
index 3bb09f3fa..79df3c297 100644
--- a/providers/dns/cloudru/internal/identity.go
+++ b/providers/dns/cloudru/internal/identity.go
@@ -49,7 +49,6 @@ func (c *Client) obtainToken(ctx context.Context) (*Token, error) {
}
tok := Token{}
-
err = json.Unmarshal(raw, &tok)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -89,7 +88,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errResp := &authResponseError{}
-
err := json.Unmarshal(raw, errResp)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/cloudru/internal/types.go b/providers/dns/cloudru/internal/types.go
index 713fd459a..d233c73bc 100644
--- a/providers/dns/cloudru/internal/types.go
+++ b/providers/dns/cloudru/internal/types.go
@@ -38,9 +38,9 @@ type Zone struct {
Valid bool `json:"valid,omitempty"`
ValidationText string `json:"validationText,omitempty"`
Delegated bool `json:"delegated,omitempty"`
- LastCheck time.Time `json:"lastCheck,omitzero"`
- CreatedAt time.Time `json:"created_at,omitzero"`
- UpdatedAt time.Time `json:"updated_at,omitzero"`
+ LastCheck time.Time `json:"lastCheck,omitempty"`
+ CreatedAt time.Time `json:"created_at,omitempty"`
+ UpdatedAt time.Time `json:"updated_at,omitempty"`
}
type Record struct {
diff --git a/providers/dns/cloudxns/cloudxns.toml b/providers/dns/cloudxns/cloudxns.toml
index 32eae8beb..e87a741df 100644
--- a/providers/dns/cloudxns/cloudxns.toml
+++ b/providers/dns/cloudxns/cloudxns.toml
@@ -9,7 +9,7 @@ Since = "v0.5.0"
Example = '''
CLOUDXNS_API_KEY=xxxx \
CLOUDXNS_SECRET_KEY=yyyy \
-lego --dns cloudxns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cloudxns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/com35/com35.go b/providers/dns/com35/com35.go
deleted file mode 100644
index 4a9de3a18..000000000
--- a/providers/dns/com35/com35.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// Package com35 implements a DNS provider for solving the DNS-01 challenge using 35.com/三五互联.
-package com35
-
-import (
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/westcn"
-)
-
-// Environment variables names.
-const (
- envNamespace = "COM35_"
-
- EnvUsername = envNamespace + "USERNAME"
- EnvPassword = envNamespace + "PASSWORD"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-const defaultBaseURL = "https://api.35.cn/api/v2"
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config = westcn.Config
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, 60),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 10*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- prv challenge.ProviderTimeout
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for 35.com/三五互联.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvUsername, EnvPassword)
- if err != nil {
- return nil, fmt.Errorf("35com: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Username = values[EnvUsername]
- config.Password = values[EnvPassword]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for 35.com/三五互联.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("35com: the configuration of the DNS provider is nil")
- }
-
- provider, err := westcn.NewDNSProviderConfig(config, defaultBaseURL)
- if err != nil {
- return nil, fmt.Errorf("35com: %w", err)
- }
-
- return &DNSProvider{prv: provider}, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("35com: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("35com: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
-}
diff --git a/providers/dns/com35/com35.toml b/providers/dns/com35/com35.toml
deleted file mode 100644
index 386ee0043..000000000
--- a/providers/dns/com35/com35.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-Name = "35.com/三五互联"
-Description = ''''''
-URL = "https://www.35.cn/"
-Code = "com35"
-Since = "v4.31.0"
-
-Example = '''
-COM35_USERNAME="xxx" \
-COM35_PASSWORD="yyy" \
-lego --dns com35 -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- COM35_USERNAME = "Username"
- COM35_PASSWORD = "API password"
- [Configuration.Additional]
- COM35_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 10)"
- COM35_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
- COM35_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"
- COM35_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://api.35.cn/CustomerCenter/doc/domain_v2.html"
diff --git a/providers/dns/conoha/conoha.go b/providers/dns/conoha/conoha.go
index f7658647c..aa6c68ce9 100644
--- a/providers/dns/conoha/conoha.go
+++ b/providers/dns/conoha/conoha.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/conoha/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -99,8 +98,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
identifier.HTTPClient = config.HTTPClient
}
- identifier.HTTPClient = clientdebug.Wrap(identifier.HTTPClient)
-
auth := internal.Auth{
TenantID: config.TenantID,
PasswordCredentials: internal.PasswordCredentials{
@@ -123,8 +120,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/conoha/conoha.toml b/providers/dns/conoha/conoha.toml
index be90acb0d..8bd83247e 100644
--- a/providers/dns/conoha/conoha.toml
+++ b/providers/dns/conoha/conoha.toml
@@ -8,7 +8,7 @@ Example = '''
CONOHA_TENANT_ID=487727e3921d44e3bfe7ebb337bf085e \
CONOHA_API_USERNAME=xxxx \
CONOHA_API_PASSWORD=yyyy \
-lego --dns conoha -d '*.example.com' -d example.com run
+lego --email you@example.com --dns conoha -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/conoha/conoha_test.go b/providers/dns/conoha/conoha_test.go
index c1c445d48..9db5ba79f 100644
--- a/providers/dns/conoha/conoha_test.go
+++ b/providers/dns/conoha/conoha_test.go
@@ -72,7 +72,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -156,7 +155,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -170,7 +168,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/conoha/internal/client.go b/providers/dns/conoha/internal/client.go
index 2f039489b..60d7fd6dc 100644
--- a/providers/dns/conoha/internal/client.go
+++ b/providers/dns/conoha/internal/client.go
@@ -124,7 +124,6 @@ func (c *Client) createRecord(ctx context.Context, domainID string, record Recor
}
newRecord := &Record{}
-
err = c.do(req, newRecord)
if err != nil {
return nil, err
diff --git a/providers/dns/conoha/internal/client_test.go b/providers/dns/conoha/internal/client_test.go
index 5e06ffc1d..0b9242c08 100644
--- a/providers/dns/conoha/internal/client_test.go
+++ b/providers/dns/conoha/internal/client_test.go
@@ -97,7 +97,6 @@ func TestClient_CreateRecord(t *testing.T) {
http.Error(rw, err.Error(), http.StatusBadRequest)
return
}
-
defer func() { _ = req.Body.Close() }()
if string(bytes.TrimSpace(raw)) != `{"name":"lego.com.","type":"TXT","data":"txtTXTtxt","ttl":300}` {
@@ -110,7 +109,6 @@ func TestClient_CreateRecord(t *testing.T) {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
-
defer func() { _ = file.Close() }()
_, _ = io.Copy(rw, file)
diff --git a/providers/dns/conohav3/conohav3.go b/providers/dns/conohav3/conohav3.go
index c1eace827..a6cb12cb1 100644
--- a/providers/dns/conohav3/conohav3.go
+++ b/providers/dns/conohav3/conohav3.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/conohav3/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -99,8 +98,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
identifier.HTTPClient = config.HTTPClient
}
- identifier.HTTPClient = clientdebug.Wrap(identifier.HTTPClient)
-
auth := internal.Auth{
Identity: internal.Identity{
Methods: []string{"password"},
@@ -132,8 +129,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/conohav3/conohav3.toml b/providers/dns/conohav3/conohav3.toml
index e2c80259d..7608e6742 100644
--- a/providers/dns/conohav3/conohav3.toml
+++ b/providers/dns/conohav3/conohav3.toml
@@ -8,7 +8,7 @@ Example = '''
CONOHAV3_TENANT_ID=487727e3921d44e3bfe7ebb337bf085e \
CONOHAV3_API_USER_ID=xxxx \
CONOHAV3_API_PASSWORD=yyyy \
-lego --dns conohav3 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns conohav3 -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/conohav3/conohav3_test.go b/providers/dns/conohav3/conohav3_test.go
index d68ea3ebb..7bba8f0b5 100644
--- a/providers/dns/conohav3/conohav3_test.go
+++ b/providers/dns/conohav3/conohav3_test.go
@@ -72,7 +72,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -156,7 +155,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -170,7 +168,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/conohav3/internal/client.go b/providers/dns/conohav3/internal/client.go
index 2a9e7c2bc..fcbd7f5ac 100644
--- a/providers/dns/conohav3/internal/client.go
+++ b/providers/dns/conohav3/internal/client.go
@@ -124,7 +124,6 @@ func (c *Client) createRecord(ctx context.Context, domainID string, record Recor
}
newRecord := &Record{}
-
err = c.do(req, newRecord)
if err != nil {
return nil, err
diff --git a/providers/dns/conohav3/internal/client_test.go b/providers/dns/conohav3/internal/client_test.go
index 66babae49..babdadf7e 100644
--- a/providers/dns/conohav3/internal/client_test.go
+++ b/providers/dns/conohav3/internal/client_test.go
@@ -98,7 +98,6 @@ func TestClient_CreateRecord(t *testing.T) {
http.Error(rw, err.Error(), http.StatusBadRequest)
return
}
-
defer func() { _ = req.Body.Close() }()
if string(bytes.TrimSpace(raw)) != `{"name":"lego.com.","type":"TXT","data":"txtTXTtxt","ttl":300}` {
@@ -111,7 +110,6 @@ func TestClient_CreateRecord(t *testing.T) {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
-
defer func() { _ = file.Close() }()
_, _ = io.Copy(rw, file)
diff --git a/providers/dns/conohav3/internal/identity.go b/providers/dns/conohav3/internal/identity.go
index 6a9ad7f1e..3bb7355ae 100644
--- a/providers/dns/conohav3/internal/identity.go
+++ b/providers/dns/conohav3/internal/identity.go
@@ -53,7 +53,6 @@ func (c *Identifier) do(req *http.Request) (string, error) {
if err != nil {
return "", errutils.NewHTTPDoError(req, err)
}
-
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusCreated {
diff --git a/providers/dns/constellix/constellix.go b/providers/dns/constellix/constellix.go
index 777e93308..f981b4974 100644
--- a/providers/dns/constellix/constellix.go
+++ b/providers/dns/constellix/constellix.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/constellix/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/hashicorp/go-retryablehttp"
)
@@ -97,7 +96,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
retryClient.HTTPClient = tr.Wrap(config.HTTPClient)
retryClient.Backoff = backoff
- client := internal.NewClient(clientdebug.Wrap(retryClient.StandardClient()))
+ client := internal.NewClient(retryClient.StandardClient())
return &DNSProvider{config: config, client: client}, nil
}
@@ -200,7 +199,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("constellix: failed to delete TXT records: %w", err)
}
-
return nil
}
diff --git a/providers/dns/constellix/constellix.toml b/providers/dns/constellix/constellix.toml
index 171a0de99..c4ae0a194 100644
--- a/providers/dns/constellix/constellix.toml
+++ b/providers/dns/constellix/constellix.toml
@@ -7,7 +7,7 @@ Since = "v3.4.0"
Example = '''
CONSTELLIX_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
CONSTELLIX_SECRET_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
-lego --dns constellix -d '*.example.com' -d example.com run
+lego --email you@example.com --dns constellix -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/constellix/constellix_test.go b/providers/dns/constellix/constellix_test.go
index e38258292..e3a30caca 100644
--- a/providers/dns/constellix/constellix_test.go
+++ b/providers/dns/constellix/constellix_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -130,7 +129,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -144,7 +142,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/constellix/internal/auth.go b/providers/dns/constellix/internal/auth.go
index 9193572eb..1a136012d 100644
--- a/providers/dns/constellix/internal/auth.go
+++ b/providers/dns/constellix/internal/auth.go
@@ -28,7 +28,6 @@ func NewTokenTransport(apiKey, secretKey string) (*TokenTransport, error) {
if apiKey == "" {
return nil, errors.New("credentials missing: API key")
}
-
if secretKey == "" {
return nil, errors.New("credentials missing: secret key")
}
@@ -58,7 +57,6 @@ func (t *TokenTransport) transport() http.RoundTripper {
if t.Transport != nil {
return t.Transport
}
-
return http.DefaultTransport
}
diff --git a/providers/dns/constellix/internal/domains.go b/providers/dns/constellix/internal/domains.go
index fa7027f55..485f0d537 100644
--- a/providers/dns/constellix/internal/domains.go
+++ b/providers/dns/constellix/internal/domains.go
@@ -30,12 +30,10 @@ func (s *DomainService) GetAll(ctx context.Context, params *PaginationParameters
if errQ != nil {
return nil, errQ
}
-
req.URL.RawQuery = v.Encode()
}
var domains []Domain
-
err = s.client.do(req, &domains)
if err != nil {
return nil, err
@@ -80,7 +78,6 @@ func (s *DomainService) Search(ctx context.Context, filter searchFilter, value s
req.URL.RawQuery = query.Encode()
var domains []Domain
-
err = s.client.do(req, &domains)
if err != nil {
var nf *NotFound
diff --git a/providers/dns/constellix/internal/domains_test.go b/providers/dns/constellix/internal/domains_test.go
index 468db4613..2d92fb8f3 100644
--- a/providers/dns/constellix/internal/domains_test.go
+++ b/providers/dns/constellix/internal/domains_test.go
@@ -30,10 +30,10 @@ func TestDomainService_GetAll(t *testing.T) {
require.NoError(t, err)
expected := []Domain{
- {ID: 273301, Name: "aaa.example", TypeID: 1, Version: 9, Status: "ACTIVE"},
- {ID: 273302, Name: "bbb.example", TypeID: 1, Version: 9, Status: "ACTIVE"},
- {ID: 273303, Name: "ccc.example", TypeID: 1, Version: 9, Status: "ACTIVE"},
- {ID: 273304, Name: "ddd.example", TypeID: 1, Version: 9, Status: "ACTIVE"},
+ {ID: 273301, Name: "aaa.wtf", TypeID: 1, Version: 9, Status: "ACTIVE"},
+ {ID: 273302, Name: "bbb.wtf", TypeID: 1, Version: 9, Status: "ACTIVE"},
+ {ID: 273303, Name: "ccc.wtf", TypeID: 1, Version: 9, Status: "ACTIVE"},
+ {ID: 273304, Name: "ddd.wtf", TypeID: 1, Version: 9, Status: "ACTIVE"},
}
assert.Equal(t, expected, data)
@@ -44,14 +44,14 @@ func TestDomainService_Search(t *testing.T) {
Route("GET /v1/domains/search",
servermock.ResponseFromFixture("domains-Search.json"),
servermock.CheckQueryParameter().Strict().
- With("exact", "example.com")).
+ With("exact", "lego.wtf")).
Build(t)
- data, err := client.Domains.Search(t.Context(), Exact, "example.com")
+ data, err := client.Domains.Search(t.Context(), Exact, "lego.wtf")
require.NoError(t, err)
expected := []Domain{
- {ID: 273302, Name: "example.com", TypeID: 1, Version: 9, Status: "ACTIVE"},
+ {ID: 273302, Name: "lego.wtf", TypeID: 1, Version: 9, Status: "ACTIVE"},
}
assert.Equal(t, expected, data)
diff --git a/providers/dns/constellix/internal/fixtures/domains-GetAll.json b/providers/dns/constellix/internal/fixtures/domains-GetAll.json
index 8ccb4e52c..5ff2ad41d 100644
--- a/providers/dns/constellix/internal/fixtures/domains-GetAll.json
+++ b/providers/dns/constellix/internal/fixtures/domains-GetAll.json
@@ -1,7 +1,7 @@
[
{
"id": 273301,
- "name": "aaa.example",
+ "name": "aaa.wtf",
"soa": {
"primaryNameserver": "ns11.constellix.com.",
"email": "dns.constellix.com.",
@@ -36,7 +36,7 @@
},
{
"id": 273302,
- "name": "bbb.example",
+ "name": "bbb.wtf",
"soa": {
"primaryNameserver": "ns11.constellix.com.",
"email": "dns.constellix.com.",
@@ -71,7 +71,7 @@
},
{
"id": 273303,
- "name": "ccc.example",
+ "name": "ccc.wtf",
"soa": {
"primaryNameserver": "ns11.constellix.com.",
"email": "dns.constellix.com.",
@@ -106,7 +106,7 @@
},
{
"id": 273304,
- "name": "ddd.example",
+ "name": "ddd.wtf",
"soa": {
"primaryNameserver": "ns11.constellix.com.",
"email": "dns.constellix.com.",
diff --git a/providers/dns/constellix/internal/fixtures/domains-Search.json b/providers/dns/constellix/internal/fixtures/domains-Search.json
index c33272515..5d018a39a 100644
--- a/providers/dns/constellix/internal/fixtures/domains-Search.json
+++ b/providers/dns/constellix/internal/fixtures/domains-Search.json
@@ -1,7 +1,7 @@
[
{
"id": 273302,
- "name": "example.com",
+ "name": "lego.wtf",
"soa": {
"primaryNameserver": "ns11.constellix.com.",
"email": "dns.constellix.com.",
diff --git a/providers/dns/constellix/internal/txtrecords.go b/providers/dns/constellix/internal/txtrecords.go
index bd00d84b7..7880da4d2 100644
--- a/providers/dns/constellix/internal/txtrecords.go
+++ b/providers/dns/constellix/internal/txtrecords.go
@@ -32,7 +32,6 @@ func (s *TxtRecordService) Create(ctx context.Context, domainID int64, record Re
}
var records []Record
-
err = s.client.do(req, &records)
if err != nil {
return nil, err
@@ -55,7 +54,6 @@ func (s *TxtRecordService) GetAll(ctx context.Context, domainID int64) ([]Record
}
var records []Record
-
err = s.client.do(req, &records)
if err != nil {
return nil, err
@@ -78,7 +76,6 @@ func (s *TxtRecordService) Get(ctx context.Context, domainID, recordID int64) (*
}
var records Record
-
err = s.client.do(req, &records)
if err != nil {
return nil, err
@@ -106,7 +103,6 @@ func (s *TxtRecordService) Update(ctx context.Context, domainID, recordID int64,
}
var msg SuccessMessage
-
err = s.client.do(req, &msg)
if err != nil {
return nil, err
@@ -129,7 +125,6 @@ func (s *TxtRecordService) Delete(ctx context.Context, domainID, recordID int64)
}
var msg *SuccessMessage
-
err = s.client.do(req, &msg)
if err != nil {
return nil, err
diff --git a/providers/dns/corenetworks/corenetworks.go b/providers/dns/corenetworks/corenetworks.go
index cde58a2bf..119b3c16b 100644
--- a/providers/dns/corenetworks/corenetworks.go
+++ b/providers/dns/corenetworks/corenetworks.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/corenetworks/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -91,8 +90,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/corenetworks/corenetworks.toml b/providers/dns/corenetworks/corenetworks.toml
index 09840bb1b..8546d8723 100644
--- a/providers/dns/corenetworks/corenetworks.toml
+++ b/providers/dns/corenetworks/corenetworks.toml
@@ -7,7 +7,7 @@ Since = "v4.20.0"
Example = '''
CORENETWORKS_LOGIN="xxxx" \
CORENETWORKS_PASSWORD="yyyy" \
-lego --dns corenetworks -d '*.example.com' -d example.com run
+lego --email you@example.com --dns corenetworks -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/corenetworks/corenetworks_test.go b/providers/dns/corenetworks/corenetworks_test.go
index 911693468..3cd80f88d 100644
--- a/providers/dns/corenetworks/corenetworks_test.go
+++ b/providers/dns/corenetworks/corenetworks_test.go
@@ -43,7 +43,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -112,7 +111,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -126,7 +124,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/corenetworks/internal/client.go b/providers/dns/corenetworks/internal/client.go
index bdc17f2c1..ea2d7efa2 100644
--- a/providers/dns/corenetworks/internal/client.go
+++ b/providers/dns/corenetworks/internal/client.go
@@ -47,7 +47,6 @@ func (c *Client) ListZone(ctx context.Context) ([]Zone, error) {
}
var zones []Zone
-
err = c.do(req, &zones)
if err != nil {
return nil, err
@@ -67,7 +66,6 @@ func (c *Client) GetZoneDetails(ctx context.Context, zone string) (*ZoneDetails,
}
var details ZoneDetails
-
err = c.do(req, &details)
if err != nil {
return nil, err
@@ -87,7 +85,6 @@ func (c *Client) ListRecords(ctx context.Context, zone string) ([]Record, error)
}
var records []Record
-
err = c.do(req, &records)
if err != nil {
return nil, err
diff --git a/providers/dns/corenetworks/internal/identity.go b/providers/dns/corenetworks/internal/identity.go
index a7e7448c0..8f5a2ee9a 100644
--- a/providers/dns/corenetworks/internal/identity.go
+++ b/providers/dns/corenetworks/internal/identity.go
@@ -22,7 +22,6 @@ func (c *Client) CreateAuthenticationToken(ctx context.Context) (*Token, error)
}
var token Token
-
err = c.do(req, &token)
if err != nil {
return nil, err
diff --git a/providers/dns/cpanel/cpanel.go b/providers/dns/cpanel/cpanel.go
index f335c0a8c..4c80e4db8 100644
--- a/providers/dns/cpanel/cpanel.go
+++ b/providers/dns/cpanel/cpanel.go
@@ -17,7 +17,6 @@ import (
"github.com/go-acme/lego/v4/providers/dns/cpanel/internal/cpanel"
"github.com/go-acme/lego/v4/providers/dns/cpanel/internal/shared"
"github.com/go-acme/lego/v4/providers/dns/cpanel/internal/whm"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -147,16 +146,12 @@ func (d *DNSProvider) Present(domain, _, keyAuth string) error {
valueB64 := base64.StdEncoding.EncodeToString([]byte(info.Value))
- var (
- found bool
- existingRecord shared.ZoneRecord
- )
-
+ var found bool
+ var existingRecord shared.ZoneRecord
for _, record := range zoneInfo {
if slices.Contains(record.DataB64, valueB64) {
existingRecord = record
found = true
-
break
}
}
@@ -225,16 +220,12 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
valueB64 := base64.StdEncoding.EncodeToString([]byte(info.Value))
- var (
- found bool
- existingRecord shared.ZoneRecord
- )
-
+ var found bool
+ var existingRecord shared.ZoneRecord
for _, record := range zoneInfo {
if slices.Contains(record.DataB64, valueB64) {
existingRecord = record
found = true
-
break
}
}
@@ -244,7 +235,6 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
}
var newData []string
-
for _, dataB64 := range existingRecord.DataB64 {
if dataB64 == valueB64 {
continue
@@ -301,7 +291,6 @@ func getZoneSerial(zoneFqdn string, zoneInfo []shared.ZoneRecord) (uint32, error
}
var newSerial uint32
-
_, err = fmt.Sscan(string(data), &newSerial)
if err != nil {
return 0, fmt.Errorf("decode serial DNameB64, invalid serial value %q: %w", string(data), err)
@@ -325,8 +314,6 @@ func createClient(config *Config) (apiClient, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return client, nil
case "whm":
@@ -339,8 +326,6 @@ func createClient(config *Config) (apiClient, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return client, nil
default:
diff --git a/providers/dns/cpanel/cpanel.toml b/providers/dns/cpanel/cpanel.toml
index b64adf0cf..faed2abe2 100644
--- a/providers/dns/cpanel/cpanel.toml
+++ b/providers/dns/cpanel/cpanel.toml
@@ -10,7 +10,7 @@ Example = '''
CPANEL_USERNAME="yyyy" \
CPANEL_TOKEN="xxxx" \
CPANEL_BASE_URL="https://example.com:2083" \
-lego --dns cpanel -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cpanel -d '*.example.com' -d example.com run
## WHM
@@ -18,7 +18,7 @@ CPANEL_MODE=whm \
CPANEL_USERNAME="yyyy" \
CPANEL_TOKEN="xxxx" \
CPANEL_BASE_URL="https://example.com:2087" \
-lego --dns cpanel -d '*.example.com' -d example.com run
+lego --email you@example.com --dns cpanel -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/cpanel/cpanel_test.go b/providers/dns/cpanel/cpanel_test.go
index 5d85b8b5b..614b9e1c7 100644
--- a/providers/dns/cpanel/cpanel_test.go
+++ b/providers/dns/cpanel/cpanel_test.go
@@ -75,7 +75,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -283,7 +282,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -297,7 +295,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/cpanel/internal/cpanel/types.go b/providers/dns/cpanel/internal/cpanel/types.go
index 0a3053647..cb4dbd535 100644
--- a/providers/dns/cpanel/internal/cpanel/types.go
+++ b/providers/dns/cpanel/internal/cpanel/types.go
@@ -6,7 +6,7 @@ import (
)
type APIResponse[T any] struct {
- Metadata Metadata `json:"metadata"`
+ Metadata Metadata `json:"metadata,omitempty"`
Data T `json:"data,omitempty"`
Status int `json:"status,omitempty"`
diff --git a/providers/dns/cpanel/internal/whm/types.go b/providers/dns/cpanel/internal/whm/types.go
index d0604a565..f1884a04d 100644
--- a/providers/dns/cpanel/internal/whm/types.go
+++ b/providers/dns/cpanel/internal/whm/types.go
@@ -7,7 +7,7 @@ import (
)
type APIResponse[T any] struct {
- Metadata Metadata `json:"metadata"`
+ Metadata Metadata `json:"metadata,omitempty"`
Data T `json:"data,omitempty"`
}
diff --git a/providers/dns/czechia/czechia.go b/providers/dns/czechia/czechia.go
deleted file mode 100644
index 3ff397c35..000000000
--- a/providers/dns/czechia/czechia.go
+++ /dev/null
@@ -1,159 +0,0 @@
-// Package czechia implements a DNS provider for solving the DNS-01 challenge using Czechia.
-package czechia
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/czechia/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "CZECHIA_"
-
- EnvToken = envNamespace + "TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Token string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Czechia.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvToken)
- if err != nil {
- return nil, fmt.Errorf("czechia: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Token = values[EnvToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Czechia.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("czechia: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.Token)
- if err != nil {
- return nil, fmt.Errorf("czechia: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("czechia: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("czechia: %w", err)
- }
-
- record := internal.TXTRecord{
- Hostname: subDomain,
- Text: info.Value,
- TTL: d.config.TTL,
- PublishZone: 1,
- }
-
- err = d.client.AddTXTRecord(ctx, dns01.UnFqdn(authZone), record)
- if err != nil {
- return fmt.Errorf("czechia: add TXT record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("czechia: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("czechia: %w", err)
- }
-
- record := internal.TXTRecord{
- Hostname: subDomain,
- Text: info.Value,
- TTL: d.config.TTL,
- PublishZone: 1,
- }
-
- err = d.client.DeleteTXTRecord(ctx, dns01.UnFqdn(authZone), record)
- if err != nil {
- return fmt.Errorf("czechia: delete TXT record: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/czechia/czechia.toml b/providers/dns/czechia/czechia.toml
deleted file mode 100644
index 2a66d2054..000000000
--- a/providers/dns/czechia/czechia.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Czechia"
-Description = ''''''
-URL = "https://www.czechia.com/"
-Code = "czechia"
-Since = "v4.33.0"
-
-Example = '''
-CZECHIA_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns czechia -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- CZECHIA_TOKEN = "Authorization token"
- [Configuration.Additional]
- CZECHIA_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- CZECHIA_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- CZECHIA_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- CZECHIA_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://api.czechia.com/swagger/index.html"
diff --git a/providers/dns/czechia/czechia_test.go b/providers/dns/czechia/czechia_test.go
deleted file mode 100644
index 7d9a2676c..000000000
--- a/providers/dns/czechia/czechia_test.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package czechia
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvToken).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvToken: "secret",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "czechia: some credentials information are missing: CZECHIA_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- token string
- expected string
- }{
- {
- desc: "success",
- token: "secret",
- },
- {
- desc: "missing credentials",
- expected: "czechia: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Token = test.token
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.Token = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With("AuthorizationToken", "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /DNS/example.com/TXT",
- servermock.Noop(),
- servermock.CheckRequestJSONBodyFromInternal("add_txt_record-request.json"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /DNS/example.com/TXT",
- servermock.Noop(),
- servermock.CheckRequestJSONBodyFromInternal("add_txt_record-request.json"),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/czechia/internal/client.go b/providers/dns/czechia/internal/client.go
deleted file mode 100644
index f3e0e462e..000000000
--- a/providers/dns/czechia/internal/client.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://api.czechia.com/api"
-
-const authorizationTokenHeader = "AuthorizationToken"
-
-// Client the Czechia API client.
-type Client struct {
- token string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(token string) (*Client, error) {
- if token == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- token: token,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) AddTXTRecord(ctx context.Context, domain string, record TXTRecord) error {
- endpoint := c.BaseURL.JoinPath("DNS", domain, "TXT")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) DeleteTXTRecord(ctx context.Context, domain string, record TXTRecord) error {
- endpoint := c.BaseURL.JoinPath("DNS", domain, "TXT")
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, record)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Set(authorizationTokenHeader, c.token)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- return req, nil
-}
diff --git a/providers/dns/czechia/internal/client_test.go b/providers/dns/czechia/internal/client_test.go
deleted file mode 100644
index c6f1141c5..000000000
--- a/providers/dns/czechia/internal/client_test.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package internal
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With(authorizationTokenHeader, "secret"),
- )
-}
-
-func TestClient_AddTXTRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /DNS/example.com/TXT",
- servermock.Noop(),
- servermock.CheckRequestJSONBodyFromFixture("add_txt_record-request.json"),
- ).
- Build(t)
-
- record := TXTRecord{
- Hostname: "_acme-challenge",
- Text: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- PublishZone: 1,
- }
-
- err := client.AddTXTRecord(t.Context(), "example.com", record)
- require.NoError(t, err)
-}
-
-func TestClient_DeleteTXTRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /DNS/example.com/TXT",
- servermock.Noop(),
- servermock.CheckRequestJSONBodyFromFixture("add_txt_record-request.json"),
- ).
- Build(t)
-
- record := TXTRecord{
- Hostname: "_acme-challenge",
- Text: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- PublishZone: 1,
- }
-
- err := client.DeleteTXTRecord(t.Context(), "example.com", record)
- require.NoError(t, err)
-}
diff --git a/providers/dns/czechia/internal/fixtures/add_txt_record-request.json b/providers/dns/czechia/internal/fixtures/add_txt_record-request.json
deleted file mode 100644
index ed5830093..000000000
--- a/providers/dns/czechia/internal/fixtures/add_txt_record-request.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "hostName": "_acme-challenge",
- "text": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 120,
- "publishZone": 1
-}
diff --git a/providers/dns/czechia/internal/fixtures/delete_txt_record-request.json b/providers/dns/czechia/internal/fixtures/delete_txt_record-request.json
deleted file mode 100644
index ed5830093..000000000
--- a/providers/dns/czechia/internal/fixtures/delete_txt_record-request.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "hostName": "_acme-challenge",
- "text": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 120,
- "publishZone": 1
-}
diff --git a/providers/dns/czechia/internal/types.go b/providers/dns/czechia/internal/types.go
deleted file mode 100644
index f4a9bfef7..000000000
--- a/providers/dns/czechia/internal/types.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package internal
-
-type TXTRecord struct {
- Hostname string `json:"hostName,omitempty"`
- Text string `json:"text,omitempty"`
- TTL int `json:"ttl,omitempty"`
- PublishZone int `json:"publishZone,omitempty"`
-}
diff --git a/providers/dns/ddnss/ddnss.go b/providers/dns/ddnss/ddnss.go
deleted file mode 100644
index 381151c55..000000000
--- a/providers/dns/ddnss/ddnss.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// Package ddnss implements a DNS provider for solving the DNS-01 challenge using DynDNS Service.
-package ddnss
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/ddnss/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "DDNSS_"
-
- EnvKey = envNamespace + "KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
- EnvSequenceInterval = envNamespace + "SEQUENCE_INTERVAL"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Key string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- SequenceInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- SequenceInterval: env.GetOrDefaultSecond(EnvSequenceInterval, dns01.DefaultPropagationTimeout),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for DynDNS Service.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvKey)
- if err != nil {
- return nil, fmt.Errorf("ddnss: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Key = values[EnvKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for DynDNS Service.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("ddnss: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(&internal.Authentication{Key: config.Key})
- if err != nil {
- return nil, fmt.Errorf("ddnss: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- err := d.client.AddTXTRecord(context.Background(), dns01.UnFqdn(info.EffectiveFQDN), info.Value)
- if err != nil {
- return fmt.Errorf("ddnss: add TXT record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- err := d.client.RemoveTXTRecord(context.Background(), dns01.UnFqdn(info.EffectiveFQDN))
- if err != nil {
- return fmt.Errorf("ddnss: remove TXT record: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Sequential All DNS challenges for this provider will be resolved sequentially.
-// Returns the interval between each iteration.
-func (d *DNSProvider) Sequential() time.Duration {
- return d.config.SequenceInterval
-}
diff --git a/providers/dns/ddnss/ddnss.toml b/providers/dns/ddnss/ddnss.toml
deleted file mode 100644
index 0d0a7132c..000000000
--- a/providers/dns/ddnss/ddnss.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-Name = "DDnss (DynDNS Service)"
-Description = ''''''
-URL = "https://ddnss.de/"
-Code = "ddnss"
-Since = "v4.32.0"
-
-Example = '''
-DDNSS_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns ddnss -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- DDNSS_KEY = "Update key"
- [Configuration.Additional]
- DDNSS_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- DDNSS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- DDNSS_SEQUENCE_INTERVAL = "Time between sequential requests in seconds (Default: 60)"
- DDNSS_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- DDNSS_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://ddnss.de/info.php"
diff --git a/providers/dns/ddnss/ddnss_test.go b/providers/dns/ddnss/ddnss_test.go
deleted file mode 100644
index 5b1d7df58..000000000
--- a/providers/dns/ddnss/ddnss_test.go
+++ /dev/null
@@ -1,168 +0,0 @@
-package ddnss
-
-import (
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvKey: "secret",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "ddnss: some credentials information are missing: DDNSS_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- Key string
- expected string
- }{
- {
- desc: "success",
- Key: "secret",
- },
- {
- desc: "missing credentials",
- expected: "ddnss: missing credentials",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Key = test.Key
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.Key = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL = server.URL
-
- return p, nil
- },
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /",
- servermock.ResponseFromInternal("success.html"),
- servermock.CheckQueryParameter().Strict().
- With("host", "_acme-challenge.example.com").
- With("key", "secret").
- With("txt", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY").
- With("txtm", "1"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /",
- servermock.ResponseFromInternal("success.html"),
- servermock.CheckQueryParameter().Strict().
- With("host", "_acme-challenge.example.com").
- With("key", "secret").
- With("txtm", "2"),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/ddnss/internal/client.go b/providers/dns/ddnss/internal/client.go
deleted file mode 100644
index a0cf4b4a6..000000000
--- a/providers/dns/ddnss/internal/client.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package internal
-
-import (
- "context"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strings"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
- "golang.org/x/net/html"
-)
-
-const defaultBaseURL = "https://ddnss.de/upd.php"
-
-// Client the DDns API client.
-type Client struct {
- auth *Authentication
-
- BaseURL string
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(auth *Authentication) (*Client, error) {
- if auth == nil {
- return nil, errors.New("credentials missing")
- }
-
- err := auth.validate()
- if err != nil {
- return nil, err
- }
-
- return &Client{
- auth: auth,
- BaseURL: defaultBaseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) AddTXTRecord(ctx context.Context, host, value string) error {
- return c.update(ctx, map[string]string{
- "host": host,
- "txt": value,
- "txtm": "1",
- })
-}
-
-func (c *Client) RemoveTXTRecord(ctx context.Context, host string) error {
- return c.update(ctx, map[string]string{
- "host": host,
- "txtm": "2",
- })
-}
-
-func (c *Client) update(ctx context.Context, params map[string]string) error {
- endpoint, err := url.Parse(c.BaseURL)
- if err != nil {
- return err
- }
-
- query := endpoint.Query()
-
- for k, v := range params {
- query.Set(k, v)
- }
-
- c.auth.set(query)
-
- endpoint.RawQuery = query.Encode()
-
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
- if err != nil {
- return fmt.Errorf("unable to create request: %w", err)
- }
-
- useragent.SetHeader(req.Header)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- content, err := readPage(raw)
- if err != nil {
- return err
- }
-
- if strings.Contains(content, "Updated 1 hostname.") {
- return nil
- }
-
- return fmt.Errorf("unexpected response: %s", content)
-}
-
-func readPage(raw []byte) (string, error) {
- page, err := html.Parse(strings.NewReader(string(raw)))
- if err != nil {
- return "", err
- }
-
- var b strings.Builder
- extractText(page, &b)
-
- return strings.TrimSpace(b.String()), nil
-}
-
-func extractText(n *html.Node, b *strings.Builder) {
- if n.Type == html.TextNode {
- text := strings.TrimSpace(n.Data)
- if text != "" {
- b.WriteString(text + " ")
- }
- }
-
- for c := n.FirstChild; c != nil; c = c.NextSibling {
- extractText(c, b)
- }
-}
diff --git a/providers/dns/ddnss/internal/client_test.go b/providers/dns/ddnss/internal/client_test.go
deleted file mode 100644
index 3faddded0..000000000
--- a/providers/dns/ddnss/internal/client_test.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package internal
-
-import (
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(&Authentication{Key: "secret"})
- if err != nil {
- return nil, err
- }
-
- client.BaseURL = server.URL
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- )
-}
-
-func TestClient_AddTXTRecord(t *testing.T) {
- client := mockBuilder().
- Route("GET /",
- servermock.ResponseFromFixture("success.html"),
- servermock.CheckQueryParameter().Strict().
- With("host", "_acme-challenge.example.com").
- With("key", "secret").
- With("txt", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY").
- With("txtm", "1"),
- ).
- Build(t)
-
- err := client.AddTXTRecord(t.Context(), "_acme-challenge.example.com", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY")
- require.NoError(t, err)
-}
-
-func TestClient_RemoveTXTRecord(t *testing.T) {
- client := mockBuilder().
- Route("GET /",
- servermock.ResponseFromFixture("success.html"),
- servermock.CheckQueryParameter().Strict().
- With("host", "_acme-challenge.example.com").
- With("key", "secret").
- With("txtm", "2"),
- ).
- Build(t)
-
- err := client.RemoveTXTRecord(t.Context(), "_acme-challenge.example.com")
- require.NoError(t, err)
-}
diff --git a/providers/dns/ddnss/internal/fixtures/error.html b/providers/dns/ddnss/internal/fixtures/error.html
deleted file mode 100644
index f0599ad9a..000000000
--- a/providers/dns/ddnss/internal/fixtures/error.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- DDNSS - Kostenloser DynDNS Service : Re-ProutDNS v5.01v
-
-
-
-Error Occurred While Processing Request :
-
- - badysys : Der System Parameter ist ungültig.
- - badauth : Die Authorisation ist fehlgeschlagen. Die Parameter username und/oder password sind falsch.
- - notfqdn : Hostname fehlt oder ist falsch.
-
diff --git a/providers/dns/ddnss/internal/fixtures/success.html b/providers/dns/ddnss/internal/fixtures/success.html
deleted file mode 100644
index f51957334..000000000
--- a/providers/dns/ddnss/internal/fixtures/success.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- DDNSS - Kostenloser DynDNS Service : Re-ProutDNS v5.01v
-
-
-
-Updated 1 hostname.
-
diff --git a/providers/dns/ddnss/internal/types.go b/providers/dns/ddnss/internal/types.go
deleted file mode 100644
index 37d41e076..000000000
--- a/providers/dns/ddnss/internal/types.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package internal
-
-import (
- "errors"
- "net/url"
-)
-
-type Authentication struct {
- Username string `url:"user,omitempty"`
- Password string `url:"pwd,omitempty"`
- Key string `url:"key,omitempty"`
-}
-
-func (a *Authentication) validate() error {
- if a.Username == "" && a.Password == "" && a.Key == "" {
- return errors.New("missing credentials")
- }
-
- if a.Username != "" && a.Password != "" && a.Key != "" {
- return errors.New("only one of username, password or key can be set")
- }
-
- if (a.Username != "" && a.Password == "") || a.Username == "" && a.Password != "" {
- return errors.New("username and password must be set together")
- }
-
- return nil
-}
-
-func (a *Authentication) set(query url.Values) {
- if a.Key != "" {
- query.Set("key", a.Key)
-
- return
- }
-
- query.Set("user", a.Username)
- query.Set("pwd", a.Password)
-}
diff --git a/providers/dns/derak/derak.go b/providers/dns/derak/derak.go
index 78165b936..6e726620a 100644
--- a/providers/dns/derak/derak.go
+++ b/providers/dns/derak/derak.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/derak/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/miekg/dns"
)
@@ -95,8 +94,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -163,7 +160,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("derak: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
diff --git a/providers/dns/derak/derak.toml b/providers/dns/derak/derak.toml
index 72f49883a..45d7e1fcf 100644
--- a/providers/dns/derak/derak.toml
+++ b/providers/dns/derak/derak.toml
@@ -6,7 +6,7 @@ Since = "v4.12.0"
Example = '''
DERAK_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns derak -d '*.example.com' -d example.com run
+lego --email you@example.com --dns derak -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/derak/derak_test.go b/providers/dns/derak/derak_test.go
index b83eb2c8c..e58cfb6c1 100644
--- a/providers/dns/derak/derak_test.go
+++ b/providers/dns/derak/derak_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -93,7 +92,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -107,7 +105,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/derak/internal/client.go b/providers/dns/derak/internal/client.go
index 4352e198b..a7c11f895 100644
--- a/providers/dns/derak/internal/client.go
+++ b/providers/dns/derak/internal/client.go
@@ -44,7 +44,6 @@ func (c *Client) GetRecords(ctx context.Context, zoneID string, params *GetRecor
if err != nil {
return nil, err
}
-
endpoint.RawQuery = v.Encode()
req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
@@ -53,7 +52,6 @@ func (c *Client) GetRecords(ctx context.Context, zoneID string, params *GetRecor
}
response := &GetRecordsResponse{}
-
err = c.do(req, response)
if err != nil {
return nil, err
@@ -72,7 +70,6 @@ func (c *Client) GetRecord(ctx context.Context, zoneID, recordID string) (*Recor
}
response := &Record{}
-
err = c.do(req, response)
if err != nil {
return nil, err
@@ -91,7 +88,6 @@ func (c *Client) CreateRecord(ctx context.Context, zoneID string, record Record)
}
response := &Record{}
-
err = c.do(req, response)
if err != nil {
return nil, err
@@ -110,7 +106,6 @@ func (c *Client) EditRecord(ctx context.Context, zoneID, recordID string, record
}
response := &Record{}
-
err = c.do(req, response)
if err != nil {
return nil, err
@@ -152,7 +147,6 @@ func (c *Client) GetZones(ctx context.Context) ([]Zone, error) {
}
response := &APIResponse[[]Zone]{}
-
err = c.do(req, response)
if err != nil {
return nil, err
@@ -227,7 +221,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var response APIResponse[any]
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/derak/internal/types.go b/providers/dns/derak/internal/types.go
index 02116314f..15ed00617 100644
--- a/providers/dns/derak/internal/types.go
+++ b/providers/dns/derak/internal/types.go
@@ -46,7 +46,7 @@ type Zone struct {
HumanReadable string `json:"humanReadable,omitempty"`
Serial string `json:"serial,omitempty"`
CreationTime int64 `json:"creationTime,omitempty"`
- CreationTimeDate time.Time `json:"creationTimeDate,omitzero"`
+ CreationTimeDate time.Time `json:"creationTimeDate,omitempty"`
Status string `json:"status,omitempty"`
IsMoved bool `json:"is_moved,omitempty"`
Paused bool `json:"paused,omitempty"`
diff --git a/providers/dns/desec/desec.go b/providers/dns/desec/desec.go
index 9cc54f65e..9d1e20e53 100644
--- a/providers/dns/desec/desec.go
+++ b/providers/dns/desec/desec.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/nrdcg/desec"
)
@@ -89,9 +88,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config.HTTPClient != nil {
opts.HTTPClient = config.HTTPClient
}
-
- opts.HTTPClient = clientdebug.Wrap(opts.HTTPClient)
-
opts.Logger = log.Default()
client := desec.New(config.Token, opts)
@@ -180,7 +176,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
records := make([]string, 0)
-
for _, record := range rrSet.Records {
if record != fmt.Sprintf(`%q`, info.Value) {
records = append(records, record)
diff --git a/providers/dns/desec/desec.toml b/providers/dns/desec/desec.toml
index f7e66ae07..a79b38cd3 100644
--- a/providers/dns/desec/desec.toml
+++ b/providers/dns/desec/desec.toml
@@ -6,7 +6,7 @@ Since = "v3.7.0"
Example = '''
DESEC_TOKEN=x-xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns desec -d '*.example.com' -d example.com run
+lego --email you@example.com --dns desec -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/desec/desec_test.go b/providers/dns/desec/desec_test.go
index 93d9bd010..f91f9e82a 100644
--- a/providers/dns/desec/desec_test.go
+++ b/providers/dns/desec/desec_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -94,7 +93,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -108,7 +106,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/designate/designate.go b/providers/dns/designate/designate.go
index 41bf251f6..c58baaace 100644
--- a/providers/dns/designate/designate.go
+++ b/providers/dns/designate/designate.go
@@ -68,9 +68,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- config *Config
- client *gophercloud.ServiceClient
-
+ config *Config
+ client *gophercloud.ServiceClient
dnsEntriesMu sync.Mutex
}
@@ -86,6 +85,7 @@ func NewDNSProvider() (*DNSProvider, error) {
opts, erro := clientconfig.AuthOptions(&clientconfig.ClientOpts{
Cloud: val[EnvCloud],
})
+
if erro != nil {
return nil, fmt.Errorf("designate: %w", erro)
}
@@ -202,7 +202,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("designate: error for %s in CleanUp: %w", info.EffectiveFQDN, err)
}
-
return nil
}
@@ -242,7 +241,6 @@ func (d *DNSProvider) updateRecord(record *recordsets.RecordSet, value string) e
}
result := recordsets.Update(d.client, record.ZoneID, record.ID, updateOpts)
-
return result.Err
}
diff --git a/providers/dns/designate/designate.toml b/providers/dns/designate/designate.toml
index a36034f64..3ea6260a6 100644
--- a/providers/dns/designate/designate.toml
+++ b/providers/dns/designate/designate.toml
@@ -7,7 +7,7 @@ Since = "v2.2.0"
Example = '''
# With a `clouds.yaml`
OS_CLOUD=my_openstack \
-lego --dns designate -d '*.example.com' -d example.com run
+lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
# or
@@ -16,7 +16,7 @@ OS_REGION_NAME=RegionOne \
OS_PROJECT_ID=23d4522a987d4ab529f722a007c27846
OS_USERNAME=myuser \
OS_PASSWORD=passw0rd \
-lego --dns designate -d '*.example.com' -d example.com run
+lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
# or
@@ -25,7 +25,7 @@ OS_REGION_NAME=RegionOne \
OS_AUTH_TYPE=v3applicationcredential \
OS_APPLICATION_CREDENTIAL_ID=imn74uq0or7dyzz20dwo1ytls4me8dry \
OS_APPLICATION_CREDENTIAL_SECRET=68FuSPSdQqkFQYH5X1OoriEIJOwyLtQ8QSqXZOc9XxFK1A9tzZT6He2PfPw0OMja \
-lego --dns designate -d '*.example.com' -d example.com run
+lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/designate/designate_test.go b/providers/dns/designate/designate_test.go
index e5edf81f8..1045baa95 100644
--- a/providers/dns/designate/designate_test.go
+++ b/providers/dns/designate/designate_test.go
@@ -105,7 +105,6 @@ func TestNewDNSProvider_fromEnv(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -193,7 +192,6 @@ func TestNewDNSProvider_fromCloud(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(map[string]string{
@@ -333,7 +331,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -347,7 +344,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/digitalocean/digitalocean.go b/providers/dns/digitalocean/digitalocean.go
index 26c6fb9d4..0b68aa5c9 100644
--- a/providers/dns/digitalocean/digitalocean.go
+++ b/providers/dns/digitalocean/digitalocean.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/digitalocean/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -89,15 +88,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("digitalocean: credentials missing")
}
- client := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.AuthToken),
- ),
- )
+ client := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.AuthToken))
if config.BaseURL != "" {
var err error
-
client.BaseURL, err = url.Parse(config.BaseURL)
if err != nil {
return nil, fmt.Errorf("digitalocean: %w", err)
@@ -153,7 +147,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("digitalocean: unknown record ID for '%s'", info.EffectiveFQDN)
}
diff --git a/providers/dns/digitalocean/digitalocean.toml b/providers/dns/digitalocean/digitalocean.toml
index 8f9107c26..b30d986f2 100644
--- a/providers/dns/digitalocean/digitalocean.toml
+++ b/providers/dns/digitalocean/digitalocean.toml
@@ -6,7 +6,7 @@ Since = "v0.3.0"
Example = '''
DO_AUTH_TOKEN=xxxxxx \
-lego --dns digitalocean -d '*.example.com' -d example.com run
+lego --email you@example.com --dns digitalocean -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/digitalocean/digitalocean_test.go b/providers/dns/digitalocean/digitalocean_test.go
index d066e12db..a01906812 100644
--- a/providers/dns/digitalocean/digitalocean_test.go
+++ b/providers/dns/digitalocean/digitalocean_test.go
@@ -51,7 +51,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -139,5 +138,5 @@ func TestDNSProvider_CleanUp(t *testing.T) {
provider.recordIDsMu.Unlock()
err := provider.CleanUp("example.com", "token", "")
- require.NoError(t, err)
+ require.NoError(t, err, "fail to remove TXT record")
}
diff --git a/providers/dns/digitalocean/internal/client.go b/providers/dns/digitalocean/internal/client.go
index 395de478c..e7dd181b2 100644
--- a/providers/dns/digitalocean/internal/client.go
+++ b/providers/dns/digitalocean/internal/client.go
@@ -45,7 +45,6 @@ func (c *Client) AddTxtRecord(ctx context.Context, zone string, record Record) (
}
respData := &TxtRecordResponse{}
-
err = c.do(req, respData)
if err != nil {
return nil, err
@@ -121,7 +120,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var errInfo APIError
-
err := json.Unmarshal(raw, &errInfo)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/directadmin/directadmin.go b/providers/dns/directadmin/directadmin.go
index 8dfa132ae..de9b14945 100644
--- a/providers/dns/directadmin/directadmin.go
+++ b/providers/dns/directadmin/directadmin.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/directadmin/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -100,8 +99,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{client: client, config: config}, nil
}
diff --git a/providers/dns/directadmin/directadmin.toml b/providers/dns/directadmin/directadmin.toml
index 294eaca1c..bd1c9316a 100644
--- a/providers/dns/directadmin/directadmin.toml
+++ b/providers/dns/directadmin/directadmin.toml
@@ -8,7 +8,7 @@ Example = '''
DIRECTADMIN_API_URL="http://example.com:2222" \
DIRECTADMIN_USERNAME=xxxx \
DIRECTADMIN_PASSWORD=yyy \
-lego --dns directadmin -d '*.example.com' -d example.com run
+lego --email you@example.com --dns directadmin -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/directadmin/directadmin_test.go b/providers/dns/directadmin/directadmin_test.go
index aed3ba505..10c079f73 100644
--- a/providers/dns/directadmin/directadmin_test.go
+++ b/providers/dns/directadmin/directadmin_test.go
@@ -59,7 +59,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -136,7 +135,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -150,7 +148,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/directadmin/internal/client.go b/providers/dns/directadmin/internal/client.go
index 64409a79d..bf6d64371 100644
--- a/providers/dns/directadmin/internal/client.go
+++ b/providers/dns/directadmin/internal/client.go
@@ -94,7 +94,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var errInfo APIError
-
err := json.Unmarshal(raw, &errInfo)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/dns_providers_test.go b/providers/dns/dns_providers_test.go
index 3b82784b4..1f39e2bdd 100644
--- a/providers/dns/dns_providers_test.go
+++ b/providers/dns/dns_providers_test.go
@@ -13,7 +13,6 @@ var envTest = tester.NewEnvTest("EXEC_PATH")
func TestKnownDNSProviderSuccess(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.Apply(map[string]string{
"EXEC_PATH": "abc",
})
@@ -27,7 +26,6 @@ func TestKnownDNSProviderSuccess(t *testing.T) {
func TestKnownDNSProviderError(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
provider, err := NewDNSChallengeProviderByName("exec")
diff --git a/providers/dns/dnsexit/dnsexit.go b/providers/dns/dnsexit/dnsexit.go
deleted file mode 100644
index ce9373a50..000000000
--- a/providers/dns/dnsexit/dnsexit.go
+++ /dev/null
@@ -1,163 +0,0 @@
-// Package dnsexit implements a DNS provider for solving the DNS-01 challenge using DNSExit.
-package dnsexit
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/dnsexit/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "DNSEXIT_"
-
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 5*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 10*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for DNSExit.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("dnsexit: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for DNSExit.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("dnsexit: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIKey)
- if err != nil {
- return nil, fmt.Errorf("dnsexit: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("dnsexit: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("dnsexit: %w", err)
- }
-
- record := internal.Record{
- Type: "TXT",
- Name: subDomain,
- Content: info.Value,
- TTL: toMinutes(d.config.TTL),
- }
-
- err = d.client.AddRecord(context.Background(), dns01.UnFqdn(authZone), record)
- if err != nil {
- return fmt.Errorf("dnsexit: add record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("dnsexit: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("dnsexit: %w", err)
- }
-
- record := internal.Record{
- Type: "TXT",
- Name: subDomain,
- Content: info.Value,
- }
-
- err = d.client.DeleteRecord(context.Background(), dns01.UnFqdn(authZone), record)
- if err != nil {
- return fmt.Errorf("dnsexit: add record: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func toMinutes(seconds int) int {
- i := seconds / 60
- if seconds%60 > 0 {
- i++
- }
-
- return i
-}
diff --git a/providers/dns/dnsexit/dnsexit.toml b/providers/dns/dnsexit/dnsexit.toml
deleted file mode 100644
index 0d5321835..000000000
--- a/providers/dns/dnsexit/dnsexit.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "DNSExit"
-Description = ''''''
-URL = "https://dnsexit.com"
-Code = "dnsexit"
-Since = "v4.32.0"
-
-Example = '''
-DNSEXIT_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns dnsexit -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- DNSEXIT_API_KEY = "API key"
- [Configuration.Additional]
- DNSEXIT_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 10)"
- DNSEXIT_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 300)"
- DNSEXIT_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- DNSEXIT_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://dnsexit.com/dns/dns-api/"
diff --git a/providers/dns/dnsexit/dnsexit_test.go b/providers/dns/dnsexit/dnsexit_test.go
deleted file mode 100644
index 31fe61497..000000000
--- a/providers/dns/dnsexit/dnsexit_test.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package dnsexit
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIKey: "key",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "dnsexit: some credentials information are missing: DNSEXIT_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- apiKey: "key",
- },
- {
- desc: "missing credentials",
- expected: "dnsexit: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIKey = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With("apikey", "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /",
- servermock.ResponseFromInternal("success.json"),
- servermock.CheckRequestJSONBodyFromInternal("add_record-request.json"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("POST /",
- servermock.ResponseFromInternal("success.json"),
- servermock.CheckRequestJSONBodyFromInternal("delete_record-request.json"),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/dnsexit/internal/client.go b/providers/dns/dnsexit/internal/client.go
deleted file mode 100644
index 9b0164846..000000000
--- a/providers/dns/dnsexit/internal/client.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://api.dnsexit.com/dns/"
-
-// Client the DNSExit API client.
-type Client struct {
- apiKey string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(apiKey string) (*Client, error) {
- if apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- apiKey: apiKey,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-// AddRecord adds a record.
-// https://dnsexit.com/dns/dns-api/#example-add-spf
-// https://dnsexit.com/dns/dns-api/#example-lse
-func (c *Client) AddRecord(ctx context.Context, domain string, record Record) error {
- payload := APIRequest{
- Domain: domain,
- Add: []Record{record},
- }
-
- req, err := newJSONRequest(ctx, http.MethodPost, c.BaseURL, payload)
- if err != nil {
- return err
- }
-
- err = c.do(req)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// DeleteRecord deletes a record.
-// https://dnsexit.com/dns/dns-api/#delete-a-record
-func (c *Client) DeleteRecord(ctx context.Context, domain string, record Record) error {
- payload := APIRequest{
- Domain: domain,
- Delete: []Record{record},
- }
-
- req, err := newJSONRequest(ctx, http.MethodPost, c.BaseURL, payload)
- if err != nil {
- return err
- }
-
- err = c.do(req)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func (c *Client) do(req *http.Request) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Set("apikey", c.apiKey)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode > http.StatusBadRequest {
- return parseError(req, resp)
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- result := &APIResponse{}
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- if result.Code != 0 {
- return result
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- return req, nil
-}
-
-func parseError(req *http.Request, resp *http.Response) error {
- raw, _ := io.ReadAll(resp.Body)
-
- var errAPI APIResponse
-
- err := json.Unmarshal(raw, &errAPI)
- if err != nil {
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- return &errAPI
-}
diff --git a/providers/dns/dnsexit/internal/client_test.go b/providers/dns/dnsexit/internal/client_test.go
deleted file mode 100644
index 26ea01203..000000000
--- a/providers/dns/dnsexit/internal/client_test.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package internal
-
-import (
- "context"
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.HTTPClient = server.Client()
- client.BaseURL, _ = url.Parse(server.URL)
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With("apikey", "secret"),
- )
-}
-
-func TestClient_AddRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("success.json"),
- servermock.CheckRequestJSONBodyFromFixture("add_record-request.json"),
- ).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "_acme-challenge",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 2,
- }
-
- err := client.AddRecord(context.Background(), "example.com", record)
- require.NoError(t, err)
-}
-
-func TestClient_AddRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusBadRequest),
- ).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "_acme-challenge",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 480,
- Overwrite: true,
- }
-
- err := client.AddRecord(context.Background(), "example.com", record)
- require.Error(t, err)
-
- require.EqualError(t, err, "JSON Defined Record Type not Supported (code=6)")
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("success.json"),
- servermock.CheckRequestJSONBodyFromFixture("delete_record-request.json"),
- ).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "_acme-challenge",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- }
-
- err := client.DeleteRecord(context.Background(), "example.com", record)
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusBadRequest),
- ).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "foo",
- Content: "txtTXTtxt",
- }
-
- err := client.DeleteRecord(context.Background(), "example.com", record)
-
- require.Error(t, err)
-
- require.EqualError(t, err, "JSON Defined Record Type not Supported (code=6)")
-}
diff --git a/providers/dns/dnsexit/internal/fixtures/add_record-request.json b/providers/dns/dnsexit/internal/fixtures/add_record-request.json
deleted file mode 100644
index 6e5e2b520..000000000
--- a/providers/dns/dnsexit/internal/fixtures/add_record-request.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "domain": "example.com",
- "add": [
- {
- "type": "TXT",
- "name": "_acme-challenge",
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 2
- }
- ]
-}
diff --git a/providers/dns/dnsexit/internal/fixtures/delete_record-request.json b/providers/dns/dnsexit/internal/fixtures/delete_record-request.json
deleted file mode 100644
index dcfef9cdf..000000000
--- a/providers/dns/dnsexit/internal/fixtures/delete_record-request.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "domain": "example.com",
- "delete": [
- {
- "type": "TXT",
- "name": "_acme-challenge",
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- }
- ]
-}
diff --git a/providers/dns/dnsexit/internal/fixtures/error.json b/providers/dns/dnsexit/internal/fixtures/error.json
deleted file mode 100644
index 9ba835895..000000000
--- a/providers/dns/dnsexit/internal/fixtures/error.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "code": 6,
- "message": "JSON Defined Record Type not Supported"
-}
diff --git a/providers/dns/dnsexit/internal/fixtures/success.json b/providers/dns/dnsexit/internal/fixtures/success.json
deleted file mode 100644
index 3af47a936..000000000
--- a/providers/dns/dnsexit/internal/fixtures/success.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "code": 0,
- "details": [
- "UPDATE Record A example.com. TTL(hh:mm) 08:00 IP 1.1.1.10"
- ],
- "message": "Success"
-}
diff --git a/providers/dns/dnsexit/internal/types.go b/providers/dns/dnsexit/internal/types.go
deleted file mode 100644
index db254549f..000000000
--- a/providers/dns/dnsexit/internal/types.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strings"
-)
-
-type Record struct {
- Type string `json:"type,omitempty"`
- Name string `json:"name,omitempty"`
- Content string `json:"content,omitempty"`
- TTL int `json:"ttl,omitempty"` // NOTE: ttl value is in minutes.
- Overwrite bool `json:"overwrite,omitempty"`
-}
-
-type APIRequest struct {
- Domain string `json:"domain,omitempty"`
- Add []Record `json:"add,omitempty"`
- Delete []Record `json:"delete,omitempty"`
- Update []Record `json:"update,omitempty"`
-}
-
-// https://dnsexit.com/dns/dns-api/#server-reply
-
-type APIResponse struct {
- Code int `json:"code,omitempty"`
- Details []string `json:"details,omitempty"`
- Message string `json:"message,omitempty"`
-}
-
-func (a APIResponse) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "%s (code=%d)", a.Message, a.Code)
-
- for _, detail := range a.Details {
- _, _ = fmt.Fprintf(msg, ", %s", detail)
- }
-
- return msg.String()
-}
diff --git a/providers/dns/dnshomede/dnshomede.go b/providers/dns/dnshomede/dnshomede.go
index c76ed6de2..91b0b11e3 100644
--- a/providers/dns/dnshomede/dnshomede.go
+++ b/providers/dns/dnshomede/dnshomede.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/dnshomede/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -57,7 +56,6 @@ type DNSProvider struct {
// Credentials must be passed in the environment variable: DNSHOMEDE_CREDENTIALS.
func NewDNSProvider() (*DNSProvider, error) {
config := NewDefaultConfig()
-
values, err := env.Get(EnvCredentials)
if err != nil {
return nil, fmt.Errorf("dnshomede: %w", err)
@@ -94,12 +92,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client := internal.NewClient(config.Credentials)
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/dnshomede/dnshomede.toml b/providers/dns/dnshomede/dnshomede.toml
index 9c3b65277..bc52bb6dd 100644
--- a/providers/dns/dnshomede/dnshomede.toml
+++ b/providers/dns/dnshomede/dnshomede.toml
@@ -6,10 +6,10 @@ Since = "v4.10.0"
Example = '''
DNSHOMEDE_CREDENTIALS=example.org:password \
-lego --dns dnshomede -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dnshomede -d '*.example.com' -d example.com run
DNSHOMEDE_CREDENTIALS=my.example.org:password1,demo.example.org:password2 \
-lego --dns dnshomede -d my.example.org -d demo.example.org
+lego --email you@example.com --dns dnshomede -d my.example.org -d demo.example.org
'''
[Configuration]
diff --git a/providers/dns/dnshomede/dnshomede_test.go b/providers/dns/dnshomede/dnshomede_test.go
index 5035a7837..bdb42f172 100644
--- a/providers/dns/dnshomede/dnshomede_test.go
+++ b/providers/dns/dnshomede/dnshomede_test.go
@@ -69,7 +69,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -145,7 +144,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -159,7 +157,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dnsimple/dnsimple.go b/providers/dns/dnsimple/dnsimple.go
index adf7d48e2..737f214e9 100644
--- a/providers/dns/dnsimple/dnsimple.go
+++ b/providers/dns/dnsimple/dnsimple.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
"golang.org/x/oauth2"
)
@@ -80,14 +79,8 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("dnsimple: OAuth token is missing")
}
- client := dnsimple.NewClient(
- clientdebug.Wrap(
- oauth2.NewClient(
- context.Background(),
- oauth2.StaticTokenSource(&oauth2.Token{AccessToken: config.AccessToken}),
- ),
- ),
- )
+ ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: config.AccessToken})
+ client := dnsimple.NewClient(oauth2.NewClient(context.Background(), ts))
client.SetUserAgent(useragent.Get())
if config.BaseURL != "" {
@@ -101,16 +94,14 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- zoneName, err := d.getHostedZone(ctx, info.EffectiveFQDN)
+ zoneName, err := d.getHostedZone(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("dnsimple: %w", err)
}
- accountID, err := d.getAccountID(ctx)
+ accountID, err := d.getAccountID()
if err != nil {
return fmt.Errorf("dnsimple: %w", err)
}
@@ -120,7 +111,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("dnsimple: %w", err)
}
- _, err = d.client.Zones.CreateRecord(ctx, accountID, zoneName, recordAttributes)
+ _, err = d.client.Zones.CreateRecord(context.Background(), accountID, zoneName, recordAttributes)
if err != nil {
return fmt.Errorf("dnsimple: API call failed: %w", err)
}
@@ -130,24 +121,21 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- records, err := d.findTxtRecords(ctx, info.EffectiveFQDN)
+ records, err := d.findTxtRecords(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("dnsimple: %w", err)
}
- accountID, err := d.getAccountID(ctx)
+ accountID, err := d.getAccountID()
if err != nil {
return fmt.Errorf("dnsimple: %w", err)
}
var lastErr error
-
for _, rec := range records {
- _, err := d.client.Zones.DeleteRecord(ctx, accountID, rec.ZoneID, rec.ID)
+ _, err := d.client.Zones.DeleteRecord(context.Background(), accountID, rec.ZoneID, rec.ID)
if err != nil {
lastErr = fmt.Errorf("dnsimple: %w", err)
}
@@ -162,18 +150,18 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
-func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (string, error) {
+func (d *DNSProvider) getHostedZone(domain string) (string, error) {
authZone, err := dns01.FindZoneByFqdn(domain)
if err != nil {
return "", fmt.Errorf("could not find zone for FQDN %q: %w", domain, err)
}
- accountID, err := d.getAccountID(ctx)
+ accountID, err := d.getAccountID()
if err != nil {
return "", err
}
- hostedZone, err := d.client.Zones.GetZone(ctx, accountID, dns01.UnFqdn(authZone))
+ hostedZone, err := d.client.Zones.GetZone(context.Background(), accountID, dns01.UnFqdn(authZone))
if err != nil {
return "", fmt.Errorf("get zone: %w", err)
}
@@ -185,13 +173,13 @@ func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (string,
return hostedZone.Data.Name, nil
}
-func (d *DNSProvider) findTxtRecords(ctx context.Context, fqdn string) ([]dnsimple.ZoneRecord, error) {
- zoneName, err := d.getHostedZone(ctx, fqdn)
+func (d *DNSProvider) findTxtRecords(fqdn string) ([]dnsimple.ZoneRecord, error) {
+ zoneName, err := d.getHostedZone(fqdn)
if err != nil {
return nil, err
}
- accountID, err := d.getAccountID(ctx)
+ accountID, err := d.getAccountID()
if err != nil {
return nil, err
}
@@ -201,7 +189,7 @@ func (d *DNSProvider) findTxtRecords(ctx context.Context, fqdn string) ([]dnsimp
return nil, err
}
- result, err := d.client.Zones.ListRecords(ctx, accountID, zoneName, &dnsimple.ZoneRecordListOptions{Name: &subDomain, Type: dnsimple.String("TXT"), ListOptions: dnsimple.ListOptions{}})
+ result, err := d.client.Zones.ListRecords(context.Background(), accountID, zoneName, &dnsimple.ZoneRecordListOptions{Name: &subDomain, Type: dnsimple.String("TXT"), ListOptions: dnsimple.ListOptions{}})
if err != nil {
return nil, fmt.Errorf("API call has failed: %w", err)
}
@@ -223,8 +211,8 @@ func newTxtRecord(zoneName, fqdn, value string, ttl int) (dnsimple.ZoneRecordAtt
}, nil
}
-func (d *DNSProvider) getAccountID(ctx context.Context) (string, error) {
- whoamiResponse, err := d.client.Identity.Whoami(ctx)
+func (d *DNSProvider) getAccountID() (string, error) {
+ whoamiResponse, err := d.client.Identity.Whoami(context.Background())
if err != nil {
return "", err
}
diff --git a/providers/dns/dnsimple/dnsimple.toml b/providers/dns/dnsimple/dnsimple.toml
index 158fb7011..dcf999136 100644
--- a/providers/dns/dnsimple/dnsimple.toml
+++ b/providers/dns/dnsimple/dnsimple.toml
@@ -6,7 +6,7 @@ Since = "v0.3.0"
Example = '''
DNSIMPLE_OAUTH_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz \
-lego --dns dnsimple -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dnsimple -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/dnsimple/dnsimple_test.go b/providers/dns/dnsimple/dnsimple_test.go
index 2a52dd2de..c07f965b4 100644
--- a/providers/dns/dnsimple/dnsimple_test.go
+++ b/providers/dns/dnsimple/dnsimple_test.go
@@ -51,7 +51,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
diff --git a/providers/dns/dnsmadeeasy/dnsmadeeasy.go b/providers/dns/dnsmadeeasy/dnsmadeeasy.go
index 69f2096fb..fcfe6714c 100644
--- a/providers/dns/dnsmadeeasy/dnsmadeeasy.go
+++ b/providers/dns/dnsmadeeasy/dnsmadeeasy.go
@@ -15,7 +15,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/dnsmadeeasy/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -113,12 +112,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("dnsmadeeasy: %w", err)
}
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
+ client.HTTPClient = config.HTTPClient
client.BaseURL, err = url.Parse(baseURL)
if err != nil {
return nil, err
@@ -155,7 +149,6 @@ func (d *DNSProvider) Present(domainName, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("dnsmadeeasy: unable to create record for %s: %w", name, err)
}
-
return nil
}
@@ -178,7 +171,6 @@ func (d *DNSProvider) CleanUp(domainName, token, keyAuth string) error {
// find matching records
name := strings.Replace(info.EffectiveFQDN, "."+authZone, "", 1)
-
records, err := d.client.GetRecords(ctx, domain, name, "TXT")
if err != nil {
return fmt.Errorf("dnsmadeeasy: unable to get records for domain %s: %w", domain.Name, err)
@@ -186,7 +178,6 @@ func (d *DNSProvider) CleanUp(domainName, token, keyAuth string) error {
// delete records
var lastError error
-
for _, record := range *records {
err = d.client.DeleteRecord(ctx, record)
if err != nil {
diff --git a/providers/dns/dnsmadeeasy/dnsmadeeasy.toml b/providers/dns/dnsmadeeasy/dnsmadeeasy.toml
index d71ab5303..11a5f85ac 100644
--- a/providers/dns/dnsmadeeasy/dnsmadeeasy.toml
+++ b/providers/dns/dnsmadeeasy/dnsmadeeasy.toml
@@ -7,7 +7,7 @@ Since = "v0.4.0"
Example = '''
DNSMADEEASY_API_KEY=xxxxxx \
DNSMADEEASY_API_SECRET=yyyyy \
-lego --dns dnsmadeeasy -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dnsmadeeasy -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go b/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go
index f6fc2e273..5c508e60d 100644
--- a/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go
+++ b/providers/dns/dnsmadeeasy/dnsmadeeasy_test.go
@@ -59,7 +59,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -136,7 +135,6 @@ func TestLivePresentAndCleanup(t *testing.T) {
os.Setenv(EnvSandbox, "true")
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dnsmadeeasy/internal/client.go b/providers/dns/dnsmadeeasy/internal/client.go
index 7963ad614..cb6f9d2cb 100644
--- a/providers/dns/dnsmadeeasy/internal/client.go
+++ b/providers/dns/dnsmadeeasy/internal/client.go
@@ -68,7 +68,6 @@ func (c *Client) GetDomain(ctx context.Context, authZone string) (*Domain, error
}
domain := &Domain{}
-
err = c.do(req, domain)
if err != nil {
return nil, err
@@ -92,7 +91,6 @@ func (c *Client) GetRecords(ctx context.Context, domain *Domain, recordName, rec
}
records := &recordsResponse{}
-
err = c.do(req, records)
if err != nil {
return nil, err
@@ -174,12 +172,10 @@ func (c *Client) sign(req *http.Request, timestamp string) error {
func computeHMAC(message, secret string) (string, error) {
key := []byte(secret)
h := hmac.New(sha1.New, key)
-
_, err := h.Write([]byte(message))
if err != nil {
return "", err
}
-
return hex.EncodeToString(h.Sum(nil)), nil
}
diff --git a/providers/dns/dnspod/dnspod.go b/providers/dns/dnspod/dnspod.go
index 52a873c7b..ab8f20c8d 100644
--- a/providers/dns/dnspod/dnspod.go
+++ b/providers/dns/dnspod/dnspod.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/nrdcg/dnspod-go"
)
@@ -83,12 +82,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
params := dnspod.CommonParams{LoginToken: config.LoginToken, Format: "json"}
client := dnspod.NewClient(params)
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
+ client.HTTPClient = config.HTTPClient
return &DNSProvider{client: client, config: config}, nil
}
@@ -135,7 +129,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return err
}
}
-
return nil
}
@@ -157,7 +150,6 @@ func (d *DNSProvider) getHostedZone(domain string) (string, string, error) {
}
var hostedZone dnspod.Domain
-
for _, zone := range zones {
if zone.Name == dns01.UnFqdn(authZone) {
hostedZone = zone
@@ -165,7 +157,7 @@ func (d *DNSProvider) getHostedZone(domain string) (string, string, error) {
}
if hostedZone.ID == "" || hostedZone.ID == "0" {
- return "", "", fmt.Errorf("zone %s not found for domain %s", authZone, domain)
+ return "", "", fmt.Errorf("zone %s not found in dnspod for domain %s", authZone, domain)
}
return hostedZone.ID.String(), hostedZone.Name, nil
@@ -193,7 +185,6 @@ func (d *DNSProvider) findTxtRecords(fqdn, zoneID, zoneName string) ([]dnspod.Re
}
var records []dnspod.Record
-
result, _, err := d.client.Records.List(zoneID, subDomain)
if err != nil {
return records, fmt.Errorf("API call has failed: %w", err)
diff --git a/providers/dns/dnspod/dnspod.toml b/providers/dns/dnspod/dnspod.toml
index 162685d76..a0bf50e31 100644
--- a/providers/dns/dnspod/dnspod.toml
+++ b/providers/dns/dnspod/dnspod.toml
@@ -8,7 +8,7 @@ Since = "v0.4.0"
Example = '''
DNSPOD_API_KEY=xxxxxx \
-lego --dns dnspod -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dnspod -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/dnspod/dnspod_test.go b/providers/dns/dnspod/dnspod_test.go
index 5d339353a..640ec34c6 100644
--- a/providers/dns/dnspod/dnspod_test.go
+++ b/providers/dns/dnspod/dnspod_test.go
@@ -37,7 +37,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -97,7 +96,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -111,7 +109,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dode/dode.go b/providers/dns/dode/dode.go
index 59ad785e8..9f307f046 100644
--- a/providers/dns/dode/dode.go
+++ b/providers/dns/dode/dode.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/dode/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -86,8 +85,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/dode/dode.toml b/providers/dns/dode/dode.toml
index eb629bb3e..a96e9ee43 100644
--- a/providers/dns/dode/dode.toml
+++ b/providers/dns/dode/dode.toml
@@ -6,7 +6,7 @@ Since = "v2.4.0"
Example = '''
DODE_TOKEN=xxxxxx \
-lego --dns dode -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dode -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/dode/dode_test.go b/providers/dns/dode/dode_test.go
index fefcc79b1..3d8e9395a 100644
--- a/providers/dns/dode/dode_test.go
+++ b/providers/dns/dode/dode_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -94,7 +93,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -108,7 +106,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dode/internal/client.go b/providers/dns/dode/internal/client.go
index 6824e7c48..bbd98b399 100644
--- a/providers/dns/dode/internal/client.go
+++ b/providers/dns/dode/internal/client.go
@@ -70,7 +70,6 @@ func (c *Client) UpdateTxtRecord(ctx context.Context, fqdn, txt string, clearRec
}
var response apiResponse
-
err = json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/domeneshop/domeneshop.go b/providers/dns/domeneshop/domeneshop.go
index fb16b442e..c194f5608 100644
--- a/providers/dns/domeneshop/domeneshop.go
+++ b/providers/dns/domeneshop/domeneshop.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/domeneshop/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -87,8 +86,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/domeneshop/domeneshop.toml b/providers/dns/domeneshop/domeneshop.toml
index b74af598e..a8d2a1064 100644
--- a/providers/dns/domeneshop/domeneshop.toml
+++ b/providers/dns/domeneshop/domeneshop.toml
@@ -8,7 +8,7 @@ Since = "v4.3.0"
Example = '''
DOMENESHOP_API_TOKEN= \
DOMENESHOP_API_SECRET= \
-lego --dns domeneshop -d '*.example.com' -d example.com run
+lego --email example@example.com --dns domeneshop -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/domeneshop/domeneshop_test.go b/providers/dns/domeneshop/domeneshop_test.go
index 086efd44a..389975bca 100644
--- a/providers/dns/domeneshop/domeneshop_test.go
+++ b/providers/dns/domeneshop/domeneshop_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -131,7 +130,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -145,7 +143,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dreamhost/dreamhost.go b/providers/dns/dreamhost/dreamhost.go
index 8663e18ce..5b4960ee0 100644
--- a/providers/dns/dreamhost/dreamhost.go
+++ b/providers/dns/dreamhost/dreamhost.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/dreamhost/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -87,8 +86,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
if config.BaseURL != "" {
client.BaseURL = config.BaseURL
}
@@ -99,7 +96,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
-
err := d.client.AddRecord(context.Background(), dns01.UnFqdn(info.EffectiveFQDN), info.Value)
if err != nil {
return fmt.Errorf("dreamhost: %w", err)
diff --git a/providers/dns/dreamhost/dreamhost.toml b/providers/dns/dreamhost/dreamhost.toml
index c3a9db360..4345e9ece 100644
--- a/providers/dns/dreamhost/dreamhost.toml
+++ b/providers/dns/dreamhost/dreamhost.toml
@@ -6,7 +6,7 @@ Since = "v1.1.0"
Example = '''
DREAMHOST_API_KEY="YOURAPIKEY" \
-lego --dns dreamhost -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dreamhost -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/dreamhost/dreamhost_test.go b/providers/dns/dreamhost/dreamhost_test.go
index 5af0b892d..f85e00da4 100644
--- a/providers/dns/dreamhost/dreamhost_test.go
+++ b/providers/dns/dreamhost/dreamhost_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -152,7 +151,7 @@ func TestDNSProvider_Cleanup(t *testing.T) {
Build(t)
err := provider.CleanUp("example.com", "", fakeChallengeToken)
- require.NoError(t, err)
+ require.NoError(t, err, "failed to remove TXT record")
}
func TestLivePresentAndCleanUp(t *testing.T) {
@@ -161,7 +160,6 @@ func TestLivePresentAndCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dreamhost/internal/client.go b/providers/dns/dreamhost/internal/client.go
index 02b33ad57..dee808ac8 100644
--- a/providers/dns/dreamhost/internal/client.go
+++ b/providers/dns/dreamhost/internal/client.go
@@ -101,7 +101,6 @@ func (c *Client) updateTxtRecord(ctx context.Context, endpoint *url.URL) error {
}
var response apiResponse
-
err = json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/duckdns/duckdns.go b/providers/dns/duckdns/duckdns.go
index 1aae0a06c..687f5bbac 100644
--- a/providers/dns/duckdns/duckdns.go
+++ b/providers/dns/duckdns/duckdns.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/duckdns/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -87,8 +86,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/duckdns/duckdns.toml b/providers/dns/duckdns/duckdns.toml
index 6866da57c..9c0b3a6be 100644
--- a/providers/dns/duckdns/duckdns.toml
+++ b/providers/dns/duckdns/duckdns.toml
@@ -6,7 +6,7 @@ Since = "v0.5.0"
Example = '''
DUCKDNS_TOKEN=xxxxxx \
-lego --dns duckdns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns duckdns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/duckdns/duckdns_test.go b/providers/dns/duckdns/duckdns_test.go
index 769513fbf..b89966a36 100644
--- a/providers/dns/duckdns/duckdns_test.go
+++ b/providers/dns/duckdns/duckdns_test.go
@@ -37,7 +37,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -95,7 +94,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -109,7 +107,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/duckdns/internal/client.go b/providers/dns/duckdns/internal/client.go
index c5d7ef97c..ced5bf187 100644
--- a/providers/dns/duckdns/internal/client.go
+++ b/providers/dns/duckdns/internal/client.go
@@ -81,7 +81,6 @@ func (c *Client) UpdateTxtRecord(ctx context.Context, domain, txt string, clearR
if body != "OK" {
return fmt.Errorf("request to change TXT record for DuckDNS returned the following result (%s) this does not match expectation (OK) used url [%s]", body, endpoint)
}
-
return nil
}
@@ -99,7 +98,6 @@ func getMainDomain(domain string) string {
}
firstSubDomainIndex := split[len(split)-3]
-
return domain[firstSubDomainIndex:]
}
diff --git a/providers/dns/dyn/dyn.go b/providers/dns/dyn/dyn.go
index 0cd445c39..627626df6 100644
--- a/providers/dns/dyn/dyn.go
+++ b/providers/dns/dyn/dyn.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/dyn/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -93,8 +92,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/dyn/dyn.toml b/providers/dns/dyn/dyn.toml
index c4b3563e0..4b0d3e652 100644
--- a/providers/dns/dyn/dyn.toml
+++ b/providers/dns/dyn/dyn.toml
@@ -8,7 +8,7 @@ Example = '''
DYN_CUSTOMER_NAME=xxxxxx \
DYN_USER_NAME=yyyyy \
DYN_PASSWORD=zzzz \
-lego --dns dyn -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dyn -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/dyn/dyn_test.go b/providers/dns/dyn/dyn_test.go
index 5b4d1c6b6..25f1f5614 100644
--- a/providers/dns/dyn/dyn_test.go
+++ b/providers/dns/dyn/dyn_test.go
@@ -71,7 +71,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -156,7 +155,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -170,7 +168,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dyn/internal/client.go b/providers/dns/dyn/internal/client.go
index a54113eec..83a1bfc0f 100644
--- a/providers/dns/dyn/internal/client.go
+++ b/providers/dns/dyn/internal/client.go
@@ -127,7 +127,6 @@ func (c *Client) do(req *http.Request) (*APIResponse, error) {
}
var response APIResponse
-
err = json.Unmarshal(raw, &response)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/dyn/internal/session.go b/providers/dns/dyn/internal/session.go
index 088510152..647080fa8 100644
--- a/providers/dns/dyn/internal/session.go
+++ b/providers/dns/dyn/internal/session.go
@@ -33,7 +33,6 @@ func (c *Client) login(ctx context.Context) (session, error) {
}
var s session
-
err = json.Unmarshal(dynRes.Data, &s)
if err != nil {
return session{}, errutils.NewUnmarshalError(req, http.StatusOK, dynRes.Data, err)
diff --git a/providers/dns/dyndnsfree/dyndnsfree.go b/providers/dns/dyndnsfree/dyndnsfree.go
index 09be2bfbd..8c1d87aaa 100644
--- a/providers/dns/dyndnsfree/dyndnsfree.go
+++ b/providers/dns/dyndnsfree/dyndnsfree.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/dyndnsfree/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -82,8 +81,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -110,6 +107,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
// Records are deleted automatically.
+
return nil
}
diff --git a/providers/dns/dyndnsfree/dyndnsfree.toml b/providers/dns/dyndnsfree/dyndnsfree.toml
index e64bb0080..dd354fb33 100644
--- a/providers/dns/dyndnsfree/dyndnsfree.toml
+++ b/providers/dns/dyndnsfree/dyndnsfree.toml
@@ -7,7 +7,7 @@ Since = "v4.23.0"
Example = '''
DYNDNSFREE_USERNAME="xxx" \
DYNDNSFREE_PASSWORD="yyy" \
-lego --dns dyndnsfree -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dyndnsfree -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/dyndnsfree/dyndnsfree_test.go b/providers/dns/dyndnsfree/dyndnsfree_test.go
index 0b03bd27f..cb063a029 100644
--- a/providers/dns/dyndnsfree/dyndnsfree_test.go
+++ b/providers/dns/dyndnsfree/dyndnsfree_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -123,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dynu/dynu.go b/providers/dns/dynu/dynu.go
index 11df45281..af602ddfc 100644
--- a/providers/dns/dynu/dynu.go
+++ b/providers/dns/dynu/dynu.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/dynu/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -87,8 +86,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}
client := internal.NewClient()
-
- client.HTTPClient = clientdebug.Wrap(tr.Wrap(config.HTTPClient))
+ client.HTTPClient = tr.Wrap(config.HTTPClient)
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/dynu/dynu.toml b/providers/dns/dynu/dynu.toml
index ae2367087..ba59034dd 100644
--- a/providers/dns/dynu/dynu.toml
+++ b/providers/dns/dynu/dynu.toml
@@ -6,7 +6,7 @@ Since = "v3.5.0"
Example = '''
DYNU_API_KEY=1234567890abcdefghijklmnopqrstuvwxyz \
-lego --dns dynu -d '*.example.com' -d example.com run
+lego --email you@example.com --dns dynu -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/dynu/dynu_test.go b/providers/dns/dynu/dynu_test.go
index ffc7c3a00..fe2c22dfb 100644
--- a/providers/dns/dynu/dynu_test.go
+++ b/providers/dns/dynu/dynu_test.go
@@ -38,7 +38,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -97,7 +96,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -111,7 +109,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/dynu/internal/auth.go b/providers/dns/dynu/internal/auth.go
index 0a91445d2..7a21a10e8 100644
--- a/providers/dns/dynu/internal/auth.go
+++ b/providers/dns/dynu/internal/auth.go
@@ -46,7 +46,6 @@ func (t *TokenTransport) transport() http.RoundTripper {
if t.Transport != nil {
return t.Transport
}
-
return http.DefaultTransport
}
diff --git a/providers/dns/dynu/internal/client.go b/providers/dns/dynu/internal/client.go
index 59e90d592..a51556a0b 100644
--- a/providers/dns/dynu/internal/client.go
+++ b/providers/dns/dynu/internal/client.go
@@ -12,9 +12,8 @@ import (
"strconv"
"time"
- "github.com/cenkalti/backoff/v5"
+ "github.com/cenkalti/backoff/v4"
"github.com/go-acme/lego/v4/log"
- "github.com/go-acme/lego/v4/platform/wait"
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
)
@@ -43,7 +42,6 @@ func (c *Client) GetRecords(ctx context.Context, hostname, recordType string) ([
endpoint.RawQuery = query.Encode()
apiResp := RecordsResponse{}
-
err := c.doRetry(ctx, http.MethodGet, endpoint.String(), nil, &apiResp)
if err != nil {
return nil, err
@@ -66,7 +64,6 @@ func (c *Client) AddNewRecord(ctx context.Context, domainID int64, record DNSRec
}
apiResp := RecordResponse{}
-
err = c.doRetry(ctx, http.MethodPost, endpoint.String(), reqBody, &apiResp)
if err != nil {
return err
@@ -84,7 +81,6 @@ func (c *Client) DeleteRecord(ctx context.Context, domainID, recordID int64) err
endpoint := c.baseURL.JoinPath("dns", strconv.FormatInt(domainID, 10), "record", strconv.FormatInt(recordID, 10))
apiResp := APIException{}
-
err := c.doRetry(ctx, http.MethodDelete, endpoint.String(), nil, &apiResp)
if err != nil {
return err
@@ -102,7 +98,6 @@ func (c *Client) GetRootDomain(ctx context.Context, hostname string) (*DNSHostna
endpoint := c.baseURL.JoinPath("dns", "getroot", hostname)
apiResp := DNSHostname{}
-
err := c.doRetry(ctx, http.MethodGet, endpoint.String(), nil, &apiResp)
if err != nil {
return nil, err
@@ -128,7 +123,12 @@ func (c *Client) doRetry(ctx context.Context, method, uri string, body []byte, r
bo := backoff.NewExponentialBackOff()
bo.InitialInterval = 1 * time.Second
- return wait.Retry(ctx, operation, backoff.WithBackOff(bo), backoff.WithNotify(notify))
+ err := backoff.RetryNotify(operation, bo, notify)
+ if err != nil {
+ return err
+ }
+
+ return nil
}
func (c *Client) do(ctx context.Context, method, uri string, body []byte, result any) error {
diff --git a/providers/dns/easydns/easydns.go b/providers/dns/easydns/easydns.go
index 205063e7b..7e5e219cb 100644
--- a/providers/dns/easydns/easydns.go
+++ b/providers/dns/easydns/easydns.go
@@ -16,7 +16,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/easydns/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -78,7 +77,6 @@ func NewDNSProvider() (*DNSProvider, error) {
if err != nil {
return nil, fmt.Errorf("easydns: %w", err)
}
-
config.Endpoint = endpoint
values, err := env.Get(EnvToken, EnvKey)
@@ -112,8 +110,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
if config.Endpoint != nil {
client.BaseURL = config.Endpoint
}
@@ -190,14 +186,15 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
err = d.client.DeleteRecord(ctx, dns01.UnFqdn(authZone), recordID)
+
+ d.recordIDsMu.Lock()
+ defer delete(d.recordIDs, key)
+ d.recordIDsMu.Unlock()
+
if err != nil {
return fmt.Errorf("easydns: %w", err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, key)
- d.recordIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/easydns/easydns.toml b/providers/dns/easydns/easydns.toml
index 307c86a09..71521bbd6 100644
--- a/providers/dns/easydns/easydns.toml
+++ b/providers/dns/easydns/easydns.toml
@@ -7,7 +7,7 @@ Since = "v2.6.0"
Example = '''
EASYDNS_TOKEN=xxx \
EASYDNS_KEY=yyy \
-lego --dns easydns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns easydns -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/easydns/easydns_test.go b/providers/dns/easydns/easydns_test.go
index 5517928d7..9a11ef6cc 100644
--- a/providers/dns/easydns/easydns_test.go
+++ b/providers/dns/easydns/easydns_test.go
@@ -76,7 +76,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -315,7 +314,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -329,7 +327,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/easydns/internal/client.go b/providers/dns/easydns/internal/client.go
index 33d7c724e..c044d7e7f 100644
--- a/providers/dns/easydns/internal/client.go
+++ b/providers/dns/easydns/internal/client.go
@@ -46,7 +46,6 @@ func (c *Client) ListZones(ctx context.Context, domain string) ([]ZoneRecord, er
}
response := &apiResponse[[]ZoneRecord]{}
-
err = c.do(req, response)
if err != nil {
return nil, err
@@ -68,7 +67,6 @@ func (c *Client) AddRecord(ctx context.Context, domain string, record ZoneRecord
}
response := &apiResponse[*ZoneRecord]{}
-
err = c.do(req, response)
if err != nil {
return "", err
diff --git a/providers/dns/edgecenter/edgecenter.go b/providers/dns/edgecenter/edgecenter.go
deleted file mode 100644
index cfc75b521..000000000
--- a/providers/dns/edgecenter/edgecenter.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Package edgecenter implements a DNS provider for solving the DNS-01 challenge using EdgeCenter.
-package edgecenter
-
-import (
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/gcore"
-)
-
-// Environment variables names.
-const (
- envNamespace = "EDGECENTER_"
-
- EnvPermanentAPIToken = envNamespace + "PERMANENT_API_TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-const defaultBaseURL = "https://api.edgecenter.ru/dns"
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config for DNSProvider.
-type Config = gcore.Config
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, gcore.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, gcore.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 10*time.Second),
- },
- }
-}
-
-// DNSProvider an implementation of challenge.Provider contract.
-type DNSProvider struct {
- prv challenge.ProviderTimeout
-}
-
-// NewDNSProvider returns an instance of DNSProvider configured for G-Core DNS API.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvPermanentAPIToken)
- if err != nil {
- return nil, fmt.Errorf("edgecenter: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIToken = values[EnvPermanentAPIToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for G-Core DNS API.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("edgecenter: the configuration of the DNS provider is nil")
- }
-
- provider, err := gcore.NewDNSProviderConfig(config, defaultBaseURL)
- if err != nil {
- return nil, fmt.Errorf("edgecenter: %w", err)
- }
-
- return &DNSProvider{prv: provider}, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("edgecenter: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("edgecenter: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
-}
diff --git a/providers/dns/edgecenter/edgecenter.toml b/providers/dns/edgecenter/edgecenter.toml
deleted file mode 100644
index 1c9e9b2a9..000000000
--- a/providers/dns/edgecenter/edgecenter.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "EdgeCenter"
-Description = ''''''
-URL = "https://edgecenter.ru/dns"
-Code = "edgecenter"
-Since = "v4.29.0"
-
-Example = '''
-EDGECENTER_PERMANENT_API_TOKEN=xxxxx \
-lego --dns edgecenter -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- EDGECENTER_PERMANENT_API_TOKEN = "Permanent API token (https://edgecenter.ru/blog/permanent-api-token-explained/)"
- [Configuration.Additional]
- EDGECENTER_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 20)"
- EDGECENTER_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 360)"
- EDGECENTER_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- EDGECENTER_HTTP_TIMEOUT = "API request timeout in seconds (Default: 10)"
-
-[Links]
- API = "https://apidocs.edgecenter.ru/dns"
diff --git a/providers/dns/edgecenter/edgecenter_test.go b/providers/dns/edgecenter/edgecenter_test.go
deleted file mode 100644
index e3ec43981..000000000
--- a/providers/dns/edgecenter/edgecenter_test.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package edgecenter
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-var envTest = tester.NewEnvTest(EnvPermanentAPIToken).WithDomain(envNamespace + "DOMAIN")
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvPermanentAPIToken: "A",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{
- EnvPermanentAPIToken: "",
- },
- expected: "edgecenter: some credentials information are missing: EDGECENTER_PERMANENT_API_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.prv)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiToken string
- expected string
- }{
- {
- desc: "success",
- apiToken: "A",
- },
- {
- desc: "missing credentials",
- expected: "edgecenter: incomplete credentials provided",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIToken = test.apiToken
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.prv)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/edgedns/edgedns.go b/providers/dns/edgedns/edgedns.go
index b5f4b99c9..10898006a 100644
--- a/providers/dns/edgedns/edgedns.go
+++ b/providers/dns/edgedns/edgedns.go
@@ -2,17 +2,14 @@
package edgedns
import (
- "context"
"errors"
"fmt"
- "net/http"
"slices"
"strings"
"time"
- edgegriddns "github.com/akamai/AkamaiOPEN-edgegrid-golang/v11/pkg/dns"
- "github.com/akamai/AkamaiOPEN-edgegrid-golang/v11/pkg/edgegrid"
- "github.com/akamai/AkamaiOPEN-edgegrid-golang/v11/pkg/session"
+ configdns "github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v2"
+ "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
@@ -23,8 +20,14 @@ import (
const (
envNamespace = "AKAMAI_"
- EnvEdgeRc = envNamespace + "EDGERC"
- EnvEdgeRcSection = envNamespace + "EDGERC_SECTION"
+ EnvEdgeRc = envNamespace + "EDGERC"
+ EnvEdgeRcSection = envNamespace + "EDGERC_SECTION"
+
+ EnvHost = envNamespace + "HOST"
+ EnvClientToken = envNamespace + "CLIENT_TOKEN"
+ EnvClientSecret = envNamespace + "CLIENT_SECRET"
+ EnvAccessToken = envNamespace + "ACCESS_TOKEN"
+
EnvAccountSwitchKey = envNamespace + "ACCOUNT_SWITCH_KEY"
EnvTTL = envNamespace + "TTL"
@@ -32,15 +35,6 @@ const (
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
)
-// Test Environment variables names (unused).
-// TODO(ldez): must be moved into test files.
-const (
- EnvHost = envNamespace + "HOST"
- EnvClientToken = envNamespace + "CLIENT_TOKEN"
- EnvClientSecret = envNamespace + "CLIENT_SECRET"
- EnvAccessToken = envNamespace + "ACCESS_TOKEN"
-)
-
const (
defaultPropagationTimeout = 3 * time.Minute
defaultPollInterval = 15 * time.Second
@@ -52,8 +46,7 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- *edgegrid.Config
-
+ edgegrid.Config
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
@@ -65,7 +58,7 @@ func NewDefaultConfig() *Config {
TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, defaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, defaultPollInterval),
- Config: &edgegrid.Config{MaxBody: maxBody},
+ Config: edgegrid.Config{MaxBody: maxBody},
}
}
@@ -80,27 +73,27 @@ type DNSProvider struct {
// 1. Section-specific environment variables `AKAMAI_{SECTION}_HOST`, `AKAMAI_{SECTION}_ACCESS_TOKEN`, `AKAMAI_{SECTION}_CLIENT_TOKEN`, `AKAMAI_{SECTION}_CLIENT_SECRET` where `{SECTION}` is specified using `AKAMAI_EDGERC_SECTION`
// 2. If `AKAMAI_EDGERC_SECTION` is not defined or is set to `default`: Environment variables `AKAMAI_HOST`, `AKAMAI_ACCESS_TOKEN`, `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`
// 3. .edgerc file located at `AKAMAI_EDGERC` (defaults to `~/.edgerc`, sections can be specified using `AKAMAI_EDGERC_SECTION`)
+// 4. Default environment variables: `AKAMAI_HOST`, `AKAMAI_ACCESS_TOKEN`, `AKAMAI_CLIENT_TOKEN`, `AKAMAI_CLIENT_SECRET`
//
// See also: https://developer.akamai.com/api/getting-started
func NewDNSProvider() (*DNSProvider, error) {
- conf, err := edgegrid.New(
- edgegrid.WithEnv(true),
- edgegrid.WithFile(env.GetOrDefaultString(EnvEdgeRc, "~/.edgerc")),
- edgegrid.WithSection(env.GetOrDefaultString(EnvEdgeRcSection, "default")),
- )
+ config := NewDefaultConfig()
+
+ rcPath := env.GetOrDefaultString(EnvEdgeRc, "")
+ rcSection := env.GetOrDefaultString(EnvEdgeRcSection, "")
+ accountSwitchKey := env.GetOrDefaultString(EnvAccountSwitchKey, "")
+
+ conf, err := edgegrid.Init(rcPath, rcSection)
if err != nil {
return nil, fmt.Errorf("edgedns: %w", err)
}
conf.MaxBody = maxBody
- accountSwitchKey := env.GetOrDefaultString(EnvAccountSwitchKey, "")
-
if accountSwitchKey != "" {
conf.AccountKey = accountSwitchKey
}
- config := NewDefaultConfig()
config.Config = conf
return NewDNSProviderConfig(config)
@@ -112,10 +105,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("edgedns: the configuration of the DNS provider is nil")
}
- err := config.Validate()
- if err != nil {
- return nil, fmt.Errorf("edgedns: %w", err)
- }
+ configdns.Init(config.Config)
return &DNSProvider{config: config}, nil
}
@@ -128,27 +118,14 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- sess, err := session.New(session.WithSigner(d.config))
- if err != nil {
- return fmt.Errorf("edgedns: %w", err)
- }
-
- client := edgegriddns.Client(sess)
-
zone, err := getZone(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("edgedns: %w", err)
}
- record, err := client.GetRecord(ctx, edgegriddns.GetRecordRequest{
- Zone: zone,
- Name: info.EffectiveFQDN,
- RecordType: "TXT",
- })
+ record, err := configdns.GetRecord(zone, info.EffectiveFQDN, "TXT")
if err != nil && !isNotFound(err) {
return fmt.Errorf("edgedns: %w", err)
}
@@ -168,16 +145,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
record.Target = append(record.Target, `"`+info.Value+`"`)
record.TTL = d.config.TTL
- err = client.UpdateRecord(ctx, edgegriddns.UpdateRecordRequest{
- Record: &edgegriddns.RecordBody{
- Name: record.Name,
- RecordType: record.RecordType,
- TTL: record.TTL,
- Active: record.Active,
- Target: record.Target,
- },
- Zone: zone,
- })
+ err = record.Update(zone)
if err != nil {
return fmt.Errorf("edgedns: %w", err)
}
@@ -185,16 +153,14 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return nil
}
- err = client.CreateRecord(ctx, edgegriddns.CreateRecordRequest{
- Record: &edgegriddns.RecordBody{
- Name: info.EffectiveFQDN,
- RecordType: "TXT",
- TTL: d.config.TTL,
- Target: []string{`"` + info.Value + `"`},
- },
- Zone: zone,
- RecLock: nil,
- })
+ record = &configdns.RecordBody{
+ Name: info.EffectiveFQDN,
+ RecordType: "TXT",
+ TTL: d.config.TTL,
+ Target: []string{`"` + info.Value + `"`},
+ }
+
+ err = record.Save(zone)
if err != nil {
return fmt.Errorf("edgedns: %w", err)
}
@@ -204,32 +170,18 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- sess, err := session.New(session.WithSigner(d.config))
- if err != nil {
- return fmt.Errorf("edgedns: %w", err)
- }
-
- client := edgegriddns.Client(sess)
-
zone, err := getZone(info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("edgedns: %w", err)
}
- existingRec, err := client.GetRecord(ctx, edgegriddns.GetRecordRequest{
- Zone: zone,
- Name: info.EffectiveFQDN,
- RecordType: "TXT",
- })
+ existingRec, err := configdns.GetRecord(zone, info.EffectiveFQDN, "TXT")
if err != nil {
if isNotFound(err) {
return nil
}
-
return fmt.Errorf("edgedns: %w", err)
}
@@ -245,21 +197,19 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return nil
}
- newRData := filterRData(existingRec, info)
+ var newRData []string
+ for _, val := range existingRec.Target {
+ val = strings.Trim(val, `"`)
+ if val == info.Value {
+ continue
+ }
+ newRData = append(newRData, val)
+ }
if len(newRData) > 0 {
existingRec.Target = newRData
- err = client.UpdateRecord(ctx, edgegriddns.UpdateRecordRequest{
- Record: &edgegriddns.RecordBody{
- Name: existingRec.Name,
- RecordType: existingRec.RecordType,
- TTL: existingRec.TTL,
- Active: existingRec.Active,
- Target: existingRec.Target,
- },
- Zone: zone,
- })
+ err = existingRec.Update(zone)
if err != nil {
return fmt.Errorf("edgedns: %w", err)
}
@@ -267,12 +217,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return nil
}
- err = client.DeleteRecord(ctx, edgegriddns.DeleteRecordRequest{
- Zone: zone,
- Name: existingRec.Name,
- RecordType: "TXT",
- RecLock: nil,
- })
+ err = existingRec.Delete(zone)
if err != nil {
return fmt.Errorf("edgedns: %w", err)
}
@@ -300,22 +245,6 @@ func isNotFound(err error) bool {
return false
}
- var e *edgegriddns.Error
-
- return errors.As(err, &e) && e.StatusCode == http.StatusNotFound
-}
-
-func filterRData(existingRec *edgegriddns.GetRecordResponse, info dns01.ChallengeInfo) []string {
- var newRData []string
-
- for _, val := range existingRec.Target {
- val = strings.Trim(val, `"`)
- if val == info.Value {
- continue
- }
-
- newRData = append(newRData, val)
- }
-
- return newRData
+ var e configdns.ConfigDNSError
+ return errors.As(err, &e) && e.NotFound()
}
diff --git a/providers/dns/edgedns/edgedns.toml b/providers/dns/edgedns/edgedns.toml
index 7c7c5b3aa..d40d5cc03 100644
--- a/providers/dns/edgedns/edgedns.toml
+++ b/providers/dns/edgedns/edgedns.toml
@@ -12,7 +12,7 @@ AKAMAI_CLIENT_SECRET=abcdefghijklmnopqrstuvwxyz1234567890ABCDEFG= \
AKAMAI_CLIENT_TOKEN=akab-mnbvcxzlkjhgfdsapoiuytrewq1234567 \
AKAMAI_HOST=akab-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.luna.akamaiapis.net \
AKAMAI_ACCESS_TOKEN=akab-1234567890qwerty-asdfghjklzxcvtnu \
-lego --dns edgedns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns edgedns -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/edgedns/edgedns_integration_test.go b/providers/dns/edgedns/edgedns_integration_test.go
index d20b8e5aa..e1b3bb7cf 100644
--- a/providers/dns/edgedns/edgedns_integration_test.go
+++ b/providers/dns/edgedns/edgedns_integration_test.go
@@ -1,13 +1,11 @@
package edgedns
import (
- "context"
"fmt"
"testing"
"time"
- edgegriddns "github.com/akamai/AkamaiOPEN-edgegrid-golang/v11/pkg/dns"
- "github.com/akamai/AkamaiOPEN-edgegrid-golang/v11/pkg/session"
+ configdns "github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v2"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -19,7 +17,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -37,7 +34,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -73,21 +69,10 @@ func TestLiveTTL(t *testing.T) {
zone, err := getZone(fqdn)
require.NoError(t, err)
- ctx := context.Background()
-
- sess, err := session.New(session.WithSigner(provider.config))
+ resourceRecordSets, err := configdns.GetRecordList(zone, fqdn, "TXT")
require.NoError(t, err)
- client := edgegriddns.Client(sess)
-
- resourceRecordSets, err := client.GetRecordList(ctx, edgegriddns.GetRecordListRequest{
- Zone: zone,
- RecordType: "TXT",
- })
-
- require.NoError(t, err)
-
- for i, rrset := range resourceRecordSets.RecordSets {
+ for i, rrset := range resourceRecordSets.Recordsets {
if rrset.Name != fqdn {
continue
}
diff --git a/providers/dns/edgedns/edgedns_test.go b/providers/dns/edgedns/edgedns_test.go
index a64efd6e2..3ac55a4a4 100644
--- a/providers/dns/edgedns/edgedns_test.go
+++ b/providers/dns/edgedns/edgedns_test.go
@@ -1,10 +1,12 @@
package edgedns
import (
+ "os"
"testing"
"time"
- "github.com/akamai/AkamaiOPEN-edgegrid-golang/v11/pkg/edgegrid"
+ configdns "github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v2"
+ "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/tester"
"github.com/stretchr/testify/require"
@@ -19,9 +21,6 @@ const (
)
var envTest = tester.NewEnvTest(
- EnvTTL,
- EnvPollingInterval,
- EnvPropagationTimeout,
EnvHost,
EnvClientToken,
EnvClientSecret,
@@ -36,7 +35,7 @@ var envTest = tester.NewEnvTest(
WithDomain(envDomain).
WithLiveTestRequirements(EnvHost, EnvClientToken, EnvClientSecret, EnvAccessToken, envDomain)
-func TestNewDNSProvider(t *testing.T) {
+func TestNewDNSProvider_FromEnv(t *testing.T) {
testCases := []struct {
desc string
envVars map[string]string
@@ -51,13 +50,13 @@ func TestNewDNSProvider(t *testing.T) {
EnvClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
EnvAccessToken: "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
},
- expectedConfig: newEdgeConfig(func(config *edgegrid.Config) {
- config.Host = "akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net"
- config.ClientToken = "akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx"
- config.ClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- config.AccessToken = "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx"
- config.MaxBody = maxBody
- }, edgegrid.WithEnv(true), edgegrid.WithFile("/dev/null")),
+ expectedConfig: &edgegrid.Config{
+ Host: "akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
+ ClientToken: "akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
+ ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ AccessToken: "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
+ MaxBody: maxBody,
+ },
},
{
desc: "with account switch key",
@@ -68,14 +67,14 @@ func TestNewDNSProvider(t *testing.T) {
EnvAccessToken: "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
EnvAccountSwitchKey: "F-AC-1234",
},
- expectedConfig: newEdgeConfig(func(config *edgegrid.Config) {
- config.Host = "akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net"
- config.ClientToken = "akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx"
- config.ClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- config.AccessToken = "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx"
- config.MaxBody = maxBody
- config.AccountKey = "F-AC-1234"
- }, edgegrid.WithEnv(true), edgegrid.WithFile("/dev/null")),
+ expectedConfig: &edgegrid.Config{
+ Host: "akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
+ ClientToken: "akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
+ ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ AccessToken: "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
+ MaxBody: maxBody,
+ AccountKey: "F-AC-1234",
+ },
},
{
desc: "with section",
@@ -86,17 +85,17 @@ func TestNewDNSProvider(t *testing.T) {
envTestClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
envTestAccessToken: "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
},
- expectedConfig: newEdgeConfig(func(config *edgegrid.Config) {
- config.Host = "akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net"
- config.ClientToken = "akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx"
- config.ClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- config.AccessToken = "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx"
- config.MaxBody = maxBody
- }, edgegrid.WithEnv(true), edgegrid.WithFile("/dev/null"), edgegrid.WithSection("test")),
+ expectedConfig: &edgegrid.Config{
+ Host: "akaa-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
+ ClientToken: "akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
+ ClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ AccessToken: "akac-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx",
+ MaxBody: maxBody,
+ },
},
{
desc: "missing credentials",
- expectedErr: `edgedns: unable to load config from environment or .edgerc file`,
+ expectedErr: "edgedns: Unable to create instance using environment or .edgerc file",
},
{
desc: "missing host",
@@ -106,7 +105,7 @@ func TestNewDNSProvider(t *testing.T) {
EnvClientSecret: "C",
EnvAccessToken: "D",
},
- expectedErr: `edgedns: unable to load config from environment or .edgerc file`,
+ expectedErr: "edgedns: Unable to create instance using environment or .edgerc file",
},
{
desc: "missing client token",
@@ -116,7 +115,7 @@ func TestNewDNSProvider(t *testing.T) {
EnvClientSecret: "C",
EnvAccessToken: "D",
},
- expectedErr: `edgedns: unable to load config from environment or .edgerc file`,
+ expectedErr: "edgedns: Fatal missing required environment variables: [AKAMAI_CLIENT_TOKEN]",
},
{
desc: "missing client secret",
@@ -126,7 +125,7 @@ func TestNewDNSProvider(t *testing.T) {
EnvClientSecret: "",
EnvAccessToken: "D",
},
- expectedErr: `edgedns: unable to load config from environment or .edgerc file`,
+ expectedErr: "edgedns: Fatal missing required environment variables: [AKAMAI_CLIENT_SECRET]",
},
{
desc: "missing access token",
@@ -136,20 +135,18 @@ func TestNewDNSProvider(t *testing.T) {
EnvClientSecret: "C",
EnvAccessToken: "",
},
- expectedErr: `edgedns: unable to load config from environment or .edgerc file`,
+ expectedErr: "edgedns: Fatal missing required environment variables: [AKAMAI_ACCESS_TOKEN]",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
if test.envVars == nil {
test.envVars = map[string]string{}
}
-
test.envVars[EnvEdgeRc] = "/dev/null"
envTest.Apply(test.envVars)
@@ -157,7 +154,7 @@ func TestNewDNSProvider(t *testing.T) {
p, err := NewDNSProvider()
if test.expectedErr != "" {
- require.ErrorContains(t, err, test.expectedErr)
+ require.EqualError(t, err, test.expectedErr)
return
}
@@ -166,63 +163,13 @@ func TestNewDNSProvider(t *testing.T) {
require.NotNil(t, p.config)
if test.expectedConfig != nil {
- require.Equal(t, test.expectedConfig, p.config.Config)
+ require.Equal(t, *test.expectedConfig, configdns.Config)
}
})
}
}
-func TestNewDefaultConfig(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected *Config
- }{
- {
- desc: "default configuration",
- expected: &Config{
- TTL: dns01.DefaultTTL,
- PropagationTimeout: 3 * time.Minute,
- PollingInterval: 15 * time.Second,
- Config: &edgegrid.Config{
- MaxBody: maxBody,
- },
- },
- },
- {
- desc: "custom values",
- envVars: map[string]string{
- EnvTTL: "99",
- EnvPropagationTimeout: "60",
- EnvPollingInterval: "60",
- },
- expected: &Config{
- TTL: 99,
- PropagationTimeout: 60 * time.Second,
- PollingInterval: 60 * time.Second,
- Config: &edgegrid.Config{
- MaxBody: maxBody,
- },
- },
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- config := NewDefaultConfig()
-
- require.Equal(t, test.expected, config)
- })
- }
-}
-
-func Test_findZone(t *testing.T) {
+func TestDNSProvider_findZone(t *testing.T) {
testCases := []struct {
desc string
domain string
@@ -251,7 +198,53 @@ func Test_findZone(t *testing.T) {
}
}
-func newEdgeConfig(opts ...edgegrid.Option) *edgegrid.Config {
- config, _ := edgegrid.New(opts...)
- return config
+func TestNewDefaultConfig(t *testing.T) {
+ defer envTest.RestoreEnv()
+
+ testCases := []struct {
+ desc string
+ envVars map[string]string
+ expected *Config
+ }{
+ {
+ desc: "default configuration",
+ expected: &Config{
+ TTL: dns01.DefaultTTL,
+ PropagationTimeout: 3 * time.Minute,
+ PollingInterval: 15 * time.Second,
+ Config: edgegrid.Config{
+ MaxBody: maxBody,
+ },
+ },
+ },
+ {
+ desc: "custom values",
+ envVars: map[string]string{
+ EnvTTL: "99",
+ EnvPropagationTimeout: "60",
+ EnvPollingInterval: "60",
+ },
+ expected: &Config{
+ TTL: 99,
+ PropagationTimeout: 60 * time.Second,
+ PollingInterval: 60 * time.Second,
+ Config: edgegrid.Config{
+ MaxBody: maxBody,
+ },
+ },
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.desc, func(t *testing.T) {
+ envTest.ClearEnv()
+ for key, value := range test.envVars {
+ os.Setenv(key, value)
+ }
+
+ config := NewDefaultConfig()
+
+ require.Equal(t, test.expected, config)
+ })
+ }
}
diff --git a/providers/dns/edgeone/edgeone.go b/providers/dns/edgeone/edgeone.go
deleted file mode 100644
index 6931c6715..000000000
--- a/providers/dns/edgeone/edgeone.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Package edgeone implements a DNS provider for solving the DNS-01 challenge using Tencent EdgeOne.
-package edgeone
-
-import (
- "context"
- "errors"
- "fmt"
- "math"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/ptr"
- teo "github.com/go-acme/tencentedgdeone/v20220901"
- "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
- "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
- "golang.org/x/net/idna"
-)
-
-// Environment variables names.
-const (
- envNamespace = "EDGEONE_"
-
- EnvSecretID = envNamespace + "SECRET_ID"
- EnvSecretKey = envNamespace + "SECRET_KEY"
- EnvRegion = envNamespace + "REGION"
- EnvSessionToken = envNamespace + "SESSION_TOKEN"
- EnvZonesMapping = envNamespace + "ZONES_MAPPING"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- SecretID string
- SecretKey string
- Region string
- SessionToken string
-
- ZonesMapping map[string]string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPTimeout time.Duration
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, 60),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 20*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 30*time.Second),
- HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *teo.Client
-
- recordIDs map[string]*string
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Tencent EdgeOne.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvSecretID, EnvSecretKey)
- if err != nil {
- return nil, fmt.Errorf("edgeone: %w", err)
- }
-
- config := NewDefaultConfig()
- config.SecretID = values[EnvSecretID]
- config.SecretKey = values[EnvSecretKey]
- config.Region = env.GetOrDefaultString(EnvRegion, "")
- config.SessionToken = env.GetOrDefaultString(EnvSessionToken, "")
-
- mapping := env.GetOrDefaultString(EnvZonesMapping, "")
- if mapping != "" {
- config.ZonesMapping, err = env.ParsePairs(mapping)
- if err != nil {
- return nil, fmt.Errorf("edgeone: zones mapping: %w", err)
- }
- }
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Tencent EdgeOne.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("edgeone: the configuration of the DNS provider is nil")
- }
-
- var credential *common.Credential
-
- switch {
- case config.SecretID != "" && config.SecretKey != "" && config.SessionToken != "":
- credential = common.NewTokenCredential(config.SecretID, config.SecretKey, config.SessionToken)
- case config.SecretID != "" && config.SecretKey != "":
- credential = common.NewCredential(config.SecretID, config.SecretKey)
- default:
- return nil, errors.New("edgeone: credentials missing")
- }
-
- cpf := profile.NewClientProfile()
- cpf.HttpProfile.Endpoint = "teo.intl.tencentcloudapi.com"
- cpf.HttpProfile.ReqTimeout = int(math.Round(config.HTTPTimeout.Seconds()))
-
- client, err := teo.NewClient(credential, config.Region, cpf)
- if err != nil {
- return nil, fmt.Errorf("edgeone: %w", err)
- }
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: map[string]*string{},
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx := context.Background()
-
- zoneID, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("edgeone: failed to get hosted zone: %w", err)
- }
-
- punnyCoded, err := idna.ToASCII(dns01.UnFqdn(info.EffectiveFQDN))
- if err != nil {
- return fmt.Errorf("edgeone: fail to convert punycode: %w", err)
- }
-
- request := teo.NewCreateDnsRecordRequest()
- request.Name = ptr.Pointer(punnyCoded)
- request.ZoneId = zoneID
- request.Type = ptr.Pointer("TXT")
- request.Content = ptr.Pointer(info.Value)
- request.TTL = ptr.Pointer(int64(d.config.TTL))
-
- nr, err := teo.CreateDnsRecordWithContext(ctx, d.client, request)
- if err != nil {
- return fmt.Errorf("edgeone: API call failed: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.recordIDs[token] = nr.Response.RecordId
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx := context.Background()
-
- zoneID, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("edgeone: failed to get hosted zone: %w", err)
- }
-
- // get the record's unique ID from when we created it
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("edgeone: unknown record ID for '%s'", info.EffectiveFQDN)
- }
-
- request := teo.NewDeleteDnsRecordsRequest()
- request.ZoneId = zoneID
- request.RecordIds = []*string{recordID}
-
- _, err = teo.DeleteDnsRecordsWithContext(ctx, d.client, request)
- if err != nil {
- return fmt.Errorf("edgeone: delete record failed: %w", err)
- }
-
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/edgeone/edgeone.toml b/providers/dns/edgeone/edgeone.toml
deleted file mode 100644
index 05b8bc516..000000000
--- a/providers/dns/edgeone/edgeone.toml
+++ /dev/null
@@ -1,28 +0,0 @@
-Name = "Tencent EdgeOne"
-Description = ''''''
-URL = "https://edgeone.ai"
-Code = "edgeone"
-Since = "v4.26.0"
-
-Example = '''
-EDGEONE_SECRET_ID=abcdefghijklmnopqrstuvwx \
-EDGEONE_SECRET_KEY=your-secret-key \
-lego --dns edgeone -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- EDGEONE_SECRET_ID = "Access key ID"
- EDGEONE_SECRET_KEY = "Access Key secret"
- [Configuration.Additional]
- EDGEONE_SESSION_TOKEN = "Access Key token"
- EDGEONE_REGION = "Region"
- EDGEONE_ZONES_MAPPING = "Mapping between DNS zones and site IDs. (ex: 'example.org:id1,example.com:id2')"
- EDGEONE_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 30)"
- EDGEONE_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 1200)"
- EDGEONE_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"
- EDGEONE_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://edgeone.ai/document/50454#dns-record-apis"
- GoClient = "https://github.com/tencentcloud/tencentcloud-sdk-go"
diff --git a/providers/dns/edgeone/edgeone_test.go b/providers/dns/edgeone/edgeone_test.go
deleted file mode 100644
index 7bd4f6f6d..000000000
--- a/providers/dns/edgeone/edgeone_test.go
+++ /dev/null
@@ -1,170 +0,0 @@
-package edgeone
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvSecretID,
- EnvSecretKey,
- EnvZonesMapping,
-).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvSecretID: "123",
- EnvSecretKey: "456",
- },
- },
- {
- desc: "success with zones mapping",
- envVars: map[string]string{
- EnvSecretID: "123",
- EnvSecretKey: "456",
- EnvZonesMapping: "example.org:id1,example.com:id2",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{
- EnvSecretID: "",
- EnvSecretKey: "",
- },
- expected: "edgeone: some credentials information are missing: EDGEONE_SECRET_ID,EDGEONE_SECRET_KEY",
- },
- {
- desc: "missing access id",
- envVars: map[string]string{
- EnvSecretID: "",
- EnvSecretKey: "456",
- },
- expected: "edgeone: some credentials information are missing: EDGEONE_SECRET_ID",
- },
- {
- desc: "missing secret key",
- envVars: map[string]string{
- EnvSecretID: "123",
- EnvSecretKey: "",
- },
- expected: "edgeone: some credentials information are missing: EDGEONE_SECRET_KEY",
- },
- {
- desc: "invalid mapping",
- envVars: map[string]string{
- EnvSecretID: "123",
- EnvSecretKey: "456",
- EnvZonesMapping: "example.org:id1,example.com",
- },
- expected: "edgeone: zones mapping: incorrect pair: example.com",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- secretID string
- secretKey string
- expected string
- }{
- {
- desc: "success",
- secretID: "123",
- secretKey: "456",
- },
- {
- desc: "missing credentials",
- expected: "edgeone: credentials missing",
- },
- {
- desc: "missing secret id",
- secretKey: "456",
- expected: "edgeone: credentials missing",
- },
- {
- desc: "missing secret key",
- secretID: "123",
- expected: "edgeone: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.SecretID = test.secretID
- config.SecretKey = test.secretKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/edgeone/wrapper.go b/providers/dns/edgeone/wrapper.go
deleted file mode 100644
index 53fae9427..000000000
--- a/providers/dns/edgeone/wrapper.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package edgeone
-
-import (
- "context"
- "fmt"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/ptr"
- teo "github.com/go-acme/tencentedgdeone/v20220901"
-)
-
-func (d *DNSProvider) getHostedZoneID(ctx context.Context, domain string) (*string, error) {
- authZone, err := dns01.FindZoneByFqdn(domain)
- if err != nil {
- return nil, fmt.Errorf("could not find zone: %w", err)
- }
-
- if d.config.ZonesMapping != nil {
- zoneID, ok := d.config.ZonesMapping[authZone]
- if ok {
- return ptr.Pointer(zoneID), nil
- }
- }
-
- request := teo.NewDescribeZonesRequest()
-
- var zones []*teo.Zone
-
- for {
- response, err := teo.DescribeZonesWithContext(ctx, d.client, request)
- if err != nil {
- return nil, fmt.Errorf("API call failed: %w", err)
- }
-
- zones = append(zones, response.Response.Zones...)
-
- if int64(len(zones)) >= ptr.Deref(response.Response.TotalCount) {
- break
- }
-
- request.Offset = ptr.Pointer(int64(len(zones)))
- }
-
- var hostedZone *teo.Zone
-
- for _, zone := range zones {
- unfqdn := dns01.UnFqdn(authZone)
- if ptr.Deref(zone.ZoneName) == unfqdn {
- hostedZone = zone
- }
- }
-
- if hostedZone == nil {
- return nil, fmt.Errorf("zone %s not found for domain %s", authZone, domain)
- }
-
- return hostedZone.ZoneId, nil
-}
diff --git a/providers/dns/efficientip/efficientip.go b/providers/dns/efficientip/efficientip.go
index 81b4530b7..15fa579ed 100644
--- a/providers/dns/efficientip/efficientip.go
+++ b/providers/dns/efficientip/efficientip.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/efficientip/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -92,15 +91,12 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config.Username == "" {
return nil, errors.New("efficientip: missing username")
}
-
if config.Password == "" {
return nil, errors.New("efficientip: missing password")
}
-
if config.Hostname == "" {
return nil, errors.New("efficientip: missing hostname")
}
-
if config.DNSName == "" {
return nil, errors.New("efficientip: missing dnsname")
}
@@ -117,8 +113,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/efficientip/efficientip.toml b/providers/dns/efficientip/efficientip.toml
index 6e1874319..565c9575b 100644
--- a/providers/dns/efficientip/efficientip.toml
+++ b/providers/dns/efficientip/efficientip.toml
@@ -9,7 +9,7 @@ EFFICIENTIP_USERNAME="user" \
EFFICIENTIP_PASSWORD="secret" \
EFFICIENTIP_HOSTNAME="ipam.example.org" \
EFFICIENTIP_DNS_NAME="dns.smart" \
-lego --dns efficientip -d '*.example.com' -d example.com run
+lego --email you@example.com --dns efficientip -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/efficientip/efficientip_test.go b/providers/dns/efficientip/efficientip_test.go
index c2751a79b..3ee2da777 100644
--- a/providers/dns/efficientip/efficientip_test.go
+++ b/providers/dns/efficientip/efficientip_test.go
@@ -83,7 +83,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -179,7 +178,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -193,7 +191,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/efficientip/internal/client.go b/providers/dns/efficientip/internal/client.go
index 5ccdf3973..cc26c5412 100644
--- a/providers/dns/efficientip/internal/client.go
+++ b/providers/dns/efficientip/internal/client.go
@@ -108,7 +108,6 @@ func (c *Client) DeleteRecord(ctx context.Context, params DeleteInputParameters)
if err != nil {
return nil, fmt.Errorf("query parameters: %w", err)
}
-
endpoint.RawQuery = v.Encode()
req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
@@ -201,7 +200,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var response APIError
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/epik/epik.go b/providers/dns/epik/epik.go
index ef5de3c4b..58390faa9 100644
--- a/providers/dns/epik/epik.go
+++ b/providers/dns/epik/epik.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/epik/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -87,8 +86,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/epik/epik.toml b/providers/dns/epik/epik.toml
index faf453581..7b4688609 100644
--- a/providers/dns/epik/epik.toml
+++ b/providers/dns/epik/epik.toml
@@ -6,7 +6,7 @@ Since = "v4.5.0"
Example = '''
EPIK_SIGNATURE=xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns epik -d '*.example.com' -d example.com run
+lego --email you@example.com --dns epik -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/epik/epik_test.go b/providers/dns/epik/epik_test.go
index b8b3c5c43..c0cd3d43b 100644
--- a/providers/dns/epik/epik_test.go
+++ b/providers/dns/epik/epik_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -93,7 +92,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -107,7 +105,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/epik/internal/client.go b/providers/dns/epik/internal/client.go
index 2c3373953..70fb42fa9 100644
--- a/providers/dns/epik/internal/client.go
+++ b/providers/dns/epik/internal/client.go
@@ -46,7 +46,6 @@ func (c *Client) GetDNSRecords(ctx context.Context, domain string) ([]Record, er
}
var data GetDNSRecordResponse
-
err = c.do(req, &data)
if err != nil {
return nil, err
@@ -68,7 +67,6 @@ func (c *Client) CreateHostRecord(ctx context.Context, domain string, record Rec
}
var data Data
-
err = c.do(req, &data)
if err != nil {
return nil, err
@@ -91,7 +89,6 @@ func (c *Client) RemoveHostRecord(ctx context.Context, domain, recordID string)
}
var data Data
-
err = c.do(req, &data)
if err != nil {
return nil, err
@@ -168,7 +165,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var apiErr APIError
-
err := json.Unmarshal(raw, &apiErr)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/eurodns/eurodns.go b/providers/dns/eurodns/eurodns.go
deleted file mode 100644
index 21ff3c3a9..000000000
--- a/providers/dns/eurodns/eurodns.go
+++ /dev/null
@@ -1,197 +0,0 @@
-// Package eurodns implements a DNS provider for solving the DNS-01 challenge using EuroDNS.
-package eurodns
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/eurodns/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "EURODNS_"
-
- EnvApplicationID = envNamespace + "APP_ID"
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- ApplicationID string
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, internal.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for EuroDNS.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvApplicationID, EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("eurodns: %w", err)
- }
-
- config := NewDefaultConfig()
- config.ApplicationID = values[EnvApplicationID]
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for EuroDNS.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("eurodns: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.ApplicationID, config.APIKey)
- if err != nil {
- return nil, fmt.Errorf("eurodns: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("eurodns: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("eurodns: %w", err)
- }
-
- authZone = dns01.UnFqdn(authZone)
-
- zone, err := d.client.GetZone(ctx, authZone)
- if err != nil {
- return fmt.Errorf("eurodns: get zone: %w", err)
- }
-
- zone.Records = append(zone.Records, internal.Record{
- Type: "TXT",
- Host: subDomain,
- TTL: internal.TTLRounder(d.config.TTL),
- RData: info.Value,
- })
-
- validation, err := d.client.ValidateZone(ctx, authZone, zone)
- if err != nil {
- return fmt.Errorf("eurodns: validate zone: %w", err)
- }
-
- if validation.Report != nil && !validation.Report.IsValid {
- return fmt.Errorf("eurodns: validation report: %w", validation.Report)
- }
-
- err = d.client.SaveZone(ctx, authZone, zone)
- if err != nil {
- return fmt.Errorf("eurodns: save zone: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("eurodns: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("eurodns: %w", err)
- }
-
- authZone = dns01.UnFqdn(authZone)
-
- zone, err := d.client.GetZone(ctx, authZone)
- if err != nil {
- return fmt.Errorf("eurodns: get zone: %w", err)
- }
-
- var recordsToKeep []internal.Record
-
- for _, record := range zone.Records {
- if record.Type == "TXT" && record.Host == subDomain && record.RData == info.Value {
- continue
- }
-
- recordsToKeep = append(recordsToKeep, record)
- }
-
- zone.Records = recordsToKeep
-
- validation, err := d.client.ValidateZone(ctx, authZone, zone)
- if err != nil {
- return fmt.Errorf("eurodns: validate zone: %w", err)
- }
-
- if validation.Report != nil && !validation.Report.IsValid {
- return fmt.Errorf("eurodns: validation report: %w", validation.Report)
- }
-
- err = d.client.SaveZone(ctx, authZone, zone)
- if err != nil {
- return fmt.Errorf("eurodns: save zone: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/eurodns/eurodns.toml b/providers/dns/eurodns/eurodns.toml
deleted file mode 100644
index 302b15d00..000000000
--- a/providers/dns/eurodns/eurodns.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-Name = "EuroDNS"
-Description = ''''''
-URL = "https://www.eurodns.com/"
-Code = "eurodns"
-Since = "v4.33.0"
-
-Example = '''
-EURODNS_APP_ID="xxx" \
-EURODNS_API_KEY="yyy" \
-lego --dns eurodns -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- EURODNS_APP_ID = "Application ID"
- EURODNS_API_KEY = "API key"
- [Configuration.Additional]
- EURODNS_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- EURODNS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- EURODNS_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)"
- EURODNS_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://docapi.eurodns.com/"
diff --git a/providers/dns/eurodns/eurodns_test.go b/providers/dns/eurodns/eurodns_test.go
deleted file mode 100644
index abbb4717e..000000000
--- a/providers/dns/eurodns/eurodns_test.go
+++ /dev/null
@@ -1,215 +0,0 @@
-package eurodns
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/eurodns/internal"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvApplicationID, EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvApplicationID: "abc",
- EnvAPIKey: "secret",
- },
- },
- {
- desc: "missing application ID",
- envVars: map[string]string{
- EnvApplicationID: "",
- EnvAPIKey: "secret",
- },
- expected: "eurodns: some credentials information are missing: EURODNS_APP_ID",
- },
- {
- desc: "missing API secret",
- envVars: map[string]string{
- EnvApplicationID: "",
- EnvAPIKey: "secret",
- },
- expected: "eurodns: some credentials information are missing: EURODNS_APP_ID",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "eurodns: some credentials information are missing: EURODNS_APP_ID,EURODNS_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- appID string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- appID: "abc",
- apiKey: "secret",
- },
- {
- desc: "missing application ID",
- expected: "eurodns: credentials missing",
- apiKey: "secret",
- },
- {
- desc: "missing API secret",
- expected: "eurodns: credentials missing",
- appID: "abc",
- },
- {
- desc: "missing credentials",
- expected: "eurodns: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.ApplicationID = test.appID
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIKey = "secret"
- config.ApplicationID = "abc"
- config.HTTPClient = server.Client()
-
- provider, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- provider.client.BaseURL, _ = url.Parse(server.URL)
-
- return provider, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With(internal.HeaderAppID, "abc").
- With(internal.HeaderAPIKey, "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /example.com",
- servermock.ResponseFromInternal("zone_get.json"),
- ).
- Route("POST /example.com/check",
- servermock.ResponseFromInternal("zone_add_validate_ok.json"),
- servermock.CheckRequestJSONBodyFromInternal("zone_add.json"),
- ).
- Route("PUT /example.com",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- servermock.CheckRequestJSONBodyFromInternal("zone_add.json"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /example.com",
- servermock.ResponseFromInternal("zone_add.json"),
- ).
- Route("POST /example.com/check",
- servermock.ResponseFromInternal("zone_remove.json"),
- servermock.CheckRequestJSONBodyFromInternal("zone_remove.json"),
- ).
- Route("PUT /example.com",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- servermock.CheckRequestJSONBodyFromInternal("zone_remove.json"),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/eurodns/internal/client.go b/providers/dns/eurodns/internal/client.go
deleted file mode 100644
index 1ebf8d143..000000000
--- a/providers/dns/eurodns/internal/client.go
+++ /dev/null
@@ -1,199 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
-)
-
-const defaultBaseURL = "https://rest-api.eurodns.com/dns-zones/"
-
-const (
- HeaderAppID = "X-APP-ID"
- HeaderAPIKey = "X-API-KEY"
-)
-
-// Client the EuroDNS API client.
-type Client struct {
- appID string
- apiKey string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(appID, apiKey string) (*Client, error) {
- if appID == "" || apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- appID: appID,
- apiKey: apiKey,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-// GetZone gets a DNS Zone.
-// https://docapi.eurodns.com/#/dnsprovider/getdnszone
-func (c *Client) GetZone(ctx context.Context, domain string) (*Zone, error) {
- endpoint := c.BaseURL.JoinPath(domain)
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- result := &Zone{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// SaveZone saves a DNS Zone.
-// https://docapi.eurodns.com/#/dnsprovider/savednszone
-func (c *Client) SaveZone(ctx context.Context, domain string, zone *Zone) error {
- endpoint := c.BaseURL.JoinPath(domain)
-
- if len(zone.URLForwards) == 0 {
- zone.URLForwards = make([]URLForward, 0)
- }
-
- if len(zone.MailForwards) == 0 {
- zone.MailForwards = make([]MailForward, 0)
- }
-
- req, err := newJSONRequest(ctx, http.MethodPut, endpoint, zone)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-// ValidateZone validates DNS Zone.
-// https://docapi.eurodns.com/#/dnsprovider/checkdnszone
-func (c *Client) ValidateZone(ctx context.Context, domain string, zone *Zone) (*Zone, error) {
- endpoint := c.BaseURL.JoinPath(domain, "check")
-
- if len(zone.URLForwards) == 0 {
- zone.URLForwards = make([]URLForward, 0)
- }
-
- if len(zone.MailForwards) == 0 {
- zone.MailForwards = make([]MailForward, 0)
- }
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, zone)
- if err != nil {
- return nil, err
- }
-
- result := &Zone{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- req.Header.Set(HeaderAppID, c.appID)
- req.Header.Set(HeaderAPIKey, c.apiKey)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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 fmt.Errorf("%d: %w", resp.StatusCode, &errAPI)
-}
-
-const DefaultTTL = 600
-
-// TTLRounder rounds the given TTL in seconds to the next accepted value.
-// Accepted TTL values are: 600, 900, 1800,3600, 7200, 14400, 21600, 43200, 86400, 172800, 432000, 604800.
-func TTLRounder(ttl int) int {
- for _, validTTL := range []int{DefaultTTL, 900, 1800, 3600, 7200, 14400, 21600, 43200, 86400, 172800, 432000, 604800} {
- if ttl <= validTTL {
- return validTTL
- }
- }
-
- return DefaultTTL
-}
diff --git a/providers/dns/eurodns/internal/client_test.go b/providers/dns/eurodns/internal/client_test.go
deleted file mode 100644
index 68d1fda84..000000000
--- a/providers/dns/eurodns/internal/client_test.go
+++ /dev/null
@@ -1,310 +0,0 @@
-package internal
-
-import (
- "context"
- "net/http"
- "net/http/httptest"
- "net/url"
- "slices"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/internal/ptr"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("abc", "secret")
- if err != nil {
- return nil, err
- }
-
- client.HTTPClient = server.Client()
- client.BaseURL, _ = url.Parse(server.URL)
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With(HeaderAppID, "abc").
- With(HeaderAPIKey, "secret"),
- )
-}
-
-func TestClient_GetZone(t *testing.T) {
- client := mockBuilder().
- Route("GET /example.com",
- servermock.ResponseFromFixture("zone_get.json"),
- ).
- Build(t)
-
- zone, err := client.GetZone(context.Background(), "example.com")
- require.NoError(t, err)
-
- expected := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: slices.Concat([]Record{fakeARecord()}),
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- }
-
- assert.Equal(t, expected, zone)
-}
-
-func TestClient_GetZone_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /example.com",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- _, err := client.GetZone(context.Background(), "example.com")
- require.Error(t, err)
-
- require.EqualError(t, err, "401: INVALID_API_KEY: Invalid API Key")
-}
-
-func TestClient_SaveZone(t *testing.T) {
- client := mockBuilder().
- Route("PUT /example.com",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- servermock.CheckRequestJSONBodyFromFixture("zone_add.json"),
- ).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Host: "_acme-challenge",
- RData: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 600,
- }
-
- zone := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: []Record{fakeARecord(), record},
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- }
-
- err := client.SaveZone(context.Background(), "example.com", zone)
- require.NoError(t, err)
-}
-
-func TestClient_SaveZone_emptyForwards(t *testing.T) {
- client := mockBuilder().
- Route("PUT /example.com",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- servermock.CheckRequestJSONBodyFromFixture("zone_add_empty_forwards.json"),
- ).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Host: "_acme-challenge",
- RData: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 600,
- }
-
- zone := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: slices.Concat([]Record{fakeARecord(), record}),
- }
-
- err := client.SaveZone(context.Background(), "example.com", zone)
- require.NoError(t, err)
-}
-
-func TestClient_SaveZone_error(t *testing.T) {
- client := mockBuilder().
- Route("PUT /example.com",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- zone := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: []Record{fakeARecord()},
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- }
-
- err := client.SaveZone(context.Background(), "example.com", zone)
- require.Error(t, err)
-
- require.EqualError(t, err, "401: INVALID_API_KEY: Invalid API Key")
-}
-
-func TestClient_ValidateZone(t *testing.T) {
- client := mockBuilder().
- Route("POST /example.com/check",
- servermock.ResponseFromFixture("zone_add_validate_ok.json"),
- servermock.CheckRequestJSONBodyFromFixture("zone_add.json"),
- ).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Host: "_acme-challenge",
- RData: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 600,
- }
-
- zone := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: []Record{fakeARecord(), record},
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- }
-
- zone, err := client.ValidateZone(context.Background(), "example.com", zone)
- require.NoError(t, err)
-
- expected := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: []Record{fakeARecord(), record},
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- Report: &Report{IsValid: true},
- }
-
- assert.Equal(t, expected, zone)
-}
-
-func TestClient_ValidateZone_report(t *testing.T) {
- client := mockBuilder().
- Route("POST /example.com/check",
- servermock.ResponseFromFixture("zone_add_validate_ko.json"),
- servermock.CheckRequestJSONBodyFromFixture("zone_add.json"),
- ).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Host: "_acme-challenge",
- RData: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 600,
- }
-
- zone := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: []Record{fakeARecord(), record},
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- }
-
- zone, err := client.ValidateZone(context.Background(), "example.com", zone)
- require.NoError(t, err)
-
- expected := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: []Record{fakeARecord(), record},
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- Report: fakeReport(),
- }
-
- assert.EqualError(t, zone.Report, `record error (ERROR): "120" is not a valid TTL, URL forward error (ERROR): string, mail forward error (ERROR): string, zone error (ERROR): string`)
-
- assert.Equal(t, expected, zone)
-}
-
-func TestClient_ValidateZone_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /example.com/check",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- zone := &Zone{
- Name: "example.com",
- DomainConnect: true,
- Records: []Record{fakeARecord()},
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- }
-
- _, err := client.ValidateZone(context.Background(), "example.com", zone)
- require.Error(t, err)
-
- require.EqualError(t, err, "401: INVALID_API_KEY: Invalid API Key")
-}
-
-func fakeARecord() Record {
- return Record{
- ID: 1000,
- Type: "A",
- Host: "@",
- TTL: 600,
- RData: "string",
- Updated: ptr.Pointer(true),
- Locked: ptr.Pointer(true),
- IsDynDNS: ptr.Pointer(true),
- Proxy: "ON",
- }
-}
-
-func fakeURLForward() URLForward {
- return URLForward{
- ID: 2000,
- ForwardType: "FRAME",
- Host: "string",
- URL: "string",
- Title: "string",
- Keywords: "string",
- Description: "string",
- Updated: ptr.Pointer(true),
- }
-}
-
-func fakeMailForward() MailForward {
- return MailForward{
- ID: 3000,
- Source: "string",
- Destination: "string",
- Updated: ptr.Pointer(true),
- }
-}
-
-func fakeReport() *Report {
- return &Report{
- IsValid: false,
- RecordErrors: []RecordError{{
- Messages: []string{`"120" is not a valid TTL`},
- Severity: "ERROR",
- Record: fakeARecord(),
- }},
- URLForwardErrors: []URLForwardError{{
- Messages: []string{"string"},
- Severity: "ERROR",
- URLForward: fakeURLForward(),
- }},
- MailForwardErrors: []MailForwardError{{
- Messages: []string{"string"},
- MailForward: fakeMailForward(),
- Severity: "ERROR",
- }},
- ZoneErrors: []ZoneError{{
- Message: "string",
- Severity: "ERROR",
- Records: []Record{fakeARecord()},
- URLForwards: []URLForward{fakeURLForward()},
- MailForwards: []MailForward{fakeMailForward()},
- }},
- }
-}
diff --git a/providers/dns/eurodns/internal/fixtures/error.json b/providers/dns/eurodns/internal/fixtures/error.json
deleted file mode 100644
index 82a334598..000000000
--- a/providers/dns/eurodns/internal/fixtures/error.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "errors": [
- {
- "code": "INVALID_API_KEY",
- "title": "Invalid API Key"
- }
- ]
-}
diff --git a/providers/dns/eurodns/internal/fixtures/zone_add.json b/providers/dns/eurodns/internal/fixtures/zone_add.json
deleted file mode 100644
index db8142357..000000000
--- a/providers/dns/eurodns/internal/fixtures/zone_add.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "name": "example.com",
- "domainConnect": true,
- "records": [
- {
- "id": 1000,
- "type": "A",
- "host": "@",
- "ttl": 600,
- "rdata": "string",
- "updated": true,
- "locked": true,
- "isDynDns": true,
- "proxy": "ON"
- },
- {
- "type": "TXT",
- "host": "_acme-challenge",
- "ttl": 600,
- "rdata": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "updated": null,
- "locked": null,
- "isDynDns": null
- }
- ],
- "urlForwards": [
- {
- "id": 2000,
- "forwardType": "FRAME",
- "host": "string",
- "url": "string",
- "title": "string",
- "keywords": "string",
- "description": "string",
- "updated": true
- }
- ],
- "mailForwards": [
- {
- "id": 3000,
- "source": "string",
- "destination": "string",
- "updated": true
- }
- ]
-}
diff --git a/providers/dns/eurodns/internal/fixtures/zone_add_empty_forwards.json b/providers/dns/eurodns/internal/fixtures/zone_add_empty_forwards.json
deleted file mode 100644
index 64f8530c9..000000000
--- a/providers/dns/eurodns/internal/fixtures/zone_add_empty_forwards.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "example.com",
- "domainConnect": true,
- "records": [
- {
- "id": 1000,
- "type": "A",
- "host": "@",
- "ttl": 600,
- "rdata": "string",
- "updated": true,
- "locked": true,
- "isDynDns": true,
- "proxy": "ON"
- },
- {
- "type": "TXT",
- "host": "_acme-challenge",
- "ttl": 600,
- "rdata": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "updated": null,
- "locked": null,
- "isDynDns": null
- }
- ],
- "urlForwards": [],
- "mailForwards": []
-}
diff --git a/providers/dns/eurodns/internal/fixtures/zone_add_validate_ko.json b/providers/dns/eurodns/internal/fixtures/zone_add_validate_ko.json
deleted file mode 100644
index e07d42299..000000000
--- a/providers/dns/eurodns/internal/fixtures/zone_add_validate_ko.json
+++ /dev/null
@@ -1,139 +0,0 @@
-{
- "name": "example.com",
- "domainConnect": true,
- "records": [
- {
- "id": 1000,
- "type": "A",
- "host": "@",
- "ttl": 600,
- "rdata": "string",
- "updated": true,
- "locked": true,
- "isDynDns": true,
- "proxy": "ON"
- },
- {
- "type": "TXT",
- "host": "_acme-challenge",
- "ttl": 600,
- "rdata": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "updated": null,
- "locked": null,
- "isDynDns": null
- }
- ],
- "urlForwards": [
- {
- "id": 2000,
- "forwardType": "FRAME",
- "host": "string",
- "url": "string",
- "title": "string",
- "keywords": "string",
- "description": "string",
- "updated": true
- }
- ],
- "mailForwards": [
- {
- "id": 3000,
- "source": "string",
- "destination": "string",
- "updated": true
- }
- ],
- "report": {
- "isValid": false,
- "recordErrors": [
- {
- "messages": [
- "\"120\" is not a valid TTL"
- ],
- "record": {
- "id": 1000,
- "type": "A",
- "host": "@",
- "ttl": 600,
- "rdata": "string",
- "updated": true,
- "locked": true,
- "isDynDns": true,
- "proxy": "ON"
- },
- "severity": "ERROR"
- }
- ],
- "urlForwardErrors": [
- {
- "messages": [
- "string"
- ],
- "urlForward": {
- "id": 2000,
- "forwardType": "FRAME",
- "host": "string",
- "url": "string",
- "title": "string",
- "keywords": "string",
- "description": "string",
- "updated": true
- },
- "severity": "ERROR"
- }
- ],
- "mailForwardErrors": [
- {
- "messages": [
- "string"
- ],
- "mailForward": {
- "id": 3000,
- "source": "string",
- "destination": "string",
- "updated": true
- },
- "severity": "ERROR"
- }
- ],
- "zoneErrors": [
- {
- "message": "string",
- "records": [
- {
- "id": 1000,
- "type": "A",
- "host": "@",
- "ttl": 600,
- "rdata": "string",
- "updated": true,
- "locked": true,
- "isDynDns": true,
- "proxy": "ON"
- }
- ],
- "urlForwards": [
- {
- "id": 2000,
- "forwardType": "FRAME",
- "host": "string",
- "url": "string",
- "title": "string",
- "keywords": "string",
- "description": "string",
- "updated": true
- }
- ],
- "mailForwards": [
- {
- "id": 3000,
- "source": "string",
- "destination": "string",
- "updated": true
- }
- ],
- "severity": "ERROR"
- }
- ]
- }
-}
diff --git a/providers/dns/eurodns/internal/fixtures/zone_add_validate_ok.json b/providers/dns/eurodns/internal/fixtures/zone_add_validate_ok.json
deleted file mode 100644
index ba0ddfefb..000000000
--- a/providers/dns/eurodns/internal/fixtures/zone_add_validate_ok.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "name": "example.com",
- "domainConnect": true,
- "records": [
- {
- "id": 1000,
- "type": "A",
- "host": "@",
- "ttl": 600,
- "rdata": "string",
- "updated": true,
- "locked": true,
- "isDynDns": true,
- "proxy": "ON"
- },
- {
- "type": "TXT",
- "host": "_acme-challenge",
- "ttl": 600,
- "rdata": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "updated": null,
- "locked": null,
- "isDynDns": null
- }
- ],
- "urlForwards": [
- {
- "id": 2000,
- "forwardType": "FRAME",
- "host": "string",
- "url": "string",
- "title": "string",
- "keywords": "string",
- "description": "string",
- "updated": true
- }
- ],
- "mailForwards": [
- {
- "id": 3000,
- "source": "string",
- "destination": "string",
- "updated": true
- }
- ],
- "report": {
- "isValid": true
- }
-}
diff --git a/providers/dns/eurodns/internal/fixtures/zone_get.json b/providers/dns/eurodns/internal/fixtures/zone_get.json
deleted file mode 100644
index ebbc8593e..000000000
--- a/providers/dns/eurodns/internal/fixtures/zone_get.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "example.com",
- "domainConnect": true,
- "records": [
- {
- "id": 1000,
- "type": "A",
- "host": "@",
- "ttl": 600,
- "rdata": "string",
- "updated": true,
- "locked": true,
- "isDynDns": true,
- "proxy": "ON"
- }
- ],
- "urlForwards": [
- {
- "id": 2000,
- "forwardType": "FRAME",
- "host": "string",
- "url": "string",
- "title": "string",
- "keywords": "string",
- "description": "string",
- "updated": true
- }
- ],
- "mailForwards": [
- {
- "id": 3000,
- "source": "string",
- "destination": "string",
- "updated": true
- }
- ]
-}
diff --git a/providers/dns/eurodns/internal/fixtures/zone_remove.json b/providers/dns/eurodns/internal/fixtures/zone_remove.json
deleted file mode 100644
index ebbc8593e..000000000
--- a/providers/dns/eurodns/internal/fixtures/zone_remove.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "example.com",
- "domainConnect": true,
- "records": [
- {
- "id": 1000,
- "type": "A",
- "host": "@",
- "ttl": 600,
- "rdata": "string",
- "updated": true,
- "locked": true,
- "isDynDns": true,
- "proxy": "ON"
- }
- ],
- "urlForwards": [
- {
- "id": 2000,
- "forwardType": "FRAME",
- "host": "string",
- "url": "string",
- "title": "string",
- "keywords": "string",
- "description": "string",
- "updated": true
- }
- ],
- "mailForwards": [
- {
- "id": 3000,
- "source": "string",
- "destination": "string",
- "updated": true
- }
- ]
-}
diff --git a/providers/dns/eurodns/internal/types.go b/providers/dns/eurodns/internal/types.go
deleted file mode 100644
index 891b02e14..000000000
--- a/providers/dns/eurodns/internal/types.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strings"
-)
-
-type APIError struct {
- Errors []Error `json:"errors"`
-}
-
-func (a *APIError) Error() string {
- var msg []string
-
- for _, e := range a.Errors {
- msg = append(msg, fmt.Sprintf("%s: %s", e.Code, e.Title))
- }
-
- return strings.Join(msg, ", ")
-}
-
-type Error struct {
- Code string `json:"code"`
- Title string `json:"title"`
-}
-
-type Zone struct {
- Name string `json:"name,omitempty"`
- DomainConnect bool `json:"domainConnect,omitempty"`
- Records []Record `json:"records"`
- URLForwards []URLForward `json:"urlForwards"`
- MailForwards []MailForward `json:"mailForwards"`
- Report *Report `json:"report,omitempty"`
-}
-
-type Record struct {
- ID int `json:"id,omitempty"`
- Type string `json:"type,omitempty"`
- Host string `json:"host,omitempty"`
- TTL int `json:"ttl,omitempty"`
- RData string `json:"rdata,omitempty"`
- Updated *bool `json:"updated"`
- Locked *bool `json:"locked"`
- IsDynDNS *bool `json:"isDynDns"`
- Proxy string `json:"proxy,omitempty"`
-}
-
-type URLForward struct {
- ID int `json:"id,omitempty"`
- ForwardType string `json:"forwardType,omitempty"`
- Host string `json:"host,omitempty"`
- URL string `json:"url,omitempty"`
- Title string `json:"title,omitempty"`
- Keywords string `json:"keywords,omitempty"`
- Description string `json:"description,omitempty"`
- Updated *bool `json:"updated,omitempty"`
-}
-
-type MailForward struct {
- ID int `json:"id,omitempty"`
- Source string `json:"source,omitempty"`
- Destination string `json:"destination,omitempty"`
- Updated *bool `json:"updated,omitempty"`
-}
-
-type Report struct {
- IsValid bool `json:"isValid,omitempty"`
- RecordErrors []RecordError `json:"recordErrors,omitempty"`
- URLForwardErrors []URLForwardError `json:"urlForwardErrors,omitempty"`
- MailForwardErrors []MailForwardError `json:"mailForwardErrors,omitempty"`
- ZoneErrors []ZoneError `json:"zoneErrors,omitempty"`
-}
-
-func (r *Report) Error() string {
- var msg []string
-
- for _, e := range r.RecordErrors {
- msg = append(msg, e.Error())
- }
-
- for _, e := range r.URLForwardErrors {
- msg = append(msg, e.Error())
- }
-
- for _, e := range r.MailForwardErrors {
- msg = append(msg, e.Error())
- }
-
- for _, e := range r.ZoneErrors {
- msg = append(msg, e.Error())
- }
-
- return strings.Join(msg, ", ")
-}
-
-type RecordError struct {
- Messages []string `json:"messages,omitempty"`
- Record Record `json:"record"`
- Severity string `json:"severity,omitempty"`
-}
-
-func (e *RecordError) Error() string {
- return fmt.Sprintf("record error (%s): %s", e.Severity, strings.Join(e.Messages, ", "))
-}
-
-type URLForwardError struct {
- Messages []string `json:"messages,omitempty"`
- URLForward URLForward `json:"urlForward"`
- Severity string `json:"severity,omitempty"`
-}
-
-func (e *URLForwardError) Error() string {
- return fmt.Sprintf("URL forward error (%s): %s", e.Severity, strings.Join(e.Messages, ", "))
-}
-
-type MailForwardError struct {
- Messages []string `json:"messages,omitempty"`
- MailForward MailForward `json:"mailForward"`
- Severity string `json:"severity,omitempty"`
-}
-
-func (e *MailForwardError) Error() string {
- return fmt.Sprintf("mail forward error (%s): %s", e.Severity, strings.Join(e.Messages, ", "))
-}
-
-type ZoneError struct {
- Message string `json:"message,omitempty"`
- Records []Record `json:"records,omitempty"`
- URLForwards []URLForward `json:"urlForwards,omitempty"`
- MailForwards []MailForward `json:"mailForwards,omitempty"`
- Severity string `json:"severity,omitempty"`
-}
-
-func (e *ZoneError) Error() string {
- return fmt.Sprintf("zone error (%s): %s", e.Severity, e.Message)
-}
diff --git a/providers/dns/excedo/excedo.go b/providers/dns/excedo/excedo.go
deleted file mode 100644
index ae9128b94..000000000
--- a/providers/dns/excedo/excedo.go
+++ /dev/null
@@ -1,176 +0,0 @@
-// Package excedo implements a DNS provider for solving the DNS-01 challenge using Excedo.
-package excedo
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "strconv"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/excedo/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "EXCEDO_"
-
- EnvAPIURL = envNamespace + "API_URL"
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIURL string
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, 60),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 5*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 10*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- recordsMu sync.Mutex
- records map[string]int64
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Excedo.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIURL, EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("excedo: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIURL = values[EnvAPIURL]
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Excedo.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("excedo: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIURL, config.APIKey)
- if err != nil {
- return nil, fmt.Errorf("excedo: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- records: make(map[string]int64),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("excedo: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("excedo: %w", err)
- }
-
- record := internal.Record{
- DomainName: dns01.UnFqdn(authZone),
- Name: subDomain,
- Type: "TXT",
- Content: info.Value,
- TTL: strconv.Itoa(d.config.TTL),
- }
-
- recordID, err := d.client.AddRecord(ctx, record)
- if err != nil {
- return fmt.Errorf("excedo: add record: %w", err)
- }
-
- d.recordsMu.Lock()
- d.records[token] = recordID
- d.recordsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("excedo: could not find zone for domain %q: %w", domain, err)
- }
-
- d.recordsMu.Lock()
- recordID, ok := d.records[token]
- d.recordsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("excedo: unknown record ID for '%s'", info.EffectiveFQDN)
- }
-
- err = d.client.DeleteRecord(ctx, dns01.UnFqdn(authZone), strconv.FormatInt(recordID, 10))
- if err != nil {
- return fmt.Errorf("excedo: delete record: %w", err)
- }
-
- d.recordsMu.Lock()
- delete(d.records, token)
- d.recordsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/excedo/excedo.toml b/providers/dns/excedo/excedo.toml
deleted file mode 100644
index 9f9874c62..000000000
--- a/providers/dns/excedo/excedo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-Name = "Excedo"
-Description = ''''''
-URL = "https://excedo.se/"
-Code = "excedo"
-Since = "v4.33.0"
-
-Example = '''
-EXCEDO_API_KEY=your-api-key \
-EXCEDO_API_URL=your-base-url \
-lego --dns excedo -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- EXCEDO_API_KEY = "API key"
- EXCEDO_API_URL = "API base URL"
- [Configuration.Additional]
- EXCEDO_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 10)"
- EXCEDO_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 300)"
- EXCEDO_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"
- EXCEDO_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "none"
diff --git a/providers/dns/excedo/excedo_test.go b/providers/dns/excedo/excedo_test.go
deleted file mode 100644
index f2350c035..000000000
--- a/providers/dns/excedo/excedo_test.go
+++ /dev/null
@@ -1,210 +0,0 @@
-package excedo
-
-import (
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIURL, EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIURL: "https://example.com",
- EnvAPIKey: "secret",
- },
- },
- {
- desc: "missing the API key",
- envVars: map[string]string{
- EnvAPIURL: "https://example.com",
- EnvAPIKey: "",
- },
- expected: "excedo: some credentials information are missing: EXCEDO_API_KEY",
- },
- {
- desc: "missing the API URL",
- envVars: map[string]string{
- EnvAPIURL: "",
- EnvAPIKey: "secret",
- },
- expected: "excedo: some credentials information are missing: EXCEDO_API_URL",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "excedo: some credentials information are missing: EXCEDO_API_URL,EXCEDO_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiURL string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- apiURL: "https://example.com",
- apiKey: "secret",
- },
- {
- desc: "missing the API key",
- apiURL: "https://example.com",
- expected: "excedo: credentials missing",
- },
- {
- desc: "missing the API URL",
- apiKey: "secret",
- expected: "excedo: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "excedo: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIURL = test.apiURL
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIURL = server.URL
- config.APIKey = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- return p, nil
- },
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /authenticate/login/",
- servermock.ResponseFromInternal("login.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secret"),
- ).
- Route("POST /dns/addrecord/",
- servermock.ResponseFromInternal("addrecord.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer session-token"),
- servermock.CheckForm().Strict().
- With("content", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY").
- With("domainName", "example.com").
- With("name", "_acme-challenge").
- With("ttl", "60").
- With("type", "TXT"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /authenticate/login/",
- servermock.ResponseFromInternal("login.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secret"),
- ).
- Route("POST /dns/deleterecord/",
- servermock.ResponseFromInternal("deleterecord.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer session-token"),
- ).
- Build(t)
-
- provider.records["abc"] = 19695822
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/excedo/internal/client.go b/providers/dns/excedo/internal/client.go
deleted file mode 100644
index a5d8be88b..000000000
--- a/providers/dns/excedo/internal/client.go
+++ /dev/null
@@ -1,205 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "mime/multipart"
- "net/http"
- "net/url"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
- querystring "github.com/google/go-querystring/query"
-)
-
-type responseChecker interface {
- Check() error
-}
-
-// Client the Excedo API client.
-type Client struct {
- apiKey string
-
- baseURL *url.URL
- HTTPClient *http.Client
-
- token *ExpirableToken
- muToken sync.Mutex
-}
-
-// NewClient creates a new Client.
-func NewClient(apiURL, apiKey string) (*Client, error) {
- if apiURL == "" || apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, err := url.Parse(apiURL)
- if err != nil {
- return nil, err
- }
-
- return &Client{
- apiKey: apiKey,
- baseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) AddRecord(ctx context.Context, record Record) (int64, error) {
- payload, err := querystring.Values(record)
- if err != nil {
- return 0, err
- }
-
- endpoint := c.baseURL.JoinPath("/dns/addrecord/")
-
- req, err := newFormRequest(ctx, http.MethodPost, endpoint, payload)
- if err != nil {
- return 0, err
- }
-
- result := new(AddRecordResponse)
-
- err = c.doAuthenticated(ctx, req, result)
- if err != nil {
- return 0, err
- }
-
- return result.RecordID, nil
-}
-
-func (c *Client) DeleteRecord(ctx context.Context, zone, recordID string) error {
- endpoint := c.baseURL.JoinPath("/dns/deleterecord/")
-
- data := map[string]string{
- "domainname": dns01.UnFqdn(zone),
- "recordid": recordID,
- }
-
- req, err := newMultipartRequest(ctx, http.MethodPost, endpoint, data)
- if err != nil {
- return err
- }
-
- result := new(BaseResponse)
-
- err = c.doAuthenticated(ctx, req, result)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func (c *Client) GetRecords(ctx context.Context, zone string) (map[string]Zone, error) {
- endpoint := c.baseURL.JoinPath("/dns/getrecords/")
-
- query := endpoint.Query()
- query.Set("domainname", zone)
-
- endpoint.RawQuery = query.Encode()
-
- req, err := newFormRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- result := new(GetRecordsResponse)
-
- err = c.doAuthenticated(ctx, req, result)
- if err != nil {
- return nil, err
- }
-
- return result.DNS, nil
-}
-
-func (c *Client) do(req *http.Request, result responseChecker) error {
- useragent.SetHeader(req.Header)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return result.Check()
-}
-
-func newMultipartRequest(ctx context.Context, method string, endpoint *url.URL, data map[string]string) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- writer := multipart.NewWriter(buf)
-
- for k, v := range data {
- err := writer.WriteField(k, v)
- if err != nil {
- return nil, err
- }
- }
-
- err := writer.Close()
- if err != nil {
- return nil, err
- }
-
- body := bytes.NewReader(buf.Bytes())
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), body)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Content-Type", writer.FormDataContentType())
-
- return req, nil
-}
-
-func newFormRequest(ctx context.Context, method string, endpoint *url.URL, form url.Values) (*http.Request, error) {
- var body io.Reader
-
- if len(form) > 0 {
- body = bytes.NewReader([]byte(form.Encode()))
- } else {
- body = http.NoBody
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), body)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- if method == http.MethodPost {
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- }
-
- return req, nil
-}
diff --git a/providers/dns/excedo/internal/client_test.go b/providers/dns/excedo/internal/client_test.go
deleted file mode 100644
index f4fd52c00..000000000
--- a/providers/dns/excedo/internal/client_test.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package internal
-
-import (
- "net/http/httptest"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(server.URL, "secret")
- if err != nil {
- return nil, err
- }
-
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- )
-}
-
-func TestClient_AddRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/addrecord/",
- servermock.ResponseFromFixture("addrecord.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer session-token"),
- servermock.CheckForm().Strict().
- With("content", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY").
- With("domainName", "example.com").
- With("name", "_acme-challenge").
- With("ttl", "60").
- With("type", "TXT"),
- ).
- Build(t)
-
- client.token = &ExpirableToken{
- Token: "session-token",
- Expires: time.Now().Add(6 * time.Hour),
- }
-
- record := Record{
- DomainName: "example.com",
- Name: "_acme-challenge",
- Type: "TXT",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: "60",
- }
-
- recordID, err := client.AddRecord(t.Context(), record)
- require.NoError(t, err)
-
- assert.EqualValues(t, 19695822, recordID)
-}
-
-func TestClient_AddRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/addrecord/",
- servermock.ResponseFromFixture("error.json"),
- ).
- Build(t)
-
- client.token = &ExpirableToken{
- Token: "session-token",
- Expires: time.Now().Add(6 * time.Hour),
- }
-
- record := Record{
- DomainName: "example.com",
- Name: "_acme-challenge",
- Type: "TXT",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: "60",
- }
-
- _, err := client.AddRecord(t.Context(), record)
- require.EqualError(t, err, "2003: Required parameter missing")
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/deleterecord/",
- servermock.ResponseFromFixture("deleterecord.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer session-token"),
- ).
- Build(t)
-
- client.token = &ExpirableToken{
- Token: "session-token",
- Expires: time.Now().Add(6 * time.Hour),
- }
-
- err := client.DeleteRecord(t.Context(), "example.com", "19695822")
- require.NoError(t, err)
-}
-
-func TestClient_GetRecords(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/getrecords/",
- servermock.ResponseFromFixture("getrecords.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer session-token"),
- servermock.CheckQueryParameter().Strict().
- With("domainname", "example.com"),
- ).
- Build(t)
-
- client.token = &ExpirableToken{
- Token: "session-token",
- Expires: time.Now().Add(6 * time.Hour),
- }
-
- zones, err := client.GetRecords(t.Context(), "example.com")
- require.NoError(t, err)
-
- expected := map[string]Zone{
- "example.com": {
- DNSType: "type",
- Records: []Record{{
- RecordID: "1234",
- Name: "_acme-challenge.example.com",
- Type: "TXT",
- Content: "txt-value",
- TTL: "60",
- }},
- },
- }
-
- assert.Equal(t, expected, zones)
-}
diff --git a/providers/dns/excedo/internal/fixtures/addrecord.json b/providers/dns/excedo/internal/fixtures/addrecord.json
deleted file mode 100644
index f1f7bf958..000000000
--- a/providers/dns/excedo/internal/fixtures/addrecord.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "code": 1000,
- "desc": "Command completed successfully",
- "recordid": 19695822,
- "session": {
- "accID": "1234",
- "usrID": "1234",
- "status": "active",
- "expire": {
- "date": "2026-03-10 19:03:18",
- "seconds": 5678
- }
- },
- "runtime": 0.2852
-}
diff --git a/providers/dns/excedo/internal/fixtures/deleterecord.json b/providers/dns/excedo/internal/fixtures/deleterecord.json
deleted file mode 100644
index 5c2431b1c..000000000
--- a/providers/dns/excedo/internal/fixtures/deleterecord.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "code": 1000,
- "desc": "Command completed successfully",
- "session": {
- "accID": "1234",
- "usrID": "1234",
- "status": "active",
- "expire": {
- "date": "2026-03-10 19:03:18",
- "seconds": 5678
- }
- },
- "runtime": 0.2852
-}
diff --git a/providers/dns/excedo/internal/fixtures/error.json b/providers/dns/excedo/internal/fixtures/error.json
deleted file mode 100644
index 5a24ec247..000000000
--- a/providers/dns/excedo/internal/fixtures/error.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "code": 2003,
- "desc": "Required parameter missing",
- "missing": [
- "domainname",
- "recordid"
- ],
- "session": {
- "accID": "1234",
- "usrID": "1234",
- "status": "active",
- "expire": {
- "date": "2026-03-10 19:03:18",
- "seconds": 5485
- }
- },
- "runtime": 0.0534
-}
diff --git a/providers/dns/excedo/internal/fixtures/getrecords.json b/providers/dns/excedo/internal/fixtures/getrecords.json
deleted file mode 100644
index 215a8abb2..000000000
--- a/providers/dns/excedo/internal/fixtures/getrecords.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "code": 1000,
- "desc": "Command completed successfully",
- "dns": {
- "example.com": {
- "dnstype": "type",
- "recordusage": {
- "used": 74
- },
- "records": [
- {
- "recordid": "1234",
- "name": "_acme-challenge.example.com",
- "type": "TXT",
- "content": "txt-value",
- "ttl": "60",
- "prio": null,
- "change_date": null
- }
- ]
- }
- }
-}
diff --git a/providers/dns/excedo/internal/fixtures/login.json b/providers/dns/excedo/internal/fixtures/login.json
deleted file mode 100644
index 2defb9843..000000000
--- a/providers/dns/excedo/internal/fixtures/login.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "code": 1000,
- "desc": "Command completed successfully",
- "parameters": {
- "token": "session-token"
- }
-}
diff --git a/providers/dns/excedo/internal/identity.go b/providers/dns/excedo/internal/identity.go
deleted file mode 100644
index 5c9ca119d..000000000
--- a/providers/dns/excedo/internal/identity.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package internal
-
-import (
- "context"
- "fmt"
- "net/http"
- "time"
-)
-
-type ExpirableToken struct {
- Token string
- Expires time.Time
-}
-
-func (t *ExpirableToken) IsExpired() bool {
- return time.Now().After(t.Expires)
-}
-
-func (c *Client) Login(ctx context.Context) (string, error) {
- endpoint := c.baseURL.JoinPath("/authenticate/login/")
-
- req, err := newFormRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return "", err
- }
-
- req.Header.Set("Authorization", "Bearer "+c.apiKey)
-
- result := new(LoginResponse)
-
- err = c.do(req, result)
- if err != nil {
- return "", err
- }
-
- if result.Code != 1000 && result.Code != 1300 {
- return "", fmt.Errorf("%d: %s", result.Code, result.Description)
- }
-
- return result.Parameters.Token, nil
-}
-
-func (c *Client) authenticate(ctx context.Context) (string, error) {
- c.muToken.Lock()
- defer c.muToken.Unlock()
-
- if c.token == nil || c.token.IsExpired() {
- token, err := c.Login(ctx)
- if err != nil {
- return "", err
- }
-
- c.token = &ExpirableToken{
- Token: token,
- Expires: time.Now().Add(2*time.Hour - time.Minute),
- }
-
- return token, nil
- }
-
- return c.token.Token, nil
-}
-
-func (c *Client) doAuthenticated(ctx context.Context, req *http.Request, result responseChecker) error {
- token, err := c.authenticate(ctx)
- if err != nil {
- return err
- }
-
- if token != "" {
- req.Header.Set("Authorization", "Bearer "+token)
- }
-
- return c.do(req, result)
-}
diff --git a/providers/dns/excedo/internal/identity_test.go b/providers/dns/excedo/internal/identity_test.go
deleted file mode 100644
index 86b7eb9d8..000000000
--- a/providers/dns/excedo/internal/identity_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package internal
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestClient_Login(t *testing.T) {
- client := mockBuilder().
- Route("GET /authenticate/login/",
- servermock.ResponseFromFixture("login.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secret"),
- ).
- Build(t)
-
- token, err := client.Login(t.Context())
- require.NoError(t, err)
-
- assert.Equal(t, "session-token", token)
-}
-
-func TestClient_Login_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /authenticate/login/",
- servermock.ResponseFromFixture("error.json"),
- ).
- Build(t)
-
- _, err := client.Login(t.Context())
- require.EqualError(t, err, "2003: Required parameter missing")
-}
diff --git a/providers/dns/excedo/internal/types.go b/providers/dns/excedo/internal/types.go
deleted file mode 100644
index eb6ce8462..000000000
--- a/providers/dns/excedo/internal/types.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package internal
-
-import "fmt"
-
-type BaseResponse struct {
- Code int `json:"code"`
- Description string `json:"desc"`
-}
-
-func (r BaseResponse) Check() error {
- // Response codes:
- // - 1000: Command completed successfully
- // - 1300: Command completed successfully; no messages
- // - 2001: Command syntax error
- // - 2002: Command use error
- // - 2003: Required parameter missing
- // - 2004: Parameter value range error
- // - 2104: Billing failure
- // - 2200: Authentication error
- // - 2201: Authorization error
- // - 2303: Object does not exist
- // - 2304: Object status prohibits operation
- // - 2309: Object duplicate found
- // - 2400: Command failed
- // - 2500: Command failed; server closing connection
- if r.Code != 1000 && r.Code != 1300 {
- return fmt.Errorf("%d: %s", r.Code, r.Description)
- }
-
- return nil
-}
-
-type GetRecordsResponse struct {
- BaseResponse
-
- DNS map[string]Zone `json:"dns"`
-}
-
-type Zone struct {
- DNSType string `json:"dnstype"`
- Records []Record `json:"records"`
-}
-
-type Record struct {
- DomainName string `json:"domainName,omitempty" url:"domainName,omitempty"`
- RecordID string `json:"recordid,omitempty" url:"recordid,omitempty"`
- Name string `json:"name,omitempty" url:"name,omitempty"`
- Type string `json:"type,omitempty" url:"type,omitempty"`
- Content string `json:"content,omitempty" url:"content,omitempty"`
- TTL string `json:"ttl,omitempty" url:"ttl,omitempty"`
-}
-
-type AddRecordResponse struct {
- BaseResponse
-
- RecordID int64 `json:"recordid"`
-}
-
-type LoginResponse struct {
- BaseResponse
-
- Parameters struct {
- Token string `json:"token"`
- } `json:"parameters"`
-}
diff --git a/providers/dns/exec/exec.toml b/providers/dns/exec/exec.toml
index 2f9c77c67..4c8d70b1c 100644
--- a/providers/dns/exec/exec.toml
+++ b/providers/dns/exec/exec.toml
@@ -6,7 +6,7 @@ Since = "v0.5.0"
Example = '''
EXEC_PATH=/the/path/to/myscript.sh \
-lego --dns exec -d '*.example.com' -d example.com run
+lego --email you@example.com --dns exec -d '*.example.com' -d example.com run
'''
Additional = '''
@@ -39,7 +39,7 @@ For example, requesting a certificate for the domain 'my.example.org' can be ach
```bash
EXEC_PATH=./update-dns.sh \
-lego --dns exec --d my.example.org run
+lego --email you@example.com --dns exec --d my.example.org run
```
It will then call the program './update-dns.sh' with like this:
@@ -59,7 +59,7 @@ If you want to use the raw domain, token, and keyAuth values with your program,
```bash
EXEC_MODE=RAW \
EXEC_PATH=./update-dns.sh \
-lego --dns exec -d my.example.org run
+lego --email you@example.com --dns exec -d my.example.org run
```
It will then call the program `./update-dns.sh` like this:
diff --git a/providers/dns/exec/exec_test.go b/providers/dns/exec/exec_test.go
index c1b6da55e..3a2edbbf4 100644
--- a/providers/dns/exec/exec_test.go
+++ b/providers/dns/exec/exec_test.go
@@ -14,7 +14,6 @@ import (
func TestDNSProvider_Present(t *testing.T) {
backupLogger := log.Logger
-
defer func() {
log.Logger = backupLogger
}()
@@ -63,7 +62,6 @@ func TestDNSProvider_Present(t *testing.T) {
}
var message string
-
logRecorder.On("Println", mock.Anything).Run(func(args mock.Arguments) {
message = args.String(0)
fmt.Fprintln(os.Stdout, "XXX", message)
@@ -89,7 +87,6 @@ func TestDNSProvider_Present(t *testing.T) {
func TestDNSProvider_CleanUp(t *testing.T) {
backupLogger := log.Logger
-
defer func() {
log.Logger = backupLogger
}()
@@ -138,7 +135,6 @@ func TestDNSProvider_CleanUp(t *testing.T) {
}
var message string
-
logRecorder.On("Println", mock.Anything).Run(func(args mock.Arguments) {
message = args.String(0)
fmt.Fprintln(os.Stdout, "XXX", message)
diff --git a/providers/dns/exoscale/exoscale.go b/providers/dns/exoscale/exoscale.go
index 05fcb6a6f..1a5f358f5 100644
--- a/providers/dns/exoscale/exoscale.go
+++ b/providers/dns/exoscale/exoscale.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
)
@@ -90,7 +89,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client, err := egoscale.NewClient(
credentials.NewStaticCredentials(config.APIKey, config.APISecret),
egoscale.ClientOptWithEndpoint(egoscale.Endpoint(config.Endpoint)),
- egoscale.ClientOptWithHTTPClient(clientdebug.Wrap(&http.Client{Timeout: config.HTTPTimeout})),
+ egoscale.ClientOptWithHTTPClient(&http.Client{Timeout: config.HTTPTimeout}),
egoscale.ClientOptWithUserAgent(useragent.Get()),
)
if err != nil {
@@ -106,7 +105,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
zoneName, recordName, err := d.findZoneAndRecordName(info.EffectiveFQDN)
@@ -114,11 +112,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("exoscale: %w", err)
}
- zone, err := d.findExistingZone(ctx, zoneName)
+ zone, err := d.findExistingZone(zoneName)
if err != nil {
return fmt.Errorf("exoscale: %w", err)
}
-
if zone == nil {
return fmt.Errorf("exoscale: zone %q not found", zoneName)
}
@@ -146,7 +143,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
zoneName, recordName, err := d.findZoneAndRecordName(info.EffectiveFQDN)
@@ -154,16 +150,15 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("exoscale: %w", err)
}
- zone, err := d.findExistingZone(ctx, zoneName)
+ zone, err := d.findExistingZone(zoneName)
if err != nil {
return fmt.Errorf("exoscale: %w", err)
}
-
if zone == nil {
return fmt.Errorf("exoscale: zone %q not found", zoneName)
}
- recordID, err := d.findExistingRecordID(ctx, zone.ID, recordName, info.Value)
+ recordID, err := d.findExistingRecordID(zone.ID, recordName, info.Value)
if err != nil {
return err
}
@@ -193,7 +188,9 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
// findExistingZone Query Exoscale to find an existing zone for this name.
// Returns nil result if no zone could be found.
-func (d *DNSProvider) findExistingZone(ctx context.Context, zoneName string) (*egoscale.DNSDomain, error) {
+func (d *DNSProvider) findExistingZone(zoneName string) (*egoscale.DNSDomain, error) {
+ ctx := context.Background()
+
zones, err := d.client.ListDNSDomains(ctx)
if err != nil {
return nil, fmt.Errorf("error while retrieving DNS zones: %w", err)
@@ -210,7 +207,9 @@ func (d *DNSProvider) findExistingZone(ctx context.Context, zoneName string) (*e
// findExistingRecordID Query Exoscale to find an existing record for this name.
// Returns empty result if no record could be found.
-func (d *DNSProvider) findExistingRecordID(ctx context.Context, zoneID egoscale.UUID, recordName, value string) (egoscale.UUID, error) {
+func (d *DNSProvider) findExistingRecordID(zoneID egoscale.UUID, recordName, value string) (egoscale.UUID, error) {
+ ctx := context.Background()
+
records, err := d.client.ListDNSDomainRecords(ctx, zoneID)
if err != nil {
return "", fmt.Errorf("error while retrieving DNS records: %w", err)
diff --git a/providers/dns/exoscale/exoscale.toml b/providers/dns/exoscale/exoscale.toml
index bcc912b07..82c005d26 100644
--- a/providers/dns/exoscale/exoscale.toml
+++ b/providers/dns/exoscale/exoscale.toml
@@ -7,7 +7,7 @@ Since = "v0.4.0"
Example = '''
EXOSCALE_API_KEY=abcdefghijklmnopqrstuvwx \
EXOSCALE_API_SECRET=xxxxxxx \
-lego --dns exoscale -d '*.example.com' -d example.com run
+lego --email you@example.com --dns exoscale -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/exoscale/exoscale_test.go b/providers/dns/exoscale/exoscale_test.go
index e9f6be602..fa58216a5 100644
--- a/providers/dns/exoscale/exoscale_test.go
+++ b/providers/dns/exoscale/exoscale_test.go
@@ -58,7 +58,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -179,7 +178,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -197,7 +195,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/f5xc/f5xc.go b/providers/dns/f5xc/f5xc.go
index 76a6e0262..2ed1f0c4f 100644
--- a/providers/dns/f5xc/f5xc.go
+++ b/providers/dns/f5xc/f5xc.go
@@ -8,12 +8,10 @@ import (
"net/http"
"time"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/platform/wait"
"github.com/go-acme/lego/v4/providers/dns/f5xc/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -22,7 +20,6 @@ const (
EnvToken = envNamespace + "API_TOKEN"
EnvTenantName = envNamespace + "TENANT_NAME"
- EnvServer = envNamespace + "SERVER"
EnvGroupName = envNamespace + "GROUP_NAME"
EnvTTL = envNamespace + "TTL"
@@ -35,7 +32,6 @@ const (
type Config struct {
APIToken string
TenantName string
- Server string
GroupName string
PropagationTimeout time.Duration
@@ -73,7 +69,6 @@ func NewDNSProvider() (*DNSProvider, error) {
config.APIToken = values[EnvToken]
config.TenantName = values[EnvTenantName]
config.GroupName = values[EnvGroupName]
- config.Server = env.GetOrFile(EnvServer)
return NewDNSProviderConfig(config)
}
@@ -88,7 +83,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("f5xc: missing group name")
}
- client, err := internal.NewClient(config.APIToken, config.TenantName, config.Server)
+ client, err := internal.NewClient(config.APIToken, config.TenantName)
if err != nil {
return nil, fmt.Errorf("f5xc: %w", err)
}
@@ -97,8 +92,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -107,8 +100,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
@@ -121,7 +112,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("f5xc: %w", err)
}
- existingRRSet, err := d.client.GetRRSet(ctx, dns01.UnFqdn(authZone), d.config.GroupName, subDomain, "TXT")
+ existingRRSet, err := d.client.GetRRSet(context.Background(), dns01.UnFqdn(authZone), d.config.GroupName, subDomain, "TXT")
if err != nil {
return fmt.Errorf("f5xc: get RR Set: %w", err)
}
@@ -137,41 +128,29 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
},
}
- return d.waitFor(ctx, func() error {
- _, err = d.client.CreateRRSet(ctx, dns01.UnFqdn(authZone), d.config.GroupName, rrSet)
+ return wait.For("f5xc create", 60*time.Second, 2*time.Second, func() (bool, error) {
+ _, err = d.client.CreateRRSet(context.Background(), dns01.UnFqdn(authZone), d.config.GroupName, rrSet)
if err != nil {
- return fmt.Errorf("create RR set: %w", err)
+ return false, fmt.Errorf("f5xc: create RR set: %w", err)
}
- return nil
+ return true, nil
})
}
// Update RRSet.
existingRRSet.RRSet.TXTRecord.Values = append(existingRRSet.RRSet.TXTRecord.Values, info.Value)
- return d.waitFor(ctx, func() error {
- _, err = d.client.ReplaceRRSet(ctx, dns01.UnFqdn(authZone), d.config.GroupName, subDomain, "TXT", existingRRSet.RRSet)
+ return wait.For("f5xc replace", 60*time.Second, 2*time.Second, func() (bool, error) {
+ _, err = d.client.ReplaceRRSet(context.Background(), dns01.UnFqdn(authZone), d.config.GroupName, subDomain, "TXT", existingRRSet.RRSet)
if err != nil {
- return fmt.Errorf("replace RR set: %w", err)
+ return false, fmt.Errorf("f5xc: replace RR set: %w", err)
}
- return nil
+ return true, nil
})
}
-func (d *DNSProvider) waitFor(ctx context.Context, operation func() error) error {
- err := wait.Retry(ctx, operation,
- backoff.WithBackOff(backoff.NewConstantBackOff(2*time.Second)),
- backoff.WithMaxElapsedTime(60*time.Second),
- )
- if err != nil {
- return fmt.Errorf("f5xc: %w", err)
- }
-
- return nil
-}
-
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
diff --git a/providers/dns/f5xc/f5xc.toml b/providers/dns/f5xc/f5xc.toml
index 6be604ddd..7a4cab419 100644
--- a/providers/dns/f5xc/f5xc.toml
+++ b/providers/dns/f5xc/f5xc.toml
@@ -8,7 +8,7 @@ Example = '''
F5XC_API_TOKEN="xxx" \
F5XC_TENANT_NAME="yyy" \
F5XC_GROUP_NAME="zzz" \
-lego --dns f5xc -d '*.example.com' -d example.com run
+lego --email you@example.com --dns f5xc -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -17,7 +17,6 @@ lego --dns f5xc -d '*.example.com' -d example.com run
F5XC_TENANT_NAME = "XC Tenant shortname"
F5XC_GROUP_NAME = "Group name"
[Configuration.Additional]
- F5XC_SERVER = "Server domain (Default: console.ves.volterra.io)"
F5XC_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
F5XC_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
F5XC_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
diff --git a/providers/dns/f5xc/f5xc_test.go b/providers/dns/f5xc/f5xc_test.go
index 890a4cf09..a298b9e51 100644
--- a/providers/dns/f5xc/f5xc_test.go
+++ b/providers/dns/f5xc/f5xc_test.go
@@ -9,12 +9,7 @@ import (
const envDomain = envNamespace + "DOMAIN"
-var envTest = tester.NewEnvTest(
- EnvToken,
- EnvTenantName,
- EnvServer,
- EnvGroupName,
-).WithDomain(envDomain)
+var envTest = tester.NewEnvTest(EnvToken, EnvTenantName, EnvGroupName).WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) {
testCases := []struct {
@@ -67,7 +62,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -151,7 +145,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -165,7 +158,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/f5xc/internal/client.go b/providers/dns/f5xc/internal/client.go
index 7beab0d03..26eb03db5 100644
--- a/providers/dns/f5xc/internal/client.go
+++ b/providers/dns/f5xc/internal/client.go
@@ -14,7 +14,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
)
-const defaultServer = "console.ves.volterra.io"
+const defaultHost = "console.ves.volterra.io"
const authorizationHeader = "Authorization"
@@ -27,14 +27,18 @@ type Client struct {
}
// NewClient creates a new Client.
-func NewClient(apiToken, tenantName, server string) (*Client, error) {
+func NewClient(apiToken, tenantName string) (*Client, error) {
if apiToken == "" {
return nil, errors.New("credentials missing")
}
- baseURL, err := createBaseURL(tenantName, server)
+ if tenantName == "" {
+ return nil, errors.New("missing tenant name")
+ }
+
+ baseURL, err := url.Parse(fmt.Sprintf("https://%s.%s", tenantName, defaultHost))
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("parse base URL: %w", err)
}
return &Client{
@@ -197,7 +201,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
apiErr := APIError{StatusCode: resp.StatusCode}
-
err := json.Unmarshal(raw, &apiErr)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
@@ -205,20 +208,3 @@ func parseError(req *http.Request, resp *http.Response) error {
return &apiErr
}
-
-func createBaseURL(tenant, server string) (*url.URL, error) {
- if tenant == "" {
- return nil, errors.New("missing tenant name")
- }
-
- if server == "" {
- server = defaultServer
- }
-
- baseURL, err := url.Parse(fmt.Sprintf("https://%s.%s", tenant, server))
- if err != nil {
- return nil, fmt.Errorf("parse base URL: %w", err)
- }
-
- return baseURL, nil
-}
diff --git a/providers/dns/f5xc/internal/client_test.go b/providers/dns/f5xc/internal/client_test.go
index bb188ef3f..0357abb16 100644
--- a/providers/dns/f5xc/internal/client_test.go
+++ b/providers/dns/f5xc/internal/client_test.go
@@ -14,7 +14,7 @@ import (
func mockBuilder() *servermock.Builder[*Client] {
return servermock.NewBuilder[*Client](
func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret", "shortname", "")
+ client, err := NewClient("secret", "shortname")
if err != nil {
return nil, err
}
@@ -28,7 +28,7 @@ func mockBuilder() *servermock.Builder[*Client] {
WithAuthorization("APIToken secret"))
}
-func TestClient_CreateRRSet(t *testing.T) {
+func TestClient_Create(t *testing.T) {
client := mockBuilder().
Route("POST /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA",
servermock.ResponseFromFixture("create.json"),
@@ -62,7 +62,7 @@ func TestClient_CreateRRSet(t *testing.T) {
assert.Equal(t, expected, result)
}
-func TestClient_CreateRRSet_error(t *testing.T) {
+func TestClient_Create_error(t *testing.T) {
client := mockBuilder().
Route("POST /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA",
servermock.Noop().WithStatusCode(http.StatusBadRequest)).
@@ -81,7 +81,7 @@ func TestClient_CreateRRSet_error(t *testing.T) {
require.Error(t, err)
}
-func TestClient_GetRRSet(t *testing.T) {
+func TestClient_Get(t *testing.T) {
client := mockBuilder().
Route("GET /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA/www/TXT",
servermock.ResponseFromFixture("get.json")).
@@ -108,7 +108,7 @@ func TestClient_GetRRSet(t *testing.T) {
assert.Equal(t, expected, result)
}
-func TestClient_GetRRSet_not_found(t *testing.T) {
+func TestClient_Get_not_found(t *testing.T) {
client := mockBuilder().
Route("GET /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA/www/TXT",
servermock.ResponseFromFixture("error_404.json").WithStatusCode(http.StatusNotFound)).
@@ -120,7 +120,7 @@ func TestClient_GetRRSet_not_found(t *testing.T) {
assert.Nil(t, result)
}
-func TestClient_GetRRSet_error(t *testing.T) {
+func TestClient_Get_error(t *testing.T) {
client := mockBuilder().
Route("GET /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA/www/TXT",
servermock.Noop().WithStatusCode(http.StatusBadRequest)).
@@ -130,7 +130,7 @@ func TestClient_GetRRSet_error(t *testing.T) {
require.Error(t, err)
}
-func TestClient_DeleteRRSet(t *testing.T) {
+func TestClient_Delete(t *testing.T) {
client := mockBuilder().
Route("DELETE /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA/www/TXT",
servermock.ResponseFromFixture("get.json")).
@@ -157,7 +157,7 @@ func TestClient_DeleteRRSet(t *testing.T) {
assert.Equal(t, expected, result)
}
-func TestClient_DeleteRRSet_error(t *testing.T) {
+func TestClient_Delete_error(t *testing.T) {
client := mockBuilder().
Route("DELETE /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA/www/TXT",
servermock.Noop().WithStatusCode(http.StatusBadRequest)).
@@ -167,7 +167,7 @@ func TestClient_DeleteRRSet_error(t *testing.T) {
require.Error(t, err)
}
-func TestClient_ReplaceRRSet(t *testing.T) {
+func TestClient_Replace(t *testing.T) {
client := mockBuilder().
Route("PUT /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA/www/TXT",
servermock.ResponseFromFixture("get.json"),
@@ -204,7 +204,7 @@ func TestClient_ReplaceRRSet(t *testing.T) {
assert.Equal(t, expected, result)
}
-func TestClient_ReplaceRRSet_error(t *testing.T) {
+func TestClient_Replace_error(t *testing.T) {
client := mockBuilder().
Route("PUT /api/config/dns/namespaces/system/dns_zones/example.com/rrsets/groupA/www/TXT",
servermock.Noop().WithStatusCode(http.StatusBadRequest)).
@@ -222,70 +222,3 @@ func TestClient_ReplaceRRSet_error(t *testing.T) {
_, err := client.ReplaceRRSet(t.Context(), "example.com", "groupA", "www", "TXT", rrSet)
require.Error(t, err)
}
-
-func Test_createBaseURL(t *testing.T) {
- testCases := []struct {
- desc string
- tenant string
- server string
- expected string
- }{
- {
- desc: "only tenant",
- tenant: "foo",
- expected: "https://foo.console.ves.volterra.io",
- },
- {
- desc: "custom server",
- tenant: "foo",
- server: "example.com",
- expected: "https://foo.example.com",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- baseURL, err := createBaseURL(test.tenant, test.server)
- require.NoError(t, err)
-
- assert.Equal(t, test.expected, baseURL.String())
- })
- }
-}
-
-func Test_createBaseURL_error(t *testing.T) {
- testCases := []struct {
- desc string
- tenant string
- server string
- expected string
- }{
- {
- desc: "no tenant",
- tenant: "",
- expected: "missing tenant name",
- },
- {
- desc: "invalid tenant",
- tenant: "%31",
- expected: `parse base URL: parse "https://%31.console.ves.volterra.io": invalid URL escape "%31"`,
- },
- {
- desc: "invalid host",
- tenant: "foo",
- server: "192.168.0.%31",
- expected: `parse base URL: parse "https://foo.192.168.0.%31": invalid URL escape "%31"`,
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- _, err := createBaseURL(test.tenant, test.server)
- require.EqualError(t, err, test.expected)
- })
- }
-}
diff --git a/providers/dns/f5xc/internal/types.go b/providers/dns/f5xc/internal/types.go
index 346283fb7..3122ca4ef 100644
--- a/providers/dns/f5xc/internal/types.go
+++ b/providers/dns/f5xc/internal/types.go
@@ -27,13 +27,13 @@ type APIRRSet struct {
Namespace string `json:"namespace,omitempty"`
RecordName string `json:"record_name,omitempty"`
Type string `json:"type,omitempty"`
- RRSet RRSet `json:"rrset"`
+ RRSet RRSet `json:"rrset,omitempty"`
}
type RRSetRequest struct {
DNSZoneName string `json:"dns_zone_name,omitempty"`
GroupName string `json:"group_name,omitempty"`
- RRSet RRSet `json:"rrset"`
+ RRSet RRSet `json:"rrset,omitempty"`
}
type RRSet struct {
diff --git a/providers/dns/freemyip/freemyip.go b/providers/dns/freemyip/freemyip.go
index fb6202e25..7613f2b8d 100644
--- a/providers/dns/freemyip/freemyip.go
+++ b/providers/dns/freemyip/freemyip.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/nrdcg/freemyip"
)
@@ -89,8 +88,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/freemyip/freemyip.toml b/providers/dns/freemyip/freemyip.toml
index adbf9e213..4821e2a9c 100644
--- a/providers/dns/freemyip/freemyip.toml
+++ b/providers/dns/freemyip/freemyip.toml
@@ -6,7 +6,7 @@ Since = "v4.5.0"
Example = '''
FREEMYIP_TOKEN=xxxxxx \
-lego --dns freemyip -d '*.example.com' -d example.com run
+lego --email you@example.com --dns freemyip -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/freemyip/freemyip_test.go b/providers/dns/freemyip/freemyip_test.go
index 24d1b98f7..dcf74dd6c 100644
--- a/providers/dns/freemyip/freemyip_test.go
+++ b/providers/dns/freemyip/freemyip_test.go
@@ -37,7 +37,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -95,7 +94,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -109,7 +107,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/gandi/gandi.go b/providers/dns/gandi/gandi.go
index bb96a7d0f..dd6622172 100644
--- a/providers/dns/gandi/gandi.go
+++ b/providers/dns/gandi/gandi.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/gandi/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -110,8 +109,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/gandi/gandi.toml b/providers/dns/gandi/gandi.toml
index 23d7de5db..96d5233be 100644
--- a/providers/dns/gandi/gandi.toml
+++ b/providers/dns/gandi/gandi.toml
@@ -6,7 +6,7 @@ Since = "v0.3.0"
Example = '''
GANDI_API_KEY=abcdefghijklmnopqrstuvwx \
-lego --dns gandi -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gandi -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/gandi/gandi_test.go b/providers/dns/gandi/gandi_test.go
index 58c25d0db..4c37fb00e 100644
--- a/providers/dns/gandi/gandi_test.go
+++ b/providers/dns/gandi/gandi_test.go
@@ -39,7 +39,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -127,7 +126,6 @@ func TestDNSProvider(t *testing.T) {
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
config.BaseURL = server.URL + "/"
- config.HTTPClient = server.Client()
config.APIKey = "123412341234123412341234"
return NewDNSProviderConfig(config)
@@ -147,6 +145,7 @@ func TestDNSProvider(t *testing.T) {
_, errS = io.Copy(rw, strings.NewReader(resp))
require.NoError(t, errS)
})).
+ Route("/", servermock.DumpRequest()).
Build(t)
fakeKeyAuth := "XXXX"
@@ -158,11 +157,9 @@ func TestDNSProvider(t *testing.T) {
// override findZoneByFqdn function
savedFindZoneByFqdn := provider.findZoneByFqdn
-
t.Cleanup(func() {
provider.findZoneByFqdn = savedFindZoneByFqdn
})
-
provider.findZoneByFqdn = fakeFindZoneByFqdn
// run Present
diff --git a/providers/dns/gandi/internal/client.go b/providers/dns/gandi/internal/client.go
index 6ca46d072..6dc09648c 100644
--- a/providers/dns/gandi/internal/client.go
+++ b/providers/dns/gandi/internal/client.go
@@ -50,7 +50,6 @@ func (c *Client) GetZoneID(ctx context.Context, domain string) (int, error) {
}
var zoneID int
-
for _, member := range resp.StructMembers {
if member.Name == "zone_id" {
zoneID = member.ValueInt
@@ -60,7 +59,6 @@ func (c *Client) GetZoneID(ctx context.Context, domain string) (int, error) {
if zoneID == 0 {
return 0, fmt.Errorf("could not find zone_id for %s", domain)
}
-
return zoneID, nil
}
@@ -90,7 +88,6 @@ func (c *Client) CloneZone(ctx context.Context, zoneID int, name string) (int, e
}
var newZoneID int
-
for _, member := range resp.StructMembers {
if member.Name == "id" {
newZoneID = member.ValueInt
@@ -100,7 +97,6 @@ func (c *Client) CloneZone(ctx context.Context, zoneID int, name string) (int, e
if newZoneID == 0 {
return 0, errors.New("could not determine cloned zone_id")
}
-
return newZoneID, nil
}
@@ -123,7 +119,6 @@ func (c *Client) NewZoneVersion(ctx context.Context, zoneID int) (int, error) {
if resp.Value == 0 {
return 0, errors.New("could not create new zone version")
}
-
return resp.Value, nil
}
@@ -179,7 +174,6 @@ func (c *Client) SetZoneVersion(ctx context.Context, zoneID, version int) error
if !resp.Value {
return errors.New("could not set zone version")
}
-
return nil
}
@@ -201,7 +195,6 @@ func (c *Client) SetZone(ctx context.Context, domain string, zoneID int) error {
}
var respZoneID int
-
for _, member := range resp.StructMembers {
if member.Name == "zone_id" {
respZoneID = member.ValueInt
@@ -211,7 +204,6 @@ func (c *Client) SetZone(ctx context.Context, domain string, zoneID int) error {
if respZoneID != zoneID {
return fmt.Errorf("could not set new zone_id for %s", domain)
}
-
return nil
}
diff --git a/providers/dns/gandi/internal/types.go b/providers/dns/gandi/internal/types.go
index 2cde62b53..cdcd0a658 100644
--- a/providers/dns/gandi/internal/types.go
+++ b/providers/dns/gandi/internal/types.go
@@ -69,7 +69,6 @@ func (r responseFault) faultString() string { return r.FaultString }
type responseStruct struct {
responseFault
-
StructMembers []struct {
Name string `xml:"name"`
ValueInt int `xml:"value>int"`
@@ -78,13 +77,11 @@ type responseStruct struct {
type responseInt struct {
responseFault
-
Value int `xml:"params>param>value>int"`
}
type responseBool struct {
responseFault
-
Value bool `xml:"params>param>value>boolean"`
}
diff --git a/providers/dns/gandiv5/gandiv5.go b/providers/dns/gandiv5/gandiv5.go
index 15014e207..3c35245de 100644
--- a/providers/dns/gandiv5/gandiv5.go
+++ b/providers/dns/gandiv5/gandiv5.go
@@ -15,7 +15,6 @@ import (
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/gandiv5/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -114,7 +113,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if err != nil {
return nil, fmt.Errorf("gandiv5: %w", err)
}
-
client.BaseURL = baseURL
}
@@ -122,8 +120,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -164,7 +160,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
authZone: authZone,
fieldName: subDomain,
}
-
return nil
}
@@ -175,7 +170,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
// acquire lock and retrieve authZone
d.inProgressMu.Lock()
defer d.inProgressMu.Unlock()
-
if _, ok := d.inProgressFQDNs[info.EffectiveFQDN]; !ok {
// if there is no cleanup information then just return
return nil
@@ -190,7 +184,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("gandiv5: %w", err)
}
-
return nil
}
diff --git a/providers/dns/gandiv5/gandiv5.toml b/providers/dns/gandiv5/gandiv5.toml
index 31568e89b..246b03524 100644
--- a/providers/dns/gandiv5/gandiv5.toml
+++ b/providers/dns/gandiv5/gandiv5.toml
@@ -6,7 +6,7 @@ Since = "v0.5.0"
Example = '''
GANDIV5_PERSONAL_ACCESS_TOKEN=abcdefghijklmnopqrstuvwx \
-lego --dns gandiv5 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gandiv5 -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/gandiv5/gandiv5_test.go b/providers/dns/gandiv5/gandiv5_test.go
index d6f077243..451b1b683 100644
--- a/providers/dns/gandiv5/gandiv5_test.go
+++ b/providers/dns/gandiv5/gandiv5_test.go
@@ -35,7 +35,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -97,7 +96,6 @@ func TestDNSProvider(t *testing.T) {
config := NewDefaultConfig()
config.PersonalAccessToken = "123412341234123412341234"
config.BaseURL = server.URL
- config.HTTPClient = server.Client()
return NewDNSProviderConfig(config)
},
@@ -121,11 +119,9 @@ func TestDNSProvider(t *testing.T) {
// override findZoneByFqdn function
savedFindZoneByFqdn := provider.findZoneByFqdn
-
defer func() {
provider.findZoneByFqdn = savedFindZoneByFqdn
}()
-
provider.findZoneByFqdn = fakeFindZoneByFqdn
// run Present
diff --git a/providers/dns/gandiv5/internal/client.go b/providers/dns/gandiv5/internal/client.go
index bfb71c9f6..57de9d615 100644
--- a/providers/dns/gandiv5/internal/client.go
+++ b/providers/dns/gandiv5/internal/client.go
@@ -15,7 +15,10 @@ import (
)
// defaultBaseURL endpoint is the Gandi API endpoint used by Present and CleanUp.
-const defaultBaseURL = "https://api.gandi.net/v5/livedns"
+const defaultBaseURL = "https://dns.api.gandi.net/api/v5"
+
+// APIKeyHeader API key header.
+const APIKeyHeader = "X-Api-Key"
// Related to Personal Access Token.
const authorizationHeader = "Authorization"
@@ -75,7 +78,6 @@ func (c *Client) getTXTRecord(ctx context.Context, domain, name string) (*Record
}
txtRecord := &Record{}
-
err = c.do(req, txtRecord)
if err != nil {
return nil, fmt.Errorf("unable to get TXT records for domain %s and name %s: %w", domain, name, err)
@@ -93,7 +95,6 @@ func (c *Client) addTXTRecord(ctx context.Context, domain, name string, newRecor
}
message := apiResponse{}
-
err = c.do(req, &message)
if err != nil {
return fmt.Errorf("unable to create TXT record for domain %s and name %s: %w", domain, name, err)
@@ -115,7 +116,6 @@ func (c *Client) DeleteTXTRecord(ctx context.Context, domain, name string) error
}
message := apiResponse{}
-
err = c.do(req, &message)
if err != nil {
return fmt.Errorf("unable to delete TXT record for domain %s and name %s: %w", domain, name, err)
@@ -130,7 +130,7 @@ func (c *Client) DeleteTXTRecord(ctx context.Context, domain, name string) error
func (c *Client) do(req *http.Request, result any) error {
if c.apiKey != "" {
- req.Header.Set(authorizationHeader, "Apikey "+c.apiKey)
+ req.Header.Set(APIKeyHeader, c.apiKey)
}
if c.pat != "" {
@@ -208,7 +208,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
response := apiResponse{}
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/gandiv5/internal/client_test.go b/providers/dns/gandiv5/internal/client_test.go
index 6a4158dcb..2465566f9 100644
--- a/providers/dns/gandiv5/internal/client_test.go
+++ b/providers/dns/gandiv5/internal/client_test.go
@@ -9,29 +9,23 @@ import (
"github.com/stretchr/testify/require"
)
-func mockBuilder(apiKey, pat string) *servermock.Builder[*Client] {
- checkHeaders := servermock.CheckHeader().WithJSONHeaders()
-
- if apiKey != "" {
- checkHeaders = checkHeaders.WithAuthorization("Apikey secret-apikey")
- } else {
- checkHeaders = checkHeaders.WithAuthorization("Bearer secret-pat")
- }
-
+func mockBuilder() *servermock.Builder[*Client] {
return servermock.NewBuilder[*Client](
func(server *httptest.Server) (*Client, error) {
- client := NewClient(apiKey, pat)
+ client := NewClient("secret", "xxx")
client.BaseURL, _ = url.Parse(server.URL)
client.HTTPClient = server.Client()
return client, nil
},
- checkHeaders,
+ servermock.CheckHeader().WithJSONHeaders().
+ With("X-Api-Key", "secret").
+ WithAuthorization("Bearer xxx"),
)
}
func TestClient_AddTXTRecord(t *testing.T) {
- client := mockBuilder("secret-apikey", "").
+ client := mockBuilder().
Route("GET /domains/example.com/records/foo/TXT",
servermock.ResponseFromFixture("add_txt_record_get.json")).
Route("PUT /domains/example.com/records/foo/TXT",
@@ -44,7 +38,7 @@ func TestClient_AddTXTRecord(t *testing.T) {
}
func TestClient_DeleteTXTRecord(t *testing.T) {
- client := mockBuilder("", "secret-pat").
+ client := mockBuilder().
Route("DELETE /domains/example.com/records/foo/TXT",
servermock.ResponseFromFixture("api_response.json")).
Build(t)
diff --git a/providers/dns/gcloud/gcloud.toml b/providers/dns/gcloud/gcloud.toml
index 63d22bed3..471e2e9d1 100644
--- a/providers/dns/gcloud/gcloud.toml
+++ b/providers/dns/gcloud/gcloud.toml
@@ -8,18 +8,18 @@ Example = '''
# Using a service account file
GCE_PROJECT="gc-project-id" \
GCE_SERVICE_ACCOUNT_FILE="/path/to/svc/account/file.json" \
-lego --dns gcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gcloud -d '*.example.com' -d example.com run
# Using default credentials with impersonation
GCE_PROJECT="gc-project-id" \
GCE_IMPERSONATE_SERVICE_ACCOUNT="target-sa@gc-project-id.iam.gserviceaccount.com" \
-lego --dns gcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gcloud -d '*.example.com' -d example.com run
# Using service account key with impersonation
GCE_PROJECT="gc-project-id" \
GCE_SERVICE_ACCOUNT_FILE="/path/to/svc/account/file.json" \
GCE_IMPERSONATE_SERVICE_ACCOUNT="target-sa@gc-project-id.iam.gserviceaccount.com" \
-lego --dns gcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gcloud -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/gcloud/googlecloud.go b/providers/dns/gcloud/googlecloud.go
index 61e8ee66f..30a028d61 100644
--- a/providers/dns/gcloud/googlecloud.go
+++ b/providers/dns/gcloud/googlecloud.go
@@ -2,7 +2,6 @@
package gcloud
import (
- "context"
"encoding/json"
"errors"
"fmt"
@@ -12,17 +11,15 @@ import (
"time"
"cloud.google.com/go/compute/metadata"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/platform/wait"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/miekg/dns"
+ "golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
- gdns "google.golang.org/api/dns/v1"
+ "google.golang.org/api/dns/v1"
"google.golang.org/api/googleapi"
"google.golang.org/api/impersonate"
"google.golang.org/api/option"
@@ -77,7 +74,7 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
config *Config
- client *gdns.Service
+ client *dns.Service
}
// NewDNSProvider returns a DNSProvider instance configured for Google Cloud DNS.
@@ -93,7 +90,6 @@ func NewDNSProvider() (*DNSProvider, error) {
// Use default credentials.
project := env.GetOrDefaultString(EnvProject, autodetectProjectID(context.Background()))
-
return NewDNSProviderCredentials(project)
}
@@ -108,7 +104,6 @@ func NewDNSProviderCredentials(project string) (*DNSProvider, error) {
config.Project = project
var err error
-
config.HTTPClient, err = newClientFromCredentials(context.Background(), config)
if err != nil {
return nil, fmt.Errorf("googlecloud: %w", err)
@@ -132,12 +127,10 @@ func NewDNSProviderServiceAccountKey(saKey []byte) (*DNSProvider, error) {
var datJSON struct {
ProjectID string `json:"project_id"`
}
-
err := json.Unmarshal(saKey, &datJSON)
if err != nil || datJSON.ProjectID == "" {
return nil, errors.New("googlecloud: project ID not found in Google Cloud Service Account file")
}
-
project = datJSON.ProjectID
}
@@ -145,7 +138,6 @@ func NewDNSProviderServiceAccountKey(saKey []byte) (*DNSProvider, error) {
config.Project = project
var err error
-
config.HTTPClient, err = newClientFromServiceAccountKey(context.Background(), config, saKey)
if err != nil {
return nil, fmt.Errorf("googlecloud: %w", err)
@@ -174,12 +166,11 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
return nil, errors.New("googlecloud: the configuration of the DNS provider is nil")
}
-
if config.HTTPClient == nil {
return nil, errors.New("googlecloud: unable to create Google Cloud DNS service: client is nil")
}
- svc, err := gdns.NewService(context.Background(), option.WithHTTPClient(clientdebug.Wrap(config.HTTPClient)))
+ svc, err := dns.NewService(context.Background(), option.WithHTTPClient(config.HTTPClient))
if err != nil {
return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: %w", err)
}
@@ -189,8 +180,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
zone, err := d.getHostedZone(info.EffectiveFQDN)
@@ -206,7 +195,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
for _, rrSet := range existingRrSet {
var rrd []string
-
for _, rr := range rrSet.Rrdatas {
data := mustUnquote(rr)
rrd = append(rrd, data)
@@ -216,18 +204,17 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return nil
}
}
-
rrSet.Rrdatas = rrd
}
// Attempt to delete the existing records before adding the new one.
if len(existingRrSet) > 0 {
- if err = d.applyChanges(ctx, zone, &gdns.Change{Deletions: existingRrSet}); err != nil {
+ if err = d.applyChanges(zone, &dns.Change{Deletions: existingRrSet}); err != nil {
return fmt.Errorf("googlecloud: %w", err)
}
}
- rec := &gdns.ResourceRecordSet{
+ rec := &dns.ResourceRecordSet{
Name: info.EffectiveFQDN,
Rrdatas: []string{info.Value},
Ttl: int64(d.config.TTL),
@@ -243,18 +230,18 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
}
}
- change := &gdns.Change{
- Additions: []*gdns.ResourceRecordSet{rec},
+ change := &dns.Change{
+ Additions: []*dns.ResourceRecordSet{rec},
}
- if err = d.applyChanges(ctx, zone, change); err != nil {
+ if err = d.applyChanges(zone, change); err != nil {
return fmt.Errorf("googlecloud: %w", err)
}
return nil
}
-func (d *DNSProvider) applyChanges(ctx context.Context, zone string, change *gdns.Change) error {
+func (d *DNSProvider) applyChanges(zone string, change *dns.Change) error {
if d.config.Debug {
data, _ := json.Marshal(change)
log.Printf("change (Create): %s", string(data))
@@ -268,7 +255,6 @@ func (d *DNSProvider) applyChanges(ctx context.Context, zone string, change *gdn
}
data, _ := json.Marshal(change)
-
return fmt.Errorf("failed to perform changes [zone %s, change %s]: %w", zone, string(data), err)
}
@@ -279,28 +265,24 @@ func (d *DNSProvider) applyChanges(ctx context.Context, zone string, change *gdn
chgID := chg.Id
// wait for change to be acknowledged
- return wait.Retry(ctx,
- func() error {
- if d.config.Debug {
- data, _ := json.Marshal(change)
- log.Printf("change (Get): %s", string(data))
- }
+ return wait.For("apply change", 30*time.Second, 3*time.Second, func() (bool, error) {
+ if d.config.Debug {
+ data, _ := json.Marshal(change)
+ log.Printf("change (Get): %s", string(data))
+ }
- chg, err = d.client.Changes.Get(d.config.Project, zone, chgID).Do()
- if err != nil {
- data, _ := json.Marshal(change)
- return fmt.Errorf("failed to get changes [zone %s, change %s]: %w", zone, string(data), err)
- }
+ chg, err = d.client.Changes.Get(d.config.Project, zone, chgID).Do()
+ if err != nil {
+ data, _ := json.Marshal(change)
+ return false, fmt.Errorf("failed to get changes [zone %s, change %s]: %w", zone, string(data), err)
+ }
- if chg.Status != changeStatusDone {
- return fmt.Errorf("status: %s", chg.Status)
- }
+ if chg.Status == changeStatusDone {
+ return true, nil
+ }
- return nil
- },
- backoff.WithBackOff(backoff.NewConstantBackOff(3*time.Second)),
- backoff.WithMaxElapsedTime(30*time.Second),
- )
+ return false, fmt.Errorf("status: %s", chg.Status)
+ })
}
// CleanUp removes the TXT record matching the specified parameters.
@@ -321,11 +303,10 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return nil
}
- _, err = d.client.Changes.Create(d.config.Project, zone, &gdns.Change{Deletions: records}).Do()
+ _, err = d.client.Changes.Create(d.config.Project, zone, &dns.Change{Deletions: records}).Do()
if err != nil {
return fmt.Errorf("googlecloud: %w", err)
}
-
return nil
}
@@ -371,7 +352,7 @@ func (d *DNSProvider) getHostedZone(domain string) (string, error) {
// (gcloud projects get-iam-policy $project_id) (a role with permission dns.managedZones.list)
//
// If we force a zone list to succeed, we demand more permissions than needed.
-func (d *DNSProvider) lookupHostedZoneID(domain string) (string, []*gdns.ManagedZone, error) {
+func (d *DNSProvider) lookupHostedZoneID(domain string) (string, []*dns.ManagedZone, error) {
// GCE_ZONE_ID override for service accounts to avoid needing zones-list permission
if d.config.ZoneID != "" {
zone, err := d.client.ManagedZones.Get(d.config.Project, d.config.ZoneID).Do()
@@ -379,10 +360,10 @@ func (d *DNSProvider) lookupHostedZoneID(domain string) (string, []*gdns.Managed
return "", nil, fmt.Errorf("API call ManagedZones.Get for explicit zone ID %q in project %q failed: %w", d.config.ZoneID, d.config.Project, err)
}
- return zone.DnsName, []*gdns.ManagedZone{zone}, nil
+ return zone.DnsName, []*dns.ManagedZone{zone}, nil
}
- authZone, err := dns01.FindZoneByFqdn(dns.Fqdn(domain))
+ authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
if err != nil {
return "", nil, fmt.Errorf("could not find zone: %w", err)
}
@@ -398,7 +379,7 @@ func (d *DNSProvider) lookupHostedZoneID(domain string) (string, []*gdns.Managed
return authZone, zones.ManagedZones, nil
}
-func (d *DNSProvider) findTxtRecords(zone, fqdn string) ([]*gdns.ResourceRecordSet, error) {
+func (d *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSet, error) {
recs, err := d.client.ResourceRecordSets.List(d.config.Project, zone).Name(fqdn).Type("TXT").Do()
if err != nil {
return nil, err
@@ -417,7 +398,7 @@ func newClientFromCredentials(ctx context.Context, config *Config) (*http.Client
return newImpersonateClient(ctx, config.ImpersonateServiceAccount, ts)
}
- client, err := google.DefaultClient(ctx, gdns.NdevClouddnsReadwriteScope)
+ client, err := google.DefaultClient(ctx, dns.NdevClouddnsReadwriteScope)
if err != nil {
return nil, fmt.Errorf("unable to get Google Cloud client: %w", err)
}
@@ -435,7 +416,7 @@ func newClientFromServiceAccountKey(ctx context.Context, config *Config, saKey [
return newImpersonateClient(ctx, config.ImpersonateServiceAccount, conf.TokenSource(ctx))
}
- conf, err := google.JWTConfigFromJSON(saKey, gdns.NdevClouddnsReadwriteScope)
+ conf, err := google.JWTConfigFromJSON(saKey, dns.NdevClouddnsReadwriteScope)
if err != nil {
return nil, fmt.Errorf("unable to acquire config: %w", err)
}
@@ -446,7 +427,7 @@ func newClientFromServiceAccountKey(ctx context.Context, config *Config, saKey [
func newImpersonateClient(ctx context.Context, impersonateServiceAccount string, ts oauth2.TokenSource) (*http.Client, error) {
impersonatedTS, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
TargetPrincipal: impersonateServiceAccount,
- Scopes: []string{gdns.NdevClouddnsReadwriteScope},
+ Scopes: []string{dns.NdevClouddnsReadwriteScope},
}, option.WithTokenSource(ts))
if err != nil {
return nil, fmt.Errorf("unable to create impersonated credentials: %w", err)
@@ -460,7 +441,6 @@ func mustUnquote(raw string) string {
if err != nil {
return raw
}
-
return clean
}
diff --git a/providers/dns/gcloud/googlecloud_test.go b/providers/dns/gcloud/googlecloud_test.go
index 28b08a2f9..7fda2f8f6 100644
--- a/providers/dns/gcloud/googlecloud_test.go
+++ b/providers/dns/gcloud/googlecloud_test.go
@@ -52,7 +52,7 @@ func TestNewDNSProvider(t *testing.T) {
envServiceAccountFile: "",
// as Travis run on GCE, we have to alter env
envGoogleApplicationCredentials: "not-a-secret-file",
- envMetadataHost: "http://example.com", // defined here to avoid the client cache.
+ envMetadataHost: "http://lego.wtf", // defined here to avoid the client cache.
},
// the error message varies according to the OS used.
expected: "googlecloud: unable to get Google Cloud client: google: error getting credentials using GOOGLE_APPLICATION_CREDENTIALS environment variable: ",
@@ -63,7 +63,7 @@ func TestNewDNSProvider(t *testing.T) {
EnvProject: "",
envServiceAccountFile: "",
// as Travis run on GCE, we have to alter env
- envMetadataHost: "http://example.com",
+ envMetadataHost: "http://lego.wtf",
},
expected: "googlecloud: project name missing",
},
@@ -86,7 +86,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -126,7 +125,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
config := NewDefaultConfig()
@@ -156,7 +154,7 @@ func TestPresentNoExistingRR(t *testing.T) {
},
}),
servermock.CheckQueryParameter().Strict().
- With("dnsName", "example.com.").
+ With("dnsName", "lego.wtf.").
With("prettyPrint", "false").
With("alt", "json")).
// findTxtRecords
@@ -165,7 +163,7 @@ func TestPresentNoExistingRR(t *testing.T) {
Rrsets: []*dns.ResourceRecordSet{},
}),
servermock.CheckQueryParameter().Strict().
- With("name", "_acme-challenge.example.com.").
+ With("name", "_acme-challenge.lego.wtf.").
With("type", "TXT").
With("prettyPrint", "false").
With("alt", "json")).
@@ -191,7 +189,7 @@ func TestPresentNoExistingRR(t *testing.T) {
With("alt", "json")).
Build(t)
- domain := "example.com"
+ domain := "lego.wtf"
err := provider.Present(domain, "", "")
require.NoError(t, err)
@@ -207,21 +205,21 @@ func TestPresentWithExistingRR(t *testing.T) {
},
}),
servermock.CheckQueryParameter().Strict().
- With("dnsName", "example.com.").
+ With("dnsName", "lego.wtf.").
With("prettyPrint", "false").
With("alt", "json")).
// findTxtRecords
Route("GET /dns/v1/projects/manhattan/managedZones/test/rrsets",
servermock.JSONEncode(&dns.ResourceRecordSetsListResponse{
Rrsets: []*dns.ResourceRecordSet{{
- Name: "_acme-challenge.example.com.",
+ Name: "_acme-challenge.lego.wtf.",
Rrdatas: []string{`"X7DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"`, `"huji"`},
Ttl: 120,
Type: "TXT",
}},
}),
servermock.CheckQueryParameter().Strict().
- With("name", "_acme-challenge.example.com.").
+ With("name", "_acme-challenge.lego.wtf.").
With("type", "TXT").
With("prettyPrint", "false").
With("alt", "json")).
@@ -239,14 +237,12 @@ func TestPresentWithExistingRR(t *testing.T) {
}
var prevVal string
-
for _, addition := range chgReq.Additions {
for _, value := range addition.Rrdatas {
if prevVal == value {
http.Error(rw, fmt.Sprintf("The resource %s already exists", value), http.StatusConflict)
return
}
-
prevVal = value
}
}
@@ -264,7 +260,7 @@ func TestPresentWithExistingRR(t *testing.T) {
With("alt", "json")).
Build(t)
- domain := "example.com"
+ domain := "lego.wtf"
err := provider.Present(domain, "", "")
require.NoError(t, err)
@@ -280,27 +276,27 @@ func TestPresentSkipExistingRR(t *testing.T) {
},
}),
servermock.CheckQueryParameter().Strict().
- With("dnsName", "example.com.").
+ With("dnsName", "lego.wtf.").
With("prettyPrint", "false").
With("alt", "json")).
// findTxtRecords
Route("GET /dns/v1/projects/manhattan/managedZones/test/rrsets",
servermock.JSONEncode(&dns.ResourceRecordSetsListResponse{
Rrsets: []*dns.ResourceRecordSet{{
- Name: "_acme-challenge.example.com.",
+ Name: "_acme-challenge.lego.wtf.",
Rrdatas: []string{`"47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"`, `"X7DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"`, `"huji"`},
Ttl: 120,
Type: "TXT",
}},
}),
servermock.CheckQueryParameter().Strict().
- With("name", "_acme-challenge.example.com.").
+ With("name", "_acme-challenge.lego.wtf.").
With("type", "TXT").
With("prettyPrint", "false").
With("alt", "json")).
Build(t)
- domain := "example.com"
+ domain := "lego.wtf"
err := provider.Present(domain, "", "")
require.NoError(t, err)
@@ -356,7 +352,7 @@ func TestLiveCleanUp(t *testing.T) {
func mockBuilder() *servermock.Builder[*DNSProvider] {
return servermock.NewBuilder(func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
+ config.HTTPClient = &http.Client{Timeout: 10 * time.Second}
config.Project = "manhattan"
p, err := NewDNSProviderConfig(config)
diff --git a/providers/dns/gcore/gcore.go b/providers/dns/gcore/gcore.go
index 9b98f28d4..646c5ab1c 100644
--- a/providers/dns/gcore/gcore.go
+++ b/providers/dns/gcore/gcore.go
@@ -1,16 +1,17 @@
-// Package gcore implements a DNS provider for solving the DNS-01 challenge using G-Core.
package gcore
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "strings"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/gcore"
+ "github.com/go-acme/lego/v4/providers/dns/gcore/internal"
)
// Environment variables names.
@@ -25,17 +26,28 @@ const (
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
+const (
+ defaultPropagationTimeout = 360 * time.Second
+ defaultPollingInterval = 20 * time.Second
+)
+
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config for DNSProvider.
-type Config = gcore.Config
+type Config struct {
+ APIToken string
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, gcore.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, gcore.DefaultPollingInterval),
+ PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, defaultPropagationTimeout),
+ PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, defaultPollingInterval),
HTTPClient: &http.Client{
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 10*time.Second),
},
@@ -44,7 +56,8 @@ func NewDefaultConfig() *Config {
// DNSProvider an implementation of challenge.Provider contract.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *internal.Client
}
// NewDNSProvider returns an instance of DNSProvider configured for G-Core DNS API.
@@ -66,36 +79,91 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("gcore: the configuration of the DNS provider is nil")
}
- provider, err := gcore.NewDNSProviderConfig(config, "")
- if err != nil {
- return nil, fmt.Errorf("gcore: %w", err)
+ if config.APIToken == "" {
+ return nil, errors.New("gcore: incomplete credentials provided")
}
- return &DNSProvider{prv: provider}, nil
+ client := internal.NewClient(config.APIToken)
+
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{
+ config: config,
+ client: client,
+ }, nil
}
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+// Present creates a TXT record to fulfill the dns-01 challenge.
+func (d *DNSProvider) Present(domain, _, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ ctx := context.Background()
+
+ zone, err := d.guessZone(ctx, info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("gcore: %w", err)
}
+ err = d.client.AddRRSet(ctx, zone, dns01.UnFqdn(info.EffectiveFQDN), info.Value, d.config.TTL)
+ if err != nil {
+ return fmt.Errorf("gcore: add txt record: %w", err)
+ }
+
return nil
}
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+// CleanUp removes the record matching the specified parameters.
+func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ ctx := context.Background()
+
+ zone, err := d.guessZone(ctx, info.EffectiveFQDN)
if err != nil {
return fmt.Errorf("gcore: %w", err)
}
+ err = d.client.DeleteRRSet(ctx, zone, dns01.UnFqdn(info.EffectiveFQDN))
+ if err != nil {
+ return fmt.Errorf("gcore: remove txt record: %w", err)
+ }
+
return nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+ return d.config.PropagationTimeout, d.config.PollingInterval
+}
+
+func (d *DNSProvider) guessZone(ctx context.Context, fqdn string) (string, error) {
+ var lastErr error
+
+ for _, zone := range extractAllZones(fqdn) {
+ dnsZone, err := d.client.GetZone(ctx, zone)
+ if err == nil {
+ return dnsZone.Name, nil
+ }
+
+ lastErr = err
+ }
+
+ return "", fmt.Errorf("zone %q not found: %w", fqdn, lastErr)
+}
+
+func extractAllZones(fqdn string) []string {
+ parts := strings.Split(dns01.UnFqdn(fqdn), ".")
+ if len(parts) < 3 {
+ return nil
+ }
+
+ var zones []string
+ for i := 1; i < len(parts)-1; i++ {
+ zones = append(zones, strings.Join(parts[i:], "."))
+ }
+
+ return zones
}
diff --git a/providers/dns/gcore/gcore.toml b/providers/dns/gcore/gcore.toml
index 983c35f8a..986455e80 100644
--- a/providers/dns/gcore/gcore.toml
+++ b/providers/dns/gcore/gcore.toml
@@ -6,7 +6,7 @@ Since = "v4.5.0"
Example = '''
GCORE_PERMANENT_API_TOKEN=xxxxx \
-lego --dns gcore -d '*.example.com' -d example.com run
+lego --email you@example.com --dns gcore -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/gcore/gcore_test.go b/providers/dns/gcore/gcore_test.go
index 6f8e38c12..a5eddee7c 100644
--- a/providers/dns/gcore/gcore_test.go
+++ b/providers/dns/gcore/gcore_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/go-acme/lego/v4/platform/tester"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -33,7 +34,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -43,7 +43,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -77,7 +78,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -91,7 +93,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -105,10 +106,36 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
require.NoError(t, err)
}
+
+func Test_extractAllZones(t *testing.T) {
+ testCases := []struct {
+ desc string
+ fqdn string
+ expected []string
+ }{
+ {
+ desc: "success",
+ fqdn: "_acme-challenge.my.test.domain.com.",
+ expected: []string{"my.test.domain.com", "test.domain.com", "domain.com"},
+ },
+ {
+ desc: "empty",
+ fqdn: "_acme-challenge.com.",
+ },
+ }
+
+ for _, test := range testCases {
+ t.Run(test.desc, func(t *testing.T) {
+ t.Parallel()
+
+ got := extractAllZones(test.fqdn)
+ assert.Equal(t, test.expected, got)
+ })
+ }
+}
diff --git a/providers/dns/internal/gcore/internal/client.go b/providers/dns/gcore/internal/client.go
similarity index 92%
rename from providers/dns/internal/gcore/internal/client.go
rename to providers/dns/gcore/internal/client.go
index f3ad4e461..b76da4388 100644
--- a/providers/dns/internal/gcore/internal/client.go
+++ b/providers/dns/gcore/internal/client.go
@@ -27,7 +27,7 @@ const txtRecordType = "TXT"
type Client struct {
token string
- BaseURL *url.URL
+ baseURL *url.URL
HTTPClient *http.Client
}
@@ -37,7 +37,7 @@ func NewClient(token string) *Client {
return &Client{
token: token,
- BaseURL: baseURL,
+ baseURL: baseURL,
HTTPClient: &http.Client{Timeout: 10 * time.Second},
}
}
@@ -45,10 +45,9 @@ func NewClient(token string) *Client {
// GetZone gets zone information.
// https://api.gcore.com/docs/dns#tag/zones/operation/Zone
func (c *Client) GetZone(ctx context.Context, name string) (Zone, error) {
- endpoint := c.BaseURL.JoinPath("v2", "zones", name)
+ endpoint := c.baseURL.JoinPath("v2", "zones", name)
zone := Zone{}
-
err := c.doRequest(ctx, http.MethodGet, endpoint, nil, &zone)
if err != nil {
return Zone{}, fmt.Errorf("get zone %s: %w", name, err)
@@ -60,10 +59,9 @@ func (c *Client) GetZone(ctx context.Context, name string) (Zone, error) {
// GetRRSet gets RRSet item.
// https://api.gcore.com/docs/dns#tag/rrsets/operation/RRSet
func (c *Client) GetRRSet(ctx context.Context, zone, name string) (RRSet, error) {
- endpoint := c.BaseURL.JoinPath("v2", "zones", zone, name, txtRecordType)
+ endpoint := c.baseURL.JoinPath("v2", "zones", zone, name, txtRecordType)
var result RRSet
-
err := c.doRequest(ctx, http.MethodGet, endpoint, nil, &result)
if err != nil {
return RRSet{}, fmt.Errorf("get txt records %s -> %s: %w", zone, name, err)
@@ -75,7 +73,7 @@ func (c *Client) GetRRSet(ctx context.Context, zone, name string) (RRSet, error)
// DeleteRRSet removes RRSet record.
// https://api.gcore.com/docs/dns#tag/rrsets/operation/DeleteRRSet
func (c *Client) DeleteRRSet(ctx context.Context, zone, name string) error {
- endpoint := c.BaseURL.JoinPath("v2", "zones", zone, name, txtRecordType)
+ endpoint := c.baseURL.JoinPath("v2", "zones", zone, name, txtRecordType)
err := c.doRequest(ctx, http.MethodDelete, endpoint, nil, nil)
if err != nil {
@@ -106,14 +104,14 @@ func (c *Client) AddRRSet(ctx context.Context, zone, recordName, value string, t
// https://api.gcore.com/docs/dns#tag/rrsets/operation/CreateRRSet
func (c *Client) createRRSet(ctx context.Context, zone, name string, record RRSet) error {
- endpoint := c.BaseURL.JoinPath("v2", "zones", zone, name, txtRecordType)
+ endpoint := c.baseURL.JoinPath("v2", "zones", zone, name, txtRecordType)
return c.doRequest(ctx, http.MethodPost, endpoint, record, nil)
}
// https://api.gcore.com/docs/dns#tag/rrsets/operation/UpdateRRSet
func (c *Client) updateRRSet(ctx context.Context, zone, name string, record RRSet) error {
- endpoint := c.BaseURL.JoinPath("v2", "zones", zone, name, txtRecordType)
+ endpoint := c.baseURL.JoinPath("v2", "zones", zone, name, txtRecordType)
return c.doRequest(ctx, http.MethodPut, endpoint, record, nil)
}
@@ -182,7 +180,6 @@ func parseError(resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errAPI := APIError{StatusCode: resp.StatusCode}
-
err := json.Unmarshal(raw, &errAPI)
if err != nil {
errAPI.Message = string(raw)
diff --git a/providers/dns/internal/gcore/internal/client_test.go b/providers/dns/gcore/internal/client_test.go
similarity index 99%
rename from providers/dns/internal/gcore/internal/client_test.go
rename to providers/dns/gcore/internal/client_test.go
index 7d70c9308..4a0f83311 100644
--- a/providers/dns/internal/gcore/internal/client_test.go
+++ b/providers/dns/gcore/internal/client_test.go
@@ -21,7 +21,7 @@ func mockBuilder() *servermock.Builder[*Client] {
return servermock.NewBuilder[*Client](
func(server *httptest.Server) (*Client, error) {
client := NewClient(testToken)
- client.BaseURL, _ = url.Parse(server.URL)
+ client.baseURL, _ = url.Parse(server.URL)
client.HTTPClient = server.Client()
return client, nil
diff --git a/providers/dns/internal/gcore/internal/types.go b/providers/dns/gcore/internal/types.go
similarity index 100%
rename from providers/dns/internal/gcore/internal/types.go
rename to providers/dns/gcore/internal/types.go
diff --git a/providers/dns/gigahostno/gigahostno.go b/providers/dns/gigahostno/gigahostno.go
deleted file mode 100644
index b9ed23f3f..000000000
--- a/providers/dns/gigahostno/gigahostno.go
+++ /dev/null
@@ -1,233 +0,0 @@
-// Package gigahostno implements a DNS provider for solving the DNS-01 challenge using Gigahost.no.
-package gigahostno
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/gigahostno/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "GIGAHOSTNO_"
-
- EnvUsername = envNamespace + "USERNAME"
- EnvPassword = envNamespace + "PASSWORD"
- EnvSecret = envNamespace + "SECRET"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Username string
- Password string
- Secret string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
-
- identifier *internal.Identifier
- client *internal.Client
-
- tokenMu sync.Mutex
- token *internal.Token
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Gigahost.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvUsername, EnvPassword)
- if err != nil {
- return nil, fmt.Errorf("gigahostno: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Username = values[EnvUsername]
- config.Password = values[EnvPassword]
- config.Secret = env.GetOrFile(EnvSecret)
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Gigahost.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("gigahostno: the configuration of the DNS provider is nil")
- }
-
- identifier, err := internal.NewIdentifier(config.Username, config.Password, config.Secret)
- if err != nil {
- return nil, fmt.Errorf("gigahostno: %w", err)
- }
-
- if config.HTTPClient != nil {
- identifier.HTTPClient = config.HTTPClient
- }
-
- identifier.HTTPClient = clientdebug.Wrap(identifier.HTTPClient)
-
- client := internal.NewClient()
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- identifier: identifier,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- err := d.authenticate(ctx)
- if err != nil {
- return fmt.Errorf("gigahostno: %w", err)
- }
-
- ctx = internal.WithContext(ctx, d.token.Token)
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("gigahostno: %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.Name)
- if err != nil {
- return fmt.Errorf("gigahostno: %w", err)
- }
-
- record := internal.Record{
- Name: subDomain,
- Type: "TXT",
- Value: info.Value,
- TTL: d.config.TTL,
- }
-
- err = d.client.CreateNewRecord(ctx, zone.ID, record)
- if err != nil {
- return fmt.Errorf("gigahostno: create new record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- err := d.authenticate(ctx)
- if err != nil {
- return fmt.Errorf("gigahostno: %w", err)
- }
-
- ctx = internal.WithContext(ctx, d.token.Token)
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("gigahostno: %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.Name)
- if err != nil {
- return fmt.Errorf("gigahostno: %w", err)
- }
-
- records, err := d.client.GetZoneRecords(ctx, zone.ID)
- if err != nil {
- return fmt.Errorf("gigahostno: get zone records: %w", err)
- }
-
- for _, record := range records {
- if record.Type == "TXT" && record.Name == subDomain && record.Value == info.Value {
- err := d.client.DeleteRecord(ctx, zone.ID, record.ID, record.Name, record.Type)
- if err != nil {
- return fmt.Errorf("gigahostno: delete record: %w", err)
- }
-
- break
- }
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) authenticate(ctx context.Context) error {
- d.tokenMu.Lock()
- defer d.tokenMu.Unlock()
-
- if !d.token.IsExpired() {
- return nil
- }
-
- tok, err := d.identifier.Authenticate(ctx)
- if err != nil {
- return fmt.Errorf("authenticate: %w", err)
- }
-
- d.token = tok
-
- return nil
-}
-
-func (d *DNSProvider) findZone(ctx context.Context, fqdn string) (*internal.Zone, error) {
- zones, err := d.client.GetZones(ctx)
- if err != nil {
- return nil, fmt.Errorf("get zones: %w", err)
- }
-
- for d := range dns01.UnFqdnDomainsSeq(fqdn) {
- for _, zone := range zones {
- if zone.Name == d && zone.Active == "1" {
- return &zone, nil
- }
- }
- }
-
- return nil, fmt.Errorf("zone not found for %q", fqdn)
-}
diff --git a/providers/dns/gigahostno/gigahostno.toml b/providers/dns/gigahostno/gigahostno.toml
deleted file mode 100644
index b8d3fad2b..000000000
--- a/providers/dns/gigahostno/gigahostno.toml
+++ /dev/null
@@ -1,25 +0,0 @@
-Name = "Gigahost.no"
-Description = ''''''
-URL = "https://gigahost.no/"
-Code = "gigahostno"
-Since = "v4.29.0"
-
-Example = '''
-GIGAHOSTNO_USERNAME="xxxxxxxxxxxxxxxxxxxxx" \
-GIGAHOSTNO_PASSWORD="yyyyyyyyyyyyyyyyyyyyy" \
-lego --dns gigahostno -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- GIGAHOSTNO_USERNAME = "Username"
- GIGAHOSTNO_PASSWORD = "Password"
- [Configuration.Additional]
- GIGAHOSTNO_SECRET = "TOTP secret"
- GIGAHOSTNO_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- GIGAHOSTNO_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- GIGAHOSTNO_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- GIGAHOSTNO_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://gigahost.no/api-dokumentasjon"
diff --git a/providers/dns/gigahostno/gigahostno_test.go b/providers/dns/gigahostno/gigahostno_test.go
deleted file mode 100644
index 7aaac0159..000000000
--- a/providers/dns/gigahostno/gigahostno_test.go
+++ /dev/null
@@ -1,277 +0,0 @@
-package gigahostno
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/gigahostno/internal"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvUsername,
- EnvPassword,
- EnvSecret,
-).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvUsername: "user",
- EnvPassword: "secret",
- EnvSecret: "super-secret",
- },
- },
- {
- desc: "missing GIGAHOSTNO_USERNAME",
- envVars: map[string]string{
- EnvPassword: "secret",
- },
- expected: "gigahostno: some credentials information are missing: GIGAHOSTNO_USERNAME",
- },
- {
- desc: "missing GIGAHOSTNO_PASSWORD",
- envVars: map[string]string{
- EnvUsername: "user",
- },
- expected: "gigahostno: some credentials information are missing: GIGAHOSTNO_PASSWORD",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "gigahostno: some credentials information are missing: GIGAHOSTNO_USERNAME,GIGAHOSTNO_PASSWORD",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- username string
- password string
- secret string
- expected string
- }{
- {
- desc: "success",
- username: "user",
- password: "secret",
- secret: "super-secret",
- },
- {
- desc: "missing username",
- password: "secret",
- expected: "gigahostno: credentials missing",
- },
- {
- desc: "missing password",
- username: "user",
- expected: "gigahostno: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "gigahostno: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Username = test.username
- config.Password = test.password
- config.Secret = test.secret
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.Username = "user"
- config.Password = "secret"
- config.Secret = "JBSWY3DPEHPK3PXP"
-
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
- p.identifier.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /authenticate",
- servermock.ResponseFromInternal("authenticate.json")).
- Route("GET /dns/zones",
- servermock.ResponseFromInternal("zones.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secrettoken")).
- Route("POST /dns/zones/123/records",
- servermock.ResponseFromInternal("create_record.json"),
- servermock.CheckRequestJSONBodyFromInternal("create_record-request.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secrettoken")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_Present_token_not_expired(t *testing.T) {
- provider := mockBuilder().
- Route("GET /dns/zones",
- servermock.ResponseFromInternal("zones.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secret-token")).
- Route("POST /dns/zones/123/records",
- servermock.ResponseFromInternal("create_record.json"),
- servermock.CheckRequestJSONBodyFromInternal("create_record-request.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secret-token")).
- Build(t)
-
- provider.token = &internal.Token{
- Token: "secret-token",
- TokenExpire: 65322892800, // 2040-01-01
- CustomerID: "123",
- }
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("POST /authenticate",
- servermock.ResponseFromInternal("authenticate.json")).
- Route("GET /dns/zones",
- servermock.ResponseFromInternal("zones.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secrettoken")).
- Route("GET /dns/zones/123/records",
- servermock.ResponseFromInternal("zone_records.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secrettoken")).
- Route("DELETE /dns/zones/123/records/jkl012",
- servermock.ResponseFromInternal("delete_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("name", "_acme-challenge").
- With("type", "TXT"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secrettoken")).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp_token_not_expired(t *testing.T) {
- provider := mockBuilder().
- Route("GET /dns/zones",
- servermock.ResponseFromInternal("zones.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secret-token")).
- Route("GET /dns/zones/123/records",
- servermock.ResponseFromInternal("zone_records.json"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secret-token")).
- Route("DELETE /dns/zones/123/records/jkl012",
- servermock.ResponseFromInternal("delete_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("name", "_acme-challenge").
- With("type", "TXT"),
- servermock.CheckHeader().
- WithAuthorization("Bearer secret-token")).
- Build(t)
-
- provider.token = &internal.Token{
- Token: "secret-token",
- TokenExpire: 65322892800, // 2040-01-01
- CustomerID: "123",
- }
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/gigahostno/internal/client.go b/providers/dns/gigahostno/internal/client.go
deleted file mode 100644
index cfff3a7b8..000000000
--- a/providers/dns/gigahostno/internal/client.go
+++ /dev/null
@@ -1,172 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://api.gigahost.no/api/v0"
-
-const authorizationHeader = "Authorization"
-
-// Client the Gigahost.no API client.
-type Client struct {
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient() *Client {
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }
-}
-
-// GetZones returns all zones.
-func (c *Client) GetZones(ctx context.Context) ([]Zone, error) {
- endpoint := c.BaseURL.JoinPath("dns", "zones")
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result APIResponse[[]Zone]
-
- err = c.do(ctx, req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Data, nil
-}
-
-// GetZoneRecords returns all records for a zone.
-func (c *Client) GetZoneRecords(ctx context.Context, zoneID string) ([]Record, error) {
- endpoint := c.BaseURL.JoinPath("dns", "zones", zoneID, "records")
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result APIResponse[[]Record]
-
- err = c.do(ctx, req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Data, nil
-}
-
-// CreateNewRecord creates a new record.
-func (c *Client) CreateNewRecord(ctx context.Context, zoneID string, record Record) error {
- endpoint := c.BaseURL.JoinPath("dns", "zones", zoneID, "records")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
- if err != nil {
- return err
- }
-
- return c.do(ctx, req, nil)
-}
-
-// DeleteRecord deletes a record.
-func (c *Client) DeleteRecord(ctx context.Context, zoneID, recordID, name, recordType string) error {
- endpoint := c.BaseURL.JoinPath("dns", "zones", zoneID, "records", recordID)
-
- query := endpoint.Query()
- query.Set("name", name)
- query.Set("type", recordType)
- endpoint.RawQuery = query.Encode()
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.do(ctx, req, nil)
-}
-
-func (c *Client) do(ctx context.Context, req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Set(authorizationHeader, "Bearer "+getToken(ctx))
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
diff --git a/providers/dns/gigahostno/internal/client_test.go b/providers/dns/gigahostno/internal/client_test.go
deleted file mode 100644
index 8d1298947..000000000
--- a/providers/dns/gigahostno/internal/client_test.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client := NewClient()
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- WithAuthorization("Bearer secret"),
- )
-}
-
-func TestClient_GetZones(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/zones",
- servermock.ResponseFromFixture("zones.json")).
- Build(t)
-
- zones, err := client.GetZones(mockContext(t))
- require.NoError(t, err)
-
- expected := []Zone{
- {
- ID: "123",
- Name: "example.com",
- NameDisplay: "example.com",
- Type: "NATIVE",
- Active: "1",
- },
- {
- ID: "226",
- Name: "example.org",
- NameDisplay: "example.org",
- Type: "NATIVE",
- Active: "1",
- },
- {
- ID: "229",
- Name: "example.xn--zckzah",
- NameDisplay: "example.テスト",
- Type: "NATIVE",
- Active: "1",
- },
- }
-
- assert.Equal(t, expected, zones)
-}
-
-func TestClient_GetZones_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/zones",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- _, err := client.GetZones(mockContext(t))
- require.EqualError(t, err, "401: 401 Unauthorized: 401 Unauthorized")
-}
-
-func TestClient_GetZoneRecords(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/zones/123/records",
- servermock.ResponseFromFixture("zone_records.json")).
- Build(t)
-
- zones, err := client.GetZoneRecords(mockContext(t), "123")
- require.NoError(t, err)
-
- expected := []Record{
- {
- ID: "abc123",
- Name: "@",
- Type: "A",
- Value: "185.125.168.166",
- TTL: 3600,
- },
- {
- ID: "def456",
- Name: "www",
- Type: "A",
- Value: "185.125.168.166",
- TTL: 3600,
- },
- {
- ID: "ghi789",
- Name: "@",
- Type: "MX",
- Value: "mail.example.no",
- TTL: 3600,
- },
- {
- ID: "jkl012",
- Name: "_acme-challenge",
- Type: "TXT",
- Value: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- },
- }
-
- assert.Equal(t, expected, zones)
-}
-
-func TestClient_CreateNewRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/zones/example.com/records",
- servermock.ResponseFromFixture("create_record.json"),
- servermock.CheckRequestJSONBodyFromFixture("create_record-request.json")).
- Build(t)
-
- record := Record{
- Name: "_acme-challenge",
- Type: "TXT",
- Value: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- }
-
- err := client.CreateNewRecord(mockContext(t), "example.com", record)
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("/dns/zones/123/records/abc123",
- servermock.ResponseFromFixture("delete_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("name", "_acme-challenge").
- With("type", "TXT")).
- Build(t)
-
- err := client.DeleteRecord(mockContext(t), "123", "abc123", "_acme-challenge", "TXT")
- require.NoError(t, err)
-}
diff --git a/providers/dns/gigahostno/internal/fixtures/authenticate-request.json b/providers/dns/gigahostno/internal/fixtures/authenticate-request.json
deleted file mode 100644
index c641cd3e5..000000000
--- a/providers/dns/gigahostno/internal/fixtures/authenticate-request.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "username": "user",
- "password": "secret"
-}
diff --git a/providers/dns/gigahostno/internal/fixtures/authenticate.json b/providers/dns/gigahostno/internal/fixtures/authenticate.json
deleted file mode 100644
index 2c43ccbfe..000000000
--- a/providers/dns/gigahostno/internal/fixtures/authenticate.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "meta": {
- "status": 200,
- "status_message": "200 OK",
- "maintenance": false
- },
- "data": {
- "token": "secrettoken",
- "token_expire": 1577836800,
- "customer_id": "16030",
- "contact_id": "15182",
- "customer_name": "Cloudline AS",
- "contact_username": "test@example.com",
- "contact_access_level": "admin",
- "customer_address": "Grønland 14",
- "customer_zipcode": "5918",
- "customer_city": "Frekhaug",
- "customer_province": "Vestland",
- "ga_secret": "ga_secret",
- "ga_enabled": "1",
- "vat": 1
- }
-}
diff --git a/providers/dns/gigahostno/internal/fixtures/create_record-request.json b/providers/dns/gigahostno/internal/fixtures/create_record-request.json
deleted file mode 100644
index f8f0b5b11..000000000
--- a/providers/dns/gigahostno/internal/fixtures/create_record-request.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "record_name": "_acme-challenge",
- "record_type": "TXT",
- "record_value": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "record_ttl": 120
-}
diff --git a/providers/dns/gigahostno/internal/fixtures/create_record.json b/providers/dns/gigahostno/internal/fixtures/create_record.json
deleted file mode 100644
index 9232677d7..000000000
--- a/providers/dns/gigahostno/internal/fixtures/create_record.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "meta": {
- "status": 201,
- "status_message": "201 Created",
- "message": "Record created successfully."
- }
-}
diff --git a/providers/dns/gigahostno/internal/fixtures/delete_record.json b/providers/dns/gigahostno/internal/fixtures/delete_record.json
deleted file mode 100644
index 9d87f2f42..000000000
--- a/providers/dns/gigahostno/internal/fixtures/delete_record.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "meta": {
- "status": 200,
- "status_message": "200 OK",
- "message": "Record deleted successfully."
- }
-}
diff --git a/providers/dns/gigahostno/internal/fixtures/error.json b/providers/dns/gigahostno/internal/fixtures/error.json
deleted file mode 100644
index f2fcfd437..000000000
--- a/providers/dns/gigahostno/internal/fixtures/error.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "meta": {
- "status": 401,
- "status_message": "401 Unauthorized",
- "maintenance": false,
- "message": "401 Unauthorized"
- },
- "data": []
-}
diff --git a/providers/dns/gigahostno/internal/fixtures/zone_records.json b/providers/dns/gigahostno/internal/fixtures/zone_records.json
deleted file mode 100644
index e67ff83f4..000000000
--- a/providers/dns/gigahostno/internal/fixtures/zone_records.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "meta": {
- "status": 200,
- "status_message": "200 OK"
- },
- "data": [
- {
- "record_id": "abc123",
- "record_name": "@",
- "record_type": "A",
- "record_value": "185.125.168.166",
- "record_ttl": 3600,
- "record_priority": null
- },
- {
- "record_id": "def456",
- "record_name": "www",
- "record_type": "A",
- "record_value": "185.125.168.166",
- "record_ttl": 3600,
- "record_priority": null
- },
- {
- "record_id": "ghi789",
- "record_name": "@",
- "record_type": "MX",
- "record_value": "mail.example.no",
- "record_ttl": 3600,
- "record_priority": 10
- },
- {
- "record_id": "jkl012",
- "record_name": "_acme-challenge",
- "record_type": "TXT",
- "record_value": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "record_ttl": 120
- }
- ]
-}
diff --git a/providers/dns/gigahostno/internal/fixtures/zones.json b/providers/dns/gigahostno/internal/fixtures/zones.json
deleted file mode 100644
index d45b0ac49..000000000
--- a/providers/dns/gigahostno/internal/fixtures/zones.json
+++ /dev/null
@@ -1,97 +0,0 @@
-{
- "meta": {
- "status": 200,
- "status_message": "200 OK",
- "maintenance": false,
- "message": "200 OK"
- },
- "data": [
- {
- "zone_id": "123",
- "cust_id": "16030",
- "order_id": "26117",
- "zone_name": "example.com",
- "zone_type": "NATIVE",
- "zone_active": "1",
- "zone_protected": "1",
- "zone_is_registered": "1",
- "domain_registrar": "norid",
- "domain_status": "active",
- "domain_registered_date": "2025-11-23 15:17:38",
- "domain_expiry_date": "2026-11-23 15:17:38",
- "domain_updated_date": "2025-11-23 16:17:38",
- "domain_auto_renew": "1",
- "domain_epp_id": "LEG2175D-NORID",
- "domain_registrant_id": "CA19777O",
- "domain_tech_id": "GH295R",
- "domain_auth_info": "XXXXXXXXXXXXXXX",
- "domain_locked": "0",
- "domain_dnssec": "0",
- "domain_dnssec_data": null,
- "domain_protected_email": null,
- "zone_created": "2025-11-23 16:17:29",
- "zone_updated": 1700000000,
- "external_dns": "0",
- "record_count": 4,
- "zone_name_display": "example.com"
- },
- {
- "zone_id": "226",
- "cust_id": "16030",
- "order_id": "26114",
- "zone_name": "example.org",
- "zone_type": "NATIVE",
- "zone_active": "1",
- "zone_protected": "1",
- "zone_is_registered": "1",
- "domain_registrar": "norid",
- "domain_status": "active",
- "domain_registered_date": "2025-11-23 14:15:01",
- "domain_expiry_date": "2026-11-23 14:15:01",
- "domain_updated_date": "2025-11-23 15:15:02",
- "domain_auto_renew": "1",
- "domain_epp_id": "TEO218D-NORID",
- "domain_registrant_id": "CA19774O",
- "domain_tech_id": "GH295R",
- "domain_auth_info": "XXXXXXXXXXXXXX",
- "domain_locked": "0",
- "domain_dnssec": "0",
- "domain_dnssec_data": null,
- "domain_protected_email": null,
- "zone_created": "2025-11-23 15:13:27",
- "zone_updated": 1700000000,
- "external_dns": "0",
- "record_count": 5,
- "zone_name_display": "example.org"
- },
- {
- "zone_id": "229",
- "cust_id": "16030",
- "order_id": "26119",
- "zone_name": "example.xn--zckzah",
- "zone_type": "NATIVE",
- "zone_active": "1",
- "zone_protected": "1",
- "zone_is_registered": "1",
- "domain_registrar": "norid",
- "domain_status": "active",
- "domain_registered_date": "2014-12-01 12:40:48",
- "domain_expiry_date": "2026-12-01 12:40:48",
- "domain_updated_date": "2025-11-23 15:37:36",
- "domain_auto_renew": "1",
- "domain_epp_id": "DIT1003D-NORID",
- "domain_registrant_id": "DCA822O",
- "domain_tech_id": "GH295R",
- "domain_auth_info": "XXXXXXXXXXXXXX",
- "domain_locked": "0",
- "domain_dnssec": "0",
- "domain_dnssec_data": null,
- "domain_protected_email": null,
- "zone_created": "2025-11-23 16:37:15",
- "zone_updated": 1700000000,
- "external_dns": "0",
- "record_count": 4,
- "zone_name_display": "example.\u30C6\u30B9\u30C8"
- }
- ]
-}
diff --git a/providers/dns/gigahostno/internal/identity.go b/providers/dns/gigahostno/internal/identity.go
deleted file mode 100644
index 262dfabdd..000000000
--- a/providers/dns/gigahostno/internal/identity.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package internal
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
- "github.com/pquerna/otp/totp"
-)
-
-type token string
-
-const tokenKey token = "token"
-
-type Identifier struct {
- username string
- password string
- Secret string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-func NewIdentifier(username, password, secret string) (*Identifier, error) {
- if username == "" || password == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Identifier{
- username: username,
- password: password,
- Secret: secret,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Identifier) Authenticate(ctx context.Context) (*Token, error) {
- endpoint := c.BaseURL.JoinPath("authenticate")
-
- auth := Auth{Username: c.username, Password: c.password}
-
- if c.Secret != "" {
- tan, err := totp.GenerateCode(c.Secret, time.Now())
- if err != nil {
- return nil, fmt.Errorf("generate TOTP: %w", err)
- }
-
- auth.Code, err = strconv.Atoi(tan)
- if err != nil {
- return nil, fmt.Errorf("parse TOTP: %w", err)
- }
- }
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, auth)
- if err != nil {
- return nil, err
- }
-
- var result APIResponse[*Token]
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Data, nil
-}
-
-func (c *Identifier) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func WithContext(ctx context.Context, credential string) context.Context {
- return context.WithValue(ctx, tokenKey, credential)
-}
-
-func getToken(ctx context.Context) string {
- credential, ok := ctx.Value(tokenKey).(string)
- if !ok {
- return ""
- }
-
- return credential
-}
diff --git a/providers/dns/gigahostno/internal/identity_test.go b/providers/dns/gigahostno/internal/identity_test.go
deleted file mode 100644
index 09d72746a..000000000
--- a/providers/dns/gigahostno/internal/identity_test.go
+++ /dev/null
@@ -1,108 +0,0 @@
-package internal
-
-import (
- "context"
- "net/http/httptest"
- "net/url"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func setupIdentifierClient(server *httptest.Server) (*Identifier, error) {
- client, err := NewIdentifier("user", "secret", "")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
-}
-
-func mockContext(t *testing.T) context.Context {
- t.Helper()
-
- return context.WithValue(t.Context(), tokenKey, "secret")
-}
-
-func TestIdentifier_Authenticate(t *testing.T) {
- identifier := servermock.NewBuilder[*Identifier](setupIdentifierClient).
- Route("POST /authenticate",
- servermock.ResponseFromFixture("authenticate.json"),
- servermock.CheckRequestJSONBodyFromFixture("authenticate-request.json")).
- Build(t)
-
- token, err := identifier.Authenticate(context.Background())
- require.NoError(t, err)
-
- expected := &Token{
- Token: "secrettoken",
- TokenExpire: 1577836800,
- CustomerID: "16030",
- ContactID: "15182",
- CustomerName: "Cloudline AS",
- ContactUsername: "test@example.com",
- ContactAccessLevel: "admin",
- CustomerAddress: "Grønland 14",
- CustomerZipcode: "5918",
- CustomerCity: "Frekhaug",
- CustomerProvince: "Vestland",
- GASecret: "ga_secret",
- GAEnabled: "1",
- VAT: 1,
- }
-
- assert.Equal(t, expected, token)
-}
-
-func TestToken_IsExpired(t *testing.T) {
- testCases := []struct {
- desc string
- token *Token
- assert assert.BoolAssertionFunc
- }{
- {
- desc: "nil",
- assert: assert.True,
- },
- {
- desc: "empty",
- token: &Token{},
- assert: assert.True,
- },
- {
- desc: "not expired",
- token: &Token{
- TokenExpire: 65322892800, // 2040-01-01
- },
- assert: assert.False,
- },
- {
- desc: "now",
- token: &Token{
- TokenExpire: time.Now().Unix(),
- },
- assert: assert.True,
- },
- {
- desc: "now + 2 minutes",
- token: &Token{
- TokenExpire: time.Now().Add(2 * time.Minute).Unix(),
- },
- assert: assert.False,
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- test.assert(t, test.token.IsExpired())
- })
- }
-}
diff --git a/providers/dns/gigahostno/internal/types.go b/providers/dns/gigahostno/internal/types.go
deleted file mode 100644
index e998dc084..000000000
--- a/providers/dns/gigahostno/internal/types.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package internal
-
-import (
- "fmt"
- "time"
-)
-
-type APIError struct {
- Meta MetaData `json:"meta"`
-}
-
-func (a *APIError) Error() string {
- return fmt.Sprintf("%d: %s: %s", a.Meta.Status, a.Meta.StatusMessage, a.Meta.Message)
-}
-
-type MetaData struct {
- Status int `json:"status,omitempty"`
- StatusMessage string `json:"status_message,omitempty"`
- Maintenance bool `json:"maintenance"`
- Message string `json:"message,omitempty"`
-}
-
-type APIResponse[T any] struct {
- Meta MetaData `json:"meta"`
- Data T `json:"data,omitempty"`
-}
-
-type Zone struct {
- ID string `json:"zone_id,omitempty"`
- Name string `json:"zone_name,omitempty"`
- NameDisplay string `json:"zone_name_display,omitempty"`
- Type string `json:"zone_type,omitempty"`
- Active string `json:"zone_active,omitempty"`
-}
-
-type Record struct {
- ID string `json:"record_id,omitempty"`
- Name string `json:"record_name,omitempty"`
- Type string `json:"record_type,omitempty"`
- Value string `json:"record_value,omitempty"`
- TTL int `json:"record_ttl,omitempty"`
-}
-
-type Auth struct {
- Username string `json:"username"`
- Password string `json:"password"`
- Code int `json:"code,omitempty"`
-}
-
-type Token struct {
- Token string `json:"token,omitempty"`
- TokenExpire int64 `json:"token_expire,omitempty"`
- CustomerID string `json:"customer_id,omitempty"`
- ContactID string `json:"contact_id,omitempty"`
- CustomerName string `json:"customer_name,omitempty"`
- ContactUsername string `json:"contact_username,omitempty"`
- ContactAccessLevel string `json:"contact_access_level,omitempty"`
- CustomerAddress string `json:"customer_address,omitempty"`
- CustomerZipcode string `json:"customer_zipcode,omitempty"`
- CustomerCity string `json:"customer_city,omitempty"`
- CustomerProvince string `json:"customer_province,omitempty"`
- GASecret string `json:"ga_secret,omitempty"`
- GAEnabled string `json:"ga_enabled,omitempty"`
- VAT int `json:"vat,omitempty"`
-}
-
-func (t *Token) IsExpired() bool {
- if t == nil {
- return true
- }
-
- return time.Now().UTC().Add(1 * time.Minute).After(time.Unix(t.TokenExpire, 0).UTC())
-}
diff --git a/providers/dns/glesys/glesys.go b/providers/dns/glesys/glesys.go
index 729756235..4b0d545ed 100644
--- a/providers/dns/glesys/glesys.go
+++ b/providers/dns/glesys/glesys.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/glesys/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -100,8 +99,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -136,7 +133,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// save data necessary for CleanUp
d.activeRecords[info.EffectiveFQDN] = recordID
-
return nil
}
@@ -147,7 +143,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
// acquire lock and retrieve authZone
d.inProgressMu.Lock()
defer d.inProgressMu.Unlock()
-
if _, ok := d.activeRecords[info.EffectiveFQDN]; !ok {
// if there is no cleanup information then just return
return nil
diff --git a/providers/dns/glesys/glesys.toml b/providers/dns/glesys/glesys.toml
index c0e2613b8..1bdd43c2b 100644
--- a/providers/dns/glesys/glesys.toml
+++ b/providers/dns/glesys/glesys.toml
@@ -7,7 +7,7 @@ Since = "v0.5.0"
Example = '''
GLESYS_API_USER=xxxxx \
GLESYS_API_KEY=yyyyy \
-lego --dns glesys -d '*.example.com' -d example.com run
+lego --email you@example.com --dns glesys -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/glesys/glesys_test.go b/providers/dns/glesys/glesys_test.go
index f2d65e514..d5fdf36da 100644
--- a/providers/dns/glesys/glesys_test.go
+++ b/providers/dns/glesys/glesys_test.go
@@ -56,7 +56,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -131,7 +130,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -145,7 +143,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/glesys/internal/client.go b/providers/dns/glesys/internal/client.go
index ee6ebc058..20bc363ba 100644
--- a/providers/dns/glesys/internal/client.go
+++ b/providers/dns/glesys/internal/client.go
@@ -102,7 +102,6 @@ func (c *Client) do(req *http.Request) (*apiResponse, error) {
}
var response apiResponse
-
err = json.Unmarshal(raw, &response)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/godaddy/godaddy.go b/providers/dns/godaddy/godaddy.go
index 1603bb57e..38e470509 100644
--- a/providers/dns/godaddy/godaddy.go
+++ b/providers/dns/godaddy/godaddy.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/godaddy/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -96,8 +95,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
@@ -131,7 +128,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
}
var newRecords []internal.DNSRecord
-
for _, record := range existingRecords {
if record.Data != "" {
newRecords = append(newRecords, record)
@@ -178,7 +174,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var recordsToKeep []internal.DNSRecord
-
for _, record := range existingRecords {
if record.Data != info.Value && record.Data != "" {
recordsToKeep = append(recordsToKeep, record)
diff --git a/providers/dns/godaddy/godaddy.toml b/providers/dns/godaddy/godaddy.toml
index b906605b3..acf0bf404 100644
--- a/providers/dns/godaddy/godaddy.toml
+++ b/providers/dns/godaddy/godaddy.toml
@@ -7,7 +7,7 @@ Since = "v0.5.0"
Example = '''
GODADDY_API_KEY=xxxxxxxx \
GODADDY_API_SECRET=yyyyyyyy \
-lego --dns godaddy -d '*.example.com' -d example.com run
+lego --email you@example.com --dns godaddy -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/godaddy/godaddy_test.go b/providers/dns/godaddy/godaddy_test.go
index 38b39672e..4cb5f2721 100644
--- a/providers/dns/godaddy/godaddy_test.go
+++ b/providers/dns/godaddy/godaddy_test.go
@@ -56,7 +56,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -127,7 +126,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -141,7 +139,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/godaddy/internal/client.go b/providers/dns/godaddy/internal/client.go
index 9dd337ddc..bf30d437f 100644
--- a/providers/dns/godaddy/internal/client.go
+++ b/providers/dns/godaddy/internal/client.go
@@ -48,7 +48,6 @@ func (c *Client) GetRecords(ctx context.Context, domainZone, rType, recordName s
}
var records []DNSRecord
-
err = c.do(req, &records)
if err != nil {
return nil, err
@@ -142,7 +141,6 @@ 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)
diff --git a/providers/dns/godaddy/internal/types.go b/providers/dns/godaddy/internal/types.go
index 3bd5c9560..a97a97896 100644
--- a/providers/dns/godaddy/internal/types.go
+++ b/providers/dns/godaddy/internal/types.go
@@ -1,9 +1,6 @@
package internal
-import (
- "fmt"
- "strings"
-)
+import "fmt"
// DNSRecord a DNS record.
type DNSRecord struct {
@@ -26,16 +23,13 @@ type APIError struct {
}
func (a APIError) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "%s: %s", a.Code, a.Message)
+ msg := fmt.Sprintf("%s: %s", a.Code, a.Message)
for _, field := range a.Fields {
- msg.WriteString(" ")
- msg.WriteString(field.String())
+ msg += " " + field.String()
}
- return msg.String()
+ return msg
}
type Field struct {
diff --git a/providers/dns/googledomains/googledomains.toml b/providers/dns/googledomains/googledomains.toml
index 52330795d..1ac7e5e54 100644
--- a/providers/dns/googledomains/googledomains.toml
+++ b/providers/dns/googledomains/googledomains.toml
@@ -8,7 +8,7 @@ Since = "v4.11.0"
Example = '''
GOOGLE_DOMAINS_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns googledomains -d '*.example.com' -d example.com run
+lego --email you@example.com --dns googledomains -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/gravity/gravity.go b/providers/dns/gravity/gravity.go
deleted file mode 100644
index b0bbb2fcb..000000000
--- a/providers/dns/gravity/gravity.go
+++ /dev/null
@@ -1,209 +0,0 @@
-// Package gravity implements a DNS provider for solving the DNS-01 challenge using Gravity.
-package gravity
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/gravity/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/google/uuid"
-)
-
-// Environment variables names.
-const (
- envNamespace = "GRAVITY_"
-
- EnvUsername = envNamespace + "USERNAME"
- EnvPassword = envNamespace + "PASSWORD"
- EnvServerURL = envNamespace + "SERVER_URL"
-
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
- EnvSequenceInterval = envNamespace + "SEQUENCE_INTERVAL"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Username string
- Password string
- ServerURL string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- SequenceInterval time.Duration
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- SequenceInterval: env.GetOrDefaultSecond(EnvSequenceInterval, 1*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- records map[string]internal.Record
- recordsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Gravity.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvUsername, EnvPassword, EnvServerURL)
- if err != nil {
- return nil, fmt.Errorf("gravity: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Username = values[EnvUsername]
- config.Password = values[EnvPassword]
- config.ServerURL = values[EnvServerURL]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Gravity.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("gravity: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.ServerURL, config.Username, config.Password)
- if err != nil {
- return nil, fmt.Errorf("gravity: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- records: make(map[string]internal.Record),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- _, err := d.client.Login(ctx)
- if err != nil {
- return fmt.Errorf("gravity: login: %w", err)
- }
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("gravity: %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
- if err != nil {
- return fmt.Errorf("gravity: %w", err)
- }
-
- id := uuid.New()
-
- record := internal.Record{
- Data: info.Value,
- Hostname: subDomain,
- Type: "TXT",
- UID: id.String(),
- }
-
- err = d.client.CreateDNSRecord(ctx, zone, record)
- if err != nil {
- return fmt.Errorf("gravity: create DNS record: %w", err)
- }
-
- d.recordsMu.Lock()
-
- record.Fqdn = zone
- d.records[token] = record
- d.recordsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- d.recordsMu.Lock()
- record, ok := d.records[token]
- d.recordsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("gravity: unknown record for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- err := d.client.DeleteDNSRecord(context.Background(), record.Fqdn, record)
- if err != nil {
- return fmt.Errorf("gravity: delete record: %w", err)
- }
-
- d.recordsMu.Lock()
- delete(d.records, token)
- d.recordsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Sequential implements the [dns01.sequential] interface.
-// It changes the behavior of the provider to resolve DNS challenges sequentially.
-// Returns the interval between each iteration.
-//
-// Gravity supports adding multiple records for the same domain, but the DNS server doesn't work as expected:
-// if you call the DNS server, it will answer only the latest record instead of all of them.
-func (d *DNSProvider) Sequential() time.Duration {
- return d.config.SequenceInterval
-}
-
-func (d *DNSProvider) findZone(ctx context.Context, effectiveFQDN string) (string, error) {
- var zone string
-
- for fqdn := range dns01.DomainsSeq(effectiveFQDN) {
- zones, err := d.client.GetDNSZones(ctx, fqdn)
- if err != nil {
- return "", fmt.Errorf("get DNS zones: %w", err)
- }
-
- if len(zones) != 0 {
- zone = zones[0].Name
- break
- }
- }
-
- if zone == "" {
- return "", fmt.Errorf("could not find zone for %q", effectiveFQDN)
- }
-
- return zone, nil
-}
diff --git a/providers/dns/gravity/gravity.toml b/providers/dns/gravity/gravity.toml
deleted file mode 100644
index 87a303839..000000000
--- a/providers/dns/gravity/gravity.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-Name = "Gravity"
-Description = ''''''
-URL = "https://gravity.beryju.io/"
-Code = "gravity"
-Since = "v4.30.0"
-
-Example = '''
-GRAVITY_SERVER_URL="https://example.org:1234" \
-GRAVITY_USERNAME="xxxxxxxxxxxxxxxxxxxxx" \
-GRAVITY_PASSWORD="yyyyyyyyyyyyyyyyyyyyy" \
-lego --dns gravity -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- GRAVITY_SERVER_URL = "URL of the server"
- GRAVITY_USERNAME = "Username"
- GRAVITY_PASSWORD = "Password"
- [Configuration.Additional]
- GRAVITY_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- GRAVITY_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- GRAVITY_SEQUENCE_INTERVAL = "Time between sequential requests in seconds (Default: 1)"
- GRAVITY_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://gravity.beryju.io/docs/api/reference/"
diff --git a/providers/dns/gravity/gravity_test.go b/providers/dns/gravity/gravity_test.go
deleted file mode 100644
index b59b856fe..000000000
--- a/providers/dns/gravity/gravity_test.go
+++ /dev/null
@@ -1,254 +0,0 @@
-package gravity
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/gravity/internal"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvUsername,
- EnvPassword,
- EnvServerURL,
-).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvUsername: "user",
- EnvPassword: "secret",
- EnvServerURL: "https://example.org:1234",
- },
- },
- {
- desc: "missing EnvUsername",
- envVars: map[string]string{
- EnvUsername: "",
- EnvPassword: "secret",
- EnvServerURL: "https://example.org:1234",
- },
- expected: "gravity: some credentials information are missing: GRAVITY_USERNAME",
- },
- {
- desc: "missing EnvPassword",
- envVars: map[string]string{
- EnvUsername: "user",
- EnvPassword: "",
- EnvServerURL: "https://example.org:1234",
- },
- expected: "gravity: some credentials information are missing: GRAVITY_PASSWORD",
- },
- {
- desc: "missing EnvServerURL",
- envVars: map[string]string{
- EnvUsername: "user",
- EnvPassword: "secret",
- EnvServerURL: "",
- },
- expected: "gravity: some credentials information are missing: GRAVITY_SERVER_URL",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "gravity: some credentials information are missing: GRAVITY_USERNAME,GRAVITY_PASSWORD,GRAVITY_SERVER_URL",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- username string
- password string
- serverURL string
- expected string
- }{
- {
- desc: "success",
- username: "user",
- password: "secret",
- serverURL: "https://example.org:1234",
- },
- {
- desc: "missing username",
- username: "",
- password: "secret",
- serverURL: "https://example.org:1234",
- expected: "gravity: credentials missing",
- },
- {
- desc: "missing password",
- username: "user",
- password: "",
- serverURL: "https://example.org:1234",
- expected: "gravity: credentials missing",
- },
- {
- desc: "missing server URL",
- username: "user",
- password: "secret",
- serverURL: "",
- expected: "gravity: server URL missing",
- },
- {
- desc: "missing credentials",
- expected: "gravity: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Username = test.username
- config.Password = test.password
- config.ServerURL = test.serverURL
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
-
- config.Username = "user"
- config.Password = "secret"
- config.ServerURL = server.URL
-
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /api/v1/auth/login",
- servermock.ResponseFromInternal("login.json"),
- servermock.CheckRequestJSONBodyFromInternal("login-request.json")).
- Route("GET /api/v1/dns/",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- if req.URL.Query().Get("name") != "example.com." {
- servermock.ResponseFromInternal("zones.json").ServeHTTP(rw, req)
- return
- }
-
- servermock.ResponseFromInternal("zones_empty.json").ServeHTTP(rw, req)
- }),
- ).
- Route("POST /api/v1/dns/zones/records",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- servermock.CheckQueryParameter().Strict().
- With("zone", "example.com.").
- WithRegexp("uid", `\w{8}-\w{4}-\w{4}-\w{4}-\w{12}`).
- With("hostname", "_acme-challenge")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /api/v1/dns/zones/records",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- servermock.CheckQueryParameter().Strict().
- With("zone", "example.com.").
- With("uid", "123").
- With("type", "TXT").
- With("hostname", "_acme-challenge")).
- Build(t)
-
- provider.records["abc"] = internal.Record{
- Fqdn: "example.com.",
- Hostname: "_acme-challenge",
- Type: "TXT",
- UID: "123",
- }
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/gravity/internal/client.go b/providers/dns/gravity/internal/client.go
deleted file mode 100644
index 41c6294c3..000000000
--- a/providers/dns/gravity/internal/client.go
+++ /dev/null
@@ -1,234 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/http/cookiejar"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
- "golang.org/x/net/publicsuffix"
-)
-
-// Client the Gravity API client.
-type Client struct {
- username string
- password string
-
- baseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(serverURL, username, password string) (*Client, error) {
- if username == "" || password == "" {
- return nil, errors.New("credentials missing")
- }
-
- if serverURL == "" {
- return nil, errors.New("server URL missing")
- }
-
- baseURL, err := url.Parse(serverURL)
- if err != nil {
- return nil, err
- }
-
- return &Client{
- username: username,
- password: password,
- baseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) Login(ctx context.Context) (*Auth, error) {
- jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
- if err != nil {
- return nil, err
- }
-
- c.HTTPClient.Jar = jar
-
- login := Login{
- Username: c.username,
- Password: c.password,
- }
-
- endpoint := c.baseURL.JoinPath("api", "v1", "auth", "login")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, login)
- if err != nil {
- return nil, err
- }
-
- result := &Auth{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-func (c *Client) Me(ctx context.Context) (*UserInfo, error) {
- endpoint := c.baseURL.JoinPath("api", "v1", "auth", "me")
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- result := &UserInfo{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, err
-}
-
-func (c *Client) GetDNSZones(ctx context.Context, name string) ([]Zone, error) {
- endpoint := c.baseURL.JoinPath("api", "v1", "dns", "zones")
-
- if name != "" {
- query := endpoint.Query()
- query.Set("name", name)
- endpoint.RawQuery = query.Encode()
- }
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- result := Zones{}
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Zones, nil
-}
-
-func (c *Client) CreateDNSRecord(ctx context.Context, zone string, record Record) error {
- endpoint := c.baseURL.JoinPath("api", "v1", "dns", "zones", "records")
-
- query := endpoint.Query()
-
- query.Set("zone", zone)
- query.Set("hostname", record.Hostname)
-
- // When the UID is the same as an existing one, the record is updated, else a new record is created.
- // An explicit UID is not required to create a record.
- if record.UID != "" {
- query.Set("uid", record.UID)
- }
-
- endpoint.RawQuery = query.Encode()
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) DeleteDNSRecord(ctx context.Context, zone string, record Record) error {
- endpoint := c.baseURL.JoinPath("api", "v1", "dns", "zones", "records")
-
- query := endpoint.Query()
-
- query.Set("zone", zone)
- query.Set("hostname", record.Hostname)
- query.Set("uid", record.UID)
- query.Set("type", record.Type)
-
- endpoint.RawQuery = query.Encode()
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
diff --git a/providers/dns/gravity/internal/client_test.go b/providers/dns/gravity/internal/client_test.go
deleted file mode 100644
index 98b17c59e..000000000
--- a/providers/dns/gravity/internal/client_test.go
+++ /dev/null
@@ -1,160 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(server.URL, "user", "secret")
- if err != nil {
- return nil, err
- }
-
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestClient_Login(t *testing.T) {
- client := mockBuilder().
- Route("POST /api/v1/auth/login",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- http.SetCookie(rw, &http.Cookie{
- Name: "gravity_session",
- Value: "session_id",
- Path: "/",
- })
-
- servermock.ResponseFromFixture("login.json").ServeHTTP(rw, req)
- }),
- servermock.CheckRequestJSONBodyFromFixture("login-request.json")).
- Build(t)
-
- auth, err := client.Login(t.Context())
- require.NoError(t, err)
-
- cookies := client.HTTPClient.Jar.Cookies(client.baseURL)
-
- require.Len(t, cookies, 1)
-
- assert.Equal(t, "gravity_session", cookies[0].Name)
- assert.Equal(t, "session_id", cookies[0].Value)
-
- expected := &Auth{Successful: true}
-
- assert.Equal(t, expected, auth)
-}
-
-func TestClient_Login_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /api/v1/auth/login",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- _, err := client.Login(t.Context())
- require.EqualError(t, err, "status: UNAUTHENTICATED, error: unauthenticated, additionalProp1: string")
-}
-
-func TestClient_Me(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/v1/auth/me",
- servermock.ResponseFromFixture("me.json")).
- Build(t)
-
- info, err := client.Me(t.Context())
- require.NoError(t, err)
-
- expected := &UserInfo{
- Username: "admin",
- Authenticated: true,
- Permissions: []Permission{{
- Methods: []string{"GET", "POST", "PUT", "HEAD", "DELETE"},
- Path: "/*",
- }},
- }
-
- assert.Equal(t, expected, info)
-}
-
-func TestClient_GetDNSZones(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/v1/dns/",
- servermock.ResponseFromFixture("zones.json"),
- servermock.CheckQueryParameter().Strict().
- With("name", "example.com.")).
- Build(t)
-
- zones, err := client.GetDNSZones(t.Context(), "example.com.")
- require.NoError(t, err)
-
- expected := []Zone{{
- Name: "example.com.",
- HandlerConfigs: []HandlerConfig{
- {Type: "memory"},
- {Type: "etcd"},
- },
- DefaultTTL: 86400,
- RecordCount: 1,
- }}
-
- assert.Equal(t, expected, zones)
-}
-
-func TestClient_CreateDNSRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /api/v1/dns/zones/records",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- servermock.CheckRequestJSONBodyFromFixture("create_record-request.json"),
- servermock.CheckQueryParameter().Strict().
- With("zone", "example.com.").
- With("uid", "123").
- With("hostname", "_acme-challenge")).
- Build(t)
-
- record := Record{
- Data: "txtTXTtxt",
- Hostname: "_acme-challenge",
- Type: "TXT",
- UID: "123",
- }
-
- err := client.CreateDNSRecord(t.Context(), "example.com.", record)
- require.NoError(t, err)
-}
-
-func TestClient_DeleteDNSRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /api/v1/dns/zones/records",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- servermock.CheckQueryParameter().Strict().
- With("zone", "example.com.").
- With("uid", "123").
- With("type", "TXT").
- With("hostname", "_acme-challenge")).
- Build(t)
-
- record := Record{
- Data: "txtTXTtxt",
- Hostname: "_acme-challenge",
- Type: "TXT",
- UID: "123",
- }
-
- err := client.DeleteDNSRecord(t.Context(), "example.com.", record)
- require.NoError(t, err)
-}
diff --git a/providers/dns/gravity/internal/fixtures/create_record-request.json b/providers/dns/gravity/internal/fixtures/create_record-request.json
deleted file mode 100644
index d671d1342..000000000
--- a/providers/dns/gravity/internal/fixtures/create_record-request.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "data": "txtTXTtxt",
- "hostname": "_acme-challenge",
- "type": "TXT",
- "uid": "123"
-}
diff --git a/providers/dns/gravity/internal/fixtures/error.json b/providers/dns/gravity/internal/fixtures/error.json
deleted file mode 100644
index 38b78fcca..000000000
--- a/providers/dns/gravity/internal/fixtures/error.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "code": 0,
- "context": {
- "additionalProp1": "string"
- },
- "error": "unauthenticated",
- "status": "UNAUTHENTICATED"
-}
diff --git a/providers/dns/gravity/internal/fixtures/login-request.json b/providers/dns/gravity/internal/fixtures/login-request.json
deleted file mode 100644
index c641cd3e5..000000000
--- a/providers/dns/gravity/internal/fixtures/login-request.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "username": "user",
- "password": "secret"
-}
diff --git a/providers/dns/gravity/internal/fixtures/login.json b/providers/dns/gravity/internal/fixtures/login.json
deleted file mode 100644
index b9ae7145f..000000000
--- a/providers/dns/gravity/internal/fixtures/login.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "successful": true
-}
diff --git a/providers/dns/gravity/internal/fixtures/me.json b/providers/dns/gravity/internal/fixtures/me.json
deleted file mode 100644
index 881a2ca5f..000000000
--- a/providers/dns/gravity/internal/fixtures/me.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "username": "admin",
- "authenticated": true,
- "permissions": [
- {
- "path": "/*",
- "methods": [
- "GET",
- "POST",
- "PUT",
- "HEAD",
- "DELETE"
- ]
- }
- ]
-}
diff --git a/providers/dns/gravity/internal/fixtures/me_unauthenticated.json b/providers/dns/gravity/internal/fixtures/me_unauthenticated.json
deleted file mode 100644
index 67698b8e2..000000000
--- a/providers/dns/gravity/internal/fixtures/me_unauthenticated.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "username": "",
- "authenticated": false,
- "permissions": null
-}
diff --git a/providers/dns/gravity/internal/fixtures/zones.json b/providers/dns/gravity/internal/fixtures/zones.json
deleted file mode 100644
index 53a8df6c1..000000000
--- a/providers/dns/gravity/internal/fixtures/zones.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "zones": [
- {
- "name": "example.com.",
- "handlerConfigs": [
- {
- "type": "memory"
- },
- {
- "type": "etcd"
- }
- ],
- "defaultTTL": 86400,
- "authoritative": false,
- "hook": "",
- "recordCount": 1
- }
- ]
-}
diff --git a/providers/dns/gravity/internal/fixtures/zones_empty.json b/providers/dns/gravity/internal/fixtures/zones_empty.json
deleted file mode 100644
index d8b70b45e..000000000
--- a/providers/dns/gravity/internal/fixtures/zones_empty.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "zones": null
-}
diff --git a/providers/dns/gravity/internal/types.go b/providers/dns/gravity/internal/types.go
deleted file mode 100644
index 872bc070f..000000000
--- a/providers/dns/gravity/internal/types.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strings"
-)
-
-type APIError struct {
- Status string `json:"status"`
- ErrorMsg string `json:"error"`
- Code int `json:"code"`
- Context map[string]string `json:"context"`
-}
-
-func (a *APIError) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "status: %s, error: %s", a.Status, a.ErrorMsg)
-
- if a.Code != 0 {
- _, _ = fmt.Fprintf(msg, ", code: %d", a.Code)
- }
-
- if len(a.Context) != 0 {
- for k, v := range a.Context {
- _, _ = fmt.Fprintf(msg, ", %s: %s", k, v)
- }
- }
-
- return msg.String()
-}
-
-type Login struct {
- Username string `json:"username"`
- Password string `json:"password"`
-}
-
-type Auth struct {
- Successful bool `json:"successful"`
-}
-
-type UserInfo struct {
- Username string `json:"username"`
- Authenticated bool `json:"authenticated"`
- Permissions []Permission `json:"permissions"`
-}
-
-type Permission struct {
- Methods []string `json:"methods"`
- Path string `json:"path"`
-}
-
-type Zones struct {
- Zones []Zone `json:"zones"`
-}
-
-type Zone struct {
- Name string `json:"name"`
- HandlerConfigs []HandlerConfig `json:"handlerConfigs"`
- DefaultTTL int `json:"defaultTTL"`
- Authoritative bool `json:"authoritative"`
- Hook string `json:"hook"`
- RecordCount int `json:"recordCount"`
-}
-
-type HandlerConfig struct {
- Type string `json:"type"`
- CacheTTL int `json:"cache_ttl,omitempty"`
- To []string `json:"to,omitempty"`
-}
-
-type Record struct {
- Data string `json:"data,omitempty"`
- Fqdn string `json:"fqdn,omitempty"`
- Hostname string `json:"hostname,omitempty"`
- MxPreference int `json:"mxPreference,omitempty"`
- SrvPort int `json:"srvPort,omitempty"`
- SrvPriority int `json:"srvPriority,omitempty"`
- SrvWeight int `json:"srvWeight,omitempty"`
- Type string `json:"type,omitempty"`
- UID string `json:"uid,omitempty"`
-}
diff --git a/providers/dns/hetzner/hetzner.go b/providers/dns/hetzner/hetzner.go
index bae985b3e..4dcd8e071 100644
--- a/providers/dns/hetzner/hetzner.go
+++ b/providers/dns/hetzner/hetzner.go
@@ -2,28 +2,28 @@
package hetzner
import (
+ "context"
"errors"
+ "fmt"
"net/http"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/hetzner/internal/hetznerv1"
- "github.com/go-acme/lego/v4/providers/dns/hetzner/internal/legacy"
+ "github.com/go-acme/lego/v4/providers/dns/hetzner/internal"
)
// Environment variables names.
const (
- // Deprecated: use EnvAPIToken instead.
- EnvAPIKey = legacy.EnvAPIKey
- EnvAPIToken = hetznerv1.EnvAPIToken
+ envNamespace = "HETZNER_"
- EnvTTL = hetznerv1.EnvTTL
- EnvPropagationTimeout = hetznerv1.EnvPropagationTimeout
- EnvPollingInterval = hetznerv1.EnvPollingInterval
- EnvHTTPTimeout = hetznerv1.EnvHTTPTimeout
+ EnvAPIKey = envNamespace + "API_KEY"
+
+ EnvTTL = envNamespace + "TTL"
+ EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
+ EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
+ EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
const minTTL = 60
@@ -32,11 +32,7 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- // Deprecated: use APIToken instead
- APIKey string
-
- APIToken string
-
+ APIKey string
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
@@ -57,41 +53,22 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- provider challenge.ProviderTimeout
+ config *Config
+ client *internal.Client
}
// NewDNSProvider returns a DNSProvider instance configured for hetzner.
+// Credentials must be passed in the environment variable: HETZNER_API_KEY.
func NewDNSProvider() (*DNSProvider, error) {
- foundAPIToken := env.GetOrFile(EnvAPIToken) != ""
- foundAPIKey := env.GetOrFile(EnvAPIKey) != ""
-
- switch {
- case foundAPIToken:
- provider, err := hetznerv1.NewDNSProvider()
- if err != nil {
- return nil, err
- }
-
- return &DNSProvider{provider: provider}, nil
-
- case foundAPIKey:
- log.Warnf("APIKey (legacy Hetzner DNS API) is deprecated, please use APIToken (Hetzner Cloud API) instead.")
-
- provider, err := legacy.NewDNSProvider()
- if err != nil {
- return nil, err
- }
-
- return &DNSProvider{provider: provider}, nil
-
- default:
- provider, err := hetznerv1.NewDNSProvider()
- if err != nil {
- return nil, err
- }
-
- return &DNSProvider{provider: provider}, nil
+ values, err := env.Get(EnvAPIKey)
+ if err != nil {
+ return nil, fmt.Errorf("hetzner: %w", err)
}
+
+ config := NewDefaultConfig()
+ config.APIKey = values[EnvAPIKey]
+
+ return NewDNSProviderConfig(config)
}
// NewDNSProviderConfig return a DNSProvider instance configured for hetzner.
@@ -100,57 +77,98 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("hetzner: the configuration of the DNS provider is nil")
}
- switch {
- case config.APIToken != "":
- cfg := &hetznerv1.Config{
- APIToken: config.APIToken,
- PropagationTimeout: config.PropagationTimeout,
- PollingInterval: config.PollingInterval,
- TTL: config.TTL,
- HTTPClient: config.HTTPClient,
- }
-
- provider, err := hetznerv1.NewDNSProviderConfig(cfg)
- if err != nil {
- return nil, err
- }
-
- return &DNSProvider{provider: provider}, nil
-
- case config.APIKey != "":
- log.Warnf("%s (legacy Hetzner DNS API) is deprecated, please use %s (Hetzner Cloud API) instead.", EnvAPIKey, EnvAPIToken)
-
- cfg := &legacy.Config{
- APIKey: config.APIKey,
- PropagationTimeout: config.PropagationTimeout,
- PollingInterval: config.PollingInterval,
- TTL: config.TTL,
- HTTPClient: config.HTTPClient,
- }
-
- provider, err := legacy.NewDNSProviderConfig(cfg)
- if err != nil {
- return nil, err
- }
-
- return &DNSProvider{provider: provider}, nil
+ if config.APIKey == "" {
+ return nil, errors.New("hetzner: credentials missing")
}
- return nil, errors.New("hetzner: credentials missing")
+ if config.TTL < minTTL {
+ return nil, fmt.Errorf("hetzner: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
+ }
+
+ client := internal.NewClient(config.APIKey)
+
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{config: config, client: client}, nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.provider.Timeout()
+ return d.config.PropagationTimeout, d.config.PollingInterval
}
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- return d.provider.Present(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("hetzner: could not find zone for domain %q: %w", domain, err)
+ }
+
+ zone := dns01.UnFqdn(authZone)
+
+ ctx := context.Background()
+
+ zoneID, err := d.client.GetZoneID(ctx, zone)
+ if err != nil {
+ return fmt.Errorf("hetzner: %w", err)
+ }
+
+ subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
+ if err != nil {
+ return fmt.Errorf("hetzner: %w", err)
+ }
+
+ record := internal.DNSRecord{
+ Type: "TXT",
+ Name: subDomain,
+ Value: info.Value,
+ TTL: d.config.TTL,
+ ZoneID: zoneID,
+ }
+
+ if err := d.client.CreateRecord(ctx, record); err != nil {
+ return fmt.Errorf("hetzner: failed to add TXT record: fqdn=%s, zoneID=%s: %w", info.EffectiveFQDN, zoneID, err)
+ }
+
+ return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- return d.provider.CleanUp(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("hetzner: could not find zone for domain %q: %w", domain, err)
+ }
+
+ zone := dns01.UnFqdn(authZone)
+
+ ctx := context.Background()
+
+ zoneID, err := d.client.GetZoneID(ctx, zone)
+ if err != nil {
+ return fmt.Errorf("hetzner: %w", err)
+ }
+
+ subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
+ if err != nil {
+ return fmt.Errorf("hetzner: %w", err)
+ }
+
+ record, err := d.client.GetTxtRecord(ctx, subDomain, info.Value, zoneID)
+ if err != nil {
+ return fmt.Errorf("hetzner: %w", err)
+ }
+
+ if err := d.client.DeleteRecord(ctx, record.ID); err != nil {
+ return fmt.Errorf("hetzner: failed to delete TXT record: id=%s, name=%s: %w", record.ID, record.Name, err)
+ }
+
+ return nil
}
diff --git a/providers/dns/hetzner/hetzner.toml b/providers/dns/hetzner/hetzner.toml
index 40d4cea72..033ae2d2f 100644
--- a/providers/dns/hetzner/hetzner.toml
+++ b/providers/dns/hetzner/hetzner.toml
@@ -5,18 +5,18 @@ Code = "hetzner"
Since = "v3.7.0"
Example = '''
-HETZNER_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns hetzner -d '*.example.com' -d example.com run
+HETZNER_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
+lego --email you@example.com --dns hetzner -d '*.example.com' -d example.com run
'''
[Configuration]
[Configuration.Credentials]
- HETZNER_API_TOKEN = "API token"
+ HETZNER_API_KEY = "API key"
[Configuration.Additional]
HETZNER_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- HETZNER_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- HETZNER_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
+ HETZNER_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
+ HETZNER_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"
HETZNER_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
[Links]
- API = "https://docs.hetzner.cloud/reference/cloud#dns"
+ API = "https://dns.hetzner.com/api-docs"
diff --git a/providers/dns/hetzner/hetzner_test.go b/providers/dns/hetzner/hetzner_test.go
index 430f0270b..d028fd06b 100644
--- a/providers/dns/hetzner/hetzner_test.go
+++ b/providers/dns/hetzner/hetzner_test.go
@@ -3,72 +3,52 @@ package hetzner
import (
"testing"
- "github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/providers/dns/hetzner/internal/hetznerv1"
- "github.com/go-acme/lego/v4/providers/dns/hetzner/internal/legacy"
- "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-var envTest = tester.NewEnvTest(EnvAPIKey, EnvAPIToken)
+const envDomain = envNamespace + "DOMAIN"
+
+var envTest = tester.NewEnvTest(
+ EnvAPIKey).
+ WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) {
testCases := []struct {
- desc string
- envVars map[string]string
-
- expectedProvider challenge.ProviderTimeout
- expectedError string
+ desc string
+ envVars map[string]string
+ expected string
}{
{
- desc: "success (v1)",
- envVars: map[string]string{
- EnvAPIToken: "123",
- },
- expectedProvider: &hetznerv1.DNSProvider{},
- },
- {
- desc: "success (legacy)",
+ desc: "success",
envVars: map[string]string{
EnvAPIKey: "123",
},
- expectedProvider: &legacy.DNSProvider{},
- },
- {
- desc: "success (both)",
- envVars: map[string]string{
- EnvAPIKey: "123",
- EnvAPIToken: "123",
- },
- expectedProvider: &hetznerv1.DNSProvider{},
},
{
desc: "missing credentials",
envVars: map[string]string{
- EnvAPIKey: "",
- EnvAPIToken: "",
+ EnvAPIKey: "",
},
- expectedError: "hetzner: some credentials information are missing: HETZNER_API_TOKEN",
+ expected: "hetzner: some credentials information are missing: HETZNER_API_KEY",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
p, err := NewDNSProvider()
- if test.expectedError == "" {
+ if test.expected == "" {
require.NoError(t, err)
- assert.IsType(t, test.expectedProvider, p.provider)
require.NotNil(t, p)
+ require.NotNil(t, p.config)
} else {
- require.EqualError(t, err, test.expectedError)
+ require.EqualError(t, err, test.expected)
}
})
}
@@ -78,53 +58,68 @@ func TestNewDNSProviderConfig(t *testing.T) {
testCases := []struct {
desc string
apiKey string
- apiToken string
ttl int
-
- expectedProvider challenge.ProviderTimeout
- expectedError string
+ expected string
}{
{
- desc: "success (v1)",
- ttl: minTTL,
- apiToken: "123",
- expectedProvider: &hetznerv1.DNSProvider{},
+ desc: "success",
+ ttl: minTTL,
+ apiKey: "123",
},
{
- desc: "success (legacy)",
- ttl: minTTL,
- apiKey: "456",
- expectedProvider: &legacy.DNSProvider{},
+ desc: "missing credentials",
+ ttl: minTTL,
+ expected: "hetzner: credentials missing",
},
{
- desc: "success (both)",
- ttl: minTTL,
- apiToken: "123",
- apiKey: "456",
- expectedProvider: &hetznerv1.DNSProvider{},
- },
- {
- desc: "missing credentials",
- ttl: minTTL,
- expectedError: "hetzner: credentials missing",
+ desc: "invalid TTL",
+ apiKey: "123",
+ ttl: 10,
+ expected: "hetzner: invalid TTL, TTL (10) must be greater than 60",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
config := NewDefaultConfig()
- config.APIToken = test.apiToken
config.APIKey = test.apiKey
config.TTL = test.ttl
p, err := NewDNSProviderConfig(config)
- if test.expectedError == "" {
+ if test.expected == "" {
require.NoError(t, err)
- assert.IsType(t, test.expectedProvider, p.provider)
+ require.NotNil(t, p)
+ require.NotNil(t, p.config)
} else {
- require.EqualError(t, err, test.expectedError)
+ require.EqualError(t, err, test.expected)
}
})
}
}
+
+func TestLivePresent(t *testing.T) {
+ if !envTest.IsLiveTest() {
+ t.Skip("skipping live test")
+ }
+
+ envTest.RestoreEnv()
+ provider, err := NewDNSProvider()
+ require.NoError(t, err)
+
+ err = provider.Present(envTest.GetDomain(), "", "123d==")
+ require.NoError(t, err)
+}
+
+func TestLiveCleanUp(t *testing.T) {
+ if !envTest.IsLiveTest() {
+ t.Skip("skipping live test")
+ }
+
+ envTest.RestoreEnv()
+ provider, err := NewDNSProvider()
+ require.NoError(t, err)
+
+ err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
+ require.NoError(t, err)
+}
diff --git a/providers/dns/hetzner/internal/legacy/internal/client.go b/providers/dns/hetzner/internal/client.go
similarity index 99%
rename from providers/dns/hetzner/internal/legacy/internal/client.go
rename to providers/dns/hetzner/internal/client.go
index cd187f6e5..381922264 100644
--- a/providers/dns/hetzner/internal/legacy/internal/client.go
+++ b/providers/dns/hetzner/internal/client.go
@@ -83,7 +83,6 @@ func (c *Client) getRecords(ctx context.Context, zoneID string) (*DNSRecords, er
}
records := &DNSRecords{}
-
err = json.Unmarshal(raw, records)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -191,7 +190,6 @@ func (c *Client) getZones(ctx context.Context, name string) (*Zones, error) {
}
zones := &Zones{}
-
err = json.Unmarshal(raw, zones)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/hetzner/internal/legacy/internal/client_test.go b/providers/dns/hetzner/internal/client_test.go
similarity index 100%
rename from providers/dns/hetzner/internal/legacy/internal/client_test.go
rename to providers/dns/hetzner/internal/client_test.go
diff --git a/providers/dns/hetzner/internal/legacy/internal/fixtures/create_txt_record-request.json b/providers/dns/hetzner/internal/fixtures/create_txt_record-request.json
similarity index 100%
rename from providers/dns/hetzner/internal/legacy/internal/fixtures/create_txt_record-request.json
rename to providers/dns/hetzner/internal/fixtures/create_txt_record-request.json
diff --git a/providers/dns/hetzner/internal/legacy/internal/fixtures/create_txt_record.json b/providers/dns/hetzner/internal/fixtures/create_txt_record.json
similarity index 100%
rename from providers/dns/hetzner/internal/legacy/internal/fixtures/create_txt_record.json
rename to providers/dns/hetzner/internal/fixtures/create_txt_record.json
diff --git a/providers/dns/hetzner/internal/legacy/internal/fixtures/get_txt_record.json b/providers/dns/hetzner/internal/fixtures/get_txt_record.json
similarity index 100%
rename from providers/dns/hetzner/internal/legacy/internal/fixtures/get_txt_record.json
rename to providers/dns/hetzner/internal/fixtures/get_txt_record.json
diff --git a/providers/dns/hetzner/internal/legacy/internal/fixtures/get_zone_id.json b/providers/dns/hetzner/internal/fixtures/get_zone_id.json
similarity index 100%
rename from providers/dns/hetzner/internal/legacy/internal/fixtures/get_zone_id.json
rename to providers/dns/hetzner/internal/fixtures/get_zone_id.json
diff --git a/providers/dns/hetzner/internal/hetznerv1/fixtures/add_rrset_records-request.json b/providers/dns/hetzner/internal/hetznerv1/fixtures/add_rrset_records-request.json
deleted file mode 100644
index 210f84435..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/fixtures/add_rrset_records-request.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "ttl": 120,
- "records": [
- {
- "value": "\"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI\""
- }
- ]
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/fixtures/add_rrset_records.json b/providers/dns/hetzner/internal/hetznerv1/fixtures/add_rrset_records.json
deleted file mode 100644
index 2341c7e6e..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/fixtures/add_rrset_records.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "action": {
- "id": 1,
- "command": "add_rrset_records",
- "status": "running",
- "progress": 50,
- "started": "2016-01-30T23:55:00+00:00",
- "finished": null,
- "resources": [
- {
- "id": 42,
- "type": "zone"
- }
- ],
- "error": null
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_error.json b/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_error.json
deleted file mode 100644
index 2a4472f67..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_error.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "action": {
- "id": 1,
- "command": "remove_rrset_records",
- "status": "error",
- "started": "2016-01-30T23:55:00+00:00",
- "finished": "2016-01-30T23:55:00+00:00",
- "progress": 50,
- "resources": [
- {
- "id": 42,
- "type": "zone"
- }
- ],
- "error": {
- "code": "action_failed",
- "message": "Action failed"
- }
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_running.json b/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_running.json
deleted file mode 100644
index dcec6c2cd..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_running.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "action": {
- "id": 1,
- "command": "remove_rrset_records",
- "status": "running",
- "started": "2016-01-30T23:55:00+00:00",
- "finished": "2016-01-30T23:55:00+00:00",
- "progress": 50,
- "resources": [
- {
- "id": 42,
- "type": "zone"
- }
- ]
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_success.json b/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_success.json
deleted file mode 100644
index 6b7267c07..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/fixtures/get_action_success.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "action": {
- "id": 1,
- "command": "remove_rrset_records",
- "status": "success",
- "started": "2016-01-30T23:55:00+00:00",
- "finished": "2016-01-30T23:55:00+00:00",
- "progress": 100,
- "resources": [
- {
- "id": 42,
- "type": "zone"
- }
- ]
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/fixtures/remove_rrset_records-request.json b/providers/dns/hetzner/internal/hetznerv1/fixtures/remove_rrset_records-request.json
deleted file mode 100644
index 982273b67..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/fixtures/remove_rrset_records-request.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "records": [
- {
- "value": "\"w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI\""
- }
- ]
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/fixtures/remove_rrset_records.json b/providers/dns/hetzner/internal/hetznerv1/fixtures/remove_rrset_records.json
deleted file mode 100644
index 1b10dfd5e..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/fixtures/remove_rrset_records.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "action": {
- "id": 1,
- "command": "remove_rrset_records",
- "status": "running",
- "progress": 50,
- "started": "2016-01-30T23:55:00+00:00",
- "finished": null,
- "resources": [
- {
- "id": 42,
- "type": "zone"
- }
- ],
- "error": null
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/hetznerv1.go b/providers/dns/hetzner/internal/hetznerv1/hetznerv1.go
deleted file mode 100644
index b31c766ce..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/hetznerv1.go
+++ /dev/null
@@ -1,209 +0,0 @@
-// Package hetznerv1 implements a DNS provider for solving the DNS-01 challenge using Hetzner.
-package hetznerv1
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "strconv"
- "time"
-
- "github.com/cenkalti/backoff/v5"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/platform/wait"
- "github.com/go-acme/lego/v4/providers/dns/hetzner/internal/hetznerv1/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "golang.org/x/net/idna"
-)
-
-// Environment variables names.
-const (
- envNamespace = "HETZNER_"
-
- EnvAPIToken = envNamespace + "API_TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIToken string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Hetzner.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIToken)
- if err != nil {
- return nil, fmt.Errorf("hetzner: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIToken = values[EnvAPIToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Hetzner.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("hetzner: the configuration of the DNS provider is nil")
- }
-
- if config.APIToken == "" {
- return nil, errors.New("hetzner: credentials missing")
- }
-
- client, err := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.APIToken),
- ),
- )
- if err != nil {
- return nil, fmt.Errorf("hetzner: %w", err)
- }
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("hetzner: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("hetzner: %w", err)
- }
-
- subDomainPunnycoded, err := idna.ToASCII(dns01.UnFqdn(subDomain))
- if err != nil {
- return fmt.Errorf("hetzner: %w", err)
- }
-
- zone, err := idna.ToASCII(dns01.UnFqdn(authZone))
- if err != nil {
- return fmt.Errorf("hetzner: %w", err)
- }
-
- records := []internal.Record{{Value: strconv.Quote(info.Value)}}
-
- action, err := d.client.AddRRSetRecords(ctx, zone, "TXT", subDomainPunnycoded, d.config.TTL, records)
- if err != nil {
- return fmt.Errorf("hetzner: add RRSet records: %w", err)
- }
-
- err = d.waitAction(ctx, action.ID)
- if err != nil {
- return fmt.Errorf("hetzner: wait (add RRSet records): %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("hetzner: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("hetzner: %w", err)
- }
-
- subDomainPunnycoded, err := idna.ToASCII(dns01.UnFqdn(subDomain))
- if err != nil {
- return fmt.Errorf("hetzner: %w", err)
- }
-
- zone, err := idna.ToASCII(dns01.UnFqdn(authZone))
- if err != nil {
- return fmt.Errorf("hetzner: %w", err)
- }
-
- records := []internal.Record{{Value: strconv.Quote(info.Value)}}
-
- action, err := d.client.RemoveRRSetRecords(ctx, zone, "TXT", subDomainPunnycoded, records)
- if err != nil {
- return fmt.Errorf("hetzner: remove RRSet records: %w", err)
- }
-
- err = d.waitAction(ctx, action.ID)
- if err != nil {
- return fmt.Errorf("hetzner: wait (remove RRSet records): %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) waitAction(ctx context.Context, actionID int64) error {
- return wait.Retry(ctx,
- func() error {
- result, err := d.client.GetAction(ctx, actionID)
- if err != nil {
- return backoff.Permanent(fmt.Errorf("get action %d: %w", actionID, err))
- }
-
- switch result.Status {
- case internal.StatusRunning:
- return fmt.Errorf("action %d is %s", actionID, internal.StatusRunning)
-
- case internal.StatusError:
- return backoff.Permanent(fmt.Errorf("action %d: %s: %w", actionID, internal.StatusError, result.ErrorInfo))
-
- default:
- return nil
- }
- },
- backoff.WithBackOff(backoff.NewConstantBackOff(d.config.PollingInterval)),
- backoff.WithMaxElapsedTime(d.config.PropagationTimeout),
- )
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/hetznerv1_test.go b/providers/dns/hetzner/internal/hetznerv1/hetznerv1_test.go
deleted file mode 100644
index bf52baa35..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/hetznerv1_test.go
+++ /dev/null
@@ -1,232 +0,0 @@
-package hetznerv1
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIToken).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIToken: "secret",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "hetzner: some credentials information are missing: HETZNER_API_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiToken string
- expected string
- }{
- {
- desc: "success",
- apiToken: "secret",
- },
- {
- desc: "missing credentials",
- expected: "hetzner: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIToken = test.apiToken
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIToken = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- WithAuthorization("Bearer secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /zones/example.com/rrsets/_acme-challenge/TXT/actions/add_records",
- servermock.ResponseFromFixture("add_rrset_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("add_rrset_records-request.json")).
- Route("GET /actions/1",
- servermock.ResponseFromFixture("get_action_success.json")).
- Build(t)
-
- err := provider.Present("example.com", "", "foobar")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_Present_error(t *testing.T) {
- provider := mockBuilder().
- Route("POST /zones/example.com/rrsets/_acme-challenge/TXT/actions/add_records",
- servermock.ResponseFromFixture("add_rrset_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("add_rrset_records-request.json")).
- Route("GET /actions/1",
- servermock.ResponseFromFixture("get_action_error.json")).
- Build(t)
-
- provider.config.PollingInterval = 20 * time.Millisecond
- provider.config.PropagationTimeout = 1 * time.Second
-
- err := provider.Present("example.com", "", "foobar")
- require.EqualError(t, err, "hetzner: wait (add RRSet records): action 1: error: action_failed: Action failed")
-}
-
-func TestDNSProvider_Present_running(t *testing.T) {
- provider := mockBuilder().
- Route("POST /zones/example.com/rrsets/_acme-challenge/TXT/actions/add_records",
- servermock.ResponseFromFixture("add_rrset_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("add_rrset_records-request.json")).
- Route("GET /actions/1",
- servermock.ResponseFromFixture("get_action_running.json")).
- Build(t)
-
- provider.config.PollingInterval = 20 * time.Millisecond
- provider.config.PropagationTimeout = 1 * time.Second
-
- err := provider.Present("example.com", "", "foobar")
- require.EqualError(t, err, "hetzner: wait (add RRSet records): action 1 is running")
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("POST /zones/example.com/rrsets/_acme-challenge/TXT/actions/remove_records",
- servermock.ResponseFromFixture("remove_rrset_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("remove_rrset_records-request.json")).
- Route("GET /actions/1",
- servermock.ResponseFromFixture("get_action_success.json")).
- Build(t)
-
- err := provider.CleanUp("example.com", "", "foobar")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp_error(t *testing.T) {
- provider := mockBuilder().
- Route("POST /zones/example.com/rrsets/_acme-challenge/TXT/actions/remove_records",
- servermock.ResponseFromFixture("remove_rrset_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("remove_rrset_records-request.json")).
- Route("GET /actions/1",
- servermock.ResponseFromFixture("get_action_error.json")).
- Build(t)
-
- provider.config.PollingInterval = 20 * time.Millisecond
- provider.config.PropagationTimeout = 1 * time.Second
-
- err := provider.CleanUp("example.com", "", "foobar")
- require.EqualError(t, err, "hetzner: wait (remove RRSet records): action 1: error: action_failed: Action failed")
-}
-
-func TestDNSProvider_CleanUp_running(t *testing.T) {
- provider := mockBuilder().
- Route("POST /zones/example.com/rrsets/_acme-challenge/TXT/actions/remove_records",
- servermock.ResponseFromFixture("remove_rrset_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("remove_rrset_records-request.json")).
- Route("GET /actions/1",
- servermock.ResponseFromFixture("get_action_running.json")).
- Build(t)
-
- provider.config.PollingInterval = 20 * time.Millisecond
- provider.config.PropagationTimeout = 1 * time.Second
-
- err := provider.CleanUp("example.com", "", "foobar")
- require.EqualError(t, err, "hetzner: wait (remove RRSet records): action 1 is running")
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/client.go b/providers/dns/hetzner/internal/hetznerv1/internal/client.go
deleted file mode 100644
index 2f29f642a..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/client.go
+++ /dev/null
@@ -1,183 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "golang.org/x/oauth2"
-)
-
-const defaultBaseURL = "https://api.hetzner.cloud/v1"
-
-const (
- StatusRunning = "running"
- StatusSuccess = "success"
- StatusError = "error"
-)
-
-// Client the Hetzner API client.
-type Client struct {
- BaseURL *url.URL
- httpClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(hc *http.Client) (*Client, error) {
- baseURL, _ := url.Parse(defaultBaseURL)
-
- if hc == nil {
- hc = &http.Client{Timeout: 10 * time.Second}
- }
-
- return &Client{
- BaseURL: baseURL,
- httpClient: hc,
- }, nil
-}
-
-// AddRRSetRecords adds records to an RRSet.
-// https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-add-records-to-an-rrset
-func (c *Client) AddRRSetRecords(ctx context.Context, zoneIDName, recordType, recordName string, ttl int, records []Record) (*Action, error) {
- endpoint := c.BaseURL.JoinPath("zones", zoneIDName, "rrsets", recordName, recordType, "actions", "add_records")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, RRSet{TTL: ttl, Records: records})
- if err != nil {
- return nil, err
- }
-
- var result ActionResponse
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Action, nil
-}
-
-// RemoveRRSetRecords removes records from an RRSet.
-// https://docs.hetzner.cloud/reference/cloud#zone-rrset-actions-remove-records-from-an-rrset
-func (c *Client) RemoveRRSetRecords(ctx context.Context, zoneIDName, recordType, recordName string, records []Record) (*Action, error) {
- endpoint := c.BaseURL.JoinPath("zones", zoneIDName, "rrsets", recordName, recordType, "actions", "remove_records")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, RRSet{Records: records})
- if err != nil {
- return nil, err
- }
-
- var result ActionResponse
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Action, nil
-}
-
-// GetAction gets an action.
-// https://docs.hetzner.cloud/reference/cloud#actions-get-an-action
-func (c *Client) GetAction(ctx context.Context, id int64) (*Action, error) {
- endpoint := c.BaseURL.JoinPath("actions", strconv.FormatInt(id, 10))
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result ActionResponse
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Action, nil
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- resp, err := c.httpClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
-
-func OAuthStaticAccessToken(client *http.Client, accessToken string) *http.Client {
- if client == nil {
- client = &http.Client{Timeout: 5 * time.Second}
- }
-
- client.Transport = &oauth2.Transport{
- Source: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: accessToken}),
- Base: client.Transport,
- }
-
- return client
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/client_test.go b/providers/dns/hetzner/internal/hetznerv1/internal/client_test.go
deleted file mode 100644
index 6fd3d77a7..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/client_test.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(OAuthStaticAccessToken(server.Client(), "secret"))
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- WithAuthorization("Bearer secret"),
- )
-}
-
-func TestClient_AddRRSetRecords(t *testing.T) {
- client := mockBuilder().
- Route("POST /zones/example.com/rrsets/www/TXT/actions/add_records",
- servermock.ResponseFromFixture("add_rrset_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("add_rrset_records-request.json")).
- Build(t)
-
- records := []Record{{
- Value: "198.51.100.1",
- Comment: "My web server at Hetzner Cloud.",
- }}
-
- result, err := client.AddRRSetRecords(t.Context(), "example.com", "TXT", "www", 3600, records)
- require.NoError(t, err)
-
- expected := &Action{
- ID: 1,
- Command: "add_rrset_records",
- Status: "running",
- Progress: 50,
- Resources: []Resources{{ID: 590000000000000, Type: "zone"}},
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_AddRRSetRecords_error_invalid_input(t *testing.T) {
- client := mockBuilder().
- Route("POST /zones/example.com/rrsets/www/TXT/actions/add_records",
- servermock.ResponseFromFixture("error-invalid_input.json").
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- records := []Record{{
- Value: "198.51.100.1",
- Comment: "My web server at Hetzner Cloud.",
- }}
-
- _, err := client.AddRRSetRecords(t.Context(), "example.com", "TXT", "www", 0, records)
- require.EqualError(t, err, "invalid_input: invalid input in field 'broken_field': is too longfield: broken_field: is too long")
-}
-
-func TestClient_AddRRSetRecords_error_resource_limit_exceeded(t *testing.T) {
- client := mockBuilder().
- Route("POST /zones/example.com/rrsets/www/TXT/actions/add_records",
- servermock.ResponseFromFixture("error-resource_limit_exceeded.json").
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- records := []Record{{
- Value: "198.51.100.1",
- Comment: "My web server at Hetzner Cloud.",
- }}
-
- _, err := client.AddRRSetRecords(t.Context(), "example.com", "TXT", "www", 0, records)
- require.EqualError(t, err, "resource_limit_exceeded: project limit exceededlimit: project_limit")
-}
-
-func TestClient_AddRRSetRecords_error_deprecated_api_endpoint(t *testing.T) {
- client := mockBuilder().
- Route("POST /zones/example.com/rrsets/www/TXT/actions/add_records",
- servermock.ResponseFromFixture("error-deprecated_api_endpoint.json").
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- records := []Record{{
- Value: "198.51.100.1",
- Comment: "My web server at Hetzner Cloud.",
- }}
-
- _, err := client.AddRRSetRecords(t.Context(), "example.com", "TXT", "www", 0, records)
- require.EqualError(t, err, "deprecated_api_endpoint: API functionality was removed: https://docs.hetzner.cloud/changelog#2023-07-20-foo-endpoint-is-deprecated")
-}
-
-func TestClient_RemoveRRSetRecords(t *testing.T) {
- client := mockBuilder().
- Route("POST /zones/example.com/rrsets/www/TXT/actions/remove_records",
- servermock.ResponseFromFixture("remove_rrset_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("remove_rrset_records-request.json")).
- Build(t)
-
- records := []Record{{
- Value: "198.51.100.1",
- Comment: "My web server at Hetzner Cloud.",
- }}
-
- result, err := client.RemoveRRSetRecords(t.Context(), "example.com", "TXT", "www", records)
- require.NoError(t, err)
-
- expected := &Action{
- ID: 1,
- Command: "remove_rrset_records",
- Status: "running",
- Progress: 50,
- Resources: []Resources{{ID: 42, Type: "zone"}},
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_GetAction(t *testing.T) {
- client := mockBuilder().
- Route("GET /actions/123", servermock.ResponseFromFixture("get_action.json")).
- Route("/", servermock.DumpRequest()).
- Build(t)
-
- result, err := client.GetAction(t.Context(), 123)
- require.NoError(t, err)
-
- expected := &Action{
- ID: 590000000000000,
- Command: "start_resource",
- Status: "running",
- Progress: 100,
- Resources: []Resources{{ID: 590000000000000, Type: "server"}},
- ErrorInfo: &ErrorInfo{
- Code: "action_failed",
- Message: "Action failed",
- },
- }
-
- assert.Equal(t, expected, result)
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/add_rrset_records-request.json b/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/add_rrset_records-request.json
deleted file mode 100644
index cba0f34d3..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/add_rrset_records-request.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "ttl": 3600,
- "records": [
- {
- "value": "198.51.100.1",
- "comment": "My web server at Hetzner Cloud."
- }
- ]
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/add_rrset_records.json b/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/add_rrset_records.json
deleted file mode 100644
index 7267b02cb..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/add_rrset_records.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "action": {
- "id": 1,
- "command": "add_rrset_records",
- "status": "running",
- "progress": 50,
- "started": "2016-01-30T23:55:00+00:00",
- "finished": null,
- "resources": [
- {
- "id": 590000000000000,
- "type": "zone"
- }
- ],
- "error": null
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-deprecated_api_endpoint.json b/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-deprecated_api_endpoint.json
deleted file mode 100644
index 4d8fb945d..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-deprecated_api_endpoint.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "error": {
- "code": "deprecated_api_endpoint",
- "message": "API functionality was removed",
- "details": {
- "announcement": "https://docs.hetzner.cloud/changelog#2023-07-20-foo-endpoint-is-deprecated"
- }
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-invalid_input.json b/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-invalid_input.json
deleted file mode 100644
index e05bf7a3e..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-invalid_input.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "error": {
- "code": "invalid_input",
- "message": "invalid input in field 'broken_field': is too long",
- "details": {
- "fields": [
- {
- "name": "broken_field",
- "messages": [
- "is too long"
- ]
- }
- ]
- }
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-resource_limit_exceeded.json b/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-resource_limit_exceeded.json
deleted file mode 100644
index 9072d10e3..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/error-resource_limit_exceeded.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "error": {
- "code": "resource_limit_exceeded",
- "message": "project limit exceeded",
- "details": {
- "limits": [
- {
- "name": "project_limit"
- }
- ]
- }
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/get_action.json b/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/get_action.json
deleted file mode 100644
index 19278fc51..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/get_action.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "action": {
- "id": 590000000000000,
- "command": "start_resource",
- "status": "running",
- "started": "2016-01-30T23:55:00+00:00",
- "finished": "2016-01-30T23:55:00+00:00",
- "progress": 100,
- "resources": [
- {
- "id": 590000000000000,
- "type": "server"
- }
- ],
- "error": {
- "code": "action_failed",
- "message": "Action failed"
- }
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/remove_rrset_records-request.json b/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/remove_rrset_records-request.json
deleted file mode 100644
index 778e051b4..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/remove_rrset_records-request.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "records": [
- {
- "value": "198.51.100.1",
- "comment": "My web server at Hetzner Cloud."
- }
- ]
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/remove_rrset_records.json b/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/remove_rrset_records.json
deleted file mode 100644
index 1b10dfd5e..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/fixtures/remove_rrset_records.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "action": {
- "id": 1,
- "command": "remove_rrset_records",
- "status": "running",
- "progress": 50,
- "started": "2016-01-30T23:55:00+00:00",
- "finished": null,
- "resources": [
- {
- "id": 42,
- "type": "zone"
- }
- ],
- "error": null
- }
-}
diff --git a/providers/dns/hetzner/internal/hetznerv1/internal/types.go b/providers/dns/hetzner/internal/hetznerv1/internal/types.go
deleted file mode 100644
index 2b38a8a8c..000000000
--- a/providers/dns/hetzner/internal/hetznerv1/internal/types.go
+++ /dev/null
@@ -1,98 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strings"
-)
-
-type APIError struct {
- ErrorInfo ErrorInfo `json:"error"`
-}
-
-type ErrorInfo struct {
- Code string `json:"code,omitempty"`
- Message string `json:"message,omitempty"`
- Details ErrorDetails `json:"details"`
-}
-
-func (i *ErrorInfo) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "%s: %s", i.Code, i.Message)
-
- if i.Details.Announcement != "" {
- _, _ = fmt.Fprintf(msg, ": %s", i.Details.Announcement)
- }
-
- for _, limit := range i.Details.Limits {
- _, _ = fmt.Fprintf(msg, "limit: %s", limit.Name)
- }
-
- for _, field := range i.Details.Fields {
- _, _ = fmt.Fprintf(msg, "field: %s: %s", field.Name, strings.Join(field.Messages, ", "))
- }
-
- return msg.String()
-}
-
-type ErrorDetails struct {
- Announcement string `json:"announcement,omitempty"`
- Limits []LimitError `json:"limits,omitempty"`
- Fields []FieldError `json:"fields,omitempty"`
-}
-
-type FieldError struct {
- Name string `json:"name,omitempty"`
- Messages []string `json:"messages,omitempty"`
-}
-
-type LimitError struct {
- Name string `json:"name,omitempty"`
-}
-
-func (a *APIError) Error() string {
- return a.ErrorInfo.Error()
-}
-
-type RRSet struct {
- ID string `json:"id,omitempty"`
- Name string `json:"name,omitempty"`
- Type string `json:"type,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Labels map[string]string `json:"labels,omitempty"`
- Protection *Protection `json:"protection,omitempty"`
- Records []Record `json:"records,omitempty"`
- ZoneID int `json:"zone,omitempty"`
-}
-
-type Protection struct {
- Change bool `json:"change,omitempty"`
-}
-
-type Record struct {
- Value string `json:"value,omitempty"`
- Comment string `json:"comment,omitempty"`
-}
-
-type ActionResponse struct {
- Action *Action `json:"action,omitempty"`
-}
-
-type Action struct {
- ID int64 `json:"id,omitempty"`
- Command string `json:"command,omitempty"`
-
- // It can be: `running`, `success`, `error`.
- // https://docs.hetzner.cloud/reference/cloud#zone-actions-get-an-action
- // https://docs.hetzner.cloud/reference/cloud#zone-actions
- Status string `json:"status,omitempty"`
- Progress int `json:"progress,omitempty"`
-
- Resources []Resources `json:"resources,omitempty"`
- ErrorInfo *ErrorInfo `json:"error,omitempty"`
-}
-
-type Resources struct {
- ID int64 `json:"id,omitempty"`
- Type string `json:"type,omitempty"`
-}
diff --git a/providers/dns/hetzner/internal/legacy/hetzner.go b/providers/dns/hetzner/internal/legacy/hetzner.go
deleted file mode 100644
index 393a3d671..000000000
--- a/providers/dns/hetzner/internal/legacy/hetzner.go
+++ /dev/null
@@ -1,177 +0,0 @@
-// Package legacy implements a DNS provider for solving the DNS-01 challenge using Hetzner DNS.
-package legacy
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/hetzner/internal/legacy/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "HETZNER_"
-
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-const minTTL = 60
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for hetzner.
-// Credentials must be passed in the environment variable: HETZNER_API_KEY.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("hetzner (legacy): %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for hetzner.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("hetzner (legacy): the configuration of the DNS provider is nil")
- }
-
- if config.APIKey == "" {
- return nil, errors.New("hetzner (legacy): credentials missing")
- }
-
- if config.TTL < minTTL {
- return nil, fmt.Errorf("hetzner (legacy): invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
- }
-
- client := internal.NewClient(config.APIKey)
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{config: config, client: client}, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record to fulfill the dns-01 challenge.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("hetzner (legacy): could not find zone for domain %q: %w", domain, err)
- }
-
- zone := dns01.UnFqdn(authZone)
-
- ctx := context.Background()
-
- zoneID, err := d.client.GetZoneID(ctx, zone)
- if err != nil {
- return fmt.Errorf("hetzner (legacy): %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
- if err != nil {
- return fmt.Errorf("hetzner (legacy): %w", err)
- }
-
- record := internal.DNSRecord{
- Type: "TXT",
- Name: subDomain,
- Value: info.Value,
- TTL: d.config.TTL,
- ZoneID: zoneID,
- }
-
- if err := d.client.CreateRecord(ctx, record); err != nil {
- return fmt.Errorf("hetzner (legacy): failed to add TXT record: fqdn=%s, zoneID=%s: %w", info.EffectiveFQDN, zoneID, err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("hetzner (legacy): could not find zone for domain %q: %w", domain, err)
- }
-
- zone := dns01.UnFqdn(authZone)
-
- ctx := context.Background()
-
- zoneID, err := d.client.GetZoneID(ctx, zone)
- if err != nil {
- return fmt.Errorf("hetzner (legacy): %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
- if err != nil {
- return fmt.Errorf("hetzner (legacy): %w", err)
- }
-
- record, err := d.client.GetTxtRecord(ctx, subDomain, info.Value, zoneID)
- if err != nil {
- return fmt.Errorf("hetzner (legacy): %w", err)
- }
-
- if err := d.client.DeleteRecord(ctx, record.ID); err != nil {
- return fmt.Errorf("hetzner (legacy): failed to delete TXT record: id=%s, name=%s: %w", record.ID, record.Name, err)
- }
-
- return nil
-}
diff --git a/providers/dns/hetzner/internal/legacy/hetzner_test.go b/providers/dns/hetzner/internal/legacy/hetzner_test.go
deleted file mode 100644
index c9258ecf8..000000000
--- a/providers/dns/hetzner/internal/legacy/hetzner_test.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package legacy
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvAPIKey).
- WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIKey: "123",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{
- EnvAPIKey: "",
- },
- expected: "hetzner (legacy): some credentials information are missing: HETZNER_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- ttl int
- expected string
- }{
- {
- desc: "success",
- ttl: minTTL,
- apiKey: "123",
- },
- {
- desc: "missing credentials",
- ttl: minTTL,
- expected: "hetzner (legacy): credentials missing",
- },
- {
- desc: "invalid TTL",
- apiKey: "123",
- ttl: 10,
- expected: "hetzner (legacy): invalid TTL, TTL (10) must be greater than 60",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIKey = test.apiKey
- config.TTL = test.ttl
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/hetzner/internal/legacy/internal/types.go b/providers/dns/hetzner/internal/types.go
similarity index 91%
rename from providers/dns/hetzner/internal/legacy/internal/types.go
rename to providers/dns/hetzner/internal/types.go
index 3b332cc8f..d0e284511 100644
--- a/providers/dns/hetzner/internal/legacy/internal/types.go
+++ b/providers/dns/hetzner/internal/types.go
@@ -25,12 +25,12 @@ type Zone struct {
// Zones a set of DNS zones.
type Zones struct {
Zones []Zone `json:"zones"`
- Meta Meta `json:"meta"`
+ Meta Meta `json:"meta,omitempty"`
}
// Meta response metadata.
type Meta struct {
- Pagination Pagination `json:"pagination"`
+ Pagination Pagination `json:"pagination,omitempty"`
}
// Pagination information about pagination.
diff --git a/providers/dns/hostingde/hostingde.go b/providers/dns/hostingde/hostingde.go
index 1e022b630..87fc73d34 100644
--- a/providers/dns/hostingde/hostingde.go
+++ b/providers/dns/hostingde/hostingde.go
@@ -2,9 +2,11 @@
package hostingde
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "sync"
"time"
"github.com/go-acme/lego/v4/challenge"
@@ -29,7 +31,14 @@ const (
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
-type Config = hostingde.Config
+type Config struct {
+ APIKey string
+ ZoneName string
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
@@ -46,7 +55,11 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *hostingde.Client
+
+ recordIDs map[string]string
+ recordIDsMu sync.Mutex
}
// NewDNSProvider returns a DNSProvider instance configured for hosting.de.
@@ -70,36 +83,140 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("hostingde: the configuration of the DNS provider is nil")
}
- provider, err := hostingde.NewDNSProviderConfig(config, "")
- if err != nil {
- return nil, fmt.Errorf("hostingde: %w", err)
+ if config.APIKey == "" {
+ return nil, errors.New("hostingde: API key missing")
}
- return &DNSProvider{prv: provider}, nil
+ return &DNSProvider{
+ config: config,
+ client: hostingde.NewClient(config.APIKey),
+ recordIDs: make(map[string]string),
+ }, nil
}
-// Present creates a TXT record using the specified parameters.
+// Timeout returns the timeout and interval to use when checking for DNS propagation.
+// Adjusting here to cope with spikes in propagation times.
+func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
+ return d.config.PropagationTimeout, d.config.PollingInterval
+}
+
+// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ zoneName, err := d.getZoneName(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("hostingde: could not find zone for domain %q: %w", domain, err)
+ }
+
+ ctx := context.Background()
+
+ // get the ZoneConfig for that domain
+ zonesFind := hostingde.ZoneConfigsFindRequest{
+ Filter: hostingde.Filter{Field: "zoneName", Value: zoneName},
+ Limit: 1,
+ Page: 1,
+ }
+
+ zoneConfig, err := d.client.GetZone(ctx, zonesFind)
if err != nil {
return fmt.Errorf("hostingde: %w", err)
}
+ zoneConfig.Name = zoneName
+
+ rec := []hostingde.DNSRecord{{
+ Type: "TXT",
+ Name: dns01.UnFqdn(info.EffectiveFQDN),
+ Content: info.Value,
+ TTL: d.config.TTL,
+ }}
+
+ req := hostingde.ZoneUpdateRequest{
+ ZoneConfig: *zoneConfig,
+ RecordsToAdd: rec,
+ }
+
+ response, err := d.client.UpdateZone(ctx, req)
+ if err != nil {
+ return fmt.Errorf("hostingde: %w", err)
+ }
+
+ for _, record := range response.Records {
+ if record.Name == dns01.UnFqdn(info.EffectiveFQDN) && record.Content == fmt.Sprintf(`%q`, info.Value) {
+ d.recordIDsMu.Lock()
+ d.recordIDs[info.EffectiveFQDN] = record.ID
+ d.recordIDsMu.Unlock()
+ }
+ }
+
+ if d.recordIDs[info.EffectiveFQDN] == "" {
+ return fmt.Errorf("hostingde: error getting ID of just created record, for domain %s", domain)
+ }
+
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ zoneName, err := d.getZoneName(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("hostingde: could not find zone for domain %q: %w", domain, err)
+ }
+
+ ctx := context.Background()
+
+ // get the ZoneConfig for that domain
+ zonesFind := hostingde.ZoneConfigsFindRequest{
+ Filter: hostingde.Filter{Field: "zoneName", Value: zoneName},
+ Limit: 1,
+ Page: 1,
+ }
+
+ zoneConfig, err := d.client.GetZone(ctx, zonesFind)
if err != nil {
return fmt.Errorf("hostingde: %w", err)
}
+ zoneConfig.Name = zoneName
+ rec := []hostingde.DNSRecord{{
+ Type: "TXT",
+ Name: dns01.UnFqdn(info.EffectiveFQDN),
+ Content: `"` + info.Value + `"`,
+ }}
+
+ req := hostingde.ZoneUpdateRequest{
+ ZoneConfig: *zoneConfig,
+ RecordsToDelete: rec,
+ }
+
+ // Delete record ID from map
+ d.recordIDsMu.Lock()
+ delete(d.recordIDs, info.EffectiveFQDN)
+ d.recordIDsMu.Unlock()
+
+ _, err = d.client.UpdateZone(ctx, req)
+ if err != nil {
+ return fmt.Errorf("hostingde: %w", err)
+ }
return nil
}
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+func (d *DNSProvider) getZoneName(fqdn string) (string, error) {
+ if d.config.ZoneName != "" {
+ return d.config.ZoneName, nil
+ }
+
+ zoneName, err := dns01.FindZoneByFqdn(fqdn)
+ if err != nil {
+ return "", fmt.Errorf("could not find zone for %s: %w", fqdn, err)
+ }
+
+ if zoneName == "" {
+ return "", errors.New("empty zone name")
+ }
+
+ return dns01.UnFqdn(zoneName), nil
}
diff --git a/providers/dns/hostingde/hostingde.toml b/providers/dns/hostingde/hostingde.toml
index 502a7fe9e..569e8a781 100644
--- a/providers/dns/hostingde/hostingde.toml
+++ b/providers/dns/hostingde/hostingde.toml
@@ -6,7 +6,7 @@ Since = "v1.1.0"
Example = '''
HOSTINGDE_API_KEY=xxxxxxxx \
-lego --dns hostingde -d '*.example.com' -d example.com run
+lego --email you@example.com --dns hostingde -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/hostingde/hostingde_test.go b/providers/dns/hostingde/hostingde_test.go
index a92006f81..d7681f953 100644
--- a/providers/dns/hostingde/hostingde_test.go
+++ b/providers/dns/hostingde/hostingde_test.go
@@ -49,7 +49,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -59,7 +58,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.recordIDs)
} else {
require.EqualError(t, err, test.expected)
}
@@ -101,7 +101,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.recordIDs)
} else {
require.EqualError(t, err, test.expected)
}
@@ -115,7 +116,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -129,7 +129,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/hostinger/hostinger.go b/providers/dns/hostinger/hostinger.go
deleted file mode 100644
index 13d9ed0f8..000000000
--- a/providers/dns/hostinger/hostinger.go
+++ /dev/null
@@ -1,211 +0,0 @@
-// Package hostinger implements a DNS provider for solving the DNS-01 challenge using Hostinger.
-package hostinger
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/hostinger/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "HOSTINGER_"
-
- EnvAPIToken = envNamespace + "API_TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIToken string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Hostinger.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIToken)
- if err != nil {
- return nil, fmt.Errorf("hostinger: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIToken = values[EnvAPIToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Hostinger.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("hostinger: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIToken)
- if err != nil {
- return nil, fmt.Errorf("hostinger: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("hostinger: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("hostinger: %w", err)
- }
-
- ctx := context.Background()
-
- request := internal.ZoneRequest{
- Overwrite: false,
- Zone: []internal.RecordSet{{
- Name: subDomain,
- Type: "TXT",
- TTL: d.config.TTL,
- Records: []internal.Record{
- {Content: info.Value},
- },
- }},
- }
-
- err = d.client.UpdateDNSRecords(ctx, dns01.UnFqdn(authZone), request)
- if err != nil {
- return fmt.Errorf("hostinger: update DNS records (add): %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("hostinger: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("hostinger: %w", err)
- }
-
- ctx := context.Background()
-
- recordSet, err := d.findRecordSet(ctx, authZone, subDomain)
- if err != nil {
- return fmt.Errorf("hostinger: %w", err)
- }
-
- var newRecords []internal.Record
-
- for _, record := range recordSet.Records {
- if record.Content == info.Value || record.Content == strconv.Quote(info.Value) {
- continue
- }
-
- newRecords = append(newRecords, record)
- }
-
- recordSet.Records = newRecords
-
- if len(recordSet.Records) > 0 {
- request := internal.ZoneRequest{
- Overwrite: true,
- Zone: []internal.RecordSet{recordSet},
- }
-
- err = d.client.UpdateDNSRecords(ctx, dns01.UnFqdn(authZone), request)
- if err != nil {
- return fmt.Errorf("hostinger: update DNS records (delete): %w", err)
- }
-
- return nil
- }
-
- filters := []internal.Filter{{
- Name: subDomain,
- Type: "TXT",
- }}
-
- err = d.client.DeleteDNSRecords(ctx, dns01.UnFqdn(authZone), filters)
- if err != nil {
- return fmt.Errorf("hostinger: delete DNS records: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findRecordSet(ctx context.Context, authZone, subDomain string) (internal.RecordSet, error) {
- recordSets, err := d.client.GetDNSRecords(ctx, dns01.UnFqdn(authZone))
- if err != nil {
- return internal.RecordSet{}, fmt.Errorf("get DNS records: %w", err)
- }
-
- for _, recordSet := range recordSets {
- if recordSet.Name != subDomain || recordSet.Type != "TXT" {
- continue
- }
-
- return recordSet, nil
- }
-
- return internal.RecordSet{}, fmt.Errorf("no record found for domain %q and subdomain %q", authZone, subDomain)
-}
diff --git a/providers/dns/hostinger/hostinger.toml b/providers/dns/hostinger/hostinger.toml
deleted file mode 100644
index a6f152e73..000000000
--- a/providers/dns/hostinger/hostinger.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Hostinger"
-Description = ''''''
-URL = "https://www.hostinger.com/"
-Code = "hostinger"
-Since = "v4.27.0"
-
-Example = '''
-HOSTINGER_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns hostinger -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- HOSTINGER_API_TOKEN = "API Token"
- [Configuration.Additional]
- HOSTINGER_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- HOSTINGER_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- HOSTINGER_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- HOSTINGER_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://developers.hostinger.com/#tag/dns-zone"
diff --git a/providers/dns/hostinger/hostinger_test.go b/providers/dns/hostinger/hostinger_test.go
deleted file mode 100644
index 90ecba529..000000000
--- a/providers/dns/hostinger/hostinger_test.go
+++ /dev/null
@@ -1,180 +0,0 @@
-package hostinger
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIToken).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIToken: "secret",
- },
- },
- {
- desc: "missing API token",
- envVars: map[string]string{
- EnvAPIToken: "",
- },
- expected: "hostinger: some credentials information are missing: HOSTINGER_API_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiToken string
- expected string
- }{
- {
- desc: "success",
- apiToken: "secret",
- },
- {
- desc: "missing API token",
- expected: "hostinger: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIToken = test.apiToken
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIToken = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- WithAuthorization("Bearer secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("PUT /api/dns/v1/zones/example.com",
- servermock.ResponseFromInternal("update_dns_records.json"),
- servermock.CheckRequestJSONBodyFromInternal("update_dns_records-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp_update(t *testing.T) {
- provider := mockBuilder().
- Route("GET /api/dns/v1/zones/example.com",
- servermock.ResponseFromInternal("get_dns_records_acme.json")).
- Route("PUT /api/dns/v1/zones/example.com",
- servermock.ResponseFromInternal("update_dns_records.json"),
- servermock.CheckRequestJSONBodyFromInternal("update_dns_records_base-request.json")).
- Build(t)
-
- err := provider.CleanUp("example.com", "", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp_delete(t *testing.T) {
- provider := mockBuilder().
- Route("GET /api/dns/v1/zones/example.com",
- servermock.ResponseFromInternal("get_dns_records_empty.json")).
- Route("DELETE /api/dns/v1/zones/example.com",
- servermock.ResponseFromInternal("delete_dns_records.json"),
- servermock.CheckRequestJSONBody(`{"filters":[{"name":"_acme-challenge","type":"TXT"}]}`)).
- Build(t)
-
- err := provider.CleanUp("example.com", "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/hostinger/internal/client.go b/providers/dns/hostinger/internal/client.go
deleted file mode 100644
index 9da712d61..000000000
--- a/providers/dns/hostinger/internal/client.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
-)
-
-const defaultBaseURL = "https://developers.hostinger.com"
-
-const authorizationHeader = "Authorization"
-
-// Client the Hostinger API client.
-type Client struct {
- token string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(token string) (*Client, error) {
- if token == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- token: token,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-// GetDNSRecords retrieves DNS zone records for a specific domain.
-// https://developers.hostinger.com/#tag/dns-zone/get/api/dns/v1/zones/{domain}
-func (c *Client) GetDNSRecords(ctx context.Context, domain string) ([]RecordSet, error) {
- endpoint := c.BaseURL.JoinPath("/api/dns/v1/zones/", domain)
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result []RecordSet
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// UpdateDNSRecords updates DNS records for the selected domain.
-// https://developers.hostinger.com/#tag/dns-zone/put/api/dns/v1/zones/{domain}
-func (c *Client) UpdateDNSRecords(ctx context.Context, domain string, zone ZoneRequest) error {
- endpoint := c.BaseURL.JoinPath("/api/dns/v1/zones/", domain)
-
- req, err := newJSONRequest(ctx, http.MethodPut, endpoint, zone)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-// DeleteDNSRecords deletes DNS records for the selected domain.
-// https://developers.hostinger.com/#tag/dns-zone/delete/api/dns/v1/zones/{domain}
-func (c *Client) DeleteDNSRecords(ctx context.Context, domain string, filters []Filter) error {
- endpoint := c.BaseURL.JoinPath("/api/dns/v1/zones/", domain)
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, Filters{Filters: filters})
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- req.Header.Set(authorizationHeader, "Bearer "+c.token)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
diff --git a/providers/dns/hostinger/internal/client_test.go b/providers/dns/hostinger/internal/client_test.go
deleted file mode 100644
index 69cab5587..000000000
--- a/providers/dns/hostinger/internal/client_test.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().WithJSONHeaders().
- With("Authorization", "Bearer secret"),
- )
-}
-
-func TestClient_GetDNSRecords(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/dns/v1/zones/example.com",
- servermock.ResponseFromFixture("get_dns_records.json")).
- Build(t)
-
- records, err := client.GetDNSRecords(t.Context(), "example.com")
- require.NoError(t, err)
-
- expected := []RecordSet{
- {
- Name: "_acme-challenge",
- Records: []Record{{
- Content: "aaa",
- }},
- TTL: 14400,
- Type: "TXT",
- },
- {
- Name: "_acme-challenge",
- Records: []Record{{
- Content: "example.com.",
- }},
- TTL: 14400,
- Type: "A",
- },
- }
-
- assert.Equal(t, expected, records)
-}
-
-func TestClient_GetDNSRecords_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/dns/v1/zones/example.com",
- servermock.ResponseFromFixture("error_401.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- _, err := client.GetDNSRecords(t.Context(), "example.com")
-
- require.EqualError(t, err, "26a91bd9-f8c8-4a83-9df9-83e23d696fe3: Unauthenticated")
-}
-
-func TestClient_UpdateDNSRecords(t *testing.T) {
- client := mockBuilder().
- Route("PUT /api/dns/v1/zones/example.com",
- servermock.ResponseFromFixture("update_dns_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("update_dns_records-request.json")).
- Build(t)
-
- zone := ZoneRequest{
- Overwrite: false,
- Zone: []RecordSet{
- {
- Name: "_acme-challenge",
- Records: []Record{
- {Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"},
- },
- TTL: 120,
- Type: "TXT",
- },
- },
- }
-
- err := client.UpdateDNSRecords(t.Context(), "example.com", zone)
- require.NoError(t, err)
-}
-
-func TestClient_UpdateDNSRecords_error(t *testing.T) {
- client := mockBuilder().
- Route("PUT /api/dns/v1/zones/example.com",
- servermock.ResponseFromFixture("error_422.json").
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- zone := ZoneRequest{
- Zone: []RecordSet{{
- Name: "_acme-challenge",
- Records: []Record{{
- Content: "aaa",
- }},
- TTL: 14400,
- Type: "TXT",
- }},
- }
-
- err := client.UpdateDNSRecords(t.Context(), "example.com", zone)
-
- require.EqualError(t, err, "26a91bd9-f8c8-4a83-9df9-83e23d696fe3: The name field is required. (and 1 more error): field_1: The field_1 field is required., The field_1 must be a number.")
-}
-
-func TestClient_DeleteDNSRecords(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /api/dns/v1/zones/example.com",
- servermock.ResponseFromFixture("delete_dns_records.json"),
- servermock.CheckRequestJSONBody(`{"filters":[{"name":"_acme-challenge","type":"TXT"}]}`)).
- Build(t)
-
- filters := []Filter{{
- Name: "_acme-challenge",
- Type: "TXT",
- }}
-
- err := client.DeleteDNSRecords(t.Context(), "example.com", filters)
- require.NoError(t, err)
-}
-
-func TestClient_DeleteDNSRecords_error(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /api/dns/v1/zones/example.com",
- servermock.ResponseFromFixture("error_401.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- filters := []Filter{{
- Name: "_acme-challenge",
- Type: "TXT",
- }}
-
- err := client.DeleteDNSRecords(t.Context(), "example.com", filters)
-
- require.EqualError(t, err, "26a91bd9-f8c8-4a83-9df9-83e23d696fe3: Unauthenticated")
-}
diff --git a/providers/dns/hostinger/internal/fixtures/delete_dns_records.json b/providers/dns/hostinger/internal/fixtures/delete_dns_records.json
deleted file mode 100644
index 11d2582b4..000000000
--- a/providers/dns/hostinger/internal/fixtures/delete_dns_records.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "message": "Request accepted"
-}
diff --git a/providers/dns/hostinger/internal/fixtures/error_401.json b/providers/dns/hostinger/internal/fixtures/error_401.json
deleted file mode 100644
index 1b7381ff6..000000000
--- a/providers/dns/hostinger/internal/fixtures/error_401.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "message": "Unauthenticated",
- "correlation_id": "26a91bd9-f8c8-4a83-9df9-83e23d696fe3"
-}
diff --git a/providers/dns/hostinger/internal/fixtures/error_422.json b/providers/dns/hostinger/internal/fixtures/error_422.json
deleted file mode 100644
index 6ec286823..000000000
--- a/providers/dns/hostinger/internal/fixtures/error_422.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "message": "The name field is required. (and 1 more error)",
- "errors": {
- "field_1": [
- "The field_1 field is required.",
- "The field_1 must be a number."
- ]
- },
- "correlation_id": "26a91bd9-f8c8-4a83-9df9-83e23d696fe3"
-}
diff --git a/providers/dns/hostinger/internal/fixtures/get_dns_records.json b/providers/dns/hostinger/internal/fixtures/get_dns_records.json
deleted file mode 100644
index e51edd4dc..000000000
--- a/providers/dns/hostinger/internal/fixtures/get_dns_records.json
+++ /dev/null
@@ -1,24 +0,0 @@
-[
- {
- "name": "_acme-challenge",
- "records": [
- {
- "content": "aaa",
- "is_disabled": false
- }
- ],
- "ttl": 14400,
- "type": "TXT"
- },
- {
- "name": "_acme-challenge",
- "records": [
- {
- "content": "example.com.",
- "is_disabled": false
- }
- ],
- "ttl": 14400,
- "type": "A"
- }
-]
diff --git a/providers/dns/hostinger/internal/fixtures/get_dns_records_acme.json b/providers/dns/hostinger/internal/fixtures/get_dns_records_acme.json
deleted file mode 100644
index 99a574514..000000000
--- a/providers/dns/hostinger/internal/fixtures/get_dns_records_acme.json
+++ /dev/null
@@ -1,27 +0,0 @@
-[
- {
- "name": "_acme-challenge",
- "records": [
- {
- "content": "aaa",
- "is_disabled": false
- },
- {
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- }
- ],
- "ttl": 14400,
- "type": "TXT"
- },
- {
- "name": "_acme-challenge",
- "records": [
- {
- "content": "example.com.",
- "is_disabled": false
- }
- ],
- "ttl": 14400,
- "type": "A"
- }
-]
diff --git a/providers/dns/hostinger/internal/fixtures/get_dns_records_empty.json b/providers/dns/hostinger/internal/fixtures/get_dns_records_empty.json
deleted file mode 100644
index 9989a3fc4..000000000
--- a/providers/dns/hostinger/internal/fixtures/get_dns_records_empty.json
+++ /dev/null
@@ -1,23 +0,0 @@
-[
- {
- "name": "_acme-challenge",
- "records": [
- {
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- }
- ],
- "ttl": 14400,
- "type": "TXT"
- },
- {
- "name": "_acme-challenge",
- "records": [
- {
- "content": "example.com.",
- "is_disabled": false
- }
- ],
- "ttl": 14400,
- "type": "A"
- }
-]
diff --git a/providers/dns/hostinger/internal/fixtures/update_dns_records-request.json b/providers/dns/hostinger/internal/fixtures/update_dns_records-request.json
deleted file mode 100644
index 6f287b3fc..000000000
--- a/providers/dns/hostinger/internal/fixtures/update_dns_records-request.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "overwrite": false,
- "zone": [
- {
- "name": "_acme-challenge",
- "records": [
- {
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- }
- ],
- "ttl": 120,
- "type": "TXT"
- }
- ]
-}
diff --git a/providers/dns/hostinger/internal/fixtures/update_dns_records.json b/providers/dns/hostinger/internal/fixtures/update_dns_records.json
deleted file mode 100644
index 11d2582b4..000000000
--- a/providers/dns/hostinger/internal/fixtures/update_dns_records.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "message": "Request accepted"
-}
diff --git a/providers/dns/hostinger/internal/fixtures/update_dns_records_base-request.json b/providers/dns/hostinger/internal/fixtures/update_dns_records_base-request.json
deleted file mode 100644
index c42ddc6d7..000000000
--- a/providers/dns/hostinger/internal/fixtures/update_dns_records_base-request.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "overwrite": true,
- "zone": [
- {
- "name": "_acme-challenge",
- "records": [
- {
- "content": "aaa"
- }
- ],
- "ttl": 14400,
- "type": "TXT"
- }
- ]
-}
diff --git a/providers/dns/hostinger/internal/types.go b/providers/dns/hostinger/internal/types.go
deleted file mode 100644
index c1a02ff8c..000000000
--- a/providers/dns/hostinger/internal/types.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strings"
-)
-
-type APIError struct {
- Message string `json:"message,omitempty"`
- Errors map[string][]string `json:"errors,omitempty"`
- CorrelationID string `json:"correlation_id,omitempty"`
-}
-
-func (a *APIError) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "%s: %s", a.CorrelationID, a.Message)
-
- for field, values := range a.Errors {
- _, _ = fmt.Fprintf(msg, ": %s: %s", field, strings.Join(values, ", "))
- }
-
- return msg.String()
-}
-
-type ZoneRequest struct {
- Overwrite bool `json:"overwrite"`
- Zone []RecordSet `json:"zone,omitempty"`
-}
-
-type RecordSet struct {
- Name string `json:"name,omitempty"`
- Records []Record `json:"records,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Type string `json:"type,omitempty"`
-}
-
-type Record struct {
- Content string `json:"content,omitempty"`
- IsDisabled bool `json:"is_disabled,omitempty"`
-}
-
-type Filters struct {
- Filters []Filter `json:"filters"`
-}
-
-type Filter struct {
- Name string `json:"name"`
- Type string `json:"type"`
-}
diff --git a/providers/dns/hostingnl/hostingnl.go b/providers/dns/hostingnl/hostingnl.go
deleted file mode 100644
index a49941817..000000000
--- a/providers/dns/hostingnl/hostingnl.go
+++ /dev/null
@@ -1,168 +0,0 @@
-// Package hostingnl implements a DNS provider for solving the DNS-01 challenge using hosting.nl.
-package hostingnl
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "strconv"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/hostingnl/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Environment variables names.
-const (
- envNamespace = "HOSTINGNL_"
-
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
- HTTPClient *http.Client
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 10*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- recordIDs map[string]string
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for hosting.nl.
-// Credentials must be passed in the environment variables:
-// HOSTINGNL_APIKEY.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("hostingnl: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for hosting.nl.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("hostingnl: the configuration of the DNS provider is nil")
- }
-
- if config.APIKey == "" {
- return nil, errors.New("hostingnl: APIKey is missing")
- }
-
- client := internal.NewClient(config.APIKey)
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]string),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("hostingnl: could not find zone for domain %q: %w", domain, err)
- }
-
- record := internal.Record{
- Name: dns01.UnFqdn(info.EffectiveFQDN),
- Type: "TXT",
- Content: strconv.Quote(info.Value),
- TTL: d.config.TTL,
- Priority: 0,
- }
-
- newRecord, err := d.client.AddRecord(context.Background(), dns01.UnFqdn(authZone), record)
- if err != nil {
- return fmt.Errorf("hostingnl: failed to create TXT record, fqdn=%s: %w", info.EffectiveFQDN, err)
- }
-
- d.recordIDsMu.Lock()
- d.recordIDs[token] = newRecord.ID
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT records matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("hostingnl: could not find zone for domain %q: %w", domain, err)
- }
-
- // gets the record's unique ID
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("hostingnl: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- err = d.client.DeleteRecord(context.Background(), dns01.UnFqdn(authZone), recordID)
- if err != nil {
- return fmt.Errorf("hostingnl: failed to delete TXT record, id=%s: %w", recordID, err)
- }
-
- // deletes record ID from map
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/hostingnl/hostingnl.toml b/providers/dns/hostingnl/hostingnl.toml
deleted file mode 100644
index 943264ed3..000000000
--- a/providers/dns/hostingnl/hostingnl.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Hosting.nl"
-Description = ''''''
-URL = "https://hosting.nl"
-Code = "hostingnl"
-Since = "v4.30.0"
-
-Example = '''
-HOSTINGNL_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns hostingnl -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- HOSTINGNL_API_KEY = "The API key"
- [Configuration.Additional]
- HOSTINGNL_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- HOSTINGNL_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
- HOSTINGNL_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- HOSTINGNL_HTTP_TIMEOUT = "API request timeout in seconds (Default: 10)"
-
-[Links]
- API = "https://api.hosting.nl/api/documentation"
diff --git a/providers/dns/hostingnl/hostingnl_test.go b/providers/dns/hostingnl/hostingnl_test.go
deleted file mode 100644
index cef754c7c..000000000
--- a/providers/dns/hostingnl/hostingnl_test.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package hostingnl
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIKey: "key",
- },
- },
- {
- desc: "missing API key",
- envVars: map[string]string{},
- expected: "hostingnl: some credentials information are missing: HOSTINGNL_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- apiKey: "key",
- },
- {
- desc: "missing API key",
- expected: "hostingnl: APIKey is missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIKey = "secret"
- config.HTTPClient = server.Client()
-
- provider, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- provider.client.BaseURL, _ = url.Parse(server.URL)
-
- return provider, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With("API-TOKEN", "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /domains/example.com/dns",
- servermock.ResponseFromInternal("add_record.json"),
- servermock.CheckQueryParameter().Strict(),
- servermock.CheckRequestJSONBodyFromInternal("add_record-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /domains/example.com/dns",
- servermock.ResponseFromInternal("delete_record.json"),
- servermock.CheckQueryParameter().Strict(),
- servermock.CheckRequestJSONBodyFromInternal("delete_record-request.json")).
- Build(t)
-
- provider.recordIDs["abc"] = "12345"
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/hostingnl/internal/client.go b/providers/dns/hostingnl/internal/client.go
deleted file mode 100644
index f2d7b5346..000000000
--- a/providers/dns/hostingnl/internal/client.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://api.hosting.nl"
-
-type Client struct {
- apiKey string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-func NewClient(apiKey string) *Client {
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- apiKey: apiKey,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 5 * time.Second},
- }
-}
-
-func (c Client) AddRecord(ctx context.Context, domain string, record Record) (*Record, error) {
- endpoint := c.BaseURL.JoinPath("domains", domain, "dns")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, []Record{record})
- if err != nil {
- return nil, err
- }
-
- var result APIResponse[Record]
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- if len(result.Data) != 1 {
- return nil, fmt.Errorf("unexpected response data: %v", result.Data)
- }
-
- return &result.Data[0], nil
-}
-
-func (c Client) DeleteRecord(ctx context.Context, domain, recordID string) error {
- endpoint := c.BaseURL.JoinPath("domains", domain, "dns")
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, []Record{{ID: recordID}})
- if err != nil {
- return err
- }
-
- var result APIResponse[Record]
-
- err = c.do(req, &result)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func (c Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Set("API-TOKEN", c.apiKey)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode != http.StatusOK {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func parseError(req *http.Request, resp *http.Response) error {
- raw, _ := io.ReadAll(resp.Body)
-
- var apiErr APIError
-
- err := json.Unmarshal(raw, &apiErr)
- if err != nil {
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- return fmt.Errorf("[status code: %d] %w", resp.StatusCode, apiErr)
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- return req, nil
-}
diff --git a/providers/dns/hostingnl/internal/client_test.go b/providers/dns/hostingnl/internal/client_test.go
deleted file mode 100644
index efdb98980..000000000
--- a/providers/dns/hostingnl/internal/client_test.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package internal
-
-import (
- "context"
- "net/http"
- "net/http/httptest"
- "net/url"
- "strconv"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*Client, error) {
- client := NewClient("secret")
- client.HTTPClient = server.Client()
- client.BaseURL, _ = url.Parse(server.URL)
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With("API-TOKEN", "secret"),
- )
-}
-
-func TestClient_AddRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/example.com/dns",
- servermock.ResponseFromFixture("add_record.json"),
- servermock.CheckQueryParameter().Strict(),
- servermock.CheckRequestJSONBodyFromFixture("add_record-request.json")).
- Build(t)
-
- record := Record{
- Name: "_acme-challenge.example.com",
- Type: "TXT",
- Content: strconv.Quote("ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"),
- TTL: 120,
- }
-
- newRecord, err := client.AddRecord(context.Background(), "example.com", record)
- require.NoError(t, err)
-
- expected := &Record{
- ID: "12345",
- Name: "_acme-challenge.example.com",
- Type: "TXT",
- Content: strconv.Quote("ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"),
- TTL: 120,
- }
-
- assert.Equal(t, expected, newRecord)
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/dns",
- servermock.ResponseFromFixture("delete_record.json"),
- servermock.CheckQueryParameter().Strict(),
- servermock.CheckRequestJSONBodyFromFixture("delete_record-request.json")).
- Build(t)
-
- err := client.DeleteRecord(context.Background(), "example.com", "12345")
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/dns",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- err := client.DeleteRecord(context.Background(), "example.com", "12345")
- require.EqualError(t, err, "[status code: 401] Something went wrong")
-}
-
-func TestClient_DeleteRecord_error_other(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/dns",
- servermock.ResponseFromFixture("error_other.json").
- WithStatusCode(http.StatusNotFound)).
- Build(t)
-
- err := client.DeleteRecord(context.Background(), "example.com", "12345")
- require.EqualError(t, err, "[status code: 404] Resource not found")
-}
diff --git a/providers/dns/hostingnl/internal/fixtures/add_record-request.json b/providers/dns/hostingnl/internal/fixtures/add_record-request.json
deleted file mode 100644
index 6b68ec3c6..000000000
--- a/providers/dns/hostingnl/internal/fixtures/add_record-request.json
+++ /dev/null
@@ -1,8 +0,0 @@
-[
- {
- "name": "_acme-challenge.example.com",
- "type": "TXT",
- "content": "\"ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY\"",
- "ttl": 120
- }
-]
diff --git a/providers/dns/hostingnl/internal/fixtures/add_record.json b/providers/dns/hostingnl/internal/fixtures/add_record.json
deleted file mode 100644
index a822a4f8d..000000000
--- a/providers/dns/hostingnl/internal/fixtures/add_record.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "success": true,
- "data": [
- {
- "id": "12345",
- "type": "TXT",
- "content": "\"ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY\"",
- "name": "_acme-challenge.example.com",
- "prio": 0,
- "ttl": 120
- }
- ]
-}
diff --git a/providers/dns/hostingnl/internal/fixtures/delete_record-request.json b/providers/dns/hostingnl/internal/fixtures/delete_record-request.json
deleted file mode 100644
index cfc26d2b9..000000000
--- a/providers/dns/hostingnl/internal/fixtures/delete_record-request.json
+++ /dev/null
@@ -1,5 +0,0 @@
-[
- {
- "id": "12345"
- }
-]
diff --git a/providers/dns/hostingnl/internal/fixtures/delete_record.json b/providers/dns/hostingnl/internal/fixtures/delete_record.json
deleted file mode 100644
index c041c1f6d..000000000
--- a/providers/dns/hostingnl/internal/fixtures/delete_record.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "success": true,
- "data": [
- {
- "id": "12345"
- }
- ]
-}
diff --git a/providers/dns/hostingnl/internal/fixtures/error.json b/providers/dns/hostingnl/internal/fixtures/error.json
deleted file mode 100644
index 170587246..000000000
--- a/providers/dns/hostingnl/internal/fixtures/error.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "errors": {
- "message": "Something went wrong"
- }
-}
diff --git a/providers/dns/hostingnl/internal/fixtures/error_other.json b/providers/dns/hostingnl/internal/fixtures/error_other.json
deleted file mode 100644
index ca7ecab28..000000000
--- a/providers/dns/hostingnl/internal/fixtures/error_other.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "error": "Resource not found"
-}
diff --git a/providers/dns/hostingnl/internal/types.go b/providers/dns/hostingnl/internal/types.go
deleted file mode 100644
index f324665fe..000000000
--- a/providers/dns/hostingnl/internal/types.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package internal
-
-type Record struct {
- ID string `json:"id,omitempty"`
- Name string `json:"name,omitempty"`
- Type string `json:"type,omitempty"`
- Content string `json:"content,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Priority int `json:"prio,omitempty"`
-}
-
-type APIResponse[T any] struct {
- Success bool `json:"success"`
- Data []T `json:"data"`
-}
-
-type APIError struct {
- ErrorMsg string `json:"error"`
- Errors Error `json:"errors"`
-}
-
-func (e APIError) Error() string {
- if e.ErrorMsg != "" {
- return e.ErrorMsg
- }
-
- return e.Errors.Error()
-}
-
-type Error struct {
- Message string `json:"message"`
-}
-
-func (e Error) Error() string {
- return e.Message
-}
diff --git a/providers/dns/hosttech/hosttech.go b/providers/dns/hosttech/hosttech.go
index 73346f6cb..22d3be7bd 100644
--- a/providers/dns/hosttech/hosttech.go
+++ b/providers/dns/hosttech/hosttech.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/hosttech/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -85,11 +84,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("hosttech: missing credentials")
}
- client := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.APIKey),
- ),
- )
+ client := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.APIKey))
return &DNSProvider{
config: config,
@@ -164,7 +159,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("hosttech: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
@@ -174,9 +168,5 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("hosttech: %w", err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/hosttech/hosttech.toml b/providers/dns/hosttech/hosttech.toml
index 52c01fd31..5d7555499 100644
--- a/providers/dns/hosttech/hosttech.toml
+++ b/providers/dns/hosttech/hosttech.toml
@@ -6,7 +6,7 @@ Since = "v4.5.0"
Example = '''
HOSTTECH_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns hosttech -d '*.example.com' -d example.com run
+lego --email you@example.com --dns hosttech -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/hosttech/hosttech_test.go b/providers/dns/hosttech/hosttech_test.go
index 042b73353..6f0d0bd3e 100644
--- a/providers/dns/hosttech/hosttech_test.go
+++ b/providers/dns/hosttech/hosttech_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -93,7 +92,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -107,7 +105,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/hosttech/internal/client.go b/providers/dns/hosttech/internal/client.go
index 557d54298..399b18d0e 100644
--- a/providers/dns/hosttech/internal/client.go
+++ b/providers/dns/hosttech/internal/client.go
@@ -58,7 +58,6 @@ func (c *Client) GetZones(ctx context.Context, query string, limit, offset int)
}
result := apiResponse[[]Zone]{}
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -78,7 +77,6 @@ func (c *Client) GetZone(ctx context.Context, zoneID string) (*Zone, error) {
}
result := apiResponse[*Zone]{}
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -106,7 +104,6 @@ func (c *Client) GetRecords(ctx context.Context, zoneID, recordType string) ([]R
}
result := apiResponse[[]Record]{}
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -126,7 +123,6 @@ func (c *Client) AddRecord(ctx context.Context, zoneID string, record Record) (*
}
result := apiResponse[*Record]{}
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -206,7 +202,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errAPI := &APIError{StatusCode: resp.StatusCode}
-
err := json.Unmarshal(raw, errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/hosttech/internal/types.go b/providers/dns/hosttech/internal/types.go
index a4b5b564d..bf86964f7 100644
--- a/providers/dns/hosttech/internal/types.go
+++ b/providers/dns/hosttech/internal/types.go
@@ -2,7 +2,6 @@ package internal
import (
"fmt"
- "strings"
)
type apiResponse[T any] struct {
@@ -16,15 +15,11 @@ type APIError struct {
}
func (a APIError) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "%d: %s", a.StatusCode, a.Message)
-
+ msg := fmt.Sprintf("%d: %s", a.StatusCode, a.Message)
for k, v := range a.Errors {
- _, _ = fmt.Fprintf(msg, " %s: %v", k, v)
+ msg += fmt.Sprintf(" %s: %v", k, v)
}
-
- return msg.String()
+ return msg
}
type Zone struct {
diff --git a/providers/dns/httpnet/httpnet.go b/providers/dns/httpnet/httpnet.go
index 4a88f1092..56bd92712 100644
--- a/providers/dns/httpnet/httpnet.go
+++ b/providers/dns/httpnet/httpnet.go
@@ -2,9 +2,12 @@
package httpnet
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "net/url"
+ "sync"
"time"
"github.com/go-acme/lego/v4/challenge"
@@ -26,12 +29,17 @@ const (
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
-const defaultBaseURL = "https://partner.http.net/api/dns/v1/json"
-
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
-type Config = hostingde.Config
+type Config struct {
+ APIKey string
+ ZoneName string
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
@@ -48,7 +56,11 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *hostingde.Client
+
+ recordIDs map[string]string
+ recordIDsMu sync.Mutex
}
// NewDNSProvider returns a DNSProvider instance configured for http.net.
@@ -72,36 +84,143 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("httpnet: the configuration of the DNS provider is nil")
}
- provider, err := hostingde.NewDNSProviderConfig(config, defaultBaseURL)
- if err != nil {
- return nil, fmt.Errorf("httpnet: %w", err)
+ if config.APIKey == "" {
+ return nil, errors.New("httpnet: API key missing")
}
- return &DNSProvider{prv: provider}, nil
+ client := hostingde.NewClient(config.APIKey)
+ client.BaseURL, _ = url.Parse(hostingde.DefaultHTTPNetBaseURL)
+
+ return &DNSProvider{
+ config: config,
+ client: client,
+ recordIDs: make(map[string]string),
+ }, nil
}
-// Present creates a TXT record using the specified parameters.
+// Timeout returns the timeout and interval to use when checking for DNS propagation.
+// Adjusting here to cope with spikes in propagation times.
+func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
+ return d.config.PropagationTimeout, d.config.PollingInterval
+}
+
+// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ zoneName, err := d.getZoneName(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("httpnet: could not find zone for domain %q: %w", domain, err)
+ }
+
+ ctx := context.Background()
+
+ // get the ZoneConfig for that domain
+ zonesFind := hostingde.ZoneConfigsFindRequest{
+ Filter: hostingde.Filter{Field: "zoneName", Value: zoneName},
+ Limit: 1,
+ Page: 1,
+ }
+
+ zoneConfig, err := d.client.GetZone(ctx, zonesFind)
if err != nil {
return fmt.Errorf("httpnet: %w", err)
}
+ zoneConfig.Name = zoneName
+
+ rec := []hostingde.DNSRecord{{
+ Type: "TXT",
+ Name: dns01.UnFqdn(info.EffectiveFQDN),
+ Content: info.Value,
+ TTL: d.config.TTL,
+ }}
+
+ req := hostingde.ZoneUpdateRequest{
+ ZoneConfig: *zoneConfig,
+ RecordsToAdd: rec,
+ }
+
+ response, err := d.client.UpdateZone(ctx, req)
+ if err != nil {
+ return fmt.Errorf("httpnet: %w", err)
+ }
+
+ for _, record := range response.Records {
+ if record.Name == dns01.UnFqdn(info.EffectiveFQDN) && record.Content == fmt.Sprintf(`%q`, info.Value) {
+ d.recordIDsMu.Lock()
+ d.recordIDs[info.EffectiveFQDN] = record.ID
+ d.recordIDsMu.Unlock()
+ }
+ }
+
+ if d.recordIDs[info.EffectiveFQDN] == "" {
+ return fmt.Errorf("httpnet: error getting ID of just created record, for domain %s", domain)
+ }
+
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ zoneName, err := d.getZoneName(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("httpnet: could not find zone for domain %q: %w", domain, err)
+ }
+
+ ctx := context.Background()
+
+ // get the ZoneConfig for that domain
+ zonesFind := hostingde.ZoneConfigsFindRequest{
+ Filter: hostingde.Filter{Field: "zoneName", Value: zoneName},
+ Limit: 1,
+ Page: 1,
+ }
+
+ zoneConfig, err := d.client.GetZone(ctx, zonesFind)
if err != nil {
return fmt.Errorf("httpnet: %w", err)
}
+ zoneConfig.Name = zoneName
+ rec := []hostingde.DNSRecord{{
+ Type: "TXT",
+ Name: dns01.UnFqdn(info.EffectiveFQDN),
+ Content: `"` + info.Value + `"`,
+ }}
+
+ req := hostingde.ZoneUpdateRequest{
+ ZoneConfig: *zoneConfig,
+ RecordsToDelete: rec,
+ }
+
+ // Delete record ID from map
+ d.recordIDsMu.Lock()
+ delete(d.recordIDs, info.EffectiveFQDN)
+ d.recordIDsMu.Unlock()
+
+ _, err = d.client.UpdateZone(ctx, req)
+ if err != nil {
+ return fmt.Errorf("httpnet: %w", err)
+ }
return nil
}
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+func (d *DNSProvider) getZoneName(fqdn string) (string, error) {
+ if d.config.ZoneName != "" {
+ return d.config.ZoneName, nil
+ }
+
+ zoneName, err := dns01.FindZoneByFqdn(fqdn)
+ if err != nil {
+ return "", fmt.Errorf("could not find zone for %s: %w", fqdn, err)
+ }
+
+ if zoneName == "" {
+ return "", errors.New("empty zone name")
+ }
+
+ return dns01.UnFqdn(zoneName), nil
}
diff --git a/providers/dns/httpnet/httpnet.toml b/providers/dns/httpnet/httpnet.toml
index 3dd581204..204f5bc54 100644
--- a/providers/dns/httpnet/httpnet.toml
+++ b/providers/dns/httpnet/httpnet.toml
@@ -6,7 +6,7 @@ Since = "v4.15.0"
Example = '''
HTTPNET_API_KEY=xxxxxxxx \
-lego --dns httpnet -d '*.example.com' -d example.com run
+lego --email you@example.com --dns httpnet -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/httpnet/httpnet_test.go b/providers/dns/httpnet/httpnet_test.go
index ef1d2a1b7..a9bc527ad 100644
--- a/providers/dns/httpnet/httpnet_test.go
+++ b/providers/dns/httpnet/httpnet_test.go
@@ -49,7 +49,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -59,7 +58,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.recordIDs)
} else {
require.EqualError(t, err, test.expected)
}
@@ -101,7 +101,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.recordIDs)
} else {
require.EqualError(t, err, test.expected)
}
@@ -115,7 +116,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -129,7 +129,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/httpreq/httpreq.go b/providers/dns/httpreq/httpreq.go
index 591e9b5e1..8f8311e0a 100644
--- a/providers/dns/httpreq/httpreq.go
+++ b/providers/dns/httpreq/httpreq.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
)
@@ -89,7 +88,6 @@ func NewDNSProvider() (*DNSProvider, error) {
config.Username = env.GetOrFile(EnvUsername)
config.Password = env.GetOrFile(EnvPassword)
config.Endpoint = endpoint
-
return NewDNSProviderConfig(config)
}
@@ -103,8 +101,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("httpreq: the endpoint is missing")
}
- config.HTTPClient = clientdebug.Wrap(config.HTTPClient)
-
return &DNSProvider{config: config}, nil
}
@@ -129,7 +125,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("httpreq: %w", err)
}
-
return nil
}
@@ -143,7 +138,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("httpreq: %w", err)
}
-
return nil
}
@@ -162,7 +156,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("httpreq: %w", err)
}
-
return nil
}
@@ -176,13 +169,11 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("httpreq: %w", err)
}
-
return nil
}
func (d *DNSProvider) doPost(ctx context.Context, uri string, msg any) error {
reqBody := new(bytes.Buffer)
-
err := json.NewEncoder(reqBody).Encode(msg)
if err != nil {
return fmt.Errorf("failed to create request JSON body: %w", err)
diff --git a/providers/dns/httpreq/httpreq.toml b/providers/dns/httpreq/httpreq.toml
index d64d61a6c..6c3f8719b 100644
--- a/providers/dns/httpreq/httpreq.toml
+++ b/providers/dns/httpreq/httpreq.toml
@@ -6,7 +6,7 @@ Since = "v2.0.0"
Example = '''
HTTPREQ_ENDPOINT=http://my.server.com:9090 \
-lego --dns httpreq -d '*.example.com' -d example.com run
+lego --email you@example.com --dns httpreq -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/httpreq/httpreq_test.go b/providers/dns/httpreq/httpreq_test.go
index 108d6a565..038b21b1a 100644
--- a/providers/dns/httpreq/httpreq_test.go
+++ b/providers/dns/httpreq/httpreq_test.go
@@ -43,7 +43,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -228,7 +227,6 @@ func mockBuilder(mode string) *servermock.Builder[*DNSProvider] {
return servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
config.Endpoint, _ = url.Parse(server.URL)
config.Mode = mode
@@ -240,7 +238,6 @@ func mockBuilderWithPathPrefix(mode, prefix string) *servermock.Builder[*DNSProv
return servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
config.Endpoint, _ = url.Parse(server.URL + prefix)
config.Mode = mode
@@ -252,7 +249,6 @@ func mockBuilderWithBasicAuth(username, password string) *servermock.Builder[*DN
return servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
config.Endpoint, _ = url.Parse(server.URL)
config.Username = username
config.Password = password
@@ -267,6 +263,5 @@ func mustParse(rawURL string) *url.URL {
if err != nil {
panic(err)
}
-
return uri
}
diff --git a/providers/dns/huaweicloud/huaweicloud.go b/providers/dns/huaweicloud/huaweicloud.go
index e47f3e2b5..32f4d3446 100644
--- a/providers/dns/huaweicloud/huaweicloud.go
+++ b/providers/dns/huaweicloud/huaweicloud.go
@@ -2,7 +2,6 @@
package huaweicloud
import (
- "context"
"errors"
"fmt"
"strconv"
@@ -10,7 +9,6 @@ import (
"sync"
"time"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
@@ -150,27 +148,19 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
d.recordIDs[token] = recordSetID
d.recordIDsMu.Unlock()
- err = wait.Retry(context.Background(),
- func() error {
- rs, errShow := d.client.ShowRecordSet(&hwmodel.ShowRecordSetRequest{
- ZoneId: zoneID,
- RecordsetId: recordSetID,
- })
- if errShow != nil {
- return fmt.Errorf("show record set: %w", errShow)
- }
+ err = wait.For("record set sync on "+domain, d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
+ rs, errShow := d.client.ShowRecordSet(&hwmodel.ShowRecordSetRequest{
+ ZoneId: zoneID,
+ RecordsetId: recordSetID,
+ })
+ if errShow != nil {
+ return false, fmt.Errorf("show record set: %w", errShow)
+ }
- if !strings.HasSuffix(ptr.Deref(rs.Status), "PENDING_") {
- return nil
- }
-
- return fmt.Errorf("status: %s", ptr.Deref(rs.Status))
- },
- backoff.WithBackOff(backoff.NewConstantBackOff(d.config.PollingInterval)),
- backoff.WithMaxElapsedTime(d.config.PropagationTimeout),
- )
+ return !strings.HasSuffix(ptr.Deref(rs.Status), "PENDING_"), nil
+ })
if err != nil {
- return fmt.Errorf("huaweicloud: record set sync on %s: %w", domain, err)
+ return fmt.Errorf("huaweicloud: %w", err)
}
return nil
@@ -184,7 +174,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("huaweicloud: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
@@ -209,10 +198,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("huaweicloud: delete record: %w", err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/huaweicloud/huaweicloud.toml b/providers/dns/huaweicloud/huaweicloud.toml
index e8d417c11..f7991dfae 100644
--- a/providers/dns/huaweicloud/huaweicloud.toml
+++ b/providers/dns/huaweicloud/huaweicloud.toml
@@ -8,7 +8,7 @@ Example = '''
HUAWEICLOUD_ACCESS_KEY_ID=your-access-key-id \
HUAWEICLOUD_SECRET_ACCESS_KEY=your-secret-access-key \
HUAWEICLOUD_REGION=cn-south-1 \
-lego --dns huaweicloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns huaweicloud -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/huaweicloud/huaweicloud_test.go b/providers/dns/huaweicloud/huaweicloud_test.go
index 25e295da7..6787650ca 100644
--- a/providers/dns/huaweicloud/huaweicloud_test.go
+++ b/providers/dns/huaweicloud/huaweicloud_test.go
@@ -62,7 +62,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -141,7 +140,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -155,7 +153,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/hurricane/hurricane.go b/providers/dns/hurricane/hurricane.go
index b23528bb0..7ce646bc9 100644
--- a/providers/dns/hurricane/hurricane.go
+++ b/providers/dns/hurricane/hurricane.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/hurricane/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -58,7 +57,6 @@ type DNSProvider struct {
// NewDNSProvider returns a DNSProvider instance configured for Hurricane Electric.
func NewDNSProvider() (*DNSProvider, error) {
config := NewDefaultConfig()
-
values, err := env.Get(EnvTokens)
if err != nil {
return nil, fmt.Errorf("hurricane: %w", err)
@@ -85,12 +83,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client := internal.NewClient(config.Credentials)
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/hurricane/hurricane.toml b/providers/dns/hurricane/hurricane.toml
index 10b370e4f..033c73984 100644
--- a/providers/dns/hurricane/hurricane.toml
+++ b/providers/dns/hurricane/hurricane.toml
@@ -6,10 +6,10 @@ Since = "v4.3.0"
Example = '''
HURRICANE_TOKENS=example.org:token \
-lego --dns hurricane -d '*.example.com' -d example.com run
+lego --email you@example.com --dns hurricane -d '*.example.com' -d example.com run
HURRICANE_TOKENS=my.example.org:token1,demo.example.org:token2 \
-lego --dns hurricane -d my.example.org -d demo.example.org
+lego --email you@example.com --dns hurricane -d my.example.org -d demo.example.org
'''
Additional = """
diff --git a/providers/dns/hurricane/hurricane_test.go b/providers/dns/hurricane/hurricane_test.go
index 2bbd638fa..f8a1f185c 100644
--- a/providers/dns/hurricane/hurricane_test.go
+++ b/providers/dns/hurricane/hurricane_test.go
@@ -55,7 +55,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -121,7 +120,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -135,7 +133,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/hyperone/hyperone.go b/providers/dns/hyperone/hyperone.go
index 3cdad8e68..890f9f627 100644
--- a/providers/dns/hyperone/hyperone.go
+++ b/providers/dns/hyperone/hyperone.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/hyperone/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Environment variables names.
@@ -77,7 +76,6 @@ func NewDNSProvider() (*DNSProvider, error) {
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config.PassportLocation == "" {
var err error
-
config.PassportLocation, err = GetDefaultPassportLocation()
if err != nil {
return nil, fmt.Errorf("hyperone: %w", err)
@@ -98,8 +96,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{client: client, config: config}, nil
}
@@ -167,7 +163,6 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
if err != nil {
return fmt.Errorf("hyperone: %w", err)
}
-
if len(records) == 1 {
if records[0].Content != info.Value {
return fmt.Errorf("hyperone: record with content %s not found: fqdn=%s", info.Value, info.EffectiveFQDN)
diff --git a/providers/dns/hyperone/hyperone.toml b/providers/dns/hyperone/hyperone.toml
index 88814356f..0f23976c4 100644
--- a/providers/dns/hyperone/hyperone.toml
+++ b/providers/dns/hyperone/hyperone.toml
@@ -5,7 +5,7 @@ Code = "hyperone"
Since = "v3.9.0"
Example = '''
-lego --dns hyperone -d '*.example.com' -d example.com run
+lego --email you@example.com --dns hyperone -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/hyperone/hyperone_test.go b/providers/dns/hyperone/hyperone_test.go
index 675a1fe19..1222d1c74 100644
--- a/providers/dns/hyperone/hyperone_test.go
+++ b/providers/dns/hyperone/hyperone_test.go
@@ -49,7 +49,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -125,7 +124,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -139,7 +137,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/hyperone/internal/passport.go b/providers/dns/hyperone/internal/passport.go
index d1503d893..b63236c3b 100644
--- a/providers/dns/hyperone/internal/passport.go
+++ b/providers/dns/hyperone/internal/passport.go
@@ -25,7 +25,6 @@ func LoadPassportFile(location string) (*Passport, error) {
defer func() { _ = file.Close() }()
var passport Passport
-
err = json.NewDecoder(file).Decode(&passport)
if err != nil {
return nil, fmt.Errorf("failed to parse passport file: %w", err)
diff --git a/providers/dns/hyperone/internal/token_test.go b/providers/dns/hyperone/internal/token_test.go
index 34b4cc573..315d0896f 100644
--- a/providers/dns/hyperone/internal/token_test.go
+++ b/providers/dns/hyperone/internal/token_test.go
@@ -38,7 +38,6 @@ func TestPayload_buildToken(t *testing.T) {
require.NoError(t, err)
var headerStruct Header
-
err = json.Unmarshal(headerString, &headerStruct)
require.NoError(t, err)
@@ -46,7 +45,6 @@ func TestPayload_buildToken(t *testing.T) {
require.NoError(t, err)
var payloadStruct Payload
-
err = json.Unmarshal(payloadString, &payloadStruct)
require.NoError(t, err)
diff --git a/providers/dns/ibmcloud/ibmcloud.toml b/providers/dns/ibmcloud/ibmcloud.toml
index 01088f09b..090c010c9 100644
--- a/providers/dns/ibmcloud/ibmcloud.toml
+++ b/providers/dns/ibmcloud/ibmcloud.toml
@@ -7,12 +7,12 @@ Since = "v4.5.0"
Example = '''
SOFTLAYER_USERNAME=xxxxx \
SOFTLAYER_API_KEY=yyyyy \
-lego --dns ibmcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ibmcloud -d '*.example.com' -d example.com run
'''
[Configuration]
[Configuration.Credentials]
- SOFTLAYER_USERNAME = "Username (IBM Cloud is {accountID}_{emailAddress})"
+ SOFTLAYER_USERNAME = "Username (IBM Cloud is _)"
SOFTLAYER_API_KEY = "Classic Infrastructure API key"
[Configuration.Additional]
SOFTLAYER_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
diff --git a/providers/dns/ibmcloud/ibmcloud_test.go b/providers/dns/ibmcloud/ibmcloud_test.go
index 6ca7cd81b..a000e3e59 100644
--- a/providers/dns/ibmcloud/ibmcloud_test.go
+++ b/providers/dns/ibmcloud/ibmcloud_test.go
@@ -55,7 +55,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -128,7 +127,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -142,7 +140,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/iij/iij.go b/providers/dns/iij/iij.go
index 1d098bde2..6bc7db21a 100644
--- a/providers/dns/iij/iij.go
+++ b/providers/dns/iij/iij.go
@@ -98,7 +98,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("iij: %w", err)
}
-
return nil
}
@@ -111,7 +110,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("iij: %w", err)
}
-
return nil
}
diff --git a/providers/dns/iij/iij.toml b/providers/dns/iij/iij.toml
index 95355200a..8dbf5ba1a 100644
--- a/providers/dns/iij/iij.toml
+++ b/providers/dns/iij/iij.toml
@@ -8,7 +8,7 @@ Example = '''
IIJ_API_ACCESS_KEY=xxxxxxxx \
IIJ_API_SECRET_KEY=yyyyyy \
IIJ_DO_SERVICE_CODE=zzzzzz \
-lego --dns iij -d '*.example.com' -d example.com run
+lego --email you@example.com --dns iij -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/iij/iij_test.go b/providers/dns/iij/iij_test.go
index bd8140532..2c7ec4217 100644
--- a/providers/dns/iij/iij_test.go
+++ b/providers/dns/iij/iij_test.go
@@ -71,7 +71,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -239,7 +238,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -253,7 +251,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/iijdpf/iijdpf.toml b/providers/dns/iijdpf/iijdpf.toml
index 650285f95..4aaa9ca37 100644
--- a/providers/dns/iijdpf/iijdpf.toml
+++ b/providers/dns/iijdpf/iijdpf.toml
@@ -7,7 +7,7 @@ Since = "v4.7.0"
Example = '''
IIJ_DPF_API_TOKEN=xxxxxxxx \
IIJ_DPF_DPM_SERVICE_CODE=yyyyyy \
-lego --dns iijdpf -d '*.example.com' -d example.com run
+lego --email you@example.com --dns iijdpf -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/iijdpf/iijdpf_test.go b/providers/dns/iijdpf/iijdpf_test.go
index fbcf3e1f5..a4fa8b8f6 100644
--- a/providers/dns/iijdpf/iijdpf_test.go
+++ b/providers/dns/iijdpf/iijdpf_test.go
@@ -43,7 +43,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -116,7 +115,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -130,7 +128,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/iijdpf/wrapper.go b/providers/dns/iijdpf/wrapper.go
index 0ab26cdcd..12b09a30c 100644
--- a/providers/dns/iijdpf/wrapper.go
+++ b/providers/dns/iijdpf/wrapper.go
@@ -51,7 +51,6 @@ func (d *DNSProvider) deleteTxtRecord(ctx context.Context, zoneID, fqdn, rdata s
// empty target rrset
return nil
}
-
return err
}
@@ -67,13 +66,11 @@ func (d *DNSProvider) deleteTxtRecord(ctx context.Context, zoneID, fqdn, rdata s
// delete rdata
rdataSlice := dpfzones.RecordRDATASlice{}
-
for _, v := range r.RData {
if v.Value != rdata {
rdataSlice = append(rdataSlice, v)
}
}
-
r.RData = rdataSlice
_, _, err = dpfapiutils.SyncUpdate(ctx, d.client, r, nil)
diff --git a/providers/dns/infoblox/infoblox.go b/providers/dns/infoblox/infoblox.go
index 054f13679..37e119e85 100644
--- a/providers/dns/infoblox/infoblox.go
+++ b/providers/dns/infoblox/infoblox.go
@@ -198,7 +198,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordRefsMu.Lock()
recordRef, ok := d.recordRefs[token]
d.recordRefsMu.Unlock()
-
if !ok {
return fmt.Errorf("infoblox: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
diff --git a/providers/dns/infoblox/infoblox.toml b/providers/dns/infoblox/infoblox.toml
index 0e6972d3a..3c2632042 100644
--- a/providers/dns/infoblox/infoblox.toml
+++ b/providers/dns/infoblox/infoblox.toml
@@ -8,7 +8,7 @@ Example = '''
INFOBLOX_USERNAME=api-user-529 \
INFOBLOX_PASSWORD=b9841238feb177a84330febba8a83208921177bffe733 \
INFOBLOX_HOST=infoblox.example.org
-lego --dns infoblox -d '*.example.com' -d example.com run
+lego --email you@example.com --dns infoblox -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/infoblox/infoblox_test.go b/providers/dns/infoblox/infoblox_test.go
index 68158cb0d..45434e0e3 100644
--- a/providers/dns/infoblox/infoblox_test.go
+++ b/providers/dns/infoblox/infoblox_test.go
@@ -68,7 +68,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -150,7 +149,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -164,7 +162,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/infomaniak/infomaniak.go b/providers/dns/infomaniak/infomaniak.go
index 9b8b53590..79c6f577e 100644
--- a/providers/dns/infomaniak/infomaniak.go
+++ b/providers/dns/infomaniak/infomaniak.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/infomaniak/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
)
// Infomaniak API reference: https://api.infomaniak.com/doc
@@ -97,11 +96,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("infomaniak: missing access token")
}
- client, err := internal.New(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.AccessToken),
- ),
- config.APIEndpoint)
+ client, err := internal.New(internal.OAuthStaticAccessToken(config.HTTPClient, config.AccessToken), config.APIEndpoint)
if err != nil {
return nil, fmt.Errorf("infomaniak: %w", err)
}
diff --git a/providers/dns/infomaniak/infomaniak.toml b/providers/dns/infomaniak/infomaniak.toml
index d924e3a26..283838053 100644
--- a/providers/dns/infomaniak/infomaniak.toml
+++ b/providers/dns/infomaniak/infomaniak.toml
@@ -6,7 +6,7 @@ Since = "v4.1.0"
Example = '''
INFOMANIAK_ACCESS_TOKEN=1234567898765432 \
-lego --dns infomaniak -d '*.example.com' -d example.com run
+lego --email you@example.com --dns infomaniak -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/infomaniak/infomaniak_test.go b/providers/dns/infomaniak/infomaniak_test.go
index 980f3b959..bc8fb7b58 100644
--- a/providers/dns/infomaniak/infomaniak_test.go
+++ b/providers/dns/infomaniak/infomaniak_test.go
@@ -39,7 +39,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -102,7 +101,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -116,7 +114,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/infomaniak/internal/client.go b/providers/dns/infomaniak/internal/client.go
index 40b56c707..886a8966f 100644
--- a/providers/dns/infomaniak/internal/client.go
+++ b/providers/dns/infomaniak/internal/client.go
@@ -50,7 +50,6 @@ func (c *Client) CreateDNSRecord(ctx context.Context, domain *DNSDomain, record
}
result := APIResponse[string]{}
-
err = c.do(req, &result)
if err != nil {
return "", err
@@ -113,7 +112,6 @@ func (c *Client) getDomainByName(ctx context.Context, name string) (*DNSDomain,
}
result := APIResponse[[]DNSDomain]{}
-
err = c.do(req, &result)
if err != nil {
return nil, err
diff --git a/providers/dns/internal/active24/internal/client.go b/providers/dns/internal/active24/client.go
similarity index 99%
rename from providers/dns/internal/active24/internal/client.go
rename to providers/dns/internal/active24/client.go
index 69e94b367..32ecc2186 100644
--- a/providers/dns/internal/active24/internal/client.go
+++ b/providers/dns/internal/active24/client.go
@@ -1,4 +1,4 @@
-package internal
+package active24
import (
"bytes"
@@ -55,7 +55,6 @@ func (c *Client) GetServices(ctx context.Context) ([]Service, error) {
}
var result OldAPIResponse
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -83,7 +82,6 @@ func (c *Client) GetRecords(ctx context.Context, service string, filter RecordFi
}
var result APIResponse
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -182,7 +180,6 @@ 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)
@@ -201,7 +198,6 @@ func (c *Client) sign(req *http.Request, now time.Time) error {
canonicalRequest := fmt.Sprintf("%s %s %d", req.Method, req.URL.Path, now.Unix())
mac := hmac.New(sha1.New, []byte(c.secret))
-
_, err := mac.Write([]byte(canonicalRequest))
if err != nil {
return err
diff --git a/providers/dns/internal/active24/internal/client_test.go b/providers/dns/internal/active24/client_test.go
similarity index 99%
rename from providers/dns/internal/active24/internal/client_test.go
rename to providers/dns/internal/active24/client_test.go
index f62f78785..ad2a8126b 100644
--- a/providers/dns/internal/active24/internal/client_test.go
+++ b/providers/dns/internal/active24/client_test.go
@@ -1,4 +1,4 @@
-package internal
+package active24
import (
"net/http"
diff --git a/providers/dns/internal/active24/internal/fixtures/error_403.json b/providers/dns/internal/active24/fixtures/error_403.json
similarity index 100%
rename from providers/dns/internal/active24/internal/fixtures/error_403.json
rename to providers/dns/internal/active24/fixtures/error_403.json
diff --git a/providers/dns/internal/active24/internal/fixtures/error_422.json b/providers/dns/internal/active24/fixtures/error_422.json
similarity index 100%
rename from providers/dns/internal/active24/internal/fixtures/error_422.json
rename to providers/dns/internal/active24/fixtures/error_422.json
diff --git a/providers/dns/internal/active24/internal/fixtures/error_v1.json b/providers/dns/internal/active24/fixtures/error_v1.json
similarity index 100%
rename from providers/dns/internal/active24/internal/fixtures/error_v1.json
rename to providers/dns/internal/active24/fixtures/error_v1.json
diff --git a/providers/dns/internal/active24/internal/fixtures/records.json b/providers/dns/internal/active24/fixtures/records.json
similarity index 100%
rename from providers/dns/internal/active24/internal/fixtures/records.json
rename to providers/dns/internal/active24/fixtures/records.json
diff --git a/providers/dns/internal/active24/internal/fixtures/services.json b/providers/dns/internal/active24/fixtures/services.json
similarity index 100%
rename from providers/dns/internal/active24/internal/fixtures/services.json
rename to providers/dns/internal/active24/fixtures/services.json
diff --git a/providers/dns/internal/active24/provider.go b/providers/dns/internal/active24/provider.go
deleted file mode 100644
index ae79b8b17..000000000
--- a/providers/dns/internal/active24/provider.go
+++ /dev/null
@@ -1,179 +0,0 @@
-// Package active24 implements a DNS provider for solving the DNS-01 challenge using Active24.
-package active24
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/active24/internal"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
- Secret string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Active24.
-func NewDNSProviderConfig(config *Config, baseAPIDomain string) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(baseAPIDomain, config.APIKey, config.Secret)
- if err != nil {
- return nil, err
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return err
- }
-
- serviceID, err := d.findServiceID(ctx, dns01.UnFqdn(authZone))
- if err != nil {
- return fmt.Errorf("find service ID: %w", err)
- }
-
- record := internal.Record{
- Type: "TXT",
- Name: subDomain,
- Content: info.Value,
- TTL: d.config.TTL,
- }
-
- err = d.client.CreateRecord(ctx, strconv.Itoa(serviceID), record)
- if err != nil {
- return fmt.Errorf("create record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("could not find zone for domain %q: %w", domain, err)
- }
-
- serviceID, err := d.findServiceID(ctx, dns01.UnFqdn(authZone))
- if err != nil {
- return fmt.Errorf("find service ID: %w", err)
- }
-
- recordID, err := d.findRecordID(ctx, strconv.Itoa(serviceID), info)
- if err != nil {
- return fmt.Errorf("find record ID: %w", err)
- }
-
- err = d.client.DeleteRecord(ctx, strconv.Itoa(serviceID), strconv.Itoa(recordID))
- if err != nil {
- return fmt.Errorf("delete record %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findServiceID(ctx context.Context, domain string) (int, error) {
- services, err := d.client.GetServices(ctx)
- if err != nil {
- return 0, fmt.Errorf("get services: %w", err)
- }
-
- for _, service := range services {
- if service.ServiceName != "domain" {
- continue
- }
-
- if service.Name != domain {
- continue
- }
-
- return service.ID, nil
- }
-
- return 0, fmt.Errorf("service not found for domain: %s", domain)
-}
-
-func (d *DNSProvider) findRecordID(ctx context.Context, serviceID string, info dns01.ChallengeInfo) (int, error) {
- // NOTE(ldez): Despite the API documentation, the filter doesn't seem to work.
- filter := internal.RecordFilter{
- Name: dns01.UnFqdn(info.EffectiveFQDN),
- Type: []string{"TXT"},
- Content: info.Value,
- }
-
- records, err := d.client.GetRecords(ctx, serviceID, filter)
- if err != nil {
- return 0, fmt.Errorf("get records: %w", err)
- }
-
- for _, record := range records {
- if record.Type != "TXT" {
- continue
- }
-
- if record.Name != dns01.UnFqdn(info.EffectiveFQDN) {
- continue
- }
-
- if record.Content != info.Value {
- continue
- }
-
- return record.ID, nil
- }
-
- return 0, errors.New("no record found")
-}
diff --git a/providers/dns/internal/active24/provider_test.go b/providers/dns/internal/active24/provider_test.go
deleted file mode 100644
index e2959fd6e..000000000
--- a/providers/dns/internal/active24/provider_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package active24
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- secret string
- expected string
- }{
- {
- desc: "success",
- apiKey: "user",
- secret: "secret",
- },
- {
- desc: "missing API key",
- apiKey: "",
- secret: "secret",
- expected: "credentials missing",
- },
- {
- desc: "missing secret",
- apiKey: "user",
- secret: "",
- expected: "credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := &Config{}
- config.APIKey = test.apiKey
- config.Secret = test.secret
-
- p, err := NewDNSProviderConfig(config, "example.com")
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
diff --git a/providers/dns/internal/active24/internal/types.go b/providers/dns/internal/active24/types.go
similarity index 99%
rename from providers/dns/internal/active24/internal/types.go
rename to providers/dns/internal/active24/types.go
index ed8dfc9d3..b9a7ea427 100644
--- a/providers/dns/internal/active24/internal/types.go
+++ b/providers/dns/internal/active24/types.go
@@ -1,4 +1,4 @@
-package internal
+package active24
import "fmt"
diff --git a/providers/dns/internal/clientdebug/.gitattributes b/providers/dns/internal/clientdebug/.gitattributes
deleted file mode 100644
index 0ce5804f7..000000000
--- a/providers/dns/internal/clientdebug/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-/testdata/** text eol=lf
diff --git a/providers/dns/internal/clientdebug/client.go b/providers/dns/internal/clientdebug/client.go
deleted file mode 100644
index 342577b93..000000000
--- a/providers/dns/internal/clientdebug/client.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package clientdebug
-
-import (
- "fmt"
- "io"
- "net/http"
- "net/http/httputil"
- "os"
- "regexp"
- "strconv"
- "strings"
-
- "github.com/go-acme/lego/v4/platform/config/env"
-)
-
-const replacement = "***"
-
-type Option func(*DumpTransport)
-
-func WithEnvKeys(keys ...string) Option {
- return func(d *DumpTransport) {
- for _, key := range keys {
- v := strings.TrimSpace(env.GetOrFile(key))
- if v == "" {
- continue
- }
-
- d.replacements = append(d.replacements, v, replacement)
- }
- }
-}
-
-func WithValues(values ...string) Option {
- return func(d *DumpTransport) {
- for _, value := range values {
- d.replacements = append(d.replacements, value, replacement)
- }
- }
-}
-
-func WithHeaders(keys ...string) Option {
- return func(d *DumpTransport) {
- d.regexps = append(d.regexps,
- regexp.MustCompile(fmt.Sprintf(`(?im)^(%s):.+$`, strings.Join(keys, "|"))))
- }
-}
-
-type DumpTransport struct {
- rt http.RoundTripper
-
- replacements []string
- replacer *strings.Replacer
-
- regexps []*regexp.Regexp
-
- writer io.Writer
-}
-
-func NewDumpTransport(rt http.RoundTripper, opts ...Option) *DumpTransport {
- if rt == nil {
- rt = http.DefaultTransport
- }
-
- d := &DumpTransport{
- rt: rt,
- writer: os.Stdout,
- }
-
- for _, opt := range opts {
- opt(d)
- }
-
- d.regexps = append(d.regexps,
- regexp.MustCompile(`(?im)^(Authorization):.+$`),
- regexp.MustCompile(`(?im)^(Token|X-Token):.+$`),
- regexp.MustCompile(`(?im)^(Auth-Token|X-Auth-Token):.+$`),
- regexp.MustCompile(`(?im)^(Api-Key|X-Api-Key|X-Api-Secret):.+$`),
- )
-
- if len(d.replacements) > 0 {
- d.replacer = strings.NewReplacer(d.replacements...)
- }
-
- return d
-}
-
-func (d *DumpTransport) RoundTrip(h *http.Request) (*http.Response, error) {
- data, _ := httputil.DumpRequestOut(h, true)
-
- _, _ = fmt.Fprintln(d.writer, "[HTTP Request]")
- _, _ = fmt.Fprintln(d.writer, d.redact(data))
-
- resp, err := d.rt.RoundTrip(h)
- if err != nil {
- return nil, err
- }
-
- data, _ = httputil.DumpResponse(resp, true)
-
- _, _ = fmt.Fprintln(d.writer, "[HTTP Response]")
- _, _ = fmt.Fprintln(d.writer, d.redact(data))
-
- return resp, err
-}
-
-func (d *DumpTransport) redact(content []byte) string {
- data := string(content)
-
- for _, r := range d.regexps {
- data = r.ReplaceAllString(data, "$1: "+replacement)
- }
-
- if d.replacer == nil {
- return data
- }
-
- return d.replacer.Replace(data)
-}
-
-// Wrap wraps an HTTP client Transport with the [DumpTransport].
-func Wrap(client *http.Client, opts ...Option) *http.Client {
- val, found := os.LookupEnv("LEGO_DEBUG_DNS_API_HTTP_CLIENT")
- if !found {
- return client
- }
-
- if ok, _ := strconv.ParseBool(val); !ok {
- return client
- }
-
- client.Transport = NewDumpTransport(client.Transport, opts...)
-
- return client
-}
diff --git a/providers/dns/internal/clientdebug/client_test.go b/providers/dns/internal/clientdebug/client_test.go
deleted file mode 100644
index 3a0c4021a..000000000
--- a/providers/dns/internal/clientdebug/client_test.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package clientdebug
-
-import (
- "bytes"
- "io"
- "net/http"
- "net/http/httptest"
- "net/url"
- "path/filepath"
- "strings"
- "testing"
- "text/template"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestWrap_redact_env_vars(t *testing.T) {
- t.Setenv("LEGO_DEBUG_DNS_API_HTTP_CLIENT", "true")
-
- t.Setenv("MY_VAR_01", "env-aaaa-aaaa")
- t.Setenv("MY_VAR_02", "query-aaaa-aaaa")
- t.Setenv("MY_VAR_03", "path-aaaa-aaaa")
- t.Setenv("MY_VAR_04", "request-body-aaaa-aaaa")
- t.Setenv("MY_VAR_05", "request-header-aaaa-aaaa")
- t.Setenv("MY_VAR_06", "response-body-aaaa-aaaa")
-
- buf := bytes.NewBufferString("")
-
- server, client, req := setupTest(t, buf,
- WithEnvKeys("MY_VAR_01", "MY_VAR_02", "MY_VAR_03", "MY_VAR_04", "MY_VAR_05", "MY_VAR_06"),
- )
-
- now := time.Now()
-
- resp, err := client.Transport.RoundTrip(req)
- require.NoError(t, err)
-
- assert.Equal(t, http.StatusOK, resp.StatusCode)
-
- assertDump(t, now, server, buf, "env_vars.txt")
-}
-
-func TestWrap_redact_headers(t *testing.T) {
- t.Setenv("LEGO_DEBUG_DNS_API_HTTP_CLIENT", "true")
-
- buf := bytes.NewBufferString("")
-
- server, client, req := setupTest(t, buf,
- WithHeaders("Secret-Request-Header", "Super-Secret-Request-Header", "Secret-Response-Header"),
- )
-
- now := time.Now()
-
- resp, err := client.Transport.RoundTrip(req)
- require.NoError(t, err)
-
- assert.Equal(t, http.StatusOK, resp.StatusCode)
-
- assertDump(t, now, server, buf, "headers.txt")
-}
-
-func TestWrap_redact_values(t *testing.T) {
- t.Setenv("LEGO_DEBUG_DNS_API_HTTP_CLIENT", "true")
-
- buf := bytes.NewBufferString("")
-
- server, client, req := setupTest(t, buf,
- WithValues("query-aaaa-aaaa", "path-aaaa-aaaa", "request-body-aaaa-aaaa"),
- )
-
- now := time.Now()
-
- resp, err := client.Transport.RoundTrip(req)
- require.NoError(t, err)
-
- assert.Equal(t, http.StatusOK, resp.StatusCode)
-
- assertDump(t, now, server, buf, "values.txt")
-}
-
-func fakeRequest(t *testing.T, baseURL string) *http.Request {
- t.Helper()
-
- endpoint, err := url.Parse(baseURL)
- require.NoError(t, err)
-
- query := endpoint.Query()
- query.Set("foo", "query-aaaa-aaaa")
- endpoint.RawQuery = query.Encode()
-
- endpoint = endpoint.JoinPath("path-aaaa-aaaa")
-
- body := `{
- "foo": "request-body-aaaa-aaaa"
-}
-`
-
- req := httptest.NewRequest(http.MethodGet, endpoint.String(), bytes.NewBufferString(body))
-
- req.Header.Set("X-Authorization", "not-redacted")
-
- req.Header.Set("Secret-Request-Header", "request-header-aaaa-aaaa")
- req.Header.Set("Super-Secret-Request-Header", "env-aaaa-aaaa")
-
- req.Header.Set("Authorization", "header-aaaa-0000")
- req.Header.Set("Token", "header-aaaa-0001")
- req.Header.Set("X-Token", "header-aaaa-0002")
- req.Header.Set("Auth-Token", "header-aaaa-0003")
- req.Header.Set("X-Auth-Token", "header-aaaa-0004")
- req.Header.Set("Api-Key", "header-aaaa-0006")
- req.Header.Set("X-Api-Key", "header-aaaa-0007")
- req.Header.Set("X-Api-Secret", "header-aaaa-0008")
-
- req.SetBasicAuth("user", "secret")
-
- return req
-}
-
-func fakeResponse() http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Secret-Response-Header", "response-header-aaaa-aaaa")
- _, _ = w.Write([]byte(`{
- "bar": "response-body-aaaa-aaaa"
-}`,
- ))
- }
-}
-
-func withWriter(w io.Writer) Option {
- return func(d *DumpTransport) {
- if w != nil {
- d.writer = w
- }
- }
-}
-
-func setupTest(t *testing.T, buf io.Writer, opts ...Option) (*httptest.Server, *http.Client, *http.Request) {
- t.Helper()
-
- server := httptest.NewServer(fakeResponse())
-
- opts = append(opts, withWriter(buf))
-
- client := Wrap(server.Client(), opts...)
-
- req := fakeRequest(t, server.URL)
-
- return server, client, req
-}
-
-func assertDump(t *testing.T, now time.Time, server *httptest.Server, actual *bytes.Buffer, filename string) {
- t.Helper()
-
- tmpl, err := template.New(filename).ParseFiles(filepath.Join("testdata", filename))
- require.NoError(t, err)
-
- expected := bytes.NewBufferString("")
-
- location, err := time.LoadLocation("GMT")
- require.NoError(t, err)
-
- baseURL, err := url.Parse(server.URL)
- require.NoError(t, err)
-
- err = tmpl.Execute(expected, map[string]string{
- "Host": baseURL.Host,
- "Date": now.In(location).Format(time.RFC1123),
- })
- require.NoError(t, err)
-
- assert.Equal(t, expected.String(), strings.ReplaceAll(actual.String(), "\r", ""))
-}
diff --git a/providers/dns/internal/clientdebug/testdata/env_vars.txt b/providers/dns/internal/clientdebug/testdata/env_vars.txt
deleted file mode 100644
index a2697850e..000000000
--- a/providers/dns/internal/clientdebug/testdata/env_vars.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-[HTTP Request]
-GET /***?foo=*** HTTP/1.1
-Host: {{ .Host }}
-User-Agent: Go-http-client/1.1
-Content-Length: 37
-Api-Key: ***
-Auth-Token: ***
-Authorization: ***
-Secret-Request-Header: ***
-Super-Secret-Request-Header: ***
-Token: ***
-X-Api-Key: ***
-X-Api-Secret: ***
-X-Auth-Token: ***
-X-Authorization: not-redacted
-X-Token: ***
-Accept-Encoding: gzip
-
-{
- "foo": "***"
-}
-
-[HTTP Response]
-HTTP/1.1 200 OK
-Content-Length: 37
-Content-Type: text/plain; charset=utf-8
-Date: {{ .Date }}
-Secret-Response-Header: response-header-aaaa-aaaa
-
-{
- "bar": "***"
-}
diff --git a/providers/dns/internal/clientdebug/testdata/headers.txt b/providers/dns/internal/clientdebug/testdata/headers.txt
deleted file mode 100644
index fe803fb22..000000000
--- a/providers/dns/internal/clientdebug/testdata/headers.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-[HTTP Request]
-GET /path-aaaa-aaaa?foo=query-aaaa-aaaa HTTP/1.1
-Host: {{ .Host }}
-User-Agent: Go-http-client/1.1
-Content-Length: 37
-Api-Key: ***
-Auth-Token: ***
-Authorization: ***
-Secret-Request-Header: ***
-Super-Secret-Request-Header: ***
-Token: ***
-X-Api-Key: ***
-X-Api-Secret: ***
-X-Auth-Token: ***
-X-Authorization: not-redacted
-X-Token: ***
-Accept-Encoding: gzip
-
-{
- "foo": "request-body-aaaa-aaaa"
-}
-
-[HTTP Response]
-HTTP/1.1 200 OK
-Content-Length: 37
-Content-Type: text/plain; charset=utf-8
-Date: {{ .Date }}
-Secret-Response-Header: ***
-
-{
- "bar": "response-body-aaaa-aaaa"
-}
diff --git a/providers/dns/internal/clientdebug/testdata/values.txt b/providers/dns/internal/clientdebug/testdata/values.txt
deleted file mode 100644
index b40f51f14..000000000
--- a/providers/dns/internal/clientdebug/testdata/values.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-[HTTP Request]
-GET /***?foo=*** HTTP/1.1
-Host: {{ .Host }}
-User-Agent: Go-http-client/1.1
-Content-Length: 37
-Api-Key: ***
-Auth-Token: ***
-Authorization: ***
-Secret-Request-Header: request-header-aaaa-aaaa
-Super-Secret-Request-Header: env-aaaa-aaaa
-Token: ***
-X-Api-Key: ***
-X-Api-Secret: ***
-X-Auth-Token: ***
-X-Authorization: not-redacted
-X-Token: ***
-Accept-Encoding: gzip
-
-{
- "foo": "***"
-}
-
-[HTTP Response]
-HTTP/1.1 200 OK
-Content-Length: 37
-Content-Type: text/plain; charset=utf-8
-Date: {{ .Date }}
-Secret-Response-Header: response-header-aaaa-aaaa
-
-{
- "bar": "response-body-aaaa-aaaa"
-}
diff --git a/providers/dns/internal/gcore/provider.go b/providers/dns/internal/gcore/provider.go
deleted file mode 100644
index b2078eba5..000000000
--- a/providers/dns/internal/gcore/provider.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Package gcore implements a DNS provider for solving the DNS-01 challenge using G-Core.
-package gcore
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/internal/gcore/internal"
-)
-
-const (
- DefaultPropagationTimeout = 360 * time.Second
- DefaultPollingInterval = 20 * time.Second
-)
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config for DNSProvider.
-type Config struct {
- APIToken string
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// DNSProvider an implementation of challenge.Provider contract.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for G-Core DNS API.
-func NewDNSProviderConfig(config *Config, baseURL string) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("the configuration of the DNS provider is nil")
- }
-
- if config.APIToken == "" {
- return nil, errors.New("incomplete credentials provided")
- }
-
- client := internal.NewClient(config.APIToken)
-
- if baseURL != "" {
- client.BaseURL, _ = url.Parse(baseURL)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record to fulfill the dns-01 challenge.
-func (d *DNSProvider) Present(domain, _, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx := context.Background()
-
- zone, err := d.guessZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return err
- }
-
- err = d.client.AddRRSet(ctx, zone, dns01.UnFqdn(info.EffectiveFQDN), info.Value, d.config.TTL)
- if err != nil {
- return fmt.Errorf("add txt record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx := context.Background()
-
- zone, err := d.guessZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return err
- }
-
- err = d.client.DeleteRRSet(ctx, zone, dns01.UnFqdn(info.EffectiveFQDN))
- if err != nil {
- return fmt.Errorf("remove txt record: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) guessZone(ctx context.Context, fqdn string) (string, error) {
- var lastErr error
-
- for zone := range dns01.UnFqdnDomainsSeq(fqdn) {
- dnsZone, err := d.client.GetZone(ctx, zone)
- if err != nil {
- lastErr = err
- continue
- }
-
- return dnsZone.Name, nil
- }
-
- return "", fmt.Errorf("zone %q not found: %w", fqdn, lastErr)
-}
diff --git a/providers/dns/internal/gcore/provider_test.go b/providers/dns/internal/gcore/provider_test.go
deleted file mode 100644
index f29dadff9..000000000
--- a/providers/dns/internal/gcore/provider_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package gcore
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiToken string
- expected string
- }{
- {
- desc: "success",
- apiToken: "A",
- },
- {
- desc: "missing credentials",
- expected: "incomplete credentials provided",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := &Config{}
- config.APIToken = test.apiToken
-
- p, err := NewDNSProviderConfig(config, "")
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
diff --git a/providers/dns/internal/hostingde/internal/client.go b/providers/dns/internal/hostingde/client.go
similarity index 83%
rename from providers/dns/internal/hostingde/internal/client.go
rename to providers/dns/internal/hostingde/client.go
index 133c3479c..869d93d3e 100644
--- a/providers/dns/internal/hostingde/internal/client.go
+++ b/providers/dns/internal/hostingde/client.go
@@ -1,4 +1,4 @@
-package internal
+package hostingde
import (
"bytes"
@@ -10,11 +10,14 @@ import (
"net/url"
"time"
- "github.com/cenkalti/backoff/v5"
+ "github.com/cenkalti/backoff/v4"
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
)
-const defaultBaseURL = "https://secure.hosting.de/api/dns/v1/json"
+const (
+ DefaultHostingdeBaseURL = "https://secure.hosting.de/api/dns/v1/json"
+ DefaultHTTPNetBaseURL = "https://partner.http.net/api/dns/v1/json"
+)
// Client the API client for Hosting.de.
type Client struct {
@@ -26,7 +29,7 @@ type Client struct {
// NewClient creates new Client.
func NewClient(apiKey string) *Client {
- baseURL, _ := url.Parse(defaultBaseURL)
+ baseURL, _ := url.Parse(DefaultHostingdeBaseURL)
return &Client{
apiKey: apiKey,
@@ -37,25 +40,35 @@ func NewClient(apiKey string) *Client {
// GetZone gets a zone.
func (c *Client) GetZone(ctx context.Context, req ZoneConfigsFindRequest) (*ZoneConfig, error) {
- operation := func() (*ZoneConfig, error) {
+ var zoneConfig *ZoneConfig
+
+ operation := func() error {
response, err := c.ListZoneConfigs(ctx, req)
if err != nil {
- return nil, backoff.Permanent(err)
+ return backoff.Permanent(err)
}
if response.Data[0].Status != "active" {
- return nil, fmt.Errorf("unexpected status: %q", response.Data[0].Status)
+ return fmt.Errorf("unexpected status: %q", response.Data[0].Status)
}
- return &response.Data[0], nil
+ zoneConfig = &response.Data[0]
+
+ return nil
}
bo := backoff.NewExponentialBackOff()
bo.InitialInterval = 3 * time.Second
bo.MaxInterval = 10 * bo.InitialInterval
+ bo.MaxElapsedTime = 100 * bo.InitialInterval
// retry in case the zone was edited recently and is not yet active
- return backoff.Retry(ctx, operation, backoff.WithBackOff(bo), backoff.WithMaxElapsedTime(100*bo.InitialInterval))
+ err := backoff.Retry(operation, bo)
+ if err != nil {
+ return nil, err
+ }
+
+ return zoneConfig, nil
}
// ListZoneConfigs lists zone configuration.
diff --git a/providers/dns/internal/hostingde/internal/client_test.go b/providers/dns/internal/hostingde/client_test.go
similarity index 99%
rename from providers/dns/internal/hostingde/internal/client_test.go
rename to providers/dns/internal/hostingde/client_test.go
index d55bbf690..93e0c76e1 100644
--- a/providers/dns/internal/hostingde/internal/client_test.go
+++ b/providers/dns/internal/hostingde/client_test.go
@@ -1,4 +1,4 @@
-package internal
+package hostingde
import (
"encoding/json"
diff --git a/providers/dns/internal/hostingde/internal/fixtures/zoneConfigsFind-request.json b/providers/dns/internal/hostingde/fixtures/zoneConfigsFind-request.json
similarity index 100%
rename from providers/dns/internal/hostingde/internal/fixtures/zoneConfigsFind-request.json
rename to providers/dns/internal/hostingde/fixtures/zoneConfigsFind-request.json
diff --git a/providers/dns/internal/hostingde/internal/fixtures/zoneConfigsFind.json b/providers/dns/internal/hostingde/fixtures/zoneConfigsFind.json
similarity index 100%
rename from providers/dns/internal/hostingde/internal/fixtures/zoneConfigsFind.json
rename to providers/dns/internal/hostingde/fixtures/zoneConfigsFind.json
diff --git a/providers/dns/internal/hostingde/internal/fixtures/zoneConfigsFind_error.json b/providers/dns/internal/hostingde/fixtures/zoneConfigsFind_error.json
similarity index 100%
rename from providers/dns/internal/hostingde/internal/fixtures/zoneConfigsFind_error.json
rename to providers/dns/internal/hostingde/fixtures/zoneConfigsFind_error.json
diff --git a/providers/dns/internal/hostingde/internal/fixtures/zoneUpdate-request.json b/providers/dns/internal/hostingde/fixtures/zoneUpdate-request.json
similarity index 100%
rename from providers/dns/internal/hostingde/internal/fixtures/zoneUpdate-request.json
rename to providers/dns/internal/hostingde/fixtures/zoneUpdate-request.json
diff --git a/providers/dns/internal/hostingde/internal/fixtures/zoneUpdate.json b/providers/dns/internal/hostingde/fixtures/zoneUpdate.json
similarity index 100%
rename from providers/dns/internal/hostingde/internal/fixtures/zoneUpdate.json
rename to providers/dns/internal/hostingde/fixtures/zoneUpdate.json
diff --git a/providers/dns/internal/hostingde/internal/fixtures/zoneUpdate_error.json b/providers/dns/internal/hostingde/fixtures/zoneUpdate_error.json
similarity index 100%
rename from providers/dns/internal/hostingde/internal/fixtures/zoneUpdate_error.json
rename to providers/dns/internal/hostingde/fixtures/zoneUpdate_error.json
diff --git a/providers/dns/internal/hostingde/provider.go b/providers/dns/internal/hostingde/provider.go
deleted file mode 100644
index b5277f042..000000000
--- a/providers/dns/internal/hostingde/provider.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// Package hostingde implements a DNS provider for solving the DNS-01 challenge using hosting.de.
-package hostingde
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/internal/hostingde/internal"
-)
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
- ZoneName string
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- recordIDs map[string]string
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for hosting.de.
-func NewDNSProviderConfig(config *Config, baseURL string) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("the configuration of the DNS provider is nil")
- }
-
- if config.APIKey == "" {
- return nil, errors.New("API key missing")
- }
-
- client := internal.NewClient(config.APIKey)
-
- if baseURL != "" {
- client.BaseURL, _ = url.Parse(baseURL)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]string),
- }, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record to fulfill the dns-01 challenge.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zoneName, err := d.getZoneName(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("could not find zone for domain %q: %w", domain, err)
- }
-
- ctx := context.Background()
-
- // get the ZoneConfig for that domain
- zonesFind := internal.ZoneConfigsFindRequest{
- Filter: internal.Filter{Field: "zoneName", Value: zoneName},
- Limit: 1,
- Page: 1,
- }
-
- zoneConfig, err := d.client.GetZone(ctx, zonesFind)
- if err != nil {
- return err
- }
-
- zoneConfig.Name = zoneName
-
- rec := []internal.DNSRecord{{
- Type: "TXT",
- Name: dns01.UnFqdn(info.EffectiveFQDN),
- Content: info.Value,
- TTL: d.config.TTL,
- }}
-
- req := internal.ZoneUpdateRequest{
- ZoneConfig: *zoneConfig,
- RecordsToAdd: rec,
- }
-
- response, err := d.client.UpdateZone(ctx, req)
- if err != nil {
- return err
- }
-
- for _, record := range response.Records {
- if record.Name == dns01.UnFqdn(info.EffectiveFQDN) && record.Content == fmt.Sprintf(`%q`, info.Value) {
- d.recordIDsMu.Lock()
- d.recordIDs[info.EffectiveFQDN] = record.ID
- d.recordIDsMu.Unlock()
- }
- }
-
- if d.recordIDs[info.EffectiveFQDN] == "" {
- return fmt.Errorf("error getting ID of just created record, for domain %s", domain)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zoneName, err := d.getZoneName(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("could not find zone for domain %q: %w", domain, err)
- }
-
- ctx := context.Background()
-
- // get the ZoneConfig for that domain
- zonesFind := internal.ZoneConfigsFindRequest{
- Filter: internal.Filter{Field: "zoneName", Value: zoneName},
- Limit: 1,
- Page: 1,
- }
-
- zoneConfig, err := d.client.GetZone(ctx, zonesFind)
- if err != nil {
- return err
- }
-
- zoneConfig.Name = zoneName
-
- rec := []internal.DNSRecord{{
- Type: "TXT",
- Name: dns01.UnFqdn(info.EffectiveFQDN),
- Content: `"` + info.Value + `"`,
- }}
-
- req := internal.ZoneUpdateRequest{
- ZoneConfig: *zoneConfig,
- RecordsToDelete: rec,
- }
-
- _, err = d.client.UpdateZone(ctx, req)
- if err != nil {
- return err
- }
-
- // Delete record ID from map
- d.recordIDsMu.Lock()
- delete(d.recordIDs, info.EffectiveFQDN)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-func (d *DNSProvider) getZoneName(fqdn string) (string, error) {
- if d.config.ZoneName != "" {
- return d.config.ZoneName, nil
- }
-
- zoneName, err := dns01.FindZoneByFqdn(fqdn)
- if err != nil {
- return "", fmt.Errorf("could not find zone for %s: %w", fqdn, err)
- }
-
- if zoneName == "" {
- return "", errors.New("empty zone name")
- }
-
- return dns01.UnFqdn(zoneName), nil
-}
diff --git a/providers/dns/internal/hostingde/provider_test.go b/providers/dns/internal/hostingde/provider_test.go
deleted file mode 100644
index 3cdabf702..000000000
--- a/providers/dns/internal/hostingde/provider_test.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package hostingde
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- zoneName string
- expected string
- }{
- {
- desc: "success",
- apiKey: "123",
- zoneName: "example.org",
- },
- {
- desc: "missing credentials",
- expected: "API key missing",
- },
- {
- desc: "missing api key",
- zoneName: "456",
- expected: "API key missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := &Config{}
- config.APIKey = test.apiKey
- config.ZoneName = test.zoneName
-
- p, err := NewDNSProviderConfig(config, "")
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.recordIDs)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
diff --git a/providers/dns/internal/hostingde/internal/types.go b/providers/dns/internal/hostingde/types.go
similarity index 98%
rename from providers/dns/internal/hostingde/internal/types.go
rename to providers/dns/internal/hostingde/types.go
index 330eab27d..4f3347190 100644
--- a/providers/dns/internal/hostingde/internal/types.go
+++ b/providers/dns/internal/hostingde/types.go
@@ -1,4 +1,4 @@
-package internal
+package hostingde
import "encoding/json"
@@ -88,8 +88,7 @@ type Zone struct {
// https://www.hosting.de/api/?json#updating-zones
type ZoneUpdateRequest struct {
BaseRequest
- ZoneConfig `json:"zoneConfig"`
-
+ ZoneConfig `json:"zoneConfig"`
RecordsToAdd []DNSRecord `json:"recordsToAdd"`
RecordsToDelete []DNSRecord `json:"recordsToDelete"`
}
@@ -98,7 +97,6 @@ type ZoneUpdateRequest struct {
// https://www.hosting.de/api/?json#list-zoneconfigs
type ZoneConfigsFindRequest struct {
BaseRequest
-
Filter Filter `json:"filter"`
Limit int `json:"limit"`
Page int `json:"page"`
diff --git a/providers/dns/internal/ionos/provider.go b/providers/dns/internal/ionos/provider.go
deleted file mode 100644
index a7d145840..000000000
--- a/providers/dns/internal/ionos/provider.go
+++ /dev/null
@@ -1,173 +0,0 @@
-package ionos
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- ionos "github.com/go-acme/lego/v4/providers/dns/internal/ionos/internal"
-)
-
-const MinTTL = 300
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *ionos.Client
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Ionos.
-func NewDNSProviderConfig(config *Config, baseURL string) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("the configuration of the DNS provider is nil")
- }
-
- if config.APIKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- if config.TTL < MinTTL {
- return nil, fmt.Errorf("invalid TTL, TTL (%d) must be greater than %d", config.TTL, MinTTL)
- }
-
- client, err := ionos.NewClient(config.APIKey)
- if err != nil {
- return nil, err
- }
-
- if baseURL != "" {
- client.BaseURL, _ = url.Parse(baseURL)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{config: config, client: client}, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, _, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx := context.Background()
-
- zones, err := d.client.ListZones(ctx)
- if err != nil {
- return fmt.Errorf("failed to get zones: %w", err)
- }
-
- name := dns01.UnFqdn(info.EffectiveFQDN)
-
- zone := findZone(zones, name)
- if zone == nil {
- return errors.New("no matching zone found for domain")
- }
-
- filter := &ionos.RecordsFilter{
- Suffix: name,
- RecordType: "TXT",
- }
-
- records, err := d.client.GetRecords(ctx, zone.ID, filter)
- if err != nil {
- return fmt.Errorf("failed to get records (zone=%s): %w", zone.ID, err)
- }
-
- records = append(records, ionos.Record{
- Name: name,
- Content: info.Value,
- TTL: d.config.TTL,
- Type: "TXT",
- })
-
- err = d.client.ReplaceRecords(ctx, zone.ID, records)
- if err != nil {
- return fmt.Errorf("failed to create/update records (zone=%s): %w", zone.ID, err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx := context.Background()
-
- zones, err := d.client.ListZones(ctx)
- if err != nil {
- return fmt.Errorf("failed to get zones: %w", err)
- }
-
- name := dns01.UnFqdn(info.EffectiveFQDN)
-
- zone := findZone(zones, name)
- if zone == nil {
- return errors.New("no matching zone found for domain")
- }
-
- filter := &ionos.RecordsFilter{
- Suffix: name,
- RecordType: "TXT",
- }
-
- records, err := d.client.GetRecords(ctx, zone.ID, filter)
- if err != nil {
- return fmt.Errorf("failed to get records (zone=%s): %w", zone.ID, err)
- }
-
- for _, record := range records {
- if record.Name == name && record.Content == strconv.Quote(info.Value) {
- err = d.client.RemoveRecord(ctx, zone.ID, record.ID)
- if err != nil {
- return fmt.Errorf("failed to remove record (zone=%s, record=%s): %w", zone.ID, record.ID, err)
- }
-
- return nil
- }
- }
-
- return fmt.Errorf("failed to remove record, record not found (zone=%s, domain=%s, fqdn=%s, value=%s)", zone.ID, domain, info.EffectiveFQDN, info.Value)
-}
-
-func findZone(zones []ionos.Zone, domain string) *ionos.Zone {
- var result *ionos.Zone
-
- for _, zone := range zones {
- if zone.Name != "" && strings.HasSuffix(domain, zone.Name) {
- if result == nil || len(zone.Name) > len(result.Name) {
- result = &zone
- }
- }
- }
-
- return result
-}
diff --git a/providers/dns/internal/ionos/provider_test.go b/providers/dns/internal/ionos/provider_test.go
deleted file mode 100644
index 6b4df5cc7..000000000
--- a/providers/dns/internal/ionos/provider_test.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package ionos
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- tll int
- expected string
- }{
- {
- desc: "success",
- apiKey: "123",
- tll: MinTTL,
- },
- {
- desc: "missing credentials",
- tll: MinTTL,
- expected: "credentials missing",
- },
- {
- desc: "invalid TTL",
- apiKey: "123",
- tll: 30,
- expected: "invalid TTL, TTL (30) must be greater than 300",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := &Config{}
- config.APIKey = test.apiKey
- config.TTL = test.tll
-
- p, err := NewDNSProviderConfig(config, "")
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
diff --git a/providers/dns/internal/rimuhosting/internal/client.go b/providers/dns/internal/rimuhosting/client.go
similarity index 94%
rename from providers/dns/internal/rimuhosting/internal/client.go
rename to providers/dns/internal/rimuhosting/client.go
index 5bf7393e7..06292453a 100644
--- a/providers/dns/internal/rimuhosting/internal/client.go
+++ b/providers/dns/internal/rimuhosting/client.go
@@ -1,4 +1,4 @@
-package internal
+package rimuhosting
import (
"context"
@@ -15,7 +15,11 @@ import (
querystring "github.com/google/go-querystring/query"
)
-const defaultBaseURL = "https://rimuhosting.com/dns/dyndns.jsp"
+// Base URL for the RimuHosting DNS services.
+const (
+ DefaultZonomiBaseURL = "https://zonomi.com/app/dns/dyndns.jsp"
+ DefaultRimuHostingBaseURL = "https://rimuhosting.com/dns/dyndns.jsp"
+)
// Action names.
const (
@@ -36,7 +40,7 @@ type Client struct {
func NewClient(apiKey string) *Client {
return &Client{
apiKey: apiKey,
- BaseURL: defaultBaseURL,
+ BaseURL: DefaultZonomiBaseURL,
HTTPClient: &http.Client{Timeout: 5 * time.Second},
}
}
@@ -78,17 +82,14 @@ func (c *Client) DoActions(ctx context.Context, actions ...ActionParameter) (*DN
if err != nil {
return nil, err
}
-
return resp, nil
}
multi := c.toMultiParameters(actions)
-
err := c.do(ctx, multi, resp)
if err != nil {
return nil, err
}
-
return resp, nil
}
@@ -159,7 +160,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errAPI := APIError{}
-
err := xml.Unmarshal(raw, &errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/internal/rimuhosting/internal/client_test.go b/providers/dns/internal/rimuhosting/client_test.go
similarity index 99%
rename from providers/dns/internal/rimuhosting/internal/client_test.go
rename to providers/dns/internal/rimuhosting/client_test.go
index 00126dfbe..6ee9ea3f7 100644
--- a/providers/dns/internal/rimuhosting/internal/client_test.go
+++ b/providers/dns/internal/rimuhosting/client_test.go
@@ -1,4 +1,4 @@
-package internal
+package rimuhosting
import (
"encoding/xml"
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/add_record.xml b/providers/dns/internal/rimuhosting/fixtures/add_record.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/add_record.xml
rename to providers/dns/internal/rimuhosting/fixtures/add_record.xml
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/add_record_error.xml b/providers/dns/internal/rimuhosting/fixtures/add_record_error.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/add_record_error.xml
rename to providers/dns/internal/rimuhosting/fixtures/add_record_error.xml
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/add_record_same_domain.xml b/providers/dns/internal/rimuhosting/fixtures/add_record_same_domain.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/add_record_same_domain.xml
rename to providers/dns/internal/rimuhosting/fixtures/add_record_same_domain.xml
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/delete_record.xml b/providers/dns/internal/rimuhosting/fixtures/delete_record.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/delete_record.xml
rename to providers/dns/internal/rimuhosting/fixtures/delete_record.xml
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/delete_record_error.xml b/providers/dns/internal/rimuhosting/fixtures/delete_record_error.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/delete_record_error.xml
rename to providers/dns/internal/rimuhosting/fixtures/delete_record_error.xml
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/delete_record_nothing.xml b/providers/dns/internal/rimuhosting/fixtures/delete_record_nothing.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/delete_record_nothing.xml
rename to providers/dns/internal/rimuhosting/fixtures/delete_record_nothing.xml
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/find_records.xml b/providers/dns/internal/rimuhosting/fixtures/find_records.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/find_records.xml
rename to providers/dns/internal/rimuhosting/fixtures/find_records.xml
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/find_records_empty.xml b/providers/dns/internal/rimuhosting/fixtures/find_records_empty.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/find_records_empty.xml
rename to providers/dns/internal/rimuhosting/fixtures/find_records_empty.xml
diff --git a/providers/dns/internal/rimuhosting/internal/fixtures/find_records_pattern.xml b/providers/dns/internal/rimuhosting/fixtures/find_records_pattern.xml
similarity index 100%
rename from providers/dns/internal/rimuhosting/internal/fixtures/find_records_pattern.xml
rename to providers/dns/internal/rimuhosting/fixtures/find_records_pattern.xml
diff --git a/providers/dns/internal/rimuhosting/provider.go b/providers/dns/internal/rimuhosting/provider.go
deleted file mode 100644
index 3be764cbf..000000000
--- a/providers/dns/internal/rimuhosting/provider.go
+++ /dev/null
@@ -1,107 +0,0 @@
-// Package rimuhosting implements a DNS provider for solving the DNS-01 challenge using RimuHosting DNS.
-package rimuhosting
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/internal/rimuhosting/internal"
-)
-
-const DefaultTTL = 3600
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for RimuHosting.
-func NewDNSProviderConfig(config *Config, baseURL string) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("the configuration of the DNS provider is nil")
- }
-
- if config.APIKey == "" {
- return nil, errors.New("incomplete credentials, missing API key")
- }
-
- client := internal.NewClient(config.APIKey)
-
- if baseURL != "" {
- client.BaseURL = baseURL
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{config: config, client: client}, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx := context.Background()
-
- records, err := d.client.FindTXTRecords(ctx, dns01.UnFqdn(info.EffectiveFQDN))
- if err != nil {
- return fmt.Errorf("failed to find record(s) for %s: %w", domain, err)
- }
-
- actions := []internal.ActionParameter{
- internal.NewAddRecordAction(dns01.UnFqdn(info.EffectiveFQDN), info.Value, d.config.TTL),
- }
-
- for _, record := range records {
- actions = append(actions, internal.NewAddRecordAction(record.Name, record.Content, d.config.TTL))
- }
-
- _, err = d.client.DoActions(ctx, actions...)
- if err != nil {
- return fmt.Errorf("failed to add record(s) for %s: %w", domain, err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- action := internal.NewDeleteRecordAction(dns01.UnFqdn(info.EffectiveFQDN), info.Value)
-
- _, err := d.client.DoActions(context.Background(), action)
- if err != nil {
- return fmt.Errorf("failed to delete record for %s: %w", domain, err)
- }
-
- return nil
-}
diff --git a/providers/dns/internal/rimuhosting/provider_test.go b/providers/dns/internal/rimuhosting/provider_test.go
deleted file mode 100644
index d1569af31..000000000
--- a/providers/dns/internal/rimuhosting/provider_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package rimuhosting
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- expected string
- apiKey string
- secretKey string
- }{
- {
- desc: "success",
- apiKey: "api_key",
- secretKey: "api_secret",
- },
- {
- desc: "missing api key",
- apiKey: "",
- secretKey: "api_secret",
- expected: "incomplete credentials, missing API key",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := &Config{}
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config, "")
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
diff --git a/providers/dns/internal/rimuhosting/internal/types.go b/providers/dns/internal/rimuhosting/types.go
similarity index 98%
rename from providers/dns/internal/rimuhosting/internal/types.go
rename to providers/dns/internal/rimuhosting/types.go
index c3df886a2..bdb333032 100644
--- a/providers/dns/internal/rimuhosting/internal/types.go
+++ b/providers/dns/internal/rimuhosting/types.go
@@ -1,4 +1,4 @@
-package internal
+package rimuhosting
import "encoding/xml"
diff --git a/providers/dns/internal/selectel/internal/client.go b/providers/dns/internal/selectel/client.go
similarity index 91%
rename from providers/dns/internal/selectel/internal/client.go
rename to providers/dns/internal/selectel/client.go
index d441c9894..1e1e4a215 100644
--- a/providers/dns/internal/selectel/internal/client.go
+++ b/providers/dns/internal/selectel/client.go
@@ -1,4 +1,4 @@
-package internal
+package selectel
import (
"bytes"
@@ -15,11 +15,15 @@ import (
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
)
-const defaultBaseURL = "https://api.selectel.ru/domains/v1"
+// Base URL for the Selectel/VScale DNS services.
+const (
+ DefaultSelectelBaseURL = "https://api.selectel.ru/domains/v1"
+ DefaultVScaleBaseURL = "https://api.vscale.io/v1/domains"
+)
const tokenHeader = "X-Token"
-// Client represents the DNS client.
+// Client represents DNS client.
type Client struct {
token string
@@ -29,7 +33,7 @@ type Client struct {
// NewClient returns a client instance.
func NewClient(token string) *Client {
- baseURL, _ := url.Parse(defaultBaseURL)
+ baseURL, _ := url.Parse(DefaultVScaleBaseURL)
return &Client{
token: token,
@@ -48,13 +52,12 @@ func (c *Client) GetDomainByName(ctx context.Context, domainName string) (*Domai
}
domain := &Domain{}
-
statusCode, err := c.do(req, domain)
if err != nil {
if statusCode == http.StatusNotFound && strings.Count(domainName, ".") > 1 {
// Look up for the next subdomain
- _, after, _ := strings.Cut(domainName, ".")
- return c.GetDomainByName(ctx, after)
+ subIndex := strings.Index(domainName, ".")
+ return c.GetDomainByName(ctx, domainName[subIndex+1:])
}
return nil, err
@@ -71,7 +74,6 @@ func (c *Client) AddRecord(ctx context.Context, domainID int, body Record) (*Rec
}
record := &Record{}
-
_, err = c.do(req, record)
if err != nil {
return nil, err
@@ -88,7 +90,6 @@ func (c *Client) ListRecords(ctx context.Context, domainID int) ([]Record, error
}
var records []Record
-
_, err = c.do(req, &records)
if err != nil {
return nil, err
@@ -107,7 +108,6 @@ func (c *Client) DeleteRecord(ctx context.Context, domainID, recordID int) error
}
_, err = c.do(req, nil)
-
return err
}
@@ -170,7 +170,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errAPI := &APIError{}
-
err := json.Unmarshal(raw, errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/internal/selectel/internal/client_test.go b/providers/dns/internal/selectel/client_test.go
similarity index 99%
rename from providers/dns/internal/selectel/internal/client_test.go
rename to providers/dns/internal/selectel/client_test.go
index edabe0130..292f70142 100644
--- a/providers/dns/internal/selectel/internal/client_test.go
+++ b/providers/dns/internal/selectel/client_test.go
@@ -1,4 +1,4 @@
-package internal
+package selectel
import (
"net/http"
diff --git a/providers/dns/internal/selectel/internal/fixtures/add_record-request.json b/providers/dns/internal/selectel/fixtures/add_record-request.json
similarity index 100%
rename from providers/dns/internal/selectel/internal/fixtures/add_record-request.json
rename to providers/dns/internal/selectel/fixtures/add_record-request.json
diff --git a/providers/dns/internal/selectel/internal/fixtures/add_record.json b/providers/dns/internal/selectel/fixtures/add_record.json
similarity index 100%
rename from providers/dns/internal/selectel/internal/fixtures/add_record.json
rename to providers/dns/internal/selectel/fixtures/add_record.json
diff --git a/providers/dns/internal/selectel/internal/fixtures/domains.json b/providers/dns/internal/selectel/fixtures/domains.json
similarity index 100%
rename from providers/dns/internal/selectel/internal/fixtures/domains.json
rename to providers/dns/internal/selectel/fixtures/domains.json
diff --git a/providers/dns/internal/selectel/internal/fixtures/error.json b/providers/dns/internal/selectel/fixtures/error.json
similarity index 100%
rename from providers/dns/internal/selectel/internal/fixtures/error.json
rename to providers/dns/internal/selectel/fixtures/error.json
diff --git a/providers/dns/internal/selectel/internal/fixtures/list_records.json b/providers/dns/internal/selectel/fixtures/list_records.json
similarity index 100%
rename from providers/dns/internal/selectel/internal/fixtures/list_records.json
rename to providers/dns/internal/selectel/fixtures/list_records.json
diff --git a/providers/dns/internal/selectel/provider.go b/providers/dns/internal/selectel/provider.go
deleted file mode 100644
index 495735736..000000000
--- a/providers/dns/internal/selectel/provider.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Package selectel implements a DNS provider for solving the DNS-01 challenge using Selectel Domains API.
-package selectel
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/internal/selectel/internal"
-)
-
-const MinTTL = 60
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Token string
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-
- // TODO(ldez): remove in v5?
- BaseURL string
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for selectel.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("the configuration of the DNS provider is nil")
- }
-
- if config.Token == "" {
- return nil, errors.New("credentials missing")
- }
-
- if config.TTL < MinTTL {
- return nil, fmt.Errorf("invalid TTL, TTL (%d) must be greater than %d", config.TTL, MinTTL)
- }
-
- client := internal.NewClient(config.Token)
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- var err error
-
- client.BaseURL, err = url.Parse(config.BaseURL)
- if err != nil {
- return nil, fmt.Errorf("%w", err)
- }
-
- return &DNSProvider{config: config, client: client}, nil
-}
-
-// Timeout returns the Timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record to fulfill DNS-01 challenge.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- ctx := context.Background()
-
- // TODO(ldez) replace domain by FQDN to follow CNAME.
- domainObj, err := d.client.GetDomainByName(ctx, domain)
- if err != nil {
- return fmt.Errorf("get domain by name: %w", err)
- }
-
- txtRecord := internal.Record{
- Type: "TXT",
- TTL: d.config.TTL,
- Name: info.EffectiveFQDN,
- Content: info.Value,
- }
-
- _, err = d.client.AddRecord(ctx, domainObj.ID, txtRecord)
- if err != nil {
- return fmt.Errorf("add record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes a TXT record used for DNS-01 challenge.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- recordName := dns01.UnFqdn(info.EffectiveFQDN)
-
- ctx := context.Background()
-
- // TODO(ldez) replace domain by FQDN to follow CNAME.
- domainObj, err := d.client.GetDomainByName(ctx, domain)
- if err != nil {
- return fmt.Errorf("%w", err)
- }
-
- records, err := d.client.ListRecords(ctx, domainObj.ID)
- if err != nil {
- return fmt.Errorf("list records: %w", err)
- }
-
- // Delete records with specific FQDN
- var lastErr error
-
- for _, record := range records {
- if record.Name == recordName {
- err = d.client.DeleteRecord(ctx, domainObj.ID, record.ID)
- if err != nil {
- lastErr = fmt.Errorf("delete record: %w", err)
- }
- }
- }
-
- return lastErr
-}
diff --git a/providers/dns/internal/selectel/provider_test.go b/providers/dns/internal/selectel/provider_test.go
deleted file mode 100644
index 75a032bf4..000000000
--- a/providers/dns/internal/selectel/provider_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package selectel
-
-import (
- "fmt"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- token string
- ttl int
- expected string
- }{
- {
- desc: "success",
- token: "123",
- ttl: 60,
- },
- {
- desc: "missing api key",
- token: "",
- ttl: 60,
- expected: "credentials missing",
- },
- {
- desc: "bad TTL value",
- token: "123",
- ttl: 59,
- expected: fmt.Sprintf("invalid TTL, TTL (59) must be greater than %d", MinTTL),
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := &Config{}
- config.TTL = test.ttl
- config.Token = test.token
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- assert.NotNil(t, p.config)
- assert.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
diff --git a/providers/dns/internal/selectel/internal/types.go b/providers/dns/internal/selectel/types.go
similarity index 98%
rename from providers/dns/internal/selectel/internal/types.go
rename to providers/dns/internal/selectel/types.go
index e6ca792c0..df7bb3fa7 100644
--- a/providers/dns/internal/selectel/internal/types.go
+++ b/providers/dns/internal/selectel/types.go
@@ -1,4 +1,4 @@
-package internal
+package selectel
import "fmt"
diff --git a/providers/dns/internal/tecnocratica/internal/client.go b/providers/dns/internal/tecnocratica/internal/client.go
deleted file mode 100644
index 5a529fa2f..000000000
--- a/providers/dns/internal/tecnocratica/internal/client.go
+++ /dev/null
@@ -1,182 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-// defaultBaseURL is the default API endpoint.
-const defaultBaseURL = "https://api.neodigit.net/v1"
-
-// Client is a Tecnocrática API client.
-type Client struct {
- token string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(token string) (*Client, error) {
- if token == "" {
- return nil, errors.New("credentials missing: token")
- }
-
- baseURL, err := url.Parse(defaultBaseURL)
- if err != nil {
- return nil, err
- }
-
- return &Client{
- token: token,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 30 * time.Second},
- }, nil
-}
-
-// GetZones lists all DNS zones.
-func (c *Client) GetZones(ctx context.Context) ([]Zone, error) {
- endpoint := c.BaseURL.JoinPath("dns", "zones")
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var zones []Zone
-
- err = c.do(req, &zones)
- if err != nil {
- return nil, err
- }
-
- return zones, nil
-}
-
-// GetRecords lists all records in a zone.
-func (c *Client) GetRecords(ctx context.Context, zoneID int, recordType string) ([]Record, error) {
- endpoint := c.BaseURL.JoinPath("dns", "zones", strconv.Itoa(zoneID), "records")
-
- if recordType != "" {
- query := endpoint.Query()
- query.Set("type", recordType)
- endpoint.RawQuery = query.Encode()
- }
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var records []Record
-
- err = c.do(req, &records)
- if err != nil {
- return nil, err
- }
-
- return records, nil
-}
-
-// CreateRecord creates a new DNS record.
-func (c *Client) CreateRecord(ctx context.Context, zoneID int, record Record) (*Record, error) {
- endpoint := c.BaseURL.JoinPath("dns", "zones", strconv.Itoa(zoneID), "records")
-
- payload := RecordRequest{Record: record}
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, payload)
- if err != nil {
- return nil, err
- }
-
- var result Record
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, nil
-}
-
-// DeleteRecord deletes a DNS record.
-func (c *Client) DeleteRecord(ctx context.Context, zoneID, recordID int) error {
- endpoint := c.BaseURL.JoinPath("dns", "zones", strconv.Itoa(zoneID), "records", strconv.Itoa(recordID))
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Set("X-TCpanel-Token", c.token)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- return req, nil
-}
diff --git a/providers/dns/internal/tecnocratica/internal/client_test.go b/providers/dns/internal/tecnocratica/internal/client_test.go
deleted file mode 100644
index 4e9cf3e85..000000000
--- a/providers/dns/internal/tecnocratica/internal/client_test.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().WithJSONHeaders().
- With("X-TCpanel-Token", "secret"))
-}
-
-func TestClient_GetZones(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/zones",
- servermock.ResponseFromFixture("get_zones.json")).
- Build(t)
-
- zones, err := client.GetZones(t.Context())
- require.NoError(t, err)
-
- expected := []Zone{
- {
- ID: 6,
- Name: "example.com",
- HumanName: "example.com",
- },
- {
- ID: 7,
- Name: "example.org",
- HumanName: "example.org",
- },
- }
-
- assert.Equal(t, expected, zones)
-}
-
-func TestClient_GetZones_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/zones",
- servermock.RawStringResponse(`{"error": "unauthorized"}`).
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- zones, err := client.GetZones(t.Context())
- require.Error(t, err)
-
- assert.Nil(t, zones)
-}
-
-func TestClient_GetRecords(t *testing.T) {
- client := mockBuilder().
- Route("GET /dns/zones/6/records",
- servermock.ResponseFromFixture("get_records.json")).
- Build(t)
-
- records, err := client.GetRecords(t.Context(), 6, "")
- require.NoError(t, err)
-
- expected := []Record{
- {
- ID: 98,
- Name: "",
- Type: "SOA",
- Content: "ns1.example.org dns.example.org 2015092102 7200 7200 1209600 1800",
- TTL: 7200,
- },
- {
- ID: 99,
- Name: "",
- Type: "NS",
- Content: "ns1.example.org",
- TTL: 7200,
- },
- {
- ID: 100,
- Name: "_acme-challenge",
- Type: "TXT",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- },
- }
-
- assert.Equal(t, expected, records)
-}
-
-func TestClient_CreateRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/zones/6/records",
- servermock.ResponseFromFixture("create_record.json").
- WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBodyFromFixture("create_record-request.json")).
- Build(t)
-
- record := Record{
- Name: "_acme-challenge",
- Type: "TXT",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- }
-
- result, err := client.CreateRecord(t.Context(), 6, record)
- require.NoError(t, err)
-
- expected := &Record{
- ID: 101,
- Name: "_acme-challenge",
- Type: "TXT",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_CreateRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/zones/6/records",
- servermock.RawStringResponse(`{"error": "bad request"}`).
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- record := Record{
- Name: "_acme-challenge",
- Type: "TXT",
- Content: "test-value",
- TTL: 120,
- }
-
- result, err := client.CreateRecord(t.Context(), 6, record)
- require.Error(t, err)
-
- assert.Nil(t, result)
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /dns/zones/6/records/101",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent)).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), 6, 101)
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /dns/zones/6/records/999",
- servermock.RawStringResponse(`{"error": "not found"}`).
- WithStatusCode(http.StatusNotFound)).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), 6, 999)
- require.Error(t, err)
-}
diff --git a/providers/dns/internal/tecnocratica/internal/fixtures/create_record-request.json b/providers/dns/internal/tecnocratica/internal/fixtures/create_record-request.json
deleted file mode 100644
index 4cd339c98..000000000
--- a/providers/dns/internal/tecnocratica/internal/fixtures/create_record-request.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "record": {
- "name": "_acme-challenge",
- "type": "TXT",
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 120
- }
-}
diff --git a/providers/dns/internal/tecnocratica/internal/fixtures/create_record.json b/providers/dns/internal/tecnocratica/internal/fixtures/create_record.json
deleted file mode 100644
index 6f30010ac..000000000
--- a/providers/dns/internal/tecnocratica/internal/fixtures/create_record.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "id": 101,
- "name": "_acme-challenge",
- "type": "TXT",
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 120,
- "prio": null,
- "created_at": "2015-09-21T14:40:27.127+02:00",
- "updated_at": "2015-09-21T14:40:27.127+02:00"
-}
diff --git a/providers/dns/internal/tecnocratica/internal/fixtures/get_records.json b/providers/dns/internal/tecnocratica/internal/fixtures/get_records.json
deleted file mode 100644
index 00e09c37f..000000000
--- a/providers/dns/internal/tecnocratica/internal/fixtures/get_records.json
+++ /dev/null
@@ -1,26 +0,0 @@
-[
- {
- "id": 98,
- "name": "",
- "type": "SOA",
- "content": "ns1.example.org dns.example.org 2015092102 7200 7200 1209600 1800",
- "ttl": 7200,
- "prio": null
- },
- {
- "id": 99,
- "name": "",
- "type": "NS",
- "content": "ns1.example.org",
- "ttl": 7200,
- "prio": null
- },
- {
- "id": 100,
- "name": "_acme-challenge",
- "type": "TXT",
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 120,
- "prio": null
- }
-]
diff --git a/providers/dns/internal/tecnocratica/internal/fixtures/get_zones.json b/providers/dns/internal/tecnocratica/internal/fixtures/get_zones.json
deleted file mode 100644
index 01a08dced..000000000
--- a/providers/dns/internal/tecnocratica/internal/fixtures/get_zones.json
+++ /dev/null
@@ -1,16 +0,0 @@
-[
- {
- "id": 6,
- "name": "example.com",
- "created_at": "2015-09-21T12:19:04.000+02:00",
- "updated_at": "2015-09-21T12:19:04.000+02:00",
- "human_name": "example.com"
- },
- {
- "id": 7,
- "name": "example.org",
- "created_at": "2015-09-22T10:00:00.000+02:00",
- "updated_at": "2015-09-22T10:00:00.000+02:00",
- "human_name": "example.org"
- }
-]
diff --git a/providers/dns/internal/tecnocratica/internal/types.go b/providers/dns/internal/tecnocratica/internal/types.go
deleted file mode 100644
index 505bfbced..000000000
--- a/providers/dns/internal/tecnocratica/internal/types.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package internal
-
-// Zone represents a DNS zone.
-type Zone struct {
- ID int `json:"id"`
- Name string `json:"name"`
- HumanName string `json:"human_name"`
-}
-
-// Record represents a DNS record.
-type Record struct {
- ID int `json:"id,omitempty"`
- Name string `json:"name,omitempty"`
- Type string `json:"type,omitempty"`
- Content string `json:"content,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Priority int `json:"prio,omitempty"`
-}
-
-// RecordRequest is the request body for creating/updating a record.
-type RecordRequest struct {
- Record Record `json:"record"`
-}
diff --git a/providers/dns/internal/tecnocratica/provider.go b/providers/dns/internal/tecnocratica/provider.go
deleted file mode 100644
index 17cfb8379..000000000
--- a/providers/dns/internal/tecnocratica/provider.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Package tecnocratica implements a DNS provider for solving the DNS-01 challenge using Tecnocrática.
-package tecnocratica
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/internal/tecnocratica/internal"
-)
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Token string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- zoneIDs map[string]int
- recordIDs map[string]int
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Tecnocrática.
-func NewDNSProviderConfig(config *Config, baseURL string) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("the configuration of the DNS provider is nil")
- }
-
- if config.Token == "" {
- return nil, errors.New("missing credentials")
- }
-
- client, err := internal.NewClient(config.Token)
- if err != nil {
- return nil, fmt.Errorf("create client: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- if baseURL != "" {
- client.BaseURL, err = url.Parse(baseURL)
- if err != nil {
- return nil, err
- }
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- zoneIDs: make(map[string]int),
- recordIDs: make(map[string]int),
- }, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("could not find zone for domain %q: %w", domain, err)
- }
-
- authZone = dns01.UnFqdn(authZone)
-
- zone, err := d.findZone(ctx, authZone)
- if err != nil {
- return fmt.Errorf("%w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("%w", err)
- }
-
- record := internal.Record{
- Name: subDomain,
- Type: "TXT",
- Content: info.Value,
- TTL: d.config.TTL,
- }
-
- newRecord, err := d.client.CreateRecord(ctx, zone.ID, record)
- if err != nil {
- return fmt.Errorf("create record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.zoneIDs[token] = zone.ID
- d.recordIDs[token] = newRecord.ID
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- d.recordIDsMu.Lock()
- zoneID, zoneOK := d.zoneIDs[token]
- recordID, recordOK := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !zoneOK || !recordOK {
- return fmt.Errorf("unknown record ID or zone ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- err := d.client.DeleteRecord(context.Background(), zoneID, recordID)
- if err != nil {
- return fmt.Errorf("delete record: fqdn=%s, zoneID=%d, recordID=%d: %w",
- info.EffectiveFQDN, zoneID, recordID, err)
- }
-
- d.recordIDsMu.Lock()
- delete(d.zoneIDs, token)
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-func (d *DNSProvider) findZone(ctx context.Context, zoneName string) (*internal.Zone, error) {
- zones, err := d.client.GetZones(ctx)
- if err != nil {
- return nil, fmt.Errorf("get zones: %w", err)
- }
-
- for _, zone := range zones {
- if zone.Name == zoneName || zone.HumanName == zoneName {
- return &zone, nil
- }
- }
-
- return nil, fmt.Errorf("zone not found: %s", zoneName)
-}
diff --git a/providers/dns/internal/tecnocratica/provider_test.go b/providers/dns/internal/tecnocratica/provider_test.go
deleted file mode 100644
index 33e5f7c67..000000000
--- a/providers/dns/internal/tecnocratica/provider_test.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package tecnocratica
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- token string
- expected string
- }{
- {
- desc: "success",
- token: "secret",
- },
- {
- desc: "missing token",
- expected: "missing credentials",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := &Config{}
- config.Token = test.token
-
- p, err := NewDNSProviderConfig(config, "")
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := &Config{
- Token: "secret",
- PropagationTimeout: 10 * time.Second,
- PollingInterval: 1 * time.Second,
- TTL: 120,
- HTTPClient: server.Client(),
- }
-
- p, err := NewDNSProviderConfig(config, server.URL)
- if err != nil {
- return nil, err
- }
-
- return p, nil
- },
- servermock.CheckHeader().WithJSONHeaders().
- With("X-TCpanel-Token", "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /dns/zones",
- servermock.ResponseFromInternal("get_zones.json")).
- Route("POST /dns/zones/6/records",
- servermock.ResponseFromInternal("create_record.json").
- WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBodyFromInternal("create_record-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /dns/zones/456/records/123",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent)).
- Build(t)
-
- token := "abc"
-
- provider.recordIDs[token] = 123
- provider.zoneIDs[token] = 456
-
- err := provider.CleanUp("example.com", token, "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/internal/useragent/useragent.go b/providers/dns/internal/useragent/useragent.go
index 090c9109a..f380c05b0 100644
--- a/providers/dns/internal/useragent/useragent.go
+++ b/providers/dns/internal/useragent/useragent.go
@@ -10,12 +10,12 @@ import (
const (
// ourUserAgent is the User-Agent of this underlying library package.
- ourUserAgent = "goacme-lego/4.32.0"
+ ourUserAgent = "goacme-lego/4.25.1"
// ourUserAgentComment is part of the UA comment linked to the version status of this underlying library package.
// values: detach|release
// NOTE: Update this with each tagged release.
- ourUserAgentComment = "detach"
+ ourUserAgentComment = "release"
)
// Get builds and returns the User-Agent string.
diff --git a/providers/dns/internal/westcn/provider.go b/providers/dns/internal/westcn/provider.go
deleted file mode 100644
index a9e6dad58..000000000
--- a/providers/dns/internal/westcn/provider.go
+++ /dev/null
@@ -1,140 +0,0 @@
-package westcn
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/internal/westcn/internal"
-)
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Username string
- Password string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- recordIDs map[string]int
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for West.cn/西部数码.
-func NewDNSProviderConfig(config *Config, baseURL string) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.Username, config.Password)
- if err != nil {
- return nil, fmt.Errorf("%w", err)
- }
-
- if baseURL != "" {
- client.BaseURL, err = url.Parse(baseURL)
- if err != nil {
- return nil, err
- }
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]int),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("%w", err)
- }
-
- record := internal.Record{
- Domain: dns01.UnFqdn(authZone),
- Host: subDomain,
- Type: "TXT",
- Value: info.Value,
- TTL: d.config.TTL,
- }
-
- recordID, err := d.client.AddRecord(context.Background(), record)
- if err != nil {
- return fmt.Errorf("add record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.recordIDs[token] = recordID
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("could not find zone for domain %q: %w", domain, err)
- }
-
- // gets the record's unique ID
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- err = d.client.DeleteRecord(context.Background(), dns01.UnFqdn(authZone), recordID)
- if err != nil {
- return fmt.Errorf("delete record: %w", err)
- }
-
- // deletes record ID from map
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/internal/westcn/provider_test.go b/providers/dns/internal/westcn/provider_test.go
deleted file mode 100644
index 2ae0f09cb..000000000
--- a/providers/dns/internal/westcn/provider_test.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package westcn
-
-import (
- "net/http/httptest"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- username string
- password string
- expected string
- }{
- {
- desc: "success",
- username: "user",
- password: "secret",
- },
- {
- desc: "missing username",
- password: "secret",
- expected: "credentials missing",
- },
- {
- desc: "missing password",
- username: "user",
- expected: "credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := &Config{}
- config.Username = test.username
- config.Password = test.password
-
- p, err := NewDNSProviderConfig(config, "")
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := &Config{
- Username: "user",
- Password: "secret",
- PropagationTimeout: 10 * time.Second,
- PollingInterval: 1 * time.Second,
- TTL: 120,
- HTTPClient: server.Client(),
- }
-
- p, err := NewDNSProviderConfig(config, server.URL)
- if err != nil {
- return nil, err
- }
-
- return p, nil
- },
- servermock.CheckHeader().
- WithContentTypeFromURLEncoded())
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /domain/",
- servermock.ResponseFromInternal("adddnsrecord.json").
- WithHeader("Content-Type", "application/json", "Charset=gb2312"),
- servermock.CheckQueryParameter().Strict().
- With("act", "adddnsrecord"),
- servermock.CheckForm().UsePostForm().Strict().
- With("domain", "example.com").
- With("host", "_acme-challenge").
- With("ttl", "120").
- With("type", "TXT").
- With("value", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY").
- // With("act", "adddnsrecord").
- With("username", "user").
- WithRegexp("time", `\d+`).
- WithRegexp("token", `[a-z0-9]{32}`),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("POST /domain/",
- servermock.ResponseFromInternal("deldnsrecord.json").
- WithHeader("Content-Type", "application/json", "Charset=gb2312"),
- servermock.CheckQueryParameter().Strict().
- With("act", "deldnsrecord"),
- servermock.CheckForm().UsePostForm().Strict().
- With("id", "123").
- With("domain", "example.com").
- With("username", "user").
- WithRegexp("time", `\d+`).
- WithRegexp("token", `[a-z0-9]{32}`),
- ).
- Build(t)
-
- provider.recordIDs["abc"] = 123
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/internetbs/internal/client.go b/providers/dns/internetbs/internal/client.go
index cf9e90dc5..4de57dc9a 100644
--- a/providers/dns/internetbs/internal/client.go
+++ b/providers/dns/internetbs/internal/client.go
@@ -48,7 +48,6 @@ func NewClient(apiKey, password string) *Client {
// AddRecord The command is intended to add a new DNS record to a specific zone (domain).
func (c *Client) AddRecord(ctx context.Context, query RecordQuery) error {
var r APIResponse
-
err := c.doRequest(ctx, "Add", query, &r)
if err != nil {
return err
@@ -64,7 +63,6 @@ func (c *Client) AddRecord(ctx context.Context, query RecordQuery) error {
// RemoveRecord The command is intended to remove a DNS record from a specific zone.
func (c *Client) RemoveRecord(ctx context.Context, query RecordQuery) error {
var r APIResponse
-
err := c.doRequest(ctx, "Remove", query, &r)
if err != nil {
return err
@@ -80,7 +78,6 @@ func (c *Client) RemoveRecord(ctx context.Context, query RecordQuery) error {
// ListRecords The command is intended to retrieve the list of DNS records for a specific domain.
func (c *Client) ListRecords(ctx context.Context, query ListRecordQuery) ([]Record, error) {
var l ListResponse
-
err := c.doRequest(ctx, "List", query, &l)
if err != nil {
return nil, err
diff --git a/providers/dns/internetbs/internetbs.go b/providers/dns/internetbs/internetbs.go
index e8cb868d2..9d6c17676 100644
--- a/providers/dns/internetbs/internetbs.go
+++ b/providers/dns/internetbs/internetbs.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internetbs/internal"
)
@@ -89,8 +88,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/internetbs/internetbs.toml b/providers/dns/internetbs/internetbs.toml
index f22850253..d25418f22 100644
--- a/providers/dns/internetbs/internetbs.toml
+++ b/providers/dns/internetbs/internetbs.toml
@@ -7,7 +7,7 @@ Since = "v4.5.0"
Example = '''
INTERNET_BS_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx \
INTERNET_BS_PASSWORD=yyyyyyyyyyyyyyyyyyyyyyyyyy \
-lego --dns internetbs -d '*.example.com' -d example.com run
+lego --email you@example.com --dns internetbs -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/internetbs/internetbs_test.go b/providers/dns/internetbs/internetbs_test.go
index be436d6e7..ea328d506 100644
--- a/providers/dns/internetbs/internetbs_test.go
+++ b/providers/dns/internetbs/internetbs_test.go
@@ -49,7 +49,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -122,7 +121,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -136,7 +134,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/inwx/inwx.go b/providers/dns/inwx/inwx.go
index 0e79d71e0..9945d904c 100644
--- a/providers/dns/inwx/inwx.go
+++ b/providers/dns/inwx/inwx.go
@@ -177,19 +177,17 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("inwx: %w", err)
}
- var recordID string
-
+ var recordID int
for _, record := range response.Records {
if record.Content != info.Value {
continue
}
recordID = record.ID
-
break
}
- if recordID == "" {
+ if recordID == 0 {
return errors.New("inwx: TXT record not found")
}
diff --git a/providers/dns/inwx/inwx.toml b/providers/dns/inwx/inwx.toml
index da4c6d959..aeab5a242 100644
--- a/providers/dns/inwx/inwx.toml
+++ b/providers/dns/inwx/inwx.toml
@@ -7,13 +7,13 @@ Since = "v2.0.0"
Example = '''
INWX_USERNAME=xxxxxxxxxx \
INWX_PASSWORD=yyyyyyyyyy \
-lego --dns inwx -d '*.example.com' -d example.com run
+lego --email you@example.com --dns inwx -d '*.example.com' -d example.com run
# 2FA
INWX_USERNAME=xxxxxxxxxx \
INWX_PASSWORD=yyyyyyyyyy \
INWX_SHARED_SECRET=zzzzzzzzzz \
-lego --dns inwx -d '*.example.com' -d example.com run
+lego --email you@example.com --dns inwx -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/inwx/inwx_test.go b/providers/dns/inwx/inwx_test.go
index 47b12e228..39ce7d70e 100644
--- a/providers/dns/inwx/inwx_test.go
+++ b/providers/dns/inwx/inwx_test.go
@@ -62,7 +62,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -125,7 +124,6 @@ func TestLivePresentAndCleanup(t *testing.T) {
}
envTest.RestoreEnv()
-
envTest.Apply(map[string]string{
EnvSandbox: "true",
EnvTTL: "3600", // In sandbox mode, the minimum allowed TTL is 3600
diff --git a/providers/dns/internal/ionos/internal/client.go b/providers/dns/ionos/internal/client.go
similarity index 98%
rename from providers/dns/internal/ionos/internal/client.go
rename to providers/dns/ionos/internal/client.go
index 2a556a49b..b51e003f7 100644
--- a/providers/dns/internal/ionos/internal/client.go
+++ b/providers/dns/ionos/internal/client.go
@@ -14,6 +14,7 @@ import (
querystring "github.com/google/go-querystring/query"
)
+// defaultBaseURL represents the API endpoint to call.
const defaultBaseURL = "https://api.hosting.ionos.com/dns"
// APIKeyHeader API key header.
@@ -51,7 +52,6 @@ func (c *Client) ListZones(ctx context.Context) ([]Zone, error) {
}
var zones []Zone
-
err = c.do(req, &zones)
if err != nil {
return nil, fmt.Errorf("failed to call API: %w", err)
@@ -96,7 +96,6 @@ func (c *Client) GetRecords(ctx context.Context, zoneID string, filter *RecordsF
}
var zone CustomerZone
-
err = c.do(req, &zone)
if err != nil {
return nil, fmt.Errorf("failed to call API: %w", err)
@@ -181,7 +180,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errClient := &ClientError{StatusCode: resp.StatusCode}
-
err := json.Unmarshal(raw, &errClient.errors)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/internal/ionos/internal/client_test.go b/providers/dns/ionos/internal/client_test.go
similarity index 100%
rename from providers/dns/internal/ionos/internal/client_test.go
rename to providers/dns/ionos/internal/client_test.go
diff --git a/providers/dns/internal/ionos/internal/fixtures/get_records.json b/providers/dns/ionos/internal/fixtures/get_records.json
similarity index 100%
rename from providers/dns/internal/ionos/internal/fixtures/get_records.json
rename to providers/dns/ionos/internal/fixtures/get_records.json
diff --git a/providers/dns/internal/ionos/internal/fixtures/get_records_error.json b/providers/dns/ionos/internal/fixtures/get_records_error.json
similarity index 100%
rename from providers/dns/internal/ionos/internal/fixtures/get_records_error.json
rename to providers/dns/ionos/internal/fixtures/get_records_error.json
diff --git a/providers/dns/internal/ionos/internal/fixtures/list_zones.json b/providers/dns/ionos/internal/fixtures/list_zones.json
similarity index 100%
rename from providers/dns/internal/ionos/internal/fixtures/list_zones.json
rename to providers/dns/ionos/internal/fixtures/list_zones.json
diff --git a/providers/dns/internal/ionos/internal/fixtures/list_zones_error.json b/providers/dns/ionos/internal/fixtures/list_zones_error.json
similarity index 100%
rename from providers/dns/internal/ionos/internal/fixtures/list_zones_error.json
rename to providers/dns/ionos/internal/fixtures/list_zones_error.json
diff --git a/providers/dns/internal/ionos/internal/fixtures/remove_record_error.json b/providers/dns/ionos/internal/fixtures/remove_record_error.json
similarity index 100%
rename from providers/dns/internal/ionos/internal/fixtures/remove_record_error.json
rename to providers/dns/ionos/internal/fixtures/remove_record_error.json
diff --git a/providers/dns/internal/ionos/internal/fixtures/replace_records_error.json b/providers/dns/ionos/internal/fixtures/replace_records_error.json
similarity index 100%
rename from providers/dns/internal/ionos/internal/fixtures/replace_records_error.json
rename to providers/dns/ionos/internal/fixtures/replace_records_error.json
diff --git a/providers/dns/internal/ionos/internal/types.go b/providers/dns/ionos/internal/types.go
similarity index 91%
rename from providers/dns/internal/ionos/internal/types.go
rename to providers/dns/ionos/internal/types.go
index 35bfe0966..3b7acbec2 100644
--- a/providers/dns/internal/ionos/internal/types.go
+++ b/providers/dns/ionos/internal/types.go
@@ -3,7 +3,6 @@ package internal
import (
"fmt"
"strconv"
- "strings"
)
// ClientError a detailed error.
@@ -14,23 +13,21 @@ type ClientError struct {
}
func (f ClientError) Error() string {
- var msg strings.Builder
-
- msg.WriteString(strconv.Itoa(f.StatusCode) + ": ")
+ msg := strconv.Itoa(f.StatusCode) + ": "
if f.message != "" {
- msg.WriteString(f.message + ": ")
+ msg += f.message + ": "
}
for i, e := range f.errors {
if i != 0 {
- msg.WriteString(", ")
+ msg += ", "
}
- msg.WriteString(e.Error())
+ msg += e.Error()
}
- return msg.String()
+ return msg
}
func (f ClientError) Unwrap() error {
diff --git a/providers/dns/ionos/ionos.go b/providers/dns/ionos/ionos.go
index 892370f5d..394def027 100644
--- a/providers/dns/ionos/ionos.go
+++ b/providers/dns/ionos/ionos.go
@@ -2,15 +2,18 @@
package ionos
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "strconv"
+ "strings"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/ionos"
+ "github.com/go-acme/lego/v4/providers/dns/ionos/internal"
)
// Environment variables names.
@@ -30,12 +33,18 @@ const minTTL = 300
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
-type Config = ionos.Config
+type Config struct {
+ APIKey string
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, ionos.MinTTL),
+ TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 15*time.Minute),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPClient: &http.Client{
@@ -46,7 +55,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *internal.Client
}
// NewDNSProvider returns a DNSProvider instance configured for Ionos.
@@ -69,36 +79,126 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("ionos: the configuration of the DNS provider is nil")
}
- provider, err := ionos.NewDNSProviderConfig(config, "")
+ if config.APIKey == "" {
+ return nil, errors.New("ionos: credentials missing")
+ }
+
+ if config.TTL < minTTL {
+ return nil, fmt.Errorf("ionos: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
+ }
+
+ client, err := internal.NewClient(config.APIKey)
if err != nil {
return nil, fmt.Errorf("ionos: %w", err)
}
- return &DNSProvider{prv: provider}, nil
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{config: config, client: client}, nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+ return d.config.PropagationTimeout, d.config.PollingInterval
}
// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+func (d *DNSProvider) Present(domain, _, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ ctx := context.Background()
+
+ zones, err := d.client.ListZones(ctx)
if err != nil {
- return fmt.Errorf("ionos: %w", err)
+ return fmt.Errorf("ionos: failed to get zones: %w", err)
+ }
+
+ name := dns01.UnFqdn(info.EffectiveFQDN)
+
+ zone := findZone(zones, name)
+ if zone == nil {
+ return errors.New("ionos: no matching zone found for domain")
+ }
+
+ filter := &internal.RecordsFilter{
+ Suffix: name,
+ RecordType: "TXT",
+ }
+
+ records, err := d.client.GetRecords(ctx, zone.ID, filter)
+ if err != nil {
+ return fmt.Errorf("ionos: failed to get records (zone=%s): %w", zone.ID, err)
+ }
+
+ records = append(records, internal.Record{
+ Name: name,
+ Content: info.Value,
+ TTL: d.config.TTL,
+ Type: "TXT",
+ })
+
+ err = d.client.ReplaceRecords(ctx, zone.ID, records)
+ if err != nil {
+ return fmt.Errorf("ionos: failed to create/update records (zone=%s): %w", zone.ID, err)
}
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ ctx := context.Background()
+
+ zones, err := d.client.ListZones(ctx)
if err != nil {
- return fmt.Errorf("ionos: %w", err)
+ return fmt.Errorf("ionos: failed to get zones: %w", err)
}
- return nil
+ name := dns01.UnFqdn(info.EffectiveFQDN)
+
+ zone := findZone(zones, name)
+ if zone == nil {
+ return errors.New("ionos: no matching zone found for domain")
+ }
+
+ filter := &internal.RecordsFilter{
+ Suffix: name,
+ RecordType: "TXT",
+ }
+
+ records, err := d.client.GetRecords(ctx, zone.ID, filter)
+ if err != nil {
+ return fmt.Errorf("ionos: failed to get records (zone=%s): %w", zone.ID, err)
+ }
+
+ for _, record := range records {
+ if record.Name == name && record.Content == strconv.Quote(info.Value) {
+ err = d.client.RemoveRecord(ctx, zone.ID, record.ID)
+ if err != nil {
+ return fmt.Errorf("ionos: failed to remove record (zone=%s, record=%s): %w", zone.ID, record.ID, err)
+ }
+ return nil
+ }
+ }
+
+ return fmt.Errorf("ionos: failed to remove record, record not found (zone=%s, domain=%s, fqdn=%s, value=%s)", zone.ID, domain, info.EffectiveFQDN, info.Value)
+}
+
+func findZone(zones []internal.Zone, domain string) *internal.Zone {
+ var result *internal.Zone
+
+ for _, zone := range zones {
+ if zone.Name != "" && strings.HasSuffix(domain, zone.Name) {
+ if result == nil || len(zone.Name) > len(result.Name) {
+ result = &zone
+ }
+ }
+ }
+
+ return result
}
diff --git a/providers/dns/ionos/ionos.toml b/providers/dns/ionos/ionos.toml
index a2c9518fb..0c905273f 100644
--- a/providers/dns/ionos/ionos.toml
+++ b/providers/dns/ionos/ionos.toml
@@ -6,7 +6,7 @@ Since = "v4.2.0"
Example = '''
IONOS_API_KEY=xxxxxxxx \
-lego --dns ionos -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ionos -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/ionos/ionos_test.go b/providers/dns/ionos/ionos_test.go
index 39dc0c511..5aef6ad14 100644
--- a/providers/dns/ionos/ionos_test.go
+++ b/providers/dns/ionos/ionos_test.go
@@ -9,7 +9,9 @@ import (
const envDomain = envNamespace + "DOMAIN"
-var envTest = tester.NewEnvTest(EnvAPIKey).WithDomain(envDomain)
+var envTest = tester.NewEnvTest(
+ EnvAPIKey).
+ WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) {
testCases := []struct {
@@ -35,7 +37,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -45,7 +46,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -89,7 +91,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -103,7 +106,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -117,7 +119,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/ionoscloud/internal/client.go b/providers/dns/ionoscloud/internal/client.go
deleted file mode 100644
index 5b7d3a0fc..000000000
--- a/providers/dns/ionoscloud/internal/client.go
+++ /dev/null
@@ -1,172 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://dns.de-fra.ionos.com"
-
-const authorizationHeader = "Authorization"
-
-// Client the Ionos Cloud API client.
-type Client struct {
- apiKey string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(apiKey string) (*Client, error) {
- if apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- apiKey: apiKey,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-// RetrieveZones returns a list of the DNS zones.
-// https://api.ionos.com/docs/dns/v1/#tag/Zones/operation/zonesGet
-func (c *Client) RetrieveZones(ctx context.Context, zoneName string) ([]Zone, error) {
- endpoint := c.BaseURL.JoinPath("zones")
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- query := req.URL.Query()
- query.Add("filter.zoneName", zoneName)
- req.URL.RawQuery = query.Encode()
-
- result := ZonesResponse{}
-
- if err := c.do(req, &result); err != nil {
- return nil, err
- }
-
- return result.Items, nil
-}
-
-// CreateRecord creates a new record for the DNS zone.
-// https://api.ionos.com/docs/dns/v1/#tag/Records/operation/zonesRecordsPost
-func (c *Client) CreateRecord(ctx context.Context, zoneID string, record RecordProperties) (*RecordResponse, error) {
- endpoint := c.BaseURL.JoinPath("zones", zoneID, "records")
-
- payload := map[string]RecordProperties{
- "properties": record,
- }
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, payload)
- if err != nil {
- return nil, err
- }
-
- result := &RecordResponse{}
-
- if err := c.do(req, result); err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// DeleteRecord deletes a specified record from the DNS zone.
-// https://api.ionos.com/docs/dns/v1/#tag/Records/operation/zonesRecordsDelete
-func (c *Client) DeleteRecord(ctx context.Context, zoneID, recordID string) error {
- endpoint := c.BaseURL.JoinPath("zones", zoneID, "records", recordID)
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Set(authorizationHeader, "Bearer "+c.apiKey)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
diff --git a/providers/dns/ionoscloud/internal/client_test.go b/providers/dns/ionoscloud/internal/client_test.go
deleted file mode 100644
index dc478cc64..000000000
--- a/providers/dns/ionoscloud/internal/client_test.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- WithAuthorization("Bearer secret"),
- )
-}
-
-func TestClient_RetrieveZones(t *testing.T) {
- client := mockBuilder().
- Route("GET /zones",
- servermock.ResponseFromFixture("zones.json"),
- servermock.CheckQueryParameter().Strict().
- With("filter.zoneName", "example.com")).
- Build(t)
-
- zones, err := client.RetrieveZones(t.Context(), "example.com")
- require.NoError(t, err)
-
- expected := []Zone{{
- ID: "e74d0d15-f567-4b7b-9069-26ee1f93bae3",
- Type: "zone",
- Metadata: ZoneMetadata{
- CreatedDate: time.Date(2022, time.August, 21, 15, 52, 53, 0, time.UTC),
- CreatedBy: "ionos:iam:cloud:31960002:users/87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- CreatedByUserID: "87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- LastModifiedDate: time.Date(2022, time.August, 21, 15, 52, 53, 0, time.UTC),
- LastModifiedBy: "ionos:iam:cloud:31960002:users/87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- LastModifiedByUserID: "63cef532-26fe-4a64-a4e0-de7c8a506c90",
- ResourceURN: "ionos::::",
- State: "PROVISIONING",
- Nameservers: []string{"ns-ic.ui-dns.com", "ns-ic.ui-dns.de", "ns-ic.ui-dns.org", "ns-ic.ui-dns.biz"},
- },
- Properties: ZoneProperties{
- ZoneName: "example.com",
- Description: "The hosted zone is used for example.com",
- Enabled: true,
- },
- }}
-
- assert.Equal(t, expected, zones)
-}
-
-func TestClient_RetrieveZones_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /zones",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- _, err := client.RetrieveZones(t.Context(), "example.com")
- require.EqualError(t, err, "401: paas-auth-1: Unauthorized, wrong or no api key provided to process this request")
-}
-
-func TestClient_CreateRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /zones/abc/records",
- servermock.ResponseFromFixture("create_record.json"),
- servermock.CheckRequestJSONBodyFromFixture("create_record-request.json")).
- Build(t)
-
- record := RecordProperties{
- Name: "_acme-challenge",
- Type: "TXT",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 120,
- }
-
- result, err := client.CreateRecord(t.Context(), "abc", record)
- require.NoError(t, err)
-
- expected := &RecordResponse{
- ID: "90d81ac0-3a30-44d4-95a5-12959effa6ee",
- Type: "record",
- Metadata: RecordMetadata{
- CreatedDate: time.Date(2022, time.August, 21, 15, 52, 53, 0, time.UTC),
- CreatedBy: "ionos:iam:cloud:31960002:users/87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- CreatedByUserID: "87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- LastModifiedDate: time.Date(2022, time.August, 21, 15, 52, 53, 0, time.UTC),
- LastModifiedBy: "ionos:iam:cloud:31960002:users/87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- LastModifiedByUserID: "63cef532-26fe-4a64-a4e0-de7c8a506c90",
- ResourceURN: "ionos::::",
- State: "PROVISIONING",
- Fqdn: "app.example.com",
- ZoneID: "a363f30c-4c0c-4552-9a07-298d87f219bf",
- },
- Properties: RecordProperties{
- Name: "app",
- Type: "A",
- Content: "1.2.3.4",
- TTL: 3600,
- Priority: 3600,
- Enabled: true,
- },
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /zones/abc/records/def",
- servermock.Noop().
- WithStatusCode(http.StatusAccepted)).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), "abc", "def")
- require.NoError(t, err)
-}
diff --git a/providers/dns/ionoscloud/internal/fixtures/create_record-request.json b/providers/dns/ionoscloud/internal/fixtures/create_record-request.json
deleted file mode 100644
index d4f52bba8..000000000
--- a/providers/dns/ionoscloud/internal/fixtures/create_record-request.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "properties": {
- "name": "_acme-challenge",
- "type": "TXT",
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 120
- }
-}
diff --git a/providers/dns/ionoscloud/internal/fixtures/create_record.json b/providers/dns/ionoscloud/internal/fixtures/create_record.json
deleted file mode 100644
index d3094c3b2..000000000
--- a/providers/dns/ionoscloud/internal/fixtures/create_record.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "id": "90d81ac0-3a30-44d4-95a5-12959effa6ee",
- "type": "record",
- "href": "",
- "metadata": {
- "createdDate": "2022-08-21T15:52:53Z",
- "createdBy": "ionos:iam:cloud:31960002:users/87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- "createdByUserId": "87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- "lastModifiedDate": "2022-08-21T15:52:53Z",
- "lastModifiedBy": "ionos:iam:cloud:31960002:users/87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- "lastModifiedByUserId": "63cef532-26fe-4a64-a4e0-de7c8a506c90",
- "resourceURN": "ionos::::",
- "state": "PROVISIONING",
- "fqdn": "app.example.com",
- "zoneId": "a363f30c-4c0c-4552-9a07-298d87f219bf"
- },
- "properties": {
- "name": "app",
- "type": "A",
- "content": "1.2.3.4",
- "ttl": 3600,
- "priority": 3600,
- "enabled": true
- }
-}
diff --git a/providers/dns/ionoscloud/internal/fixtures/error.json b/providers/dns/ionoscloud/internal/fixtures/error.json
deleted file mode 100644
index bed0e5efb..000000000
--- a/providers/dns/ionoscloud/internal/fixtures/error.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "httpStatus": 401,
- "messages": [
- {
- "errorCode": "paas-auth-1",
- "message": "Unauthorized, wrong or no api key provided to process this request"
- }
- ]
-}
diff --git a/providers/dns/ionoscloud/internal/fixtures/zones.json b/providers/dns/ionoscloud/internal/fixtures/zones.json
deleted file mode 100644
index c9c2c62f9..000000000
--- a/providers/dns/ionoscloud/internal/fixtures/zones.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "id": "e74d0d15-f567-4b7b-9069-26ee1f93bae3",
- "type": "collection",
- "href": "",
- "offset": 0,
- "limit": 1000,
- "_links": {
- "prev": "http://PREVIOUS-PAGE-URI",
- "self": "http://THIS-PAGE-URI",
- "next": "http://NEXT-PAGE-URI"
- },
- "items": [
- {
- "id": "e74d0d15-f567-4b7b-9069-26ee1f93bae3",
- "type": "zone",
- "href": "",
- "metadata": {
- "createdDate": "2022-08-21T15:52:53Z",
- "createdBy": "ionos:iam:cloud:31960002:users/87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- "createdByUserId": "87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- "lastModifiedDate": "2022-08-21T15:52:53Z",
- "lastModifiedBy": "ionos:iam:cloud:31960002:users/87f9a82e-b28d-49ed-9d04-fba2c0459cd3",
- "lastModifiedByUserId": "63cef532-26fe-4a64-a4e0-de7c8a506c90",
- "resourceURN": "ionos::::",
- "state": "PROVISIONING",
- "nameservers": [
- "ns-ic.ui-dns.com",
- "ns-ic.ui-dns.de",
- "ns-ic.ui-dns.org",
- "ns-ic.ui-dns.biz"
- ]
- },
- "properties": {
- "zoneName": "example.com",
- "description": "The hosted zone is used for example.com",
- "enabled": true
- }
- }
- ]
-}
diff --git a/providers/dns/ionoscloud/internal/types.go b/providers/dns/ionoscloud/internal/types.go
deleted file mode 100644
index 49348f4d1..000000000
--- a/providers/dns/ionoscloud/internal/types.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strconv"
- "strings"
- "time"
-)
-
-type APIError struct {
- HTTPStatus int `json:"httpStatus"`
- Messages []ErrorMessage `json:"messages"`
-}
-
-func (a *APIError) Error() string {
- var msg strings.Builder
-
- msg.WriteString(strconv.Itoa(a.HTTPStatus))
-
- for _, m := range a.Messages {
- msg.WriteString(": ")
- msg.WriteString(m.String())
- }
-
- return msg.String()
-}
-
-type ErrorMessage struct {
- ErrorCode string `json:"errorCode"`
- Message string `json:"message"`
-}
-
-func (e ErrorMessage) String() string {
- return fmt.Sprintf("%s: %s", e.ErrorCode, e.Message)
-}
-
-type ZonesResponse struct {
- ID string `json:"id"`
- Type string `json:"type"`
- Offset int `json:"offset"`
- Limit int `json:"limit"`
- Items []Zone `json:"items"`
-}
-
-type Zone struct {
- ID string `json:"id"`
- Type string `json:"type"`
- Metadata ZoneMetadata `json:"metadata"`
- Properties ZoneProperties `json:"properties"`
-}
-
-type ZoneMetadata struct {
- CreatedDate time.Time `json:"createdDate"`
- CreatedBy string `json:"createdBy"`
- CreatedByUserID string `json:"createdByUserId"`
- LastModifiedDate time.Time `json:"lastModifiedDate"`
- LastModifiedBy string `json:"lastModifiedBy"`
- LastModifiedByUserID string `json:"lastModifiedByUserId"`
- ResourceURN string `json:"resourceURN"`
- State string `json:"state"`
- Nameservers []string `json:"nameservers"`
-}
-
-type ZoneProperties struct {
- ZoneName string `json:"zoneName"`
- Description string `json:"description"`
- Enabled bool `json:"enabled"`
-}
-
-type RecordResponse struct {
- ID string `json:"id"`
- Type string `json:"type"`
- Metadata RecordMetadata `json:"metadata"`
- Properties RecordProperties `json:"properties"`
-}
-
-type RecordMetadata struct {
- CreatedDate time.Time `json:"createdDate"`
- CreatedBy string `json:"createdBy"`
- CreatedByUserID string `json:"createdByUserId"`
- LastModifiedDate time.Time `json:"lastModifiedDate"`
- LastModifiedBy string `json:"lastModifiedBy"`
- LastModifiedByUserID string `json:"lastModifiedByUserId"`
- ResourceURN string `json:"resourceURN"`
- State string `json:"state"`
- Fqdn string `json:"fqdn"`
- ZoneID string `json:"zoneId"`
-}
-
-type RecordProperties struct {
- Name string `json:"name"`
- Type string `json:"type,omitempty"`
- Content string `json:"content,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Priority int `json:"priority,omitempty"`
- Enabled bool `json:"enabled,omitempty"`
-}
diff --git a/providers/dns/ionoscloud/ionoscloud.go b/providers/dns/ionoscloud/ionoscloud.go
deleted file mode 100644
index 0c33fba9f..000000000
--- a/providers/dns/ionoscloud/ionoscloud.go
+++ /dev/null
@@ -1,184 +0,0 @@
-// Package ionoscloud implements a DNS provider for solving the DNS-01 challenge using Ionos Cloud.
-package ionoscloud
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/ionoscloud/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "IONOSCLOUD_"
-
- EnvAPIToken = envNamespace + "API_TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIToken string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- zoneIDs map[string]string
- recordIDs map[string]string
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Ionos Cloud.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIToken)
- if err != nil {
- return nil, fmt.Errorf("ionoscloud: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIToken = values[EnvAPIToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Ionos Cloud.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("ionoscloud: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIToken)
- if err != nil {
- return nil, fmt.Errorf("ionoscloud: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- zoneIDs: make(map[string]string),
- recordIDs: make(map[string]string),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("ionoscloud: could not find zone for domain %q: %w", domain, err)
- }
-
- zones, err := d.client.RetrieveZones(ctx, dns01.UnFqdn(authZone))
- if err != nil {
- return fmt.Errorf("ionoscloud: retrieve zones: %w", err)
- }
-
- if len(zones) != 1 {
- return fmt.Errorf("ionoscloud: zone ID not found for domain %q", domain)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("ionoscloud: %w", err)
- }
-
- zoneID := zones[0].ID
-
- request := internal.RecordProperties{
- Name: subDomain,
- Type: "TXT",
- Content: info.Value,
- TTL: d.config.TTL,
- }
-
- record, err := d.client.CreateRecord(ctx, zoneID, request)
- if err != nil {
- return fmt.Errorf("ionoscloud: create record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.zoneIDs[token] = zoneID
- d.recordIDs[token] = record.ID
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- d.recordIDsMu.Lock()
- zoneID, ok := d.zoneIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("ionoscloud: unknown zone ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("ionoscloud: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- err := d.client.DeleteRecord(context.Background(), zoneID, recordID)
- if err != nil {
- return fmt.Errorf("ionoscloud: delete record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- delete(d.zoneIDs, token)
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/ionoscloud/ionoscloud.toml b/providers/dns/ionoscloud/ionoscloud.toml
deleted file mode 100644
index 6e1d080e4..000000000
--- a/providers/dns/ionoscloud/ionoscloud.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Ionos Cloud"
-Description = ''''''
-URL = "https://cloud.ionos.de/network/cloud-dns"
-Code = "ionoscloud"
-Since = "v4.30.0"
-
-Example = '''
-IONOSCLOUD_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns ionoscloud -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- IONOSCLOUD_API_TOKEN = "API token"
- [Configuration.Additional]
- IONOSCLOUD_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- IONOSCLOUD_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
- IONOSCLOUD_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- IONOSCLOUD_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://api.ionos.com/docs/dns/v1/"
diff --git a/providers/dns/ionoscloud/ionoscloud_test.go b/providers/dns/ionoscloud/ionoscloud_test.go
deleted file mode 100644
index 8282e08fc..000000000
--- a/providers/dns/ionoscloud/ionoscloud_test.go
+++ /dev/null
@@ -1,173 +0,0 @@
-package ionoscloud
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIToken).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIToken: "secret",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "ionoscloud: some credentials information are missing: IONOSCLOUD_API_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiToken string
- expected string
- }{
- {
- desc: "success",
- apiToken: "secret",
- },
- {
- desc: "missing credentials",
- expected: "ionoscloud: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIToken = test.apiToken
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIToken = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- WithAuthorization("Bearer secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /zones",
- servermock.ResponseFromInternal("zones.json"),
- servermock.CheckQueryParameter().Strict().
- With("filter.zoneName", "example.com")).
- Route("POST /zones/e74d0d15-f567-4b7b-9069-26ee1f93bae3/records",
- servermock.ResponseFromInternal("create_record.json"),
- servermock.CheckRequestJSONBodyFromInternal("create_record-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /zones/e74d0d15-f567-4b7b-9069-26ee1f93bae3/records/90d81ac0-3a30-44d4-95a5-12959effa6ee",
- servermock.Noop().
- WithStatusCode(http.StatusAccepted)).
- Build(t)
-
- token := "abc"
-
- provider.zoneIDs[token] = "e74d0d15-f567-4b7b-9069-26ee1f93bae3"
- provider.recordIDs[token] = "90d81ac0-3a30-44d4-95a5-12959effa6ee"
-
- err := provider.CleanUp("example.com", token, "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/ipv64/internal/client.go b/providers/dns/ipv64/internal/client.go
index 0dfd94374..1cb9c532f 100644
--- a/providers/dns/ipv64/internal/client.go
+++ b/providers/dns/ipv64/internal/client.go
@@ -131,7 +131,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errAPI := &APIError{}
-
err := json.Unmarshal(raw, errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/ipv64/internal/types.go b/providers/dns/ipv64/internal/types.go
index 6ef31a3cc..e9e357ecc 100644
--- a/providers/dns/ipv64/internal/types.go
+++ b/providers/dns/ipv64/internal/types.go
@@ -11,7 +11,6 @@ type APIResponse struct {
type APIError struct {
APIResponse
-
AddRecordMessage string `json:"add_record"`
DelRecordMessage string `json:"del_record"`
AddDomainMessage string `json:"add_domain"`
@@ -42,7 +41,6 @@ func (a APIError) Error() string {
type Domains struct {
APIResponse
-
APICall string `json:"add_domain"`
Subdomains map[string]Subdomain `json:"subdomains"`
}
diff --git a/providers/dns/ipv64/ipv64.go b/providers/dns/ipv64/ipv64.go
index 078fe5ca1..6e8d1c5bb 100644
--- a/providers/dns/ipv64/ipv64.go
+++ b/providers/dns/ipv64/ipv64.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/ipv64/internal"
"github.com/miekg/dns"
)
@@ -86,8 +85,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/ipv64/ipv64.toml b/providers/dns/ipv64/ipv64.toml
index aa1720c9e..fba210bdb 100644
--- a/providers/dns/ipv64/ipv64.toml
+++ b/providers/dns/ipv64/ipv64.toml
@@ -6,7 +6,7 @@ Since = "v4.13.0"
Example = '''
IPV64_API_KEY=xxxxxx \
-lego --dns ipv64 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ipv64 -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/ipv64/ipv64_test.go b/providers/dns/ipv64/ipv64_test.go
index 6dc7d1cfc..b3fe142e9 100644
--- a/providers/dns/ipv64/ipv64_test.go
+++ b/providers/dns/ipv64/ipv64_test.go
@@ -114,7 +114,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -172,7 +171,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -186,7 +184,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/ispconfig/internal/client.go b/providers/dns/ispconfig/internal/client.go
deleted file mode 100644
index 9280fdec1..000000000
--- a/providers/dns/ispconfig/internal/client.go
+++ /dev/null
@@ -1,318 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
-)
-
-type Client struct {
- serverURL string
- HTTPClient *http.Client
-}
-
-func NewClient(serverURL string) (*Client, error) {
- _, err := url.Parse(serverURL)
- if err != nil {
- return nil, fmt.Errorf("server URL: %w", err)
- }
-
- return &Client{
- serverURL: serverURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) Login(ctx context.Context, username, password string) (string, error) {
- payload := LoginRequest{
- Username: username,
- Password: password,
- ClientLogin: false,
- }
-
- endpoint, err := url.Parse(c.serverURL)
- if err != nil {
- return "", err
- }
-
- endpoint.RawQuery = "login"
-
- req, err := newJSONRequest(ctx, endpoint, payload)
- if err != nil {
- return "", err
- }
-
- var response APIResponse
-
- err = c.do(req, &response)
- if err != nil {
- return "", err
- }
-
- return extractResponse[string](response)
-}
-
-func (c *Client) GetClientID(ctx context.Context, sessionID, sysUserID string) (int, error) {
- payload := ClientIDRequest{
- SessionID: sessionID,
- SysUserID: sysUserID,
- }
-
- endpoint, err := url.Parse(c.serverURL)
- if err != nil {
- return 0, err
- }
-
- endpoint.RawQuery = "client_get_id"
-
- req, err := newJSONRequest(ctx, endpoint, payload)
- if err != nil {
- return 0, err
- }
-
- var response APIResponse
-
- err = c.do(req, &response)
- if err != nil {
- return 0, err
- }
-
- return extractResponse[int](response)
-}
-
-// GetZoneID returns the zone ID for the given name.
-func (c *Client) GetZoneID(ctx context.Context, sessionID, name string) (int, error) {
- payload := map[string]any{
- "session_id": sessionID,
- "origin": name,
- }
-
- endpoint, err := url.Parse(c.serverURL)
- if err != nil {
- return 0, err
- }
-
- endpoint.RawQuery = "dns_zone_get_id"
-
- req, err := newJSONRequest(ctx, endpoint, payload)
- if err != nil {
- return 0, err
- }
-
- var response APIResponse
-
- err = c.do(req, &response)
- if err != nil {
- return 0, err
- }
-
- return extractResponse[int](response)
-}
-
-// GetZone returns the zone information for the zone ID.
-func (c *Client) GetZone(ctx context.Context, sessionID, zoneID string) (*Zone, error) {
- payload := map[string]any{
- "session_id": sessionID,
- "primary_id": zoneID,
- }
-
- endpoint, err := url.Parse(c.serverURL)
- if err != nil {
- return nil, err
- }
-
- endpoint.RawQuery = "dns_zone_get"
-
- req, err := newJSONRequest(ctx, endpoint, payload)
- if err != nil {
- return nil, err
- }
-
- var response APIResponse
-
- err = c.do(req, &response)
- if err != nil {
- return nil, err
- }
-
- return extractResponse[*Zone](response)
-}
-
-// GetTXT returns the TXT record for the given name.
-// `name` must be a fully qualified domain name, e.g. "example.com.".
-func (c *Client) GetTXT(ctx context.Context, sessionID, name string) (*Record, error) {
- payload := GetTXTRequest{
- SessionID: sessionID,
- PrimaryID: struct {
- Name string `json:"name"`
- Type string `json:"type"`
- }{
- Name: name,
- Type: "txt",
- },
- }
-
- endpoint, err := url.Parse(c.serverURL)
- if err != nil {
- return nil, err
- }
-
- endpoint.RawQuery = "dns_txt_get"
-
- req, err := newJSONRequest(ctx, endpoint, payload)
- if err != nil {
- return nil, err
- }
-
- var response APIResponse
-
- err = c.do(req, &response)
- if err != nil {
- return nil, err
- }
-
- return extractResponse[*Record](response)
-}
-
-// AddTXT adds a TXT record.
-// It returns the ID of the newly created record.
-func (c *Client) AddTXT(ctx context.Context, sessionID, clientID string, params RecordParams) (string, error) {
- payload := AddTXTRequest{
- SessionID: sessionID,
- ClientID: clientID,
- Params: ¶ms,
- UpdateSerial: true,
- }
-
- endpoint, err := url.Parse(c.serverURL)
- if err != nil {
- return "", err
- }
-
- endpoint.RawQuery = "dns_txt_add"
-
- req, err := newJSONRequest(ctx, endpoint, payload)
- if err != nil {
- return "", err
- }
-
- var response APIResponse
-
- err = c.do(req, &response)
- if err != nil {
- return "", err
- }
-
- return extractResponse[string](response)
-}
-
-// DeleteTXT deletes a TXT record.
-// It returns the number of deleted records.
-func (c *Client) DeleteTXT(ctx context.Context, sessionID, recordID string) (int, error) {
- payload := DeleteTXTRequest{
- SessionID: sessionID,
- PrimaryID: recordID,
- UpdateSerial: true,
- }
-
- endpoint, err := url.Parse(c.serverURL)
- if err != nil {
- return 0, err
- }
-
- endpoint.RawQuery = "dns_txt_delete"
-
- req, err := newJSONRequest(ctx, endpoint, payload)
- if err != nil {
- return 0, err
- }
-
- var response APIResponse
-
- err = c.do(req, &response)
- if err != nil {
- return 0, err
- }
-
- return extractResponse[int](response)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- return req, nil
-}
-
-func extractResponse[T any](response APIResponse) (T, error) {
- if response.Code != "ok" {
- var zero T
-
- return zero, &APIError{APIResponse: response}
- }
-
- var result T
-
- err := json.Unmarshal(response.Response, &result)
- if err != nil {
- var zero T
- return zero, fmt.Errorf("unable to unmarshal response: %s, %w", string(response.Response), err)
- }
-
- return result, nil
-}
diff --git a/providers/dns/ispconfig/internal/client_test.go b/providers/dns/ispconfig/internal/client_test.go
deleted file mode 100644
index a4db3d5f7..000000000
--- a/providers/dns/ispconfig/internal/client_test.go
+++ /dev/null
@@ -1,175 +0,0 @@
-package internal
-
-import (
- "net/http/httptest"
- "testing"
- "time"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(server.URL)
- if err != nil {
- return nil, err
- }
-
- client.HTTPClient = server.Client()
-
- return client, nil
- })
-}
-
-func TestClient_Login(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("login.json"),
- servermock.CheckRequestJSONBodyFromFixture("login-request.json"),
- servermock.CheckQueryParameter().Strict().
- With("login", ""),
- ).
- Build(t)
-
- sessionID, err := client.Login(t.Context(), "user", "secret")
- require.NoError(t, err)
-
- assert.Equal(t, "abc", sessionID)
-}
-
-func TestClient_Login_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("error.json"),
- ).
- Build(t)
-
- _, err := client.Login(t.Context(), "user", "secret")
- require.EqualError(t, err, `code: remote_fault, message: The login failed. Username or password wrong., response: false`)
-}
-
-func TestClient_GetClientID(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("client_get_id.json"),
- servermock.CheckRequestJSONBodyFromFixture("client_get_id-request.json"),
- servermock.CheckQueryParameter().Strict().
- With("client_get_id", ""),
- ).
- Build(t)
-
- id, err := client.GetClientID(t.Context(), "sessionA", "sysA")
- require.NoError(t, err)
-
- assert.Equal(t, 123, id)
-}
-
-func TestClient_GetZoneID(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("dns_zone_get_id.json"),
- servermock.CheckRequestJSONBodyFromFixture("dns_zone_get_id-request.json"),
- servermock.CheckQueryParameter().Strict().
- With("dns_zone_get_id", ""),
- ).
- Build(t)
-
- zoneID, err := client.GetZoneID(t.Context(), "sessionA", "example.com")
- require.NoError(t, err)
-
- assert.Equal(t, 123, zoneID)
-}
-
-func TestClient_GetZone(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("dns_zone_get.json"),
- servermock.CheckRequestJSONBodyFromFixture("dns_zone_get-request.json"),
- servermock.CheckQueryParameter().Strict().
- With("dns_zone_get", ""),
- ).
- Build(t)
-
- zone, err := client.GetZone(t.Context(), "sessionA", "example.com.")
- require.NoError(t, err)
-
- expected := &Zone{
- ID: "456",
- ServerID: "123",
- SysUserID: "789",
- SysGroupID: "2",
- Origin: "example.com.",
- Serial: "2025102902",
- Active: "Y",
- }
-
- assert.Equal(t, expected, zone)
-}
-
-func TestClient_GetTXT(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("dns_txt_get.json"),
- servermock.CheckRequestJSONBodyFromFixture("dns_txt_get-request.json"),
- servermock.CheckQueryParameter().Strict().
- With("dns_txt_get", ""),
- ).
- Build(t)
-
- record, err := client.GetTXT(t.Context(), "sessionA", "example.com.")
- require.NoError(t, err)
-
- expected := &Record{ID: 123}
-
- assert.Equal(t, expected, record)
-}
-
-func TestClient_AddTXT(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("dns_txt_add.json"),
- servermock.CheckRequestJSONBodyFromFixture("dns_txt_add-request.json"),
- servermock.CheckQueryParameter().Strict().
- With("dns_txt_add", ""),
- ).
- Build(t)
-
- now := time.Date(2025, 12, 25, 1, 1, 1, 0, time.UTC)
-
- params := RecordParams{
- ServerID: "serverA",
- Zone: "example.com.",
- Name: "foo.example.com.",
- Type: "txt",
- Data: "txtTXTtxt",
- Aux: "0",
- TTL: "3600",
- Active: "y",
- Stamp: now.Format("2006-01-02 15:04:05"),
- UpdateSerial: true,
- }
-
- recordID, err := client.AddTXT(t.Context(), "sessionA", "clientA", params)
- require.NoError(t, err)
-
- assert.Equal(t, "123", recordID)
-}
-
-func TestClient_DeleteTXT(t *testing.T) {
- client := mockBuilder().
- Route("POST /",
- servermock.ResponseFromFixture("dns_txt_delete.json"),
- servermock.CheckRequestJSONBodyFromFixture("dns_txt_delete-request.json"),
- servermock.CheckQueryParameter().Strict().
- With("dns_txt_delete", ""),
- ).
- Build(t)
-
- count, err := client.DeleteTXT(t.Context(), "sessionA", "123")
- require.NoError(t, err)
-
- assert.Equal(t, 1, count)
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/client_get_id-request.json b/providers/dns/ispconfig/internal/fixtures/client_get_id-request.json
deleted file mode 100644
index ba573f824..000000000
--- a/providers/dns/ispconfig/internal/fixtures/client_get_id-request.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "session_id": "sessionA",
- "sys_userid": "sysA"
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/client_get_id.json b/providers/dns/ispconfig/internal/fixtures/client_get_id.json
deleted file mode 100644
index 7b9f667a0..000000000
--- a/providers/dns/ispconfig/internal/fixtures/client_get_id.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "code": "ok",
- "message": "foo",
- "response": 123
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_txt_add-request.json b/providers/dns/ispconfig/internal/fixtures/dns_txt_add-request.json
deleted file mode 100644
index bf5242cd1..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_txt_add-request.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "session_id": "sessionA",
- "client_id": "clientA",
- "params": {
- "server_id": "serverA",
- "zone": "example.com.",
- "name": "foo.example.com.",
- "type": "txt",
- "data": "txtTXTtxt",
- "aux": "0",
- "ttl": "3600",
- "active": "y",
- "stamp": "2025-12-25 01:01:01",
- "update_serial": true
- },
- "update_serial": true
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_txt_add.json b/providers/dns/ispconfig/internal/fixtures/dns_txt_add.json
deleted file mode 100644
index 7980619fe..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_txt_add.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "code": "ok",
- "message": "foo",
- "response": "123"
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_txt_delete-request.json b/providers/dns/ispconfig/internal/fixtures/dns_txt_delete-request.json
deleted file mode 100644
index 240976654..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_txt_delete-request.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "session_id": "sessionA",
- "primary_id": "123",
- "update_serial": true
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_txt_delete.json b/providers/dns/ispconfig/internal/fixtures/dns_txt_delete.json
deleted file mode 100644
index 960b650bd..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_txt_delete.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "code": "ok",
- "message": "foo",
- "response": 1
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_txt_get-request.json b/providers/dns/ispconfig/internal/fixtures/dns_txt_get-request.json
deleted file mode 100644
index 8bda44067..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_txt_get-request.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "session_id": "sessionA",
- "primary_id": {
- "name": "example.com.",
- "type": "txt"
- }
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_txt_get.json b/providers/dns/ispconfig/internal/fixtures/dns_txt_get.json
deleted file mode 100644
index f707d50c3..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_txt_get.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "code": "ok",
- "message": "foo",
- "response": {
- "id": 123
- }
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_zone_get-request.json b/providers/dns/ispconfig/internal/fixtures/dns_zone_get-request.json
deleted file mode 100644
index 3d44d468f..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_zone_get-request.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "primary_id": "example.com.",
- "session_id": "sessionA"
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_zone_get.json b/providers/dns/ispconfig/internal/fixtures/dns_zone_get.json
deleted file mode 100644
index 37975d0e6..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_zone_get.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "code": "ok",
- "message": "foo",
- "response": {
- "id": "456",
- "sys_userid": "789",
- "sys_groupid": "2",
- "sys_perm_user": "riud",
- "sys_perm_group": "riud",
- "sys_perm_other": "",
- "server_id": "123",
- "origin": "example.com.",
- "ns": "ns1.example.org.",
- "mbox": "support.example.net.",
- "serial": "2025102902",
- "refresh": "7200",
- "retry": "540",
- "expire": "604800",
- "minimum": "3600",
- "ttl": "3600",
- "active": "Y",
- "xfer": "",
- "also_notify": "",
- "update_acl": "",
- "dnssec_initialized": "N",
- "dnssec_wanted": "N",
- "dnssec_algo": "ECDSAP256SHA256",
- "dnssec_last_signed": "0",
- "dnssec_info": "",
- "rendered_zone": ""
- }
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_zone_get_id-request.json b/providers/dns/ispconfig/internal/fixtures/dns_zone_get_id-request.json
deleted file mode 100644
index e3084242e..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_zone_get_id-request.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "origin": "example.com",
- "session_id": "sessionA"
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/dns_zone_get_id.json b/providers/dns/ispconfig/internal/fixtures/dns_zone_get_id.json
deleted file mode 100644
index 7b9f667a0..000000000
--- a/providers/dns/ispconfig/internal/fixtures/dns_zone_get_id.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "code": "ok",
- "message": "foo",
- "response": 123
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/error.json b/providers/dns/ispconfig/internal/fixtures/error.json
deleted file mode 100644
index a9c76546c..000000000
--- a/providers/dns/ispconfig/internal/fixtures/error.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "code": "remote_fault",
- "message": "The login failed. Username or password wrong.",
- "response": false
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/login-request.json b/providers/dns/ispconfig/internal/fixtures/login-request.json
deleted file mode 100644
index c3293a2e8..000000000
--- a/providers/dns/ispconfig/internal/fixtures/login-request.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "username": "user",
- "password": "secret",
- "client_login": false
-}
diff --git a/providers/dns/ispconfig/internal/fixtures/login.json b/providers/dns/ispconfig/internal/fixtures/login.json
deleted file mode 100644
index e380a86ec..000000000
--- a/providers/dns/ispconfig/internal/fixtures/login.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "code": "ok",
- "message": "foo",
- "response": "abc"
-}
diff --git a/providers/dns/ispconfig/internal/readme.md b/providers/dns/ispconfig/internal/readme.md
deleted file mode 100644
index 2284c338f..000000000
--- a/providers/dns/ispconfig/internal/readme.md
+++ /dev/null
@@ -1,249 +0,0 @@
-## Error Response
-
-```json
-{
- "code": "",
- "message": "",
- "response": false
-}
-```
-
-## Login Endpoint
-
-* URL: `?login`
-* HTTP Method: `POST`
-
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/API-docs/login.html
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/examples/login.php
-
-### Request Body (JSON)
-
-```json
-{
- "username": "",
- "password": "",
- "client_login": false
-}
-```
-
-### Response Body (JSON)
-
-```json
-{
- "code": "ok",
- "message": "foo",
- "response": "abc"
-}
-```
-
-- `response`: is the `sessionID`
-
-## Get Client ID Endpoint
-
-* URL: `?client_get_id`
-* HTTP Method: `POST`
-
-- function `client_get_id`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/client.inc.php#L97
-- TABLE `sys_user`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/install/sql/ispconfig3.sql?ref_type=heads#L1852
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/API-docs/client_get_id.html
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/examples/client_get_id.php
-
-### Request Body (JSON)
-
-```json
-{
- "session_id": "",
- "sys_userid": ""
-}
-```
-
-### Response Body (JSON)
-
-```json
-{
- "code": "ok",
- "message": "foo",
- "response": 123
-}
-```
-
-## DNS Zone Get ID Endpoint
-
-* URL: `?dns_zone_get_id`
-* HTTP Method: `POST`
-
-- function `dns_zone_get_id`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/dns.inc.php#L142
-- TABLE `dns_soa`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/install/sql/ispconfig3.sql?ref_type=heads#L615
-
-### Request Body (JSON)
-
-```json
-{
- "session_id": "",
- "origin": ""
-}
-```
-
-### Response Body (JSON)
-
-```json
-{
- "code": "ok",
- "message": "foo",
- "response": 123
-}
-```
-
-## DNS Zone Get Endpoint
-
-* URL: `?dns_zone_get`
-* HTTP Method: `POST`
-
-- function `dns_zone_get`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/dns.inc.php#L87
-- function `getDataRecord`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remoting_lib.inc.php#L248
-- TABLE `dns_soa`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/install/sql/ispconfig3.sql?ref_type=heads#L615
-- Depending on the request, the response may be an array or an object (`primary_id` can be a string, an array or an object).
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/API-docs/dns_zone_get.html
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/examples/dns_zone_get.php
-
-### Request Body (JSON)
-
-```json
-{
- "session_id": "",
- "primary_id": ""
-}
-```
-
-### Response Body (JSON)
-
-```json
-{
- "code": "ok",
- "message": "foo",
- "response": {
- "id": 456,
- "server_id": 123,
- "sys_userid": 789
- }
-}
-```
-
-## DNS TXT Get Endpoint
-
-* URL: `?dns_txt_get`
-* HTTP Method: `POST`
-
-- function `dns_txt_get`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/dns.inc.php#L640
-- function `dns_rr_get`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/dns.inc.php#L195
-- form: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/web/dns/form/dns_txt.tform.php
-- TABLE `dns_rr`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/install/sql/ispconfig3.sql?ref_type=heads#L490
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/API-docs/dns_txt_get.html
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/examples/dns_txt_get.php
-
-### Request Body (JSON)
-
-```json
-{
- "session_id": "",
- "primary_id": {
- "name": ".",
- "type": "TXT"
- }
-}
-```
-
-### Response Body (JSON)
-
-```json
-{
- "code": "ok",
- "message": "foo",
- "response": {
- "id": 123
- }
-}
-```
-
-## DNS TXT Add Endpoint
-
-* URL: `?dns_txt_add`
-* HTTP Method: `POST`
-
-- function `dns_txt_add`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/dns.inc.php#L645
-- function `dns_rr_add` https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/dns.inc.php#L212
-- form: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/web/dns/form/dns_txt.tform.php
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/API-docs/dns_txt_add.html
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/examples/dns_txt_add.php
-
-### Request Body (JSON)
-
-```json
-{
- "session_id": "",
- "client_id": "",
- "params": {
- "server_id": "",
- "zone": "",
- "name": ".",
- "type": "txt",
- "data": "",
- "aux": "0",
- "ttl": "3600",
- "active": "y",
- "stamp": "",
- "update_serial": true
- },
- "update_serial": true
-}
-```
-
-- `stamp`: (ex: `2025-12-17 23:35:58`)
-- `serial`: (ex: `1766010947`)
-
-### Response Body (JSON)
-
-```json
-{
- "code": "ok",
- "message": "foo",
- "response": "123"
-}
-```
-
-## DNS TXT Delete Endpoint
-
-* URL: `?dns_txt_delete`
-* HTTP Method: `POST`
-
-- function `dns_txt_delete`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/dns.inc.php#L655
-- function `dns_rr_delete`: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/lib/classes/remote.d/dns.inc.php#L247
-- form: https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/interface/web/dns/form/dns_txt.tform.php
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/API-docs/dns_txt_delete.html
-- https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/examples/dns_txt_delete.php
-
-### Request Body (JSON)
-
-```json
-{
- "session_id": "",
- "primary_id": "",
- "update_serial": true
-}
-```
-
-### Response Body (JSON)
-
-```json
-{
- "code": "ok",
- "message": "foo",
- "response": 1
-}
-```
-
----
-
-https://www.ispconfig.org/
-https://git.ispconfig.org/ispconfig/ispconfig3
-https://forum.howtoforge.com/#ispconfig-3.23
diff --git a/providers/dns/ispconfig/internal/types.go b/providers/dns/ispconfig/internal/types.go
deleted file mode 100644
index 7db0846cc..000000000
--- a/providers/dns/ispconfig/internal/types.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "strings"
-)
-
-type APIError struct {
- APIResponse
-}
-
-func (e *APIError) Error() string {
- var msg strings.Builder
-
- msg.WriteString("code: " + e.Code)
-
- if e.Message != "" {
- msg.WriteString(", message: " + e.Message)
- }
-
- if len(e.Response) > 0 {
- msg.WriteString(", response: " + string(e.Response))
- }
-
- return msg.String()
-}
-
-type APIResponse struct {
- Code string `json:"code"`
- Message string `json:"message"`
- Response json.RawMessage `json:"response"`
-}
-
-type LoginRequest struct {
- Username string `json:"username"`
- Password string `json:"password"`
- ClientLogin bool `json:"client_login"`
-}
-
-type ClientIDRequest struct {
- SessionID string `json:"session_id"`
- SysUserID string `json:"sys_userid"`
-}
-
-type Zone struct {
- ID string `json:"id"`
- ServerID string `json:"server_id"`
- SysUserID string `json:"sys_userid"`
- SysGroupID string `json:"sys_groupid"`
- Origin string `json:"origin"`
- Serial string `json:"serial"`
- Active string `json:"active"`
-}
-
-type GetTXTRequest struct {
- SessionID string `json:"session_id"`
- PrimaryID struct {
- Name string `json:"name"`
- Type string `json:"type"`
- } `json:"primary_id"`
-}
-
-type Record struct {
- ID int `json:"id"`
-}
-
-type AddTXTRequest struct {
- SessionID string `json:"session_id"`
- ClientID string `json:"client_id"`
- Params *RecordParams `json:"params,omitempty"`
- UpdateSerial bool `json:"update_serial"`
-}
-
-type RecordParams struct {
- ServerID string `json:"server_id"`
- Zone string `json:"zone"`
- Name string `json:"name"`
- // 'a','aaaa','alias','cname','hinfo','mx','naptr','ns','ds','ptr','rp','srv','txt'
- Type string `json:"type"`
- Data string `json:"data"`
- // "0"
- Aux string `json:"aux"`
- TTL string `json:"ttl"`
- // 'n','y'
- Active string `json:"active"`
- // `2025-12-17 23:35:58`
- Stamp string `json:"stamp"`
- UpdateSerial bool `json:"update_serial"`
-}
-
-type DeleteTXTRequest struct {
- SessionID string `json:"session_id"`
- PrimaryID string `json:"primary_id"`
- UpdateSerial bool `json:"update_serial"`
-}
diff --git a/providers/dns/ispconfig/ispconfig.go b/providers/dns/ispconfig/ispconfig.go
deleted file mode 100644
index 9396430b7..000000000
--- a/providers/dns/ispconfig/ispconfig.go
+++ /dev/null
@@ -1,220 +0,0 @@
-// Package ispconfig implements a DNS provider for solving the DNS-01 challenge using ISPConfig.
-package ispconfig
-
-import (
- "context"
- "crypto/tls"
- "errors"
- "fmt"
- "net/http"
- "strconv"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/ispconfig/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "ISPCONFIG_"
-
- EnvServerURL = envNamespace + "SERVER_URL"
- EnvUsername = envNamespace + "USERNAME"
- EnvPassword = envNamespace + "PASSWORD"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
- EnvInsecureSkipVerify = envNamespace + "INSECURE_SKIP_VERIFY"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- ServerURL string
- Username string
- Password string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
- InsecureSkipVerify bool
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- recordIDs map[string]string
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for ISPConfig.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvServerURL, EnvUsername, EnvPassword)
- if err != nil {
- return nil, fmt.Errorf("ispconfig: %w", err)
- }
-
- config := NewDefaultConfig()
- config.ServerURL = values[EnvServerURL]
- config.Username = values[EnvUsername]
- config.Password = values[EnvPassword]
- config.InsecureSkipVerify = env.GetOrDefaultBool(EnvInsecureSkipVerify, false)
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for ISPConfig.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("ispconfig: the configuration of the DNS provider is nil")
- }
-
- if config.ServerURL == "" {
- return nil, errors.New("ispconfig: missing server URL")
- }
-
- if config.Username == "" || config.Password == "" {
- return nil, errors.New("ispconfig: credentials missing")
- }
-
- client, err := internal.NewClient(config.ServerURL)
- if err != nil {
- return nil, fmt.Errorf("ispconfig: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- if config.InsecureSkipVerify {
- client.HTTPClient.Transport = &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- }
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]string),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- sessionID, err := d.client.Login(ctx, d.config.Username, d.config.Password)
- if err != nil {
- return fmt.Errorf("ispconfig: login: %w", err)
- }
-
- zoneID, err := d.findZone(ctx, sessionID, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("ispconfig: get zone id: %w", err)
- }
-
- zone, err := d.client.GetZone(ctx, sessionID, strconv.Itoa(zoneID))
- if err != nil {
- return fmt.Errorf("ispconfig: get zone: %w", err)
- }
-
- clientID, err := d.client.GetClientID(ctx, sessionID, zone.SysUserID)
- if err != nil {
- return fmt.Errorf("ispconfig: get client id: %w", err)
- }
-
- params := internal.RecordParams{
- ServerID: "serverA",
- Zone: zone.ID,
- Name: info.EffectiveFQDN,
- Type: "txt",
- Data: info.Value,
- Aux: "0",
- TTL: strconv.Itoa(d.config.TTL),
- Active: "y",
- Stamp: time.Now().UTC().Format("2006-01-02 15:04:05"),
- }
-
- recordID, err := d.client.AddTXT(ctx, sessionID, strconv.Itoa(clientID), params)
- if err != nil {
- return fmt.Errorf("ispconfig: add txt record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.recordIDs[token] = recordID
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- // gets the record's unique ID
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("ispconfig: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- sessionID, err := d.client.Login(ctx, d.config.Username, d.config.Password)
- if err != nil {
- return fmt.Errorf("ispconfig: login: %w", err)
- }
-
- _, err = d.client.DeleteTXT(ctx, sessionID, recordID)
- if err != nil {
- return fmt.Errorf("ispconfig: delete txt record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findZone(ctx context.Context, sessionID, fqdn string) (int, error) {
- for domain := range dns01.UnFqdnDomainsSeq(fqdn) {
- zoneID, err := d.client.GetZoneID(ctx, sessionID, domain)
- if err == nil {
- return zoneID, nil
- }
- }
-
- return 0, fmt.Errorf("zone not found for %q", fqdn)
-}
diff --git a/providers/dns/ispconfig/ispconfig.toml b/providers/dns/ispconfig/ispconfig.toml
deleted file mode 100644
index 4defd5509..000000000
--- a/providers/dns/ispconfig/ispconfig.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-Name = "ISPConfig 3"
-Description = ''''''
-URL = "https://www.ispconfig.org/"
-Code = "ispconfig"
-Since = "v4.31.0"
-
-Example = '''
-ISPCONFIG_SERVER_URL="https://example.com:8080/remote/json.php" \
-ISPCONFIG_USERNAME="xxx" \
-ISPCONFIG_PASSWORD="yyy" \
-lego --dns ispconfig -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- ISPCONFIG_SERVER_URL = "Server URL"
- ISPCONFIG_USERNAME = "Username"
- ISPCONFIG_PASSWORD = "Password"
- [Configuration.Additional]
- ISPCONFIG_INSECURE_SKIP_VERIFY = "Whether to verify the API certificate"
- ISPCONFIG_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- ISPCONFIG_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- ISPCONFIG_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- ISPCONFIG_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://git.ispconfig.org/ispconfig/ispconfig3/-/blob/develop/remoting_client/API-docs/index.html"
diff --git a/providers/dns/ispconfig/ispconfig_test.go b/providers/dns/ispconfig/ispconfig_test.go
deleted file mode 100644
index b03463aee..000000000
--- a/providers/dns/ispconfig/ispconfig_test.go
+++ /dev/null
@@ -1,173 +0,0 @@
-package ispconfig
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvServerURL,
- EnvUsername,
- EnvPassword,
-).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvServerURL: "https://example.com:80/",
- EnvUsername: "user",
- EnvPassword: "secret",
- },
- },
- {
- desc: "missing server URL",
- envVars: map[string]string{
- EnvServerURL: "",
- EnvUsername: "user",
- EnvPassword: "secret",
- },
- expected: "ispconfig: some credentials information are missing: ISPCONFIG_SERVER_URL",
- },
- {
- desc: "missing username",
- envVars: map[string]string{
- EnvServerURL: "https://example.com:80/",
- EnvUsername: "",
- EnvPassword: "secret",
- },
- expected: "ispconfig: some credentials information are missing: ISPCONFIG_USERNAME",
- },
- {
- desc: "missing password",
- envVars: map[string]string{
- EnvServerURL: "https://example.com:80/",
- EnvUsername: "user",
- EnvPassword: "",
- },
- expected: "ispconfig: some credentials information are missing: ISPCONFIG_PASSWORD",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "ispconfig: some credentials information are missing: ISPCONFIG_SERVER_URL,ISPCONFIG_USERNAME,ISPCONFIG_PASSWORD",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- serverURL string
- username string
- password string
- expected string
- }{
- {
- desc: "success",
- serverURL: "https://example.com:80/",
- username: "user",
- password: "secret",
- },
- {
- desc: "missing server URL",
- username: "user",
- password: "secret",
- expected: "ispconfig: missing server URL",
- },
- {
- desc: "missing username",
- serverURL: "https://example.com:80/",
- password: "secret",
- expected: "ispconfig: credentials missing",
- },
- {
- desc: "missing password",
- serverURL: "https://example.com:80/",
- username: "user",
- expected: "ispconfig: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "ispconfig: missing server URL",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.ServerURL = test.serverURL
- config.Username = test.username
- config.Password = test.password
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/ispconfigddns/internal/client.go b/providers/dns/ispconfigddns/internal/client.go
deleted file mode 100644
index 700b58f89..000000000
--- a/providers/dns/ispconfigddns/internal/client.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package internal
-
-import (
- "context"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
- querystring "github.com/google/go-querystring/query"
-)
-
-const (
- addAction = "add"
- deleteAction = "delete"
-)
-
-type Client struct {
- token string
- serverURL string
-
- HTTPClient *http.Client
-}
-
-func NewClient(serverURL, token string) (*Client, error) {
- _, err := url.Parse(serverURL)
- if err != nil {
- return nil, fmt.Errorf("server URL: %w", err)
- }
-
- return &Client{
- serverURL: serverURL,
- token: token,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) AddTXTRecord(ctx context.Context, zone, fqdn, content string) error {
- return c.updateRecord(ctx, UpdateRecord{Action: addAction, Zone: zone, Type: "TXT", Record: fqdn, Data: content})
-}
-
-func (c *Client) DeleteTXTRecord(ctx context.Context, zone, fqdn, recordContent string) error {
- return c.updateRecord(ctx, UpdateRecord{Action: deleteAction, Zone: zone, Type: "TXT", Record: fqdn, Data: recordContent})
-}
-
-func (c *Client) updateRecord(ctx context.Context, action UpdateRecord) error {
- req, err := c.newRequest(ctx, action)
- if err != nil {
- return err
- }
-
- return c.do(req)
-}
-
-func (c *Client) do(req *http.Request) error {
- useragent.SetHeader(req.Header)
-
- req.SetBasicAuth("anonymous", c.token)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- // The endpoint uses the `DefaultDdnsResponseWriter`,
- // and this writer uses HTTP status code to determine if the request was successful or not.
- // - https://github.com/mhofer117/ispconfig-ddns-module/blob/8b011a5bb138881d9f13360a5c4fec10c0084613/lib/updater/DdnsUpdater.php#L53-L57
- // - https://github.com/mhofer117/ispconfig-ddns-module/blob/master/lib/updater/response/DefaultDdnsResponseWriter.php
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- return nil
-}
-
-func (c *Client) newRequest(ctx context.Context, action UpdateRecord) (*http.Request, error) {
- endpoint, err := url.Parse(c.serverURL)
- if err != nil {
- return nil, err
- }
-
- endpoint = endpoint.JoinPath("ddns", "update.php")
-
- values, err := querystring.Values(action)
- if err != nil {
- return nil, err
- }
-
- endpoint.RawQuery = values.Encode()
-
- method := http.MethodPost
- if action.Action == deleteAction {
- method = http.MethodDelete
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), nil)
- if err != nil {
- return nil, err
- }
-
- req.Header.Set("Accept", "application/json")
-
- return req, nil
-}
diff --git a/providers/dns/ispconfigddns/internal/client_test.go b/providers/dns/ispconfigddns/internal/client_test.go
deleted file mode 100644
index 774e5ee46..000000000
--- a/providers/dns/ispconfigddns/internal/client_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-func setupClient(server *httptest.Server) (*Client, error) {
- client, err := NewClient(server.URL, "secret")
- if err != nil {
- return nil, err
- }
-
- client.HTTPClient = server.Client()
-
- return client, nil
-}
-
-func TestClient_AddTXTRecord(t *testing.T) {
- client := servermock.NewBuilder[*Client](setupClient).
- Route("POST /ddns/update.php",
- servermock.Noop(),
- servermock.CheckHeader().
- WithBasicAuth("anonymous", "secret"),
- servermock.CheckQueryParameter().Strict().
- With("action", "add").
- With("zone", "example.com").
- With("type", "TXT").
- With("record", "_acme-challenge.example.com.").
- With("data", "token"),
- ).
- Build(t)
-
- err := client.AddTXTRecord(t.Context(), "example.com", "_acme-challenge.example.com.", "token")
- require.NoError(t, err)
-}
-
-func TestClient_AddTXTRecord_error(t *testing.T) {
- client := servermock.NewBuilder[*Client](setupClient).
- Route("POST /ddns/update.php",
- servermock.RawStringResponse("Missing or invalid token.").
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- err := client.AddTXTRecord(t.Context(), "example.com", "_acme-challenge.example.com.", "token")
- require.EqualError(t, err, "unexpected status code: [status code: 401] body: Missing or invalid token.")
-}
-
-func TestClient_DeleteTXTRecord(t *testing.T) {
- client := servermock.NewBuilder[*Client](setupClient).
- Route("DELETE /ddns/update.php",
- servermock.Noop(),
- servermock.CheckHeader().
- WithBasicAuth("anonymous", "secret"),
- servermock.CheckQueryParameter().Strict().
- With("action", "delete").
- With("zone", "example.com").
- With("type", "TXT").
- With("record", "_acme-challenge.example.com.").
- With("data", "token"),
- ).
- Build(t)
-
- err := client.DeleteTXTRecord(t.Context(), "example.com", "_acme-challenge.example.com.", "token")
- require.NoError(t, err)
-}
-
-func TestClient_DeleteTXTRecord_error(t *testing.T) {
- client := servermock.NewBuilder[*Client](setupClient).
- Route("DELETE /ddns/update.php",
- servermock.RawStringResponse("Missing or invalid token.").
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- err := client.DeleteTXTRecord(t.Context(), "example.com", "_acme-challenge.example.com.", "token")
- require.EqualError(t, err, "unexpected status code: [status code: 401] body: Missing or invalid token.")
-}
diff --git a/providers/dns/ispconfigddns/internal/types.go b/providers/dns/ispconfigddns/internal/types.go
deleted file mode 100644
index 278738108..000000000
--- a/providers/dns/ispconfigddns/internal/types.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package internal
-
-type UpdateRecord struct {
- Action string `url:"action,omitempty"`
- Zone string `url:"zone,omitempty"`
- Type string `url:"type,omitempty"`
- Record string `url:"record,omitempty"`
- Data string `url:"data,omitempty"`
-}
diff --git a/providers/dns/ispconfigddns/ispconfigddns.go b/providers/dns/ispconfigddns/ispconfigddns.go
deleted file mode 100644
index eab5d413f..000000000
--- a/providers/dns/ispconfigddns/ispconfigddns.go
+++ /dev/null
@@ -1,145 +0,0 @@
-// Package ispconfigddns implements a DNS provider for solving the DNS-01 challenge using ISPConfig 3 Dynamic DNS (DDNS) Module.
-package ispconfigddns
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/ispconfigddns/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "ISPCONFIG_DDNS_"
-
- EnvServerURL = envNamespace + "SERVER_URL"
- EnvToken = envNamespace + "TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- ServerURL string
- Token string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, 3600),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for ISPConfig 3 Dynamic DNS (DDNS) Module.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvServerURL, EnvToken)
- if err != nil {
- return nil, fmt.Errorf("ispconfig (DDNS module): %w", err)
- }
-
- config := NewDefaultConfig()
- config.ServerURL = values[EnvServerURL]
- config.Token = values[EnvToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for ISPConfig 3 Dynamic DNS (DDNS) Module.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("ispconfig (DDNS module): the configuration of the DNS provider is nil")
- }
-
- if config.ServerURL == "" {
- return nil, errors.New("ispconfig (DDNS module): missing server URL")
- }
-
- if config.Token == "" {
- return nil, errors.New("ispconfig (DDNS module): missing token")
- }
-
- client, err := internal.NewClient(config.ServerURL, config.Token)
- if err != nil {
- return nil, fmt.Errorf("ispconfig (DDNS module): %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to control checking compliance to spec.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-// Present creates a TXT record to fulfill the dns-01 challenge.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("ispconfig (DDNS module): could not find zone for domain %q: %w", domain, err)
- }
-
- err = d.client.AddTXTRecord(context.Background(), dns01.UnFqdn(zone), info.EffectiveFQDN, info.Value)
- if err != nil {
- return fmt.Errorf("ispconfig (DDNS module): add record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("ispconfig (DDNS module): could not find zone for domain %q: %w", domain, err)
- }
-
- err = d.client.DeleteTXTRecord(context.Background(), dns01.UnFqdn(zone), info.EffectiveFQDN, info.Value)
- if err != nil {
- return fmt.Errorf("ispconfig (DDNS module): delete record: %w", err)
- }
-
- return nil
-}
diff --git a/providers/dns/ispconfigddns/ispconfigddns.toml b/providers/dns/ispconfigddns/ispconfigddns.toml
deleted file mode 100644
index 158ee9fbd..000000000
--- a/providers/dns/ispconfigddns/ispconfigddns.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-Name = "ISPConfig 3 - Dynamic DNS (DDNS) Module"
-Description = ''''''
-URL = "https://www.ispconfig.org/"
-Code = "ispconfigddns"
-Since = "v4.31.0"
-
-Example = '''
-ISPCONFIG_DDNS_SERVER_URL="https://panel.example.com:8080" \
-ISPCONFIG_DDNS_TOKEN=xxxxxx \
-lego --dns ispconfigddns -d '*.example.com' -d example.com run
-'''
-
-Additional = '''
-ISPConfig DNS provider supports leveraging the [ISPConfig 3 Dynamic DNS (DDNS) Module](https://github.com/mhofer117/ispconfig-ddns-module).
-
-Requires the DDNS module described at https://www.ispconfig.org/ispconfig/download/
-
-See https://www.howtoforge.com/community/threads/ispconfig-3-danymic-dns-ddns-module.87967/ for additional details.
-'''
-
-[Configuration]
- [Configuration.Credentials]
- ISPCONFIG_DDNS_SERVER_URL = "API server URL (ex: https://panel.example.com:8080)"
- ISPCONFIG_DDNS_TOKEN = "DDNS API token"
- [Configuration.Additional]
- ISPCONFIG_DDNS_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- ISPCONFIG_DDNS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- ISPCONFIG_DDNS_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 3600)"
- ISPCONFIG_DDNS_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://github.com/mhofer117/ispconfig-ddns-module/tree/master/lib/updater"
diff --git a/providers/dns/ispconfigddns/ispconfigddns_test.go b/providers/dns/ispconfigddns/ispconfigddns_test.go
deleted file mode 100644
index 58e7a8f54..000000000
--- a/providers/dns/ispconfigddns/ispconfigddns_test.go
+++ /dev/null
@@ -1,193 +0,0 @@
-package ispconfigddns
-
-import (
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvServerURL, EnvToken).
- WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvServerURL: "https://example.com",
- EnvToken: "secret",
- },
- },
- {
- desc: "missing server URL",
- envVars: map[string]string{
- EnvServerURL: "",
- EnvToken: "secret",
- },
- expected: "ispconfig (DDNS module): some credentials information are missing: ISPCONFIG_DDNS_SERVER_URL",
- },
- {
- desc: "missing token",
- envVars: map[string]string{
- EnvServerURL: "https://example.com",
- EnvToken: "",
- },
- expected: "ispconfig (DDNS module): some credentials information are missing: ISPCONFIG_DDNS_TOKEN",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "ispconfig (DDNS module): some credentials information are missing: ISPCONFIG_DDNS_SERVER_URL,ISPCONFIG_DDNS_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- serverURL string
- token string
- expected string
- }{
- {
- desc: "success",
- serverURL: "https://example.com",
- token: "secret",
- },
- {
- desc: "missing server URL",
- serverURL: "",
- token: "secret",
- expected: "ispconfig (DDNS module): missing server URL",
- },
- {
- desc: "missing token",
- serverURL: "https://example.com",
- token: "",
- expected: "ispconfig (DDNS module): missing token",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.ServerURL = test.serverURL
- config.Token = test.token
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.HTTPClient = server.Client()
- config.Token = "secret"
- config.ServerURL = server.URL
-
- return NewDNSProviderConfig(config)
- },
- servermock.CheckHeader().
- WithBasicAuth("anonymous", "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /ddns/update.php",
- servermock.DumpRequest(),
- servermock.CheckQueryParameter().Strict().
- With("action", "add").
- With("zone", "example.com").
- With("type", "TXT").
- With("record", "_acme-challenge.example.com.").
- With("data", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /ddns/update.php",
- servermock.DumpRequest(),
- servermock.CheckQueryParameter().Strict().
- With("action", "delete").
- With("zone", "example.com").
- With("type", "TXT").
- With("record", "_acme-challenge.example.com.").
- With("data", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/iwantmyname/internal/client.go b/providers/dns/iwantmyname/internal/client.go
new file mode 100644
index 000000000..c3418c854
--- /dev/null
+++ b/providers/dns/iwantmyname/internal/client.go
@@ -0,0 +1,66 @@
+package internal
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "net/url"
+ "time"
+
+ "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
+ querystring "github.com/google/go-querystring/query"
+)
+
+const defaultBaseURL = "https://iwantmyname.com/basicauth/ddns"
+
+// Client iwantmyname client.
+type Client struct {
+ username string
+ password string
+
+ baseURL *url.URL
+ HTTPClient *http.Client
+}
+
+// NewClient creates a new Client.
+func NewClient(username, password string) *Client {
+ baseURL, _ := url.Parse(defaultBaseURL)
+
+ return &Client{
+ username: username,
+ password: password,
+ baseURL: baseURL,
+ HTTPClient: &http.Client{Timeout: 10 * time.Second},
+ }
+}
+
+// SendRequest send a request (create/add/delete) to the API.
+func (c *Client) SendRequest(ctx context.Context, record Record) error {
+ values, err := querystring.Values(record)
+ if err != nil {
+ return err
+ }
+
+ endpoint := c.baseURL
+ endpoint.RawQuery = values.Encode()
+
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), http.NoBody)
+ if err != nil {
+ return fmt.Errorf("unable to create request: %w", err)
+ }
+
+ req.SetBasicAuth(c.username, c.password)
+
+ resp, err := c.HTTPClient.Do(req)
+ if err != nil {
+ return errutils.NewHTTPDoError(req, err)
+ }
+
+ defer func() { _ = resp.Body.Close() }()
+
+ if resp.StatusCode/100 != 2 {
+ return errutils.NewUnexpectedResponseStatusCodeError(req, resp)
+ }
+
+ return nil
+}
diff --git a/providers/dns/iwantmyname/internal/client_test.go b/providers/dns/iwantmyname/internal/client_test.go
new file mode 100644
index 000000000..c25eb56ef
--- /dev/null
+++ b/providers/dns/iwantmyname/internal/client_test.go
@@ -0,0 +1,46 @@
+package internal
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "testing"
+
+ "github.com/go-acme/lego/v4/platform/tester/servermock"
+ "github.com/stretchr/testify/require"
+)
+
+func setupClient(server *httptest.Server) (*Client, error) {
+ client := NewClient("user", "secret")
+ client.HTTPClient = server.Client()
+ client.baseURL, _ = url.Parse(server.URL)
+
+ return client, nil
+}
+
+func TestClient_Do(t *testing.T) {
+ client := servermock.NewBuilder[*Client](setupClient,
+ servermock.CheckHeader().
+ WithBasicAuth("user", "secret"),
+ ).
+ Route("POST /", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+ fmt.Println(req)
+ }),
+ servermock.CheckQueryParameter().Strict().
+ With("hostname", "example.com").
+ With("ttl", "120").
+ With("type", "TXT").
+ With("value", "data")).
+ Build(t)
+
+ record := Record{
+ Hostname: "example.com",
+ Type: "TXT",
+ Value: "data",
+ TTL: 120,
+ }
+
+ err := client.SendRequest(t.Context(), record)
+ require.NoError(t, err)
+}
diff --git a/providers/dns/iwantmyname/internal/types.go b/providers/dns/iwantmyname/internal/types.go
new file mode 100644
index 000000000..b259235f5
--- /dev/null
+++ b/providers/dns/iwantmyname/internal/types.go
@@ -0,0 +1,9 @@
+package internal
+
+// Record represents a record.
+type Record struct {
+ Hostname string `url:"hostname,omitempty"`
+ Type string `url:"type,omitempty"`
+ Value string `url:"value,omitempty"`
+ TTL int `url:"ttl,omitempty"`
+}
diff --git a/providers/dns/iwantmyname/iwantmyname.go b/providers/dns/iwantmyname/iwantmyname.go
index f53287e69..2b53377ed 100644
--- a/providers/dns/iwantmyname/iwantmyname.go
+++ b/providers/dns/iwantmyname/iwantmyname.go
@@ -2,13 +2,16 @@
package iwantmyname
import (
+ "context"
"errors"
"fmt"
"net/http"
"time"
"github.com/go-acme/lego/v4/challenge"
+ "github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
+ "github.com/go-acme/lego/v4/providers/dns/iwantmyname/internal"
)
// Environment variables names.
@@ -38,12 +41,20 @@ type Config struct {
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
- return &Config{}
+ return &Config{
+ TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
+ PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
+ PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
+ HTTPClient: &http.Client{
+ Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
+ },
+ }
}
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
config *Config
+ client *internal.Client
}
// NewDNSProvider returns a DNSProvider instance configured for iwantmyname.
@@ -63,7 +74,24 @@ func NewDNSProvider() (*DNSProvider, error) {
// NewDNSProviderConfig return a DNSProvider instance configured for iwantmyname.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- return nil, errors.New("iwantmyname: the iwantmyname API has shut down https://github.com/go-acme/lego/issues/2563")
+ if config == nil {
+ return nil, errors.New("iwantmyname: the configuration of the DNS provider is nil")
+ }
+
+ if config.Username == "" || config.Password == "" {
+ return nil, errors.New("iwantmyname: credentials missing")
+ }
+
+ client := internal.NewClient(config.Username, config.Password)
+
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{
+ config: config,
+ client: client,
+ }, nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
@@ -74,10 +102,38 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, _, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ record := internal.Record{
+ Hostname: dns01.UnFqdn(info.EffectiveFQDN),
+ Type: "TXT",
+ Value: info.Value,
+ TTL: d.config.TTL,
+ }
+
+ err := d.client.SendRequest(context.Background(), record)
+ if err != nil {
+ return fmt.Errorf("iwantmyname: %w", err)
+ }
+
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ record := internal.Record{
+ Hostname: dns01.UnFqdn(info.EffectiveFQDN),
+ Type: "TXT",
+ Value: "delete",
+ TTL: d.config.TTL,
+ }
+
+ err := d.client.SendRequest(context.Background(), record)
+ if err != nil {
+ return fmt.Errorf("iwantmyname: %w", err)
+ }
+
return nil
}
diff --git a/providers/dns/iwantmyname/iwantmyname.toml b/providers/dns/iwantmyname/iwantmyname.toml
index a82c2b749..00a45b714 100644
--- a/providers/dns/iwantmyname/iwantmyname.toml
+++ b/providers/dns/iwantmyname/iwantmyname.toml
@@ -1,9 +1,5 @@
-Name = "iwantmyname (Deprecated)"
-Description = '''
-The iwantmyname API has shut down.
-
-https://github.com/go-acme/lego/issues/2563
-'''
+Name = "iwantmyname"
+Description = ''''''
URL = "https://iwantmyname.com"
Code = "iwantmyname"
Since = "v4.7.0"
@@ -11,7 +7,7 @@ Since = "v4.7.0"
Example = '''
IWANTMYNAME_USERNAME=xxxxxxxx \
IWANTMYNAME_PASSWORD=xxxxxxxx \
-lego --dns iwantmyname -d '*.example.com' -d example.com run
+lego --email you@example.com --dns iwantmyname -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/com35/com35_test.go b/providers/dns/iwantmyname/iwantmyname_test.go
similarity index 77%
rename from providers/dns/com35/com35_test.go
rename to providers/dns/iwantmyname/iwantmyname_test.go
index 78fd8f829..7ae4545b2 100644
--- a/providers/dns/com35/com35_test.go
+++ b/providers/dns/iwantmyname/iwantmyname_test.go
@@ -1,4 +1,4 @@
-package com35
+package iwantmyname
import (
"testing"
@@ -9,7 +9,8 @@ import (
const envDomain = envNamespace + "DOMAIN"
-var envTest = tester.NewEnvTest(EnvUsername, EnvPassword).WithDomain(envDomain)
+var envTest = tester.NewEnvTest(EnvUsername, EnvPassword).
+ WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) {
testCases := []struct {
@@ -24,33 +25,30 @@ func TestNewDNSProvider(t *testing.T) {
EnvPassword: "secret",
},
},
+ {
+ desc: "missing credentials",
+ envVars: map[string]string{},
+ expected: "iwantmyname: some credentials information are missing: IWANTMYNAME_USERNAME,IWANTMYNAME_PASSWORD",
+ },
{
desc: "missing username",
envVars: map[string]string{
- EnvUsername: "",
EnvPassword: "secret",
},
- expected: "35com: some credentials information are missing: COM35_USERNAME",
+ expected: "iwantmyname: some credentials information are missing: IWANTMYNAME_USERNAME",
},
{
desc: "missing password",
envVars: map[string]string{
EnvUsername: "user",
- EnvPassword: "",
},
- expected: "35com: some credentials information are missing: COM35_PASSWORD",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "35com: some credentials information are missing: COM35_USERNAME,COM35_PASSWORD",
+ expected: "iwantmyname: some credentials information are missing: IWANTMYNAME_PASSWORD",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -60,7 +58,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -80,19 +79,19 @@ func TestNewDNSProviderConfig(t *testing.T) {
username: "user",
password: "secret",
},
+ {
+ desc: "missing credentials",
+ expected: "iwantmyname: credentials missing",
+ },
{
desc: "missing username",
password: "secret",
- expected: "35com: credentials missing",
+ expected: "iwantmyname: credentials missing",
},
{
desc: "missing password",
username: "user",
- expected: "35com: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "35com: credentials missing",
+ expected: "iwantmyname: credentials missing",
},
}
@@ -107,7 +106,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -121,7 +121,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -135,7 +134,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/jdcloud/fixtures/create_record-request.json b/providers/dns/jdcloud/fixtures/create_record-request.json
deleted file mode 100644
index 581c00fea..000000000
--- a/providers/dns/jdcloud/fixtures/create_record-request.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "domainId": "20",
- "regionId": "cn-north-1",
- "req": {
- "hostRecord": "_acme-challenge",
- "hostValue": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "jcloudRes": null,
- "mxPriority": null,
- "port": null,
- "ttl": 120,
- "type": "TXT",
- "viewValue": -1,
- "weight": null
- }
-}
diff --git a/providers/dns/jdcloud/fixtures/create_record.json b/providers/dns/jdcloud/fixtures/create_record.json
deleted file mode 100644
index 08bd3db26..000000000
--- a/providers/dns/jdcloud/fixtures/create_record.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "requestId": "azerty",
- "error": {
- "code": 0,
- "status": "",
- "message": ""
- },
- "result": {
- "dataList": {
- "id": 123,
- "hostRecord": "_acme-challenge",
- "hostValue": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "jcloudRes": false,
- "mxPriority": 0,
- "port": 0,
- "ttl": 120,
- "type": "TXT",
- "weight": 0,
- "viewValue": [
- 1,
- 2
- ]
- }
- }
-}
diff --git a/providers/dns/jdcloud/fixtures/delete_record.json b/providers/dns/jdcloud/fixtures/delete_record.json
deleted file mode 100644
index 20525751c..000000000
--- a/providers/dns/jdcloud/fixtures/delete_record.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "requestId": "azerty",
- "error": {
- "code": 0,
- "status": "",
- "message": ""
- },
- "result": {}
-}
diff --git a/providers/dns/jdcloud/fixtures/describe_domains_page1.json b/providers/dns/jdcloud/fixtures/describe_domains_page1.json
deleted file mode 100644
index cde6dcd6f..000000000
--- a/providers/dns/jdcloud/fixtures/describe_domains_page1.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "requestId": "azerty",
- "error": {
- "code": 0,
- "status": "",
- "message": ""
- },
- "result": {
- "dataList": [
- {
- "id": 1,
- "domainName": "1.example"
- },
- {
- "id": 2,
- "domainName": "2.example"
- },
- {
- "id": 3,
- "domainName": "3.example"
- },
- {
- "id": 4,
- "domainName": "4.example"
- },
- {
- "id": 5,
- "domainName": "5.example"
- },
- {
- "id": 6,
- "domainName": "6.example"
- },
- {
- "id": 7,
- "domainName": "7.example"
- },
- {
- "id": 8,
- "domainName": "8.example"
- },
- {
- "id": 9,
- "domainName": "9.example"
- },
- {
- "id": 10,
- "domainName": "10.example"
- }
- ],
- "currentCount": 10,
- "totalCount": 20,
- "totalPage": 2
- }
-}
diff --git a/providers/dns/jdcloud/fixtures/describe_domains_page2.json b/providers/dns/jdcloud/fixtures/describe_domains_page2.json
deleted file mode 100644
index b1e1560ab..000000000
--- a/providers/dns/jdcloud/fixtures/describe_domains_page2.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "requestId": "azerty",
- "error": {
- "code": 0,
- "status": "",
- "message": ""
- },
- "result": {
- "dataList": [
- {
- "id": 11,
- "domainName": "11.example"
- },
- {
- "id": 12,
- "domainName": "12.example"
- },
- {
- "id": 13,
- "domainName": "13.example"
- },
- {
- "id": 14,
- "domainName": "14.example"
- },
- {
- "id": 15,
- "domainName": "15.example"
- },
- {
- "id": 16,
- "domainName": "16.example"
- },
- {
- "id": 17,
- "domainName": "17.example"
- },
- {
- "id": 18,
- "domainName": "18.example"
- },
- {
- "id": 19,
- "domainName": "19.example"
- },
- {
- "id": 20,
- "domainName": "example.com"
- }
- ],
- "currentCount": 10,
- "totalCount": 20,
- "totalPage": 2
- }
-}
diff --git a/providers/dns/jdcloud/jdcloud.go b/providers/dns/jdcloud/jdcloud.go
deleted file mode 100644
index 7d9ad4e6b..000000000
--- a/providers/dns/jdcloud/jdcloud.go
+++ /dev/null
@@ -1,217 +0,0 @@
-// Package jdcloud implements a DNS provider for solving the DNS-01 challenge using JD Cloud.
-package jdcloud
-
-import (
- "errors"
- "fmt"
- "strconv"
- "sync"
- "time"
-
- "github.com/go-acme/jdcloud-sdk-go/core"
- "github.com/go-acme/jdcloud-sdk-go/services/domainservice/apis"
- jdcclient "github.com/go-acme/jdcloud-sdk-go/services/domainservice/client"
- domainservice "github.com/go-acme/jdcloud-sdk-go/services/domainservice/models"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
-)
-
-// Environment variables names.
-const (
- envNamespace = "JDCLOUD_"
-
- EnvAccessKeyID = envNamespace + "ACCESS_KEY_ID"
- EnvAccessKeySecret = envNamespace + "ACCESS_KEY_SECRET"
- EnvRegionID = envNamespace + "REGION_ID"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- AccessKeyID string
- AccessKeySecret string
- RegionID string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPTimeout time.Duration
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *jdcclient.DomainserviceClient
-
- recordIDs map[string]int
- domainIDs map[string]int
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for JD Cloud.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAccessKeyID, EnvAccessKeySecret)
- if err != nil {
- return nil, fmt.Errorf("jdcloud: %w", err)
- }
-
- config := NewDefaultConfig()
- config.AccessKeyID = values[EnvAccessKeyID]
- config.AccessKeySecret = values[EnvAccessKeySecret]
-
- // https://docs.jdcloud.com/en/common-declaration/api/introduction#Region%20Code
- config.RegionID = env.GetOrDefaultString(EnvRegionID, "cn-north-1")
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for JD Cloud.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("jdcloud: the configuration of the DNS provider is nil")
- }
-
- if config.AccessKeyID == "" || config.AccessKeySecret == "" {
- return nil, errors.New("jdcloud: missing credentials")
- }
-
- cred := core.NewCredentials(config.AccessKeyID, config.AccessKeySecret)
-
- client := jdcclient.NewDomainserviceClient(cred)
- client.DisableLogger()
- client.Config.SetTimeout(config.HTTPTimeout)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]int),
- domainIDs: make(map[string]int),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("jdcloud: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("jdcloud: %w", err)
- }
-
- zone, err := d.findZone(dns01.UnFqdn(authZone))
- if err != nil {
- return fmt.Errorf("jdcloud: %w", err)
- }
-
- // https://docs.jdcloud.com/cn/jd-cloud-dns/api/createresourcerecord
- crrr := apis.NewCreateResourceRecordRequestWithAllParams(
- d.config.RegionID,
- strconv.Itoa(zone.Id),
- &domainservice.AddRR{
- HostRecord: subDomain,
- HostValue: info.Value,
- Ttl: d.config.TTL,
- Type: "TXT",
- ViewValue: -1,
- },
- )
-
- record, err := jdcclient.CreateResourceRecord(d.client, crrr)
- if err != nil {
- return fmt.Errorf("jdcloud: create resource record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.domainIDs[token] = zone.Id
- d.recordIDs[token] = record.Result.DataList.Id
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- d.recordIDsMu.Lock()
- recordID, recordOK := d.recordIDs[token]
- domainID, domainOK := d.domainIDs[token]
- d.recordIDsMu.Unlock()
-
- if !recordOK {
- return fmt.Errorf("jdcloud: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- if !domainOK {
- return fmt.Errorf("jdcloud: unknown domain ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- // https://docs.jdcloud.com/cn/jd-cloud-dns/api/deleteresourcerecord
- drrr := apis.NewDeleteResourceRecordRequestWithAllParams(
- d.config.RegionID,
- strconv.Itoa(domainID),
- strconv.Itoa(recordID),
- )
-
- _, err := jdcclient.DeleteResourceRecord(d.client, drrr)
- if err != nil {
- return fmt.Errorf("jdcloud: delete resource record: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findZone(zone string) (*domainservice.DomainInfo, error) {
- // https://docs.jdcloud.com/cn/jd-cloud-dns/api/describedomains
- ddr := apis.NewDescribeDomainsRequestWithoutParam()
- ddr.SetRegionId(d.config.RegionID)
- ddr.SetPageNumber(1)
- ddr.SetPageSize(10)
- ddr.SetDomainName(zone)
-
- for {
- response, err := jdcclient.DescribeDomains(d.client, ddr)
- if err != nil {
- return nil, fmt.Errorf("describe domains: %w", err)
- }
-
- for _, d := range response.Result.DataList {
- if d.DomainName == zone {
- return &d, nil
- }
- }
-
- if len(response.Result.DataList) < ddr.PageSize || response.Result.TotalPage <= ddr.PageNumber {
- break
- }
-
- ddr.SetPageNumber(ddr.PageNumber + 1)
- }
-
- return nil, errors.New("zone not found")
-}
diff --git a/providers/dns/jdcloud/jdcloud.toml b/providers/dns/jdcloud/jdcloud.toml
deleted file mode 100644
index 7ab403822..000000000
--- a/providers/dns/jdcloud/jdcloud.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-Name = "JD Cloud"
-Description = ''''''
-URL = "https://www.jdcloud.com/"
-Code = "jdcloud"
-Since = "v4.31.0"
-
-Example = '''
-JDCLOUD_ACCESS_KEY_ID="xxx" \
-JDCLOUD_ACCESS_KEY_SECRET="yyy" \
-lego --dns jdcloud -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- JDCLOUD_ACCESS_KEY_ID = "Access key ID"
- JDCLOUD_ACCESS_KEY_SECRET = "Access key secret"
- [Configuration.Additional]
- JDCLOUD_REGION_ID = "Region ID (Default: cn-north-1)"
- JDCLOUD_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- JDCLOUD_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- JDCLOUD_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- JDCLOUD_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://docs.jdcloud.com/cn/jd-cloud-dns/api/overview"
- Common = "https://docs.jdcloud.com/en/common-declaration/api/introduction"
- GoClient = "https://github.com/jdcloud-api/jdcloud-sdk-go"
diff --git a/providers/dns/jdcloud/jdcloud_test.go b/providers/dns/jdcloud/jdcloud_test.go
deleted file mode 100644
index 6b3368938..000000000
--- a/providers/dns/jdcloud/jdcloud_test.go
+++ /dev/null
@@ -1,242 +0,0 @@
-package jdcloud
-
-import (
- "fmt"
- "net"
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvAccessKeyID,
- EnvAccessKeySecret,
- EnvRegionID,
-).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAccessKeyID: "abc123",
- EnvAccessKeySecret: "secret",
- },
- },
- {
- desc: "missing access key ID",
- envVars: map[string]string{
- EnvAccessKeyID: "",
- EnvAccessKeySecret: "secret",
- },
- expected: "jdcloud: some credentials information are missing: JDCLOUD_ACCESS_KEY_ID",
- },
- {
- desc: "missing access key secret",
- envVars: map[string]string{
- EnvAccessKeyID: "abc123",
- EnvAccessKeySecret: "",
- },
- expected: "jdcloud: some credentials information are missing: JDCLOUD_ACCESS_KEY_SECRET",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "jdcloud: some credentials information are missing: JDCLOUD_ACCESS_KEY_ID,JDCLOUD_ACCESS_KEY_SECRET",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- accessKeyID string
- accessKeySecret string
- expected string
- }{
- {
- desc: "success",
- accessKeyID: "abc123",
- accessKeySecret: "secret",
- },
- {
- desc: "missing access key ID",
- accessKeySecret: "secret",
- expected: "jdcloud: missing credentials",
- },
- {
- desc: "missing access key secret",
- accessKeyID: "abc123",
- expected: "jdcloud: missing credentials",
- },
- {
- desc: "missing credentials",
- expected: "jdcloud: missing credentials",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.AccessKeyID = test.accessKeyID
- config.AccessKeySecret = test.accessKeySecret
- config.RegionID = "cn-north-1"
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.AccessKeyID = "abc123"
- config.AccessKeySecret = "secret"
- config.RegionID = "cn-north-1"
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- serverURL, _ := url.Parse(server.URL)
-
- p.client.Config.SetEndpoint(net.JoinHostPort(serverURL.Hostname(), serverURL.Port()))
- p.client.Config.SetScheme(serverURL.Scheme)
- p.client.Config.SetTimeout(server.Client().Timeout)
-
- return p, nil
- },
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /v2/regions/cn-north-1/domain",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- pageNumber := req.URL.Query().Get("pageNumber")
-
- servermock.ResponseFromFixture(
- fmt.Sprintf("describe_domains_page%s.json", pageNumber),
- ).ServeHTTP(rw, req)
- }),
- servermock.CheckQueryParameter().Strict().
- With("domainName", "example.com").
- WithRegexp("pageNumber", `(1|2)`).
- With("pageSize", "10"),
- servermock.CheckHeader().
- WithRegexp("Authorization",
- `JDCLOUD2-HMAC-SHA256 Credential=abc123/\d{8}/cn-north-1/domainservice/jdcloud2_request, SignedHeaders=content-type;host;x-jdcloud-date;x-jdcloud-nonce, Signature=\w+`).
- WithRegexp("X-Jdcloud-Date", `\d{8}T\d{6}Z`).
- WithRegexp("X-Jdcloud-Nonce", `[\w-]+`),
- ).
- Route("POST /v2/regions/cn-north-1/domain/20/ResourceRecord",
- servermock.ResponseFromFixture("create_record.json"),
- servermock.CheckRequestJSONBodyFromFixture("create_record-request.json"),
- servermock.CheckHeader().
- WithRegexp("Authorization",
- `JDCLOUD2-HMAC-SHA256 Credential=abc123/\d{8}/cn-north-1/domainservice/jdcloud2_request, SignedHeaders=content-type;host;x-jdcloud-date;x-jdcloud-nonce, Signature=\w+`).
- WithRegexp("X-Jdcloud-Date", `\d{8}T\d{6}Z`).
- WithRegexp("X-Jdcloud-Nonce", `[\w-]+`),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-
- require.Len(t, provider.domainIDs, 1)
- require.Len(t, provider.recordIDs, 1)
-
- assert.Equal(t, 20, provider.domainIDs["abc"])
- assert.Equal(t, 123, provider.recordIDs["abc"])
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /v2/regions/cn-north-1/domain/20/ResourceRecord/123",
- servermock.ResponseFromFixture("delete_record.json"),
- servermock.CheckHeader().
- WithRegexp("Authorization",
- `JDCLOUD2-HMAC-SHA256 Credential=abc123/\d{8}/cn-north-1/domainservice/jdcloud2_request, SignedHeaders=content-type;host;x-jdcloud-date;x-jdcloud-nonce, Signature=\w+`).
- WithRegexp("X-Jdcloud-Date", `\d{8}T\d{6}Z`).
- WithRegexp("X-Jdcloud-Nonce", `[\w-]+`),
- ).
- Build(t)
-
- provider.domainIDs["abc"] = 20
- provider.recordIDs["abc"] = 123
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/joker/internal/dmapi/client.go b/providers/dns/joker/internal/dmapi/client.go
index 576410723..6496abe2e 100644
--- a/providers/dns/joker/internal/dmapi/client.go
+++ b/providers/dns/joker/internal/dmapi/client.go
@@ -176,15 +176,12 @@ func RemoveTxtEntryFromZone(zone, relative string) (string, bool) {
prefix := fmt.Sprintf("%s TXT 0 ", relative)
modified := false
-
var zoneEntries []string
-
for line := range strings.Lines(zone) {
if strings.HasPrefix(line, prefix) {
modified = true
continue
}
-
zoneEntries = append(zoneEntries, line)
}
diff --git a/providers/dns/joker/internal/dmapi/identity.go b/providers/dns/joker/internal/dmapi/identity.go
index 63c0b2ea1..351d987e9 100644
--- a/providers/dns/joker/internal/dmapi/identity.go
+++ b/providers/dns/joker/internal/dmapi/identity.go
@@ -24,7 +24,6 @@ type Token struct {
// login performs a log in to Joker's DMAPI.
func (c *Client) login(ctx context.Context) (*Response, error) {
var values url.Values
-
switch {
case c.username != "" && c.password != "":
values = url.Values{
@@ -107,6 +106,5 @@ func formatResponseError(response *Response, err error) error {
if response != nil {
return fmt.Errorf("joker: DMAPI error: %w Response: %v", err, response.Headers)
}
-
return fmt.Errorf("joker: DMAPI error: %w", err)
}
diff --git a/providers/dns/joker/joker.toml b/providers/dns/joker/joker.toml
index 20e481a6d..35713df18 100644
--- a/providers/dns/joker/joker.toml
+++ b/providers/dns/joker/joker.toml
@@ -9,17 +9,17 @@ Example = '''
JOKER_API_MODE=SVC \
JOKER_USERNAME= \
JOKER_PASSWORD= \
-lego --dns joker -d '*.example.com' -d example.com run
+lego --email you@example.com --dns joker -d '*.example.com' -d example.com run
# DMAPI
JOKER_API_MODE=DMAPI \
JOKER_USERNAME= \
JOKER_PASSWORD= \
-lego --dns joker -d '*.example.com' -d example.com run
+lego --email you@example.com --dns joker -d '*.example.com' -d example.com run
## or
JOKER_API_MODE=DMAPI \
JOKER_API_KEY= \
-lego --dns joker -d '*.example.com' -d example.com run
+lego --email you@example.com --dns joker -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/joker/joker_test.go b/providers/dns/joker/joker_test.go
index bc21ccbbc..20e3fc7a5 100644
--- a/providers/dns/joker/joker_test.go
+++ b/providers/dns/joker/joker_test.go
@@ -53,7 +53,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -113,7 +112,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -127,7 +125,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/joker/provider_dmapi.go b/providers/dns/joker/provider_dmapi.go
index 11f850136..5c623467a 100644
--- a/providers/dns/joker/provider_dmapi.go
+++ b/providers/dns/joker/provider_dmapi.go
@@ -10,7 +10,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/joker/internal/dmapi"
)
@@ -28,7 +27,6 @@ func newDmapiProvider() (*dmapiProvider, error) {
values, err := env.Get(EnvAPIKey)
if err != nil {
var errU error
-
values, errU = env.Get(EnvUsername, EnvPassword)
if errU != nil {
//nolint:errorlint // false-positive
@@ -68,8 +66,6 @@ func newDmapiProviderConfig(config *Config) (*dmapiProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &dmapiProvider{config: config, client: client}, nil
}
@@ -162,7 +158,6 @@ func (d *dmapiProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return formatResponseError(response, err)
}
-
return nil
}
@@ -171,6 +166,5 @@ func formatResponseError(response *dmapi.Response, err error) error {
if response != nil {
return fmt.Errorf("joker: DMAPI error: %w Response: %v", err, response.Headers)
}
-
return fmt.Errorf("joker: DMAPI error: %w", err)
}
diff --git a/providers/dns/joker/provider_dmapi_test.go b/providers/dns/joker/provider_dmapi_test.go
index 06f283872..4704f2b80 100644
--- a/providers/dns/joker/provider_dmapi_test.go
+++ b/providers/dns/joker/provider_dmapi_test.go
@@ -58,7 +58,6 @@ func Test_newDmapiProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
diff --git a/providers/dns/joker/provider_svc.go b/providers/dns/joker/provider_svc.go
index f4d8fcf3f..991772fe7 100644
--- a/providers/dns/joker/provider_svc.go
+++ b/providers/dns/joker/provider_svc.go
@@ -9,7 +9,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/joker/internal/svc"
)
@@ -48,8 +47,6 @@ func newSvcProviderConfig(config *Config) (*svcProvider, error) {
client := svc.NewClient(config.Username, config.Password)
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &svcProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/joker/provider_svc_test.go b/providers/dns/joker/provider_svc_test.go
index dc981b6b4..ad6c74c87 100644
--- a/providers/dns/joker/provider_svc_test.go
+++ b/providers/dns/joker/provider_svc_test.go
@@ -49,7 +49,6 @@ func Test_newSvcProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
diff --git a/providers/dns/keyhelp/internal/client.go b/providers/dns/keyhelp/internal/client.go
deleted file mode 100644
index a5a80db5c..000000000
--- a/providers/dns/keyhelp/internal/client.go
+++ /dev/null
@@ -1,175 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
-)
-
-// APIKeyHeader API key header.
-const APIKeyHeader = "X-Api-Key"
-
-// Client the KeyHelp API client.
-type Client struct {
- apiKey string
-
- baseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(baseURL, apiKey string) (*Client, error) {
- if baseURL == "" {
- return nil, errors.New("missing base URL")
- }
-
- if apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- base, err := url.Parse(baseURL)
- if err != nil {
- return nil, fmt.Errorf("parse base URL: %w", err)
- }
-
- return &Client{
- apiKey: apiKey,
- baseURL: base.JoinPath("api", "v2"),
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- req.Header.Set(APIKeyHeader, c.apiKey)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func (c *Client) ListDomains(ctx context.Context) ([]Domain, error) {
- endpoint := c.baseURL.JoinPath("domains")
-
- query := endpoint.Query()
- query.Set("sort", "domain_utf8")
- endpoint.RawQuery = query.Encode()
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result []Domain
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-func (c *Client) ListDomainRecords(ctx context.Context, domainID int) (*DomainRecords, error) {
- endpoint := c.baseURL.JoinPath("dns", strconv.Itoa(domainID))
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result DomainRecords
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, nil
-}
-
-func (c *Client) UpdateDomainRecords(ctx context.Context, domainID int, records DomainRecords) (*DomainID, error) {
- endpoint := c.baseURL.JoinPath("dns", strconv.Itoa(domainID))
-
- req, err := newJSONRequest(ctx, http.MethodPut, endpoint, records)
- if err != nil {
- return nil, err
- }
-
- var result DomainID
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
diff --git a/providers/dns/keyhelp/internal/client_test.go b/providers/dns/keyhelp/internal/client_test.go
deleted file mode 100644
index 80b21495b..000000000
--- a/providers/dns/keyhelp/internal/client_test.go
+++ /dev/null
@@ -1,169 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(server.URL, "secret")
- if err != nil {
- return nil, err
- }
-
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- With(APIKeyHeader, "secret").
- WithJSONHeaders(),
- )
-}
-
-func TestClient_ListDomains(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/v2/domains",
- servermock.ResponseFromFixture("get_domains.json"),
- servermock.CheckQueryParameter().
- With("sort", "domain_utf8").
- Strict()).
- Build(t)
-
- domains, err := client.ListDomains(t.Context())
- require.NoError(t, err)
-
- expected := []Domain{{
- ID: 8,
- UserID: 4,
- ParentDomainID: 0,
- Status: 1,
- Domain: "example.com",
- DomainUTF8: "example.com",
- IsEmailDomain: true,
- }}
-
- assert.Equal(t, expected, domains)
-}
-
-func TestClient_ListDomains_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/v2/domains",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- _, err := client.ListDomains(t.Context())
-
- require.EqualError(t, err, "401 Unauthorized: API key is missing or invalid.")
-}
-
-func TestClient_ListDomainRecords(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/v2/dns/123",
- servermock.ResponseFromFixture("get_domain_records.json")).
- Build(t)
-
- domainRecords, err := client.ListDomainRecords(t.Context(), 123)
- require.NoError(t, err)
-
- expected := &DomainRecords{
- DkimRecord: `default._domainkey IN TXT ( "v=DKIM1; k=rsa; s=email; " "...DKIM KEY..." )`,
- Records: &Records{
- Soa: &SOARecord{
- TTL: 86400,
- PrimaryNs: "ns.example.com.",
- RName: "root.example.com.",
- Refresh: 14400,
- Retry: 1800,
- Expire: 604800,
- Minimum: 3600,
- },
- Other: []Record{{
- Host: "@",
- TTL: 86400,
- Type: "A",
- Value: "192.168.178.1",
- }},
- },
- }
-
- assert.Equal(t, expected, domainRecords)
-}
-
-func TestClient_ListDomainRecords_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/v2/dns/8",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- _, err := client.ListDomainRecords(t.Context(), 8)
-
- require.EqualError(t, err, "401 Unauthorized: API key is missing or invalid.")
-}
-
-func TestClient_UpdateDomainRecords(t *testing.T) {
- client := mockBuilder().
- Route("PUT /api/v2/dns/8",
- servermock.ResponseFromFixture("update_domain_records.json"),
- servermock.CheckRequestJSONBodyFromFixture("update_domain_records-request.json")).
- Build(t)
-
- records := DomainRecords{
- DkimRecord: `default._domainkey IN TXT ( "v=DKIM1; k=rsa; s=email; " "...DKIM KEY..." )`,
- Records: &Records{
- Soa: &SOARecord{
- TTL: 86400,
- PrimaryNs: "ns.example.com.",
- RName: "root.example.com.",
- Refresh: 14400,
- Retry: 1800,
- Expire: 604800,
- Minimum: 3600,
- },
- Other: []Record{
- {
- Host: "@",
- TTL: 86400,
- Type: "A",
- Value: "192.168.178.1",
- },
- {
- Host: "_acme-challenge",
- TTL: 120,
- Type: "TXT",
- Value: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- },
- },
- },
- }
-
- domainID, err := client.UpdateDomainRecords(t.Context(), 8, records)
- require.NoError(t, err)
-
- expected := &DomainID{ID: 8}
-
- assert.Equal(t, expected, domainID)
-}
-
-func TestClient_UpdateDomainRecords_error(t *testing.T) {
- client := mockBuilder().
- Route("PUT /api/v2/dns/123",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- records := DomainRecords{}
-
- _, err := client.UpdateDomainRecords(t.Context(), 123, records)
-
- require.EqualError(t, err, "401 Unauthorized: API key is missing or invalid.")
-}
diff --git a/providers/dns/keyhelp/internal/fixtures/error.json b/providers/dns/keyhelp/internal/fixtures/error.json
deleted file mode 100644
index 4fdf5e8f5..000000000
--- a/providers/dns/keyhelp/internal/fixtures/error.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "code": "401 Unauthorized",
- "message": "API key is missing or invalid."
-}
diff --git a/providers/dns/keyhelp/internal/fixtures/get_domain_records.json b/providers/dns/keyhelp/internal/fixtures/get_domain_records.json
deleted file mode 100644
index 50483bb8e..000000000
--- a/providers/dns/keyhelp/internal/fixtures/get_domain_records.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "is_custom_dns": false,
- "is_dns_disabled": false,
- "dkim_record": "default._domainkey IN TXT ( \"v=DKIM1; k=rsa; s=email; \" \"...DKIM KEY...\" )",
- "records": {
- "soa": {
- "ttl": 86400,
- "primary_ns": "ns.example.com.",
- "rname": "root.example.com.",
- "refresh": 14400,
- "retry": 1800,
- "expire": 604800,
- "minimum": 3600
- },
- "other": [
- {
- "host": "@",
- "ttl": 86400,
- "type": "A",
- "value": "192.168.178.1"
- }
- ]
- }
-}
diff --git a/providers/dns/keyhelp/internal/fixtures/get_domain_records2.json b/providers/dns/keyhelp/internal/fixtures/get_domain_records2.json
deleted file mode 100644
index cd49fd6d0..000000000
--- a/providers/dns/keyhelp/internal/fixtures/get_domain_records2.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "is_custom_dns": false,
- "is_dns_disabled": false,
- "dkim_record": "default._domainkey IN TXT ( \"v=DKIM1; k=rsa; s=email; \" \"...DKIM KEY...\" )",
- "records": {
- "soa": {
- "ttl": 86400,
- "primary_ns": "ns.example.com.",
- "rname": "root.example.com.",
- "refresh": 14400,
- "retry": 1800,
- "expire": 604800,
- "minimum": 3600
- },
- "other": [
- {
- "host": "@",
- "ttl": 86400,
- "type": "A",
- "value": "192.168.178.1"
- },
- {
- "host": "_acme-challenge",
- "ttl": 120,
- "type": "TXT",
- "value": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- }
- ]
- }
-}
diff --git a/providers/dns/keyhelp/internal/fixtures/get_domains.json b/providers/dns/keyhelp/internal/fixtures/get_domains.json
deleted file mode 100644
index 28ae0887d..000000000
--- a/providers/dns/keyhelp/internal/fixtures/get_domains.json
+++ /dev/null
@@ -1,41 +0,0 @@
-[
- {
- "id": 8,
- "id_user": 4,
- "id_parent_domain": 0,
- "status": 1,
- "domain": "example.com",
- "domain_utf8": "example.com",
- "created_at": "2019-08-15T11:29:13+02:00",
- "php_version": "",
- "traffic": 32434624,
- "is_disabled": false,
- "delete_on": "2025-09-02T19:31:14+0000",
- "dkim_selector": "default",
- "dkim_record": "default._domainkey IN TXT ( \"v=DKIM1; k=rsa; s=email; \" \"...DKIM KEY...\" )",
- "is_custom_dns": false,
- "is_dns_disabled": false,
- "is_subdomain": false,
- "is_system_domain": false,
- "is_email_domain": true,
- "is_email_sending_only": false,
- "target": {
- "target": "https://www.keyhelp.de",
- "is_forwarding": true,
- "forwarding_type": 301
- },
- "security": {
- "id_certificate": 0,
- "lets_encrypt": true,
- "is_prefer_https": true,
- "is_hsts": true,
- "hsts_max_age": 10368000,
- "hsts_include": true,
- "hsts_preload": true
- },
- "apache": {
- "http_directives": "# My custom HTTP directives",
- "https_directives": "# My custom HTTPS directives"
- }
- }
-]
diff --git a/providers/dns/keyhelp/internal/fixtures/update_domain_records-request.json b/providers/dns/keyhelp/internal/fixtures/update_domain_records-request.json
deleted file mode 100644
index 6f83ead11..000000000
--- a/providers/dns/keyhelp/internal/fixtures/update_domain_records-request.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "dkim_record": "default._domainkey IN TXT ( \"v=DKIM1; k=rsa; s=email; \" \"...DKIM KEY...\" )",
- "records": {
- "soa": {
- "ttl": 86400,
- "primary_ns": "ns.example.com.",
- "rname": "root.example.com.",
- "refresh": 14400,
- "retry": 1800,
- "expire": 604800,
- "minimum": 3600
- },
- "other": [
- {
- "host": "@",
- "ttl": 86400,
- "type": "A",
- "value": "192.168.178.1"
- },
- {
- "host": "_acme-challenge",
- "ttl": 120,
- "type": "TXT",
- "value": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- }
- ]
- }
-}
diff --git a/providers/dns/keyhelp/internal/fixtures/update_domain_records-request2.json b/providers/dns/keyhelp/internal/fixtures/update_domain_records-request2.json
deleted file mode 100644
index 3ebb2ee7a..000000000
--- a/providers/dns/keyhelp/internal/fixtures/update_domain_records-request2.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "dkim_record": "default._domainkey IN TXT ( \"v=DKIM1; k=rsa; s=email; \" \"...DKIM KEY...\" )",
- "records": {
- "soa": {
- "ttl": 86400,
- "primary_ns": "ns.example.com.",
- "rname": "root.example.com.",
- "refresh": 14400,
- "retry": 1800,
- "expire": 604800,
- "minimum": 3600
- },
- "other": [
- {
- "host": "@",
- "ttl": 86400,
- "type": "A",
- "value": "192.168.178.1"
- }
- ]
- }
-}
diff --git a/providers/dns/keyhelp/internal/fixtures/update_domain_records.json b/providers/dns/keyhelp/internal/fixtures/update_domain_records.json
deleted file mode 100644
index a335b5ba5..000000000
--- a/providers/dns/keyhelp/internal/fixtures/update_domain_records.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "id": 8
-}
diff --git a/providers/dns/keyhelp/internal/types.go b/providers/dns/keyhelp/internal/types.go
deleted file mode 100644
index 8716fa0c8..000000000
--- a/providers/dns/keyhelp/internal/types.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package internal
-
-import (
- "fmt"
-)
-
-type APIError struct {
- Code string `json:"code,omitempty"`
- Message string `json:"message,omitempty"`
-}
-
-func (a *APIError) Error() string {
- return fmt.Sprintf("%s: %s", a.Code, a.Message)
-}
-
-type Domain struct {
- ID int `json:"id,omitempty"`
- UserID int `json:"id_user,omitempty"`
- ParentDomainID int `json:"id_parent_domain,omitempty"`
- Status int `json:"status,omitempty"`
- Domain string `json:"domain,omitempty"`
- DomainUTF8 string `json:"domain_utf8,omitempty"`
- IsDisabled bool `json:"is_disabled,omitempty"`
- IsCustomDNS bool `json:"is_custom_dns,omitempty"`
- IsDNSDisabled bool `json:"is_dns_disabled,omitempty"`
- IsSubdomain bool `json:"is_subdomain,omitempty"`
- IsSystemDomain bool `json:"is_system_domain,omitempty"`
- IsEmailDomain bool `json:"is_email_domain,omitempty"`
- IsEmailSendingOnly bool `json:"is_email_sending_only,omitempty"`
-}
-
-type DomainID struct {
- ID int `json:"id,omitempty"`
-}
-
-type DomainRecords struct {
- IsCustomDNS bool `json:"is_custom_dns,omitempty"`
- IsDNSDisabled bool `json:"is_dns_disabled,omitempty"`
- DkimRecord string `json:"dkim_record,omitempty"`
- Records *Records `json:"records,omitempty"`
-}
-
-type Records struct {
- Soa *SOARecord `json:"soa,omitempty"`
- Other []Record `json:"other,omitempty"`
-}
-
-type SOARecord struct {
- TTL int `json:"ttl,omitempty"`
- PrimaryNs string `json:"primary_ns,omitempty"`
- RName string `json:"rname,omitempty"`
- Refresh int `json:"refresh,omitempty"`
- Retry int `json:"retry,omitempty"`
- Expire int `json:"expire,omitempty"`
- Minimum int `json:"minimum,omitempty"`
-}
-
-type Record struct {
- Host string `json:"host"`
- TTL int `json:"ttl"`
- Type string `json:"type"`
- Value string `json:"value"`
-}
diff --git a/providers/dns/keyhelp/keyhelp.go b/providers/dns/keyhelp/keyhelp.go
deleted file mode 100644
index 67ceaaa63..000000000
--- a/providers/dns/keyhelp/keyhelp.go
+++ /dev/null
@@ -1,225 +0,0 @@
-// Package keyhelp implements a DNS provider for solving the DNS-01 challenge using KeyHelp.
-package keyhelp
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/keyhelp/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "KEYHELP_"
-
- EnvBaseURL = envNamespace + "BASE_URL"
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- BaseURL string
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- domainIDs map[string]int
- domainIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for KeyHelp.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvBaseURL, EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("keyhelp: %w", err)
- }
-
- config := NewDefaultConfig()
- config.BaseURL = values[EnvBaseURL]
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for KeyHelp.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("keyhelp: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.BaseURL, config.APIKey)
- if err != nil {
- return nil, fmt.Errorf("keyhelp: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- domainIDs: make(map[string]int),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("keyhelp: could not find zone for domain %q: %w", domain, err)
- }
-
- ctx := context.Background()
-
- domainInfo, err := d.findDomain(ctx, dns01.UnFqdn(authZone))
- if err != nil {
- return fmt.Errorf("keyhelp: %w", err)
- }
-
- domainRecords, err := d.client.ListDomainRecords(ctx, domainInfo.ID)
- if err != nil {
- return fmt.Errorf("keyhelp: list domain records: %w", err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("keyhelp: %w", err)
- }
-
- records := domainRecords.Records.Other
- records = append(records, internal.Record{
- Host: subDomain,
- TTL: d.config.TTL,
- Type: "TXT",
- Value: info.Value,
- })
-
- req := internal.DomainRecords{
- DkimRecord: domainRecords.DkimRecord,
- Records: &internal.Records{
- Soa: domainRecords.Records.Soa,
- Other: records,
- },
- }
-
- _, err = d.client.UpdateDomainRecords(ctx, domainInfo.ID, req)
- if err != nil {
- return fmt.Errorf("keyhelp: update domain records (add): %w", err)
- }
-
- d.domainIDsMu.Lock()
- d.domainIDs[token] = domainInfo.ID
- d.domainIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- // get the domain's unique ID from when we created it
- d.domainIDsMu.Lock()
- domainID, ok := d.domainIDs[token]
- d.domainIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("keyhelp: unknown record ID for '%s'", info.EffectiveFQDN)
- }
-
- domainRecords, err := d.client.ListDomainRecords(ctx, domainID)
- if err != nil {
- return fmt.Errorf("keyhelp: list domain records: %w", err)
- }
-
- var records []internal.Record
-
- for _, record := range domainRecords.Records.Other {
- if record.Type == "TXT" && record.Value == info.Value {
- continue
- }
-
- records = append(records, record)
- }
-
- req := internal.DomainRecords{
- DkimRecord: domainRecords.DkimRecord,
- Records: &internal.Records{
- Soa: domainRecords.Records.Soa,
- Other: records,
- },
- }
-
- _, err = d.client.UpdateDomainRecords(ctx, domainID, req)
- if err != nil {
- return fmt.Errorf("keyhelp: update domain records (delete): %w", err)
- }
-
- // Delete domain ID from map
- d.domainIDsMu.Lock()
- delete(d.domainIDs, token)
- d.domainIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findDomain(ctx context.Context, zone string) (internal.Domain, error) {
- domains, err := d.client.ListDomains(ctx)
- if err != nil {
- return internal.Domain{}, fmt.Errorf("list domains: %w", err)
- }
-
- for _, domain := range domains {
- if domain.DomainUTF8 == zone || domain.Domain == zone {
- return domain, nil
- }
- }
-
- return internal.Domain{}, fmt.Errorf("domain not found: %s", zone)
-}
diff --git a/providers/dns/keyhelp/keyhelp.toml b/providers/dns/keyhelp/keyhelp.toml
deleted file mode 100644
index e622794ca..000000000
--- a/providers/dns/keyhelp/keyhelp.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-Name = "KeyHelp"
-Description = ''''''
-URL = "https://www.keyweb.de/en/keyhelp/keyhelp/"
-Code = "keyhelp"
-Since = "v4.26.0"
-
-Example = '''
-KEYHELP_BASE_URL="https://keyhelp.example.com" \
-KEYHELP_API_KEY="xxx" \
-lego --dns keyhelp -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- KEYHELP_BASE_URL= "Server URL"
- KEYHELP_API_KEY = "API key"
- [Configuration.Additional]
- KEYHELP_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- KEYHELP_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- KEYHELP_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- KEYHELP_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://app.swaggerhub.com/apis-docs/keyhelp/api/"
diff --git a/providers/dns/keyhelp/keyhelp_test.go b/providers/dns/keyhelp/keyhelp_test.go
deleted file mode 100644
index 8d8ac821d..000000000
--- a/providers/dns/keyhelp/keyhelp_test.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package keyhelp
-
-import (
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/keyhelp/internal"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvBaseURL, EnvAPIKey).
- WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvBaseURL: "https://keyhelp.example.com",
- EnvAPIKey: "secret",
- },
- },
- {
- desc: "missing base URL",
- envVars: map[string]string{
- EnvAPIKey: "secret",
- },
- expected: "keyhelp: some credentials information are missing: KEYHELP_BASE_URL",
- },
- {
- desc: "missing API key",
- envVars: map[string]string{
- EnvBaseURL: "https://keyhelp.example.com",
- },
- expected: "keyhelp: some credentials information are missing: KEYHELP_API_KEY",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "keyhelp: some credentials information are missing: KEYHELP_BASE_URL,KEYHELP_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- baseURL string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- baseURL: "https://keyhelp.example.com",
- apiKey: "secret",
- },
- {
- desc: "missing base URL",
- apiKey: "secret",
- expected: "keyhelp: missing base URL",
- },
- {
- desc: "missing API key",
- baseURL: "https://keyhelp.example.com",
- expected: "keyhelp: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "keyhelp: missing base URL",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.BaseURL = test.baseURL
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.HTTPClient = server.Client()
- config.APIKey = "secret"
- config.BaseURL = server.URL
-
- return NewDNSProviderConfig(config)
- },
- servermock.CheckHeader().
- With(internal.APIKeyHeader, "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /api/v2/domains",
- servermock.ResponseFromInternal("get_domains.json"),
- servermock.CheckQueryParameter().
- With("sort", "domain_utf8").
- Strict()).
- Route("GET /api/v2/dns/8",
- servermock.ResponseFromInternal("get_domain_records.json")).
- Route("PUT /api/v2/dns/8",
- servermock.ResponseFromInternal("update_domain_records.json"),
- servermock.CheckRequestJSONBodyFromInternal("update_domain_records-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-
- assert.Equal(t, 8, provider.domainIDs["abc"])
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /api/v2/dns/8",
- servermock.ResponseFromInternal("get_domain_records2.json")).
- Route("PUT /api/v2/dns/8",
- servermock.ResponseFromInternal("update_domain_records.json"),
- servermock.CheckRequestJSONBodyFromInternal("update_domain_records-request2.json")).
- Build(t)
-
- provider.domainIDs["abc"] = 8
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/leaseweb/internal/client.go b/providers/dns/leaseweb/internal/client.go
deleted file mode 100644
index 01619d49b..000000000
--- a/providers/dns/leaseweb/internal/client.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://api.leaseweb.com/hosting/v2"
-
-const AuthHeader = "X-LSW-Auth"
-
-// Client the Leaseweb API client.
-type Client struct {
- apiKey string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(apiKey string) (*Client, error) {
- if apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- apiKey: apiKey,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-// CreateRRSet creates a resource record set.
-// https://developer.leaseweb.com/docs/#tag/DNS/operation/createResourceRecordSet
-func (c *Client) CreateRRSet(ctx context.Context, domainName string, rrset RRSet) (*RRSet, error) {
- endpoint := c.BaseURL.JoinPath("domains", domainName, "resourceRecordSets")
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, rrset)
- if err != nil {
- return nil, err
- }
-
- result := &RRSet{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// GetRRSet gets a resource record set.
-// https://developer.leaseweb.com/docs/#tag/DNS/operation/getResourceRecordSet
-func (c *Client) GetRRSet(ctx context.Context, domainName, name, rType string) (*RRSet, error) {
- endpoint := c.BaseURL.JoinPath("domains", domainName, "resourceRecordSets", name, rType)
-
- req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- result := &RRSet{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// UpdateRRSet updates a resource record set.
-// https://developer.leaseweb.com/docs/#tag/DNS/operation/updateResourceRecordSet
-func (c *Client) UpdateRRSet(ctx context.Context, domainName string, rrset RRSet) (*RRSet, error) {
- endpoint := c.BaseURL.JoinPath("domains", domainName, "resourceRecordSets", rrset.Name, rrset.Type)
-
- // Reset values that are not allowed to be updated.
- rrset.Name = ""
- rrset.Type = ""
- rrset.Editable = false
-
- req, err := newJSONRequest(ctx, http.MethodPut, endpoint, rrset)
- if err != nil {
- return nil, err
- }
-
- result := &RRSet{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-// DeleteRRSet deletes a resource record set.
-// https://developer.leaseweb.com/docs/#tag/DNS/operation/deleteResourceRecordSet
-func (c *Client) DeleteRRSet(ctx context.Context, domainName, name, rType string) error {
- endpoint := c.BaseURL.JoinPath("domains", domainName, "resourceRecordSets", name, rType)
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Add(AuthHeader, c.apiKey)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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 {
- if resp.StatusCode == http.StatusNotFound {
- return &NotFoundError{APIError{
- CorrelationID: resp.Header.Get("Correlation-Id"),
- ErrorCode: strconv.Itoa(http.StatusNotFound),
- ErrorMessage: string(raw),
- }}
- }
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- if errAPI.ErrorCode == strconv.Itoa(http.StatusNotFound) {
- return &NotFoundError{APIError: errAPI}
- }
-
- return &errAPI
-}
-
-// TTLRounder rounds the given TTL in seconds to the next accepted value.
-// Accepted TTL values are: 60, 300, 1800, 3600, 14400, 28800, 43200, 86400.
-func TTLRounder(ttl int) int {
- for _, validTTL := range []int{60, 300, 1800, 3600, 14400, 28800, 43200, 86400} {
- if ttl <= validTTL {
- return validTTL
- }
- }
-
- return 3600
-}
diff --git a/providers/dns/leaseweb/internal/client_test.go b/providers/dns/leaseweb/internal/client_test.go
deleted file mode 100644
index 5762aad4b..000000000
--- a/providers/dns/leaseweb/internal/client_test.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With(AuthHeader, "secret"),
- )
-}
-
-func TestClient_CreateRRSet(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/example.com/resourceRecordSets",
- servermock.ResponseFromFixture("createResourceRecordSet.json"),
- servermock.CheckRequestJSONBodyFromFixture("createResourceRecordSet-request.json"),
- ).
- Build(t)
-
- rrset := RRSet{
- Content: []string{"ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"},
- Name: "_acme-challenge.example.com.",
- TTL: 300,
- Type: "TXT",
- }
-
- result, err := client.CreateRRSet(t.Context(), "example.com", rrset)
- require.NoError(t, err)
-
- expected := &RRSet{
- Content: []string{"ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"},
- Name: "_acme-challenge.example.com.",
- Editable: true,
- TTL: 300,
- Type: "TXT",
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_GetRRSet(t *testing.T) {
- client := mockBuilder().
- Route("GET /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromFixture("getResourceRecordSet.json"),
- ).
- Build(t)
-
- result, err := client.GetRRSet(t.Context(), "example.com", "_acme-challenge.example.com.", "TXT")
- require.NoError(t, err)
-
- expected := &RRSet{
- Content: []string{"foo", "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo"},
- Name: "_acme-challenge.example.com.",
- Editable: true,
- TTL: 3600,
- Type: "TXT",
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_GetRRSet_error_404(t *testing.T) {
- client := mockBuilder().
- Route("GET /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromFixture("error_404.json").
- WithStatusCode(http.StatusNotFound),
- ).
- Build(t)
-
- _, err := client.GetRRSet(t.Context(), "example.com", "_acme-challenge.example.com.", "TXT")
- require.EqualError(t, err, "404: Resource not found (289346a1-3eaf-4da4-b707-62ef12eb08be)")
-
- target := &NotFoundError{}
- require.ErrorAs(t, err, &target)
-}
-
-func TestClient_UpdateRRSet(t *testing.T) {
- client := mockBuilder().
- Route("PUT /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromFixture("updateResourceRecordSet.json"),
- servermock.CheckRequestJSONBodyFromFixture("updateResourceRecordSet-request.json"),
- ).
- Build(t)
-
- rrset := RRSet{
- Content: []string{"foo", "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"},
- Name: "_acme-challenge.example.com.",
- TTL: 3600,
- Type: "TXT",
- }
-
- result, err := client.UpdateRRSet(t.Context(), "example.com", rrset)
- require.NoError(t, err)
-
- expected := &RRSet{
- Content: []string{"foo", "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"},
- Name: "_acme-challenge.example.com.",
- Editable: true,
- TTL: 3600,
- Type: "TXT",
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_DeleteRRSet(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- ).
- Build(t)
-
- err := client.DeleteRRSet(t.Context(), "example.com", "_acme-challenge.example.com.", "TXT")
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRRSet_error(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromFixture("error_401.json").
- WithStatusCode(http.StatusUnauthorized),
- ).
- Build(t)
-
- err := client.DeleteRRSet(t.Context(), "example.com", "_acme-challenge.example.com.", "TXT")
- require.EqualError(t, err, "401: You are not authorized to view this resource. (289346a1-3eaf-4da4-b707-62ef12eb08be)")
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/createResourceRecordSet-request.json b/providers/dns/leaseweb/internal/fixtures/createResourceRecordSet-request.json
deleted file mode 100644
index af53fcf04..000000000
--- a/providers/dns/leaseweb/internal/fixtures/createResourceRecordSet-request.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "content": [
- "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- ],
- "name": "_acme-challenge.example.com.",
- "ttl": 300,
- "type": "TXT"
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/createResourceRecordSet.json b/providers/dns/leaseweb/internal/fixtures/createResourceRecordSet.json
deleted file mode 100644
index 8ca040d63..000000000
--- a/providers/dns/leaseweb/internal/fixtures/createResourceRecordSet.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "_links": {
- "self": {
- "href": "/domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT"
- },
- "collection": {
- "href": "/domains/example.com/resourceRecordSets"
- }
- },
- "content": [
- "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- ],
- "editable": true,
- "name": "_acme-challenge.example.com.",
- "ttl": 300,
- "type": "TXT"
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/error_400.json b/providers/dns/leaseweb/internal/fixtures/error_400.json
deleted file mode 100644
index 1a980b6bb..000000000
--- a/providers/dns/leaseweb/internal/fixtures/error_400.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "correlationId": "289346a1-3eaf-4da4-b707-62ef12eb08be",
- "errorCode": "400",
- "errorDetails": {},
- "errorMessage": "The API could not interpret your request correctly."
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/error_401.json b/providers/dns/leaseweb/internal/fixtures/error_401.json
deleted file mode 100644
index 47d8a311d..000000000
--- a/providers/dns/leaseweb/internal/fixtures/error_401.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "correlationId": "289346a1-3eaf-4da4-b707-62ef12eb08be",
- "errorCode": "401",
- "errorMessage": "You are not authorized to view this resource."
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/error_404.json b/providers/dns/leaseweb/internal/fixtures/error_404.json
deleted file mode 100644
index 1deaf5606..000000000
--- a/providers/dns/leaseweb/internal/fixtures/error_404.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "correlationId": "289346a1-3eaf-4da4-b707-62ef12eb08be",
- "errorCode": "404",
- "errorMessage": "Resource not found"
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/getResourceRecordSet.json b/providers/dns/leaseweb/internal/fixtures/getResourceRecordSet.json
deleted file mode 100644
index fd48f60c6..000000000
--- a/providers/dns/leaseweb/internal/fixtures/getResourceRecordSet.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "_links": {
- "self": {
- "href": "/domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT"
- },
- "collection": {
- "href": "/domains/example.com/resourceRecordSets"
- }
- },
- "content": [
- "foo",
- "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo"
- ],
- "editable": true,
- "name": "_acme-challenge.example.com.",
- "ttl": 3600,
- "type": "TXT"
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/getResourceRecordSet2.json b/providers/dns/leaseweb/internal/fixtures/getResourceRecordSet2.json
deleted file mode 100644
index abf3fb4c3..000000000
--- a/providers/dns/leaseweb/internal/fixtures/getResourceRecordSet2.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "_links": {
- "self": {
- "href": "/domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT"
- },
- "collection": {
- "href": "/domains/example.com/resourceRecordSets"
- }
- },
- "content": [
- "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo"
- ],
- "editable": true,
- "name": "_acme-challenge.example.com.",
- "ttl": 3600,
- "type": "TXT"
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet-request.json b/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet-request.json
deleted file mode 100644
index e781958c8..000000000
--- a/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet-request.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "content": [
- "foo",
- "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo",
- "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- ],
- "ttl": 3600
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet-request2.json b/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet-request2.json
deleted file mode 100644
index 0acc314de..000000000
--- a/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet-request2.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "content": [
- "foo"
- ],
- "ttl": 3600
-}
diff --git a/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet.json b/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet.json
deleted file mode 100644
index 2b877982c..000000000
--- a/providers/dns/leaseweb/internal/fixtures/updateResourceRecordSet.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "_links": {
- "self": {
- "href": "/domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT"
- },
- "collection": {
- "href": "/domains/example.com/resourceRecordSets"
- }
- },
- "content": [
- "foo",
- "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo",
- "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
- ],
- "editable": true,
- "name": "_acme-challenge.example.com.",
- "ttl": 3600,
- "type": "TXT"
-}
diff --git a/providers/dns/leaseweb/internal/types.go b/providers/dns/leaseweb/internal/types.go
deleted file mode 100644
index 7a4547584..000000000
--- a/providers/dns/leaseweb/internal/types.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "fmt"
-)
-
-type NotFoundError struct {
- APIError
-}
-
-type APIError struct {
- CorrelationID string `json:"correlationId,omitempty"`
- ErrorCode string `json:"errorCode,omitempty"`
- ErrorMessage string `json:"errorMessage,omitempty"`
- ErrorDetails json.RawMessage `json:"errorDetails,omitempty"`
-}
-
-func (a *APIError) Error() string {
- msg := fmt.Sprintf("%s: %s (%s)", a.ErrorCode, a.ErrorMessage, a.CorrelationID)
-
- if len(a.ErrorDetails) > 0 {
- msg += fmt.Sprintf(": %s", string(a.ErrorDetails))
- }
-
- return msg
-}
-
-type RRSet struct {
- Content []string `json:"content,omitempty"`
- Name string `json:"name,omitempty"`
- Editable bool `json:"editable,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Type string `json:"type,omitempty"`
-}
diff --git a/providers/dns/leaseweb/leaseweb.go b/providers/dns/leaseweb/leaseweb.go
deleted file mode 100644
index fafaf1c4d..000000000
--- a/providers/dns/leaseweb/leaseweb.go
+++ /dev/null
@@ -1,187 +0,0 @@
-// Package leaseweb implements a DNS provider for solving the DNS-01 challenge using Leaseweb.
-package leaseweb
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/leaseweb/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "LEASEWEB_"
-
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Leaseweb.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("leaseweb: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Leaseweb.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("leaseweb: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIKey)
- if err != nil {
- return nil, fmt.Errorf("leaseweb: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("leaseweb: could not find zone for domain %q: %w", domain, err)
- }
-
- existingRRSet, err := d.client.GetRRSet(ctx, dns01.UnFqdn(authZone), info.EffectiveFQDN, "TXT")
- if err != nil {
- notfoundErr := &internal.NotFoundError{}
- if !errors.As(err, ¬foundErr) {
- return fmt.Errorf("leaseweb: get RRSet: %w", err)
- }
-
- // Create the RRSet.
-
- rrset := internal.RRSet{
- Content: []string{info.Value},
- Name: info.EffectiveFQDN,
- TTL: internal.TTLRounder(d.config.TTL),
- Type: "TXT",
- }
-
- _, err = d.client.CreateRRSet(ctx, dns01.UnFqdn(authZone), rrset)
- if err != nil {
- return fmt.Errorf("leaseweb: create RRSet: %w", err)
- }
-
- return nil
- }
-
- // Update the RRSet.
-
- existingRRSet.Content = append(existingRRSet.Content, info.Value)
-
- _, err = d.client.UpdateRRSet(ctx, dns01.UnFqdn(authZone), *existingRRSet)
- if err != nil {
- return fmt.Errorf("leaseweb: update RRSet: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("leaseweb: could not find zone for domain %q: %w", domain, err)
- }
-
- existingRRSet, err := d.client.GetRRSet(ctx, dns01.UnFqdn(authZone), info.EffectiveFQDN, "TXT")
- if err != nil {
- return fmt.Errorf("leaseweb: get RRSet: %w", err)
- }
-
- var content []string
-
- for _, s := range existingRRSet.Content {
- if s != info.Value {
- content = append(content, s)
- }
- }
-
- if len(content) == 0 {
- err = d.client.DeleteRRSet(ctx, dns01.UnFqdn(authZone), info.EffectiveFQDN, "TXT")
- if err != nil {
- return fmt.Errorf("leaseweb: delete RRSet: %w", err)
- }
-
- return nil
- }
-
- existingRRSet.Content = content
-
- _, err = d.client.UpdateRRSet(ctx, dns01.UnFqdn(authZone), *existingRRSet)
- if err != nil {
- return fmt.Errorf("leaseweb: update RRSet: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/leaseweb/leaseweb.toml b/providers/dns/leaseweb/leaseweb.toml
deleted file mode 100644
index 2c3503291..000000000
--- a/providers/dns/leaseweb/leaseweb.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Leaseweb"
-Description = ''''''
-URL = "https://www.leaseweb.com/en/"
-Code = "leaseweb"
-Since = "v4.32.0"
-
-Example = '''
-LEASEWEB_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns leaseweb -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- LEASEWEB_API_KEY = "API key"
- [Configuration.Additional]
- LEASEWEB_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- LEASEWEB_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- LEASEWEB_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- LEASEWEB_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://developer.leaseweb.com/docs/#tag/DNS"
diff --git a/providers/dns/leaseweb/leaseweb_test.go b/providers/dns/leaseweb/leaseweb_test.go
deleted file mode 100644
index 0450cd2c2..000000000
--- a/providers/dns/leaseweb/leaseweb_test.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package leaseweb
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/go-acme/lego/v4/providers/dns/leaseweb/internal"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIKey: "secret",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "leaseweb: some credentials information are missing: LEASEWEB_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- apiKey: "secret",
- },
- {
- desc: "missing credentials",
- expected: "leaseweb: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIKey = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With(internal.AuthHeader, "secret"),
- )
-}
-
-func TestDNSProvider_Present_create(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromInternal("error_404.json").
- WithStatusCode(http.StatusNotFound),
- ).
- Route("POST /domains/example.com/resourceRecordSets",
- servermock.ResponseFromInternal("createResourceRecordSet.json"),
- servermock.CheckRequestJSONBodyFromInternal("createResourceRecordSet-request.json"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_Present_update(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromInternal("getResourceRecordSet.json"),
- ).
- Route("PUT /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromInternal("updateResourceRecordSet.json"),
- servermock.CheckRequestJSONBodyFromInternal("updateResourceRecordSet-request.json"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp_delete(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromInternal("getResourceRecordSet2.json"),
- ).
- Route("DELETE /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.Noop().
- WithStatusCode(http.StatusNoContent),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "1234d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp_update(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromInternal("getResourceRecordSet.json"),
- ).
- Route("PUT /domains/example.com/resourceRecordSets/_acme-challenge.example.com./TXT",
- servermock.ResponseFromInternal("updateResourceRecordSet.json"),
- servermock.CheckRequestJSONBodyFromInternal("updateResourceRecordSet-request2.json"),
- ).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "1234d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/liara/internal/client.go b/providers/dns/liara/internal/client.go
index 95c39695b..3d4af1d3b 100644
--- a/providers/dns/liara/internal/client.go
+++ b/providers/dns/liara/internal/client.go
@@ -20,23 +20,17 @@ const defaultBaseURL = "https://dns-service.iran.liara.ir"
type Client struct {
baseURL *url.URL
httpClient *http.Client
-
- teamID string
}
// NewClient creates a new Client.
-func NewClient(hc *http.Client, teamID string) *Client {
+func NewClient(hc *http.Client) *Client {
baseURL, _ := url.Parse(defaultBaseURL)
if hc == nil {
hc = &http.Client{Timeout: 10 * time.Second}
}
- return &Client{
- httpClient: hc,
- baseURL: baseURL,
- teamID: teamID,
- }
+ return &Client{httpClient: hc, baseURL: baseURL}
}
// GetRecords gets the records of a domain.
@@ -44,7 +38,7 @@ func NewClient(hc *http.Client, teamID string) *Client {
func (c *Client) GetRecords(ctx context.Context, domainName string) ([]Record, error) {
endpoint := c.baseURL.JoinPath("api", "v1", "zones", domainName, "dns-records")
- req, err := c.newJSONRequest(ctx, http.MethodGet, endpoint, nil)
+ req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
@@ -66,7 +60,6 @@ func (c *Client) GetRecords(ctx context.Context, domainName string) ([]Record, e
}
var response Response[[]Record]
-
err = json.Unmarshal(raw, &response)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -79,7 +72,7 @@ func (c *Client) GetRecords(ctx context.Context, domainName string) ([]Record, e
func (c *Client) CreateRecord(ctx context.Context, domainName string, record Record) (*Record, error) {
endpoint := c.baseURL.JoinPath("api", "v1", "zones", domainName, "dns-records")
- req, err := c.newJSONRequest(ctx, http.MethodPost, endpoint, record)
+ req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
@@ -101,7 +94,6 @@ func (c *Client) CreateRecord(ctx context.Context, domainName string, record Rec
}
var response Response[*Record]
-
err = json.Unmarshal(raw, &response)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -114,7 +106,7 @@ func (c *Client) CreateRecord(ctx context.Context, domainName string, record Rec
func (c *Client) GetRecord(ctx context.Context, domainName, recordID string) (*Record, error) {
endpoint := c.baseURL.JoinPath("api", "v1", "zones", domainName, "dns-records", recordID)
- req, err := c.newJSONRequest(ctx, http.MethodGet, endpoint, nil)
+ req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
@@ -136,7 +128,6 @@ func (c *Client) GetRecord(ctx context.Context, domainName, recordID string) (*R
}
var response Response[*Record]
-
err = json.Unmarshal(raw, &response)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -149,7 +140,7 @@ func (c *Client) GetRecord(ctx context.Context, domainName, recordID string) (*R
func (c *Client) DeleteRecord(ctx context.Context, domainName, recordID string) error {
endpoint := c.baseURL.JoinPath("api", "v1", "zones", domainName, "dns-records", recordID)
- req, err := c.newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
+ req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
if err != nil {
return fmt.Errorf("create request: %w", err)
}
@@ -168,14 +159,7 @@ func (c *Client) DeleteRecord(ctx context.Context, domainName, recordID string)
return nil
}
-func (c *Client) newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- if c.teamID != "" {
- query := endpoint.Query()
- query.Set("teamID", c.teamID)
-
- endpoint.RawQuery = query.Encode()
- }
-
+func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
buf := new(bytes.Buffer)
if payload != nil {
@@ -203,7 +187,6 @@ 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)
diff --git a/providers/dns/liara/internal/client_test.go b/providers/dns/liara/internal/client_test.go
index b6d007046..57ac7e8b3 100644
--- a/providers/dns/liara/internal/client_test.go
+++ b/providers/dns/liara/internal/client_test.go
@@ -13,10 +13,10 @@ import (
const apiKey = "key"
-func mockBuilder(teamID string) *servermock.Builder[*Client] {
+func mockBuilder() *servermock.Builder[*Client] {
return servermock.NewBuilder[*Client](
func(server *httptest.Server) (*Client, error) {
- client := NewClient(OAuthStaticAccessToken(server.Client(), apiKey), teamID)
+ client := NewClient(OAuthStaticAccessToken(server.Client(), apiKey))
client.baseURL, _ = url.Parse(server.URL)
return client, nil
@@ -26,7 +26,7 @@ func mockBuilder(teamID string) *servermock.Builder[*Client] {
}
func TestClient_GetRecords(t *testing.T) {
- client := mockBuilder("").
+ client := mockBuilder().
Route("GET /api/v1/zones/example.com/dns-records", servermock.ResponseFromFixture("RecordsResponse.json")).
Build(t)
@@ -50,7 +50,7 @@ func TestClient_GetRecords(t *testing.T) {
}
func TestClient_GetRecord(t *testing.T) {
- client := mockBuilder("").
+ client := mockBuilder().
Route("GET /api/v1/zones/example.com/dns-records/123", servermock.ResponseFromFixture("RecordResponse.json")).
Build(t)
@@ -72,7 +72,7 @@ func TestClient_GetRecord(t *testing.T) {
}
func TestClient_CreateRecord(t *testing.T) {
- client := mockBuilder("").
+ client := mockBuilder().
Route("POST /api/v1/zones/example.com/dns-records",
servermock.ResponseFromFixture("RecordResponse.json").
WithStatusCode(http.StatusCreated),
@@ -108,47 +108,8 @@ func TestClient_CreateRecord(t *testing.T) {
assert.Equal(t, expected, record)
}
-func TestClient_CreateRecord_withTeamID(t *testing.T) {
- client := mockBuilder("123").
- Route("POST /api/v1/zones/example.com/dns-records",
- servermock.ResponseFromFixture("RecordResponse.json").
- WithStatusCode(http.StatusCreated),
- servermock.CheckRequestJSONBody(`{"name":"string","type":"string","ttl":3600,"contents":[{"text":"string"}]}`),
- servermock.CheckQueryParameter().Strict().With("teamID", "123"),
- ).
- Build(t)
-
- data := Record{
- Type: "string",
- Name: "string",
- Contents: []Content{
- {
- Text: "string",
- },
- },
- TTL: 3600,
- }
-
- record, err := client.CreateRecord(t.Context(), "example.com", data)
- require.NoError(t, err)
-
- expected := &Record{
- ID: "string",
- Type: "string",
- Name: "string",
- Contents: []Content{
- {
- Text: "string",
- },
- },
- TTL: 3600,
- }
-
- assert.Equal(t, expected, record)
-}
-
func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder("").
+ client := mockBuilder().
Route("DELETE /api/v1/zones/example.com/dns-records/123",
servermock.Noop().
WithStatusCode(http.StatusNoContent)).
@@ -159,7 +120,7 @@ func TestClient_DeleteRecord(t *testing.T) {
}
func TestClient_DeleteRecord_NotFound_Response(t *testing.T) {
- client := mockBuilder("").
+ client := mockBuilder().
Route("DELETE /api/v1/zones/example.com/dns-records/123",
servermock.Noop().
WithStatusCode(http.StatusNotFound)).
@@ -170,7 +131,7 @@ func TestClient_DeleteRecord_NotFound_Response(t *testing.T) {
}
func TestClient_DeleteRecord_error(t *testing.T) {
- client := mockBuilder("").
+ client := mockBuilder().
Route("DELETE /api/v1/zones/example.com/dns-records/123",
servermock.ResponseFromFixture("error.json").
WithStatusCode(http.StatusUnauthorized)).
diff --git a/providers/dns/liara/liara.go b/providers/dns/liara/liara.go
index c7e403eed..a0437b0eb 100644
--- a/providers/dns/liara/liara.go
+++ b/providers/dns/liara/liara.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/liara/internal"
"github.com/hashicorp/go-retryablehttp"
)
@@ -23,7 +22,6 @@ const (
envNamespace = "LIARA_"
EnvAPIKey = envNamespace + "API_KEY"
- EnvTeamID = envNamespace + "TEAM_ID"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@@ -40,9 +38,7 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- APIKey string
- TeamID string
-
+ APIKey string
TTL int
PropagationTimeout time.Duration
PollingInterval time.Duration
@@ -80,7 +76,6 @@ func NewDNSProvider() (*DNSProvider, error) {
config := NewDefaultConfig()
config.APIKey = values[EnvAPIKey]
- config.TeamID = env.GetOrFile(EnvTeamID)
return NewDNSProviderConfig(config)
}
@@ -104,20 +99,13 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}
retryClient := retryablehttp.NewClient()
-
retryClient.RetryMax = 5
if config.HTTPClient != nil {
retryClient.HTTPClient = config.HTTPClient
}
-
retryClient.Logger = log.Logger
- client := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(retryClient.StandardClient(), config.APIKey),
- ),
- config.TeamID,
- )
+ client := internal.NewClient(internal.OAuthStaticAccessToken(retryClient.StandardClient(), config.APIKey))
return &DNSProvider{
config: config,
@@ -152,7 +140,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
Contents: []internal.Content{{Text: info.Value}},
TTL: d.config.TTL,
}
-
newRecord, err := d.client.CreateRecord(context.Background(), dns01.UnFqdn(authZone), record)
if err != nil {
return fmt.Errorf("liara: failed to create TXT record, fqdn=%s: %w", info.EffectiveFQDN, err)
@@ -178,7 +165,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("liara: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
diff --git a/providers/dns/liara/liara.toml b/providers/dns/liara/liara.toml
index f471de04e..1259999a2 100644
--- a/providers/dns/liara/liara.toml
+++ b/providers/dns/liara/liara.toml
@@ -6,14 +6,13 @@ Since = "v4.10.0"
Example = '''
LIARA_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns liara -d '*.example.com' -d example.com run
+lego --email you@example.com --dns liara -d '*.example.com' -d example.com run
'''
[Configuration]
[Configuration.Credentials]
LIARA_API_KEY = "The API key"
[Configuration.Additional]
- LIARA_TEAM_ID = "The team ID to access services in a team"
LIARA_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
LIARA_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
LIARA_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 3600)"
diff --git a/providers/dns/liara/liara_test.go b/providers/dns/liara/liara_test.go
index b1f3f77c9..4256be55e 100644
--- a/providers/dns/liara/liara_test.go
+++ b/providers/dns/liara/liara_test.go
@@ -38,7 +38,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -114,7 +113,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -128,7 +126,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/lightsail/lightsail.go b/providers/dns/lightsail/lightsail.go
index 95b07c503..ddaf7baca 100644
--- a/providers/dns/lightsail/lightsail.go
+++ b/providers/dns/lightsail/lightsail.go
@@ -99,7 +99,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
retryCount := min(attempt, 7)
delay := (1 << uint(retryCount)) * (rand.Intn(50) + 200)
-
return time.Duration(delay) * time.Millisecond, nil
})
})
diff --git a/providers/dns/lightsail/lightsail_integration_test.go b/providers/dns/lightsail/lightsail_integration_test.go
index dc86bf079..718e57460 100644
--- a/providers/dns/lightsail/lightsail_integration_test.go
+++ b/providers/dns/lightsail/lightsail_integration_test.go
@@ -34,7 +34,6 @@ func TestLiveTTL(t *testing.T) {
require.NoError(t, err)
svc := lightsail.NewFromConfig(cfg)
-
require.NoError(t, err)
defer func() {
diff --git a/providers/dns/lightsail/lightsail_test.go b/providers/dns/lightsail/lightsail_test.go
index a6b46045e..010e794a9 100644
--- a/providers/dns/lightsail/lightsail_test.go
+++ b/providers/dns/lightsail/lightsail_test.go
@@ -34,7 +34,6 @@ var envTest = tester.NewEnvTest(
func TestCredentialsFromEnv(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
_ = os.Setenv(envAwsAccessKeyID, "123")
@@ -61,7 +60,6 @@ func TestDNSProvider_Present(t *testing.T) {
func(server *httptest.Server) (*DNSProvider, error) {
return &DNSProvider{
client: lightsail.NewFromConfig(aws.Config{
- HTTPClient: server.Client(),
Credentials: credentials.NewStaticCredentialsProvider("abc", "123", " "),
Region: "mock-region",
BaseEndpoint: aws.String(server.URL),
@@ -77,5 +75,5 @@ func TestDNSProvider_Present(t *testing.T) {
keyAuth := "123456d=="
err := provider.Present(domain, "", keyAuth)
- require.NoError(t, err)
+ require.NoError(t, err, "Expected Present to return no error")
}
diff --git a/providers/dns/limacity/internal/client.go b/providers/dns/limacity/internal/client.go
index ae6ab87eb..07622e121 100644
--- a/providers/dns/limacity/internal/client.go
+++ b/providers/dns/limacity/internal/client.go
@@ -41,7 +41,6 @@ func (c *Client) GetDomains(ctx context.Context) ([]Domain, error) {
}
var results DomainsResponse
-
err = c.do(req, &results)
if err != nil {
return nil, err
@@ -59,7 +58,6 @@ func (c *Client) GetRecords(ctx context.Context, domainID int) ([]Record, error)
}
var results RecordsResponse
-
err = c.do(req, &results)
if err != nil {
return nil, err
@@ -77,7 +75,6 @@ func (c *Client) AddRecord(ctx context.Context, domainID int, record Record) err
}
var results APIResponse
-
err = c.do(req, &results)
if err != nil {
return err
@@ -95,7 +92,6 @@ func (c *Client) UpdateRecord(ctx context.Context, domainID, recordID int, recor
}
var results APIResponse
-
err = c.do(req, &results)
if err != nil {
return err
@@ -114,7 +110,6 @@ func (c *Client) DeleteRecord(ctx context.Context, domainID, recordID int) error
}
var results APIResponse
-
err = c.do(req, &results)
if err != nil {
return err
@@ -182,7 +177,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var errAPI APIResponse
-
err := json.Unmarshal(raw, &errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/limacity/internal/types.go b/providers/dns/limacity/internal/types.go
index 7411632ea..5fdbacef9 100644
--- a/providers/dns/limacity/internal/types.go
+++ b/providers/dns/limacity/internal/types.go
@@ -10,7 +10,7 @@ type RecordsResponse struct {
}
type NameserverRecordPayload struct {
- Data Record `json:"nameserver_record"`
+ Data Record `json:"nameserver_record,omitempty"`
}
type DomainsResponse struct {
diff --git a/providers/dns/limacity/limacity.go b/providers/dns/limacity/limacity.go
index 3291faf66..58755aabe 100644
--- a/providers/dns/limacity/limacity.go
+++ b/providers/dns/limacity/limacity.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/limacity/internal"
)
@@ -90,12 +89,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client := internal.NewClient(config.APIKey)
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -117,11 +110,9 @@ func (d *DNSProvider) Sequential() time.Duration {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- domains, err := d.client.GetDomains(ctx)
+ domains, err := d.client.GetDomains(context.Background())
if err != nil {
return fmt.Errorf("limacity: get domains: %w", err)
}
@@ -143,7 +134,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
Type: "TXT",
}
- err = d.client.AddRecord(ctx, dom.ID, record)
+ err = d.client.AddRecord(context.Background(), dom.ID, record)
if err != nil {
return fmt.Errorf("limacity: add record: %w", err)
}
@@ -157,26 +148,22 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the TXT record.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
// gets the domain's unique ID
d.domainIDsMu.Lock()
domainID, ok := d.domainIDs[token]
d.domainIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("limacity: unknown domain ID for '%s' '%s'", info.EffectiveFQDN, token)
}
- records, err := d.client.GetRecords(ctx, domainID)
+ records, err := d.client.GetRecords(context.Background(), domainID)
if err != nil {
return fmt.Errorf("limacity: get records: %w", err)
}
var recordID int
-
for _, record := range records {
if record.Type == "TXT" && record.Content == strconv.Quote(info.Value) {
recordID = record.ID
@@ -188,15 +175,11 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return errors.New("limacity: TXT record not found")
}
- err = d.client.DeleteRecord(ctx, domainID, recordID)
+ err = d.client.DeleteRecord(context.Background(), domainID, recordID)
if err != nil {
return fmt.Errorf("limacity: delete record (domain ID=%d, record ID=%d): %w", domainID, recordID, err)
}
- d.domainIDsMu.Lock()
- delete(d.domainIDs, info.EffectiveFQDN)
- d.domainIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/limacity/limacity.toml b/providers/dns/limacity/limacity.toml
index d236577d0..b9b9f0018 100644
--- a/providers/dns/limacity/limacity.toml
+++ b/providers/dns/limacity/limacity.toml
@@ -6,7 +6,7 @@ Since = "v4.18.0"
Example = '''
LIMACITY_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns limacity -d '*.example.com' -d example.com run
+lego --email you@example.com --dns limacity -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/limacity/limacity_test.go b/providers/dns/limacity/limacity_test.go
index 3301fcb2e..2834a5f1f 100644
--- a/providers/dns/limacity/limacity_test.go
+++ b/providers/dns/limacity/limacity_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -93,7 +92,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -107,7 +105,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/linode/linode.go b/providers/dns/linode/linode.go
index b03dee4f5..25e1b07d1 100644
--- a/providers/dns/linode/linode.go
+++ b/providers/dns/linode/linode.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
"github.com/linode/linodego"
"golang.org/x/oauth2"
@@ -103,7 +102,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
},
}
- client := linodego.NewClient(clientdebug.Wrap(oauth2Client))
+ client := linodego.NewClient(oauth2Client)
client.SetUserAgent(useragent.Get())
return &DNSProvider{config: config, client: &client}, nil
@@ -131,11 +130,9 @@ func (d *DNSProvider) Timeout() (time.Duration, time.Duration) {
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- zone, err := d.getHostedZoneInfo(ctx, info.EffectiveFQDN)
+ zone, err := d.getHostedZoneInfo(info.EffectiveFQDN)
if err != nil {
return err
}
@@ -147,26 +144,22 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
Type: linodego.RecordTypeTXT,
}
- _, err = d.client.CreateDomainRecord(ctx, zone.domainID, createOpts)
-
+ _, err = d.client.CreateDomainRecord(context.Background(), zone.domainID, createOpts)
return err
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- zone, err := d.getHostedZoneInfo(ctx, info.EffectiveFQDN)
+ zone, err := d.getHostedZoneInfo(info.EffectiveFQDN)
if err != nil {
return err
}
// Get all TXT records for the specified domain.
listOpts := linodego.NewListOptions(0, `{"type":"TXT"}`)
-
- resources, err := d.client.ListDomainRecords(ctx, zone.domainID, listOpts)
+ resources, err := d.client.ListDomainRecords(context.Background(), zone.domainID, listOpts)
if err != nil {
return err
}
@@ -175,7 +168,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
for _, resource := range resources {
if (resource.Name == dns01.UnFqdn(info.EffectiveFQDN) || resource.Name == zone.resourceName) &&
resource.Target == info.Value {
- if err := d.client.DeleteDomainRecord(ctx, zone.domainID, resource.ID); err != nil {
+ if err := d.client.DeleteDomainRecord(context.Background(), zone.domainID, resource.ID); err != nil {
return err
}
}
@@ -184,7 +177,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return nil
}
-func (d *DNSProvider) getHostedZoneInfo(ctx context.Context, fqdn string) (*hostedZoneInfo, error) {
+func (d *DNSProvider) getHostedZoneInfo(fqdn string) (*hostedZoneInfo, error) {
// Lookup the zone that handles the specified FQDN.
authZone, err := dns01.FindZoneByFqdn(fqdn)
if err != nil {
@@ -198,8 +191,7 @@ func (d *DNSProvider) getHostedZoneInfo(ctx context.Context, fqdn string) (*host
}
listOpts := linodego.NewListOptions(0, string(filter))
-
- domains, err := d.client.ListDomains(ctx, listOpts)
+ domains, err := d.client.ListDomains(context.Background(), listOpts)
if err != nil {
return nil, err
}
diff --git a/providers/dns/linode/linode.toml b/providers/dns/linode/linode.toml
index 9ea30b92b..f046d3f9b 100644
--- a/providers/dns/linode/linode.toml
+++ b/providers/dns/linode/linode.toml
@@ -7,7 +7,7 @@ Since = "v1.1.0"
Example = '''
LINODE_TOKEN=xxxxx \
-lego --dns linode -d '*.example.com' -d example.com run
+lego --email you@example.com --dns linode -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/linode/linode_test.go b/providers/dns/linode/linode_test.go
index 1c4903aca..08549ab7e 100644
--- a/providers/dns/linode/linode_test.go
+++ b/providers/dns/linode/linode_test.go
@@ -39,7 +39,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -95,7 +94,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
func TestDNSProvider_Present(t *testing.T) {
defer envTest.RestoreEnv()
-
os.Setenv(EnvToken, "testing")
domain := "example.com"
@@ -180,7 +178,6 @@ func TestDNSProvider_Present(t *testing.T) {
func TestDNSProvider_CleanUp(t *testing.T) {
defer envTest.RestoreEnv()
-
os.Setenv(EnvToken, "testing")
domain := "example.com"
diff --git a/providers/dns/liquidweb/liquidweb.go b/providers/dns/liquidweb/liquidweb.go
index 6e93e2a12..2d0a46142 100644
--- a/providers/dns/liquidweb/liquidweb.go
+++ b/providers/dns/liquidweb/liquidweb.go
@@ -62,9 +62,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- config *Config
- client *lw.API
-
+ config *Config
+ client *lw.API
recordIDs map[string]int
recordIDsMu sync.Mutex
}
@@ -160,7 +159,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
params := &network.DNSRecordParams{ID: recordID}
-
_, err := d.client.NetworkDNS.Delete(params)
if err != nil {
return fmt.Errorf("liquidweb: could not remove TXT record: %w", err)
@@ -181,7 +179,6 @@ func (d *DNSProvider) findZone(domain string) (string, error) {
// filter the zones on the account to only ones that match
var zs []network.DNSZone
-
for _, item := range zones.Items {
if strings.HasSuffix(domain, item.Name) {
zs = append(zs, item)
diff --git a/providers/dns/liquidweb/liquidweb.toml b/providers/dns/liquidweb/liquidweb.toml
index 386b99cab..22789f41e 100644
--- a/providers/dns/liquidweb/liquidweb.toml
+++ b/providers/dns/liquidweb/liquidweb.toml
@@ -7,7 +7,7 @@ Since = "v3.1.0"
Example = '''
LWAPI_USERNAME=someuser \
LWAPI_PASSWORD=somepass \
-lego --dns liquidweb -d '*.example.com' -d example.com run
+lego --email you@example.com --dns liquidweb -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/liquidweb/liquidweb_test.go b/providers/dns/liquidweb/liquidweb_test.go
index a34d19037..b0788c7f5 100644
--- a/providers/dns/liquidweb/liquidweb_test.go
+++ b/providers/dns/liquidweb/liquidweb_test.go
@@ -27,16 +27,16 @@ func TestNewDNSProvider(t *testing.T) {
{
desc: "minimum-success",
envVars: map[string]string{
- EnvUsername: "user",
- EnvPassword: "secret",
+ EnvUsername: "blars",
+ EnvPassword: "tacoman",
},
},
{
desc: "set-everything",
envVars: map[string]string{
- EnvURL: "https://storm.example",
- EnvUsername: "user",
- EnvPassword: "secret",
+ EnvURL: "https://storm.com",
+ EnvUsername: "blars",
+ EnvPassword: "tacoman",
EnvZone: "blars.com",
},
},
@@ -48,16 +48,16 @@ func TestNewDNSProvider(t *testing.T) {
{
desc: "missing username",
envVars: map[string]string{
- EnvPassword: "secret",
- EnvZone: "blars.example",
+ EnvPassword: "tacoman",
+ EnvZone: "blars.com",
},
expected: "liquidweb: some credentials information are missing: LIQUID_WEB_USERNAME",
},
{
desc: "missing password",
envVars: map[string]string{
- EnvUsername: "user",
- EnvZone: "blars.example",
+ EnvUsername: "blars",
+ EnvZone: "blars.com",
},
expected: "liquidweb: some credentials information are missing: LIQUID_WEB_PASSWORD",
},
@@ -66,7 +66,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -148,13 +147,13 @@ func TestNewDNSProviderConfig(t *testing.T) {
func TestDNSProvider_Present(t *testing.T) {
provider := mockProvider(t)
- err := provider.Present("tacoman.example", "", "")
+ err := provider.Present("tacoman.com", "", "")
require.NoError(t, err)
}
func TestDNSProvider_CleanUp(t *testing.T) {
provider := mockProvider(t, network.DNSRecord{
- Name: "_acme-challenge.tacoman.example",
+ Name: "_acme-challenge.tacoman.com",
RData: "123d==",
Type: "TXT",
TTL: 300,
@@ -164,7 +163,7 @@ func TestDNSProvider_CleanUp(t *testing.T) {
provider.recordIDs["123d=="] = 1234567
- err := provider.CleanUp("tacoman.example.", "123d==", "")
+ err := provider.CleanUp("tacoman.com.", "123d==", "")
require.NoError(t, err)
}
@@ -181,7 +180,7 @@ func TestDNSProvider(t *testing.T) {
}{
{
desc: "expected successful",
- domain: "tacoman.example",
+ domain: "tacoman.com",
token: "123",
keyAuth: "456",
present: true,
@@ -189,7 +188,7 @@ func TestDNSProvider(t *testing.T) {
},
{
desc: "other successful",
- domain: "banana.example",
+ domain: "banana.com",
token: "123",
keyAuth: "456",
present: true,
@@ -197,16 +196,16 @@ func TestDNSProvider(t *testing.T) {
},
{
desc: "zone not on account",
- domain: "huckleberry.example",
+ domain: "huckleberry.com",
token: "123",
keyAuth: "456",
present: true,
- expPresentErr: "no valid zone in account for certificate '_acme-challenge.huckleberry.example'",
+ expPresentErr: "no valid zone in account for certificate '_acme-challenge.huckleberry.com'",
cleanup: false,
},
{
desc: "ssl for domain",
- domain: "sundae.cherry.example",
+ domain: "sundae.cherry.com",
token: "5847953",
keyAuth: "34872934",
present: true,
@@ -214,7 +213,7 @@ func TestDNSProvider(t *testing.T) {
},
{
desc: "complicated domain",
- domain: "always.money.stand.banana.example",
+ domain: "always.money.stand.banana.com",
token: "5847953",
keyAuth: "there is always money in the banana stand",
present: true,
@@ -249,7 +248,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/liquidweb/servermock_test.go b/providers/dns/liquidweb/servermock_test.go
index 4886e17f1..9cb434761 100644
--- a/providers/dns/liquidweb/servermock_test.go
+++ b/providers/dns/liquidweb/servermock_test.go
@@ -26,14 +26,14 @@ func mockProvider(t *testing.T, initRecs ...network.DNSRecord) *DNSProvider {
return servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.Username = "user"
- config.Password = "secret"
+ config.Username = "blars"
+ config.Password = "tacoman"
config.BaseURL = server.URL
return NewDNSProviderConfig(config)
},
servermock.CheckHeader().
- WithBasicAuth("user", "secret"),
+ WithBasicAuth("blars", "tacoman"),
).
Route("/v1/Network/DNS/Record/delete", mockAPIDelete(recs)).
Route("/v1/Network/DNS/Record/create", mockAPICreate(recs)).
@@ -62,7 +62,6 @@ func mockAPICreate(recs map[int]network.DNSRecord) http.HandlerFunc {
http.Error(rw, makeEncodingError(body), http.StatusBadRequest)
return
}
-
payload.Params.ID = types.FlexInt(rand.Intn(10000000))
payload.Params.ZoneID = types.FlexInt(mockAPIServerZones[payload.Params.Name])
@@ -70,7 +69,6 @@ func mockAPICreate(recs map[int]network.DNSRecord) http.HandlerFunc {
http.Error(rw, "dns record already exists", http.StatusTeapot)
return
}
-
recs[int(payload.Params.ID)] = payload.Params
resp, err := json.Marshal(payload.Params)
@@ -78,7 +76,6 @@ func mockAPICreate(recs map[int]network.DNSRecord) http.HandlerFunc {
http.Error(rw, "", http.StatusInternalServerError)
return
}
-
http.Error(rw, string(resp), http.StatusOK)
}
}
@@ -112,7 +109,6 @@ func mockAPIDelete(recs map[int]network.DNSRecord) http.HandlerFunc {
http.Error(rw, fmt.Sprintf(`{"error":"","error_class":"LW::Exception::RecordNotFound","field":"network_dns_rr","full_message":"Record 'network_dns_rr: %d' not found","input":"%d","public_message":null}`, payload.Params.ID, payload.Params.ID), http.StatusOK)
return
}
-
delete(recs, payload.Params.ID)
http.Error(rw, fmt.Sprintf("{\"deleted\":%d}", payload.Params.ID), http.StatusOK)
}
@@ -145,7 +141,6 @@ func mockAPIListZones() http.HandlerFunc {
case payload.Params.PageNum > len(mockZones):
payload.Params.PageNum = len(mockZones)
}
-
resp := mockZones[payload.Params.PageNum]
resp.ItemTotal = types.FlexInt(len(mockAPIServerZones))
resp.PageNum = types.FlexInt(payload.Params.PageNum)
@@ -172,38 +167,38 @@ func makeMockZones() (map[int]network.DNSZoneList, map[string]int) {
Items: []network.DNSZone{
{
ID: 1,
- Name: "blars.example",
+ Name: "blars.com",
Active: 1,
DelegationStatus: "CORRECT",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 2,
- Name: "tacoman.example",
+ Name: "tacoman.com",
Active: 1,
DelegationStatus: "CORRECT",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 3,
- Name: "storm.example",
+ Name: "storm.com",
Active: 1,
DelegationStatus: "CORRECT",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 4,
- Name: "not-apple.example",
+ Name: "not-apple.com",
Active: 1,
DelegationStatus: "BAD_NAMESERVERS",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 5,
Name: "example.com",
Active: 1,
DelegationStatus: "BAD_NAMESERVERS",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
},
},
@@ -211,38 +206,38 @@ func makeMockZones() (map[int]network.DNSZoneList, map[string]int) {
Items: []network.DNSZone{
{
ID: 6,
- Name: "banana.example",
+ Name: "banana.com",
Active: 1,
DelegationStatus: "NXDOMAIN",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 7,
- Name: "cherry.example",
+ Name: "cherry.com",
Active: 1,
DelegationStatus: "SERVFAIL",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 8,
- Name: "dates.example",
+ Name: "dates.com",
Active: 1,
DelegationStatus: "SERVFAIL",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 9,
- Name: "eggplant.example",
+ Name: "eggplant.com",
Active: 1,
DelegationStatus: "SERVFAIL",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 10,
- Name: "fig.example",
+ Name: "fig.com",
Active: 1,
DelegationStatus: "UNKNOWN",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
},
},
@@ -250,43 +245,41 @@ func makeMockZones() (map[int]network.DNSZoneList, map[string]int) {
Items: []network.DNSZone{
{
ID: 11,
- Name: "grapes.example",
+ Name: "grapes.com",
Active: 1,
DelegationStatus: "UNKNOWN",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 12,
- Name: "money.banana.example",
+ Name: "money.banana.com",
Active: 1,
DelegationStatus: "UNKNOWN",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 13,
- Name: "money.stand.banana.example",
+ Name: "money.stand.banana.com",
Active: 1,
DelegationStatus: "UNKNOWN",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
{
ID: 14,
- Name: "stand.banana.example",
+ Name: "stand.banana.com",
Active: 1,
DelegationStatus: "UNKNOWN",
- PrimaryNameserver: "ns.example.org",
+ PrimaryNameserver: "ns.liquidweb.com",
},
},
},
}
mockAPIServerZones := make(map[string]int)
-
for _, page := range mockZones {
for _, zone := range page.Items {
mockAPIServerZones[zone.Name] = int(zone.ID)
}
}
-
return mockZones, mockAPIServerZones
}
diff --git a/providers/dns/loopia/internal/client_test.go b/providers/dns/loopia/internal/client_test.go
index fed7d94f1..63962b06e 100644
--- a/providers/dns/loopia/internal/client_test.go
+++ b/providers/dns/loopia/internal/client_test.go
@@ -15,7 +15,6 @@ func mockBuilder(password string) *servermock.Builder[*Client] {
return servermock.NewBuilder[*Client](
func(server *httptest.Server) (*Client, error) {
client := NewClient("apiuser", password)
- client.HTTPClient = server.Client()
client.BaseURL = server.URL + "/"
return client, nil
diff --git a/providers/dns/loopia/internal/types.go b/providers/dns/loopia/internal/types.go
index c3425c8b1..c286c01fd 100644
--- a/providers/dns/loopia/internal/types.go
+++ b/providers/dns/loopia/internal/types.go
@@ -66,7 +66,6 @@ type response interface {
type responseString struct {
responseFault
-
Value string `xml:"params>param>value>string"`
}
@@ -89,7 +88,6 @@ func (e RPCError) Error() string {
type recordObjectsResponse struct {
responseFault
-
XMLName xml.Name `xml:"methodResponse"`
Params []RecordObj `xml:"params>param>value>array>data>value>struct"`
}
@@ -104,7 +102,6 @@ type RecordObj struct {
func (r *RecordObj) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var name string
-
for {
t, err := d.Token()
if err != nil {
@@ -147,7 +144,6 @@ func (r *RecordObj) decodeValueString(name string, d *xml.Decoder, start xml.Sta
}
s = strings.TrimSpace(s)
-
switch name {
case "type":
r.Type = s
diff --git a/providers/dns/loopia/loopia.go b/providers/dns/loopia/loopia.go
index be3416ddf..8389ae5f6 100644
--- a/providers/dns/loopia/loopia.go
+++ b/providers/dns/loopia/loopia.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/loopia/internal"
)
@@ -114,8 +113,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
if config.BaseURL != "" {
client.BaseURL = config.BaseURL
}
diff --git a/providers/dns/loopia/loopia.toml b/providers/dns/loopia/loopia.toml
index a201852c9..4a127ec55 100644
--- a/providers/dns/loopia/loopia.toml
+++ b/providers/dns/loopia/loopia.toml
@@ -7,7 +7,7 @@ Since = "v4.2.0"
Example = '''
LOOPIA_API_USER=xxxxxxxx \
LOOPIA_API_PASSWORD=yyyyyyyy \
-lego --dns loopia -d '*.example.com' -d example.com run
+lego --email you@example.com --dns loopia -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/loopia/loopia_test.go b/providers/dns/loopia/loopia_test.go
index b3163fc77..e397c9639 100644
--- a/providers/dns/loopia/loopia_test.go
+++ b/providers/dns/loopia/loopia_test.go
@@ -103,7 +103,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -193,7 +192,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -207,7 +205,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/luadns/internal/client.go b/providers/dns/luadns/internal/client.go
index 5ce9cca86..8e46418f2 100644
--- a/providers/dns/luadns/internal/client.go
+++ b/providers/dns/luadns/internal/client.go
@@ -49,7 +49,6 @@ func (c *Client) ListZones(ctx context.Context) ([]DNSZone, error) {
}
var zones []DNSZone
-
err = c.do(req, &zones)
if err != nil {
return nil, fmt.Errorf("could not list zones: %w", err)
@@ -69,7 +68,6 @@ func (c *Client) CreateRecord(ctx context.Context, zone DNSZone, newRecord DNSRe
}
var record *DNSRecord
-
err = c.do(req, &record)
if err != nil {
return nil, fmt.Errorf("could not create record %#v: %w", record, err)
@@ -155,7 +153,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var errResp errorResponse
-
err := json.Unmarshal(raw, &errResp)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/luadns/luadns.go b/providers/dns/luadns/luadns.go
index 68b9c66b8..026a0da70 100644
--- a/providers/dns/luadns/luadns.go
+++ b/providers/dns/luadns/luadns.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/luadns/internal"
)
@@ -101,12 +100,11 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
- config: config,
- client: client,
- records: make(map[string]*internal.DNSRecord),
+ config: config,
+ client: client,
+ recordsMu: sync.Mutex{},
+ records: make(map[string]*internal.DNSRecord),
}, nil
}
diff --git a/providers/dns/luadns/luadns.toml b/providers/dns/luadns/luadns.toml
index e56fac0b6..c80929c21 100644
--- a/providers/dns/luadns/luadns.toml
+++ b/providers/dns/luadns/luadns.toml
@@ -7,7 +7,7 @@ Since = "v3.7.0"
Example = '''
LUADNS_API_USERNAME=youremail \
LUADNS_API_TOKEN=xxxxxxxx \
-lego --dns luadns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns luadns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/luadns/luadns_test.go b/providers/dns/luadns/luadns_test.go
index a1aa36872..ea4d06ae1 100644
--- a/providers/dns/luadns/luadns_test.go
+++ b/providers/dns/luadns/luadns_test.go
@@ -58,7 +58,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -200,7 +199,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -214,7 +212,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/mailinabox/mailinabox.go b/providers/dns/mailinabox/mailinabox.go
index cf6202a92..3ea8a9f29 100644
--- a/providers/dns/mailinabox/mailinabox.go
+++ b/providers/dns/mailinabox/mailinabox.go
@@ -5,13 +5,11 @@ import (
"context"
"errors"
"fmt"
- "net/http"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/nrdcg/mailinabox"
)
@@ -25,7 +23,6 @@ const (
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
@@ -37,7 +34,6 @@ type Config struct {
BaseURL string
PropagationTimeout time.Duration
PollingInterval time.Duration
- HTTPClient *http.Client
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
@@ -45,9 +41,6 @@ func NewDefaultConfig() *Config {
return &Config{
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 4*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
}
}
@@ -88,13 +81,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("mailinabox: missing base URL")
}
- if config.HTTPClient == nil {
- config.HTTPClient = &http.Client{Timeout: 30 * time.Second}
- }
-
- config.HTTPClient = clientdebug.Wrap(config.HTTPClient)
-
- client, err := mailinabox.New(config.BaseURL, config.Email, config.Password, mailinabox.WithHTTPClient(config.HTTPClient))
+ client, err := mailinabox.New(config.BaseURL, config.Email, config.Password)
if err != nil {
return nil, fmt.Errorf("mailinabox: %w", err)
}
diff --git a/providers/dns/mailinabox/mailinabox.toml b/providers/dns/mailinabox/mailinabox.toml
index 74d8aabbc..4b30dd9e2 100644
--- a/providers/dns/mailinabox/mailinabox.toml
+++ b/providers/dns/mailinabox/mailinabox.toml
@@ -8,7 +8,7 @@ Example = '''
MAILINABOX_EMAIL=user@example.com \
MAILINABOX_PASSWORD=yyyy \
MAILINABOX_BASE_URL=https://box.example.com \
-lego --dns mailinabox -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mailinabox -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -19,7 +19,6 @@ lego --dns mailinabox -d '*.example.com' -d example.com run
[Configuration.Additional]
MAILINABOX_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 4)"
MAILINABOX_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
- MAILINABOX_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
[Links]
API = "https://mailinabox.email/api-docs.html"
diff --git a/providers/dns/mailinabox/mailinabox_test.go b/providers/dns/mailinabox/mailinabox_test.go
index 11143a11f..1b95c220d 100644
--- a/providers/dns/mailinabox/mailinabox_test.go
+++ b/providers/dns/mailinabox/mailinabox_test.go
@@ -59,7 +59,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -137,7 +136,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -151,7 +149,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/manageengine/internal/client.go b/providers/dns/manageengine/internal/client.go
index b5a7dbae7..b360840f0 100644
--- a/providers/dns/manageengine/internal/client.go
+++ b/providers/dns/manageengine/internal/client.go
@@ -24,12 +24,12 @@ type Client struct {
}
// NewClient creates a new Client.
-func NewClient(hc *http.Client) *Client {
+func NewClient(ctx context.Context, clientID, clientSecret string) *Client {
baseURL, _ := url.Parse(defaultBaseURL)
return &Client{
baseURL: baseURL,
- httpClient: hc,
+ httpClient: createOAuthClient(ctx, clientID, clientSecret),
}
}
@@ -109,7 +109,6 @@ func (c *Client) UpdateZoneRecord(ctx context.Context, record ZoneRecord) error
if record.SpfTxtDomainID == 0 {
return errors.New("SpfTxtDomainID is empty")
}
-
if record.ZoneID == 0 {
return errors.New("ZoneID is empty")
}
@@ -189,7 +188,6 @@ 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)
diff --git a/providers/dns/manageengine/internal/client_test.go b/providers/dns/manageengine/internal/client_test.go
index 25d1730f6..0c18a245f 100644
--- a/providers/dns/manageengine/internal/client_test.go
+++ b/providers/dns/manageengine/internal/client_test.go
@@ -1,6 +1,7 @@
package internal
import (
+ "context"
"net/http"
"net/http/httptest"
"net/url"
@@ -14,8 +15,9 @@ import (
func mockBuilder() *servermock.Builder[*Client] {
return servermock.NewBuilder[*Client](
func(server *httptest.Server) (*Client, error) {
- client := NewClient(server.Client())
+ client := NewClient(context.Background(), "abc", "secret")
+ client.httpClient = server.Client()
client.baseURL, _ = url.Parse(server.URL)
return client, nil
diff --git a/providers/dns/manageengine/internal/identity.go b/providers/dns/manageengine/internal/identity.go
index ec28121e4..66a659188 100644
--- a/providers/dns/manageengine/internal/identity.go
+++ b/providers/dns/manageengine/internal/identity.go
@@ -9,7 +9,7 @@ import (
const defaultAuthURL = "https://clouddns.manageengine.com/oauth2/token/"
-func CreateOAuthClient(ctx context.Context, clientID, clientSecret string) *http.Client {
+func createOAuthClient(ctx context.Context, clientID, clientSecret string) *http.Client {
config := &clientcredentials.Config{
TokenURL: defaultAuthURL,
ClientID: clientID,
diff --git a/providers/dns/manageengine/manageengine.go b/providers/dns/manageengine/manageengine.go
index 76b6644c0..f26ae33b5 100644
--- a/providers/dns/manageengine/manageengine.go
+++ b/providers/dns/manageengine/manageengine.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/manageengine/internal"
)
@@ -76,13 +75,11 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("manageengine: credentials missing")
}
+ client := internal.NewClient(context.Background(), config.ClientID, config.ClientSecret)
+
return &DNSProvider{
config: config,
- client: internal.NewClient(
- clientdebug.Wrap(
- internal.CreateOAuthClient(context.Background(), config.ClientID, config.ClientSecret),
- ),
- ),
+ client: client,
}, nil
}
@@ -195,7 +192,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
// Update the zone record.
var values []string
-
for _, value := range record.Values {
if value != info.Value {
values = append(values, value)
diff --git a/providers/dns/manageengine/manageengine.toml b/providers/dns/manageengine/manageengine.toml
index 43a782841..7708fa74f 100644
--- a/providers/dns/manageengine/manageengine.toml
+++ b/providers/dns/manageengine/manageengine.toml
@@ -7,7 +7,7 @@ Since = "v4.21.0"
Example = '''
MANAGEENGINE_CLIENT_ID="xxx" \
MANAGEENGINE_CLIENT_SECRET="yyy" \
-lego --dns manageengine -d '*.example.com' -d example.com run
+lego --email you@example.com --dns manageengine -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/manageengine/manageengine_test.go b/providers/dns/manageengine/manageengine_test.go
index 215de68dd..624459be9 100644
--- a/providers/dns/manageengine/manageengine_test.go
+++ b/providers/dns/manageengine/manageengine_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -123,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/manual/manual.go b/providers/dns/manual/manual.go
deleted file mode 100644
index 2985bc595..000000000
--- a/providers/dns/manual/manual.go
+++ /dev/null
@@ -1,13 +0,0 @@
-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/providers/dns/metaname/metaname.go b/providers/dns/metaname/metaname.go
index d6e962024..9b8c41def 100644
--- a/providers/dns/metaname/metaname.go
+++ b/providers/dns/metaname/metaname.go
@@ -79,7 +79,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config.AccountReference == "" {
return nil, errors.New("metaname: missing account reference")
}
-
if config.APIKey == "" {
return nil, errors.New("metaname: missing api key")
}
@@ -153,10 +152,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("metaname: delete record: %w", err)
}
- d.recordsMu.Lock()
- delete(d.records, token)
- d.recordsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/metaname/metaname.toml b/providers/dns/metaname/metaname.toml
index 654dcaed0..4a147d043 100644
--- a/providers/dns/metaname/metaname.toml
+++ b/providers/dns/metaname/metaname.toml
@@ -7,7 +7,7 @@ Since = "v4.13.0"
Example = '''
METANAME_ACCOUNT_REFERENCE=xxxx \
METANAME_API_KEY=yyyyyyy \
-lego --dns metaname -d '*.example.com' -d example.com run
+lego --email you@example.com --dns metaname -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/metaname/metaname_test.go b/providers/dns/metaname/metaname_test.go
index 855fc493d..174af4014 100644
--- a/providers/dns/metaname/metaname_test.go
+++ b/providers/dns/metaname/metaname_test.go
@@ -51,7 +51,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -123,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/metaregistrar/internal/client.go b/providers/dns/metaregistrar/internal/client.go
index df99d81ba..711a1e94c 100644
--- a/providers/dns/metaregistrar/internal/client.go
+++ b/providers/dns/metaregistrar/internal/client.go
@@ -121,7 +121,6 @@ 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)
diff --git a/providers/dns/metaregistrar/metaregistrar.go b/providers/dns/metaregistrar/metaregistrar.go
index 7a601ef21..28526fcb4 100644
--- a/providers/dns/metaregistrar/metaregistrar.go
+++ b/providers/dns/metaregistrar/metaregistrar.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/metaregistrar/internal"
)
@@ -83,8 +82,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/metaregistrar/metaregistrar.toml b/providers/dns/metaregistrar/metaregistrar.toml
index e505e0ce2..952c7ea61 100644
--- a/providers/dns/metaregistrar/metaregistrar.toml
+++ b/providers/dns/metaregistrar/metaregistrar.toml
@@ -6,7 +6,7 @@ Since = "v4.23.0"
Example = '''
METAREGISTRAR_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns metaregistrar -d '*.example.com' -d example.com run
+lego --email you@example.com --dns metaregistrar -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/metaregistrar/metaregistrar_test.go b/providers/dns/metaregistrar/metaregistrar_test.go
index aa9bbbb58..ffd7965d9 100644
--- a/providers/dns/metaregistrar/metaregistrar_test.go
+++ b/providers/dns/metaregistrar/metaregistrar_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -93,7 +92,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -107,7 +105,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/mijnhost/internal/client.go b/providers/dns/mijnhost/internal/client.go
index a51233211..1a67a73b1 100644
--- a/providers/dns/mijnhost/internal/client.go
+++ b/providers/dns/mijnhost/internal/client.go
@@ -47,7 +47,6 @@ func (c *Client) ListDomains(ctx context.Context) ([]Domain, error) {
}
var results Response[DomainData]
-
err = c.do(req, &results)
if err != nil {
return nil, err
@@ -67,7 +66,6 @@ func (c *Client) GetRecords(ctx context.Context, domain string) ([]Record, error
}
var results Response[RecordData]
-
err = c.do(req, &results)
if err != nil {
return nil, err
@@ -153,7 +151,6 @@ 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)
diff --git a/providers/dns/mijnhost/mijnhost.go b/providers/dns/mijnhost/mijnhost.go
index adb3e9ce3..21aca3c9e 100644
--- a/providers/dns/mijnhost/mijnhost.go
+++ b/providers/dns/mijnhost/mijnhost.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/mijnhost/internal"
)
@@ -87,12 +86,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client := internal.NewClient(config.APIKey)
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -113,11 +106,9 @@ func (d *DNSProvider) Sequential() time.Duration {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- domains, err := d.client.ListDomains(ctx)
+ domains, err := d.client.ListDomains(context.Background())
if err != nil {
return fmt.Errorf("mijnhost: list domains: %w", err)
}
@@ -127,7 +118,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("mijnhost: find domain: %w", err)
}
- records, err := d.client.GetRecords(ctx, dom.Domain)
+ records, err := d.client.GetRecords(context.Background(), dom.Domain)
if err != nil {
return fmt.Errorf("mijnhost: get records: %w", err)
}
@@ -152,7 +143,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
cleanedRecords = append(cleanedRecords, record)
- err = d.client.UpdateRecords(ctx, dom.Domain, cleanedRecords)
+ err = d.client.UpdateRecords(context.Background(), dom.Domain, cleanedRecords)
if err != nil {
return fmt.Errorf("mijnhost: update records: %w", err)
}
@@ -162,11 +153,9 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the TXT record.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- domains, err := d.client.ListDomains(ctx)
+ domains, err := d.client.ListDomains(context.Background())
if err != nil {
return fmt.Errorf("mijnhost: list domains: %w", err)
}
@@ -176,7 +165,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("mijnhost: find domain: %w", err)
}
- records, err := d.client.GetRecords(ctx, dom.Domain)
+ records, err := d.client.GetRecords(context.Background(), dom.Domain)
if err != nil {
return fmt.Errorf("mijnhost: get records: %w", err)
}
@@ -185,7 +174,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return record.Type == txtType && record.Value == info.Value
})
- err = d.client.UpdateRecords(ctx, dom.Domain, cleanedRecords)
+ err = d.client.UpdateRecords(context.Background(), dom.Domain, cleanedRecords)
if err != nil {
return fmt.Errorf("mijnhost: update records: %w", err)
}
diff --git a/providers/dns/mijnhost/mijnhost.toml b/providers/dns/mijnhost/mijnhost.toml
index 416fdde53..00152e132 100644
--- a/providers/dns/mijnhost/mijnhost.toml
+++ b/providers/dns/mijnhost/mijnhost.toml
@@ -6,7 +6,7 @@ Since = "v4.18.0"
Example = '''
MIJNHOST_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns mijnhost -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mijnhost -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/mijnhost/mijnhost_test.go b/providers/dns/mijnhost/mijnhost_test.go
index c87ae0a40..a48f84ca8 100644
--- a/providers/dns/mijnhost/mijnhost_test.go
+++ b/providers/dns/mijnhost/mijnhost_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -95,7 +94,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -109,7 +107,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/mittwald/internal/client.go b/providers/dns/mittwald/internal/client.go
index 2b1564dc1..69222903d 100644
--- a/providers/dns/mittwald/internal/client.go
+++ b/providers/dns/mittwald/internal/client.go
@@ -47,7 +47,6 @@ func (c *Client) ListDomains(ctx context.Context) ([]Domain, error) {
}
var result []Domain
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -67,7 +66,6 @@ func (c *Client) GetDNSZone(ctx context.Context, zoneID string) (*DNSZone, error
}
result := &DNSZone{}
-
err = c.do(req, result)
if err != nil {
return nil, err
@@ -87,7 +85,6 @@ func (c *Client) ListDNSZones(ctx context.Context, projectID string) ([]DNSZone,
}
var result []DNSZone
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -107,7 +104,6 @@ func (c *Client) CreateDNSZone(ctx context.Context, zone CreateDNSZoneRequest) (
}
result := &DNSZone{}
-
err = c.do(req, result)
if err != nil {
return nil, err
@@ -201,7 +197,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var response APIError
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/mittwald/internal/types.go b/providers/dns/mittwald/internal/types.go
index 86cdf065c..df10ab293 100644
--- a/providers/dns/mittwald/internal/types.go
+++ b/providers/dns/mittwald/internal/types.go
@@ -1,9 +1,6 @@
package internal
-import (
- "fmt"
- "strings"
-)
+import "fmt"
// https://api.mittwald.de/v2/docs/#/Domain/domain-list-domains
@@ -39,7 +36,7 @@ type NewDNSZone struct {
// https://api.mittwald.de/v2/docs/#/Domain/dns-update-record-set
type TXTRecord struct {
- Settings Settings `json:"settings"`
+ Settings Settings `json:"settings,omitempty"`
Entries []string `json:"entries,omitempty"`
}
@@ -61,25 +58,23 @@ type APIError struct {
}
func (a APIError) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "%s: %s", a.Type, a.Message)
+ msg := fmt.Sprintf("%s: %s", a.Type, a.Message)
if len(a.ValidationErrors) > 0 {
for _, validationError := range a.ValidationErrors {
- _, _ = fmt.Fprintf(msg, " [%s: %s (%s, %s)]",
+ msg += fmt.Sprintf(" [%s: %s (%s, %s)]",
validationError.Type, validationError.Message, validationError.Path, validationError.Context.Format)
}
}
- return msg.String()
+ return msg
}
type ValidationError struct {
Message string `json:"message,omitempty"`
Path string `json:"path,omitempty"`
Type string `json:"type,omitempty"`
- Context ValidationErrorContext `json:"context"`
+ Context ValidationErrorContext `json:"context,omitempty"`
}
type ValidationErrorContext struct {
diff --git a/providers/dns/mittwald/mittwald.go b/providers/dns/mittwald/mittwald.go
index dcd882482..2c3c5a8f3 100644
--- a/providers/dns/mittwald/mittwald.go
+++ b/providers/dns/mittwald/mittwald.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/mittwald/internal"
)
@@ -93,17 +92,9 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("mittwald: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
}
- client := internal.NewClient(config.Token)
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
- client: client,
+ client: internal.NewClient(config.Token),
zoneIDs: map[string]string{},
}, nil
}
@@ -158,7 +149,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.zoneIDsMu.Lock()
zoneID, ok := d.zoneIDs[token]
d.zoneIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("mittwald: unknown zone ID for '%s'", info.EffectiveFQDN)
}
@@ -170,10 +160,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("mittwald: update/delete TXT record: %w", err)
}
- d.zoneIDsMu.Lock()
- delete(d.zoneIDs, token)
- d.zoneIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/mittwald/mittwald.toml b/providers/dns/mittwald/mittwald.toml
index 36a9f6c16..937b9c172 100644
--- a/providers/dns/mittwald/mittwald.toml
+++ b/providers/dns/mittwald/mittwald.toml
@@ -6,7 +6,7 @@ Since = "v1.48.0"
Example = '''
MITTWALD_TOKEN=my-token \
-lego --dns mittwald -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mittwald -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/mittwald/mittwald_test.go b/providers/dns/mittwald/mittwald_test.go
index 6a6599536..d8cbdb263 100644
--- a/providers/dns/mittwald/mittwald_test.go
+++ b/providers/dns/mittwald/mittwald_test.go
@@ -38,7 +38,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -105,7 +104,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -119,7 +117,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/myaddr/myaddr.go b/providers/dns/myaddr/myaddr.go
index fb7ea66a0..df280f2f4 100644
--- a/providers/dns/myaddr/myaddr.go
+++ b/providers/dns/myaddr/myaddr.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/myaddr/internal"
)
@@ -92,8 +91,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/myaddr/myaddr.toml b/providers/dns/myaddr/myaddr.toml
index 2f5fe6c1f..5ff306526 100644
--- a/providers/dns/myaddr/myaddr.toml
+++ b/providers/dns/myaddr/myaddr.toml
@@ -6,7 +6,7 @@ Since = "v4.22.0"
Example = '''
MYADDR_PRIVATE_KEYS_MAPPING="example:123,test:456" \
-lego --dns myaddr -d '*.example.com' -d example.com run
+lego --email you@example.com --dns myaddr -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/myaddr/myaddr_test.go b/providers/dns/myaddr/myaddr_test.go
index 8e555ecfd..d95a0cf5c 100644
--- a/providers/dns/myaddr/myaddr_test.go
+++ b/providers/dns/myaddr/myaddr_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -93,7 +92,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -107,7 +105,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/mydnsjp/mydnsjp.go b/providers/dns/mydnsjp/mydnsjp.go
index 8a790c88e..d0565e8bd 100644
--- a/providers/dns/mydnsjp/mydnsjp.go
+++ b/providers/dns/mydnsjp/mydnsjp.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/mydnsjp/internal"
)
@@ -80,17 +79,9 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("mydnsjp: some credentials information are missing")
}
- client := internal.NewClient(config.MasterID, config.Password)
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
- client: client,
+ client: internal.NewClient(config.MasterID, config.Password),
}, nil
}
@@ -109,7 +100,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("mydnsjp: %w", err)
}
-
return nil
}
@@ -122,6 +112,5 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("mydnsjp: %w", err)
}
-
return nil
}
diff --git a/providers/dns/mydnsjp/mydnsjp.toml b/providers/dns/mydnsjp/mydnsjp.toml
index eb9e73acc..ab842e37f 100644
--- a/providers/dns/mydnsjp/mydnsjp.toml
+++ b/providers/dns/mydnsjp/mydnsjp.toml
@@ -7,7 +7,7 @@ Since = "v1.2.0"
Example = '''
MYDNSJP_MASTER_ID=xxxxx \
MYDNSJP_PASSWORD=xxxxx \
-lego --dns mydnsjp -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mydnsjp -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/mydnsjp/mydnsjp_test.go b/providers/dns/mydnsjp/mydnsjp_test.go
index c82bd2264..96eb95865 100644
--- a/providers/dns/mydnsjp/mydnsjp_test.go
+++ b/providers/dns/mydnsjp/mydnsjp_test.go
@@ -56,7 +56,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -125,7 +124,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -139,7 +137,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/mythicbeasts/internal/client.go b/providers/dns/mythicbeasts/internal/client.go
index 82c51dbf3..87464553c 100644
--- a/providers/dns/mythicbeasts/internal/client.go
+++ b/providers/dns/mythicbeasts/internal/client.go
@@ -99,7 +99,6 @@ func (c *Client) createTXTRecord(ctx context.Context, zone, leaf, recordType, va
}
resp := &createTXTResponse{}
-
err = c.do(req, resp)
if err != nil {
return nil, err
diff --git a/providers/dns/mythicbeasts/internal/identity.go b/providers/dns/mythicbeasts/internal/identity.go
index 15e35ba69..417f1c759 100644
--- a/providers/dns/mythicbeasts/internal/identity.go
+++ b/providers/dns/mythicbeasts/internal/identity.go
@@ -44,7 +44,6 @@ func (c *Client) obtainToken(ctx context.Context) (*Token, error) {
}
tok := Token{}
-
err = json.Unmarshal(raw, &tok)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -84,7 +83,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errResp := &authResponseError{}
-
err := json.Unmarshal(raw, errResp)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/mythicbeasts/mythicbeasts.go b/providers/dns/mythicbeasts/mythicbeasts.go
index e8f5081f7..ae8f72d33 100644
--- a/providers/dns/mythicbeasts/mythicbeasts.go
+++ b/providers/dns/mythicbeasts/mythicbeasts.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/mythicbeasts/internal"
)
@@ -88,7 +87,6 @@ func NewDNSProvider() (*DNSProvider, error) {
if err != nil {
return nil, fmt.Errorf("mythicbeasts: %w", err)
}
-
config.UserName = values[EnvUserName]
config.Password = values[EnvPassword]
@@ -119,8 +117,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/mythicbeasts/mythicbeasts.toml b/providers/dns/mythicbeasts/mythicbeasts.toml
index cada3041d..011abba1f 100644
--- a/providers/dns/mythicbeasts/mythicbeasts.toml
+++ b/providers/dns/mythicbeasts/mythicbeasts.toml
@@ -7,7 +7,7 @@ Since = "v0.3.7"
Example = '''
MYTHICBEASTS_USERNAME=myuser \
MYTHICBEASTS_PASSWORD=mypass \
-lego --dns mythicbeasts -d '*.example.com' -d example.com run
+lego --email you@example.com --dns mythicbeasts -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/mythicbeasts/mythicbeasts_test.go b/providers/dns/mythicbeasts/mythicbeasts_test.go
index c684725b7..5a8a9d4bb 100644
--- a/providers/dns/mythicbeasts/mythicbeasts_test.go
+++ b/providers/dns/mythicbeasts/mythicbeasts_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -109,7 +108,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
config, err := NewDefaultConfig()
require.NoError(t, err)
-
config.UserName = test.username
config.Password = test.password
@@ -132,7 +130,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -146,7 +143,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/namecheap/internal/client.go b/providers/dns/namecheap/internal/client.go
index 6fb737b95..0fb32b1be 100644
--- a/providers/dns/namecheap/internal/client.go
+++ b/providers/dns/namecheap/internal/client.go
@@ -54,7 +54,6 @@ func (c *Client) GetHosts(ctx context.Context, sld, tld string) ([]Record, error
}
var ghr getHostsResponse
-
err = c.do(request, &ghr)
if err != nil {
return nil, err
@@ -89,7 +88,6 @@ func (c *Client) SetHosts(ctx context.Context, sld, tld string, hosts []Record)
}
var shr setHostsResponse
-
err = c.do(req, &shr)
if err != nil {
return err
@@ -98,7 +96,6 @@ func (c *Client) SetHosts(ctx context.Context, sld, tld string, hosts []Record)
if len(shr.Errors) > 0 {
return shr.Errors[0]
}
-
if shr.Result.IsSuccess != "true" {
return errors.New("setHosts failed")
}
diff --git a/providers/dns/namecheap/namecheap.go b/providers/dns/namecheap/namecheap.go
index 54640f8e0..48b9492c4 100644
--- a/providers/dns/namecheap/namecheap.go
+++ b/providers/dns/namecheap/namecheap.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/namecheap/internal"
"golang.org/x/net/publicsuffix"
)
@@ -76,8 +75,7 @@ func NewDefaultConfig() *Config {
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, time.Hour),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 15*time.Second),
HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, time.Minute),
- Transport: defaultTransport(envNamespace),
+ Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, time.Minute),
},
}
}
@@ -119,7 +117,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if err != nil {
return nil, fmt.Errorf("namecheap: %w", err)
}
-
config.ClientIP = clientIP
}
@@ -130,8 +127,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
@@ -176,7 +171,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("namecheap: %w", err)
}
-
return nil
}
@@ -196,11 +190,8 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
// Find the challenge TXT record and remove it if found.
- var (
- found bool
- newRecords []internal.Record
- )
-
+ var found bool
+ var newRecords []internal.Record
for _, h := range records {
if h.Name == pr.key && h.Type == "TXT" {
found = true
@@ -217,7 +208,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("namecheap: %w", err)
}
-
return nil
}
diff --git a/providers/dns/namecheap/namecheap.toml b/providers/dns/namecheap/namecheap.toml
index b0f92a1bd..3a5be870c 100644
--- a/providers/dns/namecheap/namecheap.toml
+++ b/providers/dns/namecheap/namecheap.toml
@@ -14,7 +14,7 @@ More information in the section [Enabling API Access](https://www.namecheap.com/
Example = '''
NAMECHEAP_API_USER=user \
NAMECHEAP_API_KEY=key \
-lego --dns namecheap -d '*.example.com' -d example.com run
+lego --email you@example.com --dns namecheap -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/namecheap/namecheap_test.go b/providers/dns/namecheap/namecheap_test.go
index e55a4a6bc..922e48ebb 100644
--- a/providers/dns/namecheap/namecheap_test.go
+++ b/providers/dns/namecheap/namecheap_test.go
@@ -1,8 +1,10 @@
package namecheap
import (
+ "net/http"
"net/http/httptest"
"testing"
+ "time"
"github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/stretchr/testify/assert"
@@ -152,7 +154,6 @@ func Test_newPseudoRecord_domainSplit(t *testing.T) {
for _, test := range tests {
t.Run(test.domain, func(t *testing.T) {
valid := true
-
ch, err := newPseudoRecord(test.domain, "")
if err != nil {
valid = false
@@ -178,11 +179,11 @@ func Test_newPseudoRecord_domainSplit(t *testing.T) {
func mockBuilder() *servermock.Builder[*DNSProvider] {
return servermock.NewBuilder(func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
config.BaseURL = server.URL
config.APIUser = envTestUser
config.APIKey = envTestKey
config.ClientIP = envTestClientIP
+ config.HTTPClient = &http.Client{Timeout: 60 * time.Second}
return NewDNSProviderConfig(config)
})
diff --git a/providers/dns/namecheap/transport.go b/providers/dns/namecheap/transport.go
deleted file mode 100644
index 584dc6e50..000000000
--- a/providers/dns/namecheap/transport.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package namecheap
-
-import (
- "net/http"
- "net/url"
- "strings"
- "sync"
-
- "github.com/go-acme/lego/v4/platform/config/env"
- "golang.org/x/net/http/httpproxy"
-)
-
-const (
- envHTTPProxy = "HTTP_PROXY"
- envHTTPProxyLower = "http_proxy"
- envHTTPSProxy = "HTTPS_PROXY"
- envHTTPSProxyLower = "https_proxy"
- envNoProxy = "NO_PROXY"
- envNoProxyLower = "no_proxy"
- envRequestMethod = "REQUEST_METHOD"
-)
-
-// Allows lazy loading of the proxy.
-var (
- envProxyOnce sync.Once
- envProxyFuncValue func(*url.URL) (*url.URL, error)
-)
-
-func defaultTransport(namespace string) http.RoundTripper {
- tr, ok := http.DefaultTransport.(*http.Transport)
- if !ok {
- return nil
- }
-
- clone := tr.Clone()
- clone.Proxy = proxyFromEnvironment(namespace)
-
- return clone
-}
-
-// Inspired by:
-// - https://pkg.go.dev/net/http#ProxyFromEnvironment
-// - https://pkg.go.dev/golang.org/x/net/http/httpproxy#FromEnvironment
-func envProxyFunc(namespace string) func(*url.URL) (*url.URL, error) {
- envProxyOnce.Do(func() {
- cfg := &httpproxy.Config{
- HTTPProxy: getEnv(namespace, envHTTPProxy, envHTTPProxyLower),
- HTTPSProxy: getEnv(namespace, envHTTPSProxy, envHTTPSProxyLower),
- NoProxy: getEnv(namespace, envNoProxy, envNoProxyLower),
- CGI: env.GetOneWithFallback(namespace+envRequestMethod, "", env.ParseString, envRequestMethod) != "",
- }
-
- envProxyFuncValue = cfg.ProxyFunc()
- })
-
- return envProxyFuncValue
-}
-
-// Inspired by:
-// - https://pkg.go.dev/net/http#ProxyFromEnvironment
-// - https://pkg.go.dev/golang.org/x/net/http/httpproxy#FromEnvironment
-func proxyFromEnvironment(namespace string) func(req *http.Request) (*url.URL, error) {
- return func(req *http.Request) (*url.URL, error) {
- return envProxyFunc(namespace)(req.URL)
- }
-}
-
-func getEnv(namespace, baseEnvName, baseEnvNameLower string) string {
- return env.GetOneWithFallback(namespace+baseEnvName, "", env.ParseString,
- strings.ToLower(namespace)+baseEnvNameLower, baseEnvName, baseEnvNameLower)
-}
diff --git a/providers/dns/namecheap/transport_test.go b/providers/dns/namecheap/transport_test.go
deleted file mode 100644
index cd3e9ff17..000000000
--- a/providers/dns/namecheap/transport_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package namecheap
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func Test_defaultTransport(t *testing.T) {
- client := servermock.NewBuilder(
- func(server *httptest.Server) (*http.Client, error) {
- cl := server.Client()
-
- t.Setenv("NAMECHEAP_HTTP_PROXY", server.URL)
-
- cl.Transport = defaultTransport(envNamespace)
-
- return cl, nil
- }).
- Route("/",
- servermock.Noop().WithStatusCode(http.StatusTeapot)).
- Build(t)
-
- req, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
- require.NoError(t, err)
-
- resp, err := client.Do(req)
- require.NoError(t, err)
-
- t.Cleanup(func() {
- _ = resp.Body.Close()
- })
-
- assert.Equal(t, http.StatusTeapot, resp.StatusCode)
-}
diff --git a/providers/dns/namedotcom/namedotcom.go b/providers/dns/namedotcom/namedotcom.go
index 04c8b5967..789599552 100644
--- a/providers/dns/namedotcom/namedotcom.go
+++ b/providers/dns/namedotcom/namedotcom.go
@@ -10,7 +10,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/namedotcom/go/v4/namecom"
)
@@ -98,12 +97,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}
client := namecom.New(config.Username, config.APIToken)
-
- if config.HTTPClient != nil {
- client.Client = config.HTTPClient
- }
-
- client.Client = clientdebug.Wrap(client.Client)
+ client.Client = config.HTTPClient
if config.Server != "" {
client.Server = config.Server
@@ -116,10 +110,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
- if info.EffectiveFQDN != info.FQDN {
- domain = dns01.UnFqdn(info.EffectiveFQDN)
- }
-
+ // TODO(ldez) replace domain by FQDN to follow CNAME.
domainDetails, err := d.client.GetDomain(&namecom.GetDomainRequest{DomainName: domain})
if err != nil {
return fmt.Errorf("namedotcom: API call failed: %w", err)
@@ -130,6 +121,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("namedotcom: %w", err)
}
+ // TODO(ldez) replace domain by FQDN to follow CNAME.
request := &namecom.Record{
DomainName: domain,
Host: subDomain,
@@ -150,10 +142,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
- if info.EffectiveFQDN != info.FQDN {
- domain = dns01.UnFqdn(info.EffectiveFQDN)
- }
-
+ // TODO(ldez) replace domain by FQDN to follow CNAME.
records, err := d.getRecords(domain)
if err != nil {
return fmt.Errorf("namedotcom: %w", err)
@@ -161,11 +150,11 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
for _, rec := range records {
if rec.Fqdn == info.EffectiveFQDN && rec.Type == "TXT" {
+ // TODO(ldez) replace domain by FQDN to follow CNAME.
request := &namecom.DeleteRecordRequest{
DomainName: domain,
ID: rec.ID,
}
-
_, err := d.client.DeleteRecord(request)
if err != nil {
return fmt.Errorf("namedotcom: %w", err)
@@ -189,7 +178,6 @@ func (d *DNSProvider) getRecords(domain string) ([]*namecom.Record, error) {
}
var records []*namecom.Record
-
for request.Page > 0 {
response, err := d.client.ListRecords(request)
if err != nil {
diff --git a/providers/dns/namedotcom/namedotcom.toml b/providers/dns/namedotcom/namedotcom.toml
index 3651c424b..e6de796d1 100644
--- a/providers/dns/namedotcom/namedotcom.toml
+++ b/providers/dns/namedotcom/namedotcom.toml
@@ -7,7 +7,7 @@ Since = "v0.5.0"
Example = '''
NAMECOM_USERNAME=foo.bar \
NAMECOM_API_TOKEN=a379a6f6eeafb9a55e378c118034e2751e682fab \
-lego --dns namedotcom -d '*.example.com' -d example.com run
+lego --email you@example.com --dns namedotcom -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/namedotcom/namedotcom_test.go b/providers/dns/namedotcom/namedotcom_test.go
index da9878bdc..c7d4deaa1 100644
--- a/providers/dns/namedotcom/namedotcom_test.go
+++ b/providers/dns/namedotcom/namedotcom_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -132,7 +131,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -146,7 +144,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/namesilo/namesilo.go b/providers/dns/namesilo/namesilo.go
index 0297b4e1c..f76c8549e 100644
--- a/providers/dns/namesilo/namesilo.go
+++ b/providers/dns/namesilo/namesilo.go
@@ -2,7 +2,6 @@
package namesilo
import (
- "context"
"errors"
"fmt"
"time"
@@ -10,7 +9,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/nrdcg/namesilo"
)
@@ -81,15 +79,12 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("namesilo: TTL should be in [%d, %d]", defaultTTL, maxTTL)
}
- if config.APIKey == "" {
- return nil, errors.New("namesilo: credentials missing")
+ transport, err := namesilo.NewTokenTransport(config.APIKey)
+ if err != nil {
+ return nil, fmt.Errorf("namesilo: %w", err)
}
- client := namesilo.NewClient(config.APIKey)
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{client: client, config: config}, nil
+ return &DNSProvider{client: namesilo.NewClient(transport.Client()), config: config}, nil
}
// Present creates a TXT record to fulfill the dns-01 challenge.
@@ -108,7 +103,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("namesilo: %w", err)
}
- _, err = d.client.DnsAddRecord(context.Background(), &namesilo.DnsAddRecordParams{
+ _, err = d.client.DnsAddRecord(&namesilo.DnsAddRecordParams{
Domain: zoneName,
Type: "TXT",
Host: subdomain,
@@ -118,14 +113,11 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("namesilo: failed to add record %w", err)
}
-
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
zone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
@@ -135,7 +127,7 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
zoneName := dns01.UnFqdn(zone)
- resp, err := d.client.DnsListRecords(ctx, &namesilo.DnsListRecordsParams{Domain: zoneName})
+ resp, err := d.client.DnsListRecords(&namesilo.DnsListRecordsParams{Domain: zoneName})
if err != nil {
return fmt.Errorf("namesilo: %w", err)
}
@@ -147,7 +139,7 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
for _, r := range resp.Reply.ResourceRecord {
if r.Type == "TXT" && r.Value == info.Value && (r.Host == subdomain || r.Host == dns01.UnFqdn(info.EffectiveFQDN)) {
- _, err := d.client.DnsDeleteRecord(ctx, &namesilo.DnsDeleteRecordParams{Domain: zoneName, ID: r.RecordID})
+ _, err := d.client.DnsDeleteRecord(&namesilo.DnsDeleteRecordParams{Domain: zoneName, ID: r.RecordID})
if err != nil {
return fmt.Errorf("namesilo: %w", err)
}
diff --git a/providers/dns/namesilo/namesilo.toml b/providers/dns/namesilo/namesilo.toml
index 113ddb5c5..bab7905bf 100644
--- a/providers/dns/namesilo/namesilo.toml
+++ b/providers/dns/namesilo/namesilo.toml
@@ -6,7 +6,7 @@ Since = "v2.7.0"
Example = '''
NAMESILO_API_KEY=b9841238feb177a84330febba8a83208921177bffe733 \
-lego --dns namesilo -d '*.example.com' -d example.com run
+lego --email you@example.com --dns namesilo -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/namesilo/namesilo_test.go b/providers/dns/namesilo/namesilo_test.go
index 09eacd035..4b01d7388 100644
--- a/providers/dns/namesilo/namesilo_test.go
+++ b/providers/dns/namesilo/namesilo_test.go
@@ -45,7 +45,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -78,7 +77,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
{
desc: "missing API key",
ttl: defaultTTL,
- expected: "namesilo: credentials missing",
+ expected: "namesilo: credentials missing: API key",
},
{
desc: "unavailable TTL",
@@ -113,7 +112,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/namesurfer/internal/client.go b/providers/dns/namesurfer/internal/client.go
deleted file mode 100644
index e40a7988c..000000000
--- a/providers/dns/namesurfer/internal/client.go
+++ /dev/null
@@ -1,226 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "crypto/hmac"
- "crypto/sha256"
- "encoding/hex"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "slices"
- "strconv"
- "strings"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
-)
-
-type Client struct {
- apiKey string
- apiSecret string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-func NewClient(baseURL, apiKey, apiSecret string) (*Client, error) {
- if apiKey == "" || apiSecret == "" {
- return nil, errors.New("credentials missing")
- }
-
- if baseURL == "" {
- return nil, errors.New("base URL missing")
- }
-
- apiEndpoint, err := url.Parse(baseURL)
- if err != nil {
- return nil, err
- }
-
- return &Client{
- apiKey: apiKey,
- apiSecret: apiSecret,
- BaseURL: apiEndpoint.JoinPath("jsonrpc10"),
- HTTPClient: &http.Client{
- Timeout: 5 * time.Second,
- },
- }, nil
-}
-
-// AddDNSRecord adds a DNS record.
-// http://95.128.3.201:8053/API/NSService_10#addDNSRecord
-func (d *Client) AddDNSRecord(ctx context.Context, zoneName, viewName string, record DNSNode) error {
- digest := d.computeDigest(
- zoneName,
- viewName,
- record.Name,
- record.Type,
- strconv.Itoa(record.TTL),
- record.Data,
- )
-
- // JSON-RPC 1.0 requires positional parameters array
- params := []any{
- digest,
- zoneName,
- viewName,
- record,
- }
-
- var ok bool
-
- err := d.doRequest(ctx, "addDNSRecord", params, &ok)
- if err != nil {
- return err
- }
-
- if !ok {
- return errors.New("addDNSRecord failed")
- }
-
- return nil
-}
-
-// UpdateDNSHost updates a DNS host record.
-// Passing an empty newNode removes the oldNode.
-// http://95.128.3.201:8053/API/NSService_10#updateDNSHost
-func (d *Client) UpdateDNSHost(ctx context.Context, zoneName, viewName string, oldNode, newNode DNSNode) error {
- digest := d.computeDigest(zoneName, viewName)
-
- // JSON-RPC 1.0 requires positional parameters array
- params := []any{
- digest,
- zoneName,
- viewName,
- oldNode,
- newNode,
- }
-
- var ok bool
-
- err := d.doRequest(ctx, "updateDNSHost", params, &ok)
- if err != nil {
- return err
- }
-
- if !ok {
- return errors.New("updateDNSHost failed")
- }
-
- return nil
-}
-
-// SearchDNSHosts searches for DNS host records.
-// http://95.128.3.201:8053/API/NSService_10#searchDNSHosts
-func (d *Client) SearchDNSHosts(ctx context.Context, pattern string) ([]DNSNode, error) {
- digest := d.computeDigest(pattern)
-
- // JSON-RPC 1.0 requires positional parameters array
- params := []any{
- digest,
- pattern,
- }
-
- var nodes []DNSNode
-
- err := d.doRequest(ctx, "searchDNSHosts", params, &nodes)
- if err != nil {
- return nil, err
- }
-
- return nodes, nil
-}
-
-// ListZones lists DNS zones.
-// http://95.128.3.201:8053/API/NSService_10#listZones
-func (d *Client) ListZones(ctx context.Context, mode string) ([]DNSZone, error) {
- digest := d.computeDigest()
-
- // JSON-RPC 1.0 requires positional parameters array
- params := []any{
- digest,
- mode,
- }
-
- var zones []DNSZone
-
- err := d.doRequest(ctx, "listZones", params, &zones)
- if err != nil {
- return nil, err
- }
-
- return zones, nil
-}
-
-func (d *Client) doRequest(ctx context.Context, method string, params []any, result any) error {
- payload := APIRequest{
- ID: 1,
- Method: method,
- Params: slices.Concat([]any{d.apiKey}, params),
- }
-
- buf := new(bytes.Buffer)
-
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return fmt.Errorf("failed to create request JSON body: %w", err)
- }
-
- req, err := http.NewRequestWithContext(ctx, http.MethodPost, d.BaseURL.String(), buf)
- if err != nil {
- return fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Content-Type", "application/json")
- req.Header.Set("Accept", "application/json")
-
- resp, err := d.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- if resp.StatusCode/100 != 2 {
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- var rpcResp APIResponse
-
- err = json.Unmarshal(raw, &rpcResp)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- if rpcResp.Error != nil {
- return rpcResp.Error
- }
-
- err = json.Unmarshal(rpcResp.Result, result)
- if err != nil {
- return fmt.Errorf("unable to unmarshal response: %w: %s", err, rpcResp.Result)
- }
-
- return nil
-}
-
-func (d *Client) computeDigest(parts ...string) string {
- params := []string{d.apiKey}
- params = append(params, parts...)
- params = append(params, d.apiSecret)
-
- mac := hmac.New(sha256.New, []byte(d.apiSecret))
- mac.Write([]byte(strings.Join(params, "&")))
-
- return hex.EncodeToString(mac.Sum(nil))
-}
diff --git a/providers/dns/namesurfer/internal/client_test.go b/providers/dns/namesurfer/internal/client_test.go
deleted file mode 100644
index 9e8f917bc..000000000
--- a/providers/dns/namesurfer/internal/client_test.go
+++ /dev/null
@@ -1,158 +0,0 @@
-package internal
-
-import (
- "net/http/httptest"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(server.URL, "user", "secret")
- if err != nil {
- return nil, err
- }
-
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestClient_AddDNSRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /jsonrpc10",
- servermock.ResponseFromFixture("addDNSRecord.json"),
- servermock.CheckRequestJSONBodyFromFixture("addDNSRecord-request.json"),
- ).
- Build(t)
-
- record := DNSNode{
- Name: "_acme-challenge",
- Type: "TXT",
- Data: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 300,
- }
-
- err := client.AddDNSRecord(t.Context(), "example.com", "viewA", record)
- require.NoError(t, err)
-}
-
-func TestClient_AddDNSRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /jsonrpc10",
- servermock.ResponseFromFixture("error.json"),
- ).
- Build(t)
-
- record := DNSNode{
- Name: "_acme-challenge",
- Type: "TXT",
- Data: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 300,
- }
-
- err := client.AddDNSRecord(t.Context(), "example.com", "viewA", record)
- require.EqualError(t, err, "code: Server.Keyfailure, "+
- "filename: service, line: 13, "+
- "message: Unknown keyname user, "+
- `detail: Traceback (most recent call last): File "/usr/local/namesurfer/python/lib/python2.6/site-packages/ladon/server/dispatcher.py", line 159, in dispatch_request result = self.call_method(method,req_dict,tc,export_dict,log_line) File "/usr/local/namesurfer/python/lib/python2.6/site-packages/ladon/server/dispatcher.py", line 96, in call_method result = getattr(service_class_instance,req_dict['methodname'])(*args) File "/usr/local/namesurfer/python/lib/python2.6/site-packages/ladon/ladonizer/decorator.py", line 77, in injector res = f(*args,**kw) File "/usr/local/namesurfer/webui2/webui/service/service10/NSService_10.py", line 502, in addDNSRecord key = validate_key(keyname, digest, [zonename, viewname, record.name, record.type, str(record.ttl), record.data]) File "/usr/local/namesurfer/webui2/webui/service/base/implementation.py", line 63, in validate_key raise ApiFault('Server.Keyfailure', 'Unknown keyname %s' % keyname) ApiFault: service(13): Unknown keyname user `)
-}
-
-func TestClient_UpdateDNSHost(t *testing.T) {
- client := mockBuilder().
- Route("POST /jsonrpc10",
- servermock.ResponseFromFixture("updateDNSHost.json"),
- servermock.CheckRequestJSONBodyFromFixture("updateDNSHost-request.json"),
- ).
- Build(t)
-
- record := DNSNode{
- Name: "_acme-challenge",
- Type: "TXT",
- Data: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: 300,
- }
-
- err := client.UpdateDNSHost(t.Context(), "example.com", "viewA", record, DNSNode{})
- require.NoError(t, err)
-}
-
-func TestClient_SearchDNSHosts(t *testing.T) {
- client := mockBuilder().
- Route("POST /jsonrpc10",
- servermock.ResponseFromFixture("searchDNSHosts.json"),
- servermock.CheckRequestJSONBodyFromFixture("searchDNSHosts-request.json"),
- ).
- Build(t)
-
- records, err := client.SearchDNSHosts(t.Context(), "value")
- require.NoError(t, err)
-
- expected := []DNSNode{
- {Name: "foo", Type: "TXT", Data: "xxx", TTL: 300},
- {Name: "_acme-challenge", Type: "TXT", Data: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY", TTL: 300},
- {Name: "bar", Type: "A", Data: "yyy", TTL: 300},
- }
-
- assert.Equal(t, expected, records)
-}
-
-func TestClient_ListZones(t *testing.T) {
- client := mockBuilder().
- Route("POST /jsonrpc10",
- servermock.ResponseFromFixture("listZones.json"),
- servermock.CheckRequestJSONBodyFromFixture("listZones-request.json"),
- ).
- Build(t)
-
- zones, err := client.ListZones(t.Context(), "value")
- require.NoError(t, err)
-
- expected := []DNSZone{
- {Name: "example.com", View: "viewA"},
- {Name: "example.org", View: "viewB"},
- {Name: "example.net", View: "viewC"},
- }
-
- assert.Equal(t, expected, zones)
-}
-
-func TestClient_computeDigest(t *testing.T) {
- client, err := NewClient("https://test.example.com", "testkey", "testsecret")
- require.NoError(t, err)
-
- testCases := []struct {
- desc string
- parts []string
- expected string
- }{
- {
- desc: "no parts",
- parts: []string{},
- expected: "99b5dcdc19bfc0ce2af3fe848f4bcb6f7beb352e9599e8ba50544d86de567282",
- },
- {
- desc: "parts",
- parts: []string{"zone.example.com", "default"},
- expected: "94efef76383889b1ae620582a25d1c3aa9bd9ba9ac4bdccdf4aefbc3ae6e8329",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- t.Parallel()
-
- digest := client.computeDigest(test.parts...)
-
- assert.Equal(t, test.expected, digest)
- })
- }
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/addDNSRecord-request.json b/providers/dns/namesurfer/internal/fixtures/addDNSRecord-request.json
deleted file mode 100644
index 660109aae..000000000
--- a/providers/dns/namesurfer/internal/fixtures/addDNSRecord-request.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "id": 1,
- "method": "addDNSRecord",
- "params": [
- "user",
- "4fcc5fa29531709b0381c8debea127a6a26e71cb9491727876819cf5805c4990",
- "example.com",
- "viewA",
- {
- "name": "_acme-challenge",
- "type": "TXT",
- "data": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 300
- }
- ]
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/addDNSRecord.json b/providers/dns/namesurfer/internal/fixtures/addDNSRecord.json
deleted file mode 100644
index f41779e30..000000000
--- a/providers/dns/namesurfer/internal/fixtures/addDNSRecord.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "id": 1,
- "result": true
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/error.json b/providers/dns/namesurfer/internal/fixtures/error.json
deleted file mode 100644
index 8ddf8df25..000000000
--- a/providers/dns/namesurfer/internal/fixtures/error.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "result": null,
- "error": {
- "filename": "service",
- "lineno": 13,
- "code": "Server.Keyfailure",
- "string": "Unknown keyname user",
- "detail": [
- "Traceback (most recent call last):",
- " File \"/usr/local/namesurfer/python/lib/python2.6/site-packages/ladon/server/dispatcher.py\", line 159, in dispatch_request",
- " result = self.call_method(method,req_dict,tc,export_dict,log_line)",
- " File \"/usr/local/namesurfer/python/lib/python2.6/site-packages/ladon/server/dispatcher.py\", line 96, in call_method",
- " result = getattr(service_class_instance,req_dict['methodname'])(*args)",
- " File \"/usr/local/namesurfer/python/lib/python2.6/site-packages/ladon/ladonizer/decorator.py\", line 77, in injector",
- " res = f(*args,**kw)",
- " File \"/usr/local/namesurfer/webui2/webui/service/service10/NSService_10.py\", line 502, in addDNSRecord",
- " key = validate_key(keyname, digest, [zonename, viewname, record.name, record.type, str(record.ttl), record.data])",
- " File \"/usr/local/namesurfer/webui2/webui/service/base/implementation.py\", line 63, in validate_key",
- " raise ApiFault('Server.Keyfailure', 'Unknown keyname %s' % keyname)",
- "ApiFault: service(13): Unknown keyname user",
- ""
- ]
- }
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/listZones-request.json b/providers/dns/namesurfer/internal/fixtures/listZones-request.json
deleted file mode 100644
index 06689de7a..000000000
--- a/providers/dns/namesurfer/internal/fixtures/listZones-request.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "id": 1,
- "method": "listZones",
- "params": [
- "user",
- "2739461ea1a3dc51302993f724f40228409c53b78025d8d7b1d7bba3c1bf2d66",
- "value"
- ]
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/listZones.json b/providers/dns/namesurfer/internal/fixtures/listZones.json
deleted file mode 100644
index 37fa2053b..000000000
--- a/providers/dns/namesurfer/internal/fixtures/listZones.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "id": 1,
- "result": [
- {
- "name": "example.com",
- "view": "viewA"
- },
- {
- "name": "example.org",
- "view": "viewB"
- },
- {
- "name": "example.net",
- "view": "viewC"
- }
- ]
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/searchDNSHosts-request.json b/providers/dns/namesurfer/internal/fixtures/searchDNSHosts-request.json
deleted file mode 100644
index 4a88340e2..000000000
--- a/providers/dns/namesurfer/internal/fixtures/searchDNSHosts-request.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "id": 1,
- "method": "searchDNSHosts",
- "params": [
- "user",
- "02cf1a2f6e124507d16738d595f583932185313fc96afc2d8404960acaec29b4",
- "value"
- ]
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/searchDNSHosts.json b/providers/dns/namesurfer/internal/fixtures/searchDNSHosts.json
deleted file mode 100644
index 822459148..000000000
--- a/providers/dns/namesurfer/internal/fixtures/searchDNSHosts.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "id": 1,
- "result": [
- {
- "name": "foo",
- "type": "TXT",
- "data": "xxx",
- "ttl": 300
- },
- {
- "name": "_acme-challenge",
- "type": "TXT",
- "data": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 300
- },
- {
- "name": "bar",
- "type": "A",
- "data": "yyy",
- "ttl": 300
- }
- ]
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/updateDNSHost-request.json b/providers/dns/namesurfer/internal/fixtures/updateDNSHost-request.json
deleted file mode 100644
index 494de20c6..000000000
--- a/providers/dns/namesurfer/internal/fixtures/updateDNSHost-request.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "id": 1,
- "method": "updateDNSHost",
- "params": [
- "user",
- "510e63288ac874c1d5ba313a9411591daa346e5621fb0153263adc278794e378",
- "example.com",
- "viewA",
- {
- "name": "_acme-challenge",
- "type": "TXT",
- "data": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "ttl": 300
- },
- {
- "name": "",
- "type": "",
- "data": "",
- "ttl": 0
- }
- ]
-}
diff --git a/providers/dns/namesurfer/internal/fixtures/updateDNSHost.json b/providers/dns/namesurfer/internal/fixtures/updateDNSHost.json
deleted file mode 100644
index f41779e30..000000000
--- a/providers/dns/namesurfer/internal/fixtures/updateDNSHost.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "id": 1,
- "result": true
-}
diff --git a/providers/dns/namesurfer/internal/types.go b/providers/dns/namesurfer/internal/types.go
deleted file mode 100644
index d364c1876..000000000
--- a/providers/dns/namesurfer/internal/types.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-)
-
-// DNSNode represents a DNS record.
-// http://95.128.3.201:8053/API/NSService_10#DNSNode
-type DNSNode struct {
- Name string `json:"name"`
- Type string `json:"type"`
- Data string `json:"data"`
- TTL int `json:"ttl"`
-}
-
-// DNSZone represents a DNS zone.
-// http://95.128.3.201:8053/API/NSService_10#DNSZone
-type DNSZone struct {
- Name string `json:"name,omitempty"`
- View string `json:"view,omitempty"`
-}
-
-// APIRequest represents a JSON-RPC request.
-// https://www.jsonrpc.org/specification_v1#a1.1Requestmethodinvocation
-type APIRequest struct {
- ID any `json:"id"` // Can be int or string depending on API
- Method string `json:"method"`
- Params []any `json:"params"`
-}
-
-// APIResponse represents a JSON-RPC response.
-// https://www.jsonrpc.org/specification_v1#a1.2Response
-type APIResponse struct {
- ID any `json:"id"` // Can be int or string depending on API
- Result json.RawMessage `json:"result"`
- Error *APIError `json:"error"`
-}
-
-// APIError represents an error.
-type APIError struct {
- Code any `json:"code"` // Can be int or string depending on API
- Filename string `json:"filename"`
- LineNumber int `json:"lineno"`
- Message string `json:"string"`
- Detail []string `json:"detail"`
-}
-
-func (e *APIError) Error() string {
- msg := new(strings.Builder)
-
- _, _ = fmt.Fprintf(msg, "code: %v", e.Code)
-
- if e.Filename != "" {
- _, _ = fmt.Fprintf(msg, ", filename: %s", e.Filename)
- }
-
- if e.LineNumber > 0 {
- _, _ = fmt.Fprintf(msg, ", line: %d", e.LineNumber)
- }
-
- if e.Message != "" {
- _, _ = fmt.Fprintf(msg, ", message: %s", e.Message)
- }
-
- if len(e.Detail) > 0 {
- _, _ = fmt.Fprintf(msg, ", detail: %v", strings.Join(e.Detail, " "))
- }
-
- return msg.String()
-}
diff --git a/providers/dns/namesurfer/namesurfer.go b/providers/dns/namesurfer/namesurfer.go
deleted file mode 100644
index 6b7f48402..000000000
--- a/providers/dns/namesurfer/namesurfer.go
+++ /dev/null
@@ -1,214 +0,0 @@
-// Package namesurfer implements a DNS provider for solving the DNS-01 challenge using FusionLayer NameSurfer API.
-package namesurfer
-
-import (
- "context"
- "crypto/tls"
- "errors"
- "fmt"
- "net/http"
- "strings"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/namesurfer/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "NAMESURFER_"
-
- EnvBaseURL = envNamespace + "BASE_URL"
- EnvAPIKey = envNamespace + "API_KEY"
- EnvAPISecret = envNamespace + "API_SECRET"
- EnvView = envNamespace + "VIEW"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
- EnvInsecureSkipVerify = envNamespace + "INSECURE_SKIP_VERIFY"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- BaseURL string
- APIKey string
- APISecret string
- View string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, 300),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- zones map[string]string
- zonesMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for FusionLayer NameSurfer.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvBaseURL, EnvAPIKey, EnvAPISecret)
- if err != nil {
- return nil, fmt.Errorf("namesurfer: %w", err)
- }
-
- config := NewDefaultConfig()
- config.BaseURL = values[EnvBaseURL]
- config.APIKey = values[EnvAPIKey]
- config.APISecret = values[EnvAPISecret]
- config.View = env.GetOrDefaultString(EnvView, "")
-
- if env.GetOrDefaultBool(EnvInsecureSkipVerify, false) {
- config.HTTPClient.Transport = &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- }
- }
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for FusionLayer NameSurfer.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("namesurfer: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.BaseURL, config.APIKey, config.APISecret)
- if err != nil {
- return nil, fmt.Errorf("namesurfer: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- zones: make(map[string]string),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- zone, err := d.findZone(ctx, info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("namesurfer: %w", err)
- }
-
- d.zonesMu.Lock()
- d.zones[token] = zone
- d.zonesMu.Unlock()
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
- if err != nil {
- return fmt.Errorf("namesurfer: %w", err)
- }
-
- record := internal.DNSNode{
- Name: subDomain,
- Type: "TXT",
- TTL: d.config.TTL,
- Data: info.Value,
- }
-
- err = d.client.AddDNSRecord(ctx, zone, d.config.View, record)
- if err != nil {
- return fmt.Errorf("namesurfer: add DNS record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- d.zonesMu.Lock()
- zone, ok := d.zones[token]
- d.zonesMu.Unlock()
-
- if !ok {
- return fmt.Errorf("namesurfer: unknown zone for '%s'", info.EffectiveFQDN)
- }
-
- d.zonesMu.Lock()
- delete(d.zones, token)
- d.zonesMu.Unlock()
-
- existing, err := d.client.SearchDNSHosts(ctx, dns01.UnFqdn(info.EffectiveFQDN))
- if err != nil {
- return fmt.Errorf("namesurfer: search DNS hosts: %w", err)
- }
-
- for _, node := range existing {
- if node.Type != "TXT" || node.Data != info.Value {
- continue
- }
-
- err = d.client.UpdateDNSHost(ctx, zone, d.config.View, node, internal.DNSNode{})
- if err != nil {
- return fmt.Errorf("namesurfer: update DNS host: %w", err)
- }
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) findZone(ctx context.Context, fqdn string) (string, error) {
- zones, err := d.client.ListZones(ctx, "forward")
- if err != nil {
- return "", fmt.Errorf("list zones: %w", err)
- }
-
- domain := dns01.UnFqdn(fqdn)
-
- var zoneName string
-
- for _, zone := range zones {
- if strings.HasSuffix(domain, zone.Name) && len(zone.Name) > len(zoneName) {
- zoneName = zone.Name
- }
- }
-
- if zoneName == "" {
- return "", fmt.Errorf("no zone found for %s", fqdn)
- }
-
- return zoneName, nil
-}
diff --git a/providers/dns/namesurfer/namesurfer.toml b/providers/dns/namesurfer/namesurfer.toml
deleted file mode 100644
index fd914ec0c..000000000
--- a/providers/dns/namesurfer/namesurfer.toml
+++ /dev/null
@@ -1,28 +0,0 @@
-Name = "FusionLayer NameSurfer"
-Description = ''''''
-URL = "https://www.fusionlayer.com/"
-Code = "namesurfer"
-Since = "v4.32.0"
-
-Example = '''
-NAMESURFER_BASE_URL=https://foo.example.com:8443/API/NSService_10 \
-NAMESURFER_API_KEY=xxx \
-NAMESURFER_API_SECRET=yyy \
-lego --dns namesurfer -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- NAMESURFER_BASE_URL = "The base URL of NameSurfer API (jsonrpc10) endpoint URL (e.g., https://foo.example.com:8443/API/NSService_10)"
- NAMESURFER_API_KEY = "API key name"
- NAMESURFER_API_SECRET = "API secret"
- [Configuration.Additional]
- NAMESURFER_VIEW = "DNS view name (optional, default: empty string)"
- NAMESURFER_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- NAMESURFER_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
- NAMESURFER_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)"
- NAMESURFER_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
- NAMESURFER_INSECURE_SKIP_VERIFY = "Whether to verify the API certificate"
-
-[Links]
- API = "https://web.archive.org/web/20260213170737/http://95.128.3.201:8053/API/NSService_10"
diff --git a/providers/dns/namesurfer/namesurfer_test.go b/providers/dns/namesurfer/namesurfer_test.go
deleted file mode 100644
index ce3aa37af..000000000
--- a/providers/dns/namesurfer/namesurfer_test.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package namesurfer
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(
- EnvBaseURL,
- EnvAPIKey,
- EnvAPISecret,
- EnvView,
-).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvBaseURL: "https://example.com",
- EnvAPIKey: "user",
- EnvAPISecret: "secret",
- },
- },
- {
- desc: "missing base URL",
- envVars: map[string]string{
- EnvBaseURL: "",
- EnvAPIKey: "user",
- EnvAPISecret: "secret",
- },
- expected: "namesurfer: some credentials information are missing: NAMESURFER_BASE_URL",
- },
- {
- desc: "missing API key",
- envVars: map[string]string{
- EnvBaseURL: "https://example.com",
- EnvAPIKey: "",
- EnvAPISecret: "secret",
- },
- expected: "namesurfer: some credentials information are missing: NAMESURFER_API_KEY",
- },
- {
- desc: "missing API secret",
- envVars: map[string]string{
- EnvBaseURL: "https://example.com",
- EnvAPIKey: "user",
- EnvAPISecret: "",
- },
- expected: "namesurfer: some credentials information are missing: NAMESURFER_API_SECRET",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "namesurfer: some credentials information are missing: NAMESURFER_BASE_URL,NAMESURFER_API_KEY,NAMESURFER_API_SECRET",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- baseURL string
- apiKey string
- apiSecret string
- expected string
- }{
- {
- desc: "success",
- baseURL: "https://example.com",
- apiKey: "user",
- apiSecret: "secret",
- },
- {
- desc: "missing base URL",
- apiKey: "user",
- apiSecret: "secret",
- expected: "namesurfer: base URL missing",
- },
- {
- desc: "missing API key",
- baseURL: "https://example.com",
- apiSecret: "secret",
- expected: "namesurfer: credentials missing",
- },
- {
- desc: "missing API secret",
- baseURL: "https://example.com",
- apiKey: "user",
- expected: "namesurfer: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "namesurfer: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.BaseURL = test.baseURL
- config.APIKey = test.apiKey
- config.APISecret = test.apiSecret
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/nearlyfreespeech/internal/client.go b/providers/dns/nearlyfreespeech/internal/client.go
index 5d7e79fbe..fcfe4e9b7 100644
--- a/providers/dns/nearlyfreespeech/internal/client.go
+++ b/providers/dns/nearlyfreespeech/internal/client.go
@@ -97,7 +97,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errAPI := &APIError{}
-
err := json.Unmarshal(raw, errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
@@ -119,6 +118,7 @@ func (c Signer) Sign(uri, body, login, apiKey string) string {
// Header is "login;timestamp;salt;hash".
// hash is SHA1("login;timestamp;salt;api-key;request-uri;body-hash")
// and body-hash is SHA1(body).
+
bodyHash := sha1.Sum([]byte(body))
timestamp := strconv.FormatInt(c.clock().Unix(), 10)
diff --git a/providers/dns/nearlyfreespeech/internal/client_test.go b/providers/dns/nearlyfreespeech/internal/client_test.go
index 26e4552be..1445286c3 100644
--- a/providers/dns/nearlyfreespeech/internal/client_test.go
+++ b/providers/dns/nearlyfreespeech/internal/client_test.go
@@ -163,7 +163,6 @@ func TestSigner_Sign(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
-
signer := NewSigner()
signer.saltShaker = func() []byte { return []byte(test.salt) }
signer.clock = func() time.Time { return time.Unix(test.now, 0) }
diff --git a/providers/dns/nearlyfreespeech/nearlyfreespeech.go b/providers/dns/nearlyfreespeech/nearlyfreespeech.go
index af5e5363c..464ac35d0 100644
--- a/providers/dns/nearlyfreespeech/nearlyfreespeech.go
+++ b/providers/dns/nearlyfreespeech/nearlyfreespeech.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/nearlyfreespeech/internal"
)
@@ -93,8 +92,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/nearlyfreespeech/nearlyfreespeech.toml b/providers/dns/nearlyfreespeech/nearlyfreespeech.toml
index 3a1e25942..80d4fd6bc 100644
--- a/providers/dns/nearlyfreespeech/nearlyfreespeech.toml
+++ b/providers/dns/nearlyfreespeech/nearlyfreespeech.toml
@@ -7,7 +7,7 @@ Since = "v4.8.0"
Example = '''
NEARLYFREESPEECH_API_KEY=xxxxxx \
NEARLYFREESPEECH_LOGIN=xxxx \
-lego --dns nearlyfreespeech -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nearlyfreespeech -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/nearlyfreespeech/nearlyfreespeech_test.go b/providers/dns/nearlyfreespeech/nearlyfreespeech_test.go
index b67b350e9..adc7efe1e 100644
--- a/providers/dns/nearlyfreespeech/nearlyfreespeech_test.go
+++ b/providers/dns/nearlyfreespeech/nearlyfreespeech_test.go
@@ -54,7 +54,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -127,7 +126,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -141,7 +139,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/neodigit/neodigit.go b/providers/dns/neodigit/neodigit.go
deleted file mode 100644
index d41846307..000000000
--- a/providers/dns/neodigit/neodigit.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Package neodigit implements a DNS provider for solving the DNS-01 challenge using Neodigit DNS.
-package neodigit
-
-import (
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/tecnocratica"
-)
-
-// Environment variables names.
-const (
- envNamespace = "NEODIGIT_"
-
- EnvToken = envNamespace + "TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-const defaultBaseURL = "https://api.neodigit.net/v1"
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config = tecnocratica.Config
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 5*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 10*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- prv challenge.ProviderTimeout
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Neodigit.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvToken)
- if err != nil {
- return nil, fmt.Errorf("neodigit: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Token = values[EnvToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Neodigit.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("neodigit: the configuration of the DNS provider is nil")
- }
-
- provider, err := tecnocratica.NewDNSProviderConfig(config, defaultBaseURL)
- if err != nil {
- return nil, fmt.Errorf("neodigit: %w", err)
- }
-
- return &DNSProvider{prv: provider}, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("neodigit: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("neodigit: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
-}
diff --git a/providers/dns/neodigit/neodigit.toml b/providers/dns/neodigit/neodigit.toml
deleted file mode 100644
index 91b3cfb07..000000000
--- a/providers/dns/neodigit/neodigit.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Neodigit"
-Description = ''''''
-URL = "https://www.neodigit.net"
-Code = "neodigit"
-Since = "v4.30.0"
-
-Example = '''
-NEODIGIT_TOKEN=xxxxxx \
-lego --dns neodigit -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- NEODIGIT_TOKEN = "API token"
- [Configuration.Additional]
- NEODIGIT_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 10)"
- NEODIGIT_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 300)"
- NEODIGIT_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- NEODIGIT_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://developers.neodigit.net/#dns"
diff --git a/providers/dns/neodigit/neodigit_test.go b/providers/dns/neodigit/neodigit_test.go
deleted file mode 100644
index 39f67c59c..000000000
--- a/providers/dns/neodigit/neodigit_test.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package neodigit
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvToken).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvToken: "secret",
- },
- },
- {
- desc: "missing credentials: token",
- envVars: map[string]string{
- EnvToken: "",
- },
- expected: "neodigit: some credentials information are missing: NEODIGIT_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.prv)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- token string
- expected string
- }{
- {
- desc: "success",
- token: "secret",
- },
- {
- desc: "missing token",
- expected: "neodigit: missing credentials",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Token = test.token
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.prv)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/netcup/internal/client.go b/providers/dns/netcup/internal/client.go
index 1287a8d7a..553733175 100644
--- a/providers/dns/netcup/internal/client.go
+++ b/providers/dns/netcup/internal/client.go
@@ -80,7 +80,6 @@ func (c *Client) GetDNSRecords(ctx context.Context, hostname string) ([]DNSRecor
}
var responseData InfoDNSRecordsResponse
-
err := c.doRequest(ctx, payload, &responseData)
if err != nil {
return nil, fmt.Errorf("error when sending the request: %w", err)
@@ -140,7 +139,6 @@ func GetDNSRecordIdx(records []DNSRecord, record DNSRecord) (int, error) {
return index, nil
}
}
-
return -1, errors.New("no DNS Record found")
}
@@ -175,7 +173,6 @@ func unmarshalResponseMsg(req *http.Request, resp *http.Response) (*ResponseMsg,
}
var respMsg ResponseMsg
-
err = json.Unmarshal(raw, &respMsg)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/netcup/internal/client_live_test.go b/providers/dns/netcup/internal/client_live_test.go
index 68621882e..3cf6c8c0b 100644
--- a/providers/dns/netcup/internal/client_live_test.go
+++ b/providers/dns/netcup/internal/client_live_test.go
@@ -38,7 +38,7 @@ func TestClient_GetDNSRecords_Live(t *testing.T) {
info := dns01.GetChallengeInfo(envTest.GetDomain(), "123d==")
zone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- require.NoError(t, err)
+ require.NoError(t, err, "error finding DNSZone")
zone = dns01.UnFqdn(zone)
@@ -103,7 +103,7 @@ func TestClient_UpdateDNSRecord_Live(t *testing.T) {
// Tear down
err = client.UpdateDNSRecord(ctx, envTest.GetDomain(), []DNSRecord{records[recordIdx]})
- require.NoError(t, err)
+ require.NoError(t, err, "Did not remove record! Please do so yourself.")
err = client.Logout(ctx)
require.NoError(t, err)
diff --git a/providers/dns/netcup/internal/session.go b/providers/dns/netcup/internal/session.go
index b53751edf..6627d74e1 100644
--- a/providers/dns/netcup/internal/session.go
+++ b/providers/dns/netcup/internal/session.go
@@ -24,7 +24,6 @@ func (c *Client) login(ctx context.Context) (string, error) {
}
var responseData LoginResponse
-
err := c.doRequest(ctx, payload, &responseData)
if err != nil {
return "", fmt.Errorf("loging error: %w", err)
diff --git a/providers/dns/netcup/netcup.go b/providers/dns/netcup/netcup.go
index 13b329e07..f0544bbcd 100644
--- a/providers/dns/netcup/netcup.go
+++ b/providers/dns/netcup/netcup.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/netcup/internal"
)
@@ -93,11 +92,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("netcup: %w", err)
}
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
+ client.HTTPClient = config.HTTPClient
return &DNSProvider{client: client, config: config}, nil
}
diff --git a/providers/dns/netcup/netcup.toml b/providers/dns/netcup/netcup.toml
index 4ef8688c6..0df09b0df 100644
--- a/providers/dns/netcup/netcup.toml
+++ b/providers/dns/netcup/netcup.toml
@@ -8,7 +8,7 @@ Example = '''
NETCUP_CUSTOMER_NUMBER=xxxx \
NETCUP_API_KEY=yyyy \
NETCUP_API_PASSWORD=zzzz \
-lego --dns netcup -d '*.example.com' -d example.com run
+lego --email you@example.com --dns netcup -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/netcup/netcup_test.go b/providers/dns/netcup/netcup_test.go
index fedc56ba9..f9cc43ab9 100644
--- a/providers/dns/netcup/netcup_test.go
+++ b/providers/dns/netcup/netcup_test.go
@@ -72,7 +72,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -159,14 +158,13 @@ func TestLivePresentAndCleanup(t *testing.T) {
}
envTest.RestoreEnv()
-
p, err := NewDNSProvider()
require.NoError(t, err)
info := dns01.GetChallengeInfo(envTest.GetDomain(), "123d==")
zone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- require.NoError(t, err)
+ require.NoError(t, err, "error finding DNSZone")
zone = dns01.UnFqdn(zone)
@@ -183,7 +181,7 @@ func TestLivePresentAndCleanup(t *testing.T) {
require.NoError(t, err)
err = p.CleanUp(test, "987d", "123d==")
- require.NoError(t, err)
+ require.NoError(t, err, "Did not clean up! Please remove record yourself.")
})
}
}
diff --git a/providers/dns/netlify/internal/client.go b/providers/dns/netlify/internal/client.go
index 3b6b681fe..a8e3b35c3 100644
--- a/providers/dns/netlify/internal/client.go
+++ b/providers/dns/netlify/internal/client.go
@@ -59,7 +59,6 @@ func (c *Client) GetRecords(ctx context.Context, zoneID string) ([]DNSRecord, er
}
var records []DNSRecord
-
err = json.Unmarshal(raw, &records)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -94,7 +93,6 @@ func (c *Client) CreateRecord(ctx context.Context, zoneID string, record DNSReco
}
var recordResp DNSRecord
-
err = json.Unmarshal(raw, &recordResp)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/netlify/netlify.go b/providers/dns/netlify/netlify.go
index 5b2980d24..1d4c78f4f 100644
--- a/providers/dns/netlify/netlify.go
+++ b/providers/dns/netlify/netlify.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/netlify/internal"
)
@@ -85,11 +84,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("netlify: incomplete credentials, missing token")
}
- client := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.Token),
- ),
- )
+ client := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.Token))
return &DNSProvider{
config: config,
@@ -149,7 +144,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("netlify: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
diff --git a/providers/dns/netlify/netlify.toml b/providers/dns/netlify/netlify.toml
index 9d3c0f6b5..c5cb670f9 100644
--- a/providers/dns/netlify/netlify.toml
+++ b/providers/dns/netlify/netlify.toml
@@ -6,7 +6,7 @@ Since = "v3.7.0"
Example = '''
NETLIFY_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns netlify -d '*.example.com' -d example.com run
+lego --email you@example.com --dns netlify -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/netlify/netlify_test.go b/providers/dns/netlify/netlify_test.go
index 1e84517be..f351802da 100644
--- a/providers/dns/netlify/netlify_test.go
+++ b/providers/dns/netlify/netlify_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -94,7 +93,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -108,7 +106,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/nicmanager/internal/client.go b/providers/dns/nicmanager/internal/client.go
index 16bfe497b..eb84e29ec 100644
--- a/providers/dns/nicmanager/internal/client.go
+++ b/providers/dns/nicmanager/internal/client.go
@@ -83,7 +83,6 @@ func (c *Client) GetZone(ctx context.Context, name string) (*Zone, error) {
}
var zone Zone
-
err = c.do(req, http.StatusOK, &zone)
if err != nil {
return nil, err
diff --git a/providers/dns/nicmanager/nicmanager.go b/providers/dns/nicmanager/nicmanager.go
index 9b27df64e..2a5742373 100644
--- a/providers/dns/nicmanager/nicmanager.go
+++ b/providers/dns/nicmanager/nicmanager.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/nicmanager/internal"
)
@@ -129,8 +128,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{client: client, config: config}, nil
}
@@ -191,11 +188,8 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
name := dns01.UnFqdn(info.EffectiveFQDN)
- var (
- existingRecord internal.Record
- existingRecordFound bool
- )
-
+ var existingRecord internal.Record
+ var existingRecordFound bool
for _, record := range zone.Records {
if strings.EqualFold(record.Type, "TXT") && strings.EqualFold(record.Name, name) && record.Content == info.Value {
existingRecord = record
diff --git a/providers/dns/nicmanager/nicmanager.toml b/providers/dns/nicmanager/nicmanager.toml
index d5921de5a..7fdf296c4 100644
--- a/providers/dns/nicmanager/nicmanager.toml
+++ b/providers/dns/nicmanager/nicmanager.toml
@@ -13,7 +13,7 @@ NICMANAGER_API_PASSWORD = "password" \
# Optionally, if your account has TOTP enabled, set the secret here
NICMANAGER_API_OTP = "long-secret" \
-lego --dns nicmanager -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nicmanager -d '*.example.com' -d example.com run
## Login using account name + username
@@ -24,7 +24,7 @@ NICMANAGER_API_PASSWORD = "password" \
# Optionally, if your account has TOTP enabled, set the secret here
NICMANAGER_API_OTP = "long-secret" \
-lego --dns nicmanager -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nicmanager -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/nicmanager/nicmanager_test.go b/providers/dns/nicmanager/nicmanager_test.go
index 114cdb7ca..bc2f50cc3 100644
--- a/providers/dns/nicmanager/nicmanager_test.go
+++ b/providers/dns/nicmanager/nicmanager_test.go
@@ -66,7 +66,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -160,7 +159,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -174,7 +172,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/nicru/internal/client.go b/providers/dns/nicru/internal/client.go
index 5d851fc76..37acd68f1 100644
--- a/providers/dns/nicru/internal/client.go
+++ b/providers/dns/nicru/internal/client.go
@@ -30,7 +30,6 @@ func (tr Trimmer) Token() (xml.Token, error) {
if cd, ok := t.(xml.CharData); ok {
t = xml.CharData(bytes.TrimSpace(cd))
}
-
return t, err
}
diff --git a/providers/dns/nicru/nicru.go b/providers/dns/nicru/nicru.go
index cf4255bdb..9320f94c2 100644
--- a/providers/dns/nicru/nicru.go
+++ b/providers/dns/nicru/nicru.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/nicru/internal"
)
@@ -91,7 +90,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("nicru: %w", err)
}
- client, err := internal.NewClient(clientdebug.Wrap(oauthClient))
+ client, err := internal.NewClient(oauthClient)
if err != nil {
return nil, fmt.Errorf("nicru: unable to build API client: %w", err)
}
diff --git a/providers/dns/nicru/nicru.toml b/providers/dns/nicru/nicru.toml
index f955511a2..6bffe74a5 100644
--- a/providers/dns/nicru/nicru.toml
+++ b/providers/dns/nicru/nicru.toml
@@ -9,7 +9,7 @@ NICRU_USER="" \
NICRU_PASSWORD="" \
NICRU_SERVICE_ID="" \
NICRU_SECRET="" \
-lego --dns nicru -d '*.example.com' -d example.com run
+lego --dns nicru --domains "*.example.com" --email you@example.com run
'''
Additional = '''
diff --git a/providers/dns/nicru/nicru_test.go b/providers/dns/nicru/nicru_test.go
index 7e71f9d2c..12db3a4ff 100644
--- a/providers/dns/nicru/nicru_test.go
+++ b/providers/dns/nicru/nicru_test.go
@@ -75,7 +75,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -172,7 +171,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -186,7 +184,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/nifcloud/internal/client.go b/providers/dns/nifcloud/internal/client.go
index 0f3851883..4469a1f78 100644
--- a/providers/dns/nifcloud/internal/client.go
+++ b/providers/dns/nifcloud/internal/client.go
@@ -59,7 +59,6 @@ func (c *Client) ChangeResourceRecordSets(ctx context.Context, hostedZoneID stri
}
output := &ChangeResourceRecordSetsResponse{}
-
err = c.do(req, output)
if err != nil {
return nil, err
@@ -78,7 +77,6 @@ func (c *Client) GetChange(ctx context.Context, statusID string) (*GetChangeResp
}
output := &GetChangeResponse{}
-
err = c.do(req, output)
if err != nil {
return nil, err
@@ -131,7 +129,6 @@ func (c *Client) sign(req *http.Request) error {
}
mac := hmac.New(sha1.New, []byte(c.secretKey))
-
_, err := mac.Write([]byte(req.Header.Get("Date")))
if err != nil {
return err
@@ -151,7 +148,6 @@ func newXMLRequest(ctx context.Context, method string, endpoint *url.URL, payloa
if payload != nil {
body.WriteString(xml.Header)
-
err := xml.NewEncoder(body).Encode(payload)
if err != nil {
return nil, fmt.Errorf("failed to create request XML body: %w", err)
@@ -174,7 +170,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errResp := &ErrorResponse{}
-
err := xml.Unmarshal(raw, errResp)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/nifcloud/nifcloud.go b/providers/dns/nifcloud/nifcloud.go
index ced7eff09..e73333c52 100644
--- a/providers/dns/nifcloud/nifcloud.go
+++ b/providers/dns/nifcloud/nifcloud.go
@@ -9,12 +9,10 @@ import (
"net/url"
"time"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/platform/wait"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/nifcloud/internal"
)
@@ -95,8 +93,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
if config.BaseURL != "" {
baseURL, err := url.Parse(config.BaseURL)
if err != nil {
@@ -111,29 +107,23 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- err := d.changeRecord(ctx, "CREATE", info.EffectiveFQDN, info.Value, d.config.TTL)
+ err := d.changeRecord("CREATE", info.EffectiveFQDN, info.Value, d.config.TTL)
if err != nil {
return fmt.Errorf("nifcloud: %w", err)
}
-
return err
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- err := d.changeRecord(ctx, "DELETE", info.EffectiveFQDN, info.Value, d.config.TTL)
+ err := d.changeRecord("DELETE", info.EffectiveFQDN, info.Value, d.config.TTL)
if err != nil {
return fmt.Errorf("nifcloud: %w", err)
}
-
return err
}
@@ -143,7 +133,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
-func (d *DNSProvider) changeRecord(ctx context.Context, action, fqdn, value string, ttl int) error {
+func (d *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error {
authZone, err := dns01.FindZoneByFqdn(fqdn)
if err != nil {
return fmt.Errorf("could not find zone: %w", err)
@@ -180,6 +170,8 @@ func (d *DNSProvider) changeRecord(ctx context.Context, action, fqdn, value stri
},
}
+ ctx := context.Background()
+
resp, err := d.client.ChangeResourceRecordSets(ctx, dns01.UnFqdn(authZone), reqParams)
if err != nil {
return fmt.Errorf("failed to change record set: %w", err)
@@ -187,20 +179,11 @@ func (d *DNSProvider) changeRecord(ctx context.Context, action, fqdn, value stri
statusID := resp.ChangeInfo.ID
- return wait.Retry(ctx,
- func() error {
- resp, err := d.client.GetChange(ctx, statusID)
- if err != nil {
- return fmt.Errorf("get change: %w", err)
- }
-
- if resp.ChangeInfo.Status != "INSYNC" {
- return fmt.Errorf("change status: %s", resp.ChangeInfo.Status)
- }
-
- return nil
- },
- backoff.WithBackOff(backoff.NewConstantBackOff(4*time.Second)),
- backoff.WithMaxElapsedTime(120*time.Second),
- )
+ return wait.For("nifcloud", 120*time.Second, 4*time.Second, func() (bool, error) {
+ resp, err := d.client.GetChange(ctx, statusID)
+ if err != nil {
+ return false, fmt.Errorf("failed to query change status: %w", err)
+ }
+ return resp.ChangeInfo.Status == "INSYNC", nil
+ })
}
diff --git a/providers/dns/nifcloud/nifcloud.toml b/providers/dns/nifcloud/nifcloud.toml
index 3c43b1dc0..b692bb9d3 100644
--- a/providers/dns/nifcloud/nifcloud.toml
+++ b/providers/dns/nifcloud/nifcloud.toml
@@ -7,7 +7,7 @@ Since = "v1.1.0"
Example = '''
NIFCLOUD_ACCESS_KEY_ID=xxxx \
NIFCLOUD_SECRET_ACCESS_KEY=yyyy \
-lego --dns nifcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nifcloud -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/nifcloud/nifcloud_test.go b/providers/dns/nifcloud/nifcloud_test.go
index 0eff98a71..9b635edfc 100644
--- a/providers/dns/nifcloud/nifcloud_test.go
+++ b/providers/dns/nifcloud/nifcloud_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -130,7 +129,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -144,7 +142,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/njalla/internal/client.go b/providers/dns/njalla/internal/client.go
index d2893253f..f64db3c80 100644
--- a/providers/dns/njalla/internal/client.go
+++ b/providers/dns/njalla/internal/client.go
@@ -46,7 +46,6 @@ func (c *Client) AddRecord(ctx context.Context, record Record) (*Record, error)
}
var result APIResponse[*Record]
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -93,7 +92,6 @@ func (c *Client) ListRecords(ctx context.Context, domain string) ([]Record, erro
}
var result APIResponse[Records]
-
err = c.do(req, &result)
if err != nil {
return nil, err
diff --git a/providers/dns/njalla/njalla.go b/providers/dns/njalla/njalla.go
index 2f9aef8ea..b08ce69de 100644
--- a/providers/dns/njalla/njalla.go
+++ b/providers/dns/njalla/njalla.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/njalla/internal"
"github.com/miekg/dns"
)
@@ -91,8 +90,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -148,7 +145,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("njalla: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
diff --git a/providers/dns/njalla/njalla.toml b/providers/dns/njalla/njalla.toml
index ff4750b7d..ef1fe158e 100644
--- a/providers/dns/njalla/njalla.toml
+++ b/providers/dns/njalla/njalla.toml
@@ -6,7 +6,7 @@ Since = "v4.3.0"
Example = '''
NJALLA_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns njalla -d '*.example.com' -d example.com run
+lego --email you@example.com --dns njalla -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/njalla/njalla_test.go b/providers/dns/njalla/njalla_test.go
index 61f106d75..f1489257b 100644
--- a/providers/dns/njalla/njalla_test.go
+++ b/providers/dns/njalla/njalla_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -96,7 +95,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -110,7 +108,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/nodion/nodion.go b/providers/dns/nodion/nodion.go
index 4bc887568..1fdc8b87d 100644
--- a/providers/dns/nodion/nodion.go
+++ b/providers/dns/nodion/nodion.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/nrdcg/nodion"
)
@@ -94,8 +93,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -172,7 +169,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.zoneIDsMu.Lock()
zoneID, ok := d.zoneIDs[token]
d.zoneIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("nodion: unknown zone ID for '%s' '%s'", info.EffectiveFQDN, token)
}
@@ -208,9 +204,5 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("regru: failed to remove TXT records [domain: %s]: %w", dns01.UnFqdn(authZone), err)
}
- d.zoneIDsMu.Lock()
- delete(d.zoneIDs, token)
- d.zoneIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/nodion/nodion.toml b/providers/dns/nodion/nodion.toml
index c9db46e61..0888f96c3 100644
--- a/providers/dns/nodion/nodion.toml
+++ b/providers/dns/nodion/nodion.toml
@@ -6,7 +6,7 @@ Since = "v4.11.0"
Example = '''
NODION_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns nodion -d '*.example.com' -d example.com run
+lego --email you@example.com --dns nodion -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/nodion/nodion_test.go b/providers/dns/nodion/nodion_test.go
index 0ec5c1627..fbf4b89eb 100644
--- a/providers/dns/nodion/nodion_test.go
+++ b/providers/dns/nodion/nodion_test.go
@@ -34,7 +34,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -92,7 +91,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -106,7 +104,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/ns1/ns1.go b/providers/dns/ns1/ns1.go
index 6a7846e85..c3bf168cb 100644
--- a/providers/dns/ns1/ns1.go
+++ b/providers/dns/ns1/ns1.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"gopkg.in/ns1/ns1-go.v2/rest"
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
)
@@ -81,12 +80,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("ns1: credentials missing")
}
- if config.HTTPClient == nil {
- // Because the rest.NewClient uses the http.DefaultClient.
- config.HTTPClient = &http.Client{Timeout: 10 * time.Second}
- }
-
- client := rest.NewClient(clientdebug.Wrap(config.HTTPClient), rest.SetAPIKey(config.APIKey))
+ client := rest.NewClient(config.HTTPClient, rest.SetAPIKey(config.APIKey))
return &DNSProvider{client: client, config: config}, nil
}
@@ -147,12 +141,10 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
name := dns01.UnFqdn(info.EffectiveFQDN)
-
_, err = d.client.Records.Delete(zone.Zone, name, "TXT")
if err != nil {
return fmt.Errorf("ns1: failed to delete record [zone: %q, domain: %q]: %w", zone.Zone, name, err)
}
-
return nil
}
diff --git a/providers/dns/ns1/ns1.toml b/providers/dns/ns1/ns1.toml
index 829663bf5..2a6b10deb 100644
--- a/providers/dns/ns1/ns1.toml
+++ b/providers/dns/ns1/ns1.toml
@@ -6,7 +6,7 @@ Since = "v0.4.0"
Example = '''
NS1_API_KEY=xxxx \
-lego --dns ns1 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ns1 -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/ns1/ns1_test.go b/providers/dns/ns1/ns1_test.go
index 82fa70c52..6df6b4afb 100644
--- a/providers/dns/ns1/ns1_test.go
+++ b/providers/dns/ns1/ns1_test.go
@@ -37,7 +37,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -97,7 +96,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -111,7 +109,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/octenium/fixtures/add_dns_record.json b/providers/dns/octenium/fixtures/add_dns_record.json
deleted file mode 100644
index 25edcdf11..000000000
--- a/providers/dns/octenium/fixtures/add_dns_record.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "api-status": "success",
- "api-response": {
- "record": {
- "type": "TXT",
- "name": "_acme-challenge.example.com.",
- "ttl": 120,
- "value": "w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI",
- "raw": {
- "txtdata": "w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI"
- }
- }
- }
-}
diff --git a/providers/dns/octenium/fixtures/delete_dns_record.json b/providers/dns/octenium/fixtures/delete_dns_record.json
deleted file mode 100644
index 2aa9415cc..000000000
--- a/providers/dns/octenium/fixtures/delete_dns_record.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "api-status": "success",
- "api-response": {
- "deleted": {
- "count": 1,
- "lines": [
- 123
- ]
- }
- }
-}
diff --git a/providers/dns/octenium/fixtures/list_dns_records.json b/providers/dns/octenium/fixtures/list_dns_records.json
deleted file mode 100644
index 405afff11..000000000
--- a/providers/dns/octenium/fixtures/list_dns_records.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "api-status": "success",
- "api-response": {
- "records": [
- {
- "line": 31,
- "type": "TXT",
- "name": "_dmarc.example.com.",
- "ttl": 300,
- "value": "xxx",
- "raw": {
- "txtdata": "xxx"
- }
- },
- {
- "line": 123,
- "type": "TXT",
- "name": "_acme-challenge.example.com.",
- "ttl": 300,
- "value": "w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI",
- "raw": {
- "txtdata": "w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI"
- }
- }
- ]
- }
-}
diff --git a/providers/dns/octenium/fixtures/list_domains.json b/providers/dns/octenium/fixtures/list_domains.json
deleted file mode 100644
index a62febcda..000000000
--- a/providers/dns/octenium/fixtures/list_domains.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "api-status": "success",
- "api-response": {
- "domains": {
- "2976": {
- "domain-name": "example.com",
- "registration-date": "21\/08\/2025",
- "expiration-date": "-",
- "status": "active"
- }
- }
- }
-}
diff --git a/providers/dns/octenium/internal/client.go b/providers/dns/octenium/internal/client.go
deleted file mode 100644
index 474770aeb..000000000
--- a/providers/dns/octenium/internal/client.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package internal
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- querystring "github.com/google/go-querystring/query"
-)
-
-const defaultBaseURL = "https://api.panel.octenium.com/"
-
-const statusSuccess = "success"
-
-// Client the Octenium API client.
-type Client struct {
- apiKey string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(apiKey string) (*Client, error) {
- if apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- apiKey: apiKey,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-// ListDomains retrieves a list of domains.
-// https://octenium.com/api#tag/Domains/operation/listdomains
-func (c *Client) ListDomains(ctx context.Context, domain string) (map[string]Domain, error) {
- endpoint := c.BaseURL.JoinPath("domains")
-
- data := endpoint.Query()
- data.Set("domain-name", domain)
- endpoint.RawQuery = data.Encode()
-
- req, err := newRequest(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- result := &DomainsResponse{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result.Domains, nil
-}
-
-// ListDNSRecords retrieves a list of DNS records.
-// https://octenium.com/api#tag/Domains-DNS/operation/domains-dns-records-list
-func (c *Client) ListDNSRecords(ctx context.Context, orderID, recordType string) ([]Record, error) {
- endpoint := c.BaseURL.JoinPath("domains", "dns-records", "list")
-
- data := make(url.Values)
- data.Set("order-id", orderID)
- data.Set("types[]", recordType)
-
- req, err := newRequest(ctx, http.MethodPost, endpoint, data)
- if err != nil {
- return nil, err
- }
-
- result := &ListRecordsResponse{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result.Records, nil
-}
-
-// AddDNSRecord adds a DNS record.
-// https://octenium.com/api#tag/Domains-DNS/operation/domains-dns-records-add
-func (c *Client) AddDNSRecord(ctx context.Context, orderID string, record Record) (*Record, error) {
- endpoint := c.BaseURL.JoinPath("domains", "dns-records", "add")
-
- data, err := querystring.Values(record)
- if err != nil {
- return nil, err
- }
-
- data.Set("order-id", orderID)
-
- req, err := newRequest(ctx, http.MethodPost, endpoint, data)
- if err != nil {
- return nil, err
- }
-
- result := &AddRecordResponse{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result.Record, nil
-}
-
-// DeleteDNSRecord deletes a DNS record.
-// https://octenium.com/api#tag/Domains-DNS/operation/domains-dns-records-delete
-func (c *Client) DeleteDNSRecord(ctx context.Context, orderID string, recordID int) (*DeletedRecordInfo, error) {
- endpoint := c.BaseURL.JoinPath("domains", "dns-records", "delete")
-
- data := make(url.Values)
- data.Set("order-id", orderID)
- data.Set("line", strconv.Itoa(recordID))
-
- req, err := newRequest(ctx, http.MethodPost, endpoint, data)
- if err != nil {
- return nil, err
- }
-
- result := &DeleteRecordResponse{}
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result.Deleted, nil
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- req.Header.Set("X-Api-Key", c.apiKey)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- var response APIResponse
-
- err = json.Unmarshal(raw, &response)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- if response.Status != statusSuccess {
- return fmt.Errorf("unexpected status: %s: %s", response.Status, response.Error)
- }
-
- err = json.Unmarshal(response.Response, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, response.Response, err)
- }
-
- return nil
-}
-
-func newRequest(ctx context.Context, method string, endpoint *url.URL, payload url.Values) (*http.Request, error) {
- var body io.Reader = http.NoBody
-
- if method == http.MethodPost && payload != nil {
- body = strings.NewReader(payload.Encode())
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), body)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if method == http.MethodPost && payload != nil {
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- }
-
- return req, nil
-}
diff --git a/providers/dns/octenium/internal/client_test.go b/providers/dns/octenium/internal/client_test.go
deleted file mode 100644
index ff1b21961..000000000
--- a/providers/dns/octenium/internal/client_test.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithAccept("application/json").
- With("X-Api-Key", "secret"),
- )
-}
-
-func TestClient_ListDomains(t *testing.T) {
- client := mockBuilder().
- Route("GET /domains",
- servermock.ResponseFromFixture("list_domains.json"),
- servermock.CheckQueryParameter().Strict().
- With("domain-name", "example.com")).
- Build(t)
-
- domains, err := client.ListDomains(t.Context(), "example.com")
- require.NoError(t, err)
-
- expected := map[string]Domain{
- "2976": {DomainName: "example.com", RegistrationDate: "12/09/2021", ExpirationDate: "12/09/2024", Status: "active"},
- "2977": {DomainName: "example.org", RegistrationDate: "01/10/2021", ExpirationDate: "01/10/2024", Status: "active"},
- "2978": {DomainName: "example.net", RegistrationDate: "21/08/2025", ExpirationDate: "-", Status: "active"},
- }
-
- assert.Equal(t, expected, domains)
-}
-
-func TestClient_ListDomains_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /domains",
- servermock.Noop().WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- _, err := client.ListDomains(t.Context(), "example.com")
- require.EqualError(t, err, "unexpected status code: [status code: 400] body: ")
-}
-
-func TestClient_ListDomains_api_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /domains",
- servermock.ResponseFromFixture("error.json")).
- Build(t)
-
- _, err := client.ListDomains(t.Context(), "example.com")
- require.EqualError(t, err, "unexpected status: error: missing required fields (type, name, ttl)")
-}
-
-func TestClient_ListDNSRecords(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/list",
- servermock.ResponseFromFixture("list_dns_records.json"),
- servermock.CheckHeader().
- WithContentType("application/x-www-form-urlencoded"),
- servermock.CheckForm().Strict().
- With("order-id", "abc").
- With("types[]", "TXT")).
- Build(t)
-
- records, err := client.ListDNSRecords(t.Context(), "abc", "TXT")
- require.NoError(t, err)
-
- expected := []Record{
- {ID: 15, Type: "A", Name: "example.com.", TTL: 14400, Value: "203.0.113.10"},
- {ID: 22, Type: "MX", Name: "example.com.", TTL: 14400, Value: "10 mail.example.com."},
- {ID: 31, Type: "TXT", Name: "_dmarc.example.com.", TTL: 300, Value: "v=DMARC1; p=none; rua=mailto:dmarc@example.com"},
- }
-
- assert.Equal(t, expected, records)
-}
-
-func TestClient_ListDNSRecords_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/list",
- servermock.Noop().WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- _, err := client.ListDNSRecords(t.Context(), "abc", "TXT")
- require.EqualError(t, err, "unexpected status code: [status code: 400] body: ")
-}
-
-func TestClient_ListDNSRecords_api_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/list",
- servermock.ResponseFromFixture("error.json")).
- Build(t)
-
- _, err := client.ListDNSRecords(t.Context(), "abc", "TXT")
- require.EqualError(t, err, "unexpected status: error: missing required fields (type, name, ttl)")
-}
-
-func TestClient_AddDNSRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/add",
- servermock.ResponseFromFixture("add_dns_record.json"),
- servermock.CheckHeader().
- WithContentType("application/x-www-form-urlencoded"),
- servermock.CheckForm().Strict().
- With("order-id", "abc").
- With("name", "example.com.").
- With("ttl", "120").
- With("type", "TXT").
- With("value", "txtTXTtxt")).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "example.com.",
- TTL: 120,
- Value: "txtTXTtxt",
- }
-
- result, err := client.AddDNSRecord(t.Context(), "abc", record)
- require.NoError(t, err)
-
- expected := &Record{
- Type: "A",
- Name: "example.com.",
- TTL: 14400,
- Value: "203.0.113.10",
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_AddDNSRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/add",
- servermock.Noop().WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "example.com.",
- TTL: 120,
- Value: "txtTXTtxt",
- }
-
- _, err := client.AddDNSRecord(t.Context(), "abc", record)
- require.EqualError(t, err, "unexpected status code: [status code: 400] body: ")
-}
-
-func TestClient_AddDNSRecord_api_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/add",
- servermock.ResponseFromFixture("error.json")).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Name: "example.com.",
- TTL: 120,
- Value: "txtTXTtxt",
- }
-
- _, err := client.AddDNSRecord(t.Context(), "abc", record)
- require.EqualError(t, err, "unexpected status: error: missing required fields (type, name, ttl)")
-}
-
-func TestClient_DeleteDNSRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/delete",
- servermock.ResponseFromFixture("delete_dns_record.json"),
- servermock.CheckHeader().
- WithContentType("application/x-www-form-urlencoded"),
- servermock.CheckForm().Strict().
- With("order-id", "abc").
- With("line", "123")).
- Build(t)
-
- result, err := client.DeleteDNSRecord(t.Context(), "abc", 123)
- require.NoError(t, err)
-
- expected := &DeletedRecordInfo{
- Count: 1,
- Lines: []int{15},
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_DeleteDNSRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/delete",
- servermock.Noop().WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- _, err := client.DeleteDNSRecord(t.Context(), "abc", 123)
- require.EqualError(t, err, "unexpected status code: [status code: 400] body: ")
-}
-
-func TestClient_DeleteDNSRecord_api_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/dns-records/delete",
- servermock.ResponseFromFixture("error.json")).
- Build(t)
-
- _, err := client.DeleteDNSRecord(t.Context(), "abc", 123)
- require.EqualError(t, err, "unexpected status: error: missing required fields (type, name, ttl)")
-}
diff --git a/providers/dns/octenium/internal/fixtures/add_dns_record.json b/providers/dns/octenium/internal/fixtures/add_dns_record.json
deleted file mode 100644
index 6c73ea1f9..000000000
--- a/providers/dns/octenium/internal/fixtures/add_dns_record.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "api-status": "success",
- "api-response": {
- "record": {
- "type": "A",
- "name": "example.com.",
- "ttl": 14400,
- "value": "203.0.113.10",
- "raw": {
- "address": "203.0.113.10"
- }
- }
- }
-}
diff --git a/providers/dns/octenium/internal/fixtures/delete_dns_record.json b/providers/dns/octenium/internal/fixtures/delete_dns_record.json
deleted file mode 100644
index 0d4692ffd..000000000
--- a/providers/dns/octenium/internal/fixtures/delete_dns_record.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "api-status": "success",
- "api-response": {
- "deleted": {
- "count": 1,
- "lines": [
- 15
- ]
- }
- }
-}
diff --git a/providers/dns/octenium/internal/fixtures/error.json b/providers/dns/octenium/internal/fixtures/error.json
deleted file mode 100644
index 85a90e425..000000000
--- a/providers/dns/octenium/internal/fixtures/error.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "api-status": "error",
- "api-response": [],
- "api-error": "missing required fields (type, name, ttl)"
-}
diff --git a/providers/dns/octenium/internal/fixtures/list_dns_records.json b/providers/dns/octenium/internal/fixtures/list_dns_records.json
deleted file mode 100644
index 8fa60d86f..000000000
--- a/providers/dns/octenium/internal/fixtures/list_dns_records.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "api-status": "success",
- "api-response": {
- "records": [
- {
- "line": 15,
- "type": "A",
- "name": "example.com.",
- "ttl": 14400,
- "value": "203.0.113.10",
- "raw": {
- "address": "203.0.113.10"
- }
- },
- {
- "line": 22,
- "type": "MX",
- "name": "example.com.",
- "ttl": 14400,
- "value": "10 mail.example.com.",
- "raw": {
- "preference": 10,
- "exchange": "mail.example.com."
- }
- },
- {
- "line": 31,
- "type": "TXT",
- "name": "_dmarc.example.com.",
- "ttl": 300,
- "value": "v=DMARC1; p=none; rua=mailto:dmarc@example.com",
- "raw": {
- "txtdata": "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
- }
- }
- ]
- }
-}
diff --git a/providers/dns/octenium/internal/fixtures/list_domains.json b/providers/dns/octenium/internal/fixtures/list_domains.json
deleted file mode 100644
index b10b705c9..000000000
--- a/providers/dns/octenium/internal/fixtures/list_domains.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "api-status": "success",
- "api-response": {
- "domains": {
- "2976": {
- "domain-name": "example.com",
- "registration-date": "12/09/2021",
- "expiration-date": "12/09/2024",
- "status": "active"
- },
- "2977": {
- "domain-name": "example.org",
- "registration-date": "01/10/2021",
- "expiration-date": "01/10/2024",
- "status": "active"
- },
- "2978": {
- "domain-name": "example.net",
- "registration-date": "21\/08\/2025",
- "expiration-date": "-",
- "status": "active"
- }
- }
- }
-}
diff --git a/providers/dns/octenium/internal/types.go b/providers/dns/octenium/internal/types.go
deleted file mode 100644
index a31e40921..000000000
--- a/providers/dns/octenium/internal/types.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package internal
-
-import "encoding/json"
-
-type APIResponse struct {
- Status string `json:"api-status,omitempty"`
- Response json.RawMessage `json:"api-response,omitempty"`
- Error string `json:"api-error,omitempty"`
-}
-
-type Domain struct {
- DomainName string `json:"domain-name,omitempty"`
- RegistrationDate string `json:"registration-date,omitempty"`
- ExpirationDate string `json:"expiration-date,omitempty"`
- Status string `json:"status,omitempty"`
-}
-
-type Record struct {
- ID int `json:"line,omitempty" url:"-"`
- Type string `json:"type,omitempty" url:"type,omitempty"`
- Name string `json:"name,omitempty" url:"name,omitempty"`
- TTL int `json:"ttl,omitempty" url:"ttl,omitempty"`
- Value string `json:"value,omitempty" url:"value,omitempty"`
-}
-
-type DomainsResponse struct {
- Domains map[string]Domain `json:"domains,omitempty"`
-}
-
-type AddRecordResponse struct {
- Record *Record `json:"record,omitempty"`
-}
-
-type ListRecordsResponse struct {
- Records []Record `json:"records,omitempty"`
-}
-
-type DeleteRecordResponse struct {
- Deleted *DeletedRecordInfo `json:"deleted,omitempty"`
-}
-
-type DeletedRecordInfo struct {
- Count int `json:"count,omitempty"`
- Lines []int `json:"lines,omitempty"`
-}
diff --git a/providers/dns/octenium/octenium.go b/providers/dns/octenium/octenium.go
deleted file mode 100644
index 6032dcce1..000000000
--- a/providers/dns/octenium/octenium.go
+++ /dev/null
@@ -1,204 +0,0 @@
-// Package octenium implements a DNS provider for solving the DNS-01 challenge using Octenium.
-package octenium
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/log"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/octenium/internal"
- "github.com/hashicorp/go-retryablehttp"
-)
-
-// Environment variables names.
-const (
- envNamespace = "OCTENIUM_"
-
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- domainIDs map[string]string
- domainIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Octenium.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("octenium: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Octenium.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("octenium: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIKey)
- if err != nil {
- return nil, fmt.Errorf("octenium: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- retryClient := retryablehttp.NewClient()
- retryClient.RetryMax = 5
- retryClient.HTTPClient = client.HTTPClient
- retryClient.Logger = log.Logger
-
- client.HTTPClient = clientdebug.Wrap(retryClient.StandardClient())
-
- return &DNSProvider{
- config: config,
- client: client,
- domainIDs: make(map[string]string),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("octenium: could not find zone for domain '%s': %w", domain, err)
- }
-
- domainID, err := d.getDomainID(ctx, authZone)
- if err != nil {
- return fmt.Errorf("octenium: get domain ID: %w", err)
- }
-
- d.domainIDsMu.Lock()
- d.domainIDs[token] = domainID
- d.domainIDsMu.Unlock()
-
- record := internal.Record{
- Type: "TXT",
- Name: info.EffectiveFQDN,
- TTL: d.config.TTL,
- Value: info.Value,
- }
-
- _, err = d.client.AddDNSRecord(ctx, domainID, record)
- if err != nil {
- return fmt.Errorf("octenium: add record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- d.domainIDsMu.Lock()
- domainID, ok := d.domainIDs[token]
- d.domainIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("octenium: unknown domain ID for '%s'", info.EffectiveFQDN)
- }
-
- records, err := d.client.ListDNSRecords(ctx, domainID, "TXT")
- if err != nil {
- return fmt.Errorf("octenium: list records: %w", err)
- }
-
- for _, record := range records {
- if record.Type != "TXT" || record.Name != info.EffectiveFQDN || record.Value != info.Value {
- continue
- }
-
- _, err = d.client.DeleteDNSRecord(ctx, domainID, record.ID)
- if err != nil {
- return fmt.Errorf("octenium: delete record: %w", err)
- }
-
- break
- }
-
- d.domainIDsMu.Lock()
- delete(d.domainIDs, token)
- d.domainIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
-
-func (d *DNSProvider) getDomainID(ctx context.Context, authZone string) (string, error) {
- domains, err := d.client.ListDomains(ctx, dns01.UnFqdn(authZone))
- if err != nil {
- return "", fmt.Errorf("list domains: %w", err)
- }
-
- if len(domains) == 0 {
- return "", errors.New("domain not found")
- }
-
- if len(domains) > 1 {
- return "", errors.New("multiple domains found")
- }
-
- for id := range domains {
- return id, nil
- }
-
- return "", errors.New("domain ID not found")
-}
diff --git a/providers/dns/octenium/octenium.toml b/providers/dns/octenium/octenium.toml
deleted file mode 100644
index e3c9d894f..000000000
--- a/providers/dns/octenium/octenium.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Octenium"
-Description = ''''''
-URL = "https://octenium.com/"
-Code = "octenium"
-Since = "v4.27.0"
-
-Example = '''
-OCTENIUM_API_KEY="xxx" \
-lego --dns octenium -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- OCTENIUM_API_KEY = "API key"
- [Configuration.Additional]
- OCTENIUM_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- OCTENIUM_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- OCTENIUM_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- OCTENIUM_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://octenium.com/api#tag/Domains-DNS"
diff --git a/providers/dns/octenium/octenium_test.go b/providers/dns/octenium/octenium_test.go
deleted file mode 100644
index dbb8d64b3..000000000
--- a/providers/dns/octenium/octenium_test.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package octenium
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIKey: "secret",
- },
- },
- {
- desc: "missing API key",
- envVars: map[string]string{
- EnvAPIKey: "",
- },
- expected: "octenium: some credentials information are missing: OCTENIUM_API_KEY",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "octenium: some credentials information are missing: OCTENIUM_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- apiKey: "secret",
- },
- {
- desc: "missing API key",
- expected: "octenium: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "octenium: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIKey = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithAccept("application/json").
- With("X-Api-Key", "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /domains",
- servermock.ResponseFromFixture("list_domains.json"),
- servermock.CheckQueryParameter().Strict().
- With("domain-name", "example.com")).
- Route("POST /domains/dns-records/add",
- servermock.ResponseFromFixture("add_dns_record.json"),
- servermock.CheckHeader().
- WithContentType("application/x-www-form-urlencoded"),
- servermock.CheckForm().Strict().
- With("order-id", "2976").
- With("name", "_acme-challenge.example.com.").
- With("ttl", "120").
- With("type", "TXT").
- With("value", "w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI")).
- Build(t)
-
- err := provider.Present("example.com", "", "foobar")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("POST /domains/dns-records/list",
- servermock.ResponseFromFixture("list_dns_records.json"),
- servermock.CheckHeader().
- WithContentType("application/x-www-form-urlencoded"),
- servermock.CheckForm().Strict().
- With("order-id", "2976").
- With("types[]", "TXT")).
- Route("POST /domains/dns-records/delete",
- servermock.ResponseFromFixture("delete_dns_record.json"),
- servermock.CheckHeader().
- WithContentType("application/x-www-form-urlencoded"),
- servermock.CheckForm().Strict().
- With("order-id", "2976").
- With("line", "123")).
- Build(t)
-
- provider.domainIDs["token"] = "2976"
-
- err := provider.CleanUp("example.com", "token", "foobar")
- require.NoError(t, err)
-}
diff --git a/providers/dns/oraclecloud/configprovider.go b/providers/dns/oraclecloud/configprovider.go
new file mode 100644
index 000000000..7a51811a6
--- /dev/null
+++ b/providers/dns/oraclecloud/configprovider.go
@@ -0,0 +1,97 @@
+package oraclecloud
+
+import (
+ "crypto/rsa"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/go-acme/lego/v4/platform/config/env"
+ "github.com/nrdcg/oci-go-sdk/common/v1065"
+)
+
+type configProvider struct {
+ values map[string]string
+ privateKeyPassphrase string
+}
+
+func newConfigProvider(values map[string]string) *configProvider {
+ return &configProvider{
+ values: values,
+ privateKeyPassphrase: env.GetOrFile(EnvPrivKeyPass),
+ }
+}
+
+func (p *configProvider) PrivateRSAKey() (*rsa.PrivateKey, error) {
+ privateKey, err := getPrivateKey(envPrivKey)
+ if err != nil {
+ return nil, err
+ }
+
+ return common.PrivateKeyFromBytesWithPassword(privateKey, []byte(p.privateKeyPassphrase))
+}
+
+func (p *configProvider) KeyID() (string, error) {
+ tenancy, err := p.TenancyOCID()
+ if err != nil {
+ return "", err
+ }
+
+ user, err := p.UserOCID()
+ if err != nil {
+ return "", err
+ }
+
+ fingerprint, err := p.KeyFingerprint()
+ if err != nil {
+ return "", err
+ }
+
+ return fmt.Sprintf("%s/%s/%s", tenancy, user, fingerprint), nil
+}
+
+func (p *configProvider) TenancyOCID() (value string, err error) {
+ return p.values[EnvTenancyOCID], nil
+}
+
+func (p *configProvider) UserOCID() (string, error) {
+ return p.values[EnvUserOCID], nil
+}
+
+func (p *configProvider) KeyFingerprint() (string, error) {
+ return p.values[EnvPubKeyFingerprint], nil
+}
+
+func (p *configProvider) Region() (string, error) {
+ return p.values[EnvRegion], nil
+}
+
+func (p *configProvider) AuthType() (common.AuthConfig, error) {
+ // Inspired by https://github.com/oracle/oci-go-sdk/blob/e7635c292e60d0a9dcdd3a1e7de180d7c99b1eee/common/configuration.go#L231-L234
+ return common.AuthConfig{AuthType: common.UnknownAuthenticationType}, errors.New("unsupported, keep the interface")
+}
+
+func getPrivateKey(envVar string) ([]byte, error) {
+ envVarValue := os.Getenv(envVar)
+ if envVarValue != "" {
+ bytes, err := base64.StdEncoding.DecodeString(envVarValue)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read base64 value %s (defined by env var %s): %w", envVarValue, envVar, err)
+ }
+ return bytes, nil
+ }
+
+ fileVar := envVar + "_FILE"
+ fileVarValue := os.Getenv(fileVar)
+ if fileVarValue == "" {
+ return nil, fmt.Errorf("no value provided for: %s or %s", envVar, fileVar)
+ }
+
+ fileContents, err := os.ReadFile(fileVarValue)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read the file %s (defined by env var %s): %w", fileVarValue, fileVar, err)
+ }
+
+ return fileContents, nil
+}
diff --git a/providers/dns/oraclecloud/configurationprovider.go b/providers/dns/oraclecloud/configurationprovider.go
deleted file mode 100644
index 97710108c..000000000
--- a/providers/dns/oraclecloud/configurationprovider.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package oraclecloud
-
-import (
- "crypto/rsa"
- "encoding/base64"
- "errors"
- "fmt"
- "os"
- "slices"
- "strings"
-
- "github.com/go-acme/lego/v4/log"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/nrdcg/oci-go-sdk/common/v1065"
-)
-
-type environmentConfigurationProvider struct {
- values map[string]string
-}
-
-func newEnvironmentConfigurationProvider() (*environmentConfigurationProvider, error) {
- values, err := env.GetWithFallback(
- []string{EnvRegion, altEnvTFVarRegion},
- []string{EnvUserOCID, altEnvTFVarUserOCID},
- []string{EnvTenancyOCID, altEnvTFVarTenancyOCID},
- []string{EnvPubKeyFingerprint, altEnvFingerprint, altEnvTFVarFingerprint},
- )
- if err != nil {
- return nil, err
- }
-
- return &environmentConfigurationProvider{
- values: values,
- }, nil
-}
-
-func (p *environmentConfigurationProvider) PrivateRSAKey() (*rsa.PrivateKey, error) {
- privateKey, err := getPrivateKey()
- if err != nil {
- return nil, err
- }
-
- return common.PrivateKeyFromBytesWithPassword(privateKey, []byte(p.privateKeyPassword()))
-}
-
-func (p *environmentConfigurationProvider) KeyID() (string, error) {
- tenancy, err := p.TenancyOCID()
- if err != nil {
- return "", err
- }
-
- user, err := p.UserOCID()
- if err != nil {
- return "", err
- }
-
- fingerprint, err := p.KeyFingerprint()
- if err != nil {
- return "", err
- }
-
- return fmt.Sprintf("%s/%s/%s", tenancy, user, fingerprint), nil
-}
-
-func (p *environmentConfigurationProvider) TenancyOCID() (string, error) {
- return p.values[EnvTenancyOCID], nil
-}
-
-func (p *environmentConfigurationProvider) UserOCID() (string, error) {
- return p.values[EnvUserOCID], nil
-}
-
-func (p *environmentConfigurationProvider) KeyFingerprint() (string, error) {
- return p.values[EnvPubKeyFingerprint], nil
-}
-
-func (p *environmentConfigurationProvider) Region() (string, error) {
- return p.values[EnvRegion], nil
-}
-
-func (p *environmentConfigurationProvider) AuthType() (common.AuthConfig, error) {
- // Inspired by https://github.com/oracle/oci-go-sdk/blob/e7635c292e60d0a9dcdd3a1e7de180d7c99b1eee/common/configuration.go#L231-L234
- return common.AuthConfig{AuthType: common.UnknownAuthenticationType}, errors.New("unsupported, keep the interface")
-}
-
-func (p *environmentConfigurationProvider) privateKeyPassword() string {
- return env.GetOneWithFallback(EnvPrivKeyPass, "", env.ParseString, altEnvPrivateKeyPassword, altEnvTFVarPrivateKeyPassword)
-}
-
-func getPrivateKey() ([]byte, error) {
- base64EnvKeys := []string{envPrivKey, altEnvPrivateKey}
-
- envVarValue := getEnvWithStrictFallback(base64EnvKeys...)
- if envVarValue != "" {
- bytes, err := base64.StdEncoding.DecodeString(envVarValue)
- if err != nil {
- return nil, fmt.Errorf("failed to read base64 value %s (defined by env vars %s): %w", envVarValue,
- strings.Join(base64EnvKeys, " or "), err)
- }
-
- return bytes, nil
- }
-
- fileEnvKeys := []string{EnvPrivKeyFile, altEnvPrivateKeyPath, altEnvTFVarPrivateKeyPath}
-
- fileVarValue := getEnvFileWithStrictFallback(fileEnvKeys...)
- if len(fileVarValue) == 0 {
- return nil, fmt.Errorf("no value provided for: %s",
- strings.Join(slices.Concat(base64EnvKeys, fileEnvKeys), " or "),
- )
- }
-
- return fileVarValue, nil
-}
-
-func getEnvWithStrictFallback(keys ...string) string {
- for _, key := range keys {
- envVarValue := os.Getenv(key)
- if envVarValue != "" {
- return envVarValue
- }
- }
-
- return ""
-}
-
-func getEnvFileWithStrictFallback(keys ...string) []byte {
- for _, key := range keys {
- fileVarValue := os.Getenv(key)
- if fileVarValue == "" {
- continue
- }
-
- fileContents, err := os.ReadFile(fileVarValue)
- if err != nil {
- log.Printf("Failed to read the file %s (defined by env var %s): %s", fileVarValue, key, err)
- return nil
- }
-
- return fileContents
- }
-
- return nil
-}
diff --git a/providers/dns/oraclecloud/fixtures/cert.pem b/providers/dns/oraclecloud/fixtures/cert.pem
deleted file mode 100644
index fc1dcfb53..000000000
--- a/providers/dns/oraclecloud/fixtures/cert.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDHzCCAgegAwIBAgIQKIExaCLIXtXecrT1dWGLszANBgkqhkiG9w0BAQsFADAS
-MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
-MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAwM4wEPHOGAu8tZNNWx3cH6AMuqKwAmB2RwbA3OK034MzhydOjnDm
-igw93eUc4nd3dnICyNpb2rbP9FgGlAuMlJ8raHQkG4DSXF1Bf14neOhLpfBItaX9
-+EB3oO0NupKZhaHrsTKzLGD7bauAPX6PDXuAPp3u5mgGGuZjpLZoKqg3//WImb/2
-xEMVsmvPKTb5FxS/tAMtywjGSUtCTCrudUEh4Gnj6IboVdwYmt539ETDK/Rerxf3
-/GsmEbuOkDUdBixQwLo0U+UAoMOw4zoyQDrrtyUmvffDxI50RAdZDFyFtqZ0ZQa8
-lQqrMdQdf+x1Wb7BKozSktAw4igRP/mknQIDAQABo28wbTAOBgNVHQ8BAf8EBAMC
-AqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
-FgQUcetTliVbYxxutNS8JRkotRY4DRkwFgYDVR0RBA8wDYILZXhhbXBsZS5vcmcw
-DQYJKoZIhvcNAQELBQADggEBAEJP74/XB+12aGQ+EMERIX2Pn6YaaBLt6rTLqV7A
-zFxI9YGIc4xlGa0qkpDhpz6RSypTQG6HN5aZ5b8dz3foMleUVP2cXd8zduc8GQCb
-p4/8PpEhSl6dQb5+mg/qyHGUAaDl40VAbTLXHtn98dhacaJc+TKuXVJAgYRU3Sm3
-wFJxULZSnx+aGdE9s2brOGhvz1fVWnhvWzDvJSM+8xDURz8UiEnimTpV6m3CKItz
-2GatNjM8ADKC7MHQI4I5v4fEwronN/g3NfPfFSmnOKk+lPSAW42WEvhFol+2VvdX
-3p5X2QracSLCIj/DUBebZP9110C8Lj/YfFtOjFokqtQ9Fh4=
------END CERTIFICATE-----
diff --git a/providers/dns/oraclecloud/fixtures/key.pem b/providers/dns/oraclecloud/fixtures/key.pem
deleted file mode 100644
index 1a56bb5a4..000000000
--- a/providers/dns/oraclecloud/fixtures/key.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDAzjAQ8c4YC7y1
-k01bHdwfoAy6orACYHZHBsDc4rTfgzOHJ06OcOaKDD3d5Rzid3d2cgLI2lvats/0
-WAaUC4yUnytodCQbgNJcXUF/Xid46Eul8Ei1pf34QHeg7Q26kpmFoeuxMrMsYPtt
-q4A9fo8Ne4A+ne7maAYa5mOktmgqqDf/9YiZv/bEQxWya88pNvkXFL+0Ay3LCMZJ
-S0JMKu51QSHgaePohuhV3Bia3nf0RMMr9F6vF/f8ayYRu46QNR0GLFDAujRT5QCg
-w7DjOjJAOuu3JSa998PEjnREB1kMXIW2pnRlBryVCqsx1B1/7HVZvsEqjNKS0DDi
-KBE/+aSdAgMBAAECggEAWl2pWJ/ErS9/HIl0NbMKk0YEAUuz/AEzHnoTVdPp22KW
-eY+aOZe/7c7sBj7WqWw98SVhmbsCV0HcuNSzDJtXIedyRGw+6icYMVNCGgzKqlgR
-8K3snjq1DLBGgYXpq9r/Got4ON6e7LttzIqXufrB2JtcUbzbFmGGDwCRjkcyDl9l
-M8ufwD/Xgcd2L8jainU43d2pVxvxUIpRlRdoupCCSlkRYPsXiWlqav7YO4F/Txos
-z3gJyzkXzc3WwfNZdQtEMYwBwozO+Dp2p4TUBr0Ta3MbfrKfDoTs4XT/Ce9IwJJS
-/h6E9cxZD8t5oMT50quFjwhHBKodMiUqIlh2YQEAbwKBgQDIULzo/tgDgTwveyEn
-L9n8yVbEh/SfrE9QtXcjkDB5+tYmIsIaz16NRWlAqnJVGZvcanrCq7ZTxgUcs/hW
-Ag+sfWkeg7lmfeJAkiZ6kmi1h2qJjXMOBri+Cm6MTOsE6qdIc3eT4PnYkNpV7o6S
-70hWNncVadXLV4Thm9BLAbMbQwKBgQD2ZwKe/2zRQcbuBe1loF0HWIsJPxcKQ3LH
-hVf7f0YLQlIuzOhK8TQXgM0G4hxLlk1XeLjgf3z4Ju7hfh2JQLor1QYPRGUj66SX
-KTE5eDwE0yEX1c9m5PW6M+f8vkOU4LQ/OtPw5OrKyYxpLf9dp42nmDYY/8IvUk96
-iKZNY1sSnwKBgQC27tS2SxVmjf0yt1WdfdurOQueSzKhJzD/2djFh4Zdvy8WgKOW
-7E3C4eKvBXmIMezeq/cUFNBbTPmaLtjZYuSBd74p+c20xb17jnzJby9kqBgpKh4q
-bwUDuG8gfZYbVVgTmC9ZwxkoJ5Dc7RETKqZ65R53VcHDA1f82Nitxw2UFQKBgBDl
-c2qPvViEGC4OPf8wBfERA0e5Cc1sXpyL6kKWsajn/Va0OmGZNKc/788/Bg2w2tDa
-uGK8m0cw9ESGL2RQCfQjgWzelcjmybyL2JJGSmdSSvylbrlxjeAc2xWbvmqhFfsX
-/5yPNgJ926ECxHYZnT8W0u7X6urvy/9tC2pXG9GlAoGBAKOAfij4fMbHY+Z1m825
-VhY110FDnePYFJWmExP8GAVqOzhCs0mzyCnYh6nvS/OY8moH2LOuwPUlDfF3IzyT
-hTUuXnykWT3w40eYQXXIaXEGhue+guL8ch16vEEJy5ltwEdIPNMTErbqAAk2W6Ps
-NB46HzETzEIWnzoamX6iQVWj
------END PRIVATE KEY-----
diff --git a/providers/dns/oraclecloud/oraclecloud.go b/providers/dns/oraclecloud/oraclecloud.go
index 730b3f212..2fb392e3e 100644
--- a/providers/dns/oraclecloud/oraclecloud.go
+++ b/providers/dns/oraclecloud/oraclecloud.go
@@ -11,9 +11,7 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/nrdcg/oci-go-sdk/common/v1065"
- "github.com/nrdcg/oci-go-sdk/common/v1065/auth"
"github.com/nrdcg/oci-go-sdk/dns/v1065"
)
@@ -21,22 +19,14 @@ import (
const (
envNamespace = "OCI_"
- EnvAuthType = envNamespace + "AUTH_TYPE"
-
- EnvCompartmentOCID = envNamespace + "COMPARTMENT_OCID"
- EnvRegion = envNamespace + "REGION"
-
+ EnvCompartmentOCID = envNamespace + "COMPARTMENT_OCID"
envPrivKey = envNamespace + "PRIVKEY"
EnvPrivKeyFile = envPrivKey + "_FILE"
EnvPrivKeyPass = envPrivKey + "_PASS"
EnvTenancyOCID = envNamespace + "TENANCY_OCID"
EnvUserOCID = envNamespace + "USER_OCID"
EnvPubKeyFingerprint = envNamespace + "PUBKEY_FINGERPRINT"
-
- altEnvPrivateKey = envNamespace + "PRIVATE_KEY" // alias on OCI_PRIVKEY
- altEnvPrivateKeyPath = altEnvPrivateKey + "_PATH" // alias on OCI_PRIVKEY_FILE
- altEnvPrivateKeyPassword = altEnvPrivateKey + "_PASSWORD" // alias on OCI_PRIVKEY_PASS
- altEnvFingerprint = envNamespace + "FINGERPRINT" // alias on OCI_PUBKEY_FINGERPRINT
+ EnvRegion = envNamespace + "REGION"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@@ -44,25 +34,12 @@ const (
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
-// https://github.com/oracle/oci-go-sdk/blob/7f425f74c74fd0c6a5acb74466c85eb5346e0092/common/client.go#L350
-// https://github.com/oracle/oci-go-sdk/blob/7f425f74c74fd0c6a5acb74466c85eb5346e0092/common/configuration.go#L174-L175
-const (
- altEnvTFVarNamespace = "TF_VAR_"
- altEnvTFVarRegion = altEnvTFVarNamespace + "region" // alias on OCI_REGION
- altEnvTFVarFingerprint = altEnvTFVarNamespace + "fingerprint" // alias on OCI_PUBKEY_FINGERPRINT
- altEnvTFVarUserOCID = altEnvTFVarNamespace + "user_ocid" // alias on OCI_USER_OCID
- altEnvTFVarTenancyOCID = altEnvTFVarNamespace + "tenancy_ocid" // alias on OCI_TENANCY_OCID
- altEnvTFVarPrivateKeyPath = altEnvTFVarNamespace + "private_key_path" // alias on OCI_PRIVKEY_FILE
- altEnvTFVarPrivateKeyPassword = altEnvTFVarNamespace + "private_key_password" // alias on OCI_PRIVKEY_PASS
-)
-
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- CompartmentID string
- OCIConfigProvider common.ConfigurationProvider
-
+ CompartmentID string
+ OCIConfigProvider common.ConfigurationProvider
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
@@ -89,42 +66,15 @@ type DNSProvider struct {
// NewDNSProvider returns a DNSProvider instance configured for OracleCloud.
func NewDNSProvider() (*DNSProvider, error) {
- config := NewDefaultConfig()
-
- switch env.GetOrFile(EnvAuthType) {
- case string(common.InstancePrincipal):
- values, err := env.Get(EnvCompartmentOCID)
- if err != nil {
- return nil, fmt.Errorf("oraclecloud: %w", err)
- }
-
- config.CompartmentID = values[EnvCompartmentOCID]
-
- region := env.GetOneWithFallback(EnvRegion, "", env.ParseString, altEnvTFVarRegion)
-
- configurationProvider, err := auth.InstancePrincipalConfigurationProviderForRegion(common.Region(region))
- if err != nil {
- return nil, fmt.Errorf("oraclecloud: %w", err)
- }
-
- config.OCIConfigProvider = configurationProvider
-
- default:
- values, err := env.Get(EnvCompartmentOCID)
- if err != nil {
- return nil, fmt.Errorf("oraclecloud: %w", err)
- }
-
- config.CompartmentID = values[EnvCompartmentOCID]
-
- ecp, err := newEnvironmentConfigurationProvider()
- if err != nil {
- return nil, fmt.Errorf("oraclecloud: %w", err)
- }
-
- config.OCIConfigProvider = ecp
+ values, err := env.Get(envPrivKey, EnvTenancyOCID, EnvUserOCID, EnvPubKeyFingerprint, EnvRegion, EnvCompartmentOCID)
+ if err != nil {
+ return nil, fmt.Errorf("oraclecloud: %w", err)
}
+ config := NewDefaultConfig()
+ config.CompartmentID = values[EnvCompartmentOCID]
+ config.OCIConfigProvider = newConfigProvider(values)
+
return NewDNSProviderConfig(config)
}
@@ -148,7 +98,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}
if config.HTTPClient != nil {
- client.HTTPClient = clientdebug.Wrap(config.HTTPClient)
+ client.HTTPClient = config.HTTPClient
}
return &DNSProvider{client: &client, config: config}, nil
@@ -218,7 +168,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var deleteHash *string
-
for _, record := range domainRecords.Items {
if record.Rdata != nil && *record.Rdata == `"`+info.Value+`"` {
deleteHash = record.RecordHash
diff --git a/providers/dns/oraclecloud/oraclecloud.toml b/providers/dns/oraclecloud/oraclecloud.toml
index f6155052e..8c756a374 100644
--- a/providers/dns/oraclecloud/oraclecloud.toml
+++ b/providers/dns/oraclecloud/oraclecloud.toml
@@ -5,39 +5,26 @@ Code = "oraclecloud"
Since = "v2.3.0"
Example = '''
-# Using API Key authentication:
-OCI_PRIVATE_KEY_PATH="~/.oci/oci_api_key.pem" \
-OCI_PRIVATE_KEY_PASSWORD="secret" \
+OCI_PRIVKEY_FILE="~/.oci/oci_api_key.pem" \
+OCI_PRIVKEY_PASS="secret" \
OCI_TENANCY_OCID="ocid1.tenancy.oc1..secret" \
OCI_USER_OCID="ocid1.user.oc1..secret" \
-OCI_FINGERPRINT="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" \
+OCI_PUBKEY_FINGERPRINT="00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" \
OCI_REGION="us-phoenix-1" \
OCI_COMPARTMENT_OCID="ocid1.tenancy.oc1..secret" \
-lego --dns oraclecloud -d '*.example.com' -d example.com run
-
-# Using Instance Principal authentication (when running on OCI compute instances):
-# https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm
-OCI_AUTH_TYPE="instance_principal" \
-OCI_COMPARTMENT_OCID="ocid1.tenancy.oc1..secret" \
-lego --dns oraclecloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns oraclecloud -d '*.example.com' -d example.com run
'''
[Configuration]
[Configuration.Credentials]
+ OCI_PRIVKEY_FILE = "Private key file"
+ OCI_PRIVKEY_PASS = "Private key password"
+ OCI_TENANCY_OCID = "Tenancy OCID"
+ OCI_USER_OCID = "User OCID"
+ OCI_PUBKEY_FINGERPRINT = "Public key fingerprint"
+ OCI_REGION = "Region"
OCI_COMPARTMENT_OCID = "Compartment OCID"
- OCI_REGION = "Region (it can be empty if `OCI_AUTH_TYPE=instance_principal`)."
- OCI_PRIVATE_KEY_PATH = "Private key file (ignored if `OCI_AUTH_TYPE=instance_principal`)"
- OCI_PRIVATE_KEY_PASSWORD = "Private key password (ignored if `OCI_AUTH_TYPE=instance_principal`)"
- OCI_TENANCY_OCID = "Tenancy OCID (ignored if `OCI_AUTH_TYPE=instance_principal`)"
- OCI_USER_OCID = "User OCID (ignored if `OCI_AUTH_TYPE=instance_principal`)"
- OCI_FINGERPRINT = "Public key fingerprint (ignored if `OCI_AUTH_TYPE=instance_principal`)"
[Configuration.Additional]
- OCI_AUTH_TYPE = "Authorization type. Possible values: 'instance_principal', '' (Default: '')"
- TF_VAR_region = "Alias on `OCI_REGION`"
- TF_VAR_fingerprint = "Alias on `OCI_FINGERPRINT`"
- TF_VAR_user_ocid = "Alias on `OCI_USER_OCID`"
- TF_VAR_tenancy_ocid = "Alias on `OCI_TENANCY_OCID`"
- TF_VAR_private_key_path = "Alias on `OCI_PRIVATE_KEY_PATH`"
OCI_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
OCI_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
OCI_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
diff --git a/providers/dns/oraclecloud/oraclecloud_test.go b/providers/dns/oraclecloud/oraclecloud_test.go
index 74ee06eac..5d35c01a8 100644
--- a/providers/dns/oraclecloud/oraclecloud_test.go
+++ b/providers/dns/oraclecloud/oraclecloud_test.go
@@ -6,31 +6,19 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
- "maps"
- "net/http/httptest"
"os"
"testing"
"time"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/nrdcg/oci-go-sdk/common/v1065"
"github.com/stretchr/testify/require"
)
const envDomain = envNamespace + "DOMAIN"
-// Used by Instance Principal authentication.
-const (
- envMetadataBaseURL = "OCI_METADATA_BASE_URL"
- envSDKAuthClientRegionURL = "OCI_SDK_AUTH_CLIENT_REGION_URL"
-)
-
var envTest = tester.NewEnvTest(
envPrivKey,
- EnvAuthType,
- envMetadataBaseURL,
- envSDKAuthClientRegionURL,
EnvPrivKeyFile,
EnvPrivKeyPass,
EnvTenancyOCID,
@@ -61,7 +49,7 @@ func TestNewDNSProvider(t *testing.T) {
{
desc: "success file",
envVars: map[string]string{
- EnvPrivKeyFile: mustGeneratePrivateKeyFile(t, "secret1"),
+ EnvPrivKeyFile: mustGeneratePrivateKeyFile("secret1"),
EnvPrivKeyPass: "secret1",
EnvTenancyOCID: "ocid1.tenancy.oc1..secret",
EnvUserOCID: "ocid1.user.oc1..secret",
@@ -73,7 +61,7 @@ func TestNewDNSProvider(t *testing.T) {
{
desc: "missing credentials",
envVars: map[string]string{},
- expected: "oraclecloud: some credentials information are missing: OCI_COMPARTMENT_OCID",
+ expected: "oraclecloud: some credentials information are missing: OCI_PRIVKEY,OCI_TENANCY_OCID,OCI_USER_OCID,OCI_PUBKEY_FINGERPRINT,OCI_REGION,OCI_COMPARTMENT_OCID",
},
{
desc: "missing CompartmentID",
@@ -99,7 +87,7 @@ func TestNewDNSProvider(t *testing.T) {
EnvRegion: "us-phoenix-1",
EnvCompartmentOCID: "123",
},
- expected: "oraclecloud: can not create client, bad configuration: no value provided for: OCI_PRIVKEY or OCI_PRIVATE_KEY or OCI_PRIVKEY_FILE or OCI_PRIVATE_KEY_PATH or TF_VAR_private_key_path",
+ expected: "oraclecloud: some credentials information are missing: OCI_PRIVKEY",
},
{
desc: "missing OCI_PRIVKEY_PASS",
@@ -188,10 +176,8 @@ func TestNewDNSProvider(t *testing.T) {
if privKeyFile != "" {
_ = os.Remove(privKeyFile)
}
-
envTest.RestoreEnv()
}()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -211,74 +197,6 @@ func TestNewDNSProvider(t *testing.T) {
}
}
-func TestNewDNSProvider_instance_principal(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAuthType: "instance_principal",
- EnvCompartmentOCID: "123",
- },
- },
- {
- desc: "missing CompartmentID",
- envVars: map[string]string{
- EnvAuthType: "instance_principal",
- },
- expected: "oraclecloud: some credentials information are missing: OCI_COMPARTMENT_OCID",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer func() {
- envTest.RestoreEnv()
- }()
-
- envTest.ClearEnv()
-
- serverURL := servermock.NewBuilder(
- func(server *httptest.Server) (string, error) {
- return server.URL, nil
- }).
- Route("GET /instance/region", servermock.RawStringResponse("oc1")).
- // To generate fake certificates:
- // go run `go env GOROOT`/src/crypto/tls/generate_cert.go --host example.org --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
- Route("GET /identity/cert.pem", servermock.ResponseFromFixture("cert.pem")).
- Route("GET /identity/key.pem", servermock.ResponseFromFixture("key.pem")).
- Route("GET /identity/intermediate.pem", servermock.ResponseFromFixture("cert.pem")).
- // https://github.com/oracle/oci-go-sdk/blob/413a2f277f95c5eb76e26a0e0833c396a518bf50/common/auth/jwt_test.go#L12
- Route("POST /v1/x509", servermock.RawStringResponse(`{"token":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFzdyIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJvcGMub3JhY2xlLmNvbSIsImV4cCI6MTUxMTgzODc5MywiaWF0IjoxNTExODE3MTkzLCJpc3MiOiJhdXRoU2VydmljZS5vcmFjbGUuY29tIiwib3BjLWNlcnR0eXBlIjoiaW5zdGFuY2UiLCJvcGMtY29tcGFydG1lbnQiOiJvY2lkMS5jb21wYXJ0bWVudC5vYzEuLmJsdWhibHVoYmx1aCIsIm9wYy1pbnN0YW5jZSI6Im9jaWQxLmluc3RhbmNlLm9jMS5waHguYmx1aGJsdWhibHVoIiwib3BjLXRlbmFudCI6Im9jaWR2MTp0ZW5hbmN5Om9jMTpwaHg6MTIzNDU2Nzg5MDpibHVoYmx1aGJsdWgiLCJwdHlwZSI6Imluc3RhbmNlIiwic3ViIjoib2NpZDEuaW5zdGFuY2Uub2MxLnBoeC5ibHVoYmx1aGJsdWgiLCJ0ZW5hbnQiOiJvY2lkdjE6dGVuYW5jeTpvYzE6cGh4OjEyMzQ1Njc4OTA6Ymx1aGJsdWhibHVoIiwidHR5cGUiOiJ4NTA5In0.zen7q2yJSpMjzH4ym_H7VEwZA0-vTT4Wcild-HRfLxX6A1ej4tlpACa7A24j5JoZYI4mHooZVJ8e7ZezFenK0zZx5j8RbIjsqJKwroYXExOiBXLCUwMWOLXIndEsUzzGLqnPfKHXd80vrhMLmtkVTCJqBMzvPUSYkH_ciWgmjP9m0YETdQ9ifghkADhZGt9IlnOswg0s3Bx9ASwxFZEtom0BmU9GwEuITTTZfKvndk785BlNeZMOjhovaD97-LYpv5B_PiWEz8zialK5zxjijLCw06zyA8CQRQqmVCagNUPilfz_BcPyImzvFDuzQcPyDkTcsB7weX35tafHmA_Ul"}`)).
- Build(t)
-
- envVars := map[string]string{
- envMetadataBaseURL: serverURL,
- envSDKAuthClientRegionURL: serverURL,
- }
-
- maps.Copy(envVars, test.envVars)
-
- envTest.Apply(envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.Error(t, err)
- require.Contains(t, err.Error(), test.expected)
- }
- })
- }
-}
-
func TestNewDNSProviderConfig(t *testing.T) {
envTest.ClearEnv()
defer envTest.RestoreEnv()
@@ -333,7 +251,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -347,7 +264,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -357,20 +273,21 @@ func TestLiveCleanUp(t *testing.T) {
require.NoError(t, err)
}
-func mockConfigurationProvider(keyPassphrase string) *environmentConfigurationProvider {
+func mockConfigurationProvider(keyPassphrase string) *configProvider {
envTest.Apply(map[string]string{
envPrivKey: mustGeneratePrivateKey("secret"),
})
- return &environmentConfigurationProvider{
+ return &configProvider{
values: map[string]string{
EnvCompartmentOCID: "test",
- EnvPrivKeyPass: keyPassphrase,
+ EnvPrivKeyPass: "test",
EnvTenancyOCID: "test",
EnvUserOCID: "test",
EnvPubKeyFingerprint: "test",
EnvRegion: "test",
},
+ privateKeyPassphrase: keyPassphrase,
}
}
@@ -383,21 +300,21 @@ func mustGeneratePrivateKey(pwd string) string {
return base64.StdEncoding.EncodeToString(pem.EncodeToMemory(block))
}
-func mustGeneratePrivateKeyFile(t *testing.T, pwd string) string {
- t.Helper()
-
+func mustGeneratePrivateKeyFile(pwd string) string {
block, err := generatePrivateKey(pwd)
- require.NoError(t, err)
+ if err != nil {
+ panic(err)
+ }
- file, err := os.CreateTemp(t.TempDir(), "lego_oci_*.pem")
- require.NoError(t, err)
-
- defer func() {
- _ = file.Close()
- }()
+ file, err := os.CreateTemp("", "lego_oci_*.pem")
+ if err != nil {
+ panic(err)
+ }
err = pem.Encode(file, block)
- require.NoError(t, err)
+ if err != nil {
+ panic(err)
+ }
return file.Name()
}
diff --git a/providers/dns/otc/internal/client.go b/providers/dns/otc/internal/client.go
index adb0682e1..e3e225314 100644
--- a/providers/dns/otc/internal/client.go
+++ b/providers/dns/otc/internal/client.go
@@ -42,8 +42,8 @@ func NewClient(username, password, domainName, projectName string) *Client {
}
}
-func (c *Client) GetZoneID(ctx context.Context, zone string, privateZone bool) (string, error) {
- zonesResp, err := c.getZones(ctx, zone, privateZone)
+func (c *Client) GetZoneID(ctx context.Context, zone string) (string, error) {
+ zonesResp, err := c.getZones(ctx, zone)
if err != nil {
return "", err
}
@@ -62,18 +62,13 @@ func (c *Client) GetZoneID(ctx context.Context, zone string, privateZone bool) (
}
// https://docs.otc.t-systems.com/domain-name-service/api-ref/apis/public_zone_management/querying_public_zones.html
-func (c *Client) getZones(ctx context.Context, zone string, privateZone bool) (*ZonesResponse, error) {
+func (c *Client) getZones(ctx context.Context, zone string) (*ZonesResponse, error) {
c.muBaseURL.Lock()
endpoint := c.baseURL.JoinPath("zones")
c.muBaseURL.Unlock()
query := endpoint.Query()
query.Set("name", zone)
-
- if privateZone {
- query.Set("type", "private")
- }
-
endpoint.RawQuery = query.Encode()
req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
@@ -82,7 +77,6 @@ func (c *Client) getZones(ctx context.Context, zone string, privateZone bool) (*
}
var zones ZonesResponse
-
err = c.do(req, &zones)
if err != nil {
return nil, err
@@ -129,7 +123,6 @@ func (c *Client) getRecordSet(ctx context.Context, zoneID, fqdn string) (*Record
}
var recordSetsRes RecordSetsResponse
-
err = c.do(req, &recordSetsRes)
if err != nil {
return nil, err
@@ -170,11 +163,9 @@ func (c *Client) DeleteRecordSet(ctx context.Context, zoneID, recordID string) e
func (c *Client) do(req *http.Request, result any) error {
c.muToken.Lock()
-
if c.token != "" {
req.Header.Set("X-Auth-Token", c.token)
}
-
c.muToken.Unlock()
resp, err := c.HTTPClient.Do(req)
diff --git a/providers/dns/otc/internal/client_test.go b/providers/dns/otc/internal/client_test.go
index 74b5bb3af..ea3835a56 100644
--- a/providers/dns/otc/internal/client_test.go
+++ b/providers/dns/otc/internal/client_test.go
@@ -33,22 +33,7 @@ func TestClient_GetZoneID(t *testing.T) {
With("name", "example.com.")).
Build(t)
- zoneID, err := client.GetZoneID(context.Background(), "example.com.", false)
- require.NoError(t, err)
-
- assert.Equal(t, "123123", zoneID)
-}
-
-func TestClient_GetZoneID_private(t *testing.T) {
- client := mockBuilder().
- Route("GET /zones",
- servermock.ResponseFromFixture("zones_GET.json"),
- servermock.CheckQueryParameter().Strict().
- With("name", "example.com.").
- With("type", "private")).
- Build(t)
-
- zoneID, err := client.GetZoneID(context.Background(), "example.com.", true)
+ zoneID, err := client.GetZoneID(context.Background(), "example.com.")
require.NoError(t, err)
assert.Equal(t, "123123", zoneID)
@@ -62,7 +47,7 @@ func TestClient_GetZoneID_error(t *testing.T) {
With("name", "example.com.")).
Build(t)
- _, err := client.GetZoneID(context.Background(), "example.com.", false)
+ _, err := client.GetZoneID(context.Background(), "example.com.")
require.EqualError(t, err, "zone example.com. not found")
}
@@ -99,8 +84,7 @@ func TestClient_GetRecordSetID_error(t *testing.T) {
func TestClient_CreateRecordSet(t *testing.T) {
client := mockBuilder().
Route("POST /zones/123123/recordsets",
- servermock.ResponseFromFixture("zones-recordsets_POST.json"),
- servermock.CheckRequestJSONBodyFromFixture("zones-recordsets_POST-request.json")).
+ servermock.ResponseFromFixture("zones-recordsets_POST.json")).
Build(t)
rs := RecordSets{
@@ -108,7 +92,7 @@ func TestClient_CreateRecordSet(t *testing.T) {
Description: "Added TXT record for ACME dns-01 challenge using lego client",
Type: "TXT",
TTL: 300,
- Records: []string{strconv.Quote("ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY")},
+ Records: []string{strconv.Quote("w6uP8Tcg6K2QR905Rms8iXTlksL6OD1KOWBxTK7wxPI")},
}
err := client.CreateRecordSet(context.Background(), "123123", rs)
require.NoError(t, err)
diff --git a/providers/dns/otc/internal/fixtures/zones-recordsets_POST-request.json b/providers/dns/otc/internal/fixtures/zones-recordsets_POST-request.json
deleted file mode 100644
index 41cab72a8..000000000
--- a/providers/dns/otc/internal/fixtures/zones-recordsets_POST-request.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "_acme-challenge.example.com.",
- "description": "Added TXT record for ACME dns-01 challenge using lego client",
- "type": "TXT",
- "ttl": 300,
- "records": [
- "\"ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY\""
- ]
-}
diff --git a/providers/dns/otc/internal/identity.go b/providers/dns/otc/internal/identity.go
index 154ec65e2..f9e7cb08f 100644
--- a/providers/dns/otc/internal/identity.go
+++ b/providers/dns/otc/internal/identity.go
@@ -46,7 +46,6 @@ func (c *Client) Login(ctx context.Context) error {
c.muToken.Lock()
defer c.muToken.Unlock()
-
c.token = token
if c.token == "" {
@@ -97,7 +96,6 @@ func (c *Client) obtainUserToken(ctx context.Context, payload LoginRequest) (*To
}
var newToken TokenResponse
-
err = json.Unmarshal(raw, &newToken)
if err != nil {
return nil, "", errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -108,7 +106,6 @@ func (c *Client) obtainUserToken(ctx context.Context, payload LoginRequest) (*To
func getBaseURL(tokenResp *TokenResponse) (*url.URL, error) {
var endpoints []Endpoint
-
for _, v := range tokenResp.Token.Catalog {
if v.Type == "dns" {
endpoints = append(endpoints, v.Endpoints...)
diff --git a/providers/dns/otc/internal/types.go b/providers/dns/otc/internal/types.go
index e7bfe8fcb..38da4f110 100644
--- a/providers/dns/otc/internal/types.go
+++ b/providers/dns/otc/internal/types.go
@@ -41,8 +41,8 @@ type TokenResponse struct {
}
type Token struct {
- User UserR `json:"user"`
- Domain Domain `json:"domain"`
+ User UserR `json:"user,omitempty"`
+ Domain Domain `json:"domain,omitempty"`
Catalog []Catalog `json:"catalog,omitempty"`
Methods []string `json:"methods,omitempty"`
Roles []Role `json:"roles,omitempty"`
@@ -59,7 +59,7 @@ type Catalog struct {
type UserR struct {
ID string `json:"id,omitempty"`
- Domain Domain `json:"domain"`
+ Domain Domain `json:"domain,omitempty"`
Name string `json:"name,omitempty"`
PasswordExpiresAt string `json:"password_expires_at,omitempty"`
}
@@ -106,7 +106,7 @@ type RecordSets struct {
// ZonesResponse
type ZonesResponse struct {
- Links Links `json:"links"`
+ Links Links `json:"links,omitempty"`
Zones []Zone `json:"zones"`
Metadata Metadata `json:"metadata"`
}
diff --git a/providers/dns/otc/otc.go b/providers/dns/otc/otc.go
index 65b362124..3569e6343 100644
--- a/providers/dns/otc/otc.go
+++ b/providers/dns/otc/otc.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/otc/internal"
)
@@ -24,7 +23,6 @@ const (
EnvPassword = envNamespace + "PASSWORD"
EnvProjectName = envNamespace + "PROJECT_NAME"
EnvIdentityEndpoint = envNamespace + "IDENTITY_ENDPOINT"
- EnvPrivateZone = envNamespace + "PRIVATE_ZONE"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@@ -42,13 +40,11 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- DomainName string
- ProjectName string
- UserName string
- Password string
- IdentityEndpoint string
- PrivateZone bool
-
+ IdentityEndpoint string
+ DomainName string
+ ProjectName string
+ UserName string
+ Password string
PropagationTimeout time.Duration
PollingInterval time.Duration
SequenceInterval time.Duration
@@ -69,12 +65,10 @@ func NewDefaultConfig() *Config {
tr.DisableKeepAlives = true
return &Config{
- PrivateZone: env.GetOrDefaultBool(EnvPrivateZone, false),
- IdentityEndpoint: env.GetOrDefaultString(EnvIdentityEndpoint, defaultIdentityEndpoint),
-
TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
+ IdentityEndpoint: env.GetOrDefaultString(EnvIdentityEndpoint, defaultIdentityEndpoint),
SequenceInterval: env.GetOrDefaultSecond(EnvSequenceInterval, dns01.DefaultPropagationTimeout),
HTTPClient: &http.Client{
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 10*time.Second),
@@ -131,8 +125,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
@@ -152,7 +144,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("otc: %w", err)
}
- zoneID, err := d.client.GetZoneID(ctx, authZone, d.config.PrivateZone)
+ zoneID, err := d.client.GetZoneID(ctx, authZone)
if err != nil {
return fmt.Errorf("otc: unable to get zone: %w", err)
}
@@ -189,7 +181,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("otc: %w", err)
}
- zoneID, err := d.client.GetZoneID(ctx, authZone, d.config.PrivateZone)
+ zoneID, err := d.client.GetZoneID(ctx, authZone)
if err != nil {
return fmt.Errorf("otc: %w", err)
}
diff --git a/providers/dns/otc/otc.toml b/providers/dns/otc/otc.toml
index e63077fda..cb1910d26 100644
--- a/providers/dns/otc/otc.toml
+++ b/providers/dns/otc/otc.toml
@@ -4,13 +4,7 @@ URL = "https://cloud.telekom.de/en"
Code = "otc"
Since = "v0.4.1"
-Example = '''
-OTC_DOMAIN_NAME=domain_name \
-OTC_USER_NAME=user_name \
-OTC_PASSWORD=password \
-OTC_PROJECT_NAME=project_name \
-lego --dns otc -d '*.example.com' -d example.com run
-'''
+Example = ''''''
[Configuration]
[Configuration.Credentials]
@@ -18,9 +12,8 @@ lego --dns otc -d '*.example.com' -d example.com run
OTC_PASSWORD = "Password"
OTC_PROJECT_NAME = "Project name"
OTC_DOMAIN_NAME = "Domain name"
+ OTC_IDENTITY_ENDPOINT = "Identity endpoint URL"
[Configuration.Additional]
- OTC_IDENTITY_ENDPOINT = "Identity endpoint URL (default: https://iam.eu-de.otc.t-systems.com:443/v3/auth/tokens)"
- OTC_PRIVATE_ZONE = "Set to true to use private zones only (default: use public zones only)"
OTC_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
OTC_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
OTC_SEQUENCE_INTERVAL = "Time between sequential requests in seconds (Default: 60)"
diff --git a/providers/dns/otc/otc_test.go b/providers/dns/otc/otc_test.go
index 518ce0f19..c8b32bc78 100644
--- a/providers/dns/otc/otc_test.go
+++ b/providers/dns/otc/otc_test.go
@@ -18,7 +18,6 @@ var envTest = tester.NewEnvTest(
EnvDomainName,
EnvUserName,
EnvPassword,
- EnvPrivateZone,
EnvProjectName,
EnvIdentityEndpoint).
WithDomain(envDomain)
@@ -93,7 +92,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -192,7 +190,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -206,7 +203,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -217,30 +213,12 @@ func TestLiveCleanUp(t *testing.T) {
}
func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder(false).
+ provider := mockBuilder().
Route("GET /v2/zones",
servermock.ResponseFromInternal("zones_GET.json"),
servermock.CheckQueryParameter().Strict().
With("name", "example.com.")).
- Route("POST /v2/zones/123123/recordsets",
- servermock.Noop(),
- servermock.CheckRequestJSONBodyFromInternal("zones-recordsets_POST-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_Present_private(t *testing.T) {
- provider := mockBuilder(true).
- Route("GET /v2/zones",
- servermock.ResponseFromInternal("zones_GET.json"),
- servermock.CheckQueryParameter().Strict().
- With("name", "example.com.").
- With("type", "private")).
- Route("POST /v2/zones/123123/recordsets",
- servermock.Noop(),
- servermock.CheckRequestJSONBodyFromInternal("zones-recordsets_POST-request.json")).
+ Route("/", servermock.DumpRequest()).
Build(t)
err := provider.Present("example.com", "", "123d==")
@@ -248,11 +226,12 @@ func TestDNSProvider_Present_private(t *testing.T) {
}
func TestDNSProvider_Present_emptyZone(t *testing.T) {
- provider := mockBuilder(false).
+ provider := mockBuilder().
Route("GET /v2/zones",
servermock.ResponseFromInternal("zones_GET_empty.json"),
servermock.CheckQueryParameter().Strict().
With("name", "example.com.")).
+ Route("/", servermock.DumpRequest()).
Build(t)
err := provider.Present("example.com", "", "123d==")
@@ -260,7 +239,7 @@ func TestDNSProvider_Present_emptyZone(t *testing.T) {
}
func TestDNSProvider_Cleanup(t *testing.T) {
- provider := mockBuilder(false).
+ provider := mockBuilder().
Route("GET /v2/zones",
servermock.ResponseFromInternal("zones_GET.json"),
servermock.CheckQueryParameter().Strict().
@@ -278,28 +257,8 @@ func TestDNSProvider_Cleanup(t *testing.T) {
require.NoError(t, err)
}
-func TestDNSProvider_Cleanup_private(t *testing.T) {
- provider := mockBuilder(true).
- Route("GET /v2/zones",
- servermock.ResponseFromInternal("zones_GET.json"),
- servermock.CheckQueryParameter().Strict().
- With("name", "example.com.").
- With("type", "private")).
- Route("GET /v2/zones/123123/recordsets",
- servermock.ResponseFromInternal("zones-recordsets_GET.json"),
- servermock.CheckQueryParameter().Strict().
- With("name", "_acme-challenge.example.com.").
- With("type", "TXT")).
- Route("DELETE /v2/zones/123123/recordsets/321321",
- servermock.ResponseFromInternal("zones-recordsets_DELETE.json")).
- Build(t)
-
- err := provider.CleanUp("example.com", "", "123d==")
- require.NoError(t, err)
-}
-
func TestDNSProvider_Cleanup_emptyRecordset(t *testing.T) {
- provider := mockBuilder(false).
+ provider := mockBuilder().
Route("GET /v2/zones",
servermock.ResponseFromInternal("zones_GET.json"),
servermock.CheckQueryParameter().Strict().
@@ -315,17 +274,15 @@ func TestDNSProvider_Cleanup_emptyRecordset(t *testing.T) {
require.EqualError(t, err, "otc: unable to get record _acme-challenge.example.com. for zone example.com: record not found")
}
-func mockBuilder(private bool) *servermock.Builder[*DNSProvider] {
+func mockBuilder() *servermock.Builder[*DNSProvider] {
return servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
config.UserName = "user"
config.Password = "secret"
config.DomainName = "example.com"
config.ProjectName = "test"
config.IdentityEndpoint = fmt.Sprintf("%s/v3/auth/token", server.URL)
- config.PrivateZone = private
return NewDNSProviderConfig(config)
},
diff --git a/providers/dns/ovh/ovh.go b/providers/dns/ovh/ovh.go
index a8d12d819..c70e943bc 100644
--- a/providers/dns/ovh/ovh.go
+++ b/providers/dns/ovh/ovh.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
"github.com/ovh/go-ovh/ovh"
)
@@ -102,9 +101,8 @@ func (c *Config) hasAppKeyAuth() bool {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- config *Config
- client *ovh.Client
-
+ config *Config
+ client *ovh.Client
recordIDs map[string]int64
recordIDsMu sync.Mutex
}
@@ -192,7 +190,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// Create TXT record
var respData Record
-
err = d.client.Post(reqURL, reqData, &respData)
if err != nil {
return fmt.Errorf("ovh: error when call api to add record (%s): %w", reqURL, err)
@@ -200,7 +197,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// Apply the change
reqURL = fmt.Sprintf("/domain/zone/%s/refresh", authZone)
-
err = d.client.Post(reqURL, nil, nil)
if err != nil {
return fmt.Errorf("ovh: error when call api to refresh zone (%s): %w", reqURL, err)
@@ -221,7 +217,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("ovh: unknown record ID for '%s'", info.EffectiveFQDN)
}
@@ -242,7 +237,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
// Apply the change
reqURL = fmt.Sprintf("/domain/zone/%s/refresh", authZone)
-
err = d.client.Post(reqURL, nil, nil)
if err != nil {
return fmt.Errorf("ovh: error when call api to refresh zone (%s): %w", reqURL, err)
@@ -263,10 +257,8 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
}
func newClient(config *Config) (*ovh.Client, error) {
- var (
- client *ovh.Client
- err error
- )
+ var client *ovh.Client
+ var err error
switch {
case config.hasAppKeyAuth():
@@ -285,11 +277,5 @@ func newClient(config *Config) (*ovh.Client, error) {
client.UserAgent = useragent.Get()
- if config.HTTPClient != nil {
- client.Client = config.HTTPClient
- }
-
- client.Client = clientdebug.Wrap(client.Client)
-
return client, nil
}
diff --git a/providers/dns/ovh/ovh.toml b/providers/dns/ovh/ovh.toml
index abf22bd7a..95162185b 100644
--- a/providers/dns/ovh/ovh.toml
+++ b/providers/dns/ovh/ovh.toml
@@ -11,20 +11,20 @@ OVH_APPLICATION_KEY=1234567898765432 \
OVH_APPLICATION_SECRET=b9841238feb177a84330febba8a832089 \
OVH_CONSUMER_KEY=256vfsd347245sdfg \
OVH_ENDPOINT=ovh-eu \
-lego --dns ovh -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ovh -d '*.example.com' -d example.com run
# Or Access Token:
OVH_ACCESS_TOKEN=xxx \
OVH_ENDPOINT=ovh-eu \
-lego --dns ovh -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ovh -d '*.example.com' -d example.com run
# Or OAuth2:
OVH_CLIENT_ID=yyy \
OVH_CLIENT_SECRET=xxx \
OVH_ENDPOINT=ovh-eu \
-lego --dns ovh -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ovh -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/ovh/ovh_test.go b/providers/dns/ovh/ovh_test.go
index 332e7f192..fcb2300b6 100644
--- a/providers/dns/ovh/ovh_test.go
+++ b/providers/dns/ovh/ovh_test.go
@@ -162,7 +162,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -316,7 +315,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
// The OVH client use the same env vars than lego, so it requires to clean them.
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
for _, test := range testCases {
@@ -356,7 +354,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -370,7 +367,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/pdns/internal/client.go b/providers/dns/pdns/internal/client.go
index f72dd4d78..f6b55d5de 100644
--- a/providers/dns/pdns/internal/client.go
+++ b/providers/dns/pdns/internal/client.go
@@ -69,7 +69,6 @@ func (c *Client) getAPIVersion(ctx context.Context) (int, error) {
}
var versions []apiVersion
-
err = json.Unmarshal(result, &versions)
if err != nil {
return 0, err
@@ -99,7 +98,6 @@ func (c *Client) GetHostedZone(ctx context.Context, authZone string) (*HostedZon
}
var zone HostedZone
-
err = json.Unmarshal(result, &zone)
if err != nil {
return nil, err
@@ -182,7 +180,6 @@ func (c *Client) do(req *http.Request) (json.RawMessage, error) {
}
var msg json.RawMessage
-
err = json.NewDecoder(resp.Body).Decode(&msg)
if err != nil {
if errors.Is(err, io.EOF) {
@@ -196,12 +193,10 @@ func (c *Client) do(req *http.Request) (json.RawMessage, error) {
// check for PowerDNS error message
if len(msg) > 0 && msg[0] == '{' {
var errInfo apiError
-
err = json.Unmarshal(msg, &errInfo)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, msg, err)
}
-
if errInfo.ShortMsg != "" {
return nil, fmt.Errorf("error talking to PDNS API: %w", errInfo)
}
diff --git a/providers/dns/pdns/pdns.go b/providers/dns/pdns/pdns.go
index e7ead7078..ec0ae2a70 100644
--- a/providers/dns/pdns/pdns.go
+++ b/providers/dns/pdns/pdns.go
@@ -14,7 +14,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/pdns/internal"
)
@@ -104,12 +103,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client := internal.NewClient(config.Host, config.ServerName, config.APIVersion, config.APIKey)
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
if config.APIVersion <= 0 {
err := client.SetAPIVersion(context.Background())
if err != nil {
@@ -213,7 +206,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var records []internal.Record
-
for _, r := range set.Records {
if r.Content != strconv.Quote(info.Value) {
records = append(records, r)
diff --git a/providers/dns/pdns/pdns.toml b/providers/dns/pdns/pdns.toml
index a83d80922..53b5547b9 100644
--- a/providers/dns/pdns/pdns.toml
+++ b/providers/dns/pdns/pdns.toml
@@ -7,7 +7,7 @@ Since = "v0.4.0"
Example = '''
PDNS_API_URL=http://pdns-server:80/ \
PDNS_API_KEY=xxxx \
-lego --dns pdns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns pdns -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/pdns/pdns_test.go b/providers/dns/pdns/pdns_test.go
index 0213ba17c..6762e892e 100644
--- a/providers/dns/pdns/pdns_test.go
+++ b/providers/dns/pdns/pdns_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -137,7 +136,6 @@ func TestLivePresentAndCleanup(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -157,6 +155,5 @@ func mustParse(rawURL string) *url.URL {
if err != nil {
panic(err)
}
-
return u
}
diff --git a/providers/dns/plesk/internal/client.go b/providers/dns/plesk/internal/client.go
index 47abba805..88a7fdd9f 100644
--- a/providers/dns/plesk/internal/client.go
+++ b/providers/dns/plesk/internal/client.go
@@ -121,7 +121,6 @@ func (c *Client) doRequest(ctx context.Context, payload RequestPacketType) (*Res
endpoint := c.baseURL.JoinPath("/enterprise/control/agent.php")
body := new(bytes.Buffer)
-
err := xml.NewEncoder(body).Encode(payload)
if err != nil {
return nil, err
@@ -154,7 +153,6 @@ func (c *Client) doRequest(ctx context.Context, payload RequestPacketType) (*Res
}
var response ResponsePacketType
-
err = xml.Unmarshal(raw, &response)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/plesk/plesk.go b/providers/dns/plesk/plesk.go
index 5f07dcb50..b7a7ebf77 100644
--- a/providers/dns/plesk/plesk.go
+++ b/providers/dns/plesk/plesk.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/plesk/internal"
)
@@ -108,8 +107,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -163,7 +160,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("plesk: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
@@ -173,9 +169,5 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("plesk: failed to delete record (%d): %w", recordID, err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/plesk/plesk.toml b/providers/dns/plesk/plesk.toml
index 0ef89d6b7..5fb4ce073 100644
--- a/providers/dns/plesk/plesk.toml
+++ b/providers/dns/plesk/plesk.toml
@@ -8,7 +8,7 @@ Example = '''
PLESK_SERVER_BASE_URL="https://plesk.myserver.com:8443" \
PLESK_USERNAME=xxxxxx \
PLESK_PASSWORD=yyyyyy \
-lego --dns plesk -d '*.example.com' -d example.com run
+lego --email you@example.com --dns plesk -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/plesk/plesk_test.go b/providers/dns/plesk/plesk_test.go
index 506a26a2a..417e2c1da 100644
--- a/providers/dns/plesk/plesk_test.go
+++ b/providers/dns/plesk/plesk_test.go
@@ -67,7 +67,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -150,7 +149,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -164,7 +162,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/porkbun/porkbun.go b/providers/dns/porkbun/porkbun.go
index 2f999ebcc..44bf1857b 100644
--- a/providers/dns/porkbun/porkbun.go
+++ b/providers/dns/porkbun/porkbun.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/nrdcg/porkbun"
)
@@ -101,8 +100,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -154,7 +151,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("porkbun: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
@@ -171,10 +167,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("porkbun: failed to delete record: %w", err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/porkbun/porkbun.toml b/providers/dns/porkbun/porkbun.toml
index 9ae036da6..d7ed3aedc 100644
--- a/providers/dns/porkbun/porkbun.toml
+++ b/providers/dns/porkbun/porkbun.toml
@@ -8,7 +8,7 @@ Since = "v4.4.0"
Example = '''
PORKBUN_SECRET_API_KEY=xxxxxx \
PORKBUN_API_KEY=yyyyyy \
-lego --dns porkbun -d '*.example.com' -d example.com run
+lego --email you@example.com --dns porkbun -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/porkbun/porkbun_test.go b/providers/dns/porkbun/porkbun_test.go
index 7c69edfdb..cdf022b5d 100644
--- a/providers/dns/porkbun/porkbun_test.go
+++ b/providers/dns/porkbun/porkbun_test.go
@@ -54,7 +54,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -125,7 +124,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -139,7 +137,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/rackspace/internal/client.go b/providers/dns/rackspace/internal/client.go
index 4a1872484..076409ebd 100644
--- a/providers/dns/rackspace/internal/client.go
+++ b/providers/dns/rackspace/internal/client.go
@@ -113,7 +113,6 @@ func (c *Client) listDomainsByName(ctx context.Context, domain string) (*ZoneSea
}
var zoneSearchResponse ZoneSearchResponse
-
err = c.do(req, &zoneSearchResponse)
if err != nil {
return nil, err
@@ -155,7 +154,6 @@ func (c *Client) searchRecords(ctx context.Context, zoneID, recordName, recordTy
}
var records Records
-
err = c.do(req, &records)
if err != nil {
return nil, err
diff --git a/providers/dns/rackspace/internal/identity.go b/providers/dns/rackspace/internal/identity.go
index 3ff667fb8..062350df5 100644
--- a/providers/dns/rackspace/internal/identity.go
+++ b/providers/dns/rackspace/internal/identity.go
@@ -65,7 +65,6 @@ func (a *Identifier) Login(ctx context.Context, apiUser, apiKey string) (*Identi
}
var identity Identity
-
err = json.Unmarshal(raw, &identity)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/rackspace/rackspace.go b/providers/dns/rackspace/rackspace.go
index b4c7b4a0f..b9ce8f6e3 100644
--- a/providers/dns/rackspace/rackspace.go
+++ b/providers/dns/rackspace/rackspace.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/rackspace/internal"
)
@@ -99,7 +98,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
// Iterate through the Service Catalog to get the DNS Endpoint
var dnsEndpoint string
-
for _, service := range identity.Access.ServiceCatalog {
if service.Name == "cloudDNS" {
dnsEndpoint = service.Endpoints[0].PublicURL
@@ -120,8 +118,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/rackspace/rackspace.toml b/providers/dns/rackspace/rackspace.toml
index 0a4a80ffc..7ca2c3b7a 100644
--- a/providers/dns/rackspace/rackspace.toml
+++ b/providers/dns/rackspace/rackspace.toml
@@ -7,7 +7,7 @@ Since = "v0.4.0"
Example = '''
RACKSPACE_USER=xxxx \
RACKSPACE_API_KEY=yyyy \
-lego --dns rackspace -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rackspace -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/rackspace/rackspace_test.go b/providers/dns/rackspace/rackspace_test.go
index de0749fd3..cefb46134 100644
--- a/providers/dns/rackspace/rackspace_test.go
+++ b/providers/dns/rackspace/rackspace_test.go
@@ -75,7 +75,6 @@ func TestLiveNewDNSProvider_ValidEnv(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -88,7 +87,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -102,7 +100,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -116,7 +113,6 @@ func mockBuilder() *servermock.Builder[*DNSProvider] {
return servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
config.APIUser = "testUser"
config.APIKey = "testKey"
config.HTTPClient = server.Client()
diff --git a/providers/dns/rainyun/internal/client.go b/providers/dns/rainyun/internal/client.go
index 595b39f29..3d99bd9be 100644
--- a/providers/dns/rainyun/internal/client.go
+++ b/providers/dns/rainyun/internal/client.go
@@ -84,7 +84,6 @@ func (c *Client) ListRecords(ctx context.Context, domainID int) ([]Record, error
}
var recordData APIResponse[Record]
-
err = c.do(req, &recordData)
if err != nil {
return nil, err
@@ -174,7 +173,6 @@ 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)
diff --git a/providers/dns/rainyun/rainyun.go b/providers/dns/rainyun/rainyun.go
index a4d1c4035..43ef9cb1b 100644
--- a/providers/dns/rainyun/rainyun.go
+++ b/providers/dns/rainyun/rainyun.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/rainyun/internal"
)
@@ -86,8 +85,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/rainyun/rainyun.toml b/providers/dns/rainyun/rainyun.toml
index fe2b3c07d..cca16cffe 100644
--- a/providers/dns/rainyun/rainyun.toml
+++ b/providers/dns/rainyun/rainyun.toml
@@ -6,7 +6,7 @@ Since = "v4.21.0"
Example = '''
RAINYUN_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns rainyun -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rainyun -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/rainyun/rainyun_test.go b/providers/dns/rainyun/rainyun_test.go
index d27d47e81..d0048e5d0 100644
--- a/providers/dns/rainyun/rainyun_test.go
+++ b/providers/dns/rainyun/rainyun_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -93,7 +92,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -107,7 +105,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/rcodezero/internal/client.go b/providers/dns/rcodezero/internal/client.go
index 5cf39907e..d37fec2dd 100644
--- a/providers/dns/rcodezero/internal/client.go
+++ b/providers/dns/rcodezero/internal/client.go
@@ -64,7 +64,6 @@ func (c *Client) do(req *http.Request) (*APIResponse, error) {
}
result := &APIResponse{}
-
raw, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errutils.NewReadResponseError(req, resp.StatusCode, err)
@@ -106,7 +105,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errAPI := &APIResponse{}
-
err := json.Unmarshal(raw, errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/rcodezero/rcodezero.go b/providers/dns/rcodezero/rcodezero.go
index 010a6dadc..93f3e957a 100644
--- a/providers/dns/rcodezero/rcodezero.go
+++ b/providers/dns/rcodezero/rcodezero.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/rcodezero/internal"
)
@@ -87,8 +86,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/rcodezero/rcodezero.toml b/providers/dns/rcodezero/rcodezero.toml
index c2a4a1e7b..bba5588da 100644
--- a/providers/dns/rcodezero/rcodezero.toml
+++ b/providers/dns/rcodezero/rcodezero.toml
@@ -6,7 +6,7 @@ Since = "v4.13"
Example = '''
RCODEZERO_API_TOKEN= \
-lego --dns rcodezero -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rcodezero -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/rcodezero/rcodezero_test.go b/providers/dns/rcodezero/rcodezero_test.go
index a4a242c30..1f0946072 100644
--- a/providers/dns/rcodezero/rcodezero_test.go
+++ b/providers/dns/rcodezero/rcodezero_test.go
@@ -37,7 +37,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -95,7 +94,6 @@ func TestLivePresentAndCleanup(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/regfish/regfish.go b/providers/dns/regfish/regfish.go
index 85aac92e5..6a8ccee98 100644
--- a/providers/dns/regfish/regfish.go
+++ b/providers/dns/regfish/regfish.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
regfishapi "github.com/regfish/regfish-dnsapi-go"
)
@@ -85,15 +84,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client := regfishapi.NewClient(config.APIKey)
- if config.HTTPClient != nil {
- client.Client = config.HTTPClient
- } else {
- // Because the regfishapi.NewClient uses an empty http.Client.
- client.Client = &http.Client{Timeout: 30 * time.Second}
- }
-
- client.Client = clientdebug.Wrap(client.Client)
-
return &DNSProvider{
config: config,
client: client,
@@ -132,7 +122,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("regfish: unknown record ID for '%s'", info.EffectiveFQDN)
}
diff --git a/providers/dns/regfish/regfish.toml b/providers/dns/regfish/regfish.toml
index fbaacbde4..9869ed96e 100644
--- a/providers/dns/regfish/regfish.toml
+++ b/providers/dns/regfish/regfish.toml
@@ -6,7 +6,7 @@ Since = "v4.20.0"
Example = '''
REGFISH_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns regfish -d '*.example.com' -d example.com run
+lego --email you@example.com --dns regfish -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/regfish/regfish_test.go b/providers/dns/regfish/regfish_test.go
index 6613bd508..80928048f 100644
--- a/providers/dns/regfish/regfish_test.go
+++ b/providers/dns/regfish/regfish_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -93,7 +92,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -107,7 +105,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/regru/internal/client.go b/providers/dns/regru/internal/client.go
index b0b86d567..4b0205b0f 100644
--- a/providers/dns/regru/internal/client.go
+++ b/providers/dns/regru/internal/client.go
@@ -111,7 +111,6 @@ func (c *Client) doRequest(ctx context.Context, request any, fragments ...string
}
var apiResp APIResponse
-
err = json.Unmarshal(raw, &apiResp)
if err != nil {
return nil, errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
@@ -124,7 +123,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var errAPI APIResponse
-
err := json.Unmarshal(raw, &errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/regru/internal/client_test.go b/providers/dns/regru/internal/client_test.go
index 002da0185..0779f0d5f 100644
--- a/providers/dns/regru/internal/client_test.go
+++ b/providers/dns/regru/internal/client_test.go
@@ -13,7 +13,6 @@ func mockBuilder() *servermock.Builder[*Client] {
return servermock.NewBuilder[*Client](
func(server *httptest.Server) (*Client, error) {
client := NewClient("user", "secret")
- client.HTTPClient = server.Client()
client.baseURL, _ = url.Parse(server.URL)
return client, nil
diff --git a/providers/dns/regru/regru.go b/providers/dns/regru/regru.go
index b06b355c1..1501863bd 100644
--- a/providers/dns/regru/regru.go
+++ b/providers/dns/regru/regru.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/regru/internal"
)
@@ -98,8 +97,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
if config.TLSCert != "" || config.TLSKey != "" {
if config.TLSCert == "" {
return nil, errors.New("regru: TLS certificate is missing")
diff --git a/providers/dns/regru/regru.toml b/providers/dns/regru/regru.toml
index 728bb2bf7..2ccf3a58f 100644
--- a/providers/dns/regru/regru.toml
+++ b/providers/dns/regru/regru.toml
@@ -7,7 +7,7 @@ Since = "v3.5.0"
Example = '''
REGRU_USERNAME=xxxxxx \
REGRU_PASSWORD=yyyyyy \
-lego --dns regru -d '*.example.com' -d example.com run
+lego --email you@example.com --dns regru -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/regru/regru_test.go b/providers/dns/regru/regru_test.go
index 762eeb4d3..15d86d75c 100644
--- a/providers/dns/regru/regru_test.go
+++ b/providers/dns/regru/regru_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -130,7 +129,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -144,7 +142,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/rfc2136/rfc2136.go b/providers/dns/rfc2136/rfc2136.go
index 2c4fe7aeb..6b5c47072 100644
--- a/providers/dns/rfc2136/rfc2136.go
+++ b/providers/dns/rfc2136/rfc2136.go
@@ -131,7 +131,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
config.TSIGSecret = ""
} else {
// zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
- config.TSIGKey = dns.CanonicalName(config.TSIGKey)
+ config.TSIGKey = strings.ToLower(dns.Fqdn(config.TSIGKey))
}
if config.TSIGAlgorithm == "" {
@@ -171,7 +171,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("rfc2136: failed to insert: %w", err)
}
-
return nil
}
@@ -183,7 +182,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("rfc2136: failed to remove: %w", err)
}
-
return nil
}
@@ -195,14 +193,14 @@ func (d *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error {
}
// Create RR
- rrs := []dns.RR{&dns.TXT{
- Hdr: dns.RR_Header{Name: fqdn, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: uint32(ttl)},
- Txt: []string{value},
- }}
+ rr := new(dns.TXT)
+ rr.Hdr = dns.RR_Header{Name: fqdn, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: uint32(ttl)}
+ rr.Txt = []string{value}
+ rrs := []dns.RR{rr}
// Create dynamic update packet
- m := new(dns.Msg).SetUpdate(zone)
-
+ m := new(dns.Msg)
+ m.SetUpdate(zone)
switch action {
case "INSERT":
// Always remove old challenge left over from who knows what.
@@ -230,7 +228,6 @@ func (d *DNSProvider) changeRecord(action, fqdn, value string, ttl int) error {
if err != nil {
return fmt.Errorf("DNS update failed: %w", err)
}
-
if reply != nil && reply.Rcode != dns.RcodeSuccess {
return fmt.Errorf("DNS update failed: server replied: %s", dns.RcodeToString[reply.Rcode])
}
diff --git a/providers/dns/rfc2136/rfc2136.toml b/providers/dns/rfc2136/rfc2136.toml
index 6b5bbe599..9243440a4 100644
--- a/providers/dns/rfc2136/rfc2136.toml
+++ b/providers/dns/rfc2136/rfc2136.toml
@@ -9,7 +9,7 @@ RFC2136_NAMESERVER=127.0.0.1 \
RFC2136_TSIG_KEY=example.com \
RFC2136_TSIG_ALGORITHM=hmac-sha256. \
RFC2136_TSIG_SECRET=YWJjZGVmZGdoaWprbG1ub3BxcnN0dXZ3eHl6MTIzNDU= \
-lego --dns rfc2136 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rfc2136 -d '*.example.com' -d example.com run
## ---
@@ -17,7 +17,7 @@ keyname=example.com; keyfile=example.com.key; tsig-keygen $keyname > $keyfile
RFC2136_NAMESERVER=127.0.0.1 \
RFC2136_TSIG_FILE="$keyfile" \
-lego --dns rfc2136 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rfc2136 -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/rfc2136/rfc2136_test.go b/providers/dns/rfc2136/rfc2136_test.go
index ce4859e84..80fdc69cb 100644
--- a/providers/dns/rfc2136/rfc2136_test.go
+++ b/providers/dns/rfc2136/rfc2136_test.go
@@ -2,21 +2,24 @@ package rfc2136
import (
"bytes"
+ "fmt"
+ "net"
"strings"
+ "sync"
"testing"
"time"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/dnsmock"
"github.com/miekg/dns"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const (
fakeDomain = "123456789.www.example.com"
fakeKeyAuth = "123d=="
- fakeValue = "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY"
+ fakeValue = "Now36o-3BmlB623-0c1qCIUmgWVVmDJb88KGl24pqpo"
fakeFqdn = "_acme-challenge.123456789.www.example.com."
fakeZone = "example.com."
fakeTTL = 120
@@ -84,7 +87,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -161,16 +163,39 @@ func TestNewDNSProviderConfig(t *testing.T) {
}
}
-func TestDNSProvider_Present_success(t *testing.T) {
+func TestCanaryLocalTestServer(t *testing.T) {
dns01.ClearFqdnCache()
+ dns.HandleFunc("example.com.", serverHandlerHello)
+ defer dns.HandleRemove("example.com.")
- addr := dnsmock.NewServer().
- Query(fakeZone+" SOA", dnsmock.SOA("")).
- Update(fakeZone+" SOA", dnsmock.Noop).
- Build(t)
+ server, addr, err := runLocalDNSTestServer(false)
+ require.NoError(t, err, "Failed to start test server")
+ defer func() { _ = server.Shutdown() }()
+
+ c := new(dns.Client)
+ m := new(dns.Msg)
+
+ m.SetQuestion("example.com.", dns.TypeTXT)
+
+ r, _, err := c.Exchange(m, addr)
+ require.NoError(t, err, "Failed to communicate with test server")
+ assert.Len(t, r.Extra, 1, "Failed to communicate with test server")
+
+ txt := r.Extra[0].(*dns.TXT).Txt[0]
+ assert.Equal(t, "Hello world", txt)
+}
+
+func TestServerSuccess(t *testing.T) {
+ dns01.ClearFqdnCache()
+ dns.HandleFunc(fakeZone, serverHandlerReturnSuccess)
+ defer dns.HandleRemove(fakeZone)
+
+ server, addr, err := runLocalDNSTestServer(false)
+ require.NoError(t, err, "Failed to start test server")
+ defer func() { _ = server.Shutdown() }()
config := NewDefaultConfig()
- config.Nameserver = addr.String()
+ config.Nameserver = addr
provider, err := NewDNSProviderConfig(config)
require.NoError(t, err)
@@ -179,98 +204,39 @@ func TestDNSProvider_Present_success(t *testing.T) {
require.NoError(t, err)
}
-func TestDNSProvider_Present_success_updatePacket(t *testing.T) {
+func TestServerError(t *testing.T) {
dns01.ClearFqdnCache()
+ dns.HandleFunc(fakeZone, serverHandlerReturnErr)
+ defer dns.HandleRemove(fakeZone)
- reqChan := make(chan *dns.Msg, 1)
-
- addr := dnsmock.NewServer().
- Query("_acme-challenge.123456789.www.example.com. SOA", dnsmock.SOA(fakeZone)).
- Update(fakeZone+" SOA", func(w dns.ResponseWriter, req *dns.Msg) {
- dnsmock.Noop(w, req)
-
- // Only talk back when it is not the SOA RR.
- reqChan <- req
- }).
- Build(t)
+ server, addr, err := runLocalDNSTestServer(false)
+ require.NoError(t, err, "Failed to start test server")
+ defer func() { _ = server.Shutdown() }()
config := NewDefaultConfig()
- config.Nameserver = addr.String()
-
- provider, err := NewDNSProviderConfig(config)
- require.NoError(t, err)
-
- err = provider.Present(fakeDomain, "", fakeKeyAuth)
- require.NoError(t, err)
-
- select {
- case <-time.After(time.Second):
- t.Fatal("timeout waiting for request")
-
- case rcvMsg := <-reqChan:
- txtRR := &dns.TXT{
- Hdr: dns.RR_Header{Name: fakeFqdn, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: fakeTTL},
- Txt: []string{fakeValue},
- }
-
- m := new(dns.Msg).SetUpdate(fakeZone)
-
- m.RemoveRRset([]dns.RR{txtRR})
- m.Insert([]dns.RR{txtRR})
-
- expected, err := m.Pack()
- require.NoError(t, err, "error packing")
-
- rcvMsg.Id = m.Id
-
- actual, err := rcvMsg.Pack()
- require.NoError(t, err, "error packing")
-
- if !bytes.Equal(actual, expected) {
- tmp := new(dns.Msg)
- require.NoError(t, tmp.Unpack(actual))
-
- t.Errorf("Expected msg:\n%s", m)
- t.Errorf("Actual msg:\n%s", tmp)
- }
- }
-}
-
-func TestDNSProvider_Present_error(t *testing.T) {
- dns01.ClearFqdnCache()
-
- addr := dnsmock.NewServer().
- Query(fakeZone+" SOA", dnsmock.Error(dns.RcodeNotZone)).
- Build(t)
-
- config := NewDefaultConfig()
- config.Nameserver = addr.String()
+ config.Nameserver = addr
provider, err := NewDNSProviderConfig(config)
require.NoError(t, err)
err = provider.Present(fakeDomain, "", fakeKeyAuth)
require.Error(t, err)
-
if !strings.Contains(err.Error(), "NOTZONE") {
t.Errorf("Expected Present() to return an error with the 'NOTZONE' rcode string, but it did not: %v", err)
}
}
-func TestDNSProvider_Present_tsig_success(t *testing.T) {
+func TestTsigClient(t *testing.T) {
dns01.ClearFqdnCache()
+ dns.HandleFunc(fakeZone, serverHandlerReturnSuccess)
+ defer dns.HandleRemove(fakeZone)
- addr := dnsmock.NewServer().
- Query(fakeZone+" SOA", dnsmock.SOA("")).
- Update(fakeZone+" SOA", handleTSIG).
- Build(t, func(server *dns.Server) error {
- server.TsigSecret = map[string]string{fakeTsigKey: fakeTsigSecret}
-
- return nil
- })
+ server, addr, err := runLocalDNSTestServer(true)
+ require.NoError(t, err, "Failed to start test server")
+ defer func() { _ = server.Shutdown() }()
config := NewDefaultConfig()
- config.Nameserver = addr.String()
+ config.Nameserver = addr
config.TSIGKey = fakeTsigKey
config.TSIGSecret = fakeTsigSecret
@@ -281,50 +247,143 @@ func TestDNSProvider_Present_tsig_success(t *testing.T) {
require.NoError(t, err)
}
-func TestDNSProvider_Present_tsig_error(t *testing.T) {
+func TestValidUpdatePacket(t *testing.T) {
+ reqChan := make(chan *dns.Msg, 10)
+
dns01.ClearFqdnCache()
+ dns.HandleFunc(fakeZone, serverHandlerPassBackRequest(reqChan))
+ defer dns.HandleRemove(fakeZone)
- addr := dnsmock.NewServer().
- Query(fakeZone+" SOA", dnsmock.SOA("")).
- Update(fakeZone+" SOA", handleTSIG).
- Build(t, func(server *dns.Server) error {
- server.TsigSecret = map[string]string{"example.org": fakeTsigSecret}
+ server, addr, err := runLocalDNSTestServer(false)
+ require.NoError(t, err, "Failed to start test server")
+ defer func() { _ = server.Shutdown() }()
- return nil
- })
-
- config := NewDefaultConfig()
- config.Nameserver = addr.String()
- config.TSIGKey = fakeTsigKey
- config.TSIGSecret = fakeTsigSecret
-
- provider, err := NewDNSProviderConfig(config)
- require.NoError(t, err)
-
- err = provider.Present(fakeDomain, "", fakeKeyAuth)
- require.Error(t, err)
- require.EqualError(t, err, "rfc2136: failed to insert: DNS update failed: server replied: NOTZONE")
-}
-
-func handleTSIG(w dns.ResponseWriter, req *dns.Msg) {
+ txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", fakeFqdn, fakeTTL, fakeValue))
+ rrs := []dns.RR{txtRR}
m := new(dns.Msg)
+ m.SetUpdate(fakeZone)
+ m.RemoveRRset(rrs)
+ m.Insert(rrs)
+ expectStr := m.String()
- tsig := req.IsTsig()
- if tsig == nil {
- _ = w.WriteMsg(m.SetRcode(req, dns.RcodeRefused))
- return
+ expect, err := m.Pack()
+ require.NoError(t, err, "error packing")
+
+ config := NewDefaultConfig()
+ config.Nameserver = addr
+
+ provider, err := NewDNSProviderConfig(config)
+ require.NoError(t, err)
+
+ err = provider.Present(fakeDomain, "", "1234d==")
+ require.NoError(t, err)
+
+ rcvMsg := <-reqChan
+ rcvMsg.Id = m.Id
+
+ actual, err := rcvMsg.Pack()
+ require.NoError(t, err, "error packing")
+
+ if !bytes.Equal(actual, expect) {
+ tmp := new(dns.Msg)
+ if err := tmp.Unpack(actual); err != nil {
+ t.Fatalf("Error unpacking actual msg: %v", err)
+ }
+ t.Errorf("Expected msg:\n%s", expectStr)
+ t.Errorf("Actual msg:\n%v", tmp)
+ }
+}
+
+func runLocalDNSTestServer(tsig bool) (*dns.Server, string, error) {
+ pc, err := net.ListenPacket("udp", "127.0.0.1:0")
+ if err != nil {
+ return nil, "", err
+ }
+
+ server := &dns.Server{
+ PacketConn: pc,
+ ReadTimeout: time.Hour,
+ WriteTimeout: time.Hour,
+ MsgAcceptFunc: func(dh dns.Header) dns.MsgAcceptAction {
+ // bypass defaultMsgAcceptFunc to allow dynamic update (https://github.com/miekg/dns/pull/830)
+ return dns.MsgAccept
+ },
+ }
+
+ if tsig {
+ server.TsigSecret = map[string]string{fakeTsigKey: fakeTsigSecret}
+ }
+
+ waitLock := sync.Mutex{}
+ waitLock.Lock()
+ server.NotifyStartedFunc = waitLock.Unlock
+
+ go func() {
+ _ = server.ActivateAndServe()
+ pc.Close()
+ }()
+
+ waitLock.Lock()
+ return server, pc.LocalAddr().String(), nil
+}
+
+func serverHandlerHello(w dns.ResponseWriter, req *dns.Msg) {
+ m := new(dns.Msg)
+ m.SetReply(req)
+ m.Extra = make([]dns.RR, 1)
+ m.Extra[0] = &dns.TXT{
+ Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
+ Txt: []string{"Hello world"},
+ }
+ _ = w.WriteMsg(m)
+}
+
+func serverHandlerReturnSuccess(w dns.ResponseWriter, req *dns.Msg) {
+ m := new(dns.Msg)
+ m.SetReply(req)
+ if req.Opcode == dns.OpcodeQuery && req.Question[0].Qtype == dns.TypeSOA && req.Question[0].Qclass == dns.ClassINET {
+ // Return SOA to appease findZoneByFqdn()
+ soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", fakeZone, fakeTTL, fakeZone, fakeZone))
+ m.Answer = []dns.RR{soaRR}
+ }
+
+ if t := req.IsTsig(); t != nil {
+ if w.TsigStatus() == nil {
+ // Validated
+ m.SetTsig(fakeZone, dns.HmacSHA1, 300, time.Now().Unix())
+ }
+ }
+
+ _ = w.WriteMsg(m)
+}
+
+func serverHandlerReturnErr(w dns.ResponseWriter, req *dns.Msg) {
+ m := new(dns.Msg)
+ m.SetRcode(req, dns.RcodeNotZone)
+ _ = w.WriteMsg(m)
+}
+
+func serverHandlerPassBackRequest(reqChan chan *dns.Msg) func(w dns.ResponseWriter, req *dns.Msg) {
+ return func(w dns.ResponseWriter, req *dns.Msg) {
+ m := new(dns.Msg)
+ m.SetReply(req)
+ if req.Opcode == dns.OpcodeQuery && req.Question[0].Qtype == dns.TypeSOA && req.Question[0].Qclass == dns.ClassINET {
+ // Return SOA to appease findZoneByFqdn()
+ soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", fakeZone, fakeTTL, fakeZone, fakeZone))
+ m.Answer = []dns.RR{soaRR}
+ }
+
+ if t := req.IsTsig(); t != nil {
+ if w.TsigStatus() == nil {
+ // Validated
+ m.SetTsig(fakeZone, dns.HmacSHA1, 300, time.Now().Unix())
+ }
+ }
+
+ _ = w.WriteMsg(m)
+ if req.Opcode != dns.OpcodeQuery || req.Question[0].Qtype != dns.TypeSOA || req.Question[0].Qclass != dns.ClassINET {
+ // Only talk back when it is not the SOA RR.
+ reqChan <- req
+ }
}
-
- err := w.TsigStatus()
- if err != nil {
- _ = w.WriteMsg(m.SetRcode(req, dns.RcodeNotZone))
-
- return
- }
-
- // Validated
- _ = w.WriteMsg(m.
- SetReply(req).
- SetTsig(tsig.Hdr.Name, tsig.Algorithm, tsig.Fudge, time.Now().Unix()),
- )
}
diff --git a/providers/dns/rimuhosting/rimuhosting.go b/providers/dns/rimuhosting/rimuhosting.go
index 7a7e99f60..9051d0add 100644
--- a/providers/dns/rimuhosting/rimuhosting.go
+++ b/providers/dns/rimuhosting/rimuhosting.go
@@ -2,6 +2,7 @@
package rimuhosting
import (
+ "context"
"errors"
"fmt"
"net/http"
@@ -28,12 +29,19 @@ const (
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
-type Config = rimuhosting.Config
+type Config struct {
+ APIKey string
+
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, rimuhosting.DefaultTTL),
+ TTL: env.GetOrDefaultInt(EnvTTL, 3600),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPClient: &http.Client{
@@ -44,7 +52,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *rimuhosting.Client
}
// NewDNSProvider returns a DNSProvider instance configured for RimuHosting.
@@ -67,19 +76,48 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("rimuhosting: the configuration of the DNS provider is nil")
}
- provider, err := rimuhosting.NewDNSProviderConfig(config, "")
- if err != nil {
- return nil, fmt.Errorf("rimuhosting: %w", err)
+ if config.APIKey == "" {
+ return nil, errors.New("rimuhosting: incomplete credentials, missing API key")
}
- return &DNSProvider{prv: provider}, nil
+ client := rimuhosting.NewClient(config.APIKey)
+ client.BaseURL = rimuhosting.DefaultRimuHostingBaseURL
+
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{config: config, client: client}, nil
+}
+
+// Timeout returns the timeout and interval to use when checking for DNS propagation.
+// Adjusting here to cope with spikes in propagation times.
+func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
+ return d.config.PropagationTimeout, d.config.PollingInterval
}
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ ctx := context.Background()
+
+ records, err := d.client.FindTXTRecords(ctx, dns01.UnFqdn(info.EffectiveFQDN))
if err != nil {
- return fmt.Errorf("rimuhosting: %w", err)
+ return fmt.Errorf("rimuhosting: failed to find record(s) for %s: %w", domain, err)
+ }
+
+ actions := []rimuhosting.ActionParameter{
+ rimuhosting.NewAddRecordAction(dns01.UnFqdn(info.EffectiveFQDN), info.Value, d.config.TTL),
+ }
+
+ for _, record := range records {
+ actions = append(actions, rimuhosting.NewAddRecordAction(record.Name, record.Content, d.config.TTL))
+ }
+
+ _, err = d.client.DoActions(ctx, actions...)
+ if err != nil {
+ return fmt.Errorf("rimuhosting: failed to add record(s) for %s: %w", domain, err)
}
return nil
@@ -87,16 +125,14 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ action := rimuhosting.NewDeleteRecordAction(dns01.UnFqdn(info.EffectiveFQDN), info.Value)
+
+ _, err := d.client.DoActions(context.Background(), action)
if err != nil {
- return fmt.Errorf("rimuhosting: %w", err)
+ return fmt.Errorf("rimuhosting: failed to delete record for %s: %w", domain, err)
}
return nil
}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
-}
diff --git a/providers/dns/rimuhosting/rimuhosting.toml b/providers/dns/rimuhosting/rimuhosting.toml
index c1994e2cc..0a4f983e2 100644
--- a/providers/dns/rimuhosting/rimuhosting.toml
+++ b/providers/dns/rimuhosting/rimuhosting.toml
@@ -6,7 +6,7 @@ Since = "v0.3.5"
Example = '''
RIMUHOSTING_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns rimuhosting -d '*.example.com' -d example.com run
+lego --email you@example.com --dns rimuhosting -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/rimuhosting/rimuhosting_test.go b/providers/dns/rimuhosting/rimuhosting_test.go
index 878ec14da..cbdacedc4 100644
--- a/providers/dns/rimuhosting/rimuhosting_test.go
+++ b/providers/dns/rimuhosting/rimuhosting_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -46,7 +45,7 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
} else {
require.EqualError(t, err, test.expected)
}
@@ -84,7 +83,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
} else {
require.EqualError(t, err, test.expected)
}
@@ -98,7 +97,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -112,7 +110,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/route53/route53.go b/providers/dns/route53/route53.go
index b41c95dac..db578eb00 100644
--- a/providers/dns/route53/route53.go
+++ b/providers/dns/route53/route53.go
@@ -17,7 +17,6 @@ import (
"github.com/aws/aws-sdk-go-v2/service/route53"
awstypes "github.com/aws/aws-sdk-go-v2/service/route53/types"
"github.com/aws/aws-sdk-go-v2/service/sts"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
@@ -155,7 +154,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
realValue := `"` + info.Value + `"`
var found bool
-
for _, record := range records {
if ptr.Deref(record.Value) == realValue {
found = true
@@ -201,7 +199,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var nonLegoRecords []awstypes.ResourceRecord
-
for _, record := range existingRecords {
if ptr.Deref(record.Value) != `"`+info.Value+`"` {
nonLegoRecords = append(nonLegoRecords, record)
@@ -252,22 +249,18 @@ func (d *DNSProvider) changeRecord(ctx context.Context, action awstypes.ChangeAc
changeID := resp.ChangeInfo.Id
if d.config.WaitForRecordSetsChanged {
- return wait.Retry(ctx,
- func() error {
- resp, err := d.client.GetChange(ctx, &route53.GetChangeInput{Id: changeID})
- if err != nil {
- return fmt.Errorf("failed to query change status: %w", err)
- }
+ return wait.For("route53", d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
+ resp, err := d.client.GetChange(ctx, &route53.GetChangeInput{Id: changeID})
+ if err != nil {
+ return false, fmt.Errorf("failed to query change status: %w", err)
+ }
- if resp.ChangeInfo.Status != awstypes.ChangeStatusInsync {
- return fmt.Errorf("unable to retrieve change: ID=%s, status=%s", ptr.Deref(changeID), resp.ChangeInfo.Status)
- }
+ if resp.ChangeInfo.Status == awstypes.ChangeStatusInsync {
+ return true, nil
+ }
- return nil
- },
- backoff.WithBackOff(backoff.NewConstantBackOff(d.config.PollingInterval)),
- backoff.WithMaxElapsedTime(d.config.PropagationTimeout),
- )
+ return false, fmt.Errorf("unable to retrieve change: ID=%s", ptr.Deref(changeID))
+ })
}
return nil
@@ -314,14 +307,12 @@ func (d *DNSProvider) getHostedZoneID(ctx context.Context, fqdn string) (string,
reqParams := &route53.ListHostedZonesByNameInput{
DNSName: aws.String(dns01.UnFqdn(authZone)),
}
-
resp, err := d.client.ListHostedZonesByName(ctx, reqParams)
if err != nil {
return "", err
}
var hostedZoneID string
-
for _, hostedZone := range resp.HostedZones {
// .Name has a trailing dot
if ptr.Deref(hostedZone.Name) == authZone && d.config.PrivateZone == hostedZone.Config.PrivateZone {
@@ -357,7 +348,6 @@ func createAWSConfig(ctx context.Context, config *Config) (aws.Config, error) {
retryCount := min(attempt, 7)
delay := (1 << uint(retryCount)) * (rand.Intn(50) + 200)
-
return time.Duration(delay) * time.Millisecond, nil
})
})
diff --git a/providers/dns/route53/route53.toml b/providers/dns/route53/route53.toml
index 607d9ef31..9e3b049a6 100644
--- a/providers/dns/route53/route53.toml
+++ b/providers/dns/route53/route53.toml
@@ -9,7 +9,7 @@ AWS_ACCESS_KEY_ID=your_key_id \
AWS_SECRET_ACCESS_KEY=your_secret_access_key \
AWS_REGION=aws-region \
AWS_HOSTED_ZONE_ID=your_hosted_zone_id \
-lego --dns route53 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns route53 -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/route53/route53_test.go b/providers/dns/route53/route53_test.go
index 41ed824bc..6079bb4e6 100644
--- a/providers/dns/route53/route53_test.go
+++ b/providers/dns/route53/route53_test.go
@@ -34,7 +34,6 @@ var envTest = tester.NewEnvTest(
func Test_loadCredentials_FromEnv(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
_ = os.Setenv(EnvAccessKeyID, "123")
@@ -61,7 +60,6 @@ func Test_loadCredentials_FromEnv(t *testing.T) {
func Test_loadRegion_FromEnv(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
_ = os.Setenv(EnvRegion, "foo")
@@ -74,7 +72,6 @@ func Test_loadRegion_FromEnv(t *testing.T) {
func Test_getHostedZoneID_FromEnv(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
expectedZoneID := "zoneID"
@@ -85,7 +82,7 @@ func Test_getHostedZoneID_FromEnv(t *testing.T) {
require.NoError(t, err)
hostedZoneID, err := provider.getHostedZoneID(t.Context(), "whatever")
- require.NoError(t, err)
+ require.NoError(t, err, "HostedZoneID")
assert.Equal(t, expectedZoneID, hostedZoneID)
}
@@ -131,7 +128,6 @@ func TestNewDefaultConfig(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
envTest.ClearEnv()
-
for key, value := range test.envVars {
_ = os.Setenv(key, value)
}
@@ -145,13 +141,11 @@ func TestNewDefaultConfig(t *testing.T) {
func TestDNSProvider_Present(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
provider := servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
cfg := aws.Config{
- HTTPClient: server.Client(),
Credentials: credentials.NewStaticCredentialsProvider("abc", "123", " "),
Region: "mock-region",
BaseEndpoint: aws.String(server.URL),
@@ -187,7 +181,7 @@ func TestDNSProvider_Present(t *testing.T) {
keyAuth := "123456d=="
err := provider.Present(domain, "", keyAuth)
- require.NoError(t, err)
+ require.NoError(t, err, "Expected Present to return no error")
}
func Test_createAWSConfig(t *testing.T) {
@@ -276,7 +270,6 @@ func Test_createAWSConfig(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.env)
diff --git a/providers/dns/safedns/internal/client.go b/providers/dns/safedns/internal/client.go
index 628618032..3e6f99919 100644
--- a/providers/dns/safedns/internal/client.go
+++ b/providers/dns/safedns/internal/client.go
@@ -19,7 +19,7 @@ const defaultBaseURL = "https://api.ukfast.io/safedns/v1"
const authorizationHeader = "Authorization"
-// Client the ANS SafeDNS client.
+// Client the UKFast SafeDNS client.
type Client struct {
authToken string
@@ -48,7 +48,6 @@ func (c *Client) AddRecord(ctx context.Context, zone string, record Record) (*Ad
}
respData := &AddRecordResponse{}
-
err = c.do(req, respData)
if err != nil {
return nil, fmt.Errorf("add record: %w", err)
@@ -133,7 +132,6 @@ 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)
diff --git a/providers/dns/safedns/internal/client_test.go b/providers/dns/safedns/internal/client_test.go
index 161a9f078..f984d2d8f 100644
--- a/providers/dns/safedns/internal/client_test.go
+++ b/providers/dns/safedns/internal/client_test.go
@@ -17,7 +17,6 @@ func mockBuilder() *servermock.Builder[*Client] {
func(server *httptest.Server) (*Client, error) {
client := NewClient("secret")
client.baseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
return client, nil
},
diff --git a/providers/dns/safedns/safedns.go b/providers/dns/safedns/safedns.go
index 154cfc5ee..5066db59f 100644
--- a/providers/dns/safedns/safedns.go
+++ b/providers/dns/safedns/safedns.go
@@ -1,4 +1,4 @@
-// Package safedns implements a DNS provider for solving the DNS-01 challenge using ANS SafeDNS.
+// Package safedns implements a DNS provider for solving the DNS-01 challenge using UKFast SafeDNS.
package safedns
import (
@@ -12,9 +12,7 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/safedns/internal"
- "github.com/miekg/dns"
)
// Environment variables.
@@ -75,7 +73,7 @@ func NewDNSProvider() (*DNSProvider, error) {
return NewDNSProviderConfig(config)
}
-// NewDNSProviderConfig return a DNSProvider instance configured for ANS SafeDNS.
+// NewDNSProviderConfig return a DNSProvider instance configured for UKFast SafeDNS.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
return nil, errors.New("safedns: supplied configuration was nil")
@@ -91,8 +89,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -110,7 +106,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
- zone, err := dns01.FindZoneByFqdn(dns.Fqdn(info.EffectiveFQDN))
+ zone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(info.EffectiveFQDN))
if err != nil {
return fmt.Errorf("safedns: could not find zone for domain %q: %w", domain, err)
}
@@ -146,7 +142,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("safedns: unknown record ID for '%s'", info.EffectiveFQDN)
}
diff --git a/providers/dns/safedns/safedns.toml b/providers/dns/safedns/safedns.toml
index f387f2535..dcc7bc90e 100644
--- a/providers/dns/safedns/safedns.toml
+++ b/providers/dns/safedns/safedns.toml
@@ -1,12 +1,12 @@
-Name = "ANS SafeDNS"
+Name = "UKFast SafeDNS"
Description = ''''''
-URL = "https://www.ans.co.uk/"
+URL = "https://www.ukfast.co.uk/dns-hosting.html"
Code = "safedns"
Since = "v4.6.0"
Example = '''
SAFEDNS_AUTH_TOKEN=xxxxxx \
-lego --dns safedns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns safedns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/safedns/safedns_test.go b/providers/dns/safedns/safedns_test.go
index ce7568056..dcb374718 100644
--- a/providers/dns/safedns/safedns_test.go
+++ b/providers/dns/safedns/safedns_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -96,7 +95,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -110,7 +108,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/sakuracloud/sakuracloud.go b/providers/dns/sakuracloud/sakuracloud.go
index 1adbe3a88..f12248d42 100644
--- a/providers/dns/sakuracloud/sakuracloud.go
+++ b/providers/dns/sakuracloud/sakuracloud.go
@@ -2,7 +2,6 @@
package sakuracloud
import (
- "context"
"errors"
"fmt"
"net/http"
@@ -12,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
client "github.com/sacloud/api-client-go"
"github.com/sacloud/iaas-api-go"
@@ -102,7 +100,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
Options: &client.Options{
AccessToken: config.Token,
AccessTokenSecret: config.Secret,
- HttpClient: clientdebug.Wrap(config.HTTPClient),
+ HttpClient: config.HTTPClient,
UserAgent: fmt.Sprintf("%s %s", iaas.DefaultUserAgent, useragent.Get()),
},
}
@@ -117,7 +115,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
- err := d.addTXTRecord(context.Background(), info.EffectiveFQDN, info.Value, d.config.TTL)
+ err := d.addTXTRecord(info.EffectiveFQDN, info.Value, d.config.TTL)
if err != nil {
return fmt.Errorf("sakuracloud: %w", err)
}
@@ -129,7 +127,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
- err := d.cleanupTXTRecord(context.Background(), info.EffectiveFQDN, info.Value)
+ err := d.cleanupTXTRecord(info.EffectiveFQDN, info.Value)
if err != nil {
return fmt.Errorf("sakuracloud: %w", err)
}
@@ -171,7 +169,6 @@ func newCaller(opts *api.CallerOptions) iaas.APICaller {
if strings.HasSuffix(opts.APIRootURL, "/") {
opts.APIRootURL = strings.TrimRight(opts.APIRootURL, "/")
}
-
iaas.SakuraCloudAPIRoot = opts.APIRootURL
}
diff --git a/providers/dns/sakuracloud/sakuracloud.toml b/providers/dns/sakuracloud/sakuracloud.toml
index a197cd27c..f754e0c89 100644
--- a/providers/dns/sakuracloud/sakuracloud.toml
+++ b/providers/dns/sakuracloud/sakuracloud.toml
@@ -7,7 +7,7 @@ Since = "v1.1.0"
Example = '''
SAKURACLOUD_ACCESS_TOKEN=xxxxx \
SAKURACLOUD_ACCESS_TOKEN_SECRET=yyyyy \
-lego --dns sakuracloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns sakuracloud -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/sakuracloud/sakuracloud_test.go b/providers/dns/sakuracloud/sakuracloud_test.go
index 789a27544..93cf20ea1 100644
--- a/providers/dns/sakuracloud/sakuracloud_test.go
+++ b/providers/dns/sakuracloud/sakuracloud_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -130,7 +129,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -144,7 +142,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/sakuracloud/wrapper.go b/providers/dns/sakuracloud/wrapper.go
index ff0b78e09..0898ccd3b 100644
--- a/providers/dns/sakuracloud/wrapper.go
+++ b/providers/dns/sakuracloud/wrapper.go
@@ -14,11 +14,11 @@ import (
// see: https://github.com/go-acme/lego/pull/850
var mu sync.Mutex
-func (d *DNSProvider) addTXTRecord(ctx context.Context, fqdn, value string, ttl int) error {
+func (d *DNSProvider) addTXTRecord(fqdn, value string, ttl int) error {
mu.Lock()
defer mu.Unlock()
- zone, err := d.getHostedZone(ctx, fqdn)
+ zone, err := d.getHostedZone(fqdn)
if err != nil {
return err
}
@@ -35,7 +35,7 @@ func (d *DNSProvider) addTXTRecord(ctx context.Context, fqdn, value string, ttl
TTL: ttl,
})
- _, err = d.client.UpdateSettings(ctx, zone.ID, &iaas.DNSUpdateSettingsRequest{
+ _, err = d.client.UpdateSettings(context.Background(), zone.ID, &iaas.DNSUpdateSettingsRequest{
Records: records,
SettingsHash: zone.SettingsHash,
})
@@ -46,11 +46,11 @@ func (d *DNSProvider) addTXTRecord(ctx context.Context, fqdn, value string, ttl
return nil
}
-func (d *DNSProvider) cleanupTXTRecord(ctx context.Context, fqdn, value string) error {
+func (d *DNSProvider) cleanupTXTRecord(fqdn, value string) error {
mu.Lock()
defer mu.Unlock()
- zone, err := d.getHostedZone(ctx, fqdn)
+ zone, err := d.getHostedZone(fqdn)
if err != nil {
return err
}
@@ -61,7 +61,6 @@ func (d *DNSProvider) cleanupTXTRecord(ctx context.Context, fqdn, value string)
}
var updRecords iaas.DNSRecords
-
for _, r := range zone.Records {
if !(r.Name == subDomain && r.Type == "TXT" && r.RData == value) { //nolint:staticcheck // Clearer without De Morgan's law.
updRecords = append(updRecords, r)
@@ -72,8 +71,7 @@ func (d *DNSProvider) cleanupTXTRecord(ctx context.Context, fqdn, value string)
Records: updRecords,
SettingsHash: zone.SettingsHash,
}
-
- _, err = d.client.UpdateSettings(ctx, zone.ID, settings)
+ _, err = d.client.UpdateSettings(context.Background(), zone.ID, settings)
if err != nil {
return fmt.Errorf("API call failed: %w", err)
}
@@ -81,7 +79,7 @@ func (d *DNSProvider) cleanupTXTRecord(ctx context.Context, fqdn, value string)
return nil
}
-func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (*iaas.DNS, error) {
+func (d *DNSProvider) getHostedZone(domain string) (*iaas.DNS, error) {
authZone, err := dns01.FindZoneByFqdn(domain)
if err != nil {
return nil, fmt.Errorf("could not find zone: %w", err)
@@ -95,7 +93,7 @@ func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (*iaas.D
},
}
- res, err := d.client.Find(ctx, conditions)
+ res, err := d.client.Find(context.Background(), conditions)
if err != nil {
if iaas.IsNotFoundError(err) {
return nil, fmt.Errorf("zone %s not found on SakuraCloud DNS: %w", zoneName, err)
diff --git a/providers/dns/sakuracloud/wrapper_test.go b/providers/dns/sakuracloud/wrapper_test.go
index 7432c67a6..15eb19618 100644
--- a/providers/dns/sakuracloud/wrapper_test.go
+++ b/providers/dns/sakuracloud/wrapper_test.go
@@ -44,7 +44,6 @@ func createDummyZone(t *testing.T, caller iaas.APICaller) {
if zone.Name == "example.com" {
err = dnsOp.Delete(ctx, zone.ID)
require.NoError(t, err)
-
break
}
}
@@ -65,12 +64,10 @@ func TestDNSProvider_addAndCleanupRecords(t *testing.T) {
require.NoError(t, err)
t.Run("addTXTRecord", func(t *testing.T) {
- ctx := t.Context()
-
- err = p.addTXTRecord(ctx, "test.example.com.", "dummyValue", 10)
+ err = p.addTXTRecord("test.example.com.", "dummyValue", 10)
require.NoError(t, err)
- updZone, e := p.getHostedZone(ctx, "test.example.com.")
+ updZone, e := p.getHostedZone("test.example.com.")
require.NoError(t, e)
require.NotNil(t, updZone)
@@ -78,12 +75,10 @@ func TestDNSProvider_addAndCleanupRecords(t *testing.T) {
})
t.Run("cleanupTXTRecord", func(t *testing.T) {
- ctx := t.Context()
-
- err = p.cleanupTXTRecord(ctx, "test.example.com.", "dummyValue")
+ err = p.cleanupTXTRecord("test.example.com.", "dummyValue")
require.NoError(t, err)
- updZone, e := p.getHostedZone(ctx, "test.example.com.")
+ updZone, e := p.getHostedZone("test.example.com.")
require.NoError(t, e)
require.NotNil(t, updZone)
@@ -97,7 +92,6 @@ func TestDNSProvider_concurrentAddAndCleanupRecords(t *testing.T) {
dummyRecordCount := 10
var providers []*DNSProvider
-
for range dummyRecordCount {
config := NewDefaultConfig()
config.Token = "token3"
@@ -114,11 +108,9 @@ func TestDNSProvider_concurrentAddAndCleanupRecords(t *testing.T) {
t.Run("addTXTRecord", func(t *testing.T) {
wg.Add(len(providers))
- ctx := t.Context()
-
for i, p := range providers {
go func(j int, client *DNSProvider) {
- err := client.addTXTRecord(ctx, fmt.Sprintf("test%d.example.com.", j), "dummyValue", 10)
+ err := client.addTXTRecord(fmt.Sprintf("test%d.example.com.", j), "dummyValue", 10)
require.NoError(t, err)
wg.Done()
}(i, p)
@@ -126,7 +118,7 @@ func TestDNSProvider_concurrentAddAndCleanupRecords(t *testing.T) {
wg.Wait()
- updZone, err := providers[0].getHostedZone(ctx, "example.com.")
+ updZone, err := providers[0].getHostedZone("example.com.")
require.NoError(t, err)
require.NotNil(t, updZone)
@@ -136,11 +128,9 @@ func TestDNSProvider_concurrentAddAndCleanupRecords(t *testing.T) {
t.Run("cleanupTXTRecord", func(t *testing.T) {
wg.Add(len(providers))
- ctx := t.Context()
-
for i, p := range providers {
go func(i int, client *DNSProvider) {
- err := client.cleanupTXTRecord(ctx, fmt.Sprintf("test%d.example.com.", i), "dummyValue")
+ err := client.cleanupTXTRecord(fmt.Sprintf("test%d.example.com.", i), "dummyValue")
require.NoError(t, err)
wg.Done()
}(i, p)
@@ -148,7 +138,7 @@ func TestDNSProvider_concurrentAddAndCleanupRecords(t *testing.T) {
wg.Wait()
- updZone, err := providers[0].getHostedZone(ctx, "example.com.")
+ updZone, err := providers[0].getHostedZone("example.com.")
require.NoError(t, err)
require.NotNil(t, updZone)
diff --git a/providers/dns/scaleway/scaleway.go b/providers/dns/scaleway/scaleway.go
index 9d08f93b9..5976e77a2 100644
--- a/providers/dns/scaleway/scaleway.go
+++ b/providers/dns/scaleway/scaleway.go
@@ -5,7 +5,6 @@ package scaleway
import (
"errors"
"fmt"
- "net/http"
"strconv"
"strings"
"time"
@@ -13,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
scwdomain "github.com/scaleway/scaleway-sdk-go/api/domain/v2beta1"
"github.com/scaleway/scaleway-sdk-go/scw"
@@ -34,7 +32,6 @@ const (
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
const (
@@ -50,14 +47,12 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- ProjectID string
- Token string // TODO(ldez) rename to SecretKey in the next major.
- AccessKey string
-
+ ProjectID string
+ Token string // TODO(ldez) rename to SecretKey in the next major.
+ AccessKey string
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
- HTTPClient *http.Client
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
@@ -67,9 +62,6 @@ func NewDefaultConfig() *Config {
TTL: env.GetOneWithFallback(EnvTTL, minTTL, strconv.Atoi, altEnvName(EnvTTL)),
PropagationTimeout: env.GetOneWithFallback(EnvPropagationTimeout, defaultPropagationTimeout, env.ParseSecond, altEnvName(EnvPropagationTimeout)),
PollingInterval: env.GetOneWithFallback(EnvPollingInterval, defaultPollingInterval, env.ParseSecond, altEnvName(EnvPollingInterval)),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
}
}
@@ -115,10 +107,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
scw.WithUserAgent(useragent.Get()),
}
- if config.HTTPClient != nil {
- configuration = append(configuration, scw.WithHTTPClient(clientdebug.Wrap(config.HTTPClient)))
- }
-
if config.ProjectID != "" {
configuration = append(configuration, scw.WithDefaultProjectID(config.ProjectID))
}
diff --git a/providers/dns/scaleway/scaleway.toml b/providers/dns/scaleway/scaleway.toml
index 8b556e8b1..21839e061 100644
--- a/providers/dns/scaleway/scaleway.toml
+++ b/providers/dns/scaleway/scaleway.toml
@@ -6,7 +6,7 @@ Since = "v3.4.0"
Example = '''
SCW_SECRET_KEY=xxxxxxx-xxxxx-xxxx-xxx-xxxxxx \
-lego --dns scaleway -d '*.example.com' -d example.com run
+lego --email you@example.com --dns scaleway -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -18,7 +18,6 @@ lego --dns scaleway -d '*.example.com' -d example.com run
SCW_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 10)"
SCW_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
SCW_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"
- SCW_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
[Links]
API = "https://developers.scaleway.com/en/products/domain/dns/api/"
diff --git a/providers/dns/scaleway/scaleway_test.go b/providers/dns/scaleway/scaleway_test.go
index b683d751a..bf950e84e 100644
--- a/providers/dns/scaleway/scaleway_test.go
+++ b/providers/dns/scaleway/scaleway_test.go
@@ -41,7 +41,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -106,7 +105,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -120,7 +118,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/selectel/selectel.go b/providers/dns/selectel/selectel.go
index 63ddd81ac..c5da2215f 100644
--- a/providers/dns/selectel/selectel.go
+++ b/providers/dns/selectel/selectel.go
@@ -4,9 +4,11 @@
package selectel
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "net/url"
"time"
"github.com/go-acme/lego/v4/challenge"
@@ -28,16 +30,25 @@ const (
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
+const minTTL = 60
+
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
-type Config = selectel.Config
+type Config struct {
+ BaseURL string
+ Token string
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
- BaseURL: env.GetOrDefaultString(EnvBaseURL, ""),
- TTL: env.GetOrDefaultInt(EnvTTL, selectel.MinTTL),
+ BaseURL: env.GetOrDefaultString(EnvBaseURL, selectel.DefaultSelectelBaseURL),
+ TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPClient: &http.Client{
@@ -48,7 +59,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *selectel.Client
}
// NewDNSProvider returns a DNSProvider instance configured for Selectel Domains API.
@@ -71,36 +83,89 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("selectel: the configuration of the DNS provider is nil")
}
- provider, err := selectel.NewDNSProviderConfig(config)
+ if config.Token == "" {
+ return nil, errors.New("selectel: credentials missing")
+ }
+
+ if config.TTL < minTTL {
+ return nil, fmt.Errorf("selectel: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
+ }
+
+ client := selectel.NewClient(config.Token)
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ var err error
+ client.BaseURL, err = url.Parse(config.BaseURL)
if err != nil {
return nil, fmt.Errorf("selectel: %w", err)
}
- return &DNSProvider{prv: provider}, nil
+ return &DNSProvider{config: config, client: client}, nil
}
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("selectel: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("selectel: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
+// Timeout returns the Timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+ return d.config.PropagationTimeout, d.config.PollingInterval
+}
+
+// Present creates a TXT record to fulfill DNS-01 challenge.
+func (d *DNSProvider) Present(domain, token, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ ctx := context.Background()
+
+ // TODO(ldez) replace domain by FQDN to follow CNAME.
+ domainObj, err := d.client.GetDomainByName(ctx, domain)
+ if err != nil {
+ return fmt.Errorf("selectel: %w", err)
+ }
+
+ txtRecord := selectel.Record{
+ Type: "TXT",
+ TTL: d.config.TTL,
+ Name: info.EffectiveFQDN,
+ Content: info.Value,
+ }
+ _, err = d.client.AddRecord(ctx, domainObj.ID, txtRecord)
+ if err != nil {
+ return fmt.Errorf("selectel: %w", err)
+ }
+
+ return nil
+}
+
+// CleanUp removes a TXT record used for DNS-01 challenge.
+func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ recordName := dns01.UnFqdn(info.EffectiveFQDN)
+
+ ctx := context.Background()
+
+ // TODO(ldez) replace domain by FQDN to follow CNAME.
+ domainObj, err := d.client.GetDomainByName(ctx, domain)
+ if err != nil {
+ return fmt.Errorf("selectel: %w", err)
+ }
+
+ records, err := d.client.ListRecords(ctx, domainObj.ID)
+ if err != nil {
+ return fmt.Errorf("selectel: %w", err)
+ }
+
+ // Delete records with specific FQDN
+ var lastErr error
+ for _, record := range records {
+ if record.Name == recordName {
+ err = d.client.DeleteRecord(ctx, domainObj.ID, record.ID)
+ if err != nil {
+ lastErr = fmt.Errorf("selectel: %w", err)
+ }
+ }
+ }
+
+ return lastErr
}
diff --git a/providers/dns/selectel/selectel.toml b/providers/dns/selectel/selectel.toml
index 087c97b5b..f9add7ea9 100644
--- a/providers/dns/selectel/selectel.toml
+++ b/providers/dns/selectel/selectel.toml
@@ -6,7 +6,7 @@ Since = "v1.2.0"
Example = '''
SELECTEL_API_TOKEN=xxxxx \
-lego --dns selectel -d '*.example.com' -d example.com run
+lego --email you@example.com --dns selectel -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/selectel/selectel_test.go b/providers/dns/selectel/selectel_test.go
index a456f1358..0e2de2dbe 100644
--- a/providers/dns/selectel/selectel_test.go
+++ b/providers/dns/selectel/selectel_test.go
@@ -6,7 +6,6 @@ import (
"time"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/providers/dns/internal/selectel"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -37,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -47,7 +45,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- assert.NotNil(t, p.prv)
+ assert.NotNil(t, p.config)
+ assert.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -77,7 +76,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
desc: "bad TTL value",
token: "123",
ttl: 59,
- expected: fmt.Sprintf("selectel: invalid TTL, TTL (59) must be greater than %d", selectel.MinTTL),
+ expected: fmt.Sprintf("selectel: invalid TTL, TTL (59) must be greater than %d", minTTL),
},
}
@@ -92,7 +91,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- assert.NotNil(t, p.prv)
+ assert.NotNil(t, p.config)
+ assert.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -106,7 +106,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -120,7 +119,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/selectelv2/selectelv2.go b/providers/dns/selectelv2/selectelv2.go
index 1fcb48583..ca0a9107d 100644
--- a/providers/dns/selectelv2/selectelv2.go
+++ b/providers/dns/selectelv2/selectelv2.go
@@ -11,9 +11,7 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
- "github.com/miekg/dns"
selectelapi "github.com/selectel/domains-go/pkg/v2"
"github.com/selectel/go-selvpcclient/v4/selvpcclient"
"golang.org/x/net/idna"
@@ -22,14 +20,11 @@ import (
const (
envNamespace = "SELECTELV2_"
- EnvBaseURL = envNamespace + "BASE_URL"
- EnvUsernameOS = envNamespace + "USERNAME"
- EnvPasswordOS = envNamespace + "PASSWORD"
- EnvDomainName = envNamespace + "ACCOUNT_ID"
- EnvProjectID = envNamespace + "PROJECT_ID"
- EnvAuthRegion = envNamespace + "AUTH_REGION"
- EnvAuthURL = envNamespace + "AUTH_URL"
- EnvUserDomainName = envNamespace + "USER_DOMAIN_NAME"
+ EnvBaseURL = envNamespace + "BASE_URL"
+ EnvUsernameOS = envNamespace + "USERNAME"
+ EnvPasswordOS = envNamespace + "PASSWORD"
+ EnvAccount = envNamespace + "ACCOUNT_ID"
+ EnvProjectID = envNamespace + "PROJECT_ID"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@@ -38,12 +33,7 @@ const (
)
const (
- defaultBaseURL = "https://api.selectel.ru/domains/v2"
- defaultAuthRegion = "ru-1"
- defaultAuthURL = "https://cloud.api.selcloud.ru/identity/v3/"
-)
-
-const (
+ defaultBaseURL = "https://api.selectel.ru/domains/v2"
defaultTTL = 60
defaultPropagationTimeout = 120 * time.Second
defaultPollingInterval = 5 * time.Second
@@ -56,15 +46,11 @@ var errNotFound = errors.New("rrset not found")
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- BaseURL string
- Username string
- Password string
- DomainName string
- ProjectID string
- AuthURL string
- AuthRegion string
- UserDomainName string
-
+ BaseURL string
+ Username string
+ Password string
+ Account string
+ ProjectID string
TTL int
PropagationTimeout time.Duration
PollingInterval time.Duration
@@ -74,10 +60,7 @@ type Config struct {
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
- BaseURL: env.GetOrDefaultString(EnvBaseURL, defaultBaseURL),
- AuthRegion: env.GetOrDefaultString(EnvAuthRegion, defaultAuthRegion),
- AuthURL: env.GetOrDefaultString(EnvAuthURL, defaultAuthURL),
-
+ BaseURL: env.GetOrDefaultString(EnvBaseURL, defaultBaseURL),
TTL: env.GetOrDefaultInt(EnvTTL, defaultTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, defaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, defaultPollingInterval),
@@ -94,7 +77,7 @@ type DNSProvider struct {
// NewDNSProvider returns a DNSProvider instance configured for Selectel Domains APIv2.
func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvUsernameOS, EnvPasswordOS, EnvDomainName, EnvProjectID)
+ values, err := env.Get(EnvUsernameOS, EnvPasswordOS, EnvAccount, EnvProjectID)
if err != nil {
return nil, fmt.Errorf("selectelv2: %w", err)
}
@@ -102,9 +85,8 @@ func NewDNSProvider() (*DNSProvider, error) {
config := NewDefaultConfig()
config.Username = values[EnvUsernameOS]
config.Password = values[EnvPasswordOS]
- config.DomainName = values[EnvDomainName]
+ config.Account = values[EnvAccount]
config.ProjectID = values[EnvProjectID]
- config.UserDomainName = env.GetOrDefaultString(EnvUserDomainName, "")
return NewDNSProviderConfig(config)
}
@@ -123,8 +105,8 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("selectelv2: missing password")
}
- if config.DomainName == "" {
- return nil, errors.New("selectelv2: missing account ID")
+ if config.Account == "" {
+ return nil, errors.New("selectelv2: missing account")
}
if config.ProjectID == "" {
@@ -135,7 +117,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
useragent.SetHeader(headers)
return &DNSProvider{
- baseClient: selectelapi.NewClient(config.BaseURL, clientdebug.Wrap(config.HTTPClient), headers),
+ baseClient: selectelapi.NewClient(config.BaseURL, config.HTTPClient, headers),
config: config,
}, nil
}
@@ -150,7 +132,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
func (d *DNSProvider) Present(domain, _, keyAuth string) error {
ctx := context.Background()
- client, err := d.authorize(ctx)
+ client, err := d.authorize()
if err != nil {
return fmt.Errorf("selectelv2: authorize: %w", err)
}
@@ -197,7 +179,7 @@ func (d *DNSProvider) Present(domain, _, keyAuth string) error {
func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
ctx := context.Background()
- client, err := d.authorize(ctx)
+ client, err := d.authorize()
if err != nil {
return fmt.Errorf("selectelv2: authorize: %w", err)
}
@@ -238,8 +220,8 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
return nil
}
-func (d *DNSProvider) authorize(ctx context.Context) (*clientWrapper, error) {
- token, err := obtainOpenstackToken(ctx, d.config)
+func (d *DNSProvider) authorize() (*clientWrapper, error) {
+ token, err := obtainOpenstackToken(d.config)
if err != nil {
return nil, err
}
@@ -252,16 +234,12 @@ func (d *DNSProvider) authorize(ctx context.Context) (*clientWrapper, error) {
}, nil
}
-func obtainOpenstackToken(ctx context.Context, config *Config) (string, error) {
+func obtainOpenstackToken(config *Config) (string, error) {
vpcClient, err := selvpcclient.NewClient(&selvpcclient.ClientOptions{
- Context: ctx,
- DomainName: config.DomainName,
- AuthURL: config.AuthURL,
- AuthRegion: config.AuthRegion,
Username: config.Username,
Password: config.Password,
+ UserDomainName: config.Account,
ProjectID: config.ProjectID,
- UserDomainName: config.UserDomainName,
})
if err != nil {
return "", fmt.Errorf("new VPC client: %w", err)
@@ -288,7 +266,7 @@ func (w *clientWrapper) getZone(ctx context.Context, name string) (*selectelapi.
}
for _, zone := range zones.GetItems() {
- if zone.Name == dns.Fqdn(unicodeName) {
+ if zone.Name == dns01.ToFqdn(unicodeName) {
return zone, nil
}
}
@@ -297,10 +275,10 @@ func (w *clientWrapper) getZone(ctx context.Context, name string) (*selectelapi.
return nil, fmt.Errorf("zone '%s' for challenge has not been found", name)
}
- // after is always defined since if no dots present we exit above.
- _, after, _ := strings.Cut(name, ".")
+ // -1 can not be returned since if no dots present we exit above
+ i := strings.Index(name, ".")
- return w.getZone(ctx, after)
+ return w.getZone(ctx, name[i+1:])
}
func (w *clientWrapper) getRRset(ctx context.Context, name, zoneID string) (*selectelapi.RRSet, error) {
@@ -317,7 +295,7 @@ func (w *clientWrapper) getRRset(ctx context.Context, name, zoneID string) (*sel
}
for _, rrset := range resp.GetItems() {
- if rrset.Name == dns.Fqdn(unicodeName) {
+ if rrset.Name == dns01.ToFqdn(unicodeName) {
return rrset, nil
}
}
diff --git a/providers/dns/selectelv2/selectelv2.toml b/providers/dns/selectelv2/selectelv2.toml
index 480c7756e..4993cb0f8 100644
--- a/providers/dns/selectelv2/selectelv2.toml
+++ b/providers/dns/selectelv2/selectelv2.toml
@@ -9,7 +9,7 @@ SELECTELV2_USERNAME=trex \
SELECTELV2_PASSWORD=xxxxx \
SELECTELV2_ACCOUNT_ID=1234567 \
SELECTELV2_PROJECT_ID=111a11111aaa11aa1a11aaa11111aa1a \
-lego --dns selectelv2 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns selectelv2 -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -20,9 +20,6 @@ lego --dns selectelv2 -d '*.example.com' -d example.com run
SELECTELV2_PROJECT_ID = "Cloud project ID (UUID)"
[Configuration.Additional]
SELECTELV2_BASE_URL = "API endpoint URL"
- SELECTELV2_AUTH_REGION = "Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1')"
- SELECTELV2_AUTH_URL = "Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/')"
- SELECTELV2_USER_DOMAIN_NAME = "To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID)"
SELECTELV2_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 5)"
SELECTELV2_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
SELECTELV2_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)"
diff --git a/providers/dns/selectelv2/selectelv2_test.go b/providers/dns/selectelv2/selectelv2_test.go
index 2627fa023..4859b9932 100644
--- a/providers/dns/selectelv2/selectelv2_test.go
+++ b/providers/dns/selectelv2/selectelv2_test.go
@@ -11,15 +11,7 @@ import (
const envDomain = envNamespace + "DOMAIN"
-var envTest = tester.NewEnvTest(
- EnvUsernameOS,
- EnvPasswordOS,
- EnvDomainName,
- EnvUserDomainName,
- EnvProjectID,
- EnvAuthRegion,
- EnvAuthURL,
-).
+var envTest = tester.NewEnvTest(EnvUsernameOS, EnvPasswordOS, EnvAccount, EnvProjectID).
WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) {
@@ -33,7 +25,7 @@ func TestNewDNSProvider(t *testing.T) {
envVars: map[string]string{
EnvUsernameOS: "someName",
EnvPasswordOS: "qwerty",
- EnvDomainName: "1",
+ EnvAccount: "1",
EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a",
},
},
@@ -41,7 +33,7 @@ func TestNewDNSProvider(t *testing.T) {
desc: "missing username",
envVars: map[string]string{
EnvPasswordOS: "qwerty",
- EnvDomainName: "1",
+ EnvAccount: "1",
EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a",
},
expected: "selectelv2: some credentials information are missing: SELECTELV2_USERNAME",
@@ -50,7 +42,7 @@ func TestNewDNSProvider(t *testing.T) {
desc: "missing password",
envVars: map[string]string{
EnvUsernameOS: "someName",
- EnvDomainName: "1",
+ EnvAccount: "1",
EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a",
},
expected: "selectelv2: some credentials information are missing: SELECTELV2_PASSWORD",
@@ -69,7 +61,7 @@ func TestNewDNSProvider(t *testing.T) {
envVars: map[string]string{
EnvUsernameOS: "someName",
EnvPasswordOS: "qwerty",
- EnvDomainName: "1",
+ EnvAccount: "1",
},
expected: "selectelv2: some credentials information are missing: SELECTELV2_PROJECT_ID",
},
@@ -78,7 +70,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -132,7 +123,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
username: "user",
password: "secret",
projectID: "111a11111aaa11aa1a11aaa11111aa1a",
- expected: "selectelv2: missing account ID",
+ expected: "selectelv2: missing account",
},
{
desc: "missing projectID",
@@ -148,7 +139,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
config := NewDefaultConfig()
config.Username = test.username
config.Password = test.password
- config.DomainName = test.account
+ config.Account = test.account
config.ProjectID = test.projectID
p, err := NewDNSProviderConfig(config)
@@ -171,7 +162,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -185,7 +175,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/selfhostde/mapping.go b/providers/dns/selfhostde/mapping.go
index fe11ceda1..0984419ef 100644
--- a/providers/dns/selfhostde/mapping.go
+++ b/providers/dns/selfhostde/mapping.go
@@ -88,10 +88,8 @@ func parseLine(line string) (string, *Seq, error) {
name, rawIDs := line[:idx], line[idx+1:]
- var (
- ids []string
- count int
- )
+ var ids []string
+ var count int
for {
idx, err = safeIndex(rawIDs, recordSep)
diff --git a/providers/dns/selfhostde/selfhostde.go b/providers/dns/selfhostde/selfhostde.go
index 035cd5363..0fea9f1d0 100644
--- a/providers/dns/selfhostde/selfhostde.go
+++ b/providers/dns/selfhostde/selfhostde.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/selfhostde/internal"
)
@@ -133,8 +132,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -176,7 +173,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("selfhostde: unknown record ID for %q", dns01.UnFqdn(info.EffectiveFQDN))
}
@@ -186,9 +182,5 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("selfhostde: emptied DNS TXT record (id=%s): %w", recordID, err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/selfhostde/selfhostde.toml b/providers/dns/selfhostde/selfhostde.toml
index bd22c6c41..619f2cae8 100644
--- a/providers/dns/selfhostde/selfhostde.toml
+++ b/providers/dns/selfhostde/selfhostde.toml
@@ -8,7 +8,7 @@ Example = '''
SELFHOSTDE_USERNAME=xxx \
SELFHOSTDE_PASSWORD=yyy \
SELFHOSTDE_RECORDS_MAPPING=my.example.com:123 \
-lego --dns selfhostde -d '*.example.com' -d example.com run
+lego --email you@example.com --dns selfhostde -d '*.example.com' -d example.com run
'''
Additional = """
diff --git a/providers/dns/selfhostde/selfhostde_test.go b/providers/dns/selfhostde/selfhostde_test.go
index 7c12195fa..1161049b0 100644
--- a/providers/dns/selfhostde/selfhostde_test.go
+++ b/providers/dns/selfhostde/selfhostde_test.go
@@ -71,7 +71,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -186,7 +185,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -200,7 +198,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/servercow/internal/client.go b/providers/dns/servercow/internal/client.go
index e15237201..3695b0979 100644
--- a/providers/dns/servercow/internal/client.go
+++ b/providers/dns/servercow/internal/client.go
@@ -47,7 +47,6 @@ func (c *Client) GetRecords(ctx context.Context, domain string) ([]Record, error
}
var records []Record
-
err = c.do(req, &records)
if err != nil {
return nil, err
@@ -66,7 +65,6 @@ func (c *Client) CreateUpdateRecord(ctx context.Context, domain string, data Rec
}
var msg Message
-
err = c.do(req, &msg)
if err != nil {
return nil, err
@@ -89,7 +87,6 @@ func (c *Client) DeleteRecord(ctx context.Context, domain string, data Record) (
}
var msg Message
-
err = c.do(req, &msg)
if err != nil {
return nil, err
@@ -171,7 +168,6 @@ func unmarshal(raw []byte, v any) error {
}
var apiErr Message
-
errU := json.Unmarshal(raw, &apiErr)
if errU != nil {
return fmt.Errorf("unmarshaling %T error: %w: %s", v, err, string(raw))
diff --git a/providers/dns/servercow/internal/client_test.go b/providers/dns/servercow/internal/client_test.go
index 3733ccad1..2092bf907 100644
--- a/providers/dns/servercow/internal/client_test.go
+++ b/providers/dns/servercow/internal/client_test.go
@@ -29,10 +29,10 @@ func mockBuilder() *servermock.Builder[*Client] {
func TestClient_GetRecords(t *testing.T) {
client := mockBuilder().
- Route("GET /example.com", servermock.ResponseFromFixture("records-01.json")).
+ Route("GET /lego.wtf", servermock.ResponseFromFixture("records-01.json")).
Build(t)
- records, err := client.GetRecords(t.Context(), "example.com")
+ records, err := client.GetRecords(t.Context(), "lego.wtf")
require.NoError(t, err)
recordsJSON, err := json.Marshal(records)
@@ -46,10 +46,10 @@ func TestClient_GetRecords(t *testing.T) {
func TestClient_GetRecords_error(t *testing.T) {
client := mockBuilder().
- Route("GET /example.com", servermock.JSONEncode(Message{ErrorMsg: "authentication failed"})).
+ Route("GET /lego.wtf", servermock.JSONEncode(Message{ErrorMsg: "authentication failed"})).
Build(t)
- records, err := client.GetRecords(t.Context(), "example.com")
+ records, err := client.GetRecords(t.Context(), "lego.wtf")
require.Error(t, err)
assert.Nil(t, records)
@@ -57,7 +57,7 @@ func TestClient_GetRecords_error(t *testing.T) {
func TestClient_CreateUpdateRecord(t *testing.T) {
client := mockBuilder().
- Route("POST /example.com",
+ Route("POST /lego.wtf",
servermock.JSONEncode(Message{Message: "ok"}),
servermock.CheckRequestJSONBody(`{"name":"_acme-challenge.www","type":"TXT","ttl":30,"content":["aaa","bbb"]}`)).
Build(t)
@@ -69,7 +69,7 @@ func TestClient_CreateUpdateRecord(t *testing.T) {
Content: Value{"aaa", "bbb"},
}
- msg, err := client.CreateUpdateRecord(t.Context(), "example.com", record)
+ msg, err := client.CreateUpdateRecord(t.Context(), "lego.wtf", record)
require.NoError(t, err)
expected := &Message{Message: "ok"}
@@ -78,7 +78,7 @@ func TestClient_CreateUpdateRecord(t *testing.T) {
func TestClient_CreateUpdateRecord_error(t *testing.T) {
client := mockBuilder().
- Route("POST /example.com",
+ Route("POST /lego.wtf",
servermock.JSONEncode(Message{ErrorMsg: "parameter type must be cname, txt, tlsa, caa, a or aaaa"})).
Build(t)
@@ -86,7 +86,7 @@ func TestClient_CreateUpdateRecord_error(t *testing.T) {
Name: "_acme-challenge.www",
}
- msg, err := client.CreateUpdateRecord(t.Context(), "example.com", record)
+ msg, err := client.CreateUpdateRecord(t.Context(), "lego.wtf", record)
require.Error(t, err)
assert.Nil(t, msg)
@@ -94,7 +94,7 @@ func TestClient_CreateUpdateRecord_error(t *testing.T) {
func TestClient_DeleteRecord(t *testing.T) {
client := mockBuilder().
- Route("DELETE /example.com",
+ Route("DELETE /lego.wtf",
servermock.JSONEncode(Message{Message: "ok"}),
servermock.CheckRequestJSONBody(`{"name":"_acme-challenge.www","type":"TXT"}`)).
Build(t)
@@ -104,7 +104,7 @@ func TestClient_DeleteRecord(t *testing.T) {
Type: "TXT",
}
- msg, err := client.DeleteRecord(t.Context(), "example.com", record)
+ msg, err := client.DeleteRecord(t.Context(), "lego.wtf", record)
require.NoError(t, err)
expected := &Message{Message: "ok"}
@@ -113,7 +113,7 @@ func TestClient_DeleteRecord(t *testing.T) {
func TestClient_DeleteRecord_error(t *testing.T) {
client := mockBuilder().
- Route("DELETE /example.com",
+ Route("DELETE /lego.wtf",
servermock.JSONEncode(Message{ErrorMsg: "parameter type must be cname, txt, tlsa, caa, a or aaaa"})).
Build(t)
@@ -121,7 +121,7 @@ func TestClient_DeleteRecord_error(t *testing.T) {
Name: "_acme-challenge.www",
}
- msg, err := client.DeleteRecord(t.Context(), "example.com", record)
+ msg, err := client.DeleteRecord(t.Context(), "lego.wtf", record)
require.Error(t, err)
assert.Nil(t, msg)
diff --git a/providers/dns/servercow/internal/types.go b/providers/dns/servercow/internal/types.go
index 9a951e806..5a8fb6ff8 100644
--- a/providers/dns/servercow/internal/types.go
+++ b/providers/dns/servercow/internal/types.go
@@ -43,7 +43,6 @@ func (v *Value) UnmarshalJSON(b []byte) error {
}
*v = append(*v, s)
-
return nil
}
diff --git a/providers/dns/servercow/servercow.go b/providers/dns/servercow/servercow.go
index 557c6b1ec..56f89f900 100644
--- a/providers/dns/servercow/servercow.go
+++ b/providers/dns/servercow/servercow.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/servercow/internal"
)
@@ -86,8 +85,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -140,7 +137,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("servercow: failed to update TXT records: %w", err)
}
-
return nil
}
@@ -195,7 +191,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("servercow: failed to delete TXT records: %w", err)
}
-
return nil
}
diff --git a/providers/dns/servercow/servercow.toml b/providers/dns/servercow/servercow.toml
index 5cbacbb88..655257b84 100644
--- a/providers/dns/servercow/servercow.toml
+++ b/providers/dns/servercow/servercow.toml
@@ -7,7 +7,7 @@ Since = "v3.4.0"
Example = '''
SERVERCOW_USERNAME=xxxxxxxx \
SERVERCOW_PASSWORD=xxxxxxxx \
-lego --dns servercow -d '*.example.com' -d example.com run
+lego --email you@example.com --dns servercow -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -21,4 +21,4 @@ lego --dns servercow -d '*.example.com' -d example.com run
SERVERCOW_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
[Links]
- API = "https://wiki.servercow.de/en/domains/dns_api/api-syntax/"
+ API = "https://cp.servercow.de/client/plugin/support_manager/knowledgebase/view/34/dns-api-v1/7/"
diff --git a/providers/dns/servercow/servercow_test.go b/providers/dns/servercow/servercow_test.go
index f2328fe1a..1c3facad9 100644
--- a/providers/dns/servercow/servercow_test.go
+++ b/providers/dns/servercow/servercow_test.go
@@ -57,7 +57,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -130,7 +129,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -144,7 +142,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/shellrent/internal/client.go b/providers/dns/shellrent/internal/client.go
index a70ff5452..8ec02bfc0 100644
--- a/providers/dns/shellrent/internal/client.go
+++ b/providers/dns/shellrent/internal/client.go
@@ -114,7 +114,6 @@ func (c *Client) GetDomainDetails(ctx context.Context, domainID int) (*DomainDet
if result.Code != 0 {
return nil, result.Base
}
-
return result.Data, nil
}
@@ -138,7 +137,6 @@ func (c *Client) CreateRecord(ctx context.Context, domainID int, record Record)
if result.Code != 0 {
return 0, result.Base
}
-
return result.Data.ID.Value(), nil
}
@@ -221,7 +219,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var response Base
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/shellrent/internal/types.go b/providers/dns/shellrent/internal/types.go
index 6bdd82330..a27b06347 100644
--- a/providers/dns/shellrent/internal/types.go
+++ b/providers/dns/shellrent/internal/types.go
@@ -7,7 +7,6 @@ import (
type Response[T any] struct {
Base
-
Data T `json:"data"`
}
@@ -58,7 +57,6 @@ func (m *IntOrString) UnmarshalJSON(data []byte) error {
raw := string(data)
if data[0] == '"' {
var err error
-
raw, err = strconv.Unquote(string(data))
if err != nil {
return err
diff --git a/providers/dns/shellrent/shellrent.go b/providers/dns/shellrent/shellrent.go
index 0cd33e19a..488509a84 100644
--- a/providers/dns/shellrent/shellrent.go
+++ b/providers/dns/shellrent/shellrent.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/shellrent/internal"
)
@@ -104,8 +103,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -162,7 +159,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
key, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("shellrent: unknown request key for '%s' '%s'", info.EffectiveFQDN, token)
}
@@ -172,10 +168,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("shellrent: delete record: %w", err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/shellrent/shellrent.toml b/providers/dns/shellrent/shellrent.toml
index 05b6517fc..48a5b9ad9 100644
--- a/providers/dns/shellrent/shellrent.toml
+++ b/providers/dns/shellrent/shellrent.toml
@@ -7,7 +7,7 @@ Since = "v4.16.0"
Example = '''
SHELLRENT_USERNAME=xxxx \
SHELLRENT_TOKEN=yyyy \
-lego --dns shellrent -d '*.example.com' -d example.com run
+lego --email you@example.com --dns shellrent -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/shellrent/shellrent_test.go b/providers/dns/shellrent/shellrent_test.go
index 8c4e3f6bf..e5d529917 100644
--- a/providers/dns/shellrent/shellrent_test.go
+++ b/providers/dns/shellrent/shellrent_test.go
@@ -47,7 +47,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -118,7 +117,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -132,7 +130,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/simply/internal/client.go b/providers/dns/simply/internal/client.go
index 0c0655463..74f5fe671 100644
--- a/providers/dns/simply/internal/client.go
+++ b/providers/dns/simply/internal/client.go
@@ -16,7 +16,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
)
-const defaultBaseURL = "https://api.simply.com/2/"
+const defaultBaseURL = "https://api.simply.com/1/"
// Client is a Simply.com API client.
type Client struct {
@@ -60,7 +60,6 @@ func (c *Client) GetRecords(ctx context.Context, zoneName string) ([]Record, err
}
result := &apiResponse[[]Record, json.RawMessage]{}
-
err = c.do(req, result)
if err != nil {
return nil, err
@@ -79,7 +78,6 @@ func (c *Client) AddRecord(ctx context.Context, zoneName string, record Record)
}
result := &apiResponse[json.RawMessage, recordHeader]{}
-
err = c.do(req, result)
if err != nil {
return 0, err
@@ -113,12 +111,10 @@ func (c *Client) DeleteRecord(ctx context.Context, zoneName string, id int64) er
}
func (c *Client) createEndpoint(zoneName, uri string) *url.URL {
- return c.baseURL.JoinPath("my", "products", zoneName, "dns", "records", strings.TrimSuffix(uri, "/"))
+ return c.baseURL.JoinPath(c.accountName, c.apiKey, "my", "products", zoneName, "dns", "records", strings.TrimSuffix(uri, "/"))
}
func (c *Client) do(req *http.Request, result Response) error {
- req.SetBasicAuth(c.accountName, c.apiKey)
-
resp, err := c.HTTPClient.Do(req)
if err != nil {
return errutils.NewHTTPDoError(req, err)
diff --git a/providers/dns/simply/internal/client_test.go b/providers/dns/simply/internal/client_test.go
index b0bdac6b3..83aa714bf 100644
--- a/providers/dns/simply/internal/client_test.go
+++ b/providers/dns/simply/internal/client_test.go
@@ -24,13 +24,12 @@ func mockBuilder() *servermock.Builder[*Client] {
return client, nil
},
- servermock.CheckHeader().WithJSONHeaders().
- WithBasicAuth("accountname", "apikey"))
+ servermock.CheckHeader().WithJSONHeaders())
}
func TestClient_GetRecords(t *testing.T) {
client := mockBuilder().
- Route("GET /my/products/azone01/dns/records",
+ Route("GET /accountname/apikey/my/products/azone01/dns/records",
servermock.ResponseFromFixture("get_records.json")).
Build(t)
@@ -77,7 +76,7 @@ func TestClient_GetRecords(t *testing.T) {
func TestClient_GetRecords_error(t *testing.T) {
client := mockBuilder().
- Route("GET /my/products/azone01/dns/records",
+ Route("GET /accountname/apikey/my/products/azone01/dns/records",
servermock.ResponseFromFixture("bad_auth_error.json").
WithStatusCode(http.StatusBadRequest)).
Build(t)
@@ -90,7 +89,7 @@ func TestClient_GetRecords_error(t *testing.T) {
func TestClient_AddRecord(t *testing.T) {
client := mockBuilder().
- Route("POST /my/products/azone01/dns/records",
+ Route("POST /accountname/apikey/my/products/azone01/dns/records",
servermock.ResponseFromFixture("add_record.json")).
Build(t)
@@ -110,7 +109,7 @@ func TestClient_AddRecord(t *testing.T) {
func TestClient_AddRecord_error(t *testing.T) {
client := mockBuilder().
- Route("POST /my/products/azone01/dns/records",
+ Route("POST /accountname/apikey/my/products/azone01/dns/records",
servermock.ResponseFromFixture("bad_zone_error.json").
WithStatusCode(http.StatusNotFound)).
Build(t)
@@ -131,7 +130,7 @@ func TestClient_AddRecord_error(t *testing.T) {
func TestClient_EditRecord(t *testing.T) {
client := mockBuilder().
- Route("PUT /my/products/azone01/dns/records/123456789",
+ Route("PUT /accountname/apikey/my/products/azone01/dns/records/123456789",
servermock.ResponseFromFixture("success.json")).
Build(t)
@@ -149,7 +148,7 @@ func TestClient_EditRecord(t *testing.T) {
func TestClient_EditRecord_error(t *testing.T) {
client := mockBuilder().
- Route("PUT /my/products/azone01/dns/records/123456789",
+ Route("PUT /accountname/apikey/my/products/azone01/dns/records/123456789",
servermock.ResponseFromFixture("invalid_record_id.json").
WithStatusCode(http.StatusNotFound)).
Build(t)
@@ -168,7 +167,7 @@ func TestClient_EditRecord_error(t *testing.T) {
func TestClient_DeleteRecord(t *testing.T) {
client := mockBuilder().
- Route("DELETE /my/products/azone01/dns/records/123456789",
+ Route("DELETE /accountname/apikey/my/products/azone01/dns/records/123456789",
servermock.ResponseFromFixture("success.json")).
Build(t)
@@ -178,7 +177,7 @@ func TestClient_DeleteRecord(t *testing.T) {
func TestClient_DeleteRecord_error(t *testing.T) {
client := mockBuilder().
- Route("DELETE /my/products/azone01/dns/records/123456789",
+ Route("DELETE /accountname/apikey/my/products/azone01/dns/records/123456789",
servermock.ResponseFromFixture("invalid_record_id.json").
WithStatusCode(http.StatusNotFound)).
Build(t)
diff --git a/providers/dns/simply/simply.go b/providers/dns/simply/simply.go
index fc3afd310..d2bfb1874 100644
--- a/providers/dns/simply/simply.go
+++ b/providers/dns/simply/simply.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/simply/internal"
)
@@ -100,8 +99,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -165,7 +162,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("simply: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
diff --git a/providers/dns/simply/simply.toml b/providers/dns/simply/simply.toml
index a838e245a..2814fd955 100644
--- a/providers/dns/simply/simply.toml
+++ b/providers/dns/simply/simply.toml
@@ -7,7 +7,7 @@ Since = "v4.4.0"
Example = '''
SIMPLY_ACCOUNT_NAME=xxxxxx \
SIMPLY_API_KEY=yyyyyy \
-lego --dns simply -d '*.example.com' -d example.com run
+lego --email you@example.com --dns simply -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -22,4 +22,3 @@ lego --dns simply -d '*.example.com' -d example.com run
[Links]
API = "https://www.simply.com/en/docs/api/"
- Spec = "https://generator.swagger.io/?url=https://api.simply.com/2/openapi.json#/"
diff --git a/providers/dns/simply/simply_test.go b/providers/dns/simply/simply_test.go
index e6de60d43..ace8e0b72 100644
--- a/providers/dns/simply/simply_test.go
+++ b/providers/dns/simply/simply_test.go
@@ -53,7 +53,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -122,7 +121,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -136,7 +134,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/sonic/internal/client.go b/providers/dns/sonic/internal/client.go
index cf8f7f067..3007a8248 100644
--- a/providers/dns/sonic/internal/client.go
+++ b/providers/dns/sonic/internal/client.go
@@ -83,7 +83,6 @@ func (c *Client) SetRecord(ctx context.Context, hostname, value string, ttl int)
}
r := APIResponse{}
-
err = json.Unmarshal(raw, &r)
if err != nil {
return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/sonic/sonic.go b/providers/dns/sonic/sonic.go
index 5bda2b533..80f5ea295 100644
--- a/providers/dns/sonic/sonic.go
+++ b/providers/dns/sonic/sonic.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/sonic/internal"
)
@@ -92,8 +91,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{client: client, config: config}, nil
}
diff --git a/providers/dns/sonic/sonic.toml b/providers/dns/sonic/sonic.toml
index cb501e923..921fe4988 100644
--- a/providers/dns/sonic/sonic.toml
+++ b/providers/dns/sonic/sonic.toml
@@ -7,7 +7,7 @@ Since = "v4.4.0"
Example = '''
SONIC_USER_ID=12345 \
SONIC_API_KEY=4d6fbf2f9ab0fa11697470918d37625851fc0c51 \
-lego --dns sonic -d '*.example.com' -d example.com run
+lego --email you@example.com --dns sonic -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/sonic/sonic_test.go b/providers/dns/sonic/sonic_test.go
index 7dc7fc586..f9087f8e3 100644
--- a/providers/dns/sonic/sonic_test.go
+++ b/providers/dns/sonic/sonic_test.go
@@ -49,7 +49,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -120,7 +119,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -134,7 +132,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/spaceship/internal/client.go b/providers/dns/spaceship/internal/client.go
index e690fa467..f739e01ba 100644
--- a/providers/dns/spaceship/internal/client.go
+++ b/providers/dns/spaceship/internal/client.go
@@ -114,7 +114,6 @@ func (c *Client) GetRecords(ctx context.Context, domain string) ([]Record, error
}
var result GetRecordsResponse
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -151,7 +150,6 @@ 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)
diff --git a/providers/dns/spaceship/spaceship.go b/providers/dns/spaceship/spaceship.go
index e34c584c5..9e8f0158e 100644
--- a/providers/dns/spaceship/spaceship.go
+++ b/providers/dns/spaceship/spaceship.go
@@ -10,7 +10,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/spaceship/internal"
)
@@ -85,8 +84,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/spaceship/spaceship.toml b/providers/dns/spaceship/spaceship.toml
index e9abcd408..645abd171 100644
--- a/providers/dns/spaceship/spaceship.toml
+++ b/providers/dns/spaceship/spaceship.toml
@@ -7,7 +7,7 @@ Since = "v4.22.0"
Example = '''
SPACESHIP_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
SPACESHIP_API_SECRET="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns spaceship -d '*.example.com' -d example.com run
+lego --email you@example.com --dns spaceship -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/spaceship/spaceship_test.go b/providers/dns/spaceship/spaceship_test.go
index d4eb37d88..ba60cfa5e 100644
--- a/providers/dns/spaceship/spaceship_test.go
+++ b/providers/dns/spaceship/spaceship_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -123,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/stackpath/internal/client.go b/providers/dns/stackpath/internal/client.go
index 8a40a4093..bd11bf235 100644
--- a/providers/dns/stackpath/internal/client.go
+++ b/providers/dns/stackpath/internal/client.go
@@ -25,13 +25,13 @@ type Client struct {
}
// NewClient creates a new Client.
-func NewClient(stackID string, hc *http.Client) *Client {
+func NewClient(ctx context.Context, stackID, clientID, clientSecret string) *Client {
baseURL, _ := url.Parse(defaultBaseURL)
return &Client{
baseURL: baseURL,
stackID: stackID,
- httpClient: hc,
+ httpClient: createOAuthClient(ctx, clientID, clientSecret),
}
}
@@ -55,7 +55,6 @@ func (c *Client) GetZones(ctx context.Context, domain string) (*Zone, error) {
req.URL.RawQuery = query.Encode()
var zones Zones
-
err = c.do(req, &zones)
if err != nil {
return nil, err
@@ -83,7 +82,6 @@ func (c *Client) GetZoneRecords(ctx context.Context, name string, zone *Zone) ([
req.URL.RawQuery = query.Encode()
var records Records
-
err = c.do(req, &records)
if err != nil {
return nil, err
@@ -179,7 +177,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
errResp := &ErrorResponse{}
-
err := json.Unmarshal(raw, errResp)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/stackpath/internal/client_test.go b/providers/dns/stackpath/internal/client_test.go
index baac84397..5195aa973 100644
--- a/providers/dns/stackpath/internal/client_test.go
+++ b/providers/dns/stackpath/internal/client_test.go
@@ -1,6 +1,7 @@
package internal
import (
+ "context"
"net/http"
"net/http/httptest"
"net/url"
@@ -14,8 +15,8 @@ import (
func mockBuilder() *servermock.Builder[*Client] {
return servermock.NewBuilder[*Client](
func(server *httptest.Server) (*Client, error) {
- client := NewClient("STACK_ID", server.Client())
-
+ client := NewClient(context.Background(), "STACK_ID", "CLIENT_ID", "CLIENT_SECRET")
+ client.httpClient = server.Client()
client.baseURL, _ = url.Parse(server.URL + "/")
return client, nil
diff --git a/providers/dns/stackpath/internal/identity.go b/providers/dns/stackpath/internal/identity.go
index fa3e9df07..5c6e6ab17 100644
--- a/providers/dns/stackpath/internal/identity.go
+++ b/providers/dns/stackpath/internal/identity.go
@@ -9,7 +9,7 @@ import (
const defaultAuthURL = "https://gateway.stackpath.com/identity/v1/oauth2/token"
-func CreateOAuthClient(ctx context.Context, clientID, clientSecret string) *http.Client {
+func createOAuthClient(ctx context.Context, clientID, clientSecret string) *http.Client {
config := &clientcredentials.Config{
TokenURL: defaultAuthURL,
ClientID: clientID,
diff --git a/providers/dns/stackpath/stackpath.go b/providers/dns/stackpath/stackpath.go
index 2e193b8a9..6d12ce875 100644
--- a/providers/dns/stackpath/stackpath.go
+++ b/providers/dns/stackpath/stackpath.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/stackpath/internal"
)
@@ -87,14 +86,9 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("stackpath: stack id missing")
}
- return &DNSProvider{
- config: config,
- client: internal.NewClient(config.StackID,
- clientdebug.Wrap(
- internal.CreateOAuthClient(context.Background(), config.ClientID, config.ClientSecret),
- ),
- ),
- }, nil
+ client := internal.NewClient(context.Background(), config.StackID, config.ClientID, config.ClientSecret)
+
+ return &DNSProvider{config: config, client: client}, nil
}
// Present creates a TXT record to fulfill the dns-01 challenge.
diff --git a/providers/dns/stackpath/stackpath.toml b/providers/dns/stackpath/stackpath.toml
index b50e7035f..cc14cdfba 100644
--- a/providers/dns/stackpath/stackpath.toml
+++ b/providers/dns/stackpath/stackpath.toml
@@ -8,7 +8,7 @@ Example = '''
STACKPATH_CLIENT_ID=xxxxx \
STACKPATH_CLIENT_SECRET=yyyyy \
STACKPATH_STACK_ID=zzzzz \
-lego --dns stackpath -d '*.example.com' -d example.com run
+lego --email you@example.com --dns stackpath -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/stackpath/stackpath_test.go b/providers/dns/stackpath/stackpath_test.go
index a4b959222..f8b83140f 100644
--- a/providers/dns/stackpath/stackpath_test.go
+++ b/providers/dns/stackpath/stackpath_test.go
@@ -72,7 +72,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -138,7 +137,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -152,7 +150,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/syse/internal/client.go b/providers/dns/syse/internal/client.go
deleted file mode 100644
index 8cb801469..000000000
--- a/providers/dns/syse/internal/client.go
+++ /dev/null
@@ -1,131 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://www.syse.no/api"
-
-// Client the Syse API client.
-type Client struct {
- credentials map[string]string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(credentials map[string]string) (*Client, error) {
- if len(credentials) == 0 {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- credentials: credentials,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) CreateRecord(ctx context.Context, zone string, record Record) (*Record, error) {
- endpoint := c.BaseURL.JoinPath("dns", zone)
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, record)
- if err != nil {
- return nil, err
- }
-
- req.SetBasicAuth(zone, c.credentials[zone])
-
- result := new(Record)
-
- err = c.do(req, result)
- if err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-func (c *Client) DeleteRecord(ctx context.Context, zone, recordID string) error {
- endpoint := c.BaseURL.JoinPath("dns", zone, recordID)
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return err
- }
-
- req.SetBasicAuth(zone, c.credentials[zone])
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- raw, _ := io.ReadAll(resp.Body)
-
- return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- return req, nil
-}
diff --git a/providers/dns/syse/internal/client_test.go b/providers/dns/syse/internal/client_test.go
deleted file mode 100644
index 88416aa88..000000000
--- a/providers/dns/syse/internal/client_test.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient(map[string]string{
- "example.com": "secret",
- })
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestClient_CreateRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/example.com",
- servermock.ResponseFromFixture("create_record.json"),
- servermock.CheckRequestJSONBodyFromFixture("create_record-request.json")).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Prefix: "_acme-challenge",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- Active: true,
- TTL: 120,
- }
-
- result, err := client.CreateRecord(t.Context(), "example.com", record)
- require.NoError(t, err)
-
- expected := &Record{
- ID: "1234",
- Type: "TXT",
- Prefix: "_acme-challenge",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- Active: true,
- TTL: 120,
- }
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_CreateRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /dns/example.com",
- servermock.RawStringResponse(http.StatusText(http.StatusUnauthorized)).
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- record := Record{
- Type: "TXT",
- Prefix: "_acme-challenge",
- Content: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- Active: true,
- TTL: 120,
- }
-
- _, err := client.CreateRecord(t.Context(), "example.com", record)
- require.EqualError(t, err, "unexpected status code: [status code: 401] body: Unauthorized")
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /dns/example.com/1234",
- servermock.Noop()).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), "example.com", "1234")
- require.NoError(t, err)
-}
-
-func TestClient_DeleteRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /dns/example.com/1234",
- servermock.RawStringResponse(http.StatusText(http.StatusUnauthorized)).
- WithStatusCode(http.StatusUnauthorized)).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), "example.com", "1234")
- require.EqualError(t, err, "unexpected status code: [status code: 401] body: Unauthorized")
-}
diff --git a/providers/dns/syse/internal/fixtures/create_record-request.json b/providers/dns/syse/internal/fixtures/create_record-request.json
deleted file mode 100644
index 549a0f60f..000000000
--- a/providers/dns/syse/internal/fixtures/create_record-request.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "active": true,
- "ttl": 120,
- "prefix": "_acme-challenge",
- "type": "TXT"
-}
diff --git a/providers/dns/syse/internal/fixtures/create_record.json b/providers/dns/syse/internal/fixtures/create_record.json
deleted file mode 100644
index b598779c6..000000000
--- a/providers/dns/syse/internal/fixtures/create_record.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "id": "1234",
- "content": "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- "active": true,
- "ttl": 120,
- "prefix": "_acme-challenge",
- "type": "TXT"
-}
diff --git a/providers/dns/syse/internal/types.go b/providers/dns/syse/internal/types.go
deleted file mode 100644
index 4b90205e1..000000000
--- a/providers/dns/syse/internal/types.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package internal
-
-type Record struct {
- ID string `json:"id,omitempty"`
- Type string `json:"type,omitempty"`
- Prefix string `json:"prefix,omitempty"`
- Content string `json:"content,omitempty"`
- Priority int `json:"prio,omitempty"`
- TTL int `json:"ttl,omitempty"`
- Active bool `json:"active,omitempty"`
-}
diff --git a/providers/dns/syse/syse.go b/providers/dns/syse/syse.go
deleted file mode 100644
index 29633280c..000000000
--- a/providers/dns/syse/syse.go
+++ /dev/null
@@ -1,186 +0,0 @@
-// Package syse implements a DNS provider for solving the DNS-01 challenge using Syse.
-package syse
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/syse/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "SYSE_"
-
- EnvCredentials = envNamespace + "CREDENTIALS"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- Credentials map[string]string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 1200*time.Second),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 10*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- recordIDs map[string]string
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Syse.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvCredentials)
- if err != nil {
- return nil, fmt.Errorf("syse: %w", err)
- }
-
- config := NewDefaultConfig()
-
- credentials, err := env.ParsePairs(values[EnvCredentials])
- if err != nil {
- return nil, fmt.Errorf("syse: credentials: %w", err)
- }
-
- config.Credentials = credentials
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Syse.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("syse: the configuration of the DNS provider is nil")
- }
-
- if len(config.Credentials) == 0 {
- return nil, errors.New("syse: missing credentials")
- }
-
- for domain, password := range config.Credentials {
- if domain == "" {
- return nil, fmt.Errorf(`syse: missing domain: "%s:%s"`, domain, password)
- }
-
- if password == "" {
- return nil, fmt.Errorf(`syse: missing password: "%s:%s"`, domain, password)
- }
- }
-
- client, err := internal.NewClient(config.Credentials)
- if err != nil {
- return nil, fmt.Errorf("syse: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]string),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("syse: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("syse: %w", err)
- }
-
- record := internal.Record{
- Type: "TXT",
- Prefix: subDomain,
- Content: info.Value,
- TTL: d.config.TTL,
- Active: true,
- }
-
- newRecord, err := d.client.CreateRecord(context.Background(), dns01.UnFqdn(authZone), record)
- if err != nil {
- return fmt.Errorf("syse: create record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.recordIDs[token] = newRecord.ID
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("syse: could not find zone for domain %q: %w", domain, err)
- }
-
- // gets the record's unique ID from when we created it
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("syse: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- err = d.client.DeleteRecord(context.Background(), dns01.UnFqdn(authZone), recordID)
- if err != nil {
- return fmt.Errorf("syse: delete record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/syse/syse.toml b/providers/dns/syse/syse.toml
deleted file mode 100644
index b5b1fdf47..000000000
--- a/providers/dns/syse/syse.toml
+++ /dev/null
@@ -1,25 +0,0 @@
-Name = "Syse"
-Description = ''''''
-URL = "https://www.syse.no/"
-Code = "syse"
-Since = "v4.30.0"
-
-Example = '''
-SYSE_CREDENTIALS=example.com:password \
-lego --dns syse -d '*.example.com' -d example.com run
-
-SYSE_CREDENTIALS=example.org:password1,example.com:password2 \
-lego --dns syse -d '*.example.org' -d example.org -d '*.example.com' -d example.com
-'''
-
-[Configuration]
- [Configuration.Credentials]
- SYSE_CREDENTIALS = "Comma-separated list of `zone:password` credential pairs"
- [Configuration.Additional]
- SYSE_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 10)"
- SYSE_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 1200)"
- SYSE_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- SYSE_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://www.syse.no/api/dns"
diff --git a/providers/dns/syse/syse_test.go b/providers/dns/syse/syse_test.go
deleted file mode 100644
index a4472aa7c..000000000
--- a/providers/dns/syse/syse_test.go
+++ /dev/null
@@ -1,220 +0,0 @@
-package syse
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvCredentials).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvCredentials: "example.org:123",
- },
- },
- {
- desc: "success multiple domains",
- envVars: map[string]string{
- EnvCredentials: "example.org:123,example.com:456,example.net:789",
- },
- },
- {
- desc: "invalid credentials",
- envVars: map[string]string{
- EnvCredentials: ",",
- },
- expected: `syse: credentials: incorrect pair: `,
- },
- {
- desc: "missing password",
- envVars: map[string]string{
- EnvCredentials: "example.org:",
- },
- expected: `syse: missing password: "example.org:"`,
- },
- {
- desc: "missing domain",
- envVars: map[string]string{
- EnvCredentials: ":123",
- },
- expected: `syse: missing domain: ":123"`,
- },
- {
- desc: "invalid credentials, partial",
- envVars: map[string]string{
- EnvCredentials: "example.org:123,example.net",
- },
- expected: "syse: credentials: incorrect pair: example.net",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{
- EnvCredentials: "",
- },
- expected: "syse: some credentials information are missing: SYSE_CREDENTIALS",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- creds map[string]string
- expected string
- }{
- {
- desc: "success",
- creds: map[string]string{"example.org": "123"},
- },
- {
- desc: "success multiple domains",
- creds: map[string]string{
- "example.org": "123",
- "example.com": "456",
- "example.net": "789",
- },
- },
- {
- desc: "missing credentials",
- expected: "syse: missing credentials",
- },
- {
- desc: "missing domain",
- creds: map[string]string{"": "123"},
- expected: `syse: missing domain: ":123"`,
- },
- {
- desc: "missing password",
- creds: map[string]string{"example.org": ""},
- expected: `syse: missing password: "example.org:"`,
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Credentials = test.creds
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.Credentials = map[string]string{
- "example.org": "secret",
- }
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("/", servermock.DumpRequest()).
- Route("POST /dns/example.com",
- servermock.ResponseFromInternal("create_record.json"),
- servermock.CheckRequestJSONBodyFromInternal("create_record-request.json")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /dns/example.com/1234",
- servermock.Noop()).
- Build(t)
-
- provider.recordIDs["abc"] = "1234"
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/technitium/internal/client.go b/providers/dns/technitium/internal/client.go
index 965638b1d..a68008d34 100644
--- a/providers/dns/technitium/internal/client.go
+++ b/providers/dns/technitium/internal/client.go
@@ -125,7 +125,6 @@ func (c *Client) newFormRequest(ctx context.Context, endpoint *url.URL, payload
if payload != nil {
var err error
-
values, err = querystring.Values(payload)
if err != nil {
return nil, fmt.Errorf("failed to create request body: %w", err)
@@ -150,7 +149,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var errAPI APIResponse[any]
-
err := json.Unmarshal(raw, &errAPI)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/technitium/technitium.go b/providers/dns/technitium/technitium.go
index fc60c09ad..b2cf2d701 100644
--- a/providers/dns/technitium/technitium.go
+++ b/providers/dns/technitium/technitium.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/technitium/internal"
)
@@ -88,8 +87,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/technitium/technitium.toml b/providers/dns/technitium/technitium.toml
index ac1fc6466..13b40c304 100644
--- a/providers/dns/technitium/technitium.toml
+++ b/providers/dns/technitium/technitium.toml
@@ -7,7 +7,7 @@ Since = "v4.20.0"
Example = '''
TECHNITIUM_SERVER_BASE_URL="https://localhost:5380" \
TECHNITIUM_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns technitium -d '*.example.com' -d example.com run
+lego --email you@example.com --dns technitium -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/technitium/technitium_test.go b/providers/dns/technitium/technitium_test.go
index 4eee530fd..da50b6fe6 100644
--- a/providers/dns/technitium/technitium_test.go
+++ b/providers/dns/technitium/technitium_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -123,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/tencentcloud/tencentcloud.toml b/providers/dns/tencentcloud/tencentcloud.toml
index 50f4ee9d5..75a950a49 100644
--- a/providers/dns/tencentcloud/tencentcloud.toml
+++ b/providers/dns/tencentcloud/tencentcloud.toml
@@ -1,13 +1,13 @@
Name = "Tencent Cloud DNS"
Description = ''''''
-URL = "https://cloud.tencent.com/product/dns"
+URL = "https://cloud.tencent.com/product/cns"
Code = "tencentcloud"
Since = "v4.6.0"
Example = '''
TENCENTCLOUD_SECRET_ID=abcdefghijklmnopqrstuvwx \
TENCENTCLOUD_SECRET_KEY=your-secret-key \
-lego --dns tencentcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns tencentcloud -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/tencentcloud/tencentcloud_test.go b/providers/dns/tencentcloud/tencentcloud_test.go
index ce6358174..c5a2fd974 100644
--- a/providers/dns/tencentcloud/tencentcloud_test.go
+++ b/providers/dns/tencentcloud/tencentcloud_test.go
@@ -55,7 +55,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -128,7 +127,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -142,7 +140,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/tencentcloud/wrapper.go b/providers/dns/tencentcloud/wrapper.go
index 6a66bc1c6..6fdb7f899 100644
--- a/providers/dns/tencentcloud/wrapper.go
+++ b/providers/dns/tencentcloud/wrapper.go
@@ -38,7 +38,6 @@ func (d *DNSProvider) getHostedZone(ctx context.Context, domain string) (*dnspod
}
var hostedZone *dnspod.DomainListItem
-
for _, zone := range domains {
unfqdn := dns01.UnFqdn(authZone)
if *zone.Name == unfqdn || *zone.Punycode == unfqdn {
@@ -74,7 +73,6 @@ func (d *DNSProvider) findTxtRecords(ctx context.Context, zone *dnspod.DomainLis
return nil, nil
}
}
-
return nil, err
}
diff --git a/providers/dns/timewebcloud/internal/client.go b/providers/dns/timewebcloud/internal/client.go
index ec3c8703d..b3030861e 100644
--- a/providers/dns/timewebcloud/internal/client.go
+++ b/providers/dns/timewebcloud/internal/client.go
@@ -49,7 +49,6 @@ func (c *Client) CreateRecord(ctx context.Context, zone string, record DNSRecord
}
respData := &CreateRecordResponse{}
-
err = c.do(req, respData)
if err != nil {
return nil, err
@@ -128,7 +127,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var response ErrorResponse
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/timewebcloud/internal/types.go b/providers/dns/timewebcloud/internal/types.go
index 80cdb2c70..81da4df5c 100644
--- a/providers/dns/timewebcloud/internal/types.go
+++ b/providers/dns/timewebcloud/internal/types.go
@@ -3,11 +3,9 @@ package internal
import "fmt"
type DNSRecord struct {
- ID int `json:"id,omitempty"`
- Type string `json:"type,omitempty"`
- Value string `json:"value,omitempty"`
-
- // SubDomain is the full name of a subdomain (not only the subdomain label).
+ ID int `json:"id,omitempty"`
+ Type string `json:"type,omitempty"`
+ Value string `json:"value,omitempty"`
SubDomain string `json:"subdomain,omitempty"`
}
diff --git a/providers/dns/timewebcloud/timewebcloud.go b/providers/dns/timewebcloud/timewebcloud.go
index a599566e3..a2ab0dd65 100644
--- a/providers/dns/timewebcloud/timewebcloud.go
+++ b/providers/dns/timewebcloud/timewebcloud.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/timewebcloud/internal"
)
@@ -82,11 +81,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("timewebcloud: authentication token is missing")
}
- client := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.AuthToken),
- ),
- )
+ client := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.AuthToken))
return &DNSProvider{
config: config,
@@ -110,10 +105,15 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("timewebcloud: could not find zone for domain %q: %w", domain, err)
}
+ subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
+ if err != nil {
+ return fmt.Errorf("timewebcloud: %w", err)
+ }
+
record := internal.DNSRecord{
Type: "TXT",
Value: info.Value,
- SubDomain: dns01.UnFqdn(info.EffectiveFQDN),
+ SubDomain: subDomain,
}
response, err := d.client.CreateRecord(context.Background(), authZone, record)
@@ -140,7 +140,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("timewebcloud: unknown record ID for '%s'", info.EffectiveFQDN)
}
diff --git a/providers/dns/timewebcloud/timewebcloud.toml b/providers/dns/timewebcloud/timewebcloud.toml
index c8bde636a..8c20b37b9 100644
--- a/providers/dns/timewebcloud/timewebcloud.toml
+++ b/providers/dns/timewebcloud/timewebcloud.toml
@@ -6,7 +6,7 @@ Since = "v4.20.0"
Example = '''
TIMEWEBCLOUD_AUTH_TOKEN=xxxxxx \
-lego --dns timewebcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns timewebcloud -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/timewebcloud/timewebcloud_test.go b/providers/dns/timewebcloud/timewebcloud_test.go
index 26e107578..cd3e2e26f 100644
--- a/providers/dns/timewebcloud/timewebcloud_test.go
+++ b/providers/dns/timewebcloud/timewebcloud_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -98,7 +97,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -112,7 +110,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/todaynic/internal/client.go b/providers/dns/todaynic/internal/client.go
deleted file mode 100644
index 2c537f4a7..000000000
--- a/providers/dns/todaynic/internal/client.go
+++ /dev/null
@@ -1,141 +0,0 @@
-package internal
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strconv"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
- querystring "github.com/google/go-querystring/query"
-)
-
-const defaultBaseURL = "https://todapi.now.cn:2443"
-
-// Client the TodayNIC API client.
-type Client struct {
- authUserID string
- apiKey string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(authUserID, apiKey string) (*Client, error) {
- if authUserID == "" || apiKey == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- authUserID: authUserID,
- apiKey: apiKey,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) AddRecord(ctx context.Context, record Record) (int, error) {
- endpoint := c.BaseURL.JoinPath("api", "dns", "add-domain-record.json")
-
- query, err := querystring.Values(record)
- if err != nil {
- return 0, err
- }
-
- req, err := c.newRequest(ctx, endpoint, query)
- if err != nil {
- return 0, err
- }
-
- var result APIResponse
-
- err = c.do(req, &result)
- if err != nil {
- return 0, err
- }
-
- return result.ID, nil
-}
-
-func (c *Client) DeleteRecord(ctx context.Context, recordID int) error {
- endpoint := c.BaseURL.JoinPath("api", "dns", "delete-domain-record.json")
-
- query := endpoint.Query()
- query.Set("Id", strconv.Itoa(recordID))
-
- req, err := c.newRequest(ctx, endpoint, query)
- if err != nil {
- return err
- }
-
- return c.do(req, nil)
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func (c *Client) newRequest(ctx context.Context, endpoint *url.URL, query url.Values) (*http.Request, error) {
- query.Set("auth-userid", c.authUserID)
- query.Set("api-key", c.apiKey)
-
- endpoint.RawQuery = query.Encode()
-
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- 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
-}
diff --git a/providers/dns/todaynic/internal/client_test.go b/providers/dns/todaynic/internal/client_test.go
deleted file mode 100644
index 71ee7f8b7..000000000
--- a/providers/dns/todaynic/internal/client_test.go
+++ /dev/null
@@ -1,94 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("user123", "secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestClient_AddRecord(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/dns/add-domain-record.json",
- servermock.ResponseFromFixture("add_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("Domain", "example.com").
- With("Host", "_acme-challenge").
- With("Type", "TXT").
- With("Value", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY").
- With("Ttl", "600").
- With("auth-userid", "user123").
- With("api-key", "secret"),
- ).
- Build(t)
-
- record := Record{
- Domain: "example.com",
- Host: "_acme-challenge",
- Type: "TXT",
- Value: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: "600",
- }
-
- recordID, err := client.AddRecord(t.Context(), record)
- require.NoError(t, err)
-
- assert.Equal(t, 11554102, recordID)
-}
-
-func TestClient_AddRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/dns/add-domain-record.json",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusNotFound),
- ).
- Build(t)
-
- record := Record{
- Domain: "example.com",
- Host: "_acme-challenge",
- Type: "TXT",
- Value: "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY",
- TTL: "600",
- }
-
- _, err := client.AddRecord(t.Context(), record)
- require.EqualError(t, err, "host.repeat (2d5876b2-f272-43e9-acc1-4c6a3d3683b1)")
-}
-
-func TestClient_DeleteRecord(t *testing.T) {
- client := mockBuilder().
- Route("GET /api/dns/delete-domain-record.json",
- servermock.ResponseFromFixture("add_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("Id", "123").
- With("auth-userid", "user123").
- With("api-key", "secret"),
- ).
- Build(t)
-
- err := client.DeleteRecord(t.Context(), 123)
- require.NoError(t, err)
-}
diff --git a/providers/dns/todaynic/internal/fixtures/add_record.json b/providers/dns/todaynic/internal/fixtures/add_record.json
deleted file mode 100644
index 27f34d71c..000000000
--- a/providers/dns/todaynic/internal/fixtures/add_record.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "RequestId": "f60ea4d9-67ef-49fa-bbae-06178a6e7293",
- "Id": 11554102
-}
diff --git a/providers/dns/todaynic/internal/fixtures/error.json b/providers/dns/todaynic/internal/fixtures/error.json
deleted file mode 100644
index 3ea9c9310..000000000
--- a/providers/dns/todaynic/internal/fixtures/error.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "RequestId": "2d5876b2-f272-43e9-acc1-4c6a3d3683b1",
- "error": "host.repeat"
-}
diff --git a/providers/dns/todaynic/internal/types.go b/providers/dns/todaynic/internal/types.go
deleted file mode 100644
index 0a15c7da8..000000000
--- a/providers/dns/todaynic/internal/types.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package internal
-
-import "fmt"
-
-type APIError struct {
- RequestID string `json:"RequestId"`
- Message string `json:"error"`
-}
-
-func (a *APIError) Error() string {
- return fmt.Sprintf("%s (%s)", a.Message, a.RequestID)
-}
-
-type Record struct {
- Domain string `url:"Domain,omitempty"`
- Host string `url:"Host,omitempty"`
- Type string `url:"Type,omitempty"`
- Value string `url:"Value,omitempty"`
- Mx string `url:"Mx,omitempty"`
- TTL string `url:"Ttl,omitempty"`
-}
-
-type APIResponse struct {
- RequestID string `json:"RequestId"`
- ID int `json:"Id"`
-}
diff --git a/providers/dns/todaynic/todaynic.go b/providers/dns/todaynic/todaynic.go
deleted file mode 100644
index 3a3734033..000000000
--- a/providers/dns/todaynic/todaynic.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Package todaynic implements a DNS provider for solving the DNS-01 challenge using TodayNIC.
-package todaynic
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "strconv"
- "sync"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/todaynic/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "TODAYNIC_"
-
- EnvAuthUserID = envNamespace + "AUTH_USER_ID"
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- AuthUserID string
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, 600),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-
- recordIDs map[string]int
- recordIDsMu sync.Mutex
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for TodayNIC.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAuthUserID, EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("todaynic: %w", err)
- }
-
- config := NewDefaultConfig()
- config.AuthUserID = values[EnvAuthUserID]
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for TodayNIC.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("todaynic: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.AuthUserID, config.APIKey)
- if err != nil {
- return nil, fmt.Errorf("todaynic: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- recordIDs: make(map[string]int),
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("todaynic: could not find zone for domain %q: %w", domain, err)
- }
-
- subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
- if err != nil {
- return fmt.Errorf("todaynic: %w", err)
- }
-
- record := internal.Record{
- Domain: dns01.UnFqdn(authZone),
- Host: subDomain,
- Type: "TXT",
- Value: info.Value,
- TTL: strconv.Itoa(d.config.TTL),
- }
-
- recordID, err := d.client.AddRecord(context.Background(), record)
- if err != nil {
- return fmt.Errorf("todaynic: add record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- d.recordIDs[token] = recordID
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- d.recordIDsMu.Lock()
- recordID, ok := d.recordIDs[token]
- d.recordIDsMu.Unlock()
-
- if !ok {
- return fmt.Errorf("todaynic: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
- }
-
- err := d.client.DeleteRecord(context.Background(), recordID)
- if err != nil {
- return fmt.Errorf("todaynic: delete record: %w", err)
- }
-
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/todaynic/todaynic.toml b/providers/dns/todaynic/todaynic.toml
deleted file mode 100644
index 16d55ccc0..000000000
--- a/providers/dns/todaynic/todaynic.toml
+++ /dev/null
@@ -1,25 +0,0 @@
-Name = "TodayNIC/时代互联"
-Description = ''''''
-URL = "https://www.todaynic.com/"
-Code = "todaynic"
-Since = "v4.32.0"
-
-Example = '''
-TODAYNIC_AUTH_USER_ID="xxx" \
-TODAYNIC_API_KEY="yyy" \
-lego --dns todaynic -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- TODAYNIC_AUTH_USER_ID = "account ID"
- TODAYNIC_API_KEY = "API key"
- [Configuration.Additional]
- TODAYNIC_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- TODAYNIC_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- TODAYNIC_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)"
- TODAYNIC_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://www.todaynic.com/partner/mode_Http_Api_detail.php"
- apipost = "https://docs.apipost.net/docs/detail/49dcef10a876000?target_id=0"
diff --git a/providers/dns/todaynic/todaynic_test.go b/providers/dns/todaynic/todaynic_test.go
deleted file mode 100644
index c73bf6cc5..000000000
--- a/providers/dns/todaynic/todaynic_test.go
+++ /dev/null
@@ -1,207 +0,0 @@
-package todaynic
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAuthUserID, EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAuthUserID: "user123",
- EnvAPIKey: "secret",
- },
- },
- {
- desc: "missing user ID",
- envVars: map[string]string{
- EnvAuthUserID: "",
- EnvAPIKey: "secret",
- },
- expected: "todaynic: some credentials information are missing: TODAYNIC_AUTH_USER_ID",
- },
- {
- desc: "missing API key",
- envVars: map[string]string{
- EnvAuthUserID: "user123",
- EnvAPIKey: "",
- },
- expected: "todaynic: some credentials information are missing: TODAYNIC_API_KEY",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "todaynic: some credentials information are missing: TODAYNIC_AUTH_USER_ID,TODAYNIC_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- authUserID string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- authUserID: "user123",
- apiKey: "secret",
- },
- {
- desc: "missing user ID",
- apiKey: "secret",
- expected: "todaynic: credentials missing",
- },
- {
- desc: "missing API key",
- authUserID: "user123",
- expected: "todaynic: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "todaynic: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.AuthUserID = test.authUserID
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.AuthUserID = "user123"
- config.APIKey = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders(),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("GET /api/dns/add-domain-record.json",
- servermock.ResponseFromInternal("add_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("Domain", "example.com").
- With("Host", "_acme-challenge").
- With("Type", "TXT").
- With("Value", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY").
- With("Ttl", "600").
- With("auth-userid", "user123").
- With("api-key", "secret"),
- ).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("GET /api/dns/delete-domain-record.json",
- servermock.ResponseFromInternal("add_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("Id", "123").
- With("auth-userid", "user123").
- With("api-key", "secret"),
- ).
- Build(t)
-
- provider.recordIDs["abc"] = 123
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/transip/transip.go b/providers/dns/transip/transip.go
index bc2913aa4..779704a21 100644
--- a/providers/dns/transip/transip.go
+++ b/providers/dns/transip/transip.go
@@ -4,7 +4,6 @@ package transip
import (
"errors"
"fmt"
- "net/http"
"time"
"github.com/go-acme/lego/v4/challenge"
@@ -24,7 +23,6 @@ const (
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
@@ -36,7 +34,6 @@ type Config struct {
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int64
- HTTPClient *http.Client
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
@@ -45,9 +42,6 @@ func NewDefaultConfig() *Config {
TTL: int64(env.GetOrDefaultInt(EnvTTL, 10)),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 10*time.Minute),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 10*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
}
}
@@ -79,19 +73,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("transip: the configuration of the DNS provider is nil")
}
- cfg := gotransip.ClientConfiguration{
+ client, err := gotransip.NewClient(gotransip.ClientConfiguration{
AccountName: config.AccountName,
PrivateKeyPath: config.PrivateKeyPath,
- }
-
- if config.HTTPClient != nil {
- cfg.HTTPClient = config.HTTPClient
- } else {
- // Uses an explicit default HTTP client because the desec.NewDefaultClientOptions uses the http.DefaultClient.
- cfg.HTTPClient = &http.Client{Timeout: 30 * time.Second}
- }
-
- client, err := gotransip.NewClient(cfg)
+ })
if err != nil {
return nil, fmt.Errorf("transip: %w", err)
}
@@ -168,7 +153,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err = d.repository.RemoveDNSEntry(domainName, entry); err != nil {
return fmt.Errorf("transip: couldn't get Record ID in CleanUp: %w", err)
}
-
return nil
}
}
diff --git a/providers/dns/transip/transip.toml b/providers/dns/transip/transip.toml
index bf7d58ee3..0625f819b 100644
--- a/providers/dns/transip/transip.toml
+++ b/providers/dns/transip/transip.toml
@@ -7,7 +7,7 @@ Since = "v2.0.0"
Example = '''
TRANSIP_ACCOUNT_NAME = "Account name" \
TRANSIP_PRIVATE_KEY_PATH = "transip.key" \
-lego --dns transip -d '*.example.com' -d example.com run
+lego --email you@example.com --dns transip -d '*.example.com' -d example.com run
'''
[Configuration]
@@ -18,7 +18,6 @@ lego --dns transip -d '*.example.com' -d example.com run
TRANSIP_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 10)"
TRANSIP_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 600)"
TRANSIP_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 10)"
- TRANSIP_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
[Links]
API = "https://api.transip.eu/rest/docs.html"
diff --git a/providers/dns/transip/transip_test.go b/providers/dns/transip/transip_test.go
index 3c6e86657..b42753680 100644
--- a/providers/dns/transip/transip_test.go
+++ b/providers/dns/transip/transip_test.go
@@ -58,7 +58,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -80,7 +79,6 @@ func TestNewDNSProvider(t *testing.T) {
// Therefore, we test if the error type is the same.
t.Run("could not open private key path", func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(map[string]string{
@@ -158,7 +156,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -172,7 +169,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/ultradns/ultradns.go b/providers/dns/ultradns/ultradns.go
index da76c56f4..0515cbaae 100644
--- a/providers/dns/ultradns/ultradns.go
+++ b/providers/dns/ultradns/ultradns.go
@@ -4,7 +4,6 @@ package ultradns
import (
"errors"
"fmt"
- "net/http"
"time"
"github.com/go-acme/lego/v4/challenge"
@@ -122,7 +121,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
RecordType: "TXT",
}
- resp, _, _ := recordService.Read(rrSetKeyData)
+ res, _, _ := recordService.Read(rrSetKeyData)
rrSetData := &rrset.RRSet{
OwnerName: info.EffectiveFQDN,
@@ -131,12 +130,11 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
RData: []string{info.Value},
}
- if resp != nil && resp.StatusCode == http.StatusOK {
+ if res != nil && res.StatusCode == 200 {
_, err = recordService.Update(rrSetKeyData, rrSetData)
} else {
_, err = recordService.Create(rrSetKeyData, rrSetData)
}
-
if err != nil {
return fmt.Errorf("ultradns: %w", err)
}
diff --git a/providers/dns/ultradns/ultradns.toml b/providers/dns/ultradns/ultradns.toml
index 4c3dbbe72..a403a3dcf 100644
--- a/providers/dns/ultradns/ultradns.toml
+++ b/providers/dns/ultradns/ultradns.toml
@@ -7,7 +7,7 @@ Since = "v4.10.0"
Example = '''
ULTRADNS_USERNAME=username \
ULTRADNS_PASSWORD=password \
-lego --dns ultradns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns ultradns -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/ultradns/ultradns_test.go b/providers/dns/ultradns/ultradns_test.go
index 464bc51cd..eefa63ec3 100644
--- a/providers/dns/ultradns/ultradns_test.go
+++ b/providers/dns/ultradns/ultradns_test.go
@@ -177,7 +177,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/uniteddomains/uniteddomains.go b/providers/dns/uniteddomains/uniteddomains.go
deleted file mode 100644
index 683cab1fe..000000000
--- a/providers/dns/uniteddomains/uniteddomains.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Package uniteddomains implements a DNS provider for solving the DNS-01 challenge using United-Domains.
-package uniteddomains
-
-import (
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/ionos"
-)
-
-// Environment variables names.
-const (
- envNamespace = "UNITEDDOMAINS_"
-
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-const defaultBaseURL = "https://dnsapi.united-domains.de/dns"
-
-const minTTL = 300
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config = ionos.Config
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 15*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- prv challenge.ProviderTimeout
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for United-Domains.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("uniteddomains: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for United-Domains.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("uniteddomains: the configuration of the DNS provider is nil")
- }
-
- provider, err := ionos.NewDNSProviderConfig(config, defaultBaseURL)
- if err != nil {
- return nil, fmt.Errorf("uniteddomains: %w", err)
- }
-
- return &DNSProvider{prv: provider}, nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("uniteddomains: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("uniteddomains: %w", err)
- }
-
- return nil
-}
diff --git a/providers/dns/uniteddomains/uniteddomains.toml b/providers/dns/uniteddomains/uniteddomains.toml
deleted file mode 100644
index fe8b9e574..000000000
--- a/providers/dns/uniteddomains/uniteddomains.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "United-Domains"
-Description = ''''''
-URL = "https://www.united-domains.de/"
-Code = "uniteddomains"
-Since = "v4.29.0"
-
-Example = '''
-UNITEDDOMAINS_API_KEY=xxxxxxxx \
-lego --dns uniteddomains -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- UNITEDDOMAINS_API_KEY = "API key `.` https://www.united-domains.de/help/faq-article/getting-started-with-the-united-domains-dns-api/"
- [Configuration.Additional]
- UNITEDDOMAINS_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- UNITEDDOMAINS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 900)"
- UNITEDDOMAINS_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)"
- UNITEDDOMAINS_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://www.united-domains.de/dns-apidoc/"
diff --git a/providers/dns/uniteddomains/uniteddomains_test.go b/providers/dns/uniteddomains/uniteddomains_test.go
deleted file mode 100644
index 93afb01ab..000000000
--- a/providers/dns/uniteddomains/uniteddomains_test.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package uniteddomains
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIKey: "123",
- },
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{
- EnvAPIKey: "",
- },
- expected: "uniteddomains: some credentials information are missing: UNITEDDOMAINS_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.prv)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiKey string
- tll int
- expected string
- }{
- {
- desc: "success",
- apiKey: "123",
- tll: minTTL,
- },
- {
- desc: "missing credentials",
- tll: minTTL,
- expected: "uniteddomains: credentials missing",
- },
- {
- desc: "invalid TTL",
- apiKey: "123",
- tll: 30,
- expected: "uniteddomains: invalid TTL, TTL (30) must be greater than 300",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIKey = test.apiKey
- config.TTL = test.tll
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.prv)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/variomedia/internal/client.go b/providers/dns/variomedia/internal/client.go
index 0e4ef9518..8c2a124cc 100644
--- a/providers/dns/variomedia/internal/client.go
+++ b/providers/dns/variomedia/internal/client.go
@@ -52,7 +52,6 @@ func (c *Client) CreateDNSRecord(ctx context.Context, record DNSRecord) (*Create
}
var result CreateDNSRecordResponse
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -72,7 +71,6 @@ func (c *Client) DeleteDNSRecord(ctx context.Context, id string) (*DeleteRecordR
}
var result DeleteRecordResponse
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -92,7 +90,6 @@ func (c *Client) GetJob(ctx context.Context, id string) (*GetJobResponse, error)
}
var result GetJobResponse
-
err = c.do(req, &result)
if err != nil {
return nil, err
@@ -156,7 +153,6 @@ 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)
diff --git a/providers/dns/variomedia/variomedia.go b/providers/dns/variomedia/variomedia.go
index 2d12fd975..548d8bab8 100644
--- a/providers/dns/variomedia/variomedia.go
+++ b/providers/dns/variomedia/variomedia.go
@@ -10,13 +10,11 @@ import (
"sync"
"time"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/log"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/platform/wait"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/variomedia/internal"
)
@@ -93,8 +91,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
@@ -165,7 +161,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("variomedia: unknown record ID for '%s'", info.EffectiveFQDN)
}
@@ -180,30 +175,18 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("variomedia: %w", err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
func (d *DNSProvider) waitJob(ctx context.Context, domain, id string) error {
- return wait.Retry(ctx,
- func() error {
- result, err := d.client.GetJob(ctx, id)
- if err != nil {
- return fmt.Errorf("apply change on %s: %w", domain, err)
- }
+ return wait.For("variomedia: apply change on "+domain, d.config.PropagationTimeout, d.config.PollingInterval, func() (bool, error) {
+ result, err := d.client.GetJob(ctx, id)
+ if err != nil {
+ return false, err
+ }
- log.Infof("variomedia: [%s] %s: %s %s", domain, result.Data.ID, result.Data.Attributes.JobType, result.Data.Attributes.Status)
+ log.Infof("variomedia: [%s] %s: %s %s", domain, result.Data.ID, result.Data.Attributes.JobType, result.Data.Attributes.Status)
- if result.Data.Attributes.Status != "done" {
- return fmt.Errorf("apply change on %s: status: %s", domain, result.Data.Attributes.Status)
- }
-
- return nil
- },
- backoff.WithBackOff(backoff.NewConstantBackOff(d.config.PollingInterval)),
- backoff.WithMaxElapsedTime(d.config.PropagationTimeout),
- )
+ return result.Data.Attributes.Status == "done", nil
+ })
}
diff --git a/providers/dns/variomedia/variomedia.toml b/providers/dns/variomedia/variomedia.toml
index 8390d1922..fe6f2797a 100644
--- a/providers/dns/variomedia/variomedia.toml
+++ b/providers/dns/variomedia/variomedia.toml
@@ -6,7 +6,7 @@ Since = "v4.8.0"
Example = '''
VARIOMEDIA_API_TOKEN=xxxx \
-lego --dns variomedia -d '*.example.com' -d example.com run
+lego --email you@example.com --dns variomedia -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/variomedia/variomedia_test.go b/providers/dns/variomedia/variomedia_test.go
index 552419fd0..305646070 100644
--- a/providers/dns/variomedia/variomedia_test.go
+++ b/providers/dns/variomedia/variomedia_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -92,7 +91,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -106,7 +104,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/vegadns/vegadns.go b/providers/dns/vegadns/vegadns.go
index 9f1f189c3..824f727eb 100644
--- a/providers/dns/vegadns/vegadns.go
+++ b/providers/dns/vegadns/vegadns.go
@@ -2,17 +2,14 @@
package vegadns
import (
- "context"
"errors"
"fmt"
- "net/http"
"time"
+ vegaClient "github.com/OpenDNS/vegadns2client"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/nrdcg/vegadns"
)
// Environment variables names.
@@ -26,21 +23,18 @@ const (
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
- BaseURL string
- APIKey string
- APISecret string
-
+ BaseURL string
+ APIKey string
+ APISecret string
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
- HTTPClient *http.Client
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
@@ -49,16 +43,13 @@ func NewDefaultConfig() *Config {
TTL: env.GetOrDefaultInt(EnvTTL, 10),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 12*time.Minute),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, time.Minute),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
}
}
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
config *Config
- client *vegadns.Client
+ client vegaClient.VegaDNSClient
}
// NewDNSProvider returns a DNSProvider instance configured for VegaDNS.
@@ -84,21 +75,11 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("vegadns: the configuration of the DNS provider is nil")
}
- if config.HTTPClient == nil {
- config.HTTPClient = &http.Client{Timeout: 30 * time.Second}
- }
+ vega := vegaClient.NewVegaDNSClient(config.BaseURL)
+ vega.APIKey = config.APIKey
+ vega.APISecret = config.APISecret
- config.HTTPClient = clientdebug.Wrap(config.HTTPClient)
-
- client, err := vegadns.NewClient(config.BaseURL,
- vegadns.WithOAuth(config.APIKey, config.APISecret),
- vegadns.WithHTTPClient(config.HTTPClient),
- )
- if err != nil {
- return nil, fmt.Errorf("vegadns: %w", err)
- }
-
- return &DNSProvider{client: client, config: config}, nil
+ return &DNSProvider{client: vega, config: config}, nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
@@ -109,71 +90,39 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- domainID, err := d.findDomainID(ctx, info.EffectiveFQDN)
+ _, domainID, err := d.client.GetAuthZone(info.EffectiveFQDN)
if err != nil {
- return fmt.Errorf("vegadns: find domain ID for %s: %w", info.EffectiveFQDN, err)
+ return fmt.Errorf("vegadns: can't find Authoritative Zone for %s in Present: %w", info.EffectiveFQDN, err)
}
- err = d.client.CreateTXTRecord(ctx, domainID, dns01.UnFqdn(info.EffectiveFQDN), info.Value, d.config.TTL)
+ err = d.client.CreateTXT(domainID, info.EffectiveFQDN, info.Value, d.config.TTL)
if err != nil {
- return fmt.Errorf("vegadns: create TXT record: %w", err)
+ return fmt.Errorf("vegadns: %w", err)
}
-
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
- domainID, err := d.findDomainID(ctx, info.EffectiveFQDN)
+ _, domainID, err := d.client.GetAuthZone(info.EffectiveFQDN)
if err != nil {
- return fmt.Errorf("vegadns: find domain ID for %s: %w", info.EffectiveFQDN, err)
+ return fmt.Errorf("vegadns: can't find Authoritative Zone for %s in CleanUp: %w", info.EffectiveFQDN, err)
}
- recordID, err := d.findRecordID(ctx, domainID, dns01.UnFqdn(info.EffectiveFQDN))
+ txt := dns01.UnFqdn(info.EffectiveFQDN)
+
+ recordID, err := d.client.GetRecordID(domainID, txt, "TXT")
if err != nil {
- return fmt.Errorf("vegadns: find record ID for %d: %w", domainID, err)
+ return fmt.Errorf("vegadns: couldn't get Record ID in CleanUp: %w", err)
}
- err = d.client.DeleteRecord(ctx, recordID)
+ err = d.client.DeleteRecord(recordID)
if err != nil {
- return fmt.Errorf("vegadns: delete record: %w", err)
+ return fmt.Errorf("vegadns: %w", err)
}
-
return nil
}
-
-func (d *DNSProvider) findDomainID(ctx context.Context, fqdn string) (int, error) {
- for host := range dns01.UnFqdnDomainsSeq(fqdn) {
- id, err := d.client.GetDomainID(ctx, host)
- if err != nil {
- continue
- }
-
- return id, nil
- }
-
- return 0, errors.New("domain not found")
-}
-
-func (d *DNSProvider) findRecordID(ctx context.Context, domainID int, name string) (int, error) {
- records, err := d.client.GetRecords(ctx, domainID)
- if err != nil {
- return 0, fmt.Errorf("get records: %w", err)
- }
-
- for _, r := range records {
- if r.Name == name && r.RecordType == "TXT" {
- return r.RecordID, nil
- }
- }
-
- return 0, errors.New("record not found")
-}
diff --git a/providers/dns/vegadns/vegadns_test.go b/providers/dns/vegadns/vegadns_test.go
index edcd2c60d..48f54faab 100644
--- a/providers/dns/vegadns/vegadns_test.go
+++ b/providers/dns/vegadns/vegadns_test.go
@@ -19,7 +19,6 @@ var envTest = tester.NewEnvTest(EnvKey, EnvSecret, EnvURL)
func TestNewDNSProvider_Fail(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
_, err := NewDNSProvider()
@@ -28,7 +27,6 @@ func TestNewDNSProvider_Fail(t *testing.T) {
func TestDNSProvider_TimeoutSuccess(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
provider := mockBuilder().Build(t)
@@ -46,7 +44,7 @@ func TestDNSProvider_Present(t *testing.T) {
expectedError string
}{
{
- desc: "success",
+ desc: "Success",
builder: mockBuilder().
Route("POST /1.0/token",
servermock.ResponseFromFixture("token.json")).
@@ -56,17 +54,17 @@ func TestDNSProvider_Present(t *testing.T) {
WithStatusCode(http.StatusCreated)),
},
{
- desc: "fail to find the zone",
+ desc: "FailToFindZone",
builder: mockBuilder().
Route("POST /1.0/token",
servermock.ResponseFromFixture("token.json")).
Route("GET /1.0/domains",
servermock.Noop().
WithStatusCode(http.StatusNotFound)),
- expectedError: "vegadns: find domain ID for _acme-challenge.example.com.: domain not found",
+ expectedError: "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in Present: Unable to find auth zone for fqdn _acme-challenge.example.com",
},
{
- desc: "fail to create TXT record",
+ desc: "FailToCreateTXT",
builder: mockBuilder().
Route("POST /1.0/token",
servermock.ResponseFromFixture("token.json")).
@@ -74,14 +72,13 @@ func TestDNSProvider_Present(t *testing.T) {
Route("POST /1.0/records",
servermock.Noop().
WithStatusCode(http.StatusBadRequest)),
- expectedError: "vegadns: create TXT record: bad answer from VegaDNS (code: 400, message: )",
+ expectedError: "vegadns: Got bad answer from VegaDNS on CreateTXT. Code: 400. Message: ",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
provider := test.builder.Build(t)
@@ -103,7 +100,7 @@ func TestDNSProvider_CleanUp(t *testing.T) {
expectedError string
}{
{
- desc: "success",
+ desc: "Success",
builder: mockBuilder().
Route("POST /1.0/token",
servermock.ResponseFromFixture("token.json")).
@@ -115,17 +112,17 @@ func TestDNSProvider_CleanUp(t *testing.T) {
servermock.ResponseFromFixture("record_delete.json")),
},
{
- desc: "fail to find the zone",
+ desc: "FailToFindZone",
builder: mockBuilder().
Route("POST /1.0/token",
servermock.ResponseFromFixture("token.json")).
Route("GET /1.0/domains",
servermock.Noop().
WithStatusCode(http.StatusNotFound)),
- expectedError: "vegadns: find domain ID for _acme-challenge.example.com.: domain not found",
+ expectedError: "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in CleanUp: Unable to find auth zone for fqdn _acme-challenge.example.com",
},
{
- desc: "fail to get record ID",
+ desc: "FailToGetRecordID",
builder: mockBuilder().
Route("POST /1.0/token",
servermock.ResponseFromFixture("token.json")).
@@ -134,14 +131,13 @@ func TestDNSProvider_CleanUp(t *testing.T) {
servermock.Noop().
WithStatusCode(http.StatusNotFound),
servermock.CheckQueryParameter().With("domain_id", "1")),
- expectedError: "vegadns: find record ID for 1: get records: bad answer from VegaDNS (code: 404, message: )",
+ expectedError: "vegadns: couldn't get Record ID in CleanUp: Got bad answer from VegaDNS on GetRecordID. Code: 404. Message: ",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
provider := test.builder.Build(t)
@@ -171,7 +167,6 @@ func getDomainHandler() http.HandlerFunc {
]
}
`)
-
return
}
diff --git a/providers/dns/vercel/internal/client.go b/providers/dns/vercel/internal/client.go
index 930f3543e..d852689ae 100644
--- a/providers/dns/vercel/internal/client.go
+++ b/providers/dns/vercel/internal/client.go
@@ -51,7 +51,6 @@ func (c *Client) CreateRecord(ctx context.Context, zone string, record Record) (
}
respData := &CreateRecordResponse{}
-
err = c.do(req, respData)
if err != nil {
return nil, err
@@ -136,7 +135,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var response APIErrorResponse
-
err := json.Unmarshal(raw, &response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/vercel/vercel.go b/providers/dns/vercel/vercel.go
index 965e3de12..9ba92e21f 100644
--- a/providers/dns/vercel/vercel.go
+++ b/providers/dns/vercel/vercel.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/vercel/internal"
)
@@ -87,12 +86,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("vercel: credentials missing")
}
- client := internal.NewClient(
- clientdebug.Wrap(
- internal.OAuthStaticAccessToken(config.HTTPClient, config.AuthToken),
- ),
- config.TeamID,
- )
+ client := internal.NewClient(internal.OAuthStaticAccessToken(config.HTTPClient, config.AuthToken), config.TeamID)
return &DNSProvider{
config: config,
@@ -148,7 +142,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("vercel: unknown record ID for '%s'", info.EffectiveFQDN)
}
diff --git a/providers/dns/vercel/vercel.toml b/providers/dns/vercel/vercel.toml
index 4700d6d78..2545b9c48 100644
--- a/providers/dns/vercel/vercel.toml
+++ b/providers/dns/vercel/vercel.toml
@@ -6,7 +6,7 @@ Since = "v4.7.0"
Example = '''
VERCEL_API_TOKEN=xxxxxx \
-lego --dns vercel -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vercel -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/vercel/vercel_test.go b/providers/dns/vercel/vercel_test.go
index d4cf37904..6c19a4db5 100644
--- a/providers/dns/vercel/vercel_test.go
+++ b/providers/dns/vercel/vercel_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -96,7 +95,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -110,7 +108,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/versio/internal/client.go b/providers/dns/versio/internal/client.go
index 6a92cc958..e91913556 100644
--- a/providers/dns/versio/internal/client.go
+++ b/providers/dns/versio/internal/client.go
@@ -48,7 +48,6 @@ func (c *Client) UpdateDomain(ctx context.Context, domain string, msg *DomainInf
}
respData := &DomainInfoResponse{}
-
err = c.do(req, respData)
if err != nil {
return nil, err
@@ -72,7 +71,6 @@ func (c *Client) GetDomain(ctx context.Context, domain string) (*DomainInfoRespo
}
respData := &DomainInfoResponse{}
-
err = c.do(req, respData)
if err != nil {
return nil, err
@@ -90,7 +88,6 @@ func (c *Client) do(req *http.Request, result any) error {
if resp != nil {
defer func() { _ = resp.Body.Close() }()
}
-
if err != nil {
return errutils.NewHTTPDoError(req, err)
}
@@ -143,7 +140,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
response := &ErrorResponse{}
-
err := json.Unmarshal(raw, response)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/versio/versio.go b/providers/dns/versio/versio.go
index 05a7263c4..78ddd9bac 100644
--- a/providers/dns/versio/versio.go
+++ b/providers/dns/versio/versio.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/versio/internal"
)
@@ -92,11 +91,9 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
return nil, errors.New("versio: the configuration of the DNS provider is nil")
}
-
if config.Username == "" {
return nil, errors.New("versio: the versio username is missing")
}
-
if config.Password == "" {
return nil, errors.New("versio: the versio password is missing")
}
@@ -111,8 +108,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
@@ -160,7 +155,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("versio: %w", err)
}
-
return nil
}
@@ -188,7 +182,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
// loop through the existing entries and remove the specific record
msg := &internal.DomainInfo{}
-
for _, e := range domains.DomainInfo.DNSRecords {
if e.Name != info.EffectiveFQDN {
msg.DNSRecords = append(msg.DNSRecords, e)
@@ -199,6 +192,5 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("versio: %w", err)
}
-
return nil
}
diff --git a/providers/dns/versio/versio.toml b/providers/dns/versio/versio.toml
index 733947095..33f7125c8 100644
--- a/providers/dns/versio/versio.toml
+++ b/providers/dns/versio/versio.toml
@@ -7,7 +7,7 @@ Since = "v2.7.0"
Example = '''
VERSIO_USERNAME= \
VERSIO_PASSWORD= \
-lego --dns versio -d '*.example.com' -d example.com run
+lego --email you@example.com --dns versio -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/versio/versio_test.go b/providers/dns/versio/versio_test.go
index 563e70d05..ea1ccc221 100644
--- a/providers/dns/versio/versio_test.go
+++ b/providers/dns/versio/versio_test.go
@@ -54,7 +54,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -162,7 +161,6 @@ func TestDNSProvider_Present(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
provider := test.builder.Build(t)
@@ -206,7 +204,6 @@ func TestDNSProvider_CleanUp(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
provider := test.builder.Build(t)
@@ -227,7 +224,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -241,7 +237,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -257,13 +252,6 @@ func mockBuilder() *servermock.Builder[*DNSProvider] {
EnvEndpoint: server.URL,
})
- provider, err := NewDNSProvider()
- if err != nil {
- return nil, err
- }
-
- provider.client.HTTPClient = server.Client()
-
- return provider, nil
+ return NewDNSProvider()
})
}
diff --git a/providers/dns/vinyldns/vinyldns.go b/providers/dns/vinyldns/vinyldns.go
index 65a024513..9e36ccc51 100644
--- a/providers/dns/vinyldns/vinyldns.go
+++ b/providers/dns/vinyldns/vinyldns.go
@@ -2,17 +2,14 @@
package vinyldns
import (
- "context"
"errors"
"fmt"
- "net/http"
"strconv"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/internal/useragent"
"github.com/vinyldns/go-vinyldns/vinyldns"
)
@@ -29,7 +26,6 @@ const (
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
@@ -44,7 +40,6 @@ type Config struct {
TTL int
PropagationTimeout time.Duration
PollingInterval time.Duration
- HTTPClient *http.Client
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
@@ -53,9 +48,6 @@ func NewDefaultConfig() *Config {
TTL: env.GetOrDefaultInt(EnvTTL, 30),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 4*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
}
}
@@ -104,22 +96,13 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
UserAgent: useragent.Get(),
})
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- } else {
- // For compatibility, it should be removed in v5.
- client.HTTPClient.Timeout = 30 * time.Second
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
+ client.HTTPClient.Timeout = 30 * time.Second
return &DNSProvider{client: client, config: config}, nil
}
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
existingRecord, err := d.getRecordSet(info.EffectiveFQDN)
@@ -132,7 +115,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
record := vinyldns.Record{Text: value}
if existingRecord == nil || existingRecord.ID == "" {
- err = d.createRecordSet(ctx, info.EffectiveFQDN, []vinyldns.Record{record})
+ err = d.createRecordSet(info.EffectiveFQDN, []vinyldns.Record{record})
if err != nil {
return fmt.Errorf("vinyldns: %w", err)
}
@@ -149,7 +132,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
records := existingRecord.Records
records = append(records, record)
- err = d.updateRecordSet(ctx, existingRecord, records)
+ err = d.updateRecordSet(existingRecord, records)
if err != nil {
return fmt.Errorf("vinyldns: %w", err)
}
@@ -159,8 +142,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- ctx := context.Background()
-
info := dns01.GetChallengeInfo(domain, keyAuth)
existingRecord, err := d.getRecordSet(info.EffectiveFQDN)
@@ -175,7 +156,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
value := d.formatValue(info.Value)
var records []vinyldns.Record
-
for _, i := range existingRecord.Records {
if i.Text != value {
records = append(records, i)
@@ -183,7 +163,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
if len(records) == 0 {
- err = d.deleteRecordSet(ctx, existingRecord)
+ err = d.deleteRecordSet(existingRecord)
if err != nil {
return fmt.Errorf("vinyldns: %w", err)
}
@@ -191,7 +171,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return nil
}
- err = d.updateRecordSet(ctx, existingRecord, records)
+ err = d.updateRecordSet(existingRecord, records)
if err != nil {
return fmt.Errorf("vinyldns: %w", err)
}
diff --git a/providers/dns/vinyldns/vinyldns.toml b/providers/dns/vinyldns/vinyldns.toml
index d6dd5810e..8c9f1b3a6 100644
--- a/providers/dns/vinyldns/vinyldns.toml
+++ b/providers/dns/vinyldns/vinyldns.toml
@@ -8,7 +8,7 @@ Example = '''
VINYLDNS_ACCESS_KEY=xxxxxx \
VINYLDNS_SECRET_KEY=yyyyy \
VINYLDNS_HOST=https://api.vinyldns.example.org:9443 \
-lego --dns vinyldns -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vinyldns -d '*.example.com' -d example.com run
'''
Additional = '''
@@ -26,7 +26,6 @@ Users are required to have DELETE ACL level or zone admin permissions on the Vin
VINYLDNS_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 4)"
VINYLDNS_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)"
VINYLDNS_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 30)"
- VINYLDNS_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
[Links]
API = "https://www.vinyldns.io/api/"
diff --git a/providers/dns/vinyldns/vinyldns_test.go b/providers/dns/vinyldns/vinyldns_test.go
index 7dfe2c13f..6f5b9b328 100644
--- a/providers/dns/vinyldns/vinyldns_test.go
+++ b/providers/dns/vinyldns/vinyldns_test.go
@@ -78,7 +78,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -163,7 +162,6 @@ func mockBuilder() *servermock.Builder[*DNSProvider] {
config.AccessKey = "foo"
config.SecretKey = "bar"
config.Host = server.URL
- config.HTTPClient = server.Client()
return NewDNSProviderConfig(config)
})
@@ -247,7 +245,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -261,7 +258,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/vinyldns/wrapper.go b/providers/dns/vinyldns/wrapper.go
index e7b59a82b..f17b3de31 100644
--- a/providers/dns/vinyldns/wrapper.go
+++ b/providers/dns/vinyldns/wrapper.go
@@ -1,10 +1,8 @@
package vinyldns
import (
- "context"
"fmt"
- "github.com/cenkalti/backoff/v5"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/wait"
"github.com/vinyldns/go-vinyldns/vinyldns"
@@ -27,7 +25,6 @@ func (d *DNSProvider) getRecordSet(fqdn string) (*vinyldns.RecordSet, error) {
}
var recordSets []vinyldns.RecordSet
-
for _, i := range allRecordSets {
if i.Type == "TXT" {
recordSets = append(recordSets, i)
@@ -44,7 +41,7 @@ func (d *DNSProvider) getRecordSet(fqdn string) (*vinyldns.RecordSet, error) {
}
}
-func (d *DNSProvider) createRecordSet(ctx context.Context, fqdn string, records []vinyldns.Record) error {
+func (d *DNSProvider) createRecordSet(fqdn string, records []vinyldns.Record) error {
zoneName, hostName, err := splitDomain(fqdn)
if err != nil {
return err
@@ -68,10 +65,10 @@ func (d *DNSProvider) createRecordSet(ctx context.Context, fqdn string, records
return err
}
- return d.waitForChanges(ctx, "CreateRS", resp)
+ return d.waitForChanges("CreateRS", resp)
}
-func (d *DNSProvider) updateRecordSet(ctx context.Context, recordSet *vinyldns.RecordSet, newRecords []vinyldns.Record) error {
+func (d *DNSProvider) updateRecordSet(recordSet *vinyldns.RecordSet, newRecords []vinyldns.Record) error {
operation := "delete"
if len(recordSet.Records) < len(newRecords) {
operation = "add"
@@ -85,35 +82,33 @@ func (d *DNSProvider) updateRecordSet(ctx context.Context, recordSet *vinyldns.R
return err
}
- return d.waitForChanges(ctx, "UpdateRS - "+operation, resp)
+ return d.waitForChanges("UpdateRS - "+operation, resp)
}
-func (d *DNSProvider) deleteRecordSet(ctx context.Context, existingRecord *vinyldns.RecordSet) error {
+func (d *DNSProvider) deleteRecordSet(existingRecord *vinyldns.RecordSet) error {
resp, err := d.client.RecordSetDelete(existingRecord.ZoneID, existingRecord.ID)
if err != nil {
return err
}
- return d.waitForChanges(ctx, "DeleteRS", resp)
+ return d.waitForChanges("DeleteRS", resp)
}
-func (d *DNSProvider) waitForChanges(ctx context.Context, operation string, resp *vinyldns.RecordSetUpdateResponse) error {
- return wait.Retry(ctx,
- func() error {
+func (d *DNSProvider) waitForChanges(operation string, resp *vinyldns.RecordSetUpdateResponse) error {
+ return wait.For("vinyldns", d.config.PropagationTimeout, d.config.PollingInterval,
+ func() (bool, error) {
change, err := d.client.RecordSetChange(resp.Zone.ID, resp.RecordSet.ID, resp.ChangeID)
if err != nil {
- return fmt.Errorf("failed to query change status: %w", err)
+ return false, fmt.Errorf("failed to query change status: %w", err)
}
- if change.Status != "Complete" {
- return fmt.Errorf("waiting operation: %s, zoneID: %s, recordsetID: %s, changeID: %s",
- operation, resp.Zone.ID, resp.RecordSet.ID, resp.ChangeID)
+ if change.Status == "Complete" {
+ return true, nil
}
- return nil
+ return false, fmt.Errorf("waiting operation: %s, zoneID: %s, recordsetID: %s, changeID: %s",
+ operation, resp.Zone.ID, resp.RecordSet.ID, resp.ChangeID)
},
- backoff.WithBackOff(backoff.NewConstantBackOff(d.config.PollingInterval)),
- backoff.WithMaxElapsedTime(d.config.PropagationTimeout),
)
}
diff --git a/providers/dns/virtualname/virtualname.go b/providers/dns/virtualname/virtualname.go
deleted file mode 100644
index 34637d280..000000000
--- a/providers/dns/virtualname/virtualname.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Package virtualname implements a DNS provider for solving the DNS-01 challenge using Virtualname DNS.
-package virtualname
-
-import (
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge"
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/tecnocratica"
-)
-
-// Environment variables names.
-const (
- envNamespace = "VIRTUALNAME_"
-
- EnvToken = envNamespace + "TOKEN"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-const defaultBaseURL = "https://api.virtualname.net/v1"
-
-var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config = tecnocratica.Config
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 5*time.Minute),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 10*time.Second),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- prv challenge.ProviderTimeout
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for Virtualname.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvToken)
- if err != nil {
- return nil, fmt.Errorf("virtualname: %w", err)
- }
-
- config := NewDefaultConfig()
- config.Token = values[EnvToken]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for Virtualname.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("virtualname: the configuration of the DNS provider is nil")
- }
-
- provider, err := tecnocratica.NewDNSProviderConfig(config, defaultBaseURL)
- if err != nil {
- return nil, fmt.Errorf("virtualname: %w", err)
- }
-
- return &DNSProvider{prv: provider}, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("virtualname: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("virtualname: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
-}
diff --git a/providers/dns/virtualname/virtualname.toml b/providers/dns/virtualname/virtualname.toml
deleted file mode 100644
index 881f09797..000000000
--- a/providers/dns/virtualname/virtualname.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-Name = "Virtualname"
-Description = ''''''
-URL = "https://www.virtualname.es/"
-Code = "virtualname"
-Since = "v4.30.0"
-
-Example = '''
-VIRTUALNAME_TOKEN=xxxxxx \
-lego --dns virtualname -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- VIRTUALNAME_TOKEN = "API token"
- [Configuration.Additional]
- VIRTUALNAME_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 10)"
- VIRTUALNAME_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 300)"
- VIRTUALNAME_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- VIRTUALNAME_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://developers.virtualname.net/#dns"
diff --git a/providers/dns/virtualname/virtualname_test.go b/providers/dns/virtualname/virtualname_test.go
deleted file mode 100644
index da5867e86..000000000
--- a/providers/dns/virtualname/virtualname_test.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package virtualname
-
-import (
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvToken).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvToken: "secret",
- },
- },
- {
- desc: "missing credentials: token",
- envVars: map[string]string{
- EnvToken: "",
- },
- expected: "virtualname: some credentials information are missing: VIRTUALNAME_TOKEN",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.prv)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- token string
- expected string
- }{
- {
- desc: "success",
- token: "secret",
- },
- {
- desc: "missing token",
- expected: "virtualname: missing credentials",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.Token = test.token
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.prv)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/vkcloud/internal/client.go b/providers/dns/vkcloud/internal/client.go
index 2b03518db..5ced88d2d 100644
--- a/providers/dns/vkcloud/internal/client.go
+++ b/providers/dns/vkcloud/internal/client.go
@@ -46,7 +46,6 @@ func (c *Client) ListZones() ([]DNSZone, error) {
endpoint := c.baseURL.JoinPath("/")
var zones []DNSZone
-
opts := &gophercloud.RequestOpts{JSONResponse: &zones}
err := c.request(http.MethodGet, endpoint, opts)
@@ -61,7 +60,6 @@ func (c *Client) ListTXTRecords(zoneUUID string) ([]DNSTXTRecord, error) {
endpoint := c.baseURL.JoinPath(zoneUUID, "txt", "/")
var records []DNSTXTRecord
-
opts := &gophercloud.RequestOpts{JSONResponse: &records}
err := c.request(http.MethodGet, endpoint, opts)
diff --git a/providers/dns/vkcloud/vkcloud.go b/providers/dns/vkcloud/vkcloud.go
index ffacdbe52..2aea7838c 100644
--- a/providers/dns/vkcloud/vkcloud.go
+++ b/providers/dns/vkcloud/vkcloud.go
@@ -135,7 +135,6 @@ func (d *DNSProvider) Present(domain, _, keyAuth string) error {
}
var zoneUUID string
-
for _, zone := range zones {
if zone.Zone == authZone {
zoneUUID = zone.UUID
diff --git a/providers/dns/vkcloud/vkcloud.toml b/providers/dns/vkcloud/vkcloud.toml
index 04f57fea3..366039694 100644
--- a/providers/dns/vkcloud/vkcloud.toml
+++ b/providers/dns/vkcloud/vkcloud.toml
@@ -8,7 +8,7 @@ Example = '''
VK_CLOUD_PROJECT_ID="" \
VK_CLOUD_USERNAME="" \
VK_CLOUD_PASSWORD="" \
-lego --dns vkcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vkcloud -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/vkcloud/vkcloud_test.go b/providers/dns/vkcloud/vkcloud_test.go
index e7883b486..edc32363a 100644
--- a/providers/dns/vkcloud/vkcloud_test.go
+++ b/providers/dns/vkcloud/vkcloud_test.go
@@ -60,7 +60,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -189,7 +188,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -203,7 +201,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/volcengine/volcengine.go b/providers/dns/volcengine/volcengine.go
index 765d38adb..a271e0f26 100644
--- a/providers/dns/volcengine/volcengine.go
+++ b/providers/dns/volcengine/volcengine.go
@@ -159,7 +159,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
d.recordIDsMu.Lock()
recordID, ok := d.recordIDs[token]
d.recordIDsMu.Unlock()
-
if !ok {
return fmt.Errorf("volcengine: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
}
@@ -171,10 +170,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("volcengine: delete record: %w", err)
}
- d.recordIDsMu.Lock()
- delete(d.recordIDs, token)
- d.recordIDsMu.Unlock()
-
return nil
}
diff --git a/providers/dns/volcengine/volcengine.toml b/providers/dns/volcengine/volcengine.toml
index ceedcb18a..cb7c219f7 100644
--- a/providers/dns/volcengine/volcengine.toml
+++ b/providers/dns/volcengine/volcengine.toml
@@ -7,7 +7,7 @@ Since = "v4.19.0"
Example = '''
VOLC_ACCESSKEY=xxx \
VOLC_SECRETKEY=yyy \
-lego --dns volcengine -d '*.example.com' -d example.com run
+lego --email you@example.com --dns volcengine -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/volcengine/volcengine_test.go b/providers/dns/volcengine/volcengine_test.go
index 0f79ed83a..5e9167612 100644
--- a/providers/dns/volcengine/volcengine_test.go
+++ b/providers/dns/volcengine/volcengine_test.go
@@ -55,7 +55,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -126,7 +125,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -140,7 +138,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/vscale/vscale.go b/providers/dns/vscale/vscale.go
index a159db307..6c51ae5ca 100644
--- a/providers/dns/vscale/vscale.go
+++ b/providers/dns/vscale/vscale.go
@@ -4,9 +4,11 @@
package vscale
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "net/url"
"time"
"github.com/go-acme/lego/v4/challenge"
@@ -28,18 +30,25 @@ const (
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
-const defaultBaseURL = "https://api.vscale.io/v1/domains"
+const minTTL = 60
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
-type Config = selectel.Config
+type Config struct {
+ BaseURL string
+ Token string
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
- BaseURL: env.GetOrDefaultString(EnvBaseURL, defaultBaseURL),
- TTL: env.GetOrDefaultInt(EnvTTL, selectel.MinTTL),
+ BaseURL: env.GetOrDefaultString(EnvBaseURL, selectel.DefaultVScaleBaseURL),
+ TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 120*time.Second),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPClient: &http.Client{
@@ -50,7 +59,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *selectel.Client
}
// NewDNSProvider returns a DNSProvider instance configured for Vscale Domains API.
@@ -73,40 +83,89 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("vscale: the configuration of the DNS provider is nil")
}
- if config.BaseURL == "" {
- config.BaseURL = defaultBaseURL
+ if config.Token == "" {
+ return nil, errors.New("vscale: credentials missing")
}
- provider, err := selectel.NewDNSProviderConfig(config)
+ if config.TTL < minTTL {
+ return nil, fmt.Errorf("vscale: invalid TTL, TTL (%d) must be greater than %d", config.TTL, minTTL)
+ }
+
+ client := selectel.NewClient(config.Token)
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ var err error
+ client.BaseURL, err = url.Parse(config.BaseURL)
if err != nil {
return nil, fmt.Errorf("vscale: %w", err)
}
- return &DNSProvider{prv: provider}, nil
+ return &DNSProvider{config: config, client: client}, nil
}
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("vscale: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
- if err != nil {
- return fmt.Errorf("vscale: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
+// Timeout returns the Timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+ return d.config.PropagationTimeout, d.config.PollingInterval
+}
+
+// Present creates a TXT record to fulfill DNS-01 challenge.
+func (d *DNSProvider) Present(domain, token, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ ctx := context.Background()
+
+ // TODO(ldez) replace domain by FQDN to follow CNAME.
+ domainObj, err := d.client.GetDomainByName(ctx, domain)
+ if err != nil {
+ return fmt.Errorf("vscale: %w", err)
+ }
+
+ txtRecord := selectel.Record{
+ Type: "TXT",
+ TTL: d.config.TTL,
+ Name: info.EffectiveFQDN,
+ Content: info.Value,
+ }
+ _, err = d.client.AddRecord(ctx, domainObj.ID, txtRecord)
+ if err != nil {
+ return fmt.Errorf("vscale: %w", err)
+ }
+
+ return nil
+}
+
+// CleanUp removes a TXT record used for DNS-01 challenge.
+func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ recordName := dns01.UnFqdn(info.EffectiveFQDN)
+
+ ctx := context.Background()
+
+ // TODO(ldez) replace domain by FQDN to follow CNAME.
+ domainObj, err := d.client.GetDomainByName(ctx, domain)
+ if err != nil {
+ return fmt.Errorf("vscale: %w", err)
+ }
+
+ records, err := d.client.ListRecords(ctx, domainObj.ID)
+ if err != nil {
+ return fmt.Errorf("vscale: %w", err)
+ }
+
+ // Delete records with specific FQDN
+ var lastErr error
+ for _, record := range records {
+ if record.Name == recordName {
+ err = d.client.DeleteRecord(ctx, domainObj.ID, record.ID)
+ if err != nil {
+ lastErr = fmt.Errorf("vscale: %w", err)
+ }
+ }
+ }
+
+ return lastErr
}
diff --git a/providers/dns/vscale/vscale.toml b/providers/dns/vscale/vscale.toml
index f7dc0d943..78b6c99e5 100644
--- a/providers/dns/vscale/vscale.toml
+++ b/providers/dns/vscale/vscale.toml
@@ -6,7 +6,7 @@ Since = "v2.0.0"
Example = '''
VSCALE_API_TOKEN=xxxxx \
-lego --dns vscale -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vscale -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/vscale/vscale_test.go b/providers/dns/vscale/vscale_test.go
index 9012c7563..6a9b25583 100644
--- a/providers/dns/vscale/vscale_test.go
+++ b/providers/dns/vscale/vscale_test.go
@@ -6,7 +6,6 @@ import (
"time"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/providers/dns/internal/selectel"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -37,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -47,7 +45,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- assert.NotNil(t, p.prv)
+ assert.NotNil(t, p.config)
+ assert.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -77,7 +76,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
desc: "bad TTL value",
token: "123",
ttl: 59,
- expected: fmt.Sprintf("vscale: invalid TTL, TTL (59) must be greater than %d", selectel.MinTTL),
+ expected: fmt.Sprintf("vscale: invalid TTL, TTL (59) must be greater than %d", minTTL),
},
}
@@ -92,7 +91,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- assert.NotNil(t, p.prv)
+ assert.NotNil(t, p.config)
+ assert.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -106,7 +106,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -120,7 +119,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/vultr/vultr.go b/providers/dns/vultr/vultr.go
index f97a321c1..7672d2054 100644
--- a/providers/dns/vultr/vultr.go
+++ b/providers/dns/vultr/vultr.go
@@ -13,7 +13,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/vultr/govultr/v3"
"golang.org/x/oauth2"
)
@@ -39,7 +38,7 @@ type Config struct {
PollingInterval time.Duration
TTL int
HTTPClient *http.Client
- HTTPTimeout time.Duration // TODO(ldez): remove in v5
+ HTTPTimeout time.Duration
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
@@ -85,7 +84,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
authClient := OAuthStaticAccessToken(config.HTTPClient, config.APIKey)
authClient.Timeout = config.HTTPTimeout
- client := govultr.NewClient(clientdebug.Wrap(authClient))
+ client := govultr.NewClient(authClient)
return &DNSProvider{client: client, config: config}, nil
}
@@ -107,7 +106,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("vultr: %w", err)
}
- req := govultr.DomainRecordCreateReq{
+ req := govultr.DomainRecordReq{
Name: subDomain,
Type: "TXT",
Data: `"` + info.Value + `"`,
@@ -136,7 +135,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var allErr []string
-
for _, rec := range records {
err := d.client.DomainRecord.Delete(ctx, zoneDomain, rec.ID)
if err != nil {
@@ -206,7 +204,6 @@ func (d *DNSProvider) findTxtRecords(ctx context.Context, domain, fqdn string) (
listOptions := &govultr.ListOptions{PerPage: 25}
var records []govultr.DomainRecord
-
for {
result, meta, resp, err := d.client.DomainRecord.List(ctx, zoneDomain, listOptions)
if err != nil {
diff --git a/providers/dns/vultr/vultr.toml b/providers/dns/vultr/vultr.toml
index 78e878bea..7d31bd52b 100644
--- a/providers/dns/vultr/vultr.toml
+++ b/providers/dns/vultr/vultr.toml
@@ -6,7 +6,7 @@ Since = "v0.3.1"
Example = '''
VULTR_API_KEY=xxxxx \
-lego --dns vultr -d '*.example.com' -d example.com run
+lego --email you@example.com --dns vultr -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/vultr/vultr_test.go b/providers/dns/vultr/vultr_test.go
index 17d962b2a..9be1a19b0 100644
--- a/providers/dns/vultr/vultr_test.go
+++ b/providers/dns/vultr/vultr_test.go
@@ -45,7 +45,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -165,7 +164,7 @@ func TestDNSProvider_getHostedZone(t *testing.T) {
provider := servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
- client := govultr.NewClient(server.Client())
+ client := govultr.NewClient(nil)
err := client.SetBaseURL(server.URL)
require.NoError(t, err)
@@ -222,7 +221,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -236,7 +234,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/webnames/internal/client.go b/providers/dns/webnames/internal/client.go
index 985503d2a..5b1a8b357 100644
--- a/providers/dns/webnames/internal/client.go
+++ b/providers/dns/webnames/internal/client.go
@@ -83,7 +83,6 @@ func (c *Client) doRequest(ctx context.Context, data url.Values) error {
}
var r APIResponse
-
err = json.Unmarshal(raw, &r)
if err != nil {
return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
diff --git a/providers/dns/webnames/webnames.go b/providers/dns/webnames/webnames.go
index 9c27164e3..78905e22c 100644
--- a/providers/dns/webnames/webnames.go
+++ b/providers/dns/webnames/webnames.go
@@ -6,20 +6,17 @@ import (
"errors"
"fmt"
"net/http"
- "strings"
"time"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/webnames/internal"
)
// Environment variables names.
const (
- envNamespace = "WEBNAMESRU_"
- altEnvNamespace = "WEBNAMES_"
+ envNamespace = "WEBNAMES_"
EnvAPIKey = envNamespace + "API_KEY"
@@ -42,10 +39,10 @@ type Config struct {
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
- PropagationTimeout: env.GetOneWithFallback(EnvPropagationTimeout, dns01.DefaultPropagationTimeout, env.ParseSecond, altEnvName(EnvPropagationTimeout)),
- PollingInterval: env.GetOneWithFallback(EnvPollingInterval, dns01.DefaultPollingInterval, env.ParseSecond, altEnvName(EnvPollingInterval)),
+ PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
+ PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPClient: &http.Client{
- Timeout: env.GetOneWithFallback(EnvHTTPTimeout, 20*time.Second, env.ParseSecond, altEnvName(EnvHTTPTimeout)),
+ Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
},
}
}
@@ -57,11 +54,11 @@ type DNSProvider struct {
}
// NewDNSProvider returns a new DNS provider using
-// environment variable WEBNAMESRU_API_KEY for adding and removing the DNS record.
+// environment variable WEBNAMES_API_KEY for adding and removing the DNS record.
func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.GetWithFallback([]string{EnvAPIKey, altEnvName(EnvAPIKey)})
+ values, err := env.Get(EnvAPIKey)
if err != nil {
- return nil, fmt.Errorf("webnamesru: %w", err)
+ return nil, fmt.Errorf("webnames: %w", err)
}
config := NewDefaultConfig()
@@ -73,11 +70,11 @@ func NewDNSProvider() (*DNSProvider, error) {
// NewDNSProviderConfig return a DNSProvider instance configured for Webnames.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
- return nil, errors.New("webnamesru: the configuration of the DNS provider is nil")
+ return nil, errors.New("webnames: the configuration of the DNS provider is nil")
}
if config.APIKey == "" {
- return nil, errors.New("webnamesru: credentials missing")
+ return nil, errors.New("webnames: credentials missing")
}
client := internal.NewClient(config.APIKey)
@@ -86,8 +83,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
@@ -97,17 +92,17 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil {
- return fmt.Errorf("webnamesru: could not find zone for domain %q: %w", domain, err)
+ return fmt.Errorf("webnames: could not find zone for domain %q: %w", domain, err)
}
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
- return fmt.Errorf("webnamesru: %w", err)
+ return fmt.Errorf("webnames: %w", err)
}
err = d.client.AddTXTRecord(context.Background(), dns01.UnFqdn(authZone), subDomain, info.Value)
if err != nil {
- return fmt.Errorf("webnamesru: failed to create TXT records [domain: %s, sub domain: %s]: %w",
+ return fmt.Errorf("webnames: failed to create TXT records [domain: %s, sub domain: %s]: %w",
dns01.UnFqdn(authZone), subDomain, err)
}
@@ -120,17 +115,17 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil {
- return fmt.Errorf("webnamesru: could not find zone for domain %q: %w", domain, err)
+ return fmt.Errorf("webnames: could not find zone for domain %q: %w", domain, err)
}
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
- return fmt.Errorf("webnamesru: %w", err)
+ return fmt.Errorf("webnames: %w", err)
}
err = d.client.RemoveTXTRecord(context.Background(), dns01.UnFqdn(authZone), subDomain, info.Value)
if err != nil {
- return fmt.Errorf("webnamesru: failed to remove TXT records [domain: %s, sub domain: %s]: %w",
+ return fmt.Errorf("webnames: failed to remove TXT records [domain: %s, sub domain: %s]: %w",
dns01.UnFqdn(authZone), subDomain, err)
}
@@ -142,7 +137,3 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
-
-func altEnvName(v string) string {
- return strings.ReplaceAll(v, envNamespace, altEnvNamespace)
-}
diff --git a/providers/dns/webnames/webnames.toml b/providers/dns/webnames/webnames.toml
index b038deaf5..1962a69eb 100644
--- a/providers/dns/webnames/webnames.toml
+++ b/providers/dns/webnames/webnames.toml
@@ -1,13 +1,12 @@
-Name = "webnames.ru"
+Name = "Webnames"
Description = ''''''
URL = "https://www.webnames.ru/"
Code = "webnames"
-Aliases = ["webnamesru"]
Since = "v4.15.0"
Example = '''
-WEBNAMESRU_API_KEY=xxxxxx \
-lego --dns webnamesru -d '*.example.com' -d example.com run
+WEBNAMES_API_KEY=xxxxxx \
+lego --email you@example.com --dns webnames -d '*.example.com' -d example.com run
'''
Additional = '''
@@ -20,11 +19,11 @@ The API key can be found: Personal account / My domains and services / Select th
[Configuration]
[Configuration.Credentials]
- WEBNAMESRU_API_KEY = "Domain API key"
+ WEBNAMES_API_KEY = "Domain API key"
[Configuration.Additional]
- WEBNAMESRU_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- WEBNAMESRU_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- WEBNAMESRU_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
+ WEBNAMES_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
+ WEBNAMES_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
+ WEBNAMES_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
[Links]
API = "https://github.com/regtime-ltd/certbot-dns-webnames"
diff --git a/providers/dns/webnames/webnames_test.go b/providers/dns/webnames/webnames_test.go
index 072591c68..3ec69501f 100644
--- a/providers/dns/webnames/webnames_test.go
+++ b/providers/dns/webnames/webnames_test.go
@@ -29,14 +29,13 @@ func TestNewDNSProvider(t *testing.T) {
envVars: map[string]string{
EnvAPIKey: "",
},
- expected: "webnamesru: some credentials information are missing: WEBNAMESRU_API_KEY",
+ expected: "webnames: some credentials information are missing: WEBNAMES_API_KEY",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -66,7 +65,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
},
{
desc: "missing credentials",
- expected: "webnamesru: credentials missing",
+ expected: "webnames: credentials missing",
},
}
@@ -94,7 +93,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -108,7 +106,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/webnamesca/internal/client.go b/providers/dns/webnamesca/internal/client.go
deleted file mode 100644
index 203ff9eac..000000000
--- a/providers/dns/webnamesca/internal/client.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package internal
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
- "github.com/go-acme/lego/v4/providers/dns/internal/useragent"
-)
-
-const defaultBaseURL = "https://www.webnames.ca/_/APICore"
-
-// Client the webnames.ca API client.
-type Client struct {
- user string
- key string
-
- BaseURL *url.URL
- HTTPClient *http.Client
-}
-
-// NewClient creates a new Client.
-func NewClient(user, key string) (*Client, error) {
- if user == "" || key == "" {
- return nil, errors.New("credentials missing")
- }
-
- baseURL, _ := url.Parse(defaultBaseURL)
-
- return &Client{
- user: user,
- key: key,
- BaseURL: baseURL,
- HTTPClient: &http.Client{Timeout: 10 * time.Second},
- }, nil
-}
-
-func (c *Client) AddTXTRecord(ctx context.Context, domainName, hostName, value string) ([]DNSRecordSet, error) {
- endpoint := c.BaseURL.JoinPath("domains", domainName, "add-txt-record")
-
- query := endpoint.Query()
- query.Set("hostName", hostName)
- query.Set("txt", value)
-
- endpoint.RawQuery = query.Encode()
-
- req, err := newJSONRequest(ctx, http.MethodPost, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result APIResponse[*DNSInfo]
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Result.DNSRecordSets, nil
-}
-
-func (c *Client) DeleteTXTRecord(ctx context.Context, domainName, hostName, value string) ([]DNSRecordSet, error) {
- endpoint := c.BaseURL.JoinPath("domains", domainName, "delete-txt-record")
-
- query := endpoint.Query()
- query.Set("hostName", hostName)
- query.Set("txt", value)
-
- endpoint.RawQuery = query.Encode()
-
- req, err := newJSONRequest(ctx, http.MethodDelete, endpoint, nil)
- if err != nil {
- return nil, err
- }
-
- var result APIResponse[*DNSInfo]
-
- err = c.do(req, &result)
- if err != nil {
- return nil, err
- }
-
- return result.Result.DNSRecordSets, nil
-}
-
-func (c *Client) do(req *http.Request, result any) error {
- useragent.SetHeader(req.Header)
-
- req.Header.Set("API-User", c.user)
- req.Header.Set("API-Key", c.key)
-
- resp, err := c.HTTPClient.Do(req)
- if err != nil {
- return errutils.NewHTTPDoError(req, err)
- }
-
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode/100 != 2 {
- return parseError(req, resp)
- }
-
- if result == nil {
- return nil
- }
-
- raw, err := io.ReadAll(resp.Body)
- if err != nil {
- return errutils.NewReadResponseError(req, resp.StatusCode, err)
- }
-
- err = json.Unmarshal(raw, result)
- if err != nil {
- return errutils.NewUnmarshalError(req, resp.StatusCode, raw, err)
- }
-
- return nil
-}
-
-func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, payload any) (*http.Request, error) {
- buf := new(bytes.Buffer)
-
- if payload != nil {
- err := json.NewEncoder(buf).Encode(payload)
- if err != nil {
- return nil, fmt.Errorf("failed to create request JSON body: %w", err)
- }
- }
-
- req, err := http.NewRequestWithContext(ctx, method, endpoint.String(), buf)
- if err != nil {
- return nil, fmt.Errorf("unable to create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/json")
-
- if payload != nil {
- req.Header.Set("Content-Type", "application/json")
- }
-
- 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
-}
diff --git a/providers/dns/webnamesca/internal/client_test.go b/providers/dns/webnamesca/internal/client_test.go
deleted file mode 100644
index ad8571ed0..000000000
--- a/providers/dns/webnamesca/internal/client_test.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package internal
-
-import (
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func mockBuilder() *servermock.Builder[*Client] {
- return servermock.NewBuilder[*Client](
- func(server *httptest.Server) (*Client, error) {
- client, err := NewClient("user", "secret")
- if err != nil {
- return nil, err
- }
-
- client.BaseURL, _ = url.Parse(server.URL)
- client.HTTPClient = server.Client()
-
- return client, nil
- },
- servermock.CheckHeader().
- With("API-User", "user").
- With("API-Key", "secret").
- WithJSONHeaders(),
- )
-}
-
-func TestClient_AddTXTRecord(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/example.com/add-txt-record",
- servermock.ResponseFromFixture("add_txt_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("hostName", "foo.example.com").
- With("txt", "value")).
- Build(t)
-
- result, err := client.AddTXTRecord(t.Context(), "example.com", "foo.example.com", "value")
- require.NoError(t, err)
-
- expected := []DNSRecordSet{{
- Hostname: "_acme-challenge.example.com",
- Type: "TXT",
- Records: []string{"value"},
- }}
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_AddTXTRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("POST /domains/example.com/add-txt-record",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- _, err := client.AddTXTRecord(t.Context(), "example.com", "foo.example.com", "value")
- require.EqualError(t, err, "message: User does not exist., details: string, logiD: 35579, result: {}")
-}
-
-func TestClient_DeleteTXTRecord(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/delete-txt-record",
- servermock.ResponseFromFixture("delete_txt_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("hostName", "foo.example.com").
- With("txt", "value")).
- Build(t)
-
- result, err := client.DeleteTXTRecord(t.Context(), "example.com", "foo.example.com", "value")
- require.NoError(t, err)
-
- expected := []DNSRecordSet{{
- Hostname: "_acme-challenge.example.com",
- Type: "TXT",
- Records: []string{"value"},
- }}
-
- assert.Equal(t, expected, result)
-}
-
-func TestClient_DeleteTXTRecord_error(t *testing.T) {
- client := mockBuilder().
- Route("DELETE /domains/example.com/delete-txt-record",
- servermock.ResponseFromFixture("error.json").
- WithStatusCode(http.StatusBadRequest)).
- Build(t)
-
- _, err := client.DeleteTXTRecord(t.Context(), "example.com", "foo.example.com", "value")
- require.EqualError(t, err, "message: User does not exist., details: string, logiD: 35579, result: {}")
-}
diff --git a/providers/dns/webnamesca/internal/fixtures/add_txt_record.json b/providers/dns/webnamesca/internal/fixtures/add_txt_record.json
deleted file mode 100644
index 9754689a7..000000000
--- a/providers/dns/webnamesca/internal/fixtures/add_txt_record.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "result": {
- "domainAdvancedDNSConfigID": 3258480,
- "domainID": 1333334,
- "dtCreated": "2025-10-30T11:55:23.243",
- "dtModified": "2025-10-30T11:55:23.177",
- "timeToLive": 21600,
- "soAorigin": "hosting.webnames.ca",
- "soArefresh": 21600,
- "soAretry": 180,
- "soAexpire": 1209600,
- "soAnegcache": 3600,
- "forwardingURL": null,
- "gripping": false,
- "name": null,
- "dtSubmitted": "2025-10-30T11:55:24.927",
- "dtRequestedDNSChange": null,
- "type": "REAL_DOMAIN",
- "userManaged": false,
- "effectiveMgmtOption": "AD",
- "urlForwardRootOnly": false,
- "enableDNSSEC": false,
- "dnsRecordSets": [
- {
- "hostname": "_acme-challenge.example.com",
- "type": "TXT",
- "records": [
- "value"
- ]
- }
- ]
- },
- "logID": 36014
-}
diff --git a/providers/dns/webnamesca/internal/fixtures/delete_txt_record.json b/providers/dns/webnamesca/internal/fixtures/delete_txt_record.json
deleted file mode 100644
index be2279ef6..000000000
--- a/providers/dns/webnamesca/internal/fixtures/delete_txt_record.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "errorMessage": "string",
- "errorDetails": "string",
- "logID": 0,
- "result": {
- "domainAdvancedDNSConfigID": 0,
- "domainID": 0,
- "dtCreated": "2025-10-29T21:22:31.478",
- "dtModified": "2025-10-29T21:22:31.478",
- "timeToLive": 0,
- "soAorigin": "string",
- "soArefresh": 0,
- "soAretry": 0,
- "soAexpire": 0,
- "soAnegcache": 0,
- "forwardingURL": "string",
- "gripping": true,
- "name": "string",
- "dtSubmitted": "2025-10-29T21:22:31.478",
- "dtRequestedDNSChange": "2025-10-29T21:22:31.478",
- "type": "string",
- "userManaged": true,
- "effectiveMgmtOption": "string",
- "urlForwardRootOnly": true,
- "enableDNSSEC": true,
- "dnsRecordSets": [
- {
- "hostname": "_acme-challenge.example.com",
- "type": "TXT",
- "records": [
- "value"
- ]
- }
- ]
- }
-}
diff --git a/providers/dns/webnamesca/internal/fixtures/error.json b/providers/dns/webnamesca/internal/fixtures/error.json
deleted file mode 100644
index 3e7548abb..000000000
--- a/providers/dns/webnamesca/internal/fixtures/error.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "errorMessage": "User does not exist.",
- "errorDetails": "string",
- "logID": 35579,
- "result": {}
-}
diff --git a/providers/dns/webnamesca/internal/types.go b/providers/dns/webnamesca/internal/types.go
deleted file mode 100644
index 8dc56c33a..000000000
--- a/providers/dns/webnamesca/internal/types.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "fmt"
-)
-
-type APIError struct {
- ErrorMessage string `json:"errorMessage,omitempty"`
- ErrorDetails string `json:"errorDetails,omitempty"`
- LogID int `json:"logID,omitempty"`
- Result json.RawMessage `json:"result,omitempty"`
-}
-
-func (a *APIError) Error() string {
- return fmt.Sprintf("message: %s, details: %s, logiD: %d, result: %s", a.ErrorMessage, a.ErrorDetails, a.LogID, a.Result)
-}
-
-type APIResponse[T any] struct {
- Result T `json:"result,omitempty"`
- LogID int `json:"logID,omitempty"`
-}
-
-type DNSInfo struct {
- DomainID int `json:"domainID,omitempty"`
- DNSRecordSets []DNSRecordSet `json:"dnsRecordSets,omitempty"`
-}
-
-type DNSRecordSet struct {
- Hostname string `json:"hostname"`
- Type string `json:"type"`
- Records []string `json:"records"`
-}
diff --git a/providers/dns/webnamesca/webnamesca.go b/providers/dns/webnamesca/webnamesca.go
deleted file mode 100644
index 874c1c48e..000000000
--- a/providers/dns/webnamesca/webnamesca.go
+++ /dev/null
@@ -1,134 +0,0 @@
-// Package webnamesca implements a DNS provider for solving the DNS-01 challenge using webnames.ca.
-package webnamesca
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "time"
-
- "github.com/go-acme/lego/v4/challenge/dns01"
- "github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
- "github.com/go-acme/lego/v4/providers/dns/webnamesca/internal"
-)
-
-// Environment variables names.
-const (
- envNamespace = "WEBNAMESCA_"
-
- EnvAPIUser = envNamespace + "API_USER"
- EnvAPIKey = envNamespace + "API_KEY"
-
- EnvTTL = envNamespace + "TTL"
- EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
- EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
- EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
-)
-
-// Config is used to configure the creation of the DNSProvider.
-type Config struct {
- APIUser string
- APIKey string
-
- PropagationTimeout time.Duration
- PollingInterval time.Duration
- TTL int
- HTTPClient *http.Client
-}
-
-// NewDefaultConfig returns a default configuration for the DNSProvider.
-func NewDefaultConfig() *Config {
- return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL),
- PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
- PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
- HTTPClient: &http.Client{
- Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
- },
- }
-}
-
-// DNSProvider implements the challenge.Provider interface.
-type DNSProvider struct {
- config *Config
- client *internal.Client
-}
-
-// NewDNSProvider returns a DNSProvider instance configured for webnames.ca.
-func NewDNSProvider() (*DNSProvider, error) {
- values, err := env.Get(EnvAPIUser, EnvAPIKey)
- if err != nil {
- return nil, fmt.Errorf("webnamesca: %w", err)
- }
-
- config := NewDefaultConfig()
- config.APIUser = values[EnvAPIUser]
- config.APIKey = values[EnvAPIKey]
-
- return NewDNSProviderConfig(config)
-}
-
-// NewDNSProviderConfig return a DNSProvider instance configured for webnames.ca.
-func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
- if config == nil {
- return nil, errors.New("webnamesca: the configuration of the DNS provider is nil")
- }
-
- client, err := internal.NewClient(config.APIUser, config.APIKey)
- if err != nil {
- return nil, fmt.Errorf("webnamesca: %w", err)
- }
-
- if config.HTTPClient != nil {
- client.HTTPClient = config.HTTPClient
- }
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
- return &DNSProvider{
- config: config,
- client: client,
- }, nil
-}
-
-// Present creates a TXT record using the specified parameters.
-func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("webnamesca: could not find zone for domain %q: %w", domain, err)
- }
-
- _, err = d.client.AddTXTRecord(context.Background(), dns01.UnFqdn(authZone), dns01.UnFqdn(info.EffectiveFQDN), info.Value)
- if err != nil {
- return fmt.Errorf("webnamesca: add TXT record: %w", err)
- }
-
- return nil
-}
-
-// CleanUp removes the TXT record matching the specified parameters.
-func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- info := dns01.GetChallengeInfo(domain, keyAuth)
-
- authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
- if err != nil {
- return fmt.Errorf("webnamesca: could not find zone for domain %q: %w", domain, err)
- }
-
- _, err = d.client.DeleteTXTRecord(context.Background(), dns01.UnFqdn(authZone), dns01.UnFqdn(info.EffectiveFQDN), info.Value)
- if err != nil {
- return fmt.Errorf("webnamesca: delete TXT record: %w", err)
- }
-
- return nil
-}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.config.PropagationTimeout, d.config.PollingInterval
-}
diff --git a/providers/dns/webnamesca/webnamesca.toml b/providers/dns/webnamesca/webnamesca.toml
deleted file mode 100644
index ab68a04a0..000000000
--- a/providers/dns/webnamesca/webnamesca.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-Name = "webnames.ca"
-Description = ''''''
-URL = "https://www.webnames.ca/"
-Code = "webnamesca"
-Since = "v4.28.0"
-
-Example = '''
-WEBNAMESCA_API_USER="xxx" \
-WEBNAMESCA_API_KEY="yyy" \
-lego --dns webnamesca -d '*.example.com' -d example.com run
-'''
-
-[Configuration]
- [Configuration.Credentials]
- WEBNAMESCA_API_USER = "API username"
- WEBNAMESCA_API_KEY = "API key"
- [Configuration.Additional]
- WEBNAMESCA_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
- WEBNAMESCA_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
- WEBNAMESCA_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)"
- WEBNAMESCA_HTTP_TIMEOUT = "API request timeout in seconds (Default: 30)"
-
-[Links]
- API = "https://www.webnames.ca/_/swagger/index.html"
diff --git a/providers/dns/webnamesca/webnamesca_test.go b/providers/dns/webnamesca/webnamesca_test.go
deleted file mode 100644
index 0459ef44e..000000000
--- a/providers/dns/webnamesca/webnamesca_test.go
+++ /dev/null
@@ -1,199 +0,0 @@
-package webnamesca
-
-import (
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
- "github.com/stretchr/testify/require"
-)
-
-const envDomain = envNamespace + "DOMAIN"
-
-var envTest = tester.NewEnvTest(EnvAPIUser, EnvAPIKey).WithDomain(envDomain)
-
-func TestNewDNSProvider(t *testing.T) {
- testCases := []struct {
- desc string
- envVars map[string]string
- expected string
- }{
- {
- desc: "success",
- envVars: map[string]string{
- EnvAPIUser: "user",
- EnvAPIKey: "secret",
- },
- },
- {
- desc: "missing EnvAPIUser",
- envVars: map[string]string{
- EnvAPIUser: "",
- EnvAPIKey: "secret",
- },
- expected: "webnamesca: some credentials information are missing: WEBNAMESCA_API_USER",
- },
- {
- desc: "missing EnvAPIKey",
- envVars: map[string]string{
- EnvAPIUser: "user",
- EnvAPIKey: "",
- },
- expected: "webnamesca: some credentials information are missing: WEBNAMESCA_API_KEY",
- },
- {
- desc: "missing credentials",
- envVars: map[string]string{},
- expected: "webnamesca: some credentials information are missing: WEBNAMESCA_API_USER,WEBNAMESCA_API_KEY",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- defer envTest.RestoreEnv()
-
- envTest.ClearEnv()
-
- envTest.Apply(test.envVars)
-
- p, err := NewDNSProvider()
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestNewDNSProviderConfig(t *testing.T) {
- testCases := []struct {
- desc string
- apiUser string
- apiKey string
- expected string
- }{
- {
- desc: "success",
- apiUser: "user",
- apiKey: "secret",
- },
- {
- desc: "missing apiUser",
- apiKey: "secret",
- expected: "webnamesca: credentials missing",
- },
- {
- desc: "missing apiKey",
- apiUser: "user",
- expected: "webnamesca: credentials missing",
- },
- {
- desc: "missing credentials",
- expected: "webnamesca: credentials missing",
- },
- }
-
- for _, test := range testCases {
- t.Run(test.desc, func(t *testing.T) {
- config := NewDefaultConfig()
- config.APIUser = test.apiUser
- config.APIKey = test.apiKey
-
- p, err := NewDNSProviderConfig(config)
-
- if test.expected == "" {
- require.NoError(t, err)
- require.NotNil(t, p)
- require.NotNil(t, p.config)
- require.NotNil(t, p.client)
- } else {
- require.EqualError(t, err, test.expected)
- }
- })
- }
-}
-
-func TestLivePresent(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.Present(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func TestLiveCleanUp(t *testing.T) {
- if !envTest.IsLiveTest() {
- t.Skip("skipping live test")
- }
-
- envTest.RestoreEnv()
-
- provider, err := NewDNSProvider()
- require.NoError(t, err)
-
- err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
- require.NoError(t, err)
-}
-
-func mockBuilder() *servermock.Builder[*DNSProvider] {
- return servermock.NewBuilder(
- func(server *httptest.Server) (*DNSProvider, error) {
- config := NewDefaultConfig()
- config.APIUser = "user"
- config.APIKey = "secret"
- config.HTTPClient = server.Client()
-
- p, err := NewDNSProviderConfig(config)
- if err != nil {
- return nil, err
- }
-
- p.client.BaseURL, _ = url.Parse(server.URL)
-
- return p, nil
- },
- servermock.CheckHeader().
- WithJSONHeaders().
- With("API-User", "user").
- With("API-Key", "secret"),
- )
-}
-
-func TestDNSProvider_Present(t *testing.T) {
- provider := mockBuilder().
- Route("POST /domains/example.com/add-txt-record",
- servermock.ResponseFromInternal("add_txt_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("hostName", "_acme-challenge.example.com").
- With("txt", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY")).
- Build(t)
-
- err := provider.Present("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUp(t *testing.T) {
- provider := mockBuilder().
- Route("DELETE /domains/example.com/delete-txt-record",
- servermock.ResponseFromInternal("delete_txt_record.json"),
- servermock.CheckQueryParameter().Strict().
- With("hostName", "_acme-challenge.example.com").
- With("txt", "ADw2sEd82DUgXcQ9hNBZThJs7zVJkR5v9JeSbAb9mZY")).
- Build(t)
-
- err := provider.CleanUp("example.com", "abc", "123d==")
- require.NoError(t, err)
-}
diff --git a/providers/dns/websupport/websupport.go b/providers/dns/websupport/websupport.go
index 4187ba32b..aa3c93578 100644
--- a/providers/dns/websupport/websupport.go
+++ b/providers/dns/websupport/websupport.go
@@ -2,12 +2,13 @@
package websupport
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "strconv"
"time"
- "github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
"github.com/go-acme/lego/v4/providers/dns/internal/active24"
@@ -29,7 +30,15 @@ const (
)
// Config is used to configure the creation of the DNSProvider.
-type Config = active24.Config
+type Config struct {
+ APIKey string
+ Secret string
+
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
@@ -45,7 +54,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *active24.Client
}
// NewDNSProvider returns a DNSProvider instance configured for Websupport.
@@ -69,29 +79,81 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("websupport: the configuration of the DNS provider is nil")
}
- provider, err := active24.NewDNSProviderConfig(config, baseAPIDomain)
+ client, err := active24.NewClient(baseAPIDomain, config.APIKey, config.Secret)
if err != nil {
return nil, fmt.Errorf("websupport: %w", err)
}
- return &DNSProvider{prv: provider}, nil
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{
+ config: config,
+ client: client,
+ }, nil
}
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+ ctx := context.Background()
+
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("websupport: could not find zone for domain %q: %w", domain, err)
+ }
+
+ subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
return fmt.Errorf("websupport: %w", err)
}
+ serviceID, err := d.findServiceID(ctx, dns01.UnFqdn(authZone))
+ if err != nil {
+ return fmt.Errorf("websupport: find service ID: %w", err)
+ }
+
+ record := active24.Record{
+ Type: "TXT",
+ Name: subDomain,
+ Content: info.Value,
+ TTL: d.config.TTL,
+ }
+
+ err = d.client.CreateRecord(ctx, strconv.Itoa(serviceID), record)
+ if err != nil {
+ return fmt.Errorf("websupport: create record: %w", err)
+ }
+
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+ ctx := context.Background()
+
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil {
- return fmt.Errorf("websupport: %w", err)
+ return fmt.Errorf("websupport: could not find zone for domain %q: %w", domain, err)
+ }
+
+ serviceID, err := d.findServiceID(ctx, dns01.UnFqdn(authZone))
+ if err != nil {
+ return fmt.Errorf("websupport: find service ID: %w", err)
+ }
+
+ recordID, err := d.findRecordID(ctx, strconv.Itoa(serviceID), info)
+ if err != nil {
+ return fmt.Errorf("websupport: find record ID: %w", err)
+ }
+
+ err = d.client.DeleteRecord(ctx, strconv.Itoa(serviceID), strconv.Itoa(recordID))
+ if err != nil {
+ return fmt.Errorf("websupport: delete record %w", err)
}
return nil
@@ -100,5 +162,58 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+ return d.config.PropagationTimeout, d.config.PollingInterval
+}
+
+func (d *DNSProvider) findServiceID(ctx context.Context, domain string) (int, error) {
+ services, err := d.client.GetServices(ctx)
+ if err != nil {
+ return 0, fmt.Errorf("get services: %w", err)
+ }
+
+ for _, service := range services {
+ if service.ServiceName != "domain" {
+ continue
+ }
+
+ if service.Name != domain {
+ continue
+ }
+
+ return service.ID, nil
+ }
+
+ return 0, fmt.Errorf("service not found for domain: %s", domain)
+}
+
+func (d *DNSProvider) findRecordID(ctx context.Context, serviceID string, info dns01.ChallengeInfo) (int, error) {
+ // NOTE(ldez): Despite the API documentation, the filter doesn't seem to work.
+ filter := active24.RecordFilter{
+ Name: dns01.UnFqdn(info.EffectiveFQDN),
+ Type: []string{"TXT"},
+ Content: info.Value,
+ }
+
+ records, err := d.client.GetRecords(ctx, serviceID, filter)
+ if err != nil {
+ return 0, fmt.Errorf("get records: %w", err)
+ }
+
+ for _, record := range records {
+ if record.Type != "TXT" {
+ continue
+ }
+
+ if record.Name != dns01.UnFqdn(info.EffectiveFQDN) {
+ continue
+ }
+
+ if record.Content != info.Value {
+ continue
+ }
+
+ return record.ID, nil
+ }
+
+ return 0, errors.New("no record found")
}
diff --git a/providers/dns/websupport/websupport.toml b/providers/dns/websupport/websupport.toml
index 4908f0235..1f34b431b 100644
--- a/providers/dns/websupport/websupport.toml
+++ b/providers/dns/websupport/websupport.toml
@@ -7,7 +7,7 @@ Since = "v4.10.0"
Example = '''
WEBSUPPORT_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
WEBSUPPORT_SECRET="yyyyyyyyyyyyyyyyyyyyy" \
-lego --dns websupport -d '*.example.com' -d example.com run
+lego --email you@example.com --dns websupport -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/websupport/websupport_test.go b/providers/dns/websupport/websupport_test.go
index 196c9bab8..051fdb837 100644
--- a/providers/dns/websupport/websupport_test.go
+++ b/providers/dns/websupport/websupport_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -60,7 +59,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -109,7 +109,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -123,7 +124,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +137,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/wedos/internal/client.go b/providers/dns/wedos/internal/client.go
index 48c89d189..1f573e397 100644
--- a/providers/dns/wedos/internal/client.go
+++ b/providers/dns/wedos/internal/client.go
@@ -69,7 +69,6 @@ func (c *Client) AddRecord(ctx context.Context, zone string, record DNSRow) erro
}
cmd := commandDNSRowAdd
-
if record.ID == "" {
payload.Name = record.Name
} else {
diff --git a/providers/dns/wedos/internal/token.go b/providers/dns/wedos/internal/token.go
index 11e680cb8..dd126b442 100644
--- a/providers/dns/wedos/internal/token.go
+++ b/providers/dns/wedos/internal/token.go
@@ -15,7 +15,6 @@ func authToken(userName, wapiPass string) string {
func sha1string(txt string) string {
h := sha1.New()
_, _ = io.WriteString(h, txt)
-
return hex.EncodeToString(h.Sum(nil))
}
@@ -47,13 +46,11 @@ func utcToCet(utc time.Time) time.Time {
if utcMonth < time.March || utcMonth > time.October {
return utc.Add(time.Hour)
}
-
if utcMonth > time.March && utcMonth < time.October {
return utc.Add(time.Hour * 2)
}
dayOff := 0
-
breaking := time.Date(utc.Year(), utcMonth+1, dayOff, 1, 0, 0, 0, time.UTC)
for breaking.Weekday() != time.Sunday {
dayOff--
@@ -68,7 +65,6 @@ func utcToCet(utc time.Time) time.Time {
if (utcMonth == time.March && utc.Before(breaking)) || (utcMonth == time.October && utc.After(breaking)) {
return utc.Add(time.Hour)
}
-
return utc.Add(time.Hour * 2)
}
diff --git a/providers/dns/wedos/wedos.go b/providers/dns/wedos/wedos.go
index 164fb5f10..85187ec46 100644
--- a/providers/dns/wedos/wedos.go
+++ b/providers/dns/wedos/wedos.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/wedos/internal"
)
@@ -95,8 +94,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{config: config, client: client}, nil
}
diff --git a/providers/dns/wedos/wedos.toml b/providers/dns/wedos/wedos.toml
index 89abfc16c..2ed351a2d 100644
--- a/providers/dns/wedos/wedos.toml
+++ b/providers/dns/wedos/wedos.toml
@@ -7,7 +7,7 @@ Since = "v4.4.0"
Example = '''
WEDOS_USERNAME=xxxxxxxx \
WEDOS_WAPI_PASSWORD=xxxxxxxx \
-lego --dns wedos -d '*.example.com' -d example.com run
+lego --email you@example.com --dns wedos -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/wedos/wedos_test.go b/providers/dns/wedos/wedos_test.go
index 25f70d0fc..9363002b5 100644
--- a/providers/dns/wedos/wedos_test.go
+++ b/providers/dns/wedos/wedos_test.go
@@ -54,7 +54,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -121,7 +120,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -135,7 +133,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/internal/westcn/internal/client.go b/providers/dns/westcn/internal/client.go
similarity index 96%
rename from providers/dns/internal/westcn/internal/client.go
rename to providers/dns/westcn/internal/client.go
index 621c7865f..4d967f5e1 100644
--- a/providers/dns/internal/westcn/internal/client.go
+++ b/providers/dns/westcn/internal/client.go
@@ -14,8 +14,8 @@ import (
"strings"
"time"
- "github.com/go-acme/lego/v4/providers/dns/internal/errutils"
querystring "github.com/google/go-querystring/query"
+ "github.com/nrdcg/mailinabox/errutils"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
@@ -30,7 +30,7 @@ type Client struct {
encoder *encoding.Encoder
- BaseURL *url.URL
+ baseURL *url.URL
HTTPClient *http.Client
}
@@ -46,7 +46,7 @@ func NewClient(username, password string) (*Client, error) {
username: username,
password: password,
encoder: simplifiedchinese.GBK.NewEncoder(),
- BaseURL: baseURL,
+ baseURL: baseURL,
HTTPClient: &http.Client{Timeout: 10 * time.Second},
}, nil
}
@@ -116,7 +116,7 @@ func (c *Client) newRequest(ctx context.Context, p, act string, form url.Values)
return nil, err
}
- endpoint := c.BaseURL.JoinPath(p, "/")
+ endpoint := c.baseURL.JoinPath(p, "/")
query := endpoint.Query()
query.Set("act", act)
diff --git a/providers/dns/internal/westcn/internal/client_test.go b/providers/dns/westcn/internal/client_test.go
similarity index 98%
rename from providers/dns/internal/westcn/internal/client_test.go
rename to providers/dns/westcn/internal/client_test.go
index 53fd6ed8f..f7bdac5c0 100644
--- a/providers/dns/internal/westcn/internal/client_test.go
+++ b/providers/dns/westcn/internal/client_test.go
@@ -21,7 +21,7 @@ func mockBuilder() *servermock.Builder[*Client] {
}
client.HTTPClient = server.Client()
- client.BaseURL, _ = url.Parse(server.URL)
+ client.baseURL, _ = url.Parse(server.URL)
return client, nil
},
@@ -69,8 +69,7 @@ func TestClientAddRecord_error(t *testing.T) {
servermock.ResponseFromFixture("error.json").
WithHeader("Content-Type", "application/json", "Charset=gb2312"),
servermock.CheckQueryParameter().Strict().
- With("act", "adddnsrecord"),
- ).
+ With("act", "adddnsrecord")).
Build(t)
record := Record{
diff --git a/providers/dns/internal/westcn/internal/fixtures/adddnsrecord.json b/providers/dns/westcn/internal/fixtures/adddnsrecord.json
similarity index 100%
rename from providers/dns/internal/westcn/internal/fixtures/adddnsrecord.json
rename to providers/dns/westcn/internal/fixtures/adddnsrecord.json
diff --git a/providers/dns/internal/westcn/internal/fixtures/deldnsrecord.json b/providers/dns/westcn/internal/fixtures/deldnsrecord.json
similarity index 100%
rename from providers/dns/internal/westcn/internal/fixtures/deldnsrecord.json
rename to providers/dns/westcn/internal/fixtures/deldnsrecord.json
diff --git a/providers/dns/internal/westcn/internal/fixtures/error.json b/providers/dns/westcn/internal/fixtures/error.json
similarity index 100%
rename from providers/dns/internal/westcn/internal/fixtures/error.json
rename to providers/dns/westcn/internal/fixtures/error.json
diff --git a/providers/dns/internal/westcn/internal/types.go b/providers/dns/westcn/internal/types.go
similarity index 100%
rename from providers/dns/internal/westcn/internal/types.go
rename to providers/dns/westcn/internal/types.go
diff --git a/providers/dns/westcn/westcn.go b/providers/dns/westcn/westcn.go
index 1906f9737..37f357b70 100644
--- a/providers/dns/westcn/westcn.go
+++ b/providers/dns/westcn/westcn.go
@@ -2,14 +2,17 @@
package westcn
import (
+ "context"
"errors"
"fmt"
"net/http"
+ "sync"
"time"
"github.com/go-acme/lego/v4/challenge"
+ "github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/westcn"
+ "github.com/go-acme/lego/v4/providers/dns/westcn/internal"
)
// Environment variables names.
@@ -25,12 +28,18 @@ const (
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
-const defaultBaseURL = "https://api.west.cn/api/v2"
-
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
-type Config = westcn.Config
+type Config struct {
+ Username string
+ Password string
+
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
@@ -46,7 +55,11 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *internal.Client
+
+ recordIDs map[string]int
+ recordIDsMu sync.Mutex
}
// NewDNSProvider returns a DNSProvider instance configured for West.cn/西部数码.
@@ -69,36 +82,88 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("westcn: the configuration of the DNS provider is nil")
}
- provider, err := westcn.NewDNSProviderConfig(config, defaultBaseURL)
+ client, err := internal.NewClient(config.Username, config.Password)
if err != nil {
return nil, fmt.Errorf("westcn: %w", err)
}
- return &DNSProvider{prv: provider}, nil
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{
+ config: config,
+ client: client,
+ recordIDs: make(map[string]int),
+ }, nil
}
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
+ if err != nil {
+ return fmt.Errorf("westcn: could not find zone for domain %q: %w", domain, err)
+ }
+
+ subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
if err != nil {
return fmt.Errorf("westcn: %w", err)
}
+ record := internal.Record{
+ Domain: dns01.UnFqdn(authZone),
+ Host: subDomain,
+ Type: "TXT",
+ Value: info.Value,
+ TTL: d.config.TTL,
+ }
+
+ recordID, err := d.client.AddRecord(context.Background(), record)
+ if err != nil {
+ return fmt.Errorf("westcn: add record: %w", err)
+ }
+
+ d.recordIDsMu.Lock()
+ d.recordIDs[token] = recordID
+ d.recordIDsMu.Unlock()
+
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
if err != nil {
- return fmt.Errorf("westcn: %w", err)
+ return fmt.Errorf("westcn: could not find zone for domain %q: %w", domain, err)
}
+ // gets the record's unique ID
+ d.recordIDsMu.Lock()
+ recordID, ok := d.recordIDs[token]
+ d.recordIDsMu.Unlock()
+ if !ok {
+ return fmt.Errorf("westcn: unknown record ID for '%s' '%s'", info.EffectiveFQDN, token)
+ }
+
+ err = d.client.DeleteRecord(context.Background(), dns01.UnFqdn(authZone), recordID)
+ if err != nil {
+ return fmt.Errorf("westcn: delete record: %w", err)
+ }
+
+ // deletes record ID from map
+ d.recordIDsMu.Lock()
+ delete(d.recordIDs, token)
+ d.recordIDsMu.Unlock()
+
return nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
+ return d.config.PropagationTimeout, d.config.PollingInterval
}
diff --git a/providers/dns/westcn/westcn.toml b/providers/dns/westcn/westcn.toml
index 1b0cb0a7a..acf3a4e49 100644
--- a/providers/dns/westcn/westcn.toml
+++ b/providers/dns/westcn/westcn.toml
@@ -7,7 +7,7 @@ Since = "v4.21.0"
Example = '''
WESTCN_USERNAME="xxx" \
WESTCN_PASSWORD="yyy" \
-lego --dns westcn -d '*.example.com' -d example.com run
+lego --email you@example.com --dns westcn -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/westcn/westcn_test.go b/providers/dns/westcn/westcn_test.go
index a546d518e..71632d99f 100644
--- a/providers/dns/westcn/westcn_test.go
+++ b/providers/dns/westcn/westcn_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -60,7 +59,8 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -107,7 +107,8 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
+ require.NotNil(t, p.client)
} else {
require.EqualError(t, err, test.expected)
}
@@ -121,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -135,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/yandex/internal/client.go b/providers/dns/yandex/internal/client.go
index 4b0421f49..98480a793 100644
--- a/providers/dns/yandex/internal/client.go
+++ b/providers/dns/yandex/internal/client.go
@@ -51,7 +51,6 @@ func (c *Client) AddRecord(ctx context.Context, payload Record) (*Record, error)
}
r := AddResponse{}
-
err = c.do(req, &r)
if err != nil {
return nil, err
@@ -69,7 +68,6 @@ func (c *Client) RemoveRecord(ctx context.Context, payload Record) (int, error)
}
r := RemoveResponse{}
-
err = c.do(req, &r)
if err != nil {
return 0, err
@@ -91,7 +89,6 @@ func (c *Client) GetRecords(ctx context.Context, domain string) ([]Record, error
}
r := ListResponse{}
-
err = c.do(req, &r)
if err != nil {
return nil, err
diff --git a/providers/dns/yandex/internal/types.go b/providers/dns/yandex/internal/types.go
index 48a85042c..ed1873cef 100644
--- a/providers/dns/yandex/internal/types.go
+++ b/providers/dns/yandex/internal/types.go
@@ -30,21 +30,18 @@ func (r BaseResponse) GetError() string {
type AddResponse struct {
BaseResponse
-
Domain string `json:"domain,omitempty"`
Record *Record `json:"record,omitempty"`
}
type RemoveResponse struct {
BaseResponse
-
Domain string `json:"domain,omitempty"`
RecordID int `json:"record_id,omitempty"`
}
type ListResponse struct {
BaseResponse
-
Domain string `json:"domain,omitempty"`
Records []Record `json:"records,omitempty"`
}
diff --git a/providers/dns/yandex/yandex.go b/providers/dns/yandex/yandex.go
index 7ae505ec0..c51602f67 100644
--- a/providers/dns/yandex/yandex.go
+++ b/providers/dns/yandex/yandex.go
@@ -11,7 +11,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/yandex/internal"
"github.com/miekg/dns"
)
@@ -89,8 +88,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{client: client, config: config}, nil
}
@@ -136,7 +133,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var record *internal.Record
-
for _, rcd := range records {
if rcd.Type == "TXT" && rcd.SubDomain == subDomain && rcd.Content == info.Value {
record = &rcd
@@ -157,7 +153,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("yandex: %w", err)
}
-
return nil
}
diff --git a/providers/dns/yandex/yandex.toml b/providers/dns/yandex/yandex.toml
index a36df069e..78da1444d 100644
--- a/providers/dns/yandex/yandex.toml
+++ b/providers/dns/yandex/yandex.toml
@@ -7,7 +7,7 @@ Since = "v3.7.0"
Example = '''
YANDEX_PDD_TOKEN= \
-lego --dns yandex -d '*.example.com' -d example.com run
+lego --email you@example.com --dns yandex -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/yandex/yandex_test.go b/providers/dns/yandex/yandex_test.go
index 8a0a7534a..144a24126 100644
--- a/providers/dns/yandex/yandex_test.go
+++ b/providers/dns/yandex/yandex_test.go
@@ -33,7 +33,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -96,7 +95,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -110,7 +108,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/yandex360/internal/client.go b/providers/dns/yandex360/internal/client.go
index 33aeb0daa..9ffececaf 100644
--- a/providers/dns/yandex360/internal/client.go
+++ b/providers/dns/yandex360/internal/client.go
@@ -138,7 +138,6 @@ func parseError(req *http.Request, resp *http.Response) error {
raw, _ := io.ReadAll(resp.Body)
var apiErr APIError
-
err := json.Unmarshal(raw, &apiErr)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/yandex360/yandex360.go b/providers/dns/yandex360/yandex360.go
index 0f4571750..e2ee7beb2 100644
--- a/providers/dns/yandex360/yandex360.go
+++ b/providers/dns/yandex360/yandex360.go
@@ -13,9 +13,7 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/yandex360/internal"
- "github.com/miekg/dns"
)
// Environment variables names.
@@ -99,8 +97,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
client: client,
config: config,
@@ -112,7 +108,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
- authZone, err := dns01.FindZoneByFqdn(dns.Fqdn(info.EffectiveFQDN))
+ authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(info.EffectiveFQDN))
if err != nil {
return fmt.Errorf("yandex360: could not find zone for domain %q: %w", domain, err)
}
@@ -147,7 +143,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
info := dns01.GetChallengeInfo(domain, keyAuth)
- authZone, err := dns01.FindZoneByFqdn(dns.Fqdn(info.EffectiveFQDN))
+ authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(info.EffectiveFQDN))
if err != nil {
return fmt.Errorf("yandex360: could not find zone for domain %q: %w", domain, err)
}
diff --git a/providers/dns/yandex360/yandex360.toml b/providers/dns/yandex360/yandex360.toml
index 444b1cc38..69ea02a28 100644
--- a/providers/dns/yandex360/yandex360.toml
+++ b/providers/dns/yandex360/yandex360.toml
@@ -8,7 +8,7 @@ Since = "v4.14.0"
Example = '''
YANDEX360_OAUTH_TOKEN= \
YANDEX360_ORG_ID= \
-lego --dns yandex360 -d '*.example.com' -d example.com run
+lego --email you@example.com --dns yandex360 -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/yandex360/yandex360_test.go b/providers/dns/yandex360/yandex360_test.go
index c1d37ad12..545c90985 100644
--- a/providers/dns/yandex360/yandex360_test.go
+++ b/providers/dns/yandex360/yandex360_test.go
@@ -43,7 +43,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -110,7 +109,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -124,7 +122,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/yandexcloud/yandexcloud.go b/providers/dns/yandexcloud/yandexcloud.go
index f9c64def1..346b6d952 100644
--- a/providers/dns/yandexcloud/yandexcloud.go
+++ b/providers/dns/yandexcloud/yandexcloud.go
@@ -229,7 +229,6 @@ func (d *DNSProvider) upsertRecordSetData(ctx context.Context, zoneID, name, val
}
var deletions []*ycdnsproto.RecordSet
-
if exist != nil {
record.SetData(append(record.GetData(), exist.GetData()...))
deletions = append(deletions, exist)
@@ -308,7 +307,6 @@ func decodeCredentials(accountB64 string) (credentials.Credentials, error) {
}
key := &iamkey.Key{}
-
err = json.Unmarshal(account, key)
if err != nil {
return nil, err
diff --git a/providers/dns/yandexcloud/yandexcloud.toml b/providers/dns/yandexcloud/yandexcloud.toml
index d4b40bb1d..a4bf3ebbb 100644
--- a/providers/dns/yandexcloud/yandexcloud.toml
+++ b/providers/dns/yandexcloud/yandexcloud.toml
@@ -7,7 +7,7 @@ Since = "v4.9.0"
Example = '''
YANDEX_CLOUD_IAM_TOKEN= \
YANDEX_CLOUD_FOLDER_ID= \
-lego --dns yandexcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns yandexcloud -d '*.example.com' -d example.com run
# ---
@@ -20,7 +20,7 @@ YANDEX_CLOUD_IAM_TOKEN=$(echo '{ \
"private_key": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----" \
}' | base64) \
YANDEX_CLOUD_FOLDER_ID= \
-lego --dns yandexcloud -d '*.example.com' -d example.com run
+lego --email you@example.com --dns yandexcloud -d '*.example.com' -d example.com run
'''
Additional = '''
diff --git a/providers/dns/yandexcloud/yandexcloud_test.go b/providers/dns/yandexcloud/yandexcloud_test.go
index 52dad574d..48f75d134 100644
--- a/providers/dns/yandexcloud/yandexcloud_test.go
+++ b/providers/dns/yandexcloud/yandexcloud_test.go
@@ -71,7 +71,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -144,7 +143,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -158,7 +156,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/zoneedit/internal/client.go b/providers/dns/zoneedit/internal/client.go
index c8b99e173..e97f4beb9 100644
--- a/providers/dns/zoneedit/internal/client.go
+++ b/providers/dns/zoneedit/internal/client.go
@@ -98,7 +98,6 @@ func (c *Client) do(req *http.Request) error {
}
var apiErr APIError
-
err = xml.Unmarshal(raw, &apiErr)
if err != nil {
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
diff --git a/providers/dns/zoneedit/zoneedit.go b/providers/dns/zoneedit/zoneedit.go
index c815f975a..875b84233 100644
--- a/providers/dns/zoneedit/zoneedit.go
+++ b/providers/dns/zoneedit/zoneedit.go
@@ -9,7 +9,6 @@ import (
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/zoneedit/internal"
)
@@ -81,8 +80,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client.HTTPClient = config.HTTPClient
}
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
return &DNSProvider{
config: config,
client: client,
diff --git a/providers/dns/zoneedit/zoneedit.toml b/providers/dns/zoneedit/zoneedit.toml
index cdc53b33a..d3c547c23 100644
--- a/providers/dns/zoneedit/zoneedit.toml
+++ b/providers/dns/zoneedit/zoneedit.toml
@@ -7,7 +7,7 @@ Since = "v4.25.0"
Example = '''
ZONEEDIT_USER="xxxxxxxxxxxxxxxxxxxxx" \
ZONEEDIT_AUTH_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
-lego --dns zoneedit -d '*.example.com' -d example.com run
+lego --email you@example.com --dns zoneedit -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/zoneedit/zoneedit_test.go b/providers/dns/zoneedit/zoneedit_test.go
index 0b251fddf..2a9b1754d 100644
--- a/providers/dns/zoneedit/zoneedit_test.go
+++ b/providers/dns/zoneedit/zoneedit_test.go
@@ -50,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -123,7 +122,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -137,7 +135,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/zoneee/zoneee.go b/providers/dns/zoneee/zoneee.go
index 5c34ea1c9..7dbbc4314 100644
--- a/providers/dns/zoneee/zoneee.go
+++ b/providers/dns/zoneee/zoneee.go
@@ -12,7 +12,6 @@ import (
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
- "github.com/go-acme/lego/v4/providers/dns/internal/clientdebug"
"github.com/go-acme/lego/v4/providers/dns/zoneee/internal"
)
@@ -70,7 +69,6 @@ func NewDNSProvider() (*DNSProvider, error) {
}
rawEndpoint := env.GetOrDefaultString(EnvEndpoint, internal.DefaultEndpoint)
-
endpoint, err := url.Parse(rawEndpoint)
if err != nil {
return nil, fmt.Errorf("zoneee: %w", err)
@@ -107,9 +105,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config.HTTPClient != nil {
client.HTTPClient = config.HTTPClient
}
-
- client.HTTPClient = clientdebug.Wrap(client.HTTPClient)
-
if config.Endpoint != nil {
client.BaseURL = config.Endpoint
}
@@ -143,7 +138,6 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("zoneee: %w", err)
}
-
return nil
}
@@ -166,7 +160,6 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
var id string
-
for _, record := range records {
if record.Destination == info.Value {
id = record.ID
diff --git a/providers/dns/zoneee/zoneee.toml b/providers/dns/zoneee/zoneee.toml
index ab7133180..75ccabbda 100644
--- a/providers/dns/zoneee/zoneee.toml
+++ b/providers/dns/zoneee/zoneee.toml
@@ -7,7 +7,7 @@ Since = "v2.1.0"
Example = '''
ZONEEE_API_USER=xxxxx \
ZONEEE_API_KEY=yyyyy \
-lego --dns zoneee -d '*.example.com' -d example.com run
+lego --email you@example.com --dns zoneee -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/zoneee/zoneee_test.go b/providers/dns/zoneee/zoneee_test.go
index 9ad87c02a..6f50cf36e 100644
--- a/providers/dns/zoneee/zoneee_test.go
+++ b/providers/dns/zoneee/zoneee_test.go
@@ -77,7 +77,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -248,7 +247,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -262,7 +260,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -276,7 +273,6 @@ func mockBuilder(username, apiKey string) *servermock.Builder[*DNSProvider] {
return servermock.NewBuilder(
func(server *httptest.Server) (*DNSProvider, error) {
config := NewDefaultConfig()
- config.HTTPClient = server.Client()
config.Endpoint, _ = url.Parse(server.URL)
config.Username = username
config.APIKey = apiKey
@@ -289,7 +285,6 @@ func mockBuilder(username, apiKey string) *servermock.Builder[*DNSProvider] {
func mockHandlerCreateRecord() http.HandlerFunc {
return encodeJSONHandler(func(req *http.Request, rw http.ResponseWriter) (any, error) {
record := internal.TXTRecord{}
-
err := json.NewDecoder(req.Body).Decode(&record)
if err != nil {
return nil, err
@@ -344,7 +339,6 @@ func checkBasicAuth() servermock.LinkFunc {
if username != fakeUsername || apiKey != fakeAPIKey || !ok {
rw.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm=%q`, "Please enter your username and API key."))
http.Error(rw, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
-
return
}
diff --git a/providers/dns/zonomi/zonomi.go b/providers/dns/zonomi/zonomi.go
index fe54b80fc..8c7a2943f 100644
--- a/providers/dns/zonomi/zonomi.go
+++ b/providers/dns/zonomi/zonomi.go
@@ -2,6 +2,7 @@
package zonomi
import (
+ "context"
"errors"
"fmt"
"net/http"
@@ -25,17 +26,22 @@ const (
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
)
-const defaultBaseURL = "https://zonomi.com/app/dns/dyndns.jsp"
-
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
// Config is used to configure the creation of the DNSProvider.
-type Config = rimuhosting.Config
+type Config struct {
+ APIKey string
+
+ PropagationTimeout time.Duration
+ PollingInterval time.Duration
+ TTL int
+ HTTPClient *http.Client
+}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
- TTL: env.GetOrDefaultInt(EnvTTL, rimuhosting.DefaultTTL),
+ TTL: env.GetOrDefaultInt(EnvTTL, 3600),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPClient: &http.Client{
@@ -46,7 +52,8 @@ func NewDefaultConfig() *Config {
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
- prv challenge.ProviderTimeout
+ config *Config
+ client *rimuhosting.Client
}
// NewDNSProvider returns a DNSProvider instance configured for Zonomi.
@@ -69,19 +76,48 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("zonomi: the configuration of the DNS provider is nil")
}
- provider, err := rimuhosting.NewDNSProviderConfig(config, defaultBaseURL)
- if err != nil {
- return nil, fmt.Errorf("zonomi: %w", err)
+ if config.APIKey == "" {
+ return nil, errors.New("zonomi: incomplete credentials, missing API key")
}
- return &DNSProvider{prv: provider}, nil
+ client := rimuhosting.NewClient(config.APIKey)
+ client.BaseURL = rimuhosting.DefaultZonomiBaseURL
+
+ if config.HTTPClient != nil {
+ client.HTTPClient = config.HTTPClient
+ }
+
+ return &DNSProvider{config: config, client: client}, nil
+}
+
+// Timeout returns the timeout and interval to use when checking for DNS propagation.
+// Adjusting here to cope with spikes in propagation times.
+func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
+ return d.config.PropagationTimeout, d.config.PollingInterval
}
// Present creates a TXT record using the specified parameters.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
- err := d.prv.Present(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ ctx := context.Background()
+
+ records, err := d.client.FindTXTRecords(ctx, dns01.UnFqdn(info.EffectiveFQDN))
if err != nil {
- return fmt.Errorf("zonomi: %w", err)
+ return fmt.Errorf("zonomi: failed to find record(s) for %s: %w", domain, err)
+ }
+
+ actions := []rimuhosting.ActionParameter{
+ rimuhosting.NewAddRecordAction(dns01.UnFqdn(info.EffectiveFQDN), info.Value, d.config.TTL),
+ }
+
+ for _, record := range records {
+ actions = append(actions, rimuhosting.NewAddRecordAction(record.Name, record.Content, d.config.TTL))
+ }
+
+ _, err = d.client.DoActions(ctx, actions...)
+ if err != nil {
+ return fmt.Errorf("zonomi: failed to add record(s) for %s: %w", domain, err)
}
return nil
@@ -89,16 +125,14 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
- err := d.prv.CleanUp(domain, token, keyAuth)
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+
+ action := rimuhosting.NewDeleteRecordAction(dns01.UnFqdn(info.EffectiveFQDN), info.Value)
+
+ _, err := d.client.DoActions(context.Background(), action)
if err != nil {
- return fmt.Errorf("zonomi: %w", err)
+ return fmt.Errorf("zonomi: failed to delete record for %s: %w", domain, err)
}
return nil
}
-
-// Timeout returns the timeout and interval to use when checking for DNS propagation.
-// Adjusting here to cope with spikes in propagation times.
-func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
- return d.prv.Timeout()
-}
diff --git a/providers/dns/zonomi/zonomi.toml b/providers/dns/zonomi/zonomi.toml
index b91bcaac6..a5577999a 100644
--- a/providers/dns/zonomi/zonomi.toml
+++ b/providers/dns/zonomi/zonomi.toml
@@ -6,7 +6,7 @@ Since = "v3.5.0"
Example = '''
ZONOMI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
-lego --dns zonomi -d '*.example.com' -d example.com run
+lego --email you@example.com --dns zonomi -d '*.example.com' -d example.com run
'''
[Configuration]
diff --git a/providers/dns/zonomi/zonomi_test.go b/providers/dns/zonomi/zonomi_test.go
index 2e13e937e..fb1b68773 100644
--- a/providers/dns/zonomi/zonomi_test.go
+++ b/providers/dns/zonomi/zonomi_test.go
@@ -36,7 +36,6 @@ func TestNewDNSProvider(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
-
envTest.ClearEnv()
envTest.Apply(test.envVars)
@@ -46,7 +45,7 @@ func TestNewDNSProvider(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
} else {
require.EqualError(t, err, test.expected)
}
@@ -84,7 +83,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
- require.NotNil(t, p.prv)
+ require.NotNil(t, p.config)
} else {
require.EqualError(t, err, test.expected)
}
@@ -98,7 +97,6 @@ func TestLivePresent(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
@@ -112,7 +110,6 @@ func TestLiveCleanUp(t *testing.T) {
}
envTest.RestoreEnv()
-
provider, err := NewDNSProvider()
require.NoError(t, err)
diff --git a/providers/dns/zz_gen_dns_providers.go b/providers/dns/zz_gen_dns_providers.go
index 9c4bc9e61..59205f7f6 100644
--- a/providers/dns/zz_gen_dns_providers.go
+++ b/providers/dns/zz_gen_dns_providers.go
@@ -6,14 +6,11 @@ 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"
- "github.com/go-acme/lego/v4/providers/dns/aliesa"
"github.com/go-acme/lego/v4/providers/dns/allinkl"
- "github.com/go-acme/lego/v4/providers/dns/alwaysdata"
- "github.com/go-acme/lego/v4/providers/dns/anexia"
- "github.com/go-acme/lego/v4/providers/dns/artfiles"
"github.com/go-acme/lego/v4/providers/dns/arvancloud"
"github.com/go-acme/lego/v4/providers/dns/auroradns"
"github.com/go-acme/lego/v4/providers/dns/autodns"
@@ -22,11 +19,8 @@ import (
"github.com/go-acme/lego/v4/providers/dns/azure"
"github.com/go-acme/lego/v4/providers/dns/azuredns"
"github.com/go-acme/lego/v4/providers/dns/baiducloud"
- "github.com/go-acme/lego/v4/providers/dns/beget"
- "github.com/go-acme/lego/v4/providers/dns/binarylane"
"github.com/go-acme/lego/v4/providers/dns/bindman"
"github.com/go-acme/lego/v4/providers/dns/bluecat"
- "github.com/go-acme/lego/v4/providers/dns/bluecatv2"
"github.com/go-acme/lego/v4/providers/dns/bookmyname"
"github.com/go-acme/lego/v4/providers/dns/brandit"
"github.com/go-acme/lego/v4/providers/dns/bunny"
@@ -37,20 +31,16 @@ import (
"github.com/go-acme/lego/v4/providers/dns/cloudns"
"github.com/go-acme/lego/v4/providers/dns/cloudru"
"github.com/go-acme/lego/v4/providers/dns/cloudxns"
- "github.com/go-acme/lego/v4/providers/dns/com35"
"github.com/go-acme/lego/v4/providers/dns/conoha"
"github.com/go-acme/lego/v4/providers/dns/conohav3"
"github.com/go-acme/lego/v4/providers/dns/constellix"
"github.com/go-acme/lego/v4/providers/dns/corenetworks"
"github.com/go-acme/lego/v4/providers/dns/cpanel"
- "github.com/go-acme/lego/v4/providers/dns/czechia"
- "github.com/go-acme/lego/v4/providers/dns/ddnss"
"github.com/go-acme/lego/v4/providers/dns/derak"
"github.com/go-acme/lego/v4/providers/dns/desec"
"github.com/go-acme/lego/v4/providers/dns/designate"
"github.com/go-acme/lego/v4/providers/dns/digitalocean"
"github.com/go-acme/lego/v4/providers/dns/directadmin"
- "github.com/go-acme/lego/v4/providers/dns/dnsexit"
"github.com/go-acme/lego/v4/providers/dns/dnshomede"
"github.com/go-acme/lego/v4/providers/dns/dnsimple"
"github.com/go-acme/lego/v4/providers/dns/dnsmadeeasy"
@@ -63,13 +53,9 @@ import (
"github.com/go-acme/lego/v4/providers/dns/dyndnsfree"
"github.com/go-acme/lego/v4/providers/dns/dynu"
"github.com/go-acme/lego/v4/providers/dns/easydns"
- "github.com/go-acme/lego/v4/providers/dns/edgecenter"
"github.com/go-acme/lego/v4/providers/dns/edgedns"
- "github.com/go-acme/lego/v4/providers/dns/edgeone"
"github.com/go-acme/lego/v4/providers/dns/efficientip"
"github.com/go-acme/lego/v4/providers/dns/epik"
- "github.com/go-acme/lego/v4/providers/dns/eurodns"
- "github.com/go-acme/lego/v4/providers/dns/excedo"
"github.com/go-acme/lego/v4/providers/dns/exec"
"github.com/go-acme/lego/v4/providers/dns/exoscale"
"github.com/go-acme/lego/v4/providers/dns/f5xc"
@@ -78,15 +64,11 @@ import (
"github.com/go-acme/lego/v4/providers/dns/gandiv5"
"github.com/go-acme/lego/v4/providers/dns/gcloud"
"github.com/go-acme/lego/v4/providers/dns/gcore"
- "github.com/go-acme/lego/v4/providers/dns/gigahostno"
"github.com/go-acme/lego/v4/providers/dns/glesys"
"github.com/go-acme/lego/v4/providers/dns/godaddy"
"github.com/go-acme/lego/v4/providers/dns/googledomains"
- "github.com/go-acme/lego/v4/providers/dns/gravity"
"github.com/go-acme/lego/v4/providers/dns/hetzner"
"github.com/go-acme/lego/v4/providers/dns/hostingde"
- "github.com/go-acme/lego/v4/providers/dns/hostinger"
- "github.com/go-acme/lego/v4/providers/dns/hostingnl"
"github.com/go-acme/lego/v4/providers/dns/hosttech"
"github.com/go-acme/lego/v4/providers/dns/httpnet"
"github.com/go-acme/lego/v4/providers/dns/httpreq"
@@ -101,15 +83,9 @@ import (
"github.com/go-acme/lego/v4/providers/dns/internetbs"
"github.com/go-acme/lego/v4/providers/dns/inwx"
"github.com/go-acme/lego/v4/providers/dns/ionos"
- "github.com/go-acme/lego/v4/providers/dns/ionoscloud"
"github.com/go-acme/lego/v4/providers/dns/ipv64"
- "github.com/go-acme/lego/v4/providers/dns/ispconfig"
- "github.com/go-acme/lego/v4/providers/dns/ispconfigddns"
"github.com/go-acme/lego/v4/providers/dns/iwantmyname"
- "github.com/go-acme/lego/v4/providers/dns/jdcloud"
"github.com/go-acme/lego/v4/providers/dns/joker"
- "github.com/go-acme/lego/v4/providers/dns/keyhelp"
- "github.com/go-acme/lego/v4/providers/dns/leaseweb"
"github.com/go-acme/lego/v4/providers/dns/liara"
"github.com/go-acme/lego/v4/providers/dns/lightsail"
"github.com/go-acme/lego/v4/providers/dns/limacity"
@@ -119,7 +95,6 @@ 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"
@@ -130,9 +105,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/namecheap"
"github.com/go-acme/lego/v4/providers/dns/namedotcom"
"github.com/go-acme/lego/v4/providers/dns/namesilo"
- "github.com/go-acme/lego/v4/providers/dns/namesurfer"
"github.com/go-acme/lego/v4/providers/dns/nearlyfreespeech"
- "github.com/go-acme/lego/v4/providers/dns/neodigit"
"github.com/go-acme/lego/v4/providers/dns/netcup"
"github.com/go-acme/lego/v4/providers/dns/netlify"
"github.com/go-acme/lego/v4/providers/dns/nicmanager"
@@ -141,7 +114,6 @@ import (
"github.com/go-acme/lego/v4/providers/dns/njalla"
"github.com/go-acme/lego/v4/providers/dns/nodion"
"github.com/go-acme/lego/v4/providers/dns/ns1"
- "github.com/go-acme/lego/v4/providers/dns/octenium"
"github.com/go-acme/lego/v4/providers/dns/oraclecloud"
"github.com/go-acme/lego/v4/providers/dns/otc"
"github.com/go-acme/lego/v4/providers/dns/ovh"
@@ -168,26 +140,21 @@ import (
"github.com/go-acme/lego/v4/providers/dns/sonic"
"github.com/go-acme/lego/v4/providers/dns/spaceship"
"github.com/go-acme/lego/v4/providers/dns/stackpath"
- "github.com/go-acme/lego/v4/providers/dns/syse"
"github.com/go-acme/lego/v4/providers/dns/technitium"
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
"github.com/go-acme/lego/v4/providers/dns/timewebcloud"
- "github.com/go-acme/lego/v4/providers/dns/todaynic"
"github.com/go-acme/lego/v4/providers/dns/transip"
"github.com/go-acme/lego/v4/providers/dns/ultradns"
- "github.com/go-acme/lego/v4/providers/dns/uniteddomains"
"github.com/go-acme/lego/v4/providers/dns/variomedia"
"github.com/go-acme/lego/v4/providers/dns/vegadns"
"github.com/go-acme/lego/v4/providers/dns/vercel"
"github.com/go-acme/lego/v4/providers/dns/versio"
"github.com/go-acme/lego/v4/providers/dns/vinyldns"
- "github.com/go-acme/lego/v4/providers/dns/virtualname"
"github.com/go-acme/lego/v4/providers/dns/vkcloud"
"github.com/go-acme/lego/v4/providers/dns/volcengine"
"github.com/go-acme/lego/v4/providers/dns/vscale"
"github.com/go-acme/lego/v4/providers/dns/vultr"
"github.com/go-acme/lego/v4/providers/dns/webnames"
- "github.com/go-acme/lego/v4/providers/dns/webnamesca"
"github.com/go-acme/lego/v4/providers/dns/websupport"
"github.com/go-acme/lego/v4/providers/dns/wedos"
"github.com/go-acme/lego/v4/providers/dns/westcn"
@@ -202,22 +169,16 @@ 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":
return active24.NewDNSProvider()
case "alidns":
return alidns.NewDNSProvider()
- case "aliesa":
- return aliesa.NewDNSProvider()
case "allinkl":
return allinkl.NewDNSProvider()
- case "alwaysdata":
- return alwaysdata.NewDNSProvider()
- case "anexia":
- return anexia.NewDNSProvider()
- case "artfiles":
- return artfiles.NewDNSProvider()
case "arvancloud":
return arvancloud.NewDNSProvider()
case "auroradns":
@@ -234,16 +195,10 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return azuredns.NewDNSProvider()
case "baiducloud":
return baiducloud.NewDNSProvider()
- case "beget":
- return beget.NewDNSProvider()
- case "binarylane":
- return binarylane.NewDNSProvider()
case "bindman":
return bindman.NewDNSProvider()
case "bluecat":
return bluecat.NewDNSProvider()
- case "bluecatv2":
- return bluecatv2.NewDNSProvider()
case "bookmyname":
return bookmyname.NewDNSProvider()
case "brandit":
@@ -264,8 +219,6 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return cloudru.NewDNSProvider()
case "cloudxns":
return cloudxns.NewDNSProvider()
- case "com35":
- return com35.NewDNSProvider()
case "conoha":
return conoha.NewDNSProvider()
case "conohav3":
@@ -276,10 +229,6 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return corenetworks.NewDNSProvider()
case "cpanel":
return cpanel.NewDNSProvider()
- case "czechia":
- return czechia.NewDNSProvider()
- case "ddnss":
- return ddnss.NewDNSProvider()
case "derak":
return derak.NewDNSProvider()
case "desec":
@@ -290,8 +239,6 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return digitalocean.NewDNSProvider()
case "directadmin":
return directadmin.NewDNSProvider()
- case "dnsexit":
- return dnsexit.NewDNSProvider()
case "dnshomede":
return dnshomede.NewDNSProvider()
case "dnsimple":
@@ -316,20 +263,12 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return dynu.NewDNSProvider()
case "easydns":
return easydns.NewDNSProvider()
- case "edgecenter":
- return edgecenter.NewDNSProvider()
case "edgedns", "fastdns":
return edgedns.NewDNSProvider()
- case "edgeone":
- return edgeone.NewDNSProvider()
case "efficientip":
return efficientip.NewDNSProvider()
case "epik":
return epik.NewDNSProvider()
- case "eurodns":
- return eurodns.NewDNSProvider()
- case "excedo":
- return excedo.NewDNSProvider()
case "exec":
return exec.NewDNSProvider()
case "exoscale":
@@ -346,24 +285,16 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return gcloud.NewDNSProvider()
case "gcore":
return gcore.NewDNSProvider()
- case "gigahostno":
- return gigahostno.NewDNSProvider()
case "glesys":
return glesys.NewDNSProvider()
case "godaddy":
return godaddy.NewDNSProvider()
case "googledomains":
return googledomains.NewDNSProvider()
- case "gravity":
- return gravity.NewDNSProvider()
case "hetzner":
return hetzner.NewDNSProvider()
case "hostingde":
return hostingde.NewDNSProvider()
- case "hostinger":
- return hostinger.NewDNSProvider()
- case "hostingnl":
- return hostingnl.NewDNSProvider()
case "hosttech":
return hosttech.NewDNSProvider()
case "httpnet":
@@ -392,24 +323,12 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return inwx.NewDNSProvider()
case "ionos":
return ionos.NewDNSProvider()
- case "ionoscloud":
- return ionoscloud.NewDNSProvider()
case "ipv64":
return ipv64.NewDNSProvider()
- case "ispconfig":
- return ispconfig.NewDNSProvider()
- case "ispconfigddns":
- return ispconfigddns.NewDNSProvider()
case "iwantmyname":
return iwantmyname.NewDNSProvider()
- case "jdcloud":
- return jdcloud.NewDNSProvider()
case "joker":
return joker.NewDNSProvider()
- case "keyhelp":
- return keyhelp.NewDNSProvider()
- case "leaseweb":
- return leaseweb.NewDNSProvider()
case "liara":
return liara.NewDNSProvider()
case "lightsail":
@@ -428,8 +347,6 @@ 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":
@@ -450,12 +367,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return namedotcom.NewDNSProvider()
case "namesilo":
return namesilo.NewDNSProvider()
- case "namesurfer":
- return namesurfer.NewDNSProvider()
case "nearlyfreespeech":
return nearlyfreespeech.NewDNSProvider()
- case "neodigit":
- return neodigit.NewDNSProvider()
case "netcup":
return netcup.NewDNSProvider()
case "netlify":
@@ -472,8 +385,6 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return nodion.NewDNSProvider()
case "ns1":
return ns1.NewDNSProvider()
- case "octenium":
- return octenium.NewDNSProvider()
case "oraclecloud":
return oraclecloud.NewDNSProvider()
case "otc":
@@ -526,22 +437,16 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return spaceship.NewDNSProvider()
case "stackpath":
return stackpath.NewDNSProvider()
- case "syse":
- return syse.NewDNSProvider()
case "technitium":
return technitium.NewDNSProvider()
case "tencentcloud":
return tencentcloud.NewDNSProvider()
case "timewebcloud":
return timewebcloud.NewDNSProvider()
- case "todaynic":
- return todaynic.NewDNSProvider()
case "transip":
return transip.NewDNSProvider()
case "ultradns":
return ultradns.NewDNSProvider()
- case "uniteddomains":
- return uniteddomains.NewDNSProvider()
case "variomedia":
return variomedia.NewDNSProvider()
case "vegadns":
@@ -552,8 +457,6 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return versio.NewDNSProvider()
case "vinyldns":
return vinyldns.NewDNSProvider()
- case "virtualname":
- return virtualname.NewDNSProvider()
case "vkcloud":
return vkcloud.NewDNSProvider()
case "volcengine":
@@ -562,10 +465,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return vscale.NewDNSProvider()
case "vultr":
return vultr.NewDNSProvider()
- case "webnames", "webnamesru":
+ case "webnames":
return webnames.NewDNSProvider()
- case "webnamesca":
- return webnamesca.NewDNSProvider()
case "websupport":
return websupport.NewDNSProvider()
case "wedos":
diff --git a/providers/http/memcached/memcached.go b/providers/http/memcached/memcached.go
index 376ae8c16..b26def2c4 100644
--- a/providers/http/memcached/memcached.go
+++ b/providers/http/memcached/memcached.go
@@ -33,14 +33,12 @@ func (w *HTTPProvider) Present(domain, token, keyAuth string) error {
var errs []error
challengePath := path.Join("/", http01.ChallengePath(token))
-
for _, host := range w.hosts {
mc, err := memcache.New(host)
if err != nil {
errs = append(errs, err)
continue
}
-
_ = mc.Add(&memcache.Item{
Key: challengePath,
Value: []byte(keyAuth),
diff --git a/providers/http/memcached/memcached_test.go b/providers/http/memcached/memcached_test.go
index 5862efbc6..fb450f988 100644
--- a/providers/http/memcached/memcached_test.go
+++ b/providers/http/memcached/memcached_test.go
@@ -25,7 +25,6 @@ func loadMemcachedHosts() []string {
if memcachedHostsStr != "" {
return strings.Split(memcachedHostsStr, ",")
}
-
return nil
}
@@ -39,7 +38,6 @@ func TestNewMemcachedProviderValid(t *testing.T) {
if len(memcachedHosts) == 0 {
t.Skip("Skipping memcached tests")
}
-
_, err := NewMemcachedProvider(memcachedHosts)
require.NoError(t, err)
}
@@ -48,7 +46,6 @@ func TestMemcachedPresentSingleHost(t *testing.T) {
if len(memcachedHosts) == 0 {
t.Skip("Skipping memcached tests")
}
-
p, err := NewMemcachedProvider(memcachedHosts[0:1])
require.NoError(t, err)
@@ -67,7 +64,6 @@ func TestMemcachedPresentMultiHost(t *testing.T) {
if len(memcachedHosts) <= 1 {
t.Skip("Skipping memcached multi-host tests")
}
-
p, err := NewMemcachedProvider(memcachedHosts)
require.NoError(t, err)
@@ -75,7 +71,6 @@ func TestMemcachedPresentMultiHost(t *testing.T) {
err = p.Present(domain, token, keyAuth)
require.NoError(t, err)
-
for _, host := range memcachedHosts {
mc, err := memcache.New(host)
require.NoError(t, err)
@@ -89,7 +84,6 @@ func TestMemcachedPresentPartialFailureMultiHost(t *testing.T) {
if len(memcachedHosts) == 0 {
t.Skip("Skipping memcached tests")
}
-
hosts := append(memcachedHosts, "5.5.5.5:11211")
p, err := NewMemcachedProvider(hosts)
require.NoError(t, err)
@@ -98,7 +92,6 @@ func TestMemcachedPresentPartialFailureMultiHost(t *testing.T) {
err = p.Present(domain, token, keyAuth)
require.NoError(t, err)
-
for _, host := range memcachedHosts {
mc, err := memcache.New(host)
require.NoError(t, err)
@@ -112,7 +105,6 @@ func TestMemcachedCleanup(t *testing.T) {
if len(memcachedHosts) == 0 {
t.Skip("Skipping memcached tests")
}
-
p, err := NewMemcachedProvider(memcachedHosts)
require.NoError(t, err)
require.NoError(t, p.CleanUp(domain, token, keyAuth))
diff --git a/providers/http/s3/s3.go b/providers/http/s3/s3.go
index e277deeea..07e1eed63 100644
--- a/providers/http/s3/s3.go
+++ b/providers/http/s3/s3.go
@@ -57,7 +57,6 @@ func (s *HTTPProvider) Present(domain, token, keyAuth string) error {
if err != nil {
return fmt.Errorf("s3: failed to upload token to s3: %w", err)
}
-
return nil
}
diff --git a/providers/http/webroot/webroot.go b/providers/http/webroot/webroot.go
index c94c4579c..c5b49caee 100644
--- a/providers/http/webroot/webroot.go
+++ b/providers/http/webroot/webroot.go
@@ -29,7 +29,6 @@ func (w *HTTPProvider) Present(domain, token, keyAuth string) error {
var err error
challengeFilePath := filepath.Join(w.path, http01.ChallengePath(token))
-
err = os.MkdirAll(filepath.Dir(challengeFilePath), 0o755)
if err != nil {
return fmt.Errorf("could not create required directories in webroot for HTTP challenge: %w", err)
diff --git a/providers/http/webroot/webroot_test.go b/providers/http/webroot/webroot_test.go
index 4c55e2b90..124b324a3 100644
--- a/providers/http/webroot/webroot_test.go
+++ b/providers/http/webroot/webroot_test.go
@@ -29,7 +29,6 @@ func TestHTTPProvider(t *testing.T) {
}
var data []byte
-
data, err = os.ReadFile(challengeFilePath)
require.NoError(t, err)
diff --git a/registration/registar.go b/registration/registar.go
index 5d3ea250b..15c28bad6 100644
--- a/registration/registar.go
+++ b/registration/registar.go
@@ -15,7 +15,7 @@ const mailTo = "mailto:"
// of which the client needs to keep track itself.
// WARNING: will be removed in the future (acme.ExtendedAccount), https://github.com/go-acme/lego/issues/855.
type Resource struct {
- Body acme.Account `json:"body"`
+ Body acme.Account `json:"body,omitempty"`
URI string `json:"uri,omitempty"`
}
@@ -160,7 +160,6 @@ func (r *Registrar) ResolveAccountByKey() (*Resource, error) {
log.Infof("acme: Trying to resolve account by key")
accMsg := acme.Account{OnlyReturnExisting: true}
-
account, err := r.core.Accounts.New(accMsg)
if err != nil {
return nil, err
diff --git a/registration/registar_test.go b/registration/registar_test.go
index 43df1d648..45fe33e82 100644
--- a/registration/registar_test.go
+++ b/registration/registar_test.go
@@ -3,28 +3,29 @@ package registration
import (
"crypto/rand"
"crypto/rsa"
- "fmt"
"net/http"
"testing"
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/acme/api"
"github.com/go-acme/lego/v4/platform/tester"
- "github.com/go-acme/lego/v4/platform/tester/servermock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRegistrar_ResolveAccountByKey(t *testing.T) {
- server := tester.MockACMEServer().
- Route("/account",
- http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- rw.Header().Set("Location",
- fmt.Sprintf("http://%s/account", req.Context().Value(http.LocalAddrContextKey)))
+ mux, apiURL := tester.SetupFakeAPI(t)
- servermock.JSONEncode(acme.Account{Status: "valid"}).ServeHTTP(rw, req)
- })).
- BuildHTTPS(t)
+ mux.HandleFunc("/account", func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Location", apiURL+"/account")
+ err := tester.WriteJSONResponse(w, acme.Account{
+ Status: "valid",
+ })
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ })
key, err := rsa.GenerateKey(rand.Reader, 1024)
require.NoError(t, err, "Could not generate test key")
@@ -35,7 +36,7 @@ func TestRegistrar_ResolveAccountByKey(t *testing.T) {
privatekey: key,
}
- core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
+ core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
require.NoError(t, err)
registrar := NewRegistrar(core, user)