mirror of
https://github.com/go-acme/lego
synced 2024-06-03 02:32:12 +02:00
Compare commits
99 commits
Author | SHA1 | Date | |
---|---|---|---|
96bb0ba904 | |||
e508b664b3 | |||
8abe1008bb | |||
96a8381a6b | |||
4d7fcb6048 | |||
65e8940311 | |||
71b48f8217 | |||
942ba6f591 | |||
de6f9d26b1 | |||
f038102ef9 | |||
975c40a8bb | |||
d3d59c166e | |||
5eb87685e2 | |||
f89e257694 | |||
220c608c80 | |||
92bde4cd56 | |||
d39d57fbc9 | |||
bf10a46784 | |||
c61aeba3e2 | |||
11b4beff7e | |||
2ec9e42ee3 | |||
983c181e45 | |||
f6d1413a3f | |||
acd338259d | |||
42aa57e2b9 | |||
76eb1eac8a | |||
d60c335cc0 | |||
55dd478cb2 | |||
ca32b56550 | |||
8623f0df01 | |||
a832515ad5 | |||
ef9086a0f9 | |||
8dd1fa5a32 | |||
3371145f01 | |||
874e3ea023 | |||
27fd142ca1 | |||
61553c4195 | |||
441775ec65 | |||
40dcce60be | |||
19bbefbc8c | |||
719d26c0fc | |||
5bde3fbedd | |||
008adfddca | |||
6dd8d035d1 | |||
adea063bb1 | |||
82e9a5e2a9 | |||
6933296e2f | |||
a7ca3d7f1c | |||
9d0cd24533 | |||
fac40196c5 | |||
1106ad382f | |||
fd6047a1b8 | |||
ba67a265c0 | |||
7fe1796157 | |||
b9b0412f7c | |||
23824af555 | |||
c5a95c4cd0 | |||
83ff393131 | |||
719adc3964 | |||
6decaed8a3 | |||
ac6c0a5f63 | |||
1a3de70183 | |||
ec8306f4b5 | |||
46fe435c2c | |||
755d479e62 | |||
4eab81a9eb | |||
9c1a856b73 | |||
d263a28c64 | |||
ad6e38e7db | |||
3c73f624ba | |||
bb830677d1 | |||
7fd1704282 | |||
143aa4f3ee | |||
9d4c60e67a | |||
c17f659c5d | |||
c847ac4a4c | |||
3ba40ff7da | |||
68dc83ae0a | |||
e98dea02de | |||
6da922047a | |||
7186ebb6f1 | |||
5af3c6c042 | |||
cab8e1f556 | |||
d51b5e408b | |||
4f242c93e6 | |||
c9ff534e39 | |||
52990b3c9e | |||
8afdc9d01c | |||
2140e6befe | |||
bf8c7abf6d | |||
c2fd4498e5 | |||
b523518108 | |||
d0aa6b3c0d | |||
113648a368 | |||
766e581f8d | |||
a05e3832a1 | |||
a6ddcac65a | |||
5ef996ee05 | |||
8a7fd67c58 |
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
@ -1 +0,0 @@
|
|||
github: ldez
|
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -42,6 +42,7 @@ body:
|
|||
- Through Caddy
|
||||
- Through Terraform ACME provider
|
||||
- Through Bitnami
|
||||
- Through Zoraxy
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
|
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
@ -21,6 +21,7 @@ body:
|
|||
- Through Caddy
|
||||
- Through Terraform ACME provider
|
||||
- Through Bitnami
|
||||
- Through Zoraxy
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
|
18
.github/workflows/documentation.yml
vendored
18
.github/workflows/documentation.yml
vendored
|
@ -12,23 +12,23 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO_VERSION: stable
|
||||
HUGO_VERSION: '0.117.0'
|
||||
HUGO_VERSION: 0.117.0
|
||||
CGO_ENABLED: 0
|
||||
|
||||
steps:
|
||||
|
||||
# https://github.com/marketplace/actions/setup-go-environment
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
# https://github.com/marketplace/actions/checkout
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# 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: Generate DNS docs
|
||||
run: make generate-dns
|
||||
|
||||
|
@ -42,7 +42,7 @@ jobs:
|
|||
|
||||
# https://github.com/marketplace/actions/github-pages
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: crazy-max/ghaction-github-pages@v3
|
||||
uses: crazy-max/ghaction-github-pages@v4
|
||||
with:
|
||||
target_branch: gh-pages
|
||||
build_dir: docs/public
|
||||
|
|
6
.github/workflows/go-cross.yml
vendored
6
.github/workflows/go-cross.yml
vendored
|
@ -16,17 +16,17 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ stable, oldstable ]
|
||||
go-version: [ stable ]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
# https://github.com/marketplace/actions/checkout
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/marketplace/actions/setup-go-environment
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
|
|
12
.github/workflows/pr.yml
vendored
12
.github/workflows/pr.yml
vendored
|
@ -13,8 +13,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO_VERSION: stable
|
||||
GOLANGCI_LINT_VERSION: v1.54.1
|
||||
HUGO_VERSION: '0.117.0'
|
||||
GOLANGCI_LINT_VERSION: v1.59.0
|
||||
HUGO_VERSION: 0.117.0
|
||||
CGO_ENABLED: 0
|
||||
LEGO_E2E_TESTS: CI
|
||||
MEMCACHED_HOSTS: localhost:11211
|
||||
|
@ -23,13 +23,13 @@ jobs:
|
|||
|
||||
# https://github.com/marketplace/actions/checkout
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# https://github.com/marketplace/actions/setup-go-environment
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
|
@ -46,10 +46,10 @@ jobs:
|
|||
golangci-lint --version
|
||||
|
||||
- name: Install Pebble
|
||||
run: go install github.com/letsencrypt/pebble/v2/cmd/pebble@main
|
||||
run: go install github.com/letsencrypt/pebble/v2/cmd/pebble@3fe019bbc0a41ed16e2fee31592bb91751acaa47
|
||||
|
||||
- name: Install challtestsrv
|
||||
run: go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@main
|
||||
run: go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@3fe019bbc0a41ed16e2fee31592bb91751acaa47
|
||||
|
||||
- name: Set up a Memcached server
|
||||
uses: niden/actions-memcached@v7
|
||||
|
|
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
|
@ -15,6 +15,12 @@ jobs:
|
|||
CGO_ENABLED: 0
|
||||
|
||||
steps:
|
||||
# temporary workaround for an error in free disk space action
|
||||
# https://github.com/jlumbroso/free-disk-space/issues/14
|
||||
- name: Update Package List and Remove Dotnet
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get remove -y '^dotnet-.*'
|
||||
|
||||
# https://github.com/marketplace/actions/free-disk-space-ubuntu
|
||||
- name: Free Disk Space
|
||||
|
@ -32,12 +38,12 @@ jobs:
|
|||
swap-storage: false
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
|
@ -47,17 +53,21 @@ jobs:
|
|||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
run: echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin
|
||||
|
||||
- name: Install snapcraft
|
||||
run: sudo snap install snapcraft --classic
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# https://goreleaser.com/ci/actions/
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
with:
|
||||
version: latest
|
||||
args: release -p 1 --clean --timeout=90m
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }}
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
run:
|
||||
timeout: 10m
|
||||
skip-files: []
|
||||
|
||||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
enable:
|
||||
- shadow
|
||||
gocyclo:
|
||||
min-complexity: 12
|
||||
maligned:
|
||||
suggest-new: true
|
||||
goconst:
|
||||
min-len: 3
|
||||
min-occurrences: 3
|
||||
|
@ -88,20 +86,20 @@ linters-settings:
|
|||
disabled: true
|
||||
- name: unreachable-code
|
||||
- name: redefines-builtin-id
|
||||
testifylint:
|
||||
disable:
|
||||
- require-error
|
||||
- go-require
|
||||
perfsprint:
|
||||
err-error: true
|
||||
errorf: true
|
||||
sprintf1: true
|
||||
strconcat: false
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- deadcode # deprecated
|
||||
- exhaustivestruct # deprecated
|
||||
- golint # deprecated
|
||||
- ifshort # deprecated
|
||||
- interfacer # deprecated
|
||||
- maligned # deprecated
|
||||
- nosnakecase # deprecated
|
||||
- scopelint # deprecated
|
||||
- structcheck # deprecated
|
||||
- varcheck # deprecated
|
||||
- gomnd # deprecated
|
||||
- cyclop # duplicate of gocyclo
|
||||
- sqlclosecheck # not relevant (SQL)
|
||||
- rowserrcheck # not relevant (SQL)
|
||||
|
@ -111,13 +109,13 @@ linters:
|
|||
- dupl # not relevant
|
||||
- prealloc # too many false-positive
|
||||
- bodyclose # too many false-positive
|
||||
- gomnd
|
||||
- mnd
|
||||
- testpackage # not relevant
|
||||
- tparallel # not relevant
|
||||
- paralleltest # not relevant
|
||||
- nestif # too many false-positive
|
||||
- wrapcheck
|
||||
- goerr113 # not relevant
|
||||
- err113 # not relevant
|
||||
- nlreturn # not relevant
|
||||
- wsl # not relevant
|
||||
- exhaustive # not relevant
|
||||
|
@ -137,10 +135,12 @@ linters:
|
|||
- nonamedreturns
|
||||
- musttag # false-positive https://github.com/junk1tm/musttag/issues/17
|
||||
- gosmopolitan # not relevant
|
||||
- exportloopref # Useless with go1.22
|
||||
- canonicalheader # Can create side effects in the context of API clients
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
max-per-linter: 0
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
exclude:
|
||||
- 'Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked'
|
||||
|
@ -152,6 +152,10 @@ issues:
|
|||
- funlen
|
||||
- goconst
|
||||
- maintidx
|
||||
- path: (.+)_test.go
|
||||
text: 'Error return value of `fmt.Fprintln` is not checked'
|
||||
linters:
|
||||
- errcheck
|
||||
- path: providers/dns/dns_providers.go
|
||||
linters:
|
||||
- gocyclo
|
||||
|
@ -223,4 +227,12 @@ issues:
|
|||
- path: providers/dns/hosttech/internal/client_test.go
|
||||
text: 'Duplicate words \(0\) found'
|
||||
- path: cmd/cmd_renew.go
|
||||
text: 'cyclomatic complexity 16 of func `renewForDomains` is high'
|
||||
text: 'cyclomatic complexity \d+ of func `(renewForDomains|renewForCSR)` is high'
|
||||
- path: providers/dns/cpanel/cpanel.go
|
||||
text: 'cyclomatic complexity 13 of func `\(\*DNSProvider\)\.CleanUp` is high'
|
||||
|
||||
output:
|
||||
sort-results: true
|
||||
sort-order:
|
||||
- linter
|
||||
- file
|
||||
|
|
|
@ -17,7 +17,7 @@ builds:
|
|||
- linux
|
||||
- freebsd
|
||||
- openbsd
|
||||
- solaris
|
||||
# - solaris # https://github.com/gofrs/flock/issues/60
|
||||
goarch:
|
||||
- amd64
|
||||
- 386
|
||||
|
@ -41,6 +41,14 @@ builds:
|
|||
- goos: openbsd
|
||||
goarch: arm
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '(?i)^chore:'
|
||||
- '(?i)^Detach v[\d|.]+'
|
||||
- '(?i)^Prepare release v[\d|.]+'
|
||||
|
||||
archives:
|
||||
- id: lego
|
||||
name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}'
|
||||
|
@ -133,3 +141,33 @@ dockers:
|
|||
- '--label=org.opencontainers.image.revision={{.FullCommit}}'
|
||||
- '--label=org.opencontainers.image.version={{.Version}}'
|
||||
- '--platform=linux/arm/v7'
|
||||
|
||||
# Disabled because https://github.com/go-acme/lego/pull/2134#issuecomment-2135293270
|
||||
snapcrafts:
|
||||
- name: lego
|
||||
disable: true
|
||||
grade: stable
|
||||
confinement: strict
|
||||
license: MIT
|
||||
base: core22
|
||||
publish: true
|
||||
summary: Lego is a Let's Encrypt/ACME client.
|
||||
description: |
|
||||
Lego is a Let's Encrypt/ACME client written in Go.
|
||||
|
||||
The lego snap makes it easy to install and use Lego on any Linux distribution that supports snaps.
|
||||
|
||||
Usage:
|
||||
* `sudo snap install lego`
|
||||
* `sudo lego --email="you@example.com" --domains="example.com" --server=https://acme-staging-v02.api.letsencrypt.org/directory --http --http.port :8080 run
|
||||
|
||||
channel_templates:
|
||||
- edge
|
||||
|
||||
apps:
|
||||
lego:
|
||||
command: bin/lego
|
||||
environment:
|
||||
LEGO_PATH: /var/snap/lego/common/.lego
|
||||
plugs:
|
||||
- network-bind
|
||||
|
|
202
CHANGELOG.md
202
CHANGELOG.md
|
@ -1,42 +1,165 @@
|
|||
# Changelog
|
||||
|
||||
## [v4.14.1] - 2023-09-19
|
||||
## [v4.17.3] - 2024-05-28
|
||||
|
||||
### Added
|
||||
|
||||
- **[dnsprovider]** Add DNS provider for Selectel v2
|
||||
- **[dnsprovider]** route53: adds option to not wait for changes
|
||||
- **[dnsprovider]** ovh: add OAuth2 authentication
|
||||
- **[dnsprovider]** azuredns: use TenantID also for cli authentication
|
||||
- **[dnsprovider]** godaddy: documentation about new API limitations
|
||||
- **[cli]** feat: add LEGO_ISSUER_CERT_PATH to hook
|
||||
|
||||
### Changed
|
||||
|
||||
- **[dnsprovider]** dode: update API URL
|
||||
- **[dnsprovider]** exec: stream command output
|
||||
- **[dnsprovider]** oracle: update API client
|
||||
- **[dnsprovider]** azuredns: servicediscovery for zones
|
||||
- **[dnsprovider]** scaleway: add alternative env var names
|
||||
- **[dnsprovider]** exoscale: simplify record creation
|
||||
- **[dnsprovider]** httpnet: add provider to NewDNSChallengeProviderByName
|
||||
- **[cli]** feat: fills LEGO_CERT_PFX_PATH and LEGO_CERT_PEM_PATH only when needed
|
||||
- **[lib,ari]** feat: renewal retry after value
|
||||
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** pdns: reconstruct zone URLs to enable non-root folder API endpoints
|
||||
- **[dnsprovider]** alidns: fix link to API documentation
|
||||
|
||||
## [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] - 2024-05-28
|
||||
|
||||
Canceled due to a release failure related to oci-go-sdk.
|
||||
|
||||
The module `github.com/oracle/oci-go-sdk/v65` uses `github.com/gofrs/flock` but flock doesn't support some platform (like Solaris):
|
||||
- https://github.com/gofrs/flock/issues/60
|
||||
|
||||
Due to that we will remove the Solaris build.
|
||||
|
||||
## [v4.17.0] - 2024-05-28
|
||||
|
||||
Canceled due to a release failure related to Snapcraft.
|
||||
|
||||
## [v4.16.1] - 2024-03-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- **[cli,ari]** fix: don't generate ARI cert ID if ARI is not enable
|
||||
|
||||
## [v4.16.0] - 2024-03-09
|
||||
|
||||
### Added
|
||||
|
||||
- **[dnsprovider]** Add DNS provider for Shellrent
|
||||
- **[dnsprovider]** Add DNS provider for Mail-in-a-Box
|
||||
- **[dnsprovider]** Add DNS provider for CPanel and WHM
|
||||
|
||||
### Changed
|
||||
|
||||
- **[lib,ari]** Implement 'replaces' field in newOrder and draft-ietf-acme-ari-03 CertID changes
|
||||
- **[log]** feat: improve errors and logs related to DNS call
|
||||
- **[lib]** update to go-jose/go-jose/v4 v4.0.1
|
||||
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** nifcloud: fix bug in case of same auth zone
|
||||
- **[dnsprovider]** bunny: Support delegated subdomains
|
||||
- **[dnsprovider]** easydns: fix zone detection
|
||||
- **[dnsprovider]** ns1: fix record creation
|
||||
|
||||
## [v4.15.0] - 2024-01-28
|
||||
|
||||
### Added
|
||||
|
||||
- **[dnsprovider]** Add DNS provider for http.net
|
||||
- **[dnsprovider]** Add DNS provider for Webnames
|
||||
|
||||
### Changed
|
||||
|
||||
- **[cli]** Add environment variable for specifying alternate directory URL
|
||||
- **[cli]** Add format option for PFX encoding
|
||||
- **[lib]** Support simplified issuance for very long domain names at Let's Encrypt
|
||||
- **[lib]** Update CertID format as per draft-ietf-acme-ari-02
|
||||
- **[dnsprovider]** azuredns: allow OIDC authentication
|
||||
- **[dnsprovider]** azuredns: provide the ability to select authentication methods
|
||||
- **[dnsprovider]** efficientip: add insecure skip verify option
|
||||
- **[dnsprovider]** gandiv5: add Personal Access Token support
|
||||
- **[dnsprovider]** gcloud: support GCE_ZONE_ID to bypass zone list
|
||||
- **[dnsprovider]** liquidweb: add LWAPI_ prefix for env vars
|
||||
- **[dnsprovider]** liquidweb: detect zone automatically
|
||||
- **[dnsprovider]** pdns: optional custom API version
|
||||
- **[dnsprovider]** regru: client certificate support
|
||||
- **[dnsprovider]** regru: HTTP method changed to POST
|
||||
- **[dnsprovider]** scaleway: add cname support
|
||||
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** cloudru: change default URLs
|
||||
- **[dnsprovider]** constellix: follow rate limiting headers
|
||||
- **[dnsprovider]** desec: increase default propagation interval
|
||||
- **[dnsprovider]** gandiv5: Add "Bearer" prefix to the auth header
|
||||
- **[dnsprovider]** inwx: improve sleep calculation
|
||||
- **[dnsprovider]** inwx: wait before generating new TOTP TANs
|
||||
- **[dnsprovider]** ionos: fix DNS record removal
|
||||
- **[dnsprovider]** ipv64: remove unused option
|
||||
- **[dnsprovider]** nifcloud: fix API requests
|
||||
- **[dnsprovider]** otc: sequential challenge
|
||||
|
||||
## [v4.14.1] - 2023-09-20
|
||||
|
||||
### Fixed
|
||||
|
||||
### Fixed:
|
||||
- **[dnsprovider]** bunny: fix zone detection
|
||||
- **[dnsprovider]** bunny: use NRDCG fork
|
||||
- **[dnsprovider]** ovh: update client to v1.4.2
|
||||
|
||||
## [v4.14.1] - 2023-09-19
|
||||
|
||||
Cancelled due to CI failure.
|
||||
|
||||
## [v4.14.0] - 2023-08-20
|
||||
|
||||
### Added:
|
||||
### Added
|
||||
|
||||
- **[dnsprovider]** Add DNS provider for Yandex 360
|
||||
- **[dnsprovider]** Add DNS provider for cloud.ru
|
||||
- **[httpprovider]** Adding S3 support for HTTP domain validation
|
||||
|
||||
### Changed:
|
||||
### Changed
|
||||
|
||||
- **[cli]** Allow to set EAB kid and hmac via environment variables
|
||||
- **[dnsprovider]** Migrate to aws-sdk-go-v2 (lightsail, route53)
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** nearlyfreespeech: fix authentication
|
||||
- **[dnsprovider]** pdns: fix notify
|
||||
- **[dnsprovider]** route53: avoid unexpected records deletion
|
||||
|
||||
## [v4.13.3] - 2023-07-25
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** azuredns: fix configuration from env vars
|
||||
- **[dnsprovider]** gcore: change API domain
|
||||
|
||||
## [v4.13.2] - 2023-07-21
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** servercow: fix regression
|
||||
|
||||
## [v4.13.1] - 2023-07-20
|
||||
|
||||
### Added:
|
||||
### Added
|
||||
|
||||
- **[dnsprovider]** Add DNS provider for IPv64
|
||||
- **[dnsprovider]** Add DNS provider for Metaname
|
||||
- **[dnsprovider]** Add DNS provider for RcodeZero
|
||||
|
@ -44,10 +167,12 @@
|
|||
- **[dnsprovider]** azure: new implementation based on the new API client
|
||||
- **[lib]** Experimental option to force DNS queries to use TCP
|
||||
|
||||
### Changed:
|
||||
### Changed
|
||||
|
||||
- **[dnsprovider]** cloudflare: update api client to v0.70.0
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider,cname]** fix: ensure case-insensitive comparison of CNAME records
|
||||
- **[cli]** fix: list command
|
||||
- **[lib]** fix: ARI explanationURL
|
||||
|
@ -58,33 +183,39 @@ Cancelled due to a CI issue (no space left on device).
|
|||
|
||||
## [v4.12.2] - 2023-06-19
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** dnsmadeeasy: fix DeleteRecord
|
||||
- **[lib]** fix: read status code from response
|
||||
|
||||
## [v4.12.1] - 2023-06-06
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** pdns: fix record value
|
||||
|
||||
## [v4.12.0] - 2023-05-28
|
||||
|
||||
### Added:
|
||||
### Added
|
||||
|
||||
- **[lib,cli]** Initial ACME Renewal Info (ARI) Implementation
|
||||
- **[dnsprovider]** Add DNS provider for Derak Cloud
|
||||
- **[dnsprovider]** route53: pass ExternalID property to STS:AssumeRole API operation
|
||||
- **[lib,cli]** Support custom duration for certificate
|
||||
|
||||
### Changed:
|
||||
### Changed
|
||||
|
||||
- **[dnsprovider]** Refactor DNS provider and client implementations
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** autodns: fixes wrong zone in api call if CNAME is used
|
||||
- **[cli]** fix: archive only domain-related files on revoke
|
||||
|
||||
## [v4.11.0] - 2023-05-02
|
||||
|
||||
### Added:
|
||||
### Added
|
||||
|
||||
- **[lib]** Support for certificate with raw IP SAN (RFC8738)
|
||||
- **[dnsprovider]** Add Brandit.com as DNS provider
|
||||
- **[dnsprovider]** Add DNS provider for Bunny
|
||||
|
@ -92,13 +223,15 @@ Cancelled due to a CI issue (no space left on device).
|
|||
- **[dnsprovider]** Add Google Domains as DNS provider
|
||||
- **[dnsprovider]** Add DNS provider for Plesk
|
||||
|
||||
### Changed:
|
||||
### Changed
|
||||
|
||||
- **[cli]** feat: add LEGO_CERT_PEM_PATH and LEGO_CERT_PFX_PATH to run hook
|
||||
- **[lib,cli]** feat: add RSA 3072
|
||||
- **[dnsprovider]** gcloud: update google APIs to latest version
|
||||
- **[lib,dnsprovider,cname]** chore: replace GetRecord by GetChallengeInfo
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** rimuhosting: fix API base URL
|
||||
|
||||
## [v4.10.2] - 2023-02-26
|
||||
|
@ -107,26 +240,30 @@ Fix Docker image builds.
|
|||
|
||||
## [v4.10.1] - 2023-02-25
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider,cname]** acmedns: fix CNAME support
|
||||
- **[dnsprovider]** dynu: fix subdomain support
|
||||
|
||||
## [v4.10.0] - 2023-02-10
|
||||
|
||||
### Added:
|
||||
### Added
|
||||
|
||||
- **[dnsprovider]** Add DNS provider for dnsHome.de
|
||||
- **[dnsprovider]** Add DNS provider for Liara
|
||||
- **[dnsprovider]** Add DNS provider for UltraDNS
|
||||
- **[dnsprovider]** Add DNS provider for Websupport
|
||||
|
||||
### Changed:
|
||||
### Changed
|
||||
|
||||
- **[dnsprovider]** ibmcloud: add support for subdomains
|
||||
- **[dnsprovider]** infomaniak: CNAME support
|
||||
- **[dnsprovider]** namesilo: add cleanup before add a DNS record
|
||||
- **[dnsprovider]** route53: Allow static credentials to be supplied
|
||||
- **[dnsprovider]** tencentcloud: support punycode domain
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** alidns: filter on record type
|
||||
- **[dnsprovider]** arvancloud: replace arvancloud.com by arvancloud.ir
|
||||
- **[dnsprovider]** hetzner: improve zone ID detection
|
||||
|
@ -136,12 +273,12 @@ Fix Docker image builds.
|
|||
|
||||
## [v4.9.1] - 2022-11-25
|
||||
|
||||
### Changed:
|
||||
### Changed
|
||||
-
|
||||
- **[lib,cname]** cname: add log about CNAME entries
|
||||
- **[dnsprovider]** regru: improve error handling
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
-
|
||||
- **[dnsprovider,cname]** fix CNAME support for multiple DNS providers
|
||||
- **[dnsprovider,cname]** duckdns: fix CNAME support
|
||||
|
@ -151,7 +288,7 @@ Fix Docker image builds.
|
|||
|
||||
## [v4.9.0] - 2022-10-03
|
||||
|
||||
### Added:
|
||||
### Added
|
||||
|
||||
- **[dnsprovider]** Add DNS provider for CIVO
|
||||
- **[dnsprovider]** Add DNS provider for VK Cloud
|
||||
|
@ -160,7 +297,7 @@ Fix Docker image builds.
|
|||
- **[dnsprovider]** loopia: add configurable API endpoint
|
||||
- **[dnsprovider]** pdns: notify secondary servers after updates
|
||||
|
||||
### Changed:
|
||||
### Changed
|
||||
|
||||
- **[dnsprovider]** allinkl: removed deprecated sha1 hashing
|
||||
- **[dnsprovider]** auroradns: update authentification
|
||||
|
@ -173,7 +310,8 @@ Fix Docker image builds.
|
|||
- **[lib,cname]** add recursive CNAME lookup support
|
||||
- **[lib]** Remove embedded issuer certificates from issued certificate if bundle is false
|
||||
|
||||
### Fixed:
|
||||
### Fixed
|
||||
|
||||
- **[dnsprovider]** luadns: fix cname support
|
||||
- **[dnsprovider]** njalla: fix record id unmarshal error
|
||||
- **[dnsprovider]** tencentcloud: fix subdomain error
|
||||
|
@ -538,7 +676,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
|
|||
- **[dnsprovider]** Add DNS provider for Constellix
|
||||
- **[dnsprovider]** Add DNS provider for Servercow.
|
||||
- **[dnsprovider]** Add DNS provider for Scaleway
|
||||
- **[cli]** Add "LEGO_PATH" environment variable
|
||||
- **[cli]** Add "LEGO_PATH" environment variable
|
||||
|
||||
### Changed:
|
||||
|
||||
|
@ -551,7 +689,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
|
|||
### Fixed:
|
||||
|
||||
- **[dnsprovider]** zoneee: fix subdomains.
|
||||
- **[dnsprovider]** designate: Don't clean up managed records like SOA and NS
|
||||
- **[dnsprovider]** designate: Don't clean up managed records like SOA and NS
|
||||
- **[dnsprovider]** dnspod: update lib.
|
||||
- **[lib]** crypto: Treat CommonName as optional
|
||||
- **[lib]** chore: update cenkalti/backoff to v4.
|
||||
|
@ -576,7 +714,7 @@ Cancelled due to a CI issue, replaced by v4.5.2.
|
|||
|
||||
### Changed:
|
||||
- **[dnsprovider]** httpreq: Allow use environment vars from a `_FILE` file
|
||||
- **[lib]** Don't deactivate valid authorizations
|
||||
- **[lib]** Don't deactivate valid authorizations
|
||||
- **[lib]** Expose more SOA fields found by dns01.FindZoneByFqdn
|
||||
|
||||
### Fixed:
|
||||
|
@ -749,7 +887,7 @@ There was a problem when creating the tag v3.0.1, this tag has been invalidated.
|
|||
- **[lib]** Adds `Remove` for challenges
|
||||
- **[lib]** Add version to xenolf-acme in User-Agent.
|
||||
- **[dnsprovider]** The ability for a DNS provider to solve the challenge sequentially
|
||||
- **[dnsprovider]** Add DNS provider for "HTTP request".
|
||||
- **[dnsprovider]** Add DNS provider for "HTTP request".
|
||||
- **[dnsprovider]** Add DNS Provider for Vscale
|
||||
- **[dnsprovider]** Add DNS Provider for TransIP
|
||||
- **[dnsprovider]** Add DNS Provider for inwx
|
||||
|
@ -879,7 +1017,7 @@ There was a problem when creating the tag v3.0.1, this tag has been invalidated.
|
|||
### Added:
|
||||
- lib: A new DNS provider for OTC.
|
||||
- lib: The `AWS_HOSTED_ZONE_ID` environment variable for the Route53 DNS provider to directly specify the zone.
|
||||
- lib: The `RFC2136_TIMEOUT` enviroment variable to make the timeout for the RFC2136 provider configurable.
|
||||
- lib: The `RFC2136_TIMEOUT` environment variable to make the timeout for the RFC2136 provider configurable.
|
||||
- lib: The `GCE_SERVICE_ACCOUNT_FILE` environment variable to specify a service account file for the Google Cloud DNS provider.
|
||||
|
||||
### Fixed:
|
||||
|
|
57
README.md
57
README.md
|
@ -16,7 +16,7 @@ Let's Encrypt client and ACME library written in Go.
|
|||
- 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 [draft-ietf-acme-ari-01](https://datatracker.ietf.org/doc/draft-ietf-acme-ari/): Renewal Information (ARI) Extension
|
||||
- Support [draft-ietf-acme-ari-03](https://datatracker.ietf.org/doc/draft-ietf-acme-ari/): Renewal Information (ARI) Extension
|
||||
- Register with CA
|
||||
- Obtain certificates, both from scratch or with an existing CSR
|
||||
- Renew certificates
|
||||
|
@ -58,33 +58,34 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
|
|||
| [Azure (deprecated)](https://go-acme.github.io/lego/dns/azure/) | [Azure DNS](https://go-acme.github.io/lego/dns/azuredns/) | [Bindman](https://go-acme.github.io/lego/dns/bindman/) | [Bluecat](https://go-acme.github.io/lego/dns/bluecat/) |
|
||||
| [Brandit](https://go-acme.github.io/lego/dns/brandit/) | [Bunny](https://go-acme.github.io/lego/dns/bunny/) | [Checkdomain](https://go-acme.github.io/lego/dns/checkdomain/) | [Civo](https://go-acme.github.io/lego/dns/civo/) |
|
||||
| [Cloud.ru](https://go-acme.github.io/lego/dns/cloudru/) | [CloudDNS](https://go-acme.github.io/lego/dns/clouddns/) | [Cloudflare](https://go-acme.github.io/lego/dns/cloudflare/) | [ClouDNS](https://go-acme.github.io/lego/dns/cloudns/) |
|
||||
| [CloudXNS](https://go-acme.github.io/lego/dns/cloudxns/) | [ConoHa](https://go-acme.github.io/lego/dns/conoha/) | [Constellix](https://go-acme.github.io/lego/dns/constellix/) | [Derak Cloud](https://go-acme.github.io/lego/dns/derak/) |
|
||||
| [deSEC.io](https://go-acme.github.io/lego/dns/desec/) | [Designate DNSaaS for Openstack](https://go-acme.github.io/lego/dns/designate/) | [Digital Ocean](https://go-acme.github.io/lego/dns/digitalocean/) | [DNS Made Easy](https://go-acme.github.io/lego/dns/dnsmadeeasy/) |
|
||||
| [dnsHome.de](https://go-acme.github.io/lego/dns/dnshomede/) | [DNSimple](https://go-acme.github.io/lego/dns/dnsimple/) | [DNSPod (deprecated)](https://go-acme.github.io/lego/dns/dnspod/) | [Domain Offensive (do.de)](https://go-acme.github.io/lego/dns/dode/) |
|
||||
| [Domeneshop](https://go-acme.github.io/lego/dns/domeneshop/) | [DreamHost](https://go-acme.github.io/lego/dns/dreamhost/) | [Duck DNS](https://go-acme.github.io/lego/dns/duckdns/) | [Dyn](https://go-acme.github.io/lego/dns/dyn/) |
|
||||
| [Dynu](https://go-acme.github.io/lego/dns/dynu/) | [EasyDNS](https://go-acme.github.io/lego/dns/easydns/) | [Efficient IP](https://go-acme.github.io/lego/dns/efficientip/) | [Epik](https://go-acme.github.io/lego/dns/epik/) |
|
||||
| [Exoscale](https://go-acme.github.io/lego/dns/exoscale/) | [External program](https://go-acme.github.io/lego/dns/exec/) | [freemyip.com](https://go-acme.github.io/lego/dns/freemyip/) | [G-Core](https://go-acme.github.io/lego/dns/gcore/) |
|
||||
| [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/) | [Gandi](https://go-acme.github.io/lego/dns/gandi/) | [Glesys](https://go-acme.github.io/lego/dns/glesys/) | [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/) |
|
||||
| [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/) | [Google Domains](https://go-acme.github.io/lego/dns/googledomains/) | [Hetzner](https://go-acme.github.io/lego/dns/hetzner/) | [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/) |
|
||||
| [Hosttech](https://go-acme.github.io/lego/dns/hosttech/) | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/) | [HyperOne](https://go-acme.github.io/lego/dns/hyperone/) |
|
||||
| [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/) | [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/) | [Infoblox](https://go-acme.github.io/lego/dns/infoblox/) | [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/) |
|
||||
| [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) | [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/) | [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Ionos](https://go-acme.github.io/lego/dns/ionos/) |
|
||||
| [IPv64](https://go-acme.github.io/lego/dns/ipv64/) | [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/) | [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) |
|
||||
| [Liara](https://go-acme.github.io/lego/dns/liara/) | [Linode (v4)](https://go-acme.github.io/lego/dns/linode/) | [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [Loopia](https://go-acme.github.io/lego/dns/loopia/) |
|
||||
| [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) | [Manual](https://go-acme.github.io/lego/dns/manual/) | [Metaname](https://go-acme.github.io/lego/dns/metaname/) | [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) |
|
||||
| [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) | [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) |
|
||||
| [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/) | [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) | [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/) |
|
||||
| [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) | [Njalla](https://go-acme.github.io/lego/dns/njalla/) | [Nodion](https://go-acme.github.io/lego/dns/nodion/) | [NS1](https://go-acme.github.io/lego/dns/ns1/) |
|
||||
| [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | [OVH](https://go-acme.github.io/lego/dns/ovh/) | [plesk.com](https://go-acme.github.io/lego/dns/plesk/) |
|
||||
| [Porkbun](https://go-acme.github.io/lego/dns/porkbun/) | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | [RcodeZero](https://go-acme.github.io/lego/dns/rcodezero/) |
|
||||
| [reg.ru](https://go-acme.github.io/lego/dns/regru/) | [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) |
|
||||
| [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) | [Selectel](https://go-acme.github.io/lego/dns/selectel/) | [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Simply.com](https://go-acme.github.io/lego/dns/simply/) |
|
||||
| [Sonic](https://go-acme.github.io/lego/dns/sonic/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) | [TransIP](https://go-acme.github.io/lego/dns/transip/) |
|
||||
| [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) | [Ultradns](https://go-acme.github.io/lego/dns/ultradns/) | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) |
|
||||
| [Vercel](https://go-acme.github.io/lego/dns/vercel/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) | [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/) |
|
||||
| [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [Websupport](https://go-acme.github.io/lego/dns/websupport/) | [WEDOS](https://go-acme.github.io/lego/dns/wedos/) |
|
||||
| [Yandex 360](https://go-acme.github.io/lego/dns/yandex360/) | [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) | [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) |
|
||||
| [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | | | |
|
||||
| [CloudXNS](https://go-acme.github.io/lego/dns/cloudxns/) | [ConoHa](https://go-acme.github.io/lego/dns/conoha/) | [Constellix](https://go-acme.github.io/lego/dns/constellix/) | [CPanel/WHM](https://go-acme.github.io/lego/dns/cpanel/) |
|
||||
| [Derak Cloud](https://go-acme.github.io/lego/dns/derak/) | [deSEC.io](https://go-acme.github.io/lego/dns/desec/) | [Designate DNSaaS for Openstack](https://go-acme.github.io/lego/dns/designate/) | [Digital Ocean](https://go-acme.github.io/lego/dns/digitalocean/) |
|
||||
| [DNS Made Easy](https://go-acme.github.io/lego/dns/dnsmadeeasy/) | [dnsHome.de](https://go-acme.github.io/lego/dns/dnshomede/) | [DNSimple](https://go-acme.github.io/lego/dns/dnsimple/) | [DNSPod (deprecated)](https://go-acme.github.io/lego/dns/dnspod/) |
|
||||
| [Domain Offensive (do.de)](https://go-acme.github.io/lego/dns/dode/) | [Domeneshop](https://go-acme.github.io/lego/dns/domeneshop/) | [DreamHost](https://go-acme.github.io/lego/dns/dreamhost/) | [Duck DNS](https://go-acme.github.io/lego/dns/duckdns/) |
|
||||
| [Dyn](https://go-acme.github.io/lego/dns/dyn/) | [Dynu](https://go-acme.github.io/lego/dns/dynu/) | [EasyDNS](https://go-acme.github.io/lego/dns/easydns/) | [Efficient IP](https://go-acme.github.io/lego/dns/efficientip/) |
|
||||
| [Epik](https://go-acme.github.io/lego/dns/epik/) | [Exoscale](https://go-acme.github.io/lego/dns/exoscale/) | [External program](https://go-acme.github.io/lego/dns/exec/) | [freemyip.com](https://go-acme.github.io/lego/dns/freemyip/) |
|
||||
| [G-Core](https://go-acme.github.io/lego/dns/gcore/) | [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/) | [Gandi](https://go-acme.github.io/lego/dns/gandi/) | [Glesys](https://go-acme.github.io/lego/dns/glesys/) |
|
||||
| [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/) | [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/) | [Google Domains](https://go-acme.github.io/lego/dns/googledomains/) | [Hetzner](https://go-acme.github.io/lego/dns/hetzner/) |
|
||||
| [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/) | [Hosttech](https://go-acme.github.io/lego/dns/hosttech/) | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/) | [http.net](https://go-acme.github.io/lego/dns/httpnet/) |
|
||||
| [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/) | [HyperOne](https://go-acme.github.io/lego/dns/hyperone/) | [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/) | [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/) |
|
||||
| [Infoblox](https://go-acme.github.io/lego/dns/infoblox/) | [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/) | [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/) | [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/) |
|
||||
| [INWX](https://go-acme.github.io/lego/dns/inwx/) | [Ionos](https://go-acme.github.io/lego/dns/ionos/) | [IPv64](https://go-acme.github.io/lego/dns/ipv64/) | [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/) |
|
||||
| [Joker](https://go-acme.github.io/lego/dns/joker/) | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/) | [Liara](https://go-acme.github.io/lego/dns/liara/) | [Linode (v4)](https://go-acme.github.io/lego/dns/linode/) |
|
||||
| [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/) | [Loopia](https://go-acme.github.io/lego/dns/loopia/) | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/) | [Mail-in-a-Box](https://go-acme.github.io/lego/dns/mailinabox/) |
|
||||
| [Manual](https://go-acme.github.io/lego/dns/manual/) | [Metaname](https://go-acme.github.io/lego/dns/metaname/) | [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/) | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/) |
|
||||
| [Name.com](https://go-acme.github.io/lego/dns/namedotcom/) | [Namecheap](https://go-acme.github.io/lego/dns/namecheap/) | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/) | [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/) |
|
||||
| [Netcup](https://go-acme.github.io/lego/dns/netcup/) | [Netlify](https://go-acme.github.io/lego/dns/netlify/) | [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/) | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/) |
|
||||
| [Njalla](https://go-acme.github.io/lego/dns/njalla/) | [Nodion](https://go-acme.github.io/lego/dns/nodion/) | [NS1](https://go-acme.github.io/lego/dns/ns1/) | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/) |
|
||||
| [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/) | [OVH](https://go-acme.github.io/lego/dns/ovh/) | [plesk.com](https://go-acme.github.io/lego/dns/plesk/) | [Porkbun](https://go-acme.github.io/lego/dns/porkbun/) |
|
||||
| [PowerDNS](https://go-acme.github.io/lego/dns/pdns/) | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/) | [RcodeZero](https://go-acme.github.io/lego/dns/rcodezero/) | [reg.ru](https://go-acme.github.io/lego/dns/regru/) |
|
||||
| [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/) | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/) | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/) | [Scaleway](https://go-acme.github.io/lego/dns/scaleway/) |
|
||||
| [Selectel v2](https://go-acme.github.io/lego/dns/selectelv2/) | [Selectel](https://go-acme.github.io/lego/dns/selectel/) | [Servercow](https://go-acme.github.io/lego/dns/servercow/) | [Shellrent](https://go-acme.github.io/lego/dns/shellrent/) |
|
||||
| [Simply.com](https://go-acme.github.io/lego/dns/simply/) | [Sonic](https://go-acme.github.io/lego/dns/sonic/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) |
|
||||
| [TransIP](https://go-acme.github.io/lego/dns/transip/) | [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) | [Ultradns](https://go-acme.github.io/lego/dns/ultradns/) | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) |
|
||||
| [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) | [Vercel](https://go-acme.github.io/lego/dns/vercel/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) |
|
||||
| [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/) | [Vscale](https://go-acme.github.io/lego/dns/vscale/) | [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [Webnames](https://go-acme.github.io/lego/dns/webnames/) |
|
||||
| [Websupport](https://go-acme.github.io/lego/dns/websupport/) | [WEDOS](https://go-acme.github.io/lego/dns/wedos/) | [Yandex 360](https://go-acme.github.io/lego/dns/yandex360/) | [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) |
|
||||
| [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | |
|
||||
|
||||
<!-- END DNS PROVIDERS LIST -->
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ func (a *AccountService) New(req acme.Account) (acme.ExtendedAccount, error) {
|
|||
resp, err := a.core.post(a.core.GetDirectory().NewAccountURL, req, &account)
|
||||
location := getLocation(resp)
|
||||
|
||||
if len(location) > 0 {
|
||||
if location != "" {
|
||||
a.core.jws.SetKid(location)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/go-acme/lego/v4/acme/api/internal/nonces"
|
||||
jose "github.com/go-jose/go-jose/v3"
|
||||
jose "github.com/go-jose/go-jose/v4"
|
||||
)
|
||||
|
||||
// JWS Represents a JWS.
|
||||
|
|
|
@ -5,10 +5,10 @@ package sender
|
|||
|
||||
const (
|
||||
// ourUserAgent is the User-Agent of this underlying library package.
|
||||
ourUserAgent = "xenolf-acme/4.14.1"
|
||||
ourUserAgent = "xenolf-acme/4.17.3"
|
||||
|
||||
// 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 = "release"
|
||||
ourUserAgentComment = "detach"
|
||||
)
|
||||
|
|
|
@ -13,6 +13,10 @@ import (
|
|||
type OrderOptions struct {
|
||||
NotBefore time.Time
|
||||
NotAfter time.Time
|
||||
// A string uniquely identifying a previously-issued certificate which this
|
||||
// order is intended to replace.
|
||||
// - https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-5
|
||||
ReplacesCertID string
|
||||
}
|
||||
|
||||
type OrderService service
|
||||
|
@ -45,6 +49,10 @@ func (o *OrderService) NewWithOptions(domains []string, opts *OrderOptions) (acm
|
|||
if !opts.NotBefore.IsZero() {
|
||||
orderReq.NotBefore = opts.NotBefore.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
if o.core.GetDirectory().RenewalInfo != "" {
|
||||
orderReq.Replaces = opts.ReplacesCertID
|
||||
}
|
||||
}
|
||||
|
||||
var order acme.Order
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
"github.com/go-acme/lego/v4/acme"
|
||||
"github.com/go-acme/lego/v4/platform/tester"
|
||||
"github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -94,7 +94,6 @@ func TestOrderService_NewWithOptions(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -112,7 +111,8 @@ func readSignedBody(r *http.Request, privateKey *rsa.PrivateKey) ([]byte, error)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
jws, err := jose.ParseSigned(string(reqBody))
|
||||
sigAlgs := []jose.SignatureAlgorithm{jose.RS256}
|
||||
jws, err := jose.ParseSigned(string(reqBody), sigAlgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ package api
|
|||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-acme/lego/v4/acme"
|
||||
)
|
||||
|
||||
// ErrNoARI is returned when the server does not advertise a renewal info endpoint.
|
||||
|
@ -28,26 +26,3 @@ func (c *CertificateService) GetRenewalInfo(certID string) (*http.Response, erro
|
|||
|
||||
return c.core.HTTPClient.Get(c.core.GetDirectory().RenewalInfo + "/" + certID)
|
||||
}
|
||||
|
||||
// UpdateRenewalInfo POSTs updated renewal information for a certificate to the renewalInfo endpoint.
|
||||
// This is used to indicate that a certificate has been replaced.
|
||||
//
|
||||
// Note: this endpoint is part of a draft specification, not all ACME servers will implement it.
|
||||
// This method will return api.ErrNoARI if the server does not advertise a renewal info endpoint.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/draft-ietf-acme-ari
|
||||
func (c *CertificateService) UpdateRenewalInfo(req acme.RenewalInfoUpdateRequest) (*http.Response, error) {
|
||||
if c.core.GetDirectory().RenewalInfo == "" {
|
||||
return nil, ErrNoARI
|
||||
}
|
||||
|
||||
if req.CertID == "" {
|
||||
return nil, errors.New("renewalInfo[post]: 'certID' cannot be empty")
|
||||
}
|
||||
|
||||
if !req.Replaced {
|
||||
return nil, errors.New("renewalInfo[post]: 'replaced' cannot be false")
|
||||
}
|
||||
|
||||
return c.core.post(c.core.GetDirectory().RenewalInfo, req, nil)
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ func Test_getLink(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -181,6 +181,12 @@ type Order struct {
|
|||
// certificate (optional, string):
|
||||
// A URL for the certificate that has been issued in response to this order
|
||||
Certificate string `json:"certificate,omitempty"`
|
||||
|
||||
// replaces (optional, string):
|
||||
// replaces (string, optional): A string uniquely identifying a
|
||||
// previously-issued certificate which this order is intended to replace.
|
||||
// - https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-5
|
||||
Replaces string `json:"replaces,omitempty"`
|
||||
}
|
||||
|
||||
// Authorization the ACME authorization object.
|
||||
|
@ -329,9 +335,11 @@ type RenewalInfoResponse struct {
|
|||
}
|
||||
|
||||
// RenewalInfoUpdateRequest is the JWS payload for POST requests made to the renewalInfo endpoint.
|
||||
// - (4.2. Updating Renewal Information) https://datatracker.ietf.org/doc/draft-ietf-acme-ari/
|
||||
// - (4.2. RenewalInfo Objects) https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-4.2
|
||||
type RenewalInfoUpdateRequest struct {
|
||||
// CertID is the base64url-encoded [RFC4648] bytes of a DER-encoded CertID ASN.1 sequence [RFC6960] with any trailing '=' characters stripped.
|
||||
// CertID is a composite string in the format: base64url(AKI) || '.' || base64url(Serial), where AKI is the
|
||||
// certificate's authority key identifier and Serial is the certificate's serial number. For details, see:
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-4.1
|
||||
CertID string `json:"certID"`
|
||||
// Replaced is required and indicates whether or not the client considers the certificate to have been replaced.
|
||||
// A certificate is considered replaced when its revocation would not disrupt any ongoing services,
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -88,7 +89,7 @@ func ParsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
|
|||
func ParsePEMPrivateKey(key []byte) (crypto.PrivateKey, error) {
|
||||
keyBlockDER, _ := pem.Decode(key)
|
||||
if keyBlockDER == nil {
|
||||
return nil, fmt.Errorf("invalid PEM block")
|
||||
return nil, errors.New("invalid PEM block")
|
||||
}
|
||||
|
||||
if keyBlockDER.Type != "PRIVATE KEY" && !strings.HasSuffix(keyBlockDER.Type, " PRIVATE KEY") {
|
||||
|
@ -216,6 +217,26 @@ func ParsePEMCertificate(cert []byte) (*x509.Certificate, error) {
|
|||
return x509.ParseCertificate(pemBlock.Bytes)
|
||||
}
|
||||
|
||||
func GetCertificateMainDomain(cert *x509.Certificate) (string, error) {
|
||||
return getMainDomain(cert.Subject, cert.DNSNames)
|
||||
}
|
||||
|
||||
func GetCSRMainDomain(cert *x509.CertificateRequest) (string, error) {
|
||||
return getMainDomain(cert.Subject, cert.DNSNames)
|
||||
}
|
||||
|
||||
func getMainDomain(subject pkix.Name, dnsNames []string) (string, error) {
|
||||
if subject.CommonName == "" && len(dnsNames) == 0 {
|
||||
return "", errors.New("missing domain")
|
||||
}
|
||||
|
||||
if subject.CommonName != "" {
|
||||
return subject.CommonName, nil
|
||||
}
|
||||
|
||||
return dnsNames[0], nil
|
||||
}
|
||||
|
||||
func ExtractDomains(cert *x509.Certificate) []string {
|
||||
var domains []string
|
||||
if cert.Subject.CommonName != "" {
|
||||
|
@ -248,7 +269,7 @@ func ExtractDomainsCSR(csr *x509.CertificateRequest) []string {
|
|||
|
||||
// loop over the SubjectAltName DNS names
|
||||
for _, sanName := range csr.DNSNames {
|
||||
if containsSAN(domains, sanName) {
|
||||
if slices.Contains(domains, sanName) {
|
||||
// Duplicate; skip this name
|
||||
continue
|
||||
}
|
||||
|
@ -267,15 +288,6 @@ func ExtractDomainsCSR(csr *x509.CertificateRequest) []string {
|
|||
return domains
|
||||
}
|
||||
|
||||
func containsSAN(domains []string, sanName string) bool {
|
||||
for _, existingName := range domains {
|
||||
if existingName == sanName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GeneratePemCert(privateKey *rsa.PrivateKey, domain string, extensions []pkix.Extension) ([]byte, error) {
|
||||
derBytes, err := generateDerCert(privateKey, time.Time{}, domain, extensions)
|
||||
if err != nil {
|
||||
|
|
|
@ -39,14 +39,14 @@ func TestGenerateCSR(t *testing.T) {
|
|||
expected expected
|
||||
}{
|
||||
{
|
||||
desc: "without SAN",
|
||||
desc: "without SAN (nil)",
|
||||
privateKey: privateKey,
|
||||
domain: "lego.acme",
|
||||
mustStaple: true,
|
||||
expected: expected{len: 245},
|
||||
},
|
||||
{
|
||||
desc: "without SAN",
|
||||
desc: "without SAN (empty)",
|
||||
privateKey: privateKey,
|
||||
domain: "lego.acme",
|
||||
san: []string{},
|
||||
|
@ -86,7 +86,6 @@ func TestGenerateCSR(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ const (
|
|||
// limited on the "new-reg", "new-authz" and "new-cert" endpoints.
|
||||
// From the documentation the limitation is 20 requests per second,
|
||||
// but using 20 as value doesn't work but 18 do.
|
||||
// https://letsencrypt.org/docs/rate-limits/
|
||||
overallRequestLimit = 18
|
||||
)
|
||||
|
||||
|
@ -37,7 +38,7 @@ func (c *Certifier) getAuthorizations(order acme.ExtendedOrder) ([]acme.Authoriz
|
|||
var responses []acme.Authorization
|
||||
|
||||
failures := newObtainError()
|
||||
for i := 0; i < len(order.Authorizations); i++ {
|
||||
for range len(order.Authorizations) {
|
||||
select {
|
||||
case res := <-resc:
|
||||
responses = append(responses, res)
|
||||
|
|
|
@ -63,6 +63,10 @@ type ObtainRequest struct {
|
|||
Bundle bool
|
||||
PreferredChain string
|
||||
AlwaysDeactivateAuthorizations bool
|
||||
// A string uniquely identifying a previously-issued certificate which this
|
||||
// order is intended to replace.
|
||||
// - https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-5
|
||||
ReplacesCertID string
|
||||
}
|
||||
|
||||
// ObtainForCSRRequest The request to obtain a certificate matching the CSR passed into it.
|
||||
|
@ -79,6 +83,10 @@ type ObtainForCSRRequest struct {
|
|||
Bundle bool
|
||||
PreferredChain string
|
||||
AlwaysDeactivateAuthorizations bool
|
||||
// A string uniquely identifying a previously-issued certificate which this
|
||||
// order is intended to replace.
|
||||
// - https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-5
|
||||
ReplacesCertID string
|
||||
}
|
||||
|
||||
type resolver interface {
|
||||
|
@ -124,8 +132,9 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
|
|||
}
|
||||
|
||||
orderOpts := &api.OrderOptions{
|
||||
NotBefore: request.NotBefore,
|
||||
NotAfter: request.NotAfter,
|
||||
NotBefore: request.NotBefore,
|
||||
NotAfter: request.NotAfter,
|
||||
ReplacesCertID: request.ReplacesCertID,
|
||||
}
|
||||
|
||||
order, err := c.core.Orders.NewWithOptions(domains, orderOpts)
|
||||
|
@ -189,8 +198,9 @@ func (c *Certifier) ObtainForCSR(request ObtainForCSRRequest) (*Resource, error)
|
|||
}
|
||||
|
||||
orderOpts := &api.OrderOptions{
|
||||
NotBefore: request.NotBefore,
|
||||
NotAfter: request.NotAfter,
|
||||
NotBefore: request.NotBefore,
|
||||
NotAfter: request.NotAfter,
|
||||
ReplacesCertID: request.ReplacesCertID,
|
||||
}
|
||||
|
||||
order, err := c.core.Orders.NewWithOptions(domains, orderOpts)
|
||||
|
@ -243,8 +253,10 @@ func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bund
|
|||
}
|
||||
}
|
||||
|
||||
// Determine certificate name(s) based on the authorization resources
|
||||
commonName := domains[0]
|
||||
commonName := ""
|
||||
if len(domains[0]) <= 64 {
|
||||
commonName = domains[0]
|
||||
}
|
||||
|
||||
// RFC8555 Section 7.4 "Applying for Certificate Issuance"
|
||||
// https://www.rfc-editor.org/rfc/rfc8555.html#section-7.4
|
||||
|
@ -252,7 +264,12 @@ func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, bund
|
|||
// Clients SHOULD NOT make any assumptions about the sort order of
|
||||
// "identifiers" or "authorizations" elements in the returned order
|
||||
// object.
|
||||
san := []string{commonName}
|
||||
|
||||
var san []string
|
||||
if commonName != "" {
|
||||
san = append(san, commonName)
|
||||
}
|
||||
|
||||
for _, auth := range order.Identifiers {
|
||||
if auth.Value != commonName {
|
||||
san = append(san, auth.Value)
|
||||
|
@ -274,9 +291,8 @@ func (c *Certifier) getForCSR(domains []string, order acme.ExtendedOrder, bundle
|
|||
return nil, err
|
||||
}
|
||||
|
||||
commonName := domains[0]
|
||||
certRes := &Resource{
|
||||
Domain: commonName,
|
||||
Domain: domains[0],
|
||||
CertURL: respOrder.Certificate,
|
||||
PrivateKey: privateKeyPem,
|
||||
}
|
||||
|
@ -598,8 +614,13 @@ func (c *Certifier) Get(url string, bundle bool) (*Resource, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
domain, err := certcrypto.GetCertificateMainDomain(x509Certs[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Resource{
|
||||
Domain: x509Certs[0].Subject.CommonName,
|
||||
Domain: domain,
|
||||
Certificate: cert,
|
||||
IssuerCertificate: issuer,
|
||||
CertURL: url,
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -28,7 +27,7 @@ func Test_obtainError_Join(t *testing.T) {
|
|||
err := failures.Join()
|
||||
|
||||
to := &TomatoError{}
|
||||
assert.ErrorAs(t, err, &to)
|
||||
require.ErrorAs(t, err, &to)
|
||||
}
|
||||
|
||||
func Test_obtainError_Join_multiple_domains(t *testing.T) {
|
||||
|
@ -40,16 +39,16 @@ func Test_obtainError_Join_multiple_domains(t *testing.T) {
|
|||
err := failures.Join()
|
||||
|
||||
to := &TomatoError{}
|
||||
assert.ErrorAs(t, err, &to)
|
||||
require.ErrorAs(t, err, &to)
|
||||
|
||||
ca := &CarrotError{}
|
||||
assert.ErrorAs(t, err, &ca)
|
||||
require.ErrorAs(t, err, &ca)
|
||||
}
|
||||
|
||||
func Test_obtainError_Join_no_error(t *testing.T) {
|
||||
failures := newObtainError()
|
||||
|
||||
assert.NoError(t, failures.Join())
|
||||
require.NoError(t, failures.Join())
|
||||
}
|
||||
|
||||
func Test_obtainError_Join_same_domain(t *testing.T) {
|
||||
|
@ -66,5 +65,5 @@ func Test_obtainError_Join_same_domain(t *testing.T) {
|
|||
}
|
||||
|
||||
ca := &CarrotError{}
|
||||
assert.ErrorAs(t, err, &ca)
|
||||
require.ErrorAs(t, err, &ca)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package certificate
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/acme"
|
||||
|
@ -18,16 +15,18 @@ import (
|
|||
|
||||
// RenewalInfoRequest contains the necessary renewal information.
|
||||
type RenewalInfoRequest struct {
|
||||
Cert *x509.Certificate
|
||||
Issuer *x509.Certificate
|
||||
// HashName must be the string representation of a crypto.Hash constant in the golang.org/x/crypto package (e.g. "SHA-256").
|
||||
// The correct value depends on the algorithm expected by the ACME server's ARI implementation.
|
||||
HashName string
|
||||
Cert *x509.Certificate
|
||||
}
|
||||
|
||||
// RenewalInfoResponse is a wrapper around acme.RenewalInfoResponse that provides a method for determining when to renew a certificate.
|
||||
type RenewalInfoResponse struct {
|
||||
acme.RenewalInfoResponse
|
||||
|
||||
// RetryAfter header indicating the polling interval that the ACME server recommends.
|
||||
// Conforming clients SHOULD query the renewalInfo URL again after the RetryAfter period has passed,
|
||||
// as the server may provide a different suggestedWindow.
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-03#section-4.2
|
||||
RetryAfter time.Duration
|
||||
}
|
||||
|
||||
// ShouldRenewAt determines the optimal renewal time based on the current time (UTC),renewal window suggest by ARI, and the client's willingness to sleep.
|
||||
|
@ -72,7 +71,7 @@ func (r *RenewalInfoResponse) ShouldRenewAt(now time.Time, willingToSleep time.D
|
|||
//
|
||||
// https://datatracker.ietf.org/doc/draft-ietf-acme-ari
|
||||
func (c *Certifier) GetRenewalInfo(req RenewalInfoRequest) (*RenewalInfoResponse, error) {
|
||||
certID, err := makeCertID(req.Cert, req.Issuer, req.HashName)
|
||||
certID, err := MakeARICertID(req.Cert)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error making certID: %w", err)
|
||||
}
|
||||
|
@ -88,117 +87,43 @@ func (c *Certifier) GetRenewalInfo(req RenewalInfoRequest) (*RenewalInfoResponse
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if retry := resp.Header.Get("Retry-After"); retry != "" {
|
||||
info.RetryAfter, err = time.ParseDuration(retry + "s")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// UpdateRenewalInfo sends an update to the ACME server's renewal info endpoint to indicate that the client has successfully replaced a certificate.
|
||||
// A certificate is considered replaced when its revocation would not disrupt any ongoing services,
|
||||
// for instance because it has been renewed and the new certificate is in use, or because it is no longer in use.
|
||||
//
|
||||
// Note: this endpoint is part of a draft specification, not all ACME servers will implement it.
|
||||
// This method will return api.ErrNoARI if the server does not advertise a renewal info endpoint.
|
||||
//
|
||||
// https://datatracker.ietf.org/doc/draft-ietf-acme-ari
|
||||
func (c *Certifier) UpdateRenewalInfo(req RenewalInfoRequest) error {
|
||||
certID, err := makeCertID(req.Cert, req.Issuer, req.HashName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error making certID: %w", err)
|
||||
}
|
||||
|
||||
_, err = c.core.Certificates.UpdateRenewalInfo(acme.RenewalInfoUpdateRequest{
|
||||
CertID: certID,
|
||||
Replaced: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeCertID returns a base64url-encoded string that uniquely identifies a certificate to endpoints
|
||||
// that implement the draft-ietf-acme-ari specification: https://datatracker.ietf.org/doc/draft-ietf-acme-ari.
|
||||
// hashName must be the string representation of a crypto.Hash constant in the golang.org/x/crypto package.
|
||||
// Supported hash functions are SHA-1, SHA-256, SHA-384, and SHA-512.
|
||||
func makeCertID(leaf, issuer *x509.Certificate, hashName string) (string, error) {
|
||||
// MakeARICertID constructs a certificate identifier as described in draft-ietf-acme-ari-03, section 4.1.
|
||||
func MakeARICertID(leaf *x509.Certificate) (string, error) {
|
||||
if leaf == nil {
|
||||
return "", fmt.Errorf("leaf certificate is nil")
|
||||
}
|
||||
if issuer == nil {
|
||||
return "", fmt.Errorf("issuer certificate is nil")
|
||||
return "", errors.New("leaf certificate is nil")
|
||||
}
|
||||
|
||||
var hashFunc crypto.Hash
|
||||
var oid asn1.ObjectIdentifier
|
||||
|
||||
switch hashName {
|
||||
// The following correlation of hashFunc to OID is copied from a private mapping in golang.org/x/crypto/ocsp:
|
||||
// https://cs.opensource.google/go/x/crypto/+/refs/tags/v0.8.0:ocsp/ocsp.go;l=156
|
||||
case crypto.SHA1.String():
|
||||
hashFunc = crypto.SHA1
|
||||
oid = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
|
||||
|
||||
case crypto.SHA256.String():
|
||||
hashFunc = crypto.SHA256
|
||||
oid = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 1})
|
||||
|
||||
case crypto.SHA384.String():
|
||||
hashFunc = crypto.SHA384
|
||||
oid = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 2})
|
||||
|
||||
case crypto.SHA512.String():
|
||||
hashFunc = crypto.SHA512
|
||||
oid = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 3})
|
||||
|
||||
default:
|
||||
return "", fmt.Errorf("hashName %q is not supported by this package", hashName)
|
||||
}
|
||||
|
||||
if !hashFunc.Available() {
|
||||
// This should never happen.
|
||||
return "", fmt.Errorf("hash function %q is not available on your platform", hashFunc)
|
||||
}
|
||||
|
||||
var spki struct {
|
||||
Algorithm pkix.AlgorithmIdentifier
|
||||
PublicKey asn1.BitString
|
||||
}
|
||||
|
||||
_, err := asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &spki)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
h := hashFunc.New()
|
||||
h.Write(spki.PublicKey.RightAlign())
|
||||
issuerKeyHash := h.Sum(nil)
|
||||
|
||||
h.Reset()
|
||||
h.Write(issuer.RawSubject)
|
||||
issuerNameHash := h.Sum(nil)
|
||||
|
||||
type certID struct {
|
||||
HashAlgorithm pkix.AlgorithmIdentifier
|
||||
IssuerNameHash []byte
|
||||
IssuerKeyHash []byte
|
||||
SerialNumber *big.Int
|
||||
}
|
||||
|
||||
// DER-encode the CertID ASN.1 sequence [RFC6960].
|
||||
certIDBytes, err := asn1.Marshal(certID{
|
||||
HashAlgorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: oid,
|
||||
},
|
||||
IssuerNameHash: issuerNameHash,
|
||||
IssuerKeyHash: issuerKeyHash,
|
||||
SerialNumber: leaf.SerialNumber,
|
||||
})
|
||||
// Marshal the Serial Number into DER.
|
||||
der, err := asn1.Marshal(leaf.SerialNumber)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// base64url-encode [RFC4648] the bytes of the DER-encoded CertID ASN.1 sequence [RFC6960].
|
||||
encodedBytes := base64.URLEncoding.EncodeToString(certIDBytes)
|
||||
// Check if the DER encoded bytes are sufficient (at least 3 bytes: tag,
|
||||
// length, and value).
|
||||
if len(der) < 3 {
|
||||
return "", errors.New("invalid DER encoding of serial number")
|
||||
}
|
||||
|
||||
// Any trailing '=' characters MUST be stripped.
|
||||
return strings.TrimRight(encodedBytes, "="), nil
|
||||
// Extract only the integer bytes from the DER encoded Serial Number
|
||||
// Skipping the first 2 bytes (tag and length).
|
||||
serial := base64.RawURLEncoding.EncodeToString(der[2:])
|
||||
|
||||
// Convert the Authority Key Identifier to base64url encoding without
|
||||
// padding.
|
||||
aki := base64.RawURLEncoding.EncodeToString(leaf.AuthorityKeyId)
|
||||
|
||||
// Construct the final identifier by concatenating AKI and Serial Number.
|
||||
return fmt.Sprintf("%s.%s", aki, serial), nil
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
package certificate
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -14,62 +11,28 @@ 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-jose/go-jose/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
ariLeafPEM = `-----BEGIN CERTIFICATE-----
|
||||
MIIDMDCCAhigAwIBAgIIPqNFaGVEHxwwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
|
||||
AxMVbWluaWNhIHJvb3QgY2EgM2ExMzU2MB4XDTIyMDMxNzE3NTEwOVoXDTI0MDQx
|
||||
NjE3NTEwOVowFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQCgm9K/c+il2Pf0f8qhgxn9SKqXq88cOm9ov9AVRbPA
|
||||
OWAAewqX2yUAwI4LZBGEgzGzTATkiXfoJ3cN3k39cH6tBbb3iSPuEn7OZpIk9D+e
|
||||
3Q9/hX+N/jlWkaTB/FNA+7aE5IVWhmdczYilXa10V9r+RcvACJt0gsipBZVJ4jfJ
|
||||
HnWJJGRZzzxqG/xkQmpXxZO7nOPFc8SxYKWdfcgp+rjR2ogYhSz7BfKoVakGPbpX
|
||||
vZOuT9z4kkHra/WjwlkQhtHoTXdAxH3qC2UjMzO57Tx+otj0CxAv9O7CTJXISywB
|
||||
vEVcmTSZkHS3eZtvvIwPx7I30ITRkYk/tLl1MbyB3SiZAgMBAAGjeDB2MA4GA1Ud
|
||||
DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
|
||||
AQH/BAIwADAfBgNVHSMEGDAWgBQ4zzDRUaXHVKqlSTWkULGU4zGZpTAWBgNVHREE
|
||||
DzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAx0aYvmCk7JYGNEXe
|
||||
+hrOfKawkHYzWvA92cI/Oi6h+oSdHZ2UKzwFNf37cVKZ37FCrrv5pFP/xhhHvrNV
|
||||
EnOx4IaF7OrnaTu5miZiUWuvRQP7ZGmGNFYbLTEF6/dj+WqyYdVaWzxRqHFu1ptC
|
||||
TXysJCeyiGnR+KOOjOOQ9ZlO5JUK3OE4hagPLfaIpDDy6RXQt3ss0iNLuB1+IOtp
|
||||
1URpvffLZQ8xPsEgOZyPWOcabTwJrtqBwily+lwPFn2mChUx846LwQfxtsXU/lJg
|
||||
HX2RteNJx7YYNeX3Uf960mgo5an6vE8QNAsIoNHYrGyEmXDhTRe9mCHyiW2S7fZq
|
||||
o9q12g==
|
||||
MIIBQzCB66ADAgECAgUAh2VDITAKBggqhkjOPQQDAjAVMRMwEQYDVQQDEwpFeGFt
|
||||
cGxlIENBMCIYDzAwMDEwMTAxMDAwMDAwWhgPMDAwMTAxMDEwMDAwMDBaMBYxFDAS
|
||||
BgNVBAMTC2V4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeBZu
|
||||
7cbpAYNXZLbbh8rNIzuOoqOOtmxA1v7cRm//AwyMwWxyHz4zfwmBhcSrf47NUAFf
|
||||
qzLQ2PPQxdTXREYEnKMjMCEwHwYDVR0jBBgwFoAUaYhba4dGQEHhs3uEe6CuLN4B
|
||||
yNQwCgYIKoZIzj0EAwIDRwAwRAIge09+S5TZAlw5tgtiVvuERV6cT4mfutXIlwTb
|
||||
+FYN/8oCIClDsqBklhB9KAelFiYt9+6FDj3z4KGVelYM5MdsO3pK
|
||||
-----END CERTIFICATE-----`
|
||||
ariIssuerPEM = `-----BEGIN CERTIFICATE-----
|
||||
MIIDSzCCAjOgAwIBAgIIOhNWtJ7Igr0wDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
|
||||
AxMVbWluaWNhIHJvb3QgY2EgM2ExMzU2MCAXDTIyMDMxNzE3NTEwOVoYDzIxMjIw
|
||||
MzE3MTc1MTA5WjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSAzYTEzNTYwggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDc3P6cxcCZ7FQOQrYuigReSa8T
|
||||
IOPNKmlmX9OrTkPwjThiMNEETYKO1ea99yXPK36LUHC6OLmZ9jVQW2Ny1qwQCOy6
|
||||
TrquhnwKgtkBMDAZBLySSEXYdKL3r0jA4sflW130/OLwhstU/yv0J8+pj7eSVOR3
|
||||
zJBnYd1AqnXHRSwQm299KXgqema7uwsa8cgjrXsBzAhrwrvYlVhpWFSv3lQRDFQg
|
||||
c5Z/ZDV9i26qiaJsCCmdisJZWN7N2luUgxdRqzZ4Cr2Xoilg3T+hkb2y/d6ttsPA
|
||||
kaSA+pq3q6Qa7/qfGdT5WuUkcHpvKNRWqnwT9rCYlmG00r3hGgc42D/z1VvfAgMB
|
||||
AAGjgYYwgYMwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
|
||||
BgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQ4zzDRUaXHVKql
|
||||
STWkULGU4zGZpTAfBgNVHSMEGDAWgBQ4zzDRUaXHVKqlSTWkULGU4zGZpTANBgkq
|
||||
hkiG9w0BAQsFAAOCAQEArbDHhEjGedjb/YjU80aFTPWOMRjgyfQaPPgyxwX6Dsid
|
||||
1i2H1x4ud4ntz3sTZZxdQIrOqtlIWTWVCjpStwGxaC+38SdreiTTwy/nikXGa/6W
|
||||
ZyQRppR3agh/pl5LHVO6GsJz3YHa7wQhEhj3xsRwa9VrRXgHbLGbPOFVRTHPjaPg
|
||||
Gtsv2PN3f67DsPHF47ASqyOIRpLZPQmZIw6D3isJwfl+8CzvlB1veO0Q3uh08IJc
|
||||
fspYQXvFBzYa64uKxNAJMi4Pby8cf4r36Wnb7cL4ho3fOHgAltxdW8jgibRzqZpQ
|
||||
QKyxn2jX7kxeUDt0hFDJE8lOrhP73m66eBNzxe//FQ==
|
||||
-----END CERTIFICATE-----`
|
||||
ariLeafCertID = "MFswCwYJYIZIAWUDBAIBBCCeWLRusNLb--vmWOkxm34qDjTMWkc3utIhOMoMwKDqbgQg2iiKWySZrD-6c88HMZ6vhIHZPamChLlzGHeZ7pTS8jYCCD6jRWhlRB8c"
|
||||
ariLeafCertID = "aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE"
|
||||
)
|
||||
|
||||
func Test_makeCertID(t *testing.T) {
|
||||
leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
|
||||
require.NoError(t, err)
|
||||
issuer, err := certcrypto.ParsePEMCertificate([]byte(ariIssuerPEM))
|
||||
require.NoError(t, err)
|
||||
|
||||
actual, err := makeCertID(leaf, issuer, crypto.SHA256.String())
|
||||
actual, err := MakeARICertID(leaf)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, ariLeafCertID, actual)
|
||||
}
|
||||
|
@ -77,8 +40,6 @@ func Test_makeCertID(t *testing.T) {
|
|||
func TestCertifier_GetRenewalInfo(t *testing.T) {
|
||||
leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
|
||||
require.NoError(t, err)
|
||||
issuer, err := certcrypto.ParsePEMCertificate([]byte(ariIssuerPEM))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test with a fake API.
|
||||
mux, apiURL := tester.SetupFakeAPI(t)
|
||||
|
@ -89,6 +50,7 @@ func TestCertifier_GetRenewalInfo(t *testing.T) {
|
|||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Retry-After", "21600")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, wErr := w.Write([]byte(`{
|
||||
"suggestedWindow": {
|
||||
|
@ -109,19 +71,18 @@ func TestCertifier_GetRenewalInfo(t *testing.T) {
|
|||
|
||||
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
|
||||
|
||||
ri, err := certifier.GetRenewalInfo(RenewalInfoRequest{leaf, issuer, crypto.SHA256.String()})
|
||||
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/docs/renewal-advice/", ri.ExplanationURL)
|
||||
assert.Equal(t, time.Duration(21600000000000), ri.RetryAfter)
|
||||
}
|
||||
|
||||
func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
|
||||
leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
|
||||
require.NoError(t, err)
|
||||
issuer, err := certcrypto.ParsePEMCertificate([]byte(ariIssuerPEM))
|
||||
require.NoError(t, err)
|
||||
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err, "Could not generate test key")
|
||||
|
@ -135,7 +96,7 @@ func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
|
|||
{
|
||||
desc: "API timeout",
|
||||
httpClient: &http.Client{Timeout: 500 * time.Millisecond}, // HTTP client that times out after 500ms.
|
||||
request: RenewalInfoRequest{leaf, issuer, crypto.SHA256.String()},
|
||||
request: RenewalInfoRequest{leaf},
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
// API that takes 2ms to respond.
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
|
@ -144,24 +105,15 @@ func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
|
|||
{
|
||||
desc: "API error",
|
||||
httpClient: http.DefaultClient,
|
||||
request: RenewalInfoRequest{leaf, issuer, crypto.SHA256.String()},
|
||||
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)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Issuer certificate is nil",
|
||||
httpClient: http.DefaultClient,
|
||||
request: RenewalInfoRequest{leaf, nil, crypto.SHA256.String()},
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -180,105 +132,19 @@ func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCertifier_UpdateRenewalInfo(t *testing.T) {
|
||||
leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
|
||||
require.NoError(t, err)
|
||||
issuer, err := certcrypto.ParsePEMCertificate([]byte(ariIssuerPEM))
|
||||
require.NoError(t, err)
|
||||
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err, "Could not generate test key")
|
||||
|
||||
// Test with a fake API.
|
||||
mux, apiURL := tester.SetupFakeAPI(t)
|
||||
mux.HandleFunc("/renewalInfo", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
body, rsbErr := readSignedBody(r, key)
|
||||
if rsbErr != nil {
|
||||
http.Error(w, rsbErr.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req acme.RenewalInfoUpdateRequest
|
||||
err = json.Unmarshal(body, &req)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, req.Replaced)
|
||||
assert.Equal(t, ariLeafCertID, req.CertID)
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
|
||||
require.NoError(t, err)
|
||||
|
||||
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
|
||||
|
||||
err = certifier.UpdateRenewalInfo(RenewalInfoRequest{leaf, issuer, crypto.SHA256.String()})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestCertifier_UpdateRenewalInfo_errors(t *testing.T) {
|
||||
leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
|
||||
require.NoError(t, err)
|
||||
issuer, err := certcrypto.ParsePEMCertificate([]byte(ariIssuerPEM))
|
||||
require.NoError(t, err)
|
||||
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
require.NoError(t, err, "Could not generate test key")
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
request RenewalInfoRequest
|
||||
}{
|
||||
{
|
||||
desc: "API error",
|
||||
request: RenewalInfoRequest{leaf, issuer, crypto.SHA256.String()},
|
||||
},
|
||||
{
|
||||
desc: "Certificate is nil",
|
||||
request: RenewalInfoRequest{nil, issuer, crypto.SHA256.String()},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
mux, apiURL := tester.SetupFakeAPI(t)
|
||||
|
||||
// Always returns an error.
|
||||
mux.HandleFunc("/renewalInfo", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
})
|
||||
|
||||
core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key)
|
||||
require.NoError(t, err)
|
||||
|
||||
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
|
||||
|
||||
err = certifier.UpdateRenewalInfo(test.request)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewalInfoResponse_ShouldRenew(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
|
||||
t.Run("Window is in the past", func(t *testing.T) {
|
||||
ri := RenewalInfoResponse{
|
||||
acme.RenewalInfoResponse{
|
||||
RenewalInfoResponse: acme.RenewalInfoResponse{
|
||||
SuggestedWindow: acme.Window{
|
||||
Start: now.Add(-2 * time.Hour),
|
||||
End: now.Add(-1 * time.Hour),
|
||||
},
|
||||
ExplanationURL: "",
|
||||
},
|
||||
RetryAfter: 0,
|
||||
}
|
||||
|
||||
rt := ri.ShouldRenewAt(now, 0)
|
||||
|
@ -288,13 +154,14 @@ func TestRenewalInfoResponse_ShouldRenew(t *testing.T) {
|
|||
|
||||
t.Run("Window is in the future", func(t *testing.T) {
|
||||
ri := RenewalInfoResponse{
|
||||
acme.RenewalInfoResponse{
|
||||
RenewalInfoResponse: acme.RenewalInfoResponse{
|
||||
SuggestedWindow: acme.Window{
|
||||
Start: now.Add(1 * time.Hour),
|
||||
End: now.Add(2 * time.Hour),
|
||||
},
|
||||
ExplanationURL: "",
|
||||
},
|
||||
RetryAfter: 0,
|
||||
}
|
||||
|
||||
rt := ri.ShouldRenewAt(now, 0)
|
||||
|
@ -303,13 +170,14 @@ func TestRenewalInfoResponse_ShouldRenew(t *testing.T) {
|
|||
|
||||
t.Run("Window is in the future, but caller is willing to sleep", func(t *testing.T) {
|
||||
ri := RenewalInfoResponse{
|
||||
acme.RenewalInfoResponse{
|
||||
RenewalInfoResponse: acme.RenewalInfoResponse{
|
||||
SuggestedWindow: acme.Window{
|
||||
Start: now.Add(1 * time.Hour),
|
||||
End: now.Add(2 * time.Hour),
|
||||
},
|
||||
ExplanationURL: "",
|
||||
},
|
||||
RetryAfter: 0,
|
||||
}
|
||||
|
||||
rt := ri.ShouldRenewAt(now, 2*time.Hour)
|
||||
|
@ -319,38 +187,17 @@ func TestRenewalInfoResponse_ShouldRenew(t *testing.T) {
|
|||
|
||||
t.Run("Window is in the future, but caller isn't willing to sleep long enough", func(t *testing.T) {
|
||||
ri := RenewalInfoResponse{
|
||||
acme.RenewalInfoResponse{
|
||||
RenewalInfoResponse: acme.RenewalInfoResponse{
|
||||
SuggestedWindow: acme.Window{
|
||||
Start: now.Add(1 * time.Hour),
|
||||
End: now.Add(2 * time.Hour),
|
||||
},
|
||||
ExplanationURL: "",
|
||||
},
|
||||
RetryAfter: 0,
|
||||
}
|
||||
|
||||
rt := ri.ShouldRenewAt(now, 59*time.Minute)
|
||||
assert.Nil(t, rt)
|
||||
})
|
||||
}
|
||||
|
||||
func readSignedBody(r *http.Request, privateKey *rsa.PrivateKey) ([]byte, error) {
|
||||
reqBody, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
jws, err := jose.ParseSigned(string(reqBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
body, err := jws.Verify(&jose.JSONWebKey{
|
||||
Key: privateKey.Public(),
|
||||
Algorithm: "RSA",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/acme"
|
||||
|
@ -124,7 +125,7 @@ func (c *Challenge) Solve(authz acme.Authorization) error {
|
|||
timeout, interval = DefaultPropagationTimeout, DefaultPollingInterval
|
||||
}
|
||||
|
||||
log.Infof("[%s] acme: Checking DNS record propagation using %+v", domain, recursiveNameservers)
|
||||
log.Infof("[%s] acme: Checking DNS record propagation. [nameservers=%s]", domain, strings.Join(recursiveNameservers, ","))
|
||||
|
||||
time.Sleep(interval)
|
||||
|
||||
|
@ -214,7 +215,7 @@ func getChallengeFQDN(domain string, followCNAME bool) string {
|
|||
}
|
||||
|
||||
// recursion counter so it doesn't spin out of control
|
||||
for limit := 0; limit < 50; limit++ {
|
||||
for range 50 {
|
||||
// Keep following CNAMEs
|
||||
r, err := dnsQuery(fqdn, dns.TypeCNAME, recursiveNameservers, true)
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ func (*DNSProviderManual) Present(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("manual: could not find zone: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("lego: Please create the following TXT record in your %s zone:\n", authZone)
|
||||
|
@ -33,8 +33,11 @@ func (*DNSProviderManual) Present(domain, token, keyAuth string) error {
|
|||
fmt.Printf("lego: Press 'Enter' when you are done\n")
|
||||
|
||||
_, err = bufio.NewReader(os.Stdin).ReadBytes('\n')
|
||||
if err != nil {
|
||||
return fmt.Errorf("manual: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// CleanUp prints instructions for manually removing the TXT record.
|
||||
|
@ -43,7 +46,7 @@ func (*DNSProviderManual) CleanUp(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("manual: could not find zone: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("lego: You can now remove this TXT record from your %s zone:\n", authZone)
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -32,14 +31,14 @@ func TestDNSProviderManual(t *testing.T) {
|
|||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
file, err := os.CreateTemp("", "lego_test")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
defer func() { _ = os.Remove(file.Name()) }()
|
||||
|
||||
_, err = file.WriteString(test.input)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = file.Seek(0, io.SeekStart)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
os.Stdin = file
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ func TestExtractSubDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -93,7 +92,6 @@ func TestExtractSubDomain_errors(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -14,18 +14,17 @@ func TestToFqdn(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
desc: "simple",
|
||||
domain: "foo.bar.com",
|
||||
expected: "foo.bar.com.",
|
||||
domain: "foo.example.com",
|
||||
expected: "foo.example.com.",
|
||||
},
|
||||
{
|
||||
desc: "already FQDN",
|
||||
domain: "foo.bar.com.",
|
||||
expected: "foo.bar.com.",
|
||||
domain: "foo.example.com.",
|
||||
expected: "foo.example.com.",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -43,18 +42,17 @@ func TestUnFqdn(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
desc: "simple",
|
||||
fqdn: "foo.bar.com.",
|
||||
expected: "foo.bar.com",
|
||||
fqdn: "foo.example.",
|
||||
expected: "foo.example",
|
||||
},
|
||||
{
|
||||
desc: "already domain",
|
||||
fqdn: "foo.bar.com",
|
||||
expected: "foo.bar.com",
|
||||
fqdn: "foo.example",
|
||||
expected: "foo.example",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -98,12 +99,12 @@ func lookupNameservers(fqdn string) ([]string, error) {
|
|||
|
||||
zone, err := FindZoneByFqdn(fqdn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not determine the zone: %w", err)
|
||||
return nil, fmt.Errorf("could not find zone: %w", err)
|
||||
}
|
||||
|
||||
r, err := dnsQuery(zone, dns.TypeNS, recursiveNameservers, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("NS call failed: %w", err)
|
||||
}
|
||||
|
||||
for _, rr := range r.Answer {
|
||||
|
@ -115,7 +116,8 @@ func lookupNameservers(fqdn string) ([]string, error) {
|
|||
if len(authoritativeNss) > 0 {
|
||||
return authoritativeNss, nil
|
||||
}
|
||||
return nil, errors.New("could not determine authoritative nameservers")
|
||||
|
||||
return nil, fmt.Errorf("[zone=%s] could not determine authoritative nameservers", zone)
|
||||
}
|
||||
|
||||
// FindPrimaryNsByFqdn determines the primary nameserver of the zone apex for the given fqdn
|
||||
|
@ -129,7 +131,7 @@ func FindPrimaryNsByFqdn(fqdn string) (string, error) {
|
|||
func FindPrimaryNsByFqdnCustom(fqdn string, nameservers []string) (string, error) {
|
||||
soa, err := lookupSoaByFqdn(fqdn, nameservers)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("[fqdn=%s] %w", fqdn, err)
|
||||
}
|
||||
return soa.primaryNs, nil
|
||||
}
|
||||
|
@ -145,7 +147,7 @@ func FindZoneByFqdn(fqdn string) (string, error) {
|
|||
func FindZoneByFqdnCustom(fqdn string, nameservers []string) (string, error) {
|
||||
soa, err := lookupSoaByFqdn(fqdn, nameservers)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("[fqdn=%s] %w", fqdn, err)
|
||||
}
|
||||
return soa.zone, nil
|
||||
}
|
||||
|
@ -170,35 +172,35 @@ func lookupSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error)
|
|||
|
||||
func fetchSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error) {
|
||||
var err error
|
||||
var in *dns.Msg
|
||||
var r *dns.Msg
|
||||
|
||||
labelIndexes := dns.Split(fqdn)
|
||||
for _, index := range labelIndexes {
|
||||
domain := fqdn[index:]
|
||||
|
||||
in, err = dnsQuery(domain, dns.TypeSOA, nameservers, true)
|
||||
r, err = dnsQuery(domain, dns.TypeSOA, nameservers, true)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if in == nil {
|
||||
if r == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
switch in.Rcode {
|
||||
switch r.Rcode {
|
||||
case dns.RcodeSuccess:
|
||||
// Check if we got a SOA RR in the answer section
|
||||
if len(in.Answer) == 0 {
|
||||
if len(r.Answer) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// CNAME records cannot/should not exist at the root of a zone.
|
||||
// So we skip a domain when a CNAME is found.
|
||||
if dnsMsgContainsCNAME(in) {
|
||||
if dnsMsgContainsCNAME(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ans := range in.Answer {
|
||||
for _, ans := range r.Answer {
|
||||
if soa, ok := ans.(*dns.SOA); ok {
|
||||
return newSoaCacheEntry(soa), nil
|
||||
}
|
||||
|
@ -207,36 +209,46 @@ func fetchSoaByFqdn(fqdn string, nameservers []string) (*soaCacheEntry, error) {
|
|||
// NXDOMAIN
|
||||
default:
|
||||
// Any response code other than NOERROR and NXDOMAIN is treated as error
|
||||
return nil, fmt.Errorf("unexpected response code '%s' for %s", dns.RcodeToString[in.Rcode], domain)
|
||||
return nil, &DNSError{Message: fmt.Sprintf("unexpected response for '%s'", domain), MsgOut: r}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not find the start of authority for %s%s", fqdn, formatDNSError(in, err))
|
||||
return nil, &DNSError{Message: fmt.Sprintf("could not find the start of authority for '%s'", fqdn), MsgOut: r, Err: err}
|
||||
}
|
||||
|
||||
// dnsMsgContainsCNAME checks for a CNAME answer in msg.
|
||||
func dnsMsgContainsCNAME(msg *dns.Msg) bool {
|
||||
for _, ans := range msg.Answer {
|
||||
if _, ok := ans.(*dns.CNAME); ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.ContainsFunc(msg.Answer, func(rr dns.RR) bool {
|
||||
_, ok := rr.(*dns.CNAME)
|
||||
return ok
|
||||
})
|
||||
}
|
||||
|
||||
func dnsQuery(fqdn string, rtype uint16, nameservers []string, recursive bool) (*dns.Msg, error) {
|
||||
m := createDNSMsg(fqdn, rtype, recursive)
|
||||
|
||||
var in *dns.Msg
|
||||
if len(nameservers) == 0 {
|
||||
return nil, &DNSError{Message: "empty list of nameservers"}
|
||||
}
|
||||
|
||||
var r *dns.Msg
|
||||
var err error
|
||||
var errAll error
|
||||
|
||||
for _, ns := range nameservers {
|
||||
in, err = sendDNSQuery(m, ns)
|
||||
if err == nil && len(in.Answer) > 0 {
|
||||
r, err = sendDNSQuery(m, ns)
|
||||
if err == nil && len(r.Answer) > 0 {
|
||||
break
|
||||
}
|
||||
|
||||
errAll = errors.Join(errAll, err)
|
||||
}
|
||||
return in, err
|
||||
|
||||
if err != nil {
|
||||
return r, errAll
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func createDNSMsg(fqdn string, rtype uint16, recursive bool) *dns.Msg {
|
||||
|
@ -254,37 +266,82 @@ 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}
|
||||
in, _, err := tcp.Exchange(m, ns)
|
||||
r, _, err := tcp.Exchange(m, ns)
|
||||
if err != nil {
|
||||
return r, &DNSError{Message: "DNS call error", MsgIn: m, NS: ns, Err: err}
|
||||
}
|
||||
|
||||
return in, err
|
||||
return r, nil
|
||||
}
|
||||
|
||||
udp := &dns.Client{Net: "udp", Timeout: dnsTimeout}
|
||||
in, _, err := udp.Exchange(m, ns)
|
||||
r, _, err := udp.Exchange(m, ns)
|
||||
|
||||
if in != nil && in.Truncated {
|
||||
if r != nil && r.Truncated {
|
||||
tcp := &dns.Client{Net: "tcp", Timeout: dnsTimeout}
|
||||
// If the TCP request succeeds, the "err" will reset to nil
|
||||
in, _, err = tcp.Exchange(m, ns)
|
||||
}
|
||||
|
||||
return in, err
|
||||
}
|
||||
|
||||
func formatDNSError(msg *dns.Msg, err error) string {
|
||||
var parts []string
|
||||
|
||||
if msg != nil {
|
||||
parts = append(parts, dns.RcodeToString[msg.Rcode])
|
||||
r, _, err = tcp.Exchange(m, ns)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
parts = append(parts, err.Error())
|
||||
return r, &DNSError{Message: "DNS call error", MsgIn: m, NS: ns, Err: err}
|
||||
}
|
||||
|
||||
if len(parts) > 0 {
|
||||
return ": " + strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
return ""
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// DNSError error related to DNS calls.
|
||||
type DNSError struct {
|
||||
Message string
|
||||
NS string
|
||||
MsgIn *dns.Msg
|
||||
MsgOut *dns.Msg
|
||||
Err error
|
||||
}
|
||||
|
||||
func (d *DNSError) Error() string {
|
||||
var details []string
|
||||
if d.NS != "" {
|
||||
details = append(details, "ns="+d.NS)
|
||||
}
|
||||
|
||||
if d.MsgIn != nil && len(d.MsgIn.Question) > 0 {
|
||||
details = append(details, fmt.Sprintf("question='%s'", formatQuestions(d.MsgIn.Question)))
|
||||
}
|
||||
|
||||
if d.MsgOut != nil {
|
||||
if d.MsgIn == nil || len(d.MsgIn.Question) == 0 {
|
||||
details = append(details, fmt.Sprintf("question='%s'", formatQuestions(d.MsgOut.Question)))
|
||||
}
|
||||
|
||||
details = append(details, "code="+dns.RcodeToString[d.MsgOut.Rcode])
|
||||
}
|
||||
|
||||
msg := "DNS error"
|
||||
if d.Message != "" {
|
||||
msg = d.Message
|
||||
}
|
||||
|
||||
if d.Err != nil {
|
||||
msg += ": " + d.Err.Error()
|
||||
}
|
||||
|
||||
if len(details) > 0 {
|
||||
msg += " [" + strings.Join(details, ", ") + "]"
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
func (d *DNSError) Unwrap() error {
|
||||
return d.Err
|
||||
}
|
||||
|
||||
func formatQuestions(questions []dns.Question) string {
|
||||
var parts []string
|
||||
for _, question := range questions {
|
||||
parts = append(parts, strings.ReplaceAll(strings.TrimPrefix(question.String(), ";"), "\t", " "))
|
||||
}
|
||||
|
||||
return strings.Join(parts, ";")
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package dns01
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -28,7 +30,6 @@ func TestLookupNameserversOK(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.fqdn, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -52,12 +53,11 @@ func TestLookupNameserversErr(t *testing.T) {
|
|||
{
|
||||
desc: "invalid tld",
|
||||
fqdn: "_null.n0n0.",
|
||||
error: "could not determine the zone",
|
||||
error: "could not find zone",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -109,7 +109,7 @@ var findXByFqdnTestCases = []struct {
|
|||
fqdn: "test.lego.zz.",
|
||||
zone: "lego.zz.",
|
||||
nameservers: []string{"8.8.8.8:53"},
|
||||
expectedError: "could not find the start of authority for test.lego.zz.: NXDOMAIN",
|
||||
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",
|
||||
|
@ -119,18 +119,19 @@ var findXByFqdnTestCases = []struct {
|
|||
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"},
|
||||
expectedError: "could not find the start of authority for mail.google.com.: read udp",
|
||||
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: "could not find the start of authority for test.ldez.com.",
|
||||
expectedError: "[fqdn=test.ldez.com.] could not find the start of authority for 'test.ldez.com.': empty list of nameservers",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -142,7 +143,7 @@ func TestFindZoneByFqdnCustom(t *testing.T) {
|
|||
zone, err := FindZoneByFqdnCustom(test.fqdn, test.nameservers)
|
||||
if test.expectedError != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), test.expectedError)
|
||||
assert.ErrorContains(t, err, test.expectedError)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.zone, zone)
|
||||
|
@ -159,7 +160,7 @@ func TestFindPrimaryNsByFqdnCustom(t *testing.T) {
|
|||
ns, err := FindPrimaryNsByFqdnCustom(test.fqdn, test.nameservers)
|
||||
if test.expectedError != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), test.expectedError)
|
||||
assert.ErrorContains(t, err, test.expectedError)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.primaryNs, ns)
|
||||
|
@ -197,3 +198,69 @@ func TestResolveConfServers(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSError_Error(t *testing.T) {
|
||||
msgIn := createDNSMsg("example.com.", dns.TypeTXT, true)
|
||||
|
||||
msgOut := createDNSMsg("example.org.", dns.TypeSOA, true)
|
||||
msgOut.Rcode = dns.RcodeNameError
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
err *DNSError
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "empty error",
|
||||
err: &DNSError{},
|
||||
expected: "DNS error",
|
||||
},
|
||||
{
|
||||
desc: "all fields",
|
||||
err: &DNSError{
|
||||
Message: "Oops",
|
||||
NS: "example.com.",
|
||||
MsgIn: msgIn,
|
||||
MsgOut: msgOut,
|
||||
Err: errors.New("I did it again"),
|
||||
},
|
||||
expected: "Oops: I did it again [ns=example.com., question='example.com. IN TXT', code=NXDOMAIN]",
|
||||
},
|
||||
{
|
||||
desc: "only NS",
|
||||
err: &DNSError{
|
||||
NS: "example.com.",
|
||||
},
|
||||
expected: "DNS error [ns=example.com.]",
|
||||
},
|
||||
{
|
||||
desc: "only MsgIn",
|
||||
err: &DNSError{
|
||||
MsgIn: msgIn,
|
||||
},
|
||||
expected: "DNS error [question='example.com. IN TXT']",
|
||||
},
|
||||
{
|
||||
desc: "only MsgOut",
|
||||
err: &DNSError{
|
||||
MsgOut: msgOut,
|
||||
},
|
||||
expected: "DNS error [question='example.org. IN SOA', code=NXDOMAIN]",
|
||||
},
|
||||
{
|
||||
desc: "only Err",
|
||||
err: &DNSError{
|
||||
Err: errors.New("I did it again"),
|
||||
},
|
||||
expected: "DNS error: I did it again",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.EqualError(t, test.err, test.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ func TestCheckDNSPropagation(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ClearFqdnCache()
|
||||
|
@ -69,7 +68,6 @@ func TestCheckAuthoritativeNss(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ClearFqdnCache()
|
||||
|
@ -104,7 +102,6 @@ func TestCheckAuthoritativeNssErr(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ClearFqdnCache()
|
||||
|
|
|
@ -69,7 +69,6 @@ func TestParseForwardedHeader(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ func TestProviderServer_GetAddress(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -99,7 +99,6 @@ func TestProber_Solve(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ 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-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -158,7 +158,8 @@ func validateNoBody(privateKey *rsa.PrivateKey, r *http.Request) error {
|
|||
return err
|
||||
}
|
||||
|
||||
jws, err := jose.ParseSigned(string(reqBody))
|
||||
sigAlgs := []jose.SignatureAlgorithm{jose.RS256}
|
||||
jws, err := jose.ParseSigned(string(reqBody), sigAlgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ func TestChallenge(t *testing.T) {
|
|||
_, apiURL := tester.SetupFakeAPI(t)
|
||||
|
||||
domain := "localhost"
|
||||
port := "23457"
|
||||
port := "24457"
|
||||
|
||||
mockValidate := func(_ *api.Core, _ string, chlng acme.Challenge) error {
|
||||
conn, err := tls.Dial("tcp", net.JoinHostPort(domain, port), &tls.Config{
|
||||
|
@ -75,7 +75,7 @@ func TestChallenge(t *testing.T) {
|
|||
solver := NewChallenge(
|
||||
core,
|
||||
mockValidate,
|
||||
&ProviderServer{port: "23457"},
|
||||
&ProviderServer{port: port},
|
||||
)
|
||||
|
||||
authz := acme.Authorization{
|
||||
|
@ -126,7 +126,7 @@ func TestChallengeIPaddress(t *testing.T) {
|
|||
_, apiURL := tester.SetupFakeAPI(t)
|
||||
|
||||
domain := "127.0.0.1"
|
||||
port := "23457"
|
||||
port := "24457"
|
||||
rd, _ := dns.ReverseAddr(domain)
|
||||
|
||||
mockValidate := func(_ *api.Core, _ string, chlng acme.Challenge) error {
|
||||
|
@ -141,7 +141,7 @@ func TestChallengeIPaddress(t *testing.T) {
|
|||
assert.Len(t, connState.PeerCertificates, 1, "Expected the challenge server to return exactly one certificate")
|
||||
|
||||
remoteCert := connState.PeerCertificates[0]
|
||||
assert.Len(t, remoteCert.DNSNames, 0, "Expected the challenge certificate to have no DNSNames entry in context of challenge for IP")
|
||||
assert.Empty(t, remoteCert.DNSNames, "Expected the challenge certificate to have no DNSNames entry in context of challenge for IP")
|
||||
assert.Len(t, remoteCert.IPAddresses, 1, "Expected the challenge certificate to have exactly one IPAddresses entry")
|
||||
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")
|
||||
|
@ -176,7 +176,7 @@ func TestChallengeIPaddress(t *testing.T) {
|
|||
solver := NewChallenge(
|
||||
core,
|
||||
mockValidate,
|
||||
&ProviderServer{port: "23457"},
|
||||
&ProviderServer{port: port},
|
||||
)
|
||||
|
||||
authz := acme.Authorization{
|
||||
|
|
|
@ -3,10 +3,10 @@ package cmd
|
|||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -55,17 +55,27 @@ type CertificatesStorage struct {
|
|||
pem bool
|
||||
pfx bool
|
||||
pfxPassword string
|
||||
pfxFormat string
|
||||
filename string // Deprecated
|
||||
}
|
||||
|
||||
// NewCertificatesStorage create a new certificates storage.
|
||||
func NewCertificatesStorage(ctx *cli.Context) *CertificatesStorage {
|
||||
pfxFormat := ctx.String("pfx.format")
|
||||
|
||||
switch pfxFormat {
|
||||
case "DES", "RC2", "SHA256":
|
||||
default:
|
||||
log.Fatalf("Invalid PFX format: %s", pfxFormat)
|
||||
}
|
||||
|
||||
return &CertificatesStorage{
|
||||
rootPath: filepath.Join(ctx.String("path"), baseCertificatesFolderName),
|
||||
archivePath: filepath.Join(ctx.String("path"), baseArchivesFolderName),
|
||||
pem: ctx.Bool("pem"),
|
||||
pfx: ctx.Bool("pfx"),
|
||||
pfxPassword: ctx.String("pfx.pass"),
|
||||
pfxFormat: pfxFormat,
|
||||
filename: ctx.String("filename"),
|
||||
}
|
||||
}
|
||||
|
@ -218,14 +228,9 @@ func (s *CertificatesStorage) WritePFXFile(domain string, certRes *certificate.R
|
|||
return fmt.Errorf("unable to load Certificate for domain %s: %w", domain, err)
|
||||
}
|
||||
|
||||
issuerCertPemBlock, _ := pem.Decode(certRes.IssuerCertificate)
|
||||
if issuerCertPemBlock == nil {
|
||||
return fmt.Errorf("unable to parse Issuer Certificate for domain %s", domain)
|
||||
}
|
||||
|
||||
issuerCert, err := x509.ParseCertificate(issuerCertPemBlock.Bytes)
|
||||
certChain, err := getCertificateChain(certRes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load Issuer Certificate for domain %s: %w", domain, err)
|
||||
return fmt.Errorf("unable to get certificate chain for domain %s: %w", domain, err)
|
||||
}
|
||||
|
||||
keyPemBlock, _ := pem.Decode(certRes.PrivateKey)
|
||||
|
@ -251,7 +256,12 @@ func (s *CertificatesStorage) WritePFXFile(domain string, certRes *certificate.R
|
|||
return fmt.Errorf("unsupported PrivateKey type '%s' for domain %s", keyPemBlock.Type, domain)
|
||||
}
|
||||
|
||||
pfxBytes, err := pkcs12.Encode(rand.Reader, privateKey, cert, []*x509.Certificate{issuerCert}, s.pfxPassword)
|
||||
encoder, err := getPFXEncoder(s.pfxFormat)
|
||||
if err != nil {
|
||||
return fmt.Errorf("PFX encoder: %w", err)
|
||||
}
|
||||
|
||||
pfxBytes, err := encoder.Encode(privateKey, cert, certChain, s.pfxPassword)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to encode PFX data for domain %s: %w", domain, err)
|
||||
}
|
||||
|
@ -285,6 +295,42 @@ func (s *CertificatesStorage) MoveToArchive(domain string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getCertificateChain(certRes *certificate.Resource) ([]*x509.Certificate, error) {
|
||||
chainCertPemBlock, rest := pem.Decode(certRes.IssuerCertificate)
|
||||
if chainCertPemBlock == nil {
|
||||
return nil, errors.New("unable to parse Issuer Certificate")
|
||||
}
|
||||
|
||||
var certChain []*x509.Certificate
|
||||
for chainCertPemBlock != nil {
|
||||
chainCert, err := x509.ParseCertificate(chainCertPemBlock.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse Chain Certificate: %w", err)
|
||||
}
|
||||
|
||||
certChain = append(certChain, chainCert)
|
||||
chainCertPemBlock, rest = pem.Decode(rest) // Try decoding the next pem block
|
||||
}
|
||||
|
||||
return certChain, nil
|
||||
}
|
||||
|
||||
func getPFXEncoder(pfxFormat string) (*pkcs12.Encoder, error) {
|
||||
var encoder *pkcs12.Encoder
|
||||
switch pfxFormat {
|
||||
case "SHA256":
|
||||
encoder = pkcs12.Modern2023
|
||||
case "DES":
|
||||
encoder = pkcs12.LegacyDES
|
||||
case "RC2":
|
||||
encoder = pkcs12.LegacyRC2
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid PFX format: %s", pfxFormat)
|
||||
}
|
||||
|
||||
return encoder, nil
|
||||
}
|
||||
|
||||
// sanitizedDomain Make sure no funny chars are in the cert names (like wildcards ;)).
|
||||
func sanitizedDomain(domain string) string {
|
||||
safe, err := idna.ToASCII(strings.NewReplacer(":", "-", "*", "_").Replace(domain))
|
||||
|
|
|
@ -84,10 +84,15 @@ func listCertificates(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
name, err := certcrypto.GetCertificateMainDomain(pCert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if names {
|
||||
fmt.Println(pCert.Subject.CommonName)
|
||||
fmt.Println(name)
|
||||
} else {
|
||||
fmt.Println(" Certificate Name:", pCert.Subject.CommonName)
|
||||
fmt.Println(" Certificate Name:", name)
|
||||
fmt.Println(" Domains:", strings.Join(pCert.DNSNames, ", "))
|
||||
fmt.Println(" Expiry Date:", pCert.NotAfter)
|
||||
fmt.Println(" Certificate Path:", filename)
|
||||
|
|
115
cmd/cmd_renew.go
115
cmd/cmd_renew.go
|
@ -18,12 +18,13 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
renewEnvAccountEmail = "LEGO_ACCOUNT_EMAIL"
|
||||
renewEnvCertDomain = "LEGO_CERT_DOMAIN"
|
||||
renewEnvCertPath = "LEGO_CERT_PATH"
|
||||
renewEnvCertKeyPath = "LEGO_CERT_KEY_PATH"
|
||||
renewEnvCertPEMPath = "LEGO_CERT_PEM_PATH"
|
||||
renewEnvCertPFXPath = "LEGO_CERT_PFX_PATH"
|
||||
renewEnvAccountEmail = "LEGO_ACCOUNT_EMAIL"
|
||||
renewEnvCertDomain = "LEGO_CERT_DOMAIN"
|
||||
renewEnvCertPath = "LEGO_CERT_PATH"
|
||||
renewEnvCertKeyPath = "LEGO_CERT_KEY_PATH"
|
||||
renewEnvIssuerCertKeyPath = "LEGO_ISSUER_CERT_PATH"
|
||||
renewEnvCertPEMPath = "LEGO_CERT_PEM_PATH"
|
||||
renewEnvCertPFXPath = "LEGO_CERT_PFX_PATH"
|
||||
)
|
||||
|
||||
func createRenew() *cli.Command {
|
||||
|
@ -34,7 +35,7 @@ func createRenew() *cli.Command {
|
|||
Before: func(ctx *cli.Context) error {
|
||||
// we require either domains or csr, but not both
|
||||
hasDomains := len(ctx.StringSlice("domains")) > 0
|
||||
hasCsr := len(ctx.String("csr")) > 0
|
||||
hasCsr := ctx.String("csr") != ""
|
||||
if hasDomains && hasCsr {
|
||||
log.Fatal("Please specify either --domains/-d or --csr/-c, but not both")
|
||||
}
|
||||
|
@ -53,11 +54,6 @@ func createRenew() *cli.Command {
|
|||
Name: "ari-enable",
|
||||
Usage: "Use the renewalInfo endpoint (draft-ietf-acme-ari) to check if a certificate should be renewed.",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ari-hash-name",
|
||||
Value: crypto.SHA256.String(),
|
||||
Usage: "The string representation of the hash expected by the renewalInfo endpoint (e.g. \"SHA-256\").",
|
||||
},
|
||||
&cli.DurationFlag{
|
||||
Name: "ari-wait-to-renew-duration",
|
||||
Usage: "The maximum duration you're willing to sleep for a renewal time returned by the renewalInfo endpoint.",
|
||||
|
@ -146,11 +142,7 @@ func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *Certif
|
|||
|
||||
var ariRenewalTime *time.Time
|
||||
if ctx.Bool("ari-enable") {
|
||||
if len(certificates) < 2 {
|
||||
log.Warnf("[%s] Certificate bundle does not contain issuer, cannot use the renewalInfo endpoint", domain)
|
||||
} else {
|
||||
ariRenewalTime = getARIRenewalTime(ctx, certificates[0], certificates[1], domain, client)
|
||||
}
|
||||
ariRenewalTime = getARIRenewalTime(ctx, cert, domain, client)
|
||||
if ariRenewalTime != nil {
|
||||
now := time.Now().UTC()
|
||||
// Figure out if we need to sleep before renewing.
|
||||
|
@ -207,6 +199,13 @@ func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *Certif
|
|||
AlwaysDeactivateAuthorizations: ctx.Bool("always-deactivate-authorizations"),
|
||||
}
|
||||
|
||||
if ctx.Bool("ari-enable") {
|
||||
request.ReplacesCertID, err = certificate.MakeARICertID(cert)
|
||||
if err != nil {
|
||||
log.Fatalf("Error while construction the ARI CertID for domain %s\n\t%v", domain, err)
|
||||
}
|
||||
}
|
||||
|
||||
certRes, err := client.Certificate.Obtain(request)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -214,23 +213,7 @@ func renewForDomains(ctx *cli.Context, client *lego.Client, certsStorage *Certif
|
|||
|
||||
certsStorage.SaveResource(certRes)
|
||||
|
||||
if ariRenewalTime != nil {
|
||||
// Post to the renewalInfo endpoint to indicate that we have renewed and replaced the certificate.
|
||||
err := client.Certificate.UpdateRenewalInfo(certificate.RenewalInfoRequest{
|
||||
Cert: certificates[0],
|
||||
Issuer: certificates[1],
|
||||
HashName: ctx.String("ari-hash-name"),
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("[%s] Failed to update renewal info: %v", domain, err)
|
||||
}
|
||||
}
|
||||
|
||||
meta[renewEnvCertDomain] = domain
|
||||
meta[renewEnvCertPath] = certsStorage.GetFileName(domain, ".crt")
|
||||
meta[renewEnvCertKeyPath] = certsStorage.GetFileName(domain, ".key")
|
||||
meta[renewEnvCertPEMPath] = certsStorage.GetFileName(domain, ".pem")
|
||||
meta[renewEnvCertPFXPath] = certsStorage.GetFileName(domain, ".pfx")
|
||||
addPathToMetadata(meta, domain, certRes, certsStorage)
|
||||
|
||||
return launchHook(ctx.String("renew-hook"), meta)
|
||||
}
|
||||
|
@ -241,7 +224,10 @@ func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *Certificat
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
domain := csr.Subject.CommonName
|
||||
domain, err := certcrypto.GetCSRMainDomain(csr)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %v", err)
|
||||
}
|
||||
|
||||
// load the cert resource from files.
|
||||
// We store the certificate, private key and metadata in different files
|
||||
|
@ -255,11 +241,7 @@ func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *Certificat
|
|||
|
||||
var ariRenewalTime *time.Time
|
||||
if ctx.Bool("ari-enable") {
|
||||
if len(certificates) < 2 {
|
||||
log.Warnf("[%s] Certificate bundle does not contain issuer, cannot use the renewalInfo endpoint", domain)
|
||||
} else {
|
||||
ariRenewalTime = getARIRenewalTime(ctx, certificates[0], certificates[1], domain, client)
|
||||
}
|
||||
ariRenewalTime = getARIRenewalTime(ctx, cert, domain, client)
|
||||
if ariRenewalTime != nil {
|
||||
now := time.Now().UTC()
|
||||
// Figure out if we need to sleep before renewing.
|
||||
|
@ -287,6 +269,13 @@ func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *Certificat
|
|||
AlwaysDeactivateAuthorizations: ctx.Bool("always-deactivate-authorizations"),
|
||||
}
|
||||
|
||||
if ctx.Bool("ari-enable") {
|
||||
request.ReplacesCertID, err = certificate.MakeARICertID(cert)
|
||||
if err != nil {
|
||||
log.Fatalf("Error while construction the ARI CertID for domain %s\n\t%v", domain, err)
|
||||
}
|
||||
}
|
||||
|
||||
certRes, err := client.Certificate.ObtainForCSR(request)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -294,21 +283,7 @@ func renewForCSR(ctx *cli.Context, client *lego.Client, certsStorage *Certificat
|
|||
|
||||
certsStorage.SaveResource(certRes)
|
||||
|
||||
if ariRenewalTime != nil {
|
||||
// Post to the renewalInfo endpoint to indicate that we have renewed and replaced the certificate.
|
||||
err := client.Certificate.UpdateRenewalInfo(certificate.RenewalInfoRequest{
|
||||
Cert: certificates[0],
|
||||
Issuer: certificates[1],
|
||||
HashName: ctx.String("ari-hash-name"),
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("[%s] Failed to update renewal info: %v", domain, err)
|
||||
}
|
||||
}
|
||||
|
||||
meta[renewEnvCertDomain] = domain
|
||||
meta[renewEnvCertPath] = certsStorage.GetFileName(domain, ".crt")
|
||||
meta[renewEnvCertKeyPath] = certsStorage.GetFileName(domain, ".key")
|
||||
addPathToMetadata(meta, domain, certRes, certsStorage)
|
||||
|
||||
return launchHook(ctx.String("renew-hook"), meta)
|
||||
}
|
||||
|
@ -331,23 +306,19 @@ func needRenewal(x509Cert *x509.Certificate, domain string, days int) bool {
|
|||
}
|
||||
|
||||
// getARIRenewalTime checks if the certificate needs to be renewed using the renewalInfo endpoint.
|
||||
func getARIRenewalTime(ctx *cli.Context, cert, issuer *x509.Certificate, domain string, client *lego.Client) *time.Time {
|
||||
func getARIRenewalTime(ctx *cli.Context, cert *x509.Certificate, domain string, client *lego.Client) *time.Time {
|
||||
if cert.IsCA {
|
||||
log.Fatalf("[%s] Certificate bundle starts with a CA certificate", domain)
|
||||
}
|
||||
|
||||
renewalInfo, err := client.Certificate.GetRenewalInfo(certificate.RenewalInfoRequest{
|
||||
Cert: cert,
|
||||
Issuer: issuer,
|
||||
HashName: ctx.String("ari-hash-name"),
|
||||
})
|
||||
renewalInfo, err := client.Certificate.GetRenewalInfo(certificate.RenewalInfoRequest{Cert: cert})
|
||||
if err != nil {
|
||||
if errors.Is(err, api.ErrNoARI) {
|
||||
// The server does not advertise a renewal info endpoint.
|
||||
log.Warnf("[%s] acme: %w", domain, err)
|
||||
log.Warnf("[%s] acme: %v", domain, err)
|
||||
return nil
|
||||
}
|
||||
log.Warnf("[%s] acme: calling renewal info endpoint: %w", domain, err)
|
||||
log.Warnf("[%s] acme: calling renewal info endpoint: %v", domain, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -366,6 +337,24 @@ func getARIRenewalTime(ctx *cli.Context, cert, issuer *x509.Certificate, domain
|
|||
return renewalTime
|
||||
}
|
||||
|
||||
func addPathToMetadata(meta map[string]string, domain string, certRes *certificate.Resource, certsStorage *CertificatesStorage) {
|
||||
meta[renewEnvCertDomain] = domain
|
||||
meta[renewEnvCertPath] = certsStorage.GetFileName(domain, certExt)
|
||||
meta[renewEnvCertKeyPath] = certsStorage.GetFileName(domain, keyExt)
|
||||
|
||||
if certRes.IssuerCertificate != nil {
|
||||
meta[renewEnvIssuerCertKeyPath] = certsStorage.GetFileName(domain, issuerExt)
|
||||
}
|
||||
|
||||
if certsStorage.pem {
|
||||
meta[renewEnvCertPEMPath] = certsStorage.GetFileName(domain, pemExt)
|
||||
}
|
||||
|
||||
if certsStorage.pfx {
|
||||
meta[renewEnvCertPFXPath] = certsStorage.GetFileName(domain, pfxExt)
|
||||
}
|
||||
}
|
||||
|
||||
func merge(prevDomains, nextDomains []string) []string {
|
||||
for _, next := range nextDomains {
|
||||
var found bool
|
||||
|
|
|
@ -48,7 +48,6 @@ func Test_merge(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -108,7 +107,6 @@ func Test_needRenewal(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
actual := needRenewal(test.x509Cert, "foo.com", test.days)
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ func createRun() *cli.Command {
|
|||
Before: func(ctx *cli.Context) error {
|
||||
// we require either domains or csr, but not both
|
||||
hasDomains := len(ctx.StringSlice("domains")) > 0
|
||||
hasCsr := len(ctx.String("csr")) > 0
|
||||
hasCsr := ctx.String("csr") != ""
|
||||
if hasDomains && hasCsr {
|
||||
log.Fatal("Please specify either --domains/-d or --csr/-c, but not both")
|
||||
}
|
||||
|
|
19
cmd/flags.go
19
cmd/flags.go
|
@ -18,6 +18,7 @@ func CreateFlags(defaultPath string) []cli.Flag {
|
|||
&cli.StringFlag{
|
||||
Name: "server",
|
||||
Aliases: []string{"s"},
|
||||
EnvVars: []string{"LEGO_SERVER"},
|
||||
Usage: "CA hostname (and optionally :port). The server certificate must be trusted in order to avoid further modifications to the client.",
|
||||
Value: lego.LEDirectoryProduction,
|
||||
},
|
||||
|
@ -132,13 +133,21 @@ func CreateFlags(defaultPath string) []cli.Flag {
|
|||
Usage: "Generate an additional .pem (base64) file by concatenating the .key and .crt files together.",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "pfx",
|
||||
Usage: "Generate an additional .pfx (PKCS#12) file by concatenating the .key and .crt and issuer .crt files together.",
|
||||
Name: "pfx",
|
||||
Usage: "Generate an additional .pfx (PKCS#12) file by concatenating the .key and .crt and issuer .crt files together.",
|
||||
EnvVars: []string{"LEGO_PFX"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pfx.pass",
|
||||
Usage: "The password used to encrypt the .pfx (PCKS#12) file.",
|
||||
Value: pkcs12.DefaultPassword,
|
||||
Name: "pfx.pass",
|
||||
Usage: "The password used to encrypt the .pfx (PCKS#12) file.",
|
||||
Value: pkcs12.DefaultPassword,
|
||||
EnvVars: []string{"LEGO_PFX_PASSWORD"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pfx.format",
|
||||
Usage: "The encoding format to use when encrypting the .pfx (PCKS#12) file. Supported: RC2, DES, SHA256.",
|
||||
Value: "RC2",
|
||||
EnvVars: []string{"LEGO_PFX_FORMAT"},
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "cert.timeout",
|
||||
|
|
|
@ -35,6 +35,7 @@ func allDNSCodes() string {
|
|||
"cloudxns",
|
||||
"conoha",
|
||||
"constellix",
|
||||
"cpanel",
|
||||
"derak",
|
||||
"desec",
|
||||
"designate",
|
||||
|
@ -66,6 +67,7 @@ func allDNSCodes() string {
|
|||
"hetzner",
|
||||
"hostingde",
|
||||
"hosttech",
|
||||
"httpnet",
|
||||
"httpreq",
|
||||
"hurricane",
|
||||
"hyperone",
|
||||
|
@ -86,6 +88,7 @@ func allDNSCodes() string {
|
|||
"liquidweb",
|
||||
"loopia",
|
||||
"luadns",
|
||||
"mailinabox",
|
||||
"metaname",
|
||||
"mydnsjp",
|
||||
"mythicbeasts",
|
||||
|
@ -116,7 +119,9 @@ func allDNSCodes() string {
|
|||
"sakuracloud",
|
||||
"scaleway",
|
||||
"selectel",
|
||||
"selectelv2",
|
||||
"servercow",
|
||||
"shellrent",
|
||||
"simply",
|
||||
"sonic",
|
||||
"stackpath",
|
||||
|
@ -131,6 +136,7 @@ func allDNSCodes() string {
|
|||
"vkcloud",
|
||||
"vscale",
|
||||
"vultr",
|
||||
"webnames",
|
||||
"websupport",
|
||||
"wedos",
|
||||
"yandex",
|
||||
|
@ -306,18 +312,22 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "AZURE_CLIENT_CERTIFICATE_PATH": Client certificate path`)
|
||||
ew.writeln(` - "AZURE_CLIENT_ID": Client ID`)
|
||||
ew.writeln(` - "AZURE_CLIENT_SECRET": Client secret`)
|
||||
ew.writeln(` - "AZURE_RESOURCE_GROUP": DNS zone resource group`)
|
||||
ew.writeln(` - "AZURE_SUBSCRIPTION_ID": DNS zone subscription ID`)
|
||||
ew.writeln(` - "AZURE_TENANT_ID": Tenant ID`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "AZURE_AUTH_METHOD": Specify which authentication method to use`)
|
||||
ew.writeln(` - "AZURE_AUTH_MSI_TIMEOUT": Managed Identity timeout duration`)
|
||||
ew.writeln(` - "AZURE_ENVIRONMENT": Azure environment, one of: public, usgovernment, and china`)
|
||||
ew.writeln(` - "AZURE_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "AZURE_PRIVATE_ZONE": Set to true to use Azure Private DNS Zones and not public`)
|
||||
ew.writeln(` - "AZURE_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "AZURE_RESOURCE_GROUP": DNS zone resource group`)
|
||||
ew.writeln(` - "AZURE_SERVICEDISCOVERY_FILTER": Advanced ServiceDiscovery filter using Kusto query condition`)
|
||||
ew.writeln(` - "AZURE_SUBSCRIPTION_ID": DNS zone subscription ID`)
|
||||
ew.writeln(` - "AZURE_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
ew.writeln(` - "AZURE_ZONE_NAME": Zone name to use inside Azure DNS service to add the TXT record in`)
|
||||
|
||||
|
@ -606,6 +616,30 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/constellix`)
|
||||
|
||||
case "cpanel":
|
||||
// generated from: providers/dns/cpanel/cpanel.toml
|
||||
ew.writeln(`Configuration for CPanel/WHM.`)
|
||||
ew.writeln(`Code: 'cpanel'`)
|
||||
ew.writeln(`Since: 'v4.16.0'`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "CPANEL_BASE_URL": API server URL`)
|
||||
ew.writeln(` - "CPANEL_TOKEN": API token`)
|
||||
ew.writeln(` - "CPANEL_USERNAME": username`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "CPANEL_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "CPANEL_MODE": use cpanel API or WHM API (Default: cpanel)`)
|
||||
ew.writeln(` - "CPANEL_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "CPANEL_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "CPANEL_REGION": The region`)
|
||||
ew.writeln(` - "CPANEL_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/cpanel`)
|
||||
|
||||
case "derak":
|
||||
// generated from: providers/dns/derak/derak.toml
|
||||
ew.writeln(`Configuration for Derak Cloud.`)
|
||||
|
@ -960,6 +994,7 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "EFFICIENTIP_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "EFFICIENTIP_INSECURE_SKIP_VERIFY": Whether or not to verify EfficientIP API certificate`)
|
||||
ew.writeln(` - "EFFICIENTIP_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "EFFICIENTIP_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "EFFICIENTIP_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
@ -1070,7 +1105,8 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "GANDIV5_API_KEY": API key`)
|
||||
ew.writeln(` - "GANDIV5_API_KEY": API key (Deprecated)`)
|
||||
ew.writeln(` - "GANDIV5_PERSONAL_ACCESS_TOKEN": Personal Access Token`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
|
@ -1101,6 +1137,7 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln(` - "GCE_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "GCE_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "GCE_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
ew.writeln(` - "GCE_ZONE_ID": Allows to skip the automatic detection of the zone`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/gcloud`)
|
||||
|
@ -1248,6 +1285,27 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/hosttech`)
|
||||
|
||||
case "httpnet":
|
||||
// generated from: providers/dns/httpnet/httpnet.toml
|
||||
ew.writeln(`Configuration for http.net.`)
|
||||
ew.writeln(`Code: 'httpnet'`)
|
||||
ew.writeln(`Since: 'v4.15.0'`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "HTTPNET_API_KEY": API key`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "HTTPNET_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "HTTPNET_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "HTTPNET_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "HTTPNET_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
ew.writeln(` - "HTTPNET_ZONE_NAME": Zone name in ACE format`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/httpnet`)
|
||||
|
||||
case "httpreq":
|
||||
// generated from: providers/dns/httpreq/httpreq.toml
|
||||
ew.writeln(`Configuration for HTTP request.`)
|
||||
|
@ -1490,7 +1548,6 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln(` - "IPV64_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "IPV64_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "IPV64_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "IPV64_SEQUENCE_INTERVAL": Time between sequential requests`)
|
||||
ew.writeln(` - "IPV64_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
||||
ew.writeln()
|
||||
|
@ -1610,17 +1667,17 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "LIQUID_WEB_PASSWORD": Storm API Password`)
|
||||
ew.writeln(` - "LIQUID_WEB_USERNAME": Storm API Username`)
|
||||
ew.writeln(` - "LIQUID_WEB_ZONE": DNS Zone`)
|
||||
ew.writeln(` - "LWAPI_PASSWORD": Liquid Web API Password`)
|
||||
ew.writeln(` - "LWAPI_USERNAME": Liquid Web API Username`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "LIQUID_WEB_HTTP_TIMEOUT": Maximum waiting time for the DNS records to be created (not verified)`)
|
||||
ew.writeln(` - "LIQUID_WEB_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "LIQUID_WEB_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "LIQUID_WEB_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
ew.writeln(` - "LIQUID_WEB_URL": Storm API endpoint`)
|
||||
ew.writeln(` - "LWAPI_HTTP_TIMEOUT": Maximum waiting time for the DNS records to be created (not verified)`)
|
||||
ew.writeln(` - "LWAPI_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "LWAPI_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "LWAPI_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
ew.writeln(` - "LWAPI_URL": Liquid Web API endpoint`)
|
||||
ew.writeln(` - "LWAPI_ZONE": DNS Zone`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/liquidweb`)
|
||||
|
@ -1668,6 +1725,26 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/luadns`)
|
||||
|
||||
case "mailinabox":
|
||||
// generated from: providers/dns/mailinabox/mailinabox.toml
|
||||
ew.writeln(`Configuration for Mail-in-a-Box.`)
|
||||
ew.writeln(`Code: 'mailinabox'`)
|
||||
ew.writeln(`Since: 'v4.16.0'`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "MAILINABOX_BASE_URL": Base API URL (ex: https://box.example.com)`)
|
||||
ew.writeln(` - "MAILINABOX_EMAIL": User email`)
|
||||
ew.writeln(` - "MAILINABOX_PASSWORD": User password`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "MAILINABOX_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "MAILINABOX_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/mailinabox`)
|
||||
|
||||
case "metaname":
|
||||
// generated from: providers/dns/metaname/metaname.toml
|
||||
ew.writeln(`Configuration for Metaname.`)
|
||||
|
@ -2008,6 +2085,7 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln(` - "OTC_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "OTC_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "OTC_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "OTC_SEQUENCE_INTERVAL": Time between sequential requests`)
|
||||
ew.writeln(` - "OTC_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
||||
ew.writeln()
|
||||
|
@ -2021,9 +2099,11 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "OVH_APPLICATION_KEY": Application key`)
|
||||
ew.writeln(` - "OVH_APPLICATION_SECRET": Application secret`)
|
||||
ew.writeln(` - "OVH_CONSUMER_KEY": Consumer key`)
|
||||
ew.writeln(` - "OVH_APPLICATION_KEY": Application key (Application Key authentication)`)
|
||||
ew.writeln(` - "OVH_APPLICATION_SECRET": Application secret (Application Key authentication)`)
|
||||
ew.writeln(` - "OVH_CLIENT_ID": Client ID (OAuth2)`)
|
||||
ew.writeln(` - "OVH_CLIENT_SECRET": Client secret (OAuth2)`)
|
||||
ew.writeln(` - "OVH_CONSUMER_KEY": Consumer key (Application Key authentication)`)
|
||||
ew.writeln(` - "OVH_ENDPOINT": Endpoint URL (ovh-eu or ovh-ca)`)
|
||||
ew.writeln()
|
||||
|
||||
|
@ -2049,6 +2129,7 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "PDNS_API_VERSION": Skip API version autodetection and use the provided version number.`)
|
||||
ew.writeln(` - "PDNS_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "PDNS_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "PDNS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
|
@ -2158,6 +2239,8 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln(` - "REGRU_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "REGRU_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "REGRU_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "REGRU_TLS_CERT": authentication certificate`)
|
||||
ew.writeln(` - "REGRU_TLS_KEY": authentication private key`)
|
||||
ew.writeln(` - "REGRU_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
||||
ew.writeln()
|
||||
|
@ -2223,6 +2306,7 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln(` - "AWS_REGION": Managed by the AWS client ('AWS_REGION_FILE' is not supported)`)
|
||||
ew.writeln(` - "AWS_SDK_LOAD_CONFIG": Managed by the AWS client. Retrieve the region from the CLI config file ('AWS_SDK_LOAD_CONFIG_FILE' is not supported)`)
|
||||
ew.writeln(` - "AWS_SECRET_ACCESS_KEY": Managed by the AWS client. Secret access key ('AWS_SECRET_ACCESS_KEY_FILE' is not supported, use 'AWS_SHARED_CREDENTIALS_FILE' instead)`)
|
||||
ew.writeln(` - "AWS_WAIT_FOR_RECORD_SETS_CHANGED": Wait for changes to be INSYNC (it can be unstable)`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
|
@ -2284,14 +2368,15 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "SCALEWAY_API_TOKEN": API token`)
|
||||
ew.writeln(` - "SCALEWAY_PROJECT_ID": Project to use (optional)`)
|
||||
ew.writeln(` - "SCW_PROJECT_ID": Project to use (optional)`)
|
||||
ew.writeln(` - "SCW_SECRET_KEY": Secret key`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "SCALEWAY_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "SCALEWAY_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "SCALEWAY_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
ew.writeln(` - "SCW_ACCESS_KEY": Access key`)
|
||||
ew.writeln(` - "SCW_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "SCW_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "SCW_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/scaleway`)
|
||||
|
@ -2317,6 +2402,30 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/selectel`)
|
||||
|
||||
case "selectelv2":
|
||||
// generated from: providers/dns/selectelv2/selectelv2.toml
|
||||
ew.writeln(`Configuration for Selectel v2.`)
|
||||
ew.writeln(`Code: 'selectelv2'`)
|
||||
ew.writeln(`Since: 'v4.17.0'`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "SELECTELV2_ACCOUNT_ID": Selectel account ID (INT)`)
|
||||
ew.writeln(` - "SELECTELV2_PASSWORD": Openstack username's password`)
|
||||
ew.writeln(` - "SELECTELV2_PROJECT_ID": Cloud project ID (UUID)`)
|
||||
ew.writeln(` - "SELECTELV2_USERNAME": Openstack username`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "SELECTELV2_BASE_URL": API endpoint URL`)
|
||||
ew.writeln(` - "SELECTELV2_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "SELECTELV2_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "SELECTELV2_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "SELECTELV2_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/selectelv2`)
|
||||
|
||||
case "servercow":
|
||||
// generated from: providers/dns/servercow/servercow.toml
|
||||
ew.writeln(`Configuration for Servercow.`)
|
||||
|
@ -2338,6 +2447,27 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/servercow`)
|
||||
|
||||
case "shellrent":
|
||||
// generated from: providers/dns/shellrent/shellrent.toml
|
||||
ew.writeln(`Configuration for Shellrent.`)
|
||||
ew.writeln(`Code: 'shellrent'`)
|
||||
ew.writeln(`Since: 'v4.16.0'`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "SHELLRENT_TOKEN": Token`)
|
||||
ew.writeln(` - "SHELLRENT_USERNAME": Username`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "SHELLRENT_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "SHELLRENT_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "SHELLRENT_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "SHELLRENT_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/shellrent`)
|
||||
|
||||
case "simply":
|
||||
// generated from: providers/dns/simply/simply.toml
|
||||
ew.writeln(`Configuration for Simply.com.`)
|
||||
|
@ -2638,6 +2768,26 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/vultr`)
|
||||
|
||||
case "webnames":
|
||||
// generated from: providers/dns/webnames/webnames.toml
|
||||
ew.writeln(`Configuration for Webnames.`)
|
||||
ew.writeln(`Code: 'webnames'`)
|
||||
ew.writeln(`Since: 'v4.15.0'`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "WEBNAMES_API_KEY": Domain API key`)
|
||||
ew.writeln()
|
||||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "WEBNAMES_HTTP_TIMEOUT": API request timeout`)
|
||||
ew.writeln(` - "WEBNAMES_POLLING_INTERVAL": Time between DNS propagation check`)
|
||||
ew.writeln(` - "WEBNAMES_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
|
||||
ew.writeln(` - "WEBNAMES_TTL": The TTL of the TXT record used for the DNS challenge`)
|
||||
|
||||
ew.writeln()
|
||||
ew.writeln(`More information: https://go-acme.github.io/lego/dns/webnames`)
|
||||
|
||||
case "websupport":
|
||||
// generated from: providers/dns/websupport/websupport.toml
|
||||
ew.writeln(`Configuration for Websupport.`)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.PHONY: default clean hugo hugo-build
|
||||
|
||||
default: hugo
|
||||
default: clean hugo
|
||||
|
||||
clean:
|
||||
rm -rf public/
|
||||
|
|
|
@ -70,7 +70,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
|
||||
## More information
|
||||
|
||||
- [API documentation](https://www.alibabacloud.com/help/doc-detail/42875.htm)
|
||||
- [API documentation](https://www.alibabacloud.com/help/en/alibaba-cloud-dns/latest/api-alidns-2015-01-09-dir-parsing-records)
|
||||
- [Go client](https://github.com/aliyun/alibaba-cloud-sdk-go)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
|
|
|
@ -48,15 +48,12 @@ lego --domains example.com --email your_example@email.com --dns azuredns run
|
|||
### Using Managed Identity (Azure VM)
|
||||
|
||||
AZURE_TENANT_ID=<your service principal tenant ID> \
|
||||
AZURE_SUBSCRIPTION_ID=<your target zone subscription ID> \
|
||||
AZURE_RESOURCE_GROUP=<your target zone resource group name> \
|
||||
lego --domains example.com --email your_example@email.com --dns azuredns run
|
||||
|
||||
### Using Managed Identity (Azure Arc)
|
||||
|
||||
AZURE_TENANT_ID=<your service principal tenant ID> \
|
||||
AZURE_SUBSCRIPTION_ID=<your target zone subscription ID> \
|
||||
AZURE_RESOURCE_GROUP=<your target zone resource group name> \
|
||||
IMDS_ENDPOINT=http://localhost:40342 \
|
||||
IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token \
|
||||
lego --domains example.com --email your_example@email.com --dns azuredns run
|
||||
|
@ -70,10 +67,9 @@ lego --domains example.com --email your_example@email.com --dns azuredns run
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `AZURE_CLIENT_CERTIFICATE_PATH` | Client certificate path |
|
||||
| `AZURE_CLIENT_ID` | Client ID |
|
||||
| `AZURE_CLIENT_SECRET` | Client secret |
|
||||
| `AZURE_RESOURCE_GROUP` | DNS zone resource group |
|
||||
| `AZURE_SUBSCRIPTION_ID` | DNS zone subscription ID |
|
||||
| `AZURE_TENANT_ID` | Tenant ID |
|
||||
|
||||
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
||||
|
@ -84,10 +80,15 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|--------------------------------|-------------|
|
||||
| `AZURE_AUTH_METHOD` | Specify which authentication method to use |
|
||||
| `AZURE_AUTH_MSI_TIMEOUT` | Managed Identity timeout duration |
|
||||
| `AZURE_ENVIRONMENT` | Azure environment, one of: public, usgovernment, and china |
|
||||
| `AZURE_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `AZURE_PRIVATE_ZONE` | Set to true to use Azure Private DNS Zones and not public |
|
||||
| `AZURE_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `AZURE_RESOURCE_GROUP` | DNS zone resource group |
|
||||
| `AZURE_SERVICEDISCOVERY_FILTER` | Advanced ServiceDiscovery filter using Kusto query condition |
|
||||
| `AZURE_SUBSCRIPTION_ID` | DNS zone subscription ID |
|
||||
| `AZURE_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
| `AZURE_ZONE_NAME` | Zone name to use inside Azure DNS service to add the TXT record in |
|
||||
|
||||
|
@ -96,19 +97,75 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
|
||||
## Description
|
||||
|
||||
Azure Credentials are automatically detected in the following locations and prioritized in the following order:
|
||||
Several authentication methods can be used to authenticate against Azure DNS API.
|
||||
|
||||
### Default Azure Credentials (default option)
|
||||
|
||||
Default Azure Credentials automatically detects in the following locations and prioritized in the following order:
|
||||
|
||||
1. Environment variables for client secret: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET`
|
||||
2. Environment variables for client certificate: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_CERTIFICATE_PATH`
|
||||
3. Workload identity for resources hosted in Azure environment (see below)
|
||||
4. Shared credentials file (defaults to `~/.azure`), used by Azure CLI
|
||||
4. Shared credentials (defaults to `~/.azure` folder), used by Azure CLI
|
||||
|
||||
Link:
|
||||
- [Azure Authentication](https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication)
|
||||
|
||||
### Environment variables
|
||||
|
||||
#### Service Discovery
|
||||
|
||||
Lego automatically finds all visible Azure (private) DNS zones using [Azure ResourceGraph query](https://learn.microsoft.com/en-us/azure/governance/resource-graph/).
|
||||
This can be limited by specifying environment variable `AZURE_SUBSCRIPTION_ID` and/or `AZURE_RESOURCE_GROUP` which limits the
|
||||
DNS zones to only a subscription or to one resourceGroup.
|
||||
|
||||
Additionally environment variable `AZURE_SERVICEDISCOVERY_FILTER` can be used to filter DNS zones with an addition Kusto filter eg:
|
||||
|
||||
```
|
||||
resources
|
||||
| where type =~ "microsoft.network/dnszones"
|
||||
| ${AZURE_SERVICEDISCOVERY_FILTER}
|
||||
| project subscriptionId, resourceGroup, name
|
||||
```
|
||||
|
||||
|
||||
#### Client secret
|
||||
|
||||
The Azure Credentials can be configured using the following environment variables:
|
||||
* AZURE_CLIENT_ID = "Client ID"
|
||||
* AZURE_CLIENT_SECRET = "Client secret"
|
||||
* AZURE_TENANT_ID = "Tenant ID"
|
||||
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `env`.
|
||||
|
||||
#### Client certificate
|
||||
|
||||
The Azure Credentials can be configured using the following environment variables:
|
||||
* AZURE_CLIENT_ID = "Client ID"
|
||||
* AZURE_CLIENT_CERTIFICATE_PATH = "Client certificate path"
|
||||
* AZURE_TENANT_ID = "Tenant ID"
|
||||
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `env`.
|
||||
|
||||
### Workload identity
|
||||
|
||||
#### Azure Managed Identity
|
||||
Workload identity allows workloads running Azure Kubernetes Services (AKS) clusters to authenticate as an Azure AD application identity using federated credentials.
|
||||
|
||||
This must be configured in kubernetes workload deployment in one hand and on the Azure AD application registration in the other hand.
|
||||
|
||||
Here is a summary of the steps to follow to use it :
|
||||
* create a `ServiceAccount` resource, add following annotations to reference the targeted Azure AD application registration : `azure.workload.identity/client-id` and `azure.workload.identity/tenant-id`.
|
||||
* on the `Deployment` resource you must reference the previous `ServiceAccount` and add the following label : `azure.workload.identity/use: "true"`.
|
||||
* create a federated credentials of type `Kubernetes accessing Azure resources`, add the cluster issuer URL and add the namespace and name of your kubernetes service account.
|
||||
|
||||
Link :
|
||||
- [Azure AD Workload identity](https://azure.github.io/azure-workload-identity/docs/topics/service-account-labels-and-annotations.html)
|
||||
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `wli`.
|
||||
|
||||
### Azure Managed Identity
|
||||
|
||||
#### Azure Managed Identity (with Azure workload)
|
||||
|
||||
The Azure Managed Identity service allows linking Azure AD identities to Azure resources, without needing to manually manage client IDs and secrets.
|
||||
|
||||
|
@ -138,6 +195,11 @@ az role assignment create \
|
|||
--scope "/subscriptions/${AZURE_SUBSCRIPTION_ID}/resourceGroups/${AZURE_RESOURCE_GROUP}/providers/Microsoft.Network/dnszones/${AZURE_DNS_ZONE}/TXT/${AZ_RECORD_SET}"
|
||||
```
|
||||
|
||||
A timeout wrapper is configured for this authentication method.
|
||||
The duration can be configured by setting the `AZURE_AUTH_MSI_TIMEOUT`.
|
||||
The default timeout is 2 seconds.
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `msi`.
|
||||
|
||||
#### Azure Managed Identity (with Azure Arc)
|
||||
|
||||
The Azure Arc agent provides the ability to use a Managed Identity on resources hosted outside of Azure
|
||||
|
@ -146,22 +208,26 @@ The Azure Arc agent provides the ability to use a Managed Identity on resources
|
|||
While the upstream `azidentity` SDK will try to automatically identify and use the Azure Arc metadata service,
|
||||
if you get `azuredns: DefaultAzureCredential: failed to acquire a token.` error messages,
|
||||
you may need to set the environment variables:
|
||||
* `IMDS_ENDPOINT=http://localhost:40342`
|
||||
* `IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token`
|
||||
* `IMDS_ENDPOINT=http://localhost:40342`
|
||||
* `IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token`
|
||||
|
||||
#### Workload identity for AKS
|
||||
A timeout wrapper is configured for this authentication method.
|
||||
The duration can be configured by setting the `AZURE_AUTH_MSI_TIMEOUT`.
|
||||
The default timeout is 2 seconds.
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `msi`.
|
||||
|
||||
Workload identity allows workloads running Azure Kubernetes Services (AKS) clusters to authenticate as an Azure AD application identity using federated credentials.
|
||||
### Azure CLI
|
||||
|
||||
This must be configured in kubernetes workload deployment in one hand and on the Azure AD application registration in the other hand.
|
||||
The Azure CLI is a command-line tool provided by Microsoft to interact with Azure resources.
|
||||
It provides an easy way to authenticate by simply running `az login` command.
|
||||
The generated token will be cached by default in the `~/.azure` folder.
|
||||
|
||||
Here is a summary of the steps to follow to use it :
|
||||
* create a `ServiceAccount` resource, add following annotations to reference the targeted Azure AD application registration : `azure.workload.identity/client-id` and `azure.workload.identity/tenant-id`.
|
||||
* on the `Deployment` resource you must reference the previous `ServiceAccount` and add the following label : `azure.workload.identity/use: "true"`.
|
||||
* create a fedreated credentials of type `Kubernetes accessing Azure resources`, add the cluster issuer URL and add the namespace and name of your kubernetes service account.
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `cli`.
|
||||
|
||||
Link :
|
||||
- [Azure AD Workload identity](https://azure.github.io/azure-workload-identity/docs/topics/service-account-labels-and-annotations.html)
|
||||
### Open ID Connect
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
|
||||
|
|
83
docs/content/dns/zz_gen_cpanel.md
Normal file
83
docs/content/dns/zz_gen_cpanel.md
Normal file
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
title: "CPanel/WHM"
|
||||
date: 2019-03-03T16:39:46+01:00
|
||||
draft: false
|
||||
slug: cpanel
|
||||
dnsprovider:
|
||||
since: "v4.16.0"
|
||||
code: "cpanel"
|
||||
url: "https://cpanel.net/"
|
||||
---
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/cpanel/cpanel.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
|
||||
|
||||
Configuration for [CPanel/WHM](https://cpanel.net/).
|
||||
|
||||
|
||||
<!--more-->
|
||||
|
||||
- Code: `cpanel`
|
||||
- Since: v4.16.0
|
||||
|
||||
|
||||
Here is an example bash command using the CPanel/WHM provider:
|
||||
|
||||
```bash
|
||||
### CPANEL (default)
|
||||
|
||||
CPANEL_USERNAME = "yyyy"
|
||||
CPANEL_TOKEN = "xxxx"
|
||||
CPANEL_BASE_URL = "https://example.com:2083" \
|
||||
lego --email you@example.com --dns cpanel --domains my.example.org run
|
||||
|
||||
## WHM
|
||||
|
||||
CPANEL_MODE = whm
|
||||
CPANEL_USERNAME = "yyyy"
|
||||
CPANEL_TOKEN = "xxxx"
|
||||
CPANEL_BASE_URL = "https://example.com:2087" \
|
||||
lego --email you@example.com --dns cpanel --domains my.example.org run
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Credentials
|
||||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `CPANEL_BASE_URL` | API server URL |
|
||||
| `CPANEL_TOKEN` | API token |
|
||||
| `CPANEL_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 |
|
||||
|--------------------------------|-------------|
|
||||
| `CPANEL_HTTP_TIMEOUT` | API request timeout |
|
||||
| `CPANEL_MODE` | use cpanel API or WHM API (Default: cpanel) |
|
||||
| `CPANEL_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `CPANEL_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `CPANEL_REGION` | The region |
|
||||
| `CPANEL_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/cpanel/cpanel.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
|
@ -98,6 +98,10 @@ For more information, you can read about the different methods of authentication
|
|||
- [Keystone username/password](https://docs.openstack.org/keystone/latest/user/supported_clients.html)
|
||||
- [Keystone application credentials](https://docs.openstack.org/keystone/latest/user/application_credentials.html)
|
||||
|
||||
Public cloud providers with support for Designate:
|
||||
|
||||
- [Fuga Cloud](https://fuga.cloud/)
|
||||
|
||||
|
||||
|
||||
## More information
|
||||
|
|
|
@ -61,7 +61,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
|
||||
## More information
|
||||
|
||||
- [API documentation](https://www.do.de/wiki/LetsEncrypt_-_Entwickler)
|
||||
- [API documentation](https://www.do.de/wiki/freie-ssl-tls-zertifikate-ueber-acme/)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/dode/dode.toml -->
|
||||
|
|
|
@ -54,6 +54,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
| Environment Variable Name | Description |
|
||||
|--------------------------------|-------------|
|
||||
| `EFFICIENTIP_HTTP_TIMEOUT` | API request timeout |
|
||||
| `EFFICIENTIP_INSECURE_SKIP_VERIFY` | Whether or not to verify EfficientIP API certificate |
|
||||
| `EFFICIENTIP_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `EFFICIENTIP_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `EFFICIENTIP_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
|
|
@ -26,7 +26,7 @@ Configuration for [Gandi Live DNS (v5)](https://www.gandi.net).
|
|||
Here is an example bash command using the Gandi Live DNS (v5) provider:
|
||||
|
||||
```bash
|
||||
GANDIV5_API_KEY=abcdefghijklmnopqrstuvwx \
|
||||
GANDIV5_PERSONAL_ACCESS_TOKEN=abcdefghijklmnopqrstuvwx \
|
||||
lego --email you@example.com --dns gandiv5 --domains my.example.org run
|
||||
```
|
||||
|
||||
|
@ -37,7 +37,8 @@ lego --email you@example.com --dns gandiv5 --domains my.example.org run
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `GANDIV5_API_KEY` | API key |
|
||||
| `GANDIV5_API_KEY` | API key (Deprecated) |
|
||||
| `GANDIV5_PERSONAL_ACCESS_TOKEN` | Personal Access 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" >}}).
|
||||
|
|
|
@ -58,6 +58,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
| `GCE_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `GCE_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `GCE_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
| `GCE_ZONE_ID` | Allows to skip the automatic detection of the zone |
|
||||
|
||||
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" >}}).
|
||||
|
|
|
@ -57,6 +57,12 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
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" >}}).
|
||||
|
||||
GoDaddy has recently (2024-04) updated the account requirements to access parts of their production Domains API:
|
||||
|
||||
- Availability API: Limited to accounts with 50 or more domains.
|
||||
- Management and DNS APIs: Limited to accounts with 10 or more domains and/or an active Discount Domain Club plan.
|
||||
|
||||
https://community.letsencrypt.org/t/getting-unauthorized-url-error-while-trying-to-get-cert-for-subdomains/217329/12
|
||||
|
||||
|
||||
|
||||
|
|
68
docs/content/dns/zz_gen_httpnet.md
Normal file
68
docs/content/dns/zz_gen_httpnet.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
title: "http.net"
|
||||
date: 2019-03-03T16:39:46+01:00
|
||||
draft: false
|
||||
slug: httpnet
|
||||
dnsprovider:
|
||||
since: "v4.15.0"
|
||||
code: "httpnet"
|
||||
url: "https://www.http.net/"
|
||||
---
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/httpnet/httpnet.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
|
||||
|
||||
Configuration for [http.net](https://www.http.net/).
|
||||
|
||||
|
||||
<!--more-->
|
||||
|
||||
- Code: `httpnet`
|
||||
- Since: v4.15.0
|
||||
|
||||
|
||||
Here is an example bash command using the http.net provider:
|
||||
|
||||
```bash
|
||||
HTTPNET_API_KEY=xxxxxxxx \
|
||||
lego --email you@example.com --dns httpnet --domains my.example.org run
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Credentials
|
||||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `HTTPNET_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 |
|
||||
|--------------------------------|-------------|
|
||||
| `HTTPNET_HTTP_TIMEOUT` | API request timeout |
|
||||
| `HTTPNET_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `HTTPNET_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `HTTPNET_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
| `HTTPNET_ZONE_NAME` | Zone name in ACE format |
|
||||
|
||||
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.http.net/docs/api/#dns)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/httpnet/httpnet.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
|
@ -50,7 +50,6 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
| `IPV64_HTTP_TIMEOUT` | API request timeout |
|
||||
| `IPV64_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `IPV64_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `IPV64_SEQUENCE_INTERVAL` | Time between sequential requests |
|
||||
| `IPV64_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
||||
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
||||
|
|
|
@ -26,9 +26,8 @@ Configuration for [Liquid Web](https://liquidweb.com).
|
|||
Here is an example bash command using the Liquid Web provider:
|
||||
|
||||
```bash
|
||||
LIQUID_WEB_USERNAME=someuser \
|
||||
LIQUID_WEB_PASSWORD=somepass \
|
||||
LIQUID_WEB_ZONE=tacoman.com.net \
|
||||
LWAPI_USERNAME=someuser \
|
||||
LWAPI_PASSWORD=somepass \
|
||||
lego --email you@example.com --dns liquidweb --domains my.example.org run
|
||||
```
|
||||
|
||||
|
@ -39,9 +38,8 @@ lego --email you@example.com --dns liquidweb --domains my.example.org run
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `LIQUID_WEB_PASSWORD` | Storm API Password |
|
||||
| `LIQUID_WEB_USERNAME` | Storm API Username |
|
||||
| `LIQUID_WEB_ZONE` | DNS Zone |
|
||||
| `LWAPI_PASSWORD` | Liquid Web API Password |
|
||||
| `LWAPI_USERNAME` | Liquid Web 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" >}}).
|
||||
|
@ -51,11 +49,12 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|--------------------------------|-------------|
|
||||
| `LIQUID_WEB_HTTP_TIMEOUT` | Maximum waiting time for the DNS records to be created (not verified) |
|
||||
| `LIQUID_WEB_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `LIQUID_WEB_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `LIQUID_WEB_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
| `LIQUID_WEB_URL` | Storm API endpoint |
|
||||
| `LWAPI_HTTP_TIMEOUT` | Maximum waiting time for the DNS records to be created (not verified) |
|
||||
| `LWAPI_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `LWAPI_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `LWAPI_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
| `LWAPI_URL` | Liquid Web API endpoint |
|
||||
| `LWAPI_ZONE` | DNS Zone |
|
||||
|
||||
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" >}}).
|
||||
|
@ -65,7 +64,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
|
||||
## More information
|
||||
|
||||
- [API documentation](https://cart.liquidweb.com/storm/api/docs/v1/)
|
||||
- [API documentation](https://api.liquidweb.com/docs/)
|
||||
- [Go client](https://github.com/liquidweb/liquidweb-go)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
|
|
69
docs/content/dns/zz_gen_mailinabox.md
Normal file
69
docs/content/dns/zz_gen_mailinabox.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: "Mail-in-a-Box"
|
||||
date: 2019-03-03T16:39:46+01:00
|
||||
draft: false
|
||||
slug: mailinabox
|
||||
dnsprovider:
|
||||
since: "v4.16.0"
|
||||
code: "mailinabox"
|
||||
url: "https://mailinabox.email"
|
||||
---
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/mailinabox/mailinabox.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
|
||||
|
||||
Configuration for [Mail-in-a-Box](https://mailinabox.email).
|
||||
|
||||
|
||||
<!--more-->
|
||||
|
||||
- Code: `mailinabox`
|
||||
- Since: v4.16.0
|
||||
|
||||
|
||||
Here is an example bash command using the Mail-in-a-Box provider:
|
||||
|
||||
```bash
|
||||
MAILINABOX_EMAIL=user@example.com \
|
||||
MAILINABOX_PASSWORD=yyyy \
|
||||
MAILINABOX_BASE_URL=https://box.example.com \
|
||||
lego --email you@example.com --dns mailinabox --domains my.example.org run
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Credentials
|
||||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `MAILINABOX_BASE_URL` | Base API URL (ex: https://box.example.com) |
|
||||
| `MAILINABOX_EMAIL` | User email |
|
||||
| `MAILINABOX_PASSWORD` | User password |
|
||||
|
||||
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 |
|
||||
|--------------------------------|-------------|
|
||||
| `MAILINABOX_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `MAILINABOX_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
|
||||
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://mailinabox.email/api-docs.html)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/mailinabox/mailinabox.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
|
@ -51,6 +51,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
| `OTC_HTTP_TIMEOUT` | API request timeout |
|
||||
| `OTC_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `OTC_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `OTC_SEQUENCE_INTERVAL` | Time between sequential requests |
|
||||
| `OTC_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
||||
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
||||
|
|
|
@ -26,11 +26,20 @@ Configuration for [OVH](https://www.ovh.com/).
|
|||
Here is an example bash command using the OVH provider:
|
||||
|
||||
```bash
|
||||
# Application Key authentication:
|
||||
|
||||
OVH_APPLICATION_KEY=1234567898765432 \
|
||||
OVH_APPLICATION_SECRET=b9841238feb177a84330febba8a832089 \
|
||||
OVH_CONSUMER_KEY=256vfsd347245sdfg \
|
||||
OVH_ENDPOINT=ovh-eu \
|
||||
lego --email you@example.com --dns ovh --domains my.example.org run
|
||||
|
||||
# Or OAuth2:
|
||||
|
||||
OVH_CLIENT_ID=yyy \
|
||||
OVH_CLIENT_SECRET=xxx \
|
||||
OVH_ENDPOINT=ovh-eu \
|
||||
lego --email you@example.com --dns ovh --domains my.example.org run
|
||||
```
|
||||
|
||||
|
||||
|
@ -40,9 +49,11 @@ lego --email you@example.com --dns ovh --domains my.example.org run
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `OVH_APPLICATION_KEY` | Application key |
|
||||
| `OVH_APPLICATION_SECRET` | Application secret |
|
||||
| `OVH_CONSUMER_KEY` | Consumer key |
|
||||
| `OVH_APPLICATION_KEY` | Application key (Application Key authentication) |
|
||||
| `OVH_APPLICATION_SECRET` | Application secret (Application Key authentication) |
|
||||
| `OVH_CLIENT_ID` | Client ID (OAuth2) |
|
||||
| `OVH_CLIENT_SECRET` | Client secret (OAuth2) |
|
||||
| `OVH_CONSUMER_KEY` | Consumer key (Application Key authentication) |
|
||||
| `OVH_ENDPOINT` | Endpoint URL (ovh-eu or ovh-ca) |
|
||||
|
||||
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
||||
|
@ -82,6 +93,22 @@ When requesting the consumer key, the following configuration can be used to def
|
|||
}
|
||||
```
|
||||
|
||||
## OAuth2 Client Credentials
|
||||
|
||||
Another method for authentication is by using OAuth2 client credentials.
|
||||
|
||||
An IAM policy and service account can be created by following the [OVH guide](https://help.ovhcloud.com/csm/en-manage-service-account?id=kb_article_view&sysparm_article=KB0059343).
|
||||
|
||||
Following IAM policies need to be authorized for the affected domain:
|
||||
|
||||
* dnsZone:apiovh:record/create
|
||||
* dnsZone:apiovh:record/delete
|
||||
* dnsZone:apiovh:refresh
|
||||
|
||||
## Important Note
|
||||
|
||||
Both authentication methods cannot be used at the same time.
|
||||
|
||||
|
||||
|
||||
## More information
|
||||
|
|
|
@ -49,6 +49,7 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|--------------------------------|-------------|
|
||||
| `PDNS_API_VERSION` | Skip API version autodetection and use the provided version number. |
|
||||
| `PDNS_HTTP_TIMEOUT` | API request timeout |
|
||||
| `PDNS_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `PDNS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
|
@ -65,6 +66,7 @@ Tested and confirmed to work with PowerDNS authoritative server 3.4.8 and 4.0.1.
|
|||
PowerDNS Notes:
|
||||
- PowerDNS API does not currently support SSL, therefore you should take care to ensure that traffic between lego and the PowerDNS API is over a trusted network, VPN etc.
|
||||
- In order to have the SOA serial automatically increment each time the `_acme-challenge` record is added/modified via the API, set `SOA-EDIT-API` to `INCEPTION-INCREMENT` for the zone in the `domainmetadata` table
|
||||
- Some PowerDNS servers doesn't have root API endpoints enabled and API version autodetection will not work. In that case version number can be defined using `PDNS_API_VERSION`.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
| `REGRU_HTTP_TIMEOUT` | API request timeout |
|
||||
| `REGRU_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `REGRU_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `REGRU_TLS_CERT` | authentication certificate |
|
||||
| `REGRU_TLS_KEY` | authentication private key |
|
||||
| `REGRU_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
||||
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
|
||||
|
|
|
@ -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 \
|
||||
--domains example.com --email your_example@email.com --dns route53 --accept-tos=true run
|
||||
lego --domains example.com --email your_example@email.com --dns route53 --accept-tos=true run
|
||||
```
|
||||
|
||||
|
||||
|
@ -48,6 +48,7 @@ AWS_HOSTED_ZONE_ID=your_hosted_zone_id \
|
|||
| `AWS_REGION` | Managed by the AWS client (`AWS_REGION_FILE` is not supported) |
|
||||
| `AWS_SDK_LOAD_CONFIG` | Managed by the AWS client. Retrieve the region from the CLI config file (`AWS_SDK_LOAD_CONFIG_FILE` is not supported) |
|
||||
| `AWS_SECRET_ACCESS_KEY` | Managed by the AWS client. Secret access key (`AWS_SECRET_ACCESS_KEY_FILE` is not supported, use `AWS_SHARED_CREDENTIALS_FILE` instead) |
|
||||
| `AWS_WAIT_FOR_RECORD_SETS_CHANGED` | Wait for changes to be INSYNC (it can be unstable) |
|
||||
|
||||
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" >}}).
|
||||
|
|
|
@ -26,7 +26,7 @@ Configuration for [Scaleway](https://developers.scaleway.com/).
|
|||
Here is an example bash command using the Scaleway provider:
|
||||
|
||||
```bash
|
||||
SCALEWAY_API_TOKEN=xxxxxxx-xxxxx-xxxx-xxx-xxxxxx \
|
||||
SCW_SECRET_KEY=xxxxxxx-xxxxx-xxxx-xxx-xxxxxx \
|
||||
lego --email you@example.com --dns scaleway --domains my.example.org run
|
||||
```
|
||||
|
||||
|
@ -37,8 +37,8 @@ lego --email you@example.com --dns scaleway --domains my.example.org run
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `SCALEWAY_API_TOKEN` | API token |
|
||||
| `SCALEWAY_PROJECT_ID` | Project to use (optional) |
|
||||
| `SCW_PROJECT_ID` | Project to use (optional) |
|
||||
| `SCW_SECRET_KEY` | Secret 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" >}}).
|
||||
|
@ -48,9 +48,10 @@ More information [here]({{< ref "dns#configuration-and-credentials" >}}).
|
|||
|
||||
| Environment Variable Name | Description |
|
||||
|--------------------------------|-------------|
|
||||
| `SCALEWAY_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `SCALEWAY_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `SCALEWAY_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
| `SCW_ACCESS_KEY` | Access key |
|
||||
| `SCW_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `SCW_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `SCW_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
||||
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" >}}).
|
||||
|
|
75
docs/content/dns/zz_gen_selectelv2.md
Normal file
75
docs/content/dns/zz_gen_selectelv2.md
Normal file
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
title: "Selectel v2"
|
||||
date: 2019-03-03T16:39:46+01:00
|
||||
draft: false
|
||||
slug: selectelv2
|
||||
dnsprovider:
|
||||
since: "v4.17.0"
|
||||
code: "selectelv2"
|
||||
url: "https://selectel.ru"
|
||||
---
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/selectelv2/selectelv2.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
|
||||
|
||||
Configuration for [Selectel v2](https://selectel.ru).
|
||||
|
||||
|
||||
<!--more-->
|
||||
|
||||
- Code: `selectelv2`
|
||||
- Since: v4.17.0
|
||||
|
||||
|
||||
Here is an example bash command using the Selectel v2 provider:
|
||||
|
||||
```bash
|
||||
SELECTEL_USERNAME=trex \
|
||||
SELECTEL_PASSWORD=xxxxx \
|
||||
SELECTEL_ACCOUNT_ID=1234567 \
|
||||
SELECTEL_PROJECT_ID=111a11111aaa11aa1a11aaa11111aa1a \
|
||||
lego --email you@example.com --dns selectelv2 --domains my.example.org run
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Credentials
|
||||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `SELECTELV2_ACCOUNT_ID` | Selectel account ID (INT) |
|
||||
| `SELECTELV2_PASSWORD` | Openstack username's password |
|
||||
| `SELECTELV2_PROJECT_ID` | Cloud project ID (UUID) |
|
||||
| `SELECTELV2_USERNAME` | Openstack 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 |
|
||||
|--------------------------------|-------------|
|
||||
| `SELECTELV2_BASE_URL` | API endpoint URL |
|
||||
| `SELECTELV2_HTTP_TIMEOUT` | API request timeout |
|
||||
| `SELECTELV2_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `SELECTELV2_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `SELECTELV2_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
||||
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.selectel.ru/docs/cloud-services/dns_api/dns_api_actual/)
|
||||
- [Go client](https://github.com/selectel/domains-go)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/selectelv2/selectelv2.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
69
docs/content/dns/zz_gen_shellrent.md
Normal file
69
docs/content/dns/zz_gen_shellrent.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: "Shellrent"
|
||||
date: 2019-03-03T16:39:46+01:00
|
||||
draft: false
|
||||
slug: shellrent
|
||||
dnsprovider:
|
||||
since: "v4.16.0"
|
||||
code: "shellrent"
|
||||
url: "https://www.shellrent.com/"
|
||||
---
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/shellrent/shellrent.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
|
||||
|
||||
Configuration for [Shellrent](https://www.shellrent.com/).
|
||||
|
||||
|
||||
<!--more-->
|
||||
|
||||
- Code: `shellrent`
|
||||
- Since: v4.16.0
|
||||
|
||||
|
||||
Here is an example bash command using the Shellrent provider:
|
||||
|
||||
```bash
|
||||
SHELLRENT_USERNAME=xxxx \
|
||||
SHELLRENT_TOKEN=yyyy \
|
||||
lego --email you@example.com --dns shellrent --domains my.example.org run
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Credentials
|
||||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `SHELLRENT_TOKEN` | Token |
|
||||
| `SHELLRENT_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 |
|
||||
|--------------------------------|-------------|
|
||||
| `SHELLRENT_HTTP_TIMEOUT` | API request timeout |
|
||||
| `SHELLRENT_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `SHELLRENT_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `SHELLRENT_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
||||
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.shellrent.com/section/api2)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/shellrent/shellrent.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
72
docs/content/dns/zz_gen_webnames.md
Normal file
72
docs/content/dns/zz_gen_webnames.md
Normal file
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
title: "Webnames"
|
||||
date: 2019-03-03T16:39:46+01:00
|
||||
draft: false
|
||||
slug: webnames
|
||||
dnsprovider:
|
||||
since: "v4.15.0"
|
||||
code: "webnames"
|
||||
url: "https://www.webnames.ru/"
|
||||
---
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/webnames/webnames.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
|
||||
|
||||
Configuration for [Webnames](https://www.webnames.ru/).
|
||||
|
||||
|
||||
<!--more-->
|
||||
|
||||
- Code: `webnames`
|
||||
- Since: v4.15.0
|
||||
|
||||
|
||||
Here is an example bash command using the Webnames provider:
|
||||
|
||||
```bash
|
||||
WEBNAMES_API_KEY=xxxxxx \
|
||||
lego --email you@example.com --dns webnames --domains my.example.org run
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## Credentials
|
||||
|
||||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `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" >}}).
|
||||
|
||||
|
||||
## Additional Configuration
|
||||
|
||||
| Environment Variable Name | Description |
|
||||
|--------------------------------|-------------|
|
||||
| `WEBNAMES_HTTP_TIMEOUT` | API request timeout |
|
||||
| `WEBNAMES_POLLING_INTERVAL` | Time between DNS propagation check |
|
||||
| `WEBNAMES_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
|
||||
| `WEBNAMES_TTL` | The TTL of the TXT record used for the DNS challenge |
|
||||
|
||||
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" >}}).
|
||||
|
||||
## API Key
|
||||
|
||||
To obtain the key, you need to change the DNS server to `*.nameself.com`: Personal account / My domains and services / Select the required domain / DNS servers
|
||||
|
||||
The API key can be found: Personal account / My domains and services / Select the required domain / Zone management / acme.sh or certbot settings
|
||||
|
||||
|
||||
|
||||
## More information
|
||||
|
||||
- [API documentation](https://github.com/regtime-ltd/certbot-dns-webnames)
|
||||
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
||||
<!-- providers/dns/webnames/webnames.toml -->
|
||||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
|
|
@ -30,13 +30,27 @@ docker run goacme/lego -h
|
|||
yay -S lego-bin
|
||||
```
|
||||
|
||||
- [Snap](https://snapcraft.io/lego) (official):
|
||||
|
||||
```bash
|
||||
sudo snap install lego
|
||||
```
|
||||
|
||||
- [FreeBSD (Ports)](https://www.freshports.org/security/lego) (unofficial):
|
||||
|
||||
```bash
|
||||
cd /usr/ports/security/lego && make install clean
|
||||
```
|
||||
|
||||
[Homebrew](https://brew.sh/) user can install [lego](https://formulae.brew.sh/formula/lego) with:
|
||||
- [Gentoo](https://gitweb.gentoo.org/repo/proj/guru.git/tree/app-crypt/lego) (unofficial):
|
||||
|
||||
You can [enable GURU](https://wiki.gentoo.org/wiki/Project:GURU/Information_for_End_Users) repository and then:
|
||||
|
||||
```bash
|
||||
emerge app-crypt/lego
|
||||
```
|
||||
|
||||
- [Homebrew](https://formulae.brew.sh/formula/lego) (unofficial):
|
||||
|
||||
```bash
|
||||
brew install lego
|
||||
|
@ -52,7 +66,7 @@ docker run goacme/lego -h
|
|||
|
||||
Requirements:
|
||||
|
||||
- go1.17+
|
||||
- go1.22+.
|
||||
- environment variable: `GO111MODULE=on`
|
||||
|
||||
To install the latest version from sources, just run:
|
||||
|
|
|
@ -104,6 +104,8 @@ Some information is provided through environment variables:
|
|||
- `LEGO_CERT_DOMAIN`: the main domain of the certificate.
|
||||
- `LEGO_CERT_PATH`: the path of the certificate.
|
||||
- `LEGO_CERT_KEY_PATH`: the path of the certificate key.
|
||||
- `LEGO_CERT_PEM_PATH`: (only with `--pem`) the path to the PEM certificate.
|
||||
- `LEGO_CERT_PFX_PATH`: (only with `--pfx`) the path to the PFX certificate.
|
||||
|
||||
### Use case
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@ Some information is provided through environment variables:
|
|||
- `LEGO_CERT_DOMAIN`: the main domain of the certificate.
|
||||
- `LEGO_CERT_PATH`: the path of the certificate.
|
||||
- `LEGO_CERT_KEY_PATH`: the path of the certificate key.
|
||||
- `LEGO_CERT_PEM_PATH`: (only with `--pem`) the path to the PEM certificate.
|
||||
- `LEGO_CERT_PFX_PATH`: (only with `--pfx`) the path to the PFX certificate.
|
||||
|
||||
See [Obtain a Certificate → Use case]({{< ref "usage/cli/Obtain-a-Certificate#use-case" >}}) for an example script.
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ NAME:
|
|||
lego - Let's Encrypt client written in Go
|
||||
|
||||
USAGE:
|
||||
lego [global options] command [command options] [arguments...]
|
||||
lego [global options] command [command options]
|
||||
|
||||
COMMANDS:
|
||||
run Register an account, then create and install a certificate
|
||||
|
@ -20,7 +20,7 @@ COMMANDS:
|
|||
|
||||
GLOBAL OPTIONS:
|
||||
--domains value, -d value [ --domains value, -d value ] Add a domain to the process. Can be specified multiple times.
|
||||
--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")
|
||||
--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.
|
||||
--csr value, -c value Certificate signing request filename, if an external CSR is to be used.
|
||||
|
@ -44,8 +44,9 @@ GLOBAL OPTIONS:
|
|||
--http-timeout value Set the HTTP timeout value to a specific value in seconds. (default: 0)
|
||||
--dns-timeout value Set the DNS timeout value to a specific value in seconds. Used only when performing authoritative name server queries. (default: 10)
|
||||
--pem Generate an additional .pem (base64) file by concatenating the .key and .crt files together. (default: false)
|
||||
--pfx Generate an additional .pfx (PKCS#12) file by concatenating the .key and .crt and issuer .crt files together. (default: false)
|
||||
--pfx.pass value The password used to encrypt the .pfx (PCKS#12) file. (default: "changeit")
|
||||
--pfx Generate an additional .pfx (PKCS#12) file by concatenating the .key and .crt and issuer .crt files together. (default: false) [$LEGO_PFX]
|
||||
--pfx.pass value The password used to encrypt the .pfx (PCKS#12) file. (default: "changeit") [$LEGO_PFX_PASSWORD]
|
||||
--pfx.format value The encoding format to use when encrypting the .pfx (PCKS#12) file. Supported: RC2, DES, SHA256. (default: "RC2") [$LEGO_PFX_FORMAT]
|
||||
--cert.timeout value Set the certificate timeout value to a specific value in seconds. Only used when obtaining certificates. (default: 30)
|
||||
--user-agent value Add to the user-agent sent to the CA to identify an application embedding lego-cli
|
||||
--help, -h show help
|
||||
|
@ -81,9 +82,8 @@ USAGE:
|
|||
lego renew [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--days value The number of days left on a certificate to renew it. (default: 0)
|
||||
--days value The number of days left on a certificate to renew it. (default: 30)
|
||||
--ari-enable Use the renewalInfo endpoint (draft-ietf-acme-ari) to check if a certificate should be renewed. (default: false)
|
||||
--ari-hash-name value The string representation of the hash expected by the renewalInfo endpoint (e.g. "SHA-256").
|
||||
--ari-wait-to-renew-duration value The maximum duration you're willing to sleep for a renewal time returned by the renewalInfo endpoint. (default: 0s)
|
||||
--reuse-key Used to indicate you want to reuse your current private key for the new certificate. (default: false)
|
||||
--no-bundle Do not create a certificate bundle by adding the issuers certificate to the new certificate. (default: false)
|
||||
|
@ -137,7 +137,7 @@ To display the documentation for a specific DNS provider, run:
|
|||
$ lego dnshelp -c code
|
||||
|
||||
Supported DNS providers:
|
||||
acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, azuredns, bindman, bluecat, brandit, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudru, cloudxns, conoha, constellix, derak, desec, designate, digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, efficientip, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, hostingde, hosttech, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, ipv64, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, manual, metaname, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, rcodezero, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, servercow, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, websupport, wedos, yandex, yandex360, yandexcloud, zoneee, zonomi
|
||||
acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, azuredns, bindman, bluecat, brandit, bunny, checkdomain, civo, clouddns, cloudflare, cloudns, cloudru, cloudxns, conoha, constellix, cpanel, derak, desec, designate, digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, efficientip, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, hostingde, hosttech, httpnet, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, ipv64, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, mailinabox, manual, metaname, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, rcodezero, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, selectelv2, servercow, shellrent, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, webnames, websupport, wedos, yandex, yandex360, yandexcloud, zoneee, zonomi
|
||||
|
||||
More information: https://go-acme.github.io/lego/dns
|
||||
"""
|
||||
|
|
206
go.mod
206
go.mod
|
@ -1,168 +1,190 @@
|
|||
module github.com/go-acme/lego/v4
|
||||
|
||||
go 1.20
|
||||
go 1.22
|
||||
|
||||
// github.com/exoscale/egoscale v1.19.0 => It is an error, please don't use it.
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.2.3
|
||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0
|
||||
github.com/Azure/go-autorest/autorest v0.11.24
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2
|
||||
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.2.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0
|
||||
github.com/Azure/go-autorest/autorest v0.11.29
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0
|
||||
github.com/BurntSushi/toml v1.3.2
|
||||
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755
|
||||
github.com/aws/aws-sdk-go-v2 v1.19.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.28
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.27
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3
|
||||
github.com/cenkalti/backoff/v4 v4.2.1
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.62.712
|
||||
github.com/aws/aws-sdk-go-v2 v1.26.1
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.11
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.11
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.37.0
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.4
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6
|
||||
github.com/cenkalti/backoff/v4 v4.3.0
|
||||
github.com/civo/civogo v0.3.11
|
||||
github.com/cloudflare/cloudflare-go v0.70.0
|
||||
github.com/cloudflare/cloudflare-go v0.93.0
|
||||
github.com/cpu/goacmedns v0.1.1
|
||||
github.com/dnsimple/dnsimple-go v1.2.0
|
||||
github.com/exoscale/egoscale v0.100.1
|
||||
github.com/go-jose/go-jose/v3 v3.0.0
|
||||
github.com/dnsimple/dnsimple-go v1.7.0
|
||||
github.com/exoscale/egoscale v0.102.3
|
||||
github.com/go-jose/go-jose/v4 v4.0.1
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1
|
||||
github.com/google/go-querystring v1.1.0
|
||||
github.com/gophercloud/gophercloud v1.0.0
|
||||
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4
|
||||
github.com/gophercloud/gophercloud v1.11.0
|
||||
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5
|
||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df
|
||||
github.com/infobloxopen/infoblox-go-client v1.1.1
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2
|
||||
github.com/linode/linodego v1.17.2
|
||||
github.com/liquidweb/liquidweb-go v1.6.3
|
||||
github.com/mattn/go-isatty v0.0.19
|
||||
github.com/miekg/dns v1.1.55
|
||||
github.com/linode/linodego v1.28.0
|
||||
github.com/liquidweb/liquidweb-go v1.6.4
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/miekg/dns v1.1.58
|
||||
github.com/mimuret/golang-iij-dpf v0.9.1
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04
|
||||
github.com/nrdcg/auroradns v1.1.0
|
||||
github.com/nrdcg/bunny-go v0.0.0-20230728143221-c9dda82568d9
|
||||
github.com/nrdcg/desec v0.7.0
|
||||
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3
|
||||
github.com/nrdcg/desec v0.8.0
|
||||
github.com/nrdcg/dnspod-go v0.4.0
|
||||
github.com/nrdcg/freemyip v0.2.0
|
||||
github.com/nrdcg/goinwx v0.8.2
|
||||
github.com/nrdcg/goinwx v0.10.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/porkbun v0.2.0
|
||||
github.com/nrdcg/porkbun v0.3.0
|
||||
github.com/nzdjb/go-metaname v1.0.0
|
||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible
|
||||
github.com/ovh/go-ovh v1.4.2
|
||||
github.com/oracle/oci-go-sdk/v65 v65.63.1
|
||||
github.com/ovh/go-ovh v1.5.1
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2
|
||||
github.com/sacloud/api-client-go v0.2.8
|
||||
github.com/sacloud/iaas-api-go v1.11.1
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17
|
||||
github.com/softlayer/softlayer-go v1.1.2
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490
|
||||
github.com/transip/gotransip/v6 v6.20.0
|
||||
github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c
|
||||
github.com/urfave/cli/v2 v2.25.7
|
||||
github.com/sacloud/api-client-go v0.2.10
|
||||
github.com/sacloud/iaas-api-go v1.12.0
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25
|
||||
github.com/selectel/domains-go v1.0.2
|
||||
github.com/selectel/go-selvpcclient/v3 v3.1.1
|
||||
github.com/softlayer/softlayer-go v1.1.3
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.898
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.898
|
||||
github.com/transip/gotransip/v6 v6.23.0
|
||||
github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a
|
||||
github.com/urfave/cli/v2 v2.27.1
|
||||
github.com/vinyldns/go-vinyldns v0.9.16
|
||||
github.com/vultr/govultr/v2 v2.17.2
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997
|
||||
golang.org/x/crypto v0.10.0
|
||||
golang.org/x/net v0.11.0
|
||||
golang.org/x/oauth2 v0.9.0
|
||||
golang.org/x/time v0.3.0
|
||||
google.golang.org/api v0.111.0
|
||||
gopkg.in/ns1/ns1-go.v2 v2.7.6
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20240318083951-4fe6125f286e
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20240318084659-dfa50323a0b4
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/oauth2 v0.19.0
|
||||
golang.org/x/time v0.5.0
|
||||
google.golang.org/api v0.172.0
|
||||
gopkg.in/ns1/ns1-go.v2 v2.9.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
software.sslmate.com/src/go-pkcs12 v0.2.0
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.18.0 // indirect
|
||||
cloud.google.com/go/compute v1.24.0 // indirect
|
||||
github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // 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.0.0 // indirect
|
||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
|
||||
github.com/aws/smithy-go v1.20.2 // indirect
|
||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.9.1 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
github.com/go-resty/resty/v2 v2.7.0 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-resty/resty/v2 v2.11.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // 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
|
||||
github.com/labbsr0x/goh v1.0.1 // indirect
|
||||
github.com/liquidweb/go-lwApi v0.0.5 // indirect
|
||||
github.com/liquidweb/liquidweb-cli v0.6.9 // 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/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sacloud/go-http v0.1.6 // indirect
|
||||
github.com/sacloud/packages-go v0.0.9 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/sacloud/go-http v0.1.8 // indirect
|
||||
github.com/sacloud/packages-go v0.0.10 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/smartystreets/assertions v1.0.1 // 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 v0.5.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/ratelimit v0.2.0 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
golang.org/x/text v0.10.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 // indirect
|
||||
google.golang.org/grpc v1.53.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
go.uber.org/ratelimit v0.3.0 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.20.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
|
||||
google.golang.org/grpc v1.63.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
497
go.sum
497
go.sum
|
@ -5,15 +5,13 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A
|
|||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY=
|
||||
cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
|
||||
cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
|
||||
cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
|
@ -21,99 +19,108 @@ 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.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 h1:8iR6OLffWWorFdzL2JFCab5xpD8VKEE2DUBBl+HNTDY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0/go.mod h1:copqlcjMWc/wgQ1N2fzsJFQxDdqKGg1EQt8T5wJMOGE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0 h1:rR8ZW79lE/ppfXTfiYSnMFv5EzmVuY4pfZWIkscIJ64=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0/go.mod h1:y2zXtLSMM/X5Mfawq0lOftpWn3f4V6OCsRdINsvWBPI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 h1:FDif4R1+UUR+00q6wquyX90K7A8dN+R5E8GEadoP7sU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2/go.mod h1:aiYBYui4BJ/BJCAIKs92XiPyQfTaBWqvHujDwKb6CBU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
|
||||
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/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 h1:9Eih8XcEeQnFD0ntMlUDleKMzfeCeUfa+VbnDCI4AZs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0/go.mod h1:wGPyTi+aURdqPAGMZDQqnNs9IrShADF8w2WZb6bKeq0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 h1:zLzoX5+W2l95UJoVwiyNS4dX8vHyQ6x2xRLoBBL9wMk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.11.24 h1:1fIGgHKqVm54KIPT+q8Zmd1QlVsmHqeUGso5qm2BqqE=
|
||||
github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 h1:kLnPsRjzZZUF3K5REu/Kc+qMQrvuza2bwSnNdhmzLfQ=
|
||||
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
|
||||
github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.22 h1:/GblQdIudfEM3AWWZ0mrYJQSd7JS4S/Mbzh6F0ov0Xc=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk=
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 h1:0W/yGmFdTIT77fvdlGZ0LMISoLHFJ7Tx4U0yeB+uFs4=
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
|
||||
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
|
||||
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
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/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
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/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 h1:J45/QHgrzUdqe/Vco/Vxk0wRvdS2nKUxmf/zLgvfass=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
|
||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI=
|
||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.62.712 h1:lM7JnA9dEdDFH9XOgRNQMDTQnOjlLkDTNA7c0aWTQ30=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.62.712/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
|
||||
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-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go-v2 v1.19.0 h1:klAT+y3pGFBU/qVf1uzwttpBbiuozJYWzNLHioyDJ+k=
|
||||
github.com/aws/aws-sdk-go-v2 v1.19.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.28 h1:TINEaKyh1Td64tqFvn09iYpKiWjmHYrG1fa91q2gnqw=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.28/go.mod h1:nIL+4/8JdAuNHEjn/gPEXqtnS02Q3NXB/9Z7o5xE4+A=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.27 h1:dz0yr/yR1jweAnsCx+BmjerUILVPQ6FS5AwF/OyG1kA=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.27/go.mod h1:syOqAek45ZXZp29HlnRS/BNgMIW6uiRmeuQsz4Qh2UE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 h1:kP3Me6Fy3vdi+9uHd7YLr6ewPxRL+PU6y15urfTaamU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5/go.mod h1:Gj7tm95r+QsDoN2Fhuz/3npQvcZbkEf5mL70n3Xfluc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 h1:hMUCiE3Zi5AHrRNGf5j985u0WyqI6r2NULhUfo0N/No=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35/go.mod h1:ipR5PvpSPqIqL5Mi82BxLnfMkHVbmco8kUwO2xrCi0M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 h1:yOpYx+FTBdpk/g+sBU6Cb1H0U/TLEcYYp66mYqsPpcc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29/go.mod h1:M/eUABlDbw2uVrdAn+UsI6M727qp2fxkp8K0ejcBDUY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 h1:8r5m1BoAWkn0TDC34lUculryf7nUF25EgIMdjvGCkgo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36/go.mod h1:Rmw2M1hMVTwiUhjwMoIBFWFJMhvJbct06sSidxInkhY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27 h1:cZG7psLfqpkB6H+fIrgUDWmlzM474St1LP0jcz272yI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27/go.mod h1:ZdjYvJpDlefgh8/hWelJhqgqJeodxu4SmbVsSdBlL7E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 h1:Bje8Xkh2OWpjBdNfXLrnn8eZg569dUQmhgtydxAYyP0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30/go.mod h1:qQtIBl5OVMfmeQkz8HaVyh5DzFmmFXyvK27UgIgOr4c=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 h1:IiDolu/eLmuB18DRZibj77n1hHQT7z12jnGO7Ze3pLc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29/go.mod h1:fDbkK4o7fpPXWn8YAPmTieAMuB9mk/VgvW64uaUqxd4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 h1:hx4WksB0NRQ9utR+2c3gEGzl6uKj3eM6PMQ6tN3lgXs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4/go.mod h1:JniVpqvw90sVjNqanGLufrVapWySL28fhBlYgl96Q/w=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2 h1:PwNeYoonBzmTdCztKiiutws3U24KrnDBuabzRfIlZY4=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2/go.mod h1:gQhLZrTEath4zik5ixIe6axvgY5jJrgSBDJ360Fxnco=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4 h1:p4mTxJfCAyiTT4Wp6p/mOPa6j5MqCSRGot8qZwFs+Z0=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4/go.mod h1:VBLWpaHvhQNeu7N9rMEf00SWeOONb/HvaDUxe/7b44k=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0 h1:PalLOEGZ/4XfQxpGZFTLaoJSmPoybnqJYotaIZEf/Rg=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0/go.mod h1:PwyKKVL0cNkC37QwLcrhyeCrAk+5bY8O2ou7USyAS2A=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 h1:sWDv7cMITPcZ21QdreULwxOOAmE05JjEsT6fCDtDA9k=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13/go.mod h1:DfX0sWuT46KpcqbMhJ9QWtxAIP1VozkDWf8VAkByjYY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 h1:BFubHS/xN5bjl818QaroN6mQdjneYQ+AOx44KNXlyH4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13/go.mod h1:BzqsVVFduubEmzrVtUFQQIQdFqvUItF8XUq2EnS8Wog=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 h1:e5mnydVdCVWxP+5rPAGi2PYxC7u2OZgH1ypC114H04U=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3/go.mod h1:yVGZA1CPkmUhBdA039jXNJJG7/6t+G+EBWmFq23xqnY=
|
||||
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
|
||||
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.11 h1:YuIB1dJNf1Re822rriUOTxopaHHvIq0l/pX3fwO+Tzs=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.11/go.mod h1:AQtFPsDH9bI2O+71anW6EKL+NcD7LG3dpKGMV4SShgo=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5 h1:81KE7vaZzrl7yHBYHVEzYB8sypz11NMOZ40YlWvPxsU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5/go.mod h1:LIt2rg7Mcgn09Ygbdh/RdIm0rQ+3BNkbP1gyVMFtRK0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 h1:ZMeFZ5yk+Ek+jNr1+uwCd2tG89t6oTS5yVWpa6yy2es=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7/go.mod h1:mxV05U+4JiHqIpGqqYXOHLPKUC6bDXC44bsUhNjOEwY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 h1:f9RyWNtS8oH7cZlbn+/JNPpjUk5+5fLd5lM9M0i49Ys=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5/go.mod h1:h5CoMZV2VF297/VLhRhO1WF+XYWOzXo+4HsObA4HjBQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.37.0 h1:lfVUMJEGXzi5l8jam/WXLNSn+vM/fpe2dmMYOdRiQ+k=
|
||||
github.com/aws/aws-sdk-go-v2/service/lightsail v1.37.0/go.mod h1:GSVUed6FJivX6v7Pgrk9iXuRa2NuCtT+nMWGxQHSAXQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.4 h1:ZZKiHm4cN8IDDZ2kh8DTk+YnYBjVsiFdwf5FwVs//IQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.40.4/go.mod h1:RTfjFUctf+Zyq8e4rgLXmz43+0kIoIXbENvrFtilumI=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1 h1:6cnno47Me9bRykw9AEv9zkXE+5or7jz8TsskTTccbgc=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1/go.mod h1:qmdkIIAC+GCLASF7R2whgNrJADz0QZPX+Seiw/i4S3o=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 h1:vN8hEbpRnL7+Hopy9dzmRle1xmDc7o8tmY0klsr175w=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw=
|
||||
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
|
||||
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
|
||||
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=
|
||||
|
@ -123,8 +130,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8
|
|||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
|
||||
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
|
@ -134,8 +141,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
|||
github.com/civo/civogo v0.3.11 h1:mON/fyrV946Sbk6paRtOSGsN+asCgCmHCgArf5xmGxM=
|
||||
github.com/civo/civogo v0.3.11/go.mod h1:7+GeeFwc4AYTULaEshpT2vIcl3Qq8HPoxA17viX3l6g=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cloudflare-go v0.70.0 h1:4opGbUygM8DjirUuaz23jn3akuAcnOCEx+0nQtQEcFo=
|
||||
github.com/cloudflare/cloudflare-go v0.70.0/go.mod h1:VW6GuazkaZ4xEDkFt24lkXQUsE8q7BiGqDniC2s8WEM=
|
||||
github.com/cloudflare/cloudflare-go v0.93.0 h1:rV0eHb42NUewfK5qa2+LKAD4v4oFA0QGDABn/lMyF78=
|
||||
github.com/cloudflare/cloudflare-go v0.93.0/go.mod h1:N1u1cLZ4lG6NeezGOWi7P6aq1DK2iVYg9ze7GZbUmZE=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
|
@ -164,8 +171,9 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
|
|||
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
|
||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnsimple/dnsimple-go v1.2.0 h1:ddTGyLVKly5HKb5L65AkLqFqwZlWo3WnR0BlFZlIddM=
|
||||
github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6GbmkPH84plM4U=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/dnsimple/dnsimple-go v1.7.0 h1:JKu9xJtZ3SqOC+BuYgAWeab7+EEx0sz422vu8j611ZY=
|
||||
github.com/dnsimple/dnsimple-go v1.7.0/go.mod h1:EKpuihlWizqYafSnQHGCd/gyvy3HkEQJ7ODB4KdV8T8=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
|
@ -173,17 +181,21 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
|||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/exoscale/egoscale v0.100.1 h1:iXsV1Ei7daqe/6FYSCSDyrFs1iUG1l1X9qNh2uMw6z0=
|
||||
github.com/exoscale/egoscale v0.100.1/go.mod h1:BAb9p4rmyU+Wl400CJZO5270H2sXtdsZjLcm5xMKkz4=
|
||||
github.com/exoscale/egoscale v0.102.3 h1:DYqN2ipoLKpiFoprRGQkp2av/Ze7sUYYlGhi1N62tfY=
|
||||
github.com/exoscale/egoscale v0.102.3/go.mod h1:RPf2Gah6up+6kAEayHTQwqapzXlm93f0VQas/UEGU5c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
|
@ -194,11 +206,16 @@ github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW
|
|||
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-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
|
||||
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/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-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
|
@ -208,13 +225,21 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
|
|||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
|
||||
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
|
||||
github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
|
||||
github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
|
||||
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/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
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-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
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/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/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
|
@ -224,10 +249,14 @@ github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw
|
|||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/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=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
|
@ -244,8 +273,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -256,10 +286,11 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
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=
|
||||
|
@ -270,21 +301,24 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
|
|||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
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 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||
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.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||
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.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
|
||||
github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
|
||||
github.com/gophercloud/gophercloud v1.0.0 h1:9nTGx0jizmHxDobe4mck89FyQHVyA3CaXLIUSGJjP9k=
|
||||
github.com/gophercloud/gophercloud v1.0.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
|
||||
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae h1:Hi3IgB9RQDE15Kfovd8MTZrcana+UlQqNbOif8dLpA0=
|
||||
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD8oQD0Ryhz6+6ykq75PJ79iPyEqYHfwZ4l7OsA=
|
||||
github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
|
||||
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
|
||||
github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
|
||||
github.com/gophercloud/gophercloud v1.11.0 h1:ls0O747DIq1D8SUHc7r2vI8BFbMLeLFuENaAIfEx7OM=
|
||||
github.com/gophercloud/gophercloud v1.11.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
|
||||
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 h1:sH7xkTfYzxIEgzq1tDHIMKRh1vThOEOGNsettdEeLbE=
|
||||
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56/go.mod h1:VSalo4adEk+3sNkmVJLnhHoOyOYYS8sTWLG4mv5BKto=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
|
@ -304,19 +338,21 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n
|
|||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
|
||||
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
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.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=
|
||||
|
@ -333,14 +369,13 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
|||
github.com/infobloxopen/infoblox-go-client v1.1.1 h1:728A6LbLjptj/7kZjHyIxQnm768PWHfGFm0HH8FnbtU=
|
||||
github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI=
|
||||
github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
|
||||
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
|
@ -349,6 +384,7 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
|
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
|
@ -383,15 +419,13 @@ github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++
|
|||
github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
|
||||
github.com/lestrrat-go/jwx v1.2.7/go.mod h1:bw24IXWbavc0R2RsOtpXL7RtMyP589yZ1+L7kd09ZGA=
|
||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/linode/linodego v1.17.2 h1:b32dj4662PGG5P9qVa6nBezccWdqgukndlMIuPGq1CQ=
|
||||
github.com/linode/linodego v1.17.2/go.mod h1:C2iyT3Vg2O2sPxkWka4XAQ5WSUtm5LmTZ3Adw43Ra7Q=
|
||||
github.com/linode/linodego v1.28.0 h1:lzxxJebsYg5cCWRNDLyL2StW3sfMyAwf/FYfxFjFrlk=
|
||||
github.com/linode/linodego v1.28.0/go.mod h1:5oAsx+uinHtVo6U77nXXXtox7MWzUW6aEkTOKXxA9uo=
|
||||
github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
||||
github.com/liquidweb/go-lwApi v0.0.5 h1:CT4cdXzJXmo0bon298kS7NeSk+Gt8/UHpWBBol1NGCA=
|
||||
github.com/liquidweb/go-lwApi v0.0.5/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=
|
||||
github.com/liquidweb/liquidweb-go v1.6.3 h1:NVHvcnX3eb3BltiIoA+gLYn15nOpkYkdizOEYGSKrk4=
|
||||
github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc=
|
||||
github.com/liquidweb/liquidweb-go v1.6.4 h1:6S0m3hHSpiLqGD7AFSb7lH/W/qr1wx+tKil9fgIbjMc=
|
||||
github.com/liquidweb/liquidweb-go v1.6.4/go.mod h1:B934JPIIcdA+uTq2Nz5PgOtG6CuCaEvQKe/Ge/5GgZ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
|
@ -403,22 +437,24 @@ github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
|
|||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
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=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
|
||||
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
|
||||
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
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/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
|
@ -448,22 +484,24 @@ github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uY
|
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
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-20230728143221-c9dda82568d9 h1:qpB3wZR4+MPK92cTC9zZPnndkJgDgPvQqPUAgVc1NXU=
|
||||
github.com/nrdcg/bunny-go v0.0.0-20230728143221-c9dda82568d9/go.mod h1:HUoHXDrFvidN1NK9Wb/mZKNOfDNutKkzF2Pg71M9hHA=
|
||||
github.com/nrdcg/desec v0.7.0 h1:iuGhi4pstF3+vJWwt292Oqe2+AsSPKDynQna/eu1fDs=
|
||||
github.com/nrdcg/desec v0.7.0/go.mod h1:e1uRqqKv1mJdd5+SQROAhmy75lKMphLzWIuASLkpeFY=
|
||||
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 h1:ouZ2JWDl8IW5k1qugYbmpbmW8hn85Ig6buSMBRlz3KI=
|
||||
github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3/go.mod h1:ZwadWt7mVhMHMbAQ1w8IhDqtWO3eWqWq72W7trnaiE8=
|
||||
github.com/nrdcg/desec v0.8.0 h1:FJbRWUAluTCUi9nHFnhqPhLSIHiNnB9elZVWYgFtIqA=
|
||||
github.com/nrdcg/desec v0.8.0/go.mod h1:BsnYPtSlBttJL3Gyzv0kDH7zkk60obwThlnqiiKzn+o=
|
||||
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.2.0 h1:/GscavT4GVqAY13HExl5UyoB4wlchv6Cg5NYDGsUoJ8=
|
||||
github.com/nrdcg/freemyip v0.2.0/go.mod h1:HjF0Yz0lSb37HD2ihIyGz9esyGcxbCrrGFLPpKevbx4=
|
||||
github.com/nrdcg/goinwx v0.8.2 h1:RmjiHlEA+lzi3toXyPSaE6hWnBQ0+G+1u7w8C6Fpp4g=
|
||||
github.com/nrdcg/goinwx v0.8.2/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4=
|
||||
github.com/nrdcg/goinwx v0.10.0 h1:6W630bjDxQD6OuXKqrFRYVpTt0G/9GXXm3CeOrN0zJM=
|
||||
github.com/nrdcg/goinwx v0.10.0/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4=
|
||||
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/porkbun v0.2.0 h1:ghaqPtIKcffba99epWFkK3VWf6TKJT9WMXMgaTqv95Y=
|
||||
github.com/nrdcg/porkbun v0.2.0/go.mod h1:i0uLMn9ItFsLsSQIAeEu1wQ9/+6EvX1eQw15hulMMRw=
|
||||
github.com/nrdcg/porkbun v0.3.0 h1:jnRV7j2zd3hmh+tSDOGetJyy3+WklaMxbs7HtTTmWMs=
|
||||
github.com/nrdcg/porkbun v0.3.0/go.mod h1:jh1DKz96jGHW+NCdG3AmTbbnQeBlNUz1KeSgeN/cBVw=
|
||||
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=
|
||||
|
@ -482,17 +520,19 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl
|
|||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU=
|
||||
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||
github.com/ovh/go-ovh v1.4.2 h1:ub4jVK6ERbiBTo4y5wbLCjeKCjGY+K36e7BviW+MaAU=
|
||||
github.com/ovh/go-ovh v1.4.2/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY=
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.63.1 h1:dYL7sk9L1+C9LCmoq+zjPMNteuJJfk54YExq/4pV9xQ=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.63.1/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
|
||||
github.com/ovh/go-ovh v1.5.1 h1:P8O+7H+NQuFK9P/j4sFW5C0fvSS2DnHYGPwdVCp45wI=
|
||||
github.com/ovh/go-ovh v1.5.1/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/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/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -529,26 +569,33 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
|||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||
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.2.8 h1:tIY6PZNBX900K66TqEPa4d6UIbedUczfCBnPJkzi8kw=
|
||||
github.com/sacloud/api-client-go v0.2.8/go.mod h1:0CV/kWNYlS1hCNdnk6Wx7Wdg8DPFCnv0zOIzdXjeAeY=
|
||||
github.com/sacloud/go-http v0.1.6 h1:lJGXDt9xrxJiDszRPaN9NIP8MVj10YKMzmnyzdSfI8w=
|
||||
github.com/sacloud/go-http v0.1.6/go.mod h1:oLAHoDJRkptf8sq4fE8oERLkdCh0kJWfWu+paoJY7I0=
|
||||
github.com/sacloud/iaas-api-go v1.11.1 h1:2MsFZ4H1uRdRVx2nVXuERWQ3swoFc3XreIV5hJ3Nsws=
|
||||
github.com/sacloud/iaas-api-go v1.11.1/go.mod h1:uBDSa06F/V0OnoR66jGdbH0PVnCJw+NeE9RVbVgMfss=
|
||||
github.com/sacloud/packages-go v0.0.9 h1:GbinkBLC/eirFhHpLjoDW6JV7+95Rnd2d8RWj7Afeks=
|
||||
github.com/sacloud/packages-go v0.0.9/go.mod h1:k+EEUMF2LlncjbNIJNOqLyZ9wjTESPIWIk1OA7x9j2Q=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17 h1:1WuWJu7/e8SqK+uQl7lfk/N/oMZTL2NE/TJsNKRNMc4=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||
github.com/sacloud/api-client-go v0.2.10 h1:+rv3jDohD+pkdYwOTBiB+jZsM0xK3AxadXRzhp3q66c=
|
||||
github.com/sacloud/api-client-go v0.2.10/go.mod h1:Jj3CTy2+O4bcMedVDXlbHuqqche85HEPuVXoQFhLaRc=
|
||||
github.com/sacloud/go-http v0.1.8 h1:ynreWA/vnM8G2ksbMlmefBHsXURKPz49qlPRqQ9IQdw=
|
||||
github.com/sacloud/go-http v0.1.8/go.mod h1:7TL7TN1fnPKHsMifIqURDkGujnKViCgEz5Ei/LQdFK8=
|
||||
github.com/sacloud/iaas-api-go v1.12.0 h1:kqXFn3HzCiawlX6hVJb1GVqcSJqcmiGHB4Zp14sxiI8=
|
||||
github.com/sacloud/iaas-api-go v1.12.0/go.mod h1:SZLXeWOdXk3WReIS557sbU1gkOgrE4rseIBQV1B3b7o=
|
||||
github.com/sacloud/packages-go v0.0.10 h1:UiQGjy8LretewkRhsuna1TBM9Vz/l9FoYpQx+D+AOck=
|
||||
github.com/sacloud/packages-go v0.0.10/go.mod h1:f8QITBh9z4IZc4yE9j21Q8b0sXEMwRlRmhhjWeDVTYs=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25 h1:/8rfZAdFfafRXOgz+ZpMZZWZ5pYggCY9t7e/BvjaBHM=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/selectel/domains-go v1.0.2 h1:Si6iGaMnTFJxwiJVI50DOdZnwcxc87kqaWrVQYW0a4U=
|
||||
github.com/selectel/domains-go v1.0.2/go.mod h1:SugRKfq4sTpnOHquslCpzda72wV8u0cMBHx0C0l+bzA=
|
||||
github.com/selectel/go-selvpcclient/v3 v3.1.1 h1:C1q2LqqosiapoLpnGITGmysg0YCSQYDo2Gh69CioevM=
|
||||
github.com/selectel/go-selvpcclient/v3 v3.1.1/go.mod h1:NM7IXhh1IzqZ88DOw1Qc5Ez3tULLViXo95l5+rKPuyQ=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
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.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
|
||||
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
|
@ -556,11 +603,14 @@ github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 h1:hp2CY
|
|||
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/smartystreets/gunit v1.0.4 h1:tpTjnuH7MLlqhoD21vRoMZbMIi5GmBsAJDFyF67GhZA=
|
||||
github.com/softlayer/softlayer-go v1.1.2 h1:rUSSGCyaxymvTOsaFjwr+cGxA8muw3xg2LSrIMNcN/c=
|
||||
github.com/softlayer/softlayer-go v1.1.2/go.mod h1:hvAbzGH4LRXA6yXY8BNx99yoqZ7urfDdtl9mvBf0G+g=
|
||||
github.com/smartystreets/gunit v1.0.4/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ=
|
||||
github.com/softlayer/softlayer-go v1.1.3 h1:dfFzt5eOKIAyB/b78fHMyDu5ICx0ZtxL9NRhBlf831A=
|
||||
github.com/softlayer/softlayer-go v1.1.3/go.mod h1:Pc7F57OgUKaAam7TtpqkUeqL7QyKknfiUI4R49h41/U=
|
||||
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=
|
||||
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
|
||||
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
|
@ -577,8 +627,9 @@ github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
@ -588,24 +639,29 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 h1:mmz27tVi2r70JYnm5y0Zk8w0Qzsx+vfUw3oqSyrEfP8=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 h1:g9SWTaTy/rEuhMErC2jWq9Qt5ci+jBYSvXnJsLq4adg=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490/go.mod h1:l9q4vc1QiawUB1m3RU+87yLvrrxe54jc0w/kEl4DbSQ=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.898 h1:ERwcXqhc94L9cFxtiI0pvt7IJtlHl/p/Jayl3mLw+ms=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.898/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.898 h1:LoYv5u+gUoFpU/AmIuTRG/2KiEkdm9gCC0dTvk8WITQ=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.898/go.mod h1:c1j6YQ+vCbeA8kJ59Im4UnMd1GxovlpPBDhGZoewfn8=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/transip/gotransip/v6 v6.20.0 h1:AuvwyOZ51f2brzMbTqlRy/wmaM3kF7Vx5Wds8xcDflY=
|
||||
github.com/transip/gotransip/v6 v6.20.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c=
|
||||
github.com/transip/gotransip/v6 v6.23.0 h1:PsTdjortrEZ8IFFifEryzjVjOy9SgK4ahlnhKBBIQgA=
|
||||
github.com/transip/gotransip/v6 v6.23.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c=
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
|
||||
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||
github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c h1:mKnW6IGLw7uXu6DL6RitufZWcXS6hCnauXRUFof7rKM=
|
||||
github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c/go.mod h1:F4UyVEmq4/m5lAmx+GccrxyRCXmnBjzUL09JLTQFp94=
|
||||
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a h1:w4PK5/N9kq8PfNxBv8a5t1bqlYRrVT7XzT7iTPTtiPk=
|
||||
github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a/go.mod h1:Xwz7o+ExFtxR/i0aJDnTXuiccQJlOxDgNe6FsZC4TzQ=
|
||||
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
|
||||
|
@ -618,24 +674,33 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
|
|||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f h1:cG+ehPRJSlqljSufLf1KXeXpUd1dLNjnzA18mZcB/O0=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 h1:2wzke3JH7OtN20WsNDZx2VH/TCmsbqtDEbXzjF+i05E=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997/go.mod h1:2CHKs/YGbCcNn/BPaCkEBwKz/FNCELi+MLILjR9RaTA=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20240318083951-4fe6125f286e h1:jLIqA7M9qY31g/Nw/5htVD0DFbxmLnlFZcHKJiG3osI=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20240318083951-4fe6125f286e/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20240318084659-dfa50323a0b4 h1:wtzLQJmghkSUb1YkeFphIh7ST7NNVDaVOJZSAJcjMdw=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20240318084659-dfa50323a0b4/go.mod h1:9d1MV6u4lK715YXnZceKqhP4L0bKBKmv4mSLnVSjJaM=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
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 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA=
|
||||
go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg=
|
||||
go.uber.org/ratelimit v0.3.0 h1:IdZd9wqvFXnvLvSEBo0KPcGfkoBGNkpTHlrE3Rcjkjw=
|
||||
go.uber.org/ratelimit v0.3.0/go.mod h1:So5LG7CV1zWpY1sHe+DXTJqQvOx+FFPFaAs2SnoyBaI=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
@ -643,25 +708,29 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
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=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -678,8 +747,10 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
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=
|
||||
|
@ -705,17 +776,20 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
|||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
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-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs=
|
||||
golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw=
|
||||
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
|
||||
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
|
||||
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=
|
||||
|
@ -725,7 +799,10 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
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=
|
||||
|
@ -762,21 +839,31 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/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-20220908164124-27713097b956/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.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=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
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=
|
||||
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
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=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -785,17 +872,24 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
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-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
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=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
|
@ -816,25 +910,29 @@ golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4X
|
|||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
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.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||
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=
|
||||
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/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=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.111.0 h1:bwKi+z2BsdwYFRKrqwutM+axAlYLz83gt5pDSXCJT+0=
|
||||
google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
|
||||
google.golang.org/api v0.172.0 h1:/1OcMZGPmW1rX2LCu2CmGUD1KXK1+pfzxotxyRUCCdk=
|
||||
google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis=
|
||||
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=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
@ -847,8 +945,12 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx
|
|||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 h1:znp6mq/drrY+6khTAlJUDNFFcDGV2ENLYKpMq8SyCds=
|
||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
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=
|
||||
|
@ -860,8 +962,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.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
|
||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
||||
google.golang.org/grpc v1.63.1 h1:pNClQmvdlyNUiwFETOux/PYqfhmA7BrswEdGRnib1fA=
|
||||
google.golang.org/grpc v1.63.1/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
||||
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=
|
||||
|
@ -874,8 +976,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
|||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
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.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
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=
|
||||
|
@ -890,11 +992,10 @@ gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdOD
|
|||
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.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.2/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/ns1/ns1-go.v2 v2.7.6 h1:mCPl7q0jbIGACXvGBljAuuApmKZo3rRi4tlRIEbMvjA=
|
||||
gopkg.in/ns1/ns1-go.v2 v2.7.6/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk=
|
||||
gopkg.in/ns1/ns1-go.v2 v2.9.1 h1:3/QYzUazRCSE49d3sh1Q+X7IrDp/I7OqR/M7dKA0Oks=
|
||||
gopkg.in/ns1/ns1-go.v2 v2.9.1/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=
|
||||
|
@ -909,6 +1010,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -917,5 +1019,6 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE=
|
||||
software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
|
||||
|
|
|
@ -155,7 +155,7 @@ func generateCLIHelp(models *Providers) error {
|
|||
}
|
||||
|
||||
func generateReadMe(models *Providers) error {
|
||||
max, lines := extractTableData(models)
|
||||
maximum, lines := extractTableData(models)
|
||||
|
||||
file, err := os.Open(readmePath)
|
||||
if err != nil {
|
||||
|
@ -174,7 +174,7 @@ func generateReadMe(models *Providers) error {
|
|||
|
||||
if text == startLine {
|
||||
_, _ = fmt.Fprintln(buffer, text)
|
||||
err = writeDNSTable(buffer, lines, max)
|
||||
err = writeDNSTable(buffer, lines, maximum)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -208,14 +208,14 @@ func extractTableData(models *Providers) (int, [][]string) {
|
|||
|
||||
items := []string{fmt.Sprintf(readmePattern, "Manual", "manual")}
|
||||
|
||||
var max int
|
||||
var maximum int
|
||||
|
||||
for _, pvd := range models.Providers {
|
||||
item := fmt.Sprintf(readmePattern, strings.ReplaceAll(pvd.Name, "|", "/"), pvd.Code)
|
||||
items = append(items, item)
|
||||
|
||||
if max < len(item) {
|
||||
max = len(item)
|
||||
if maximum < len(item) {
|
||||
maximum = len(item)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ func extractTableData(models *Providers) (int, [][]string) {
|
|||
lines = append(lines, line)
|
||||
}
|
||||
|
||||
return max, lines
|
||||
return maximum, lines
|
||||
}
|
||||
|
||||
func writeDNSTable(w io.Writer, lines [][]string, size int) error {
|
||||
|
|
87
platform/config/env/env.go
vendored
87
platform/config/env/env.go
vendored
|
@ -78,15 +78,26 @@ func GetWithFallback(groups ...[]string) (map[string]string, error) {
|
|||
return values, nil
|
||||
}
|
||||
|
||||
func GetOneWithFallback[T any](main string, defaultValue T, fn func(string) (T, error), names ...string) T {
|
||||
v, _ := getOneWithFallback(main, names...)
|
||||
|
||||
value, err := fn(v)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getOneWithFallback(main string, names ...string) (string, string) {
|
||||
value := GetOrFile(main)
|
||||
if len(value) > 0 {
|
||||
if value != "" {
|
||||
return value, main
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
value := GetOrFile(name)
|
||||
if len(value) > 0 {
|
||||
if value != "" {
|
||||
return value, main
|
||||
}
|
||||
}
|
||||
|
@ -94,43 +105,32 @@ func getOneWithFallback(main string, names ...string) (string, string) {
|
|||
return "", main
|
||||
}
|
||||
|
||||
// GetOrDefaultInt returns the given environment variable value as an integer.
|
||||
// Returns the default if the env var cannot be coopered to an int, or is not found.
|
||||
func GetOrDefaultInt(envVar string, defaultValue int) int {
|
||||
v, err := strconv.Atoi(GetOrFile(envVar))
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// GetOrDefaultSecond returns the given environment variable value as a time.Duration (second).
|
||||
// Returns the default if the env var cannot be coopered to an int, or is not found.
|
||||
func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration {
|
||||
v := GetOrDefaultInt(envVar, -1)
|
||||
if v < 0 {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return time.Duration(v) * time.Second
|
||||
}
|
||||
|
||||
// GetOrDefaultString returns the given environment variable value as a string.
|
||||
// Returns the default if the env var cannot be found.
|
||||
func GetOrDefaultString(envVar, defaultValue string) string {
|
||||
v := GetOrFile(envVar)
|
||||
if v == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return v
|
||||
func GetOrDefaultString(envVar string, defaultValue string) string {
|
||||
return getOrDefault(envVar, defaultValue, ParseString)
|
||||
}
|
||||
|
||||
// GetOrDefaultBool returns the given environment variable value as a boolean.
|
||||
// Returns the default if the env var cannot be coopered to a boolean, or is not found.
|
||||
func GetOrDefaultBool(envVar string, defaultValue bool) bool {
|
||||
v, err := strconv.ParseBool(GetOrFile(envVar))
|
||||
return getOrDefault(envVar, defaultValue, strconv.ParseBool)
|
||||
}
|
||||
|
||||
// GetOrDefaultInt returns the given environment variable value as an integer.
|
||||
// Returns the default if the env var cannot be coopered to an int, or is not found.
|
||||
func GetOrDefaultInt(envVar string, defaultValue int) int {
|
||||
return getOrDefault(envVar, defaultValue, strconv.Atoi)
|
||||
}
|
||||
|
||||
// GetOrDefaultSecond returns the given environment variable value as a time.Duration (second).
|
||||
// Returns the default if the env var cannot be coopered to an int, or is not found.
|
||||
func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration {
|
||||
return getOrDefault(envVar, defaultValue, ParseSecond)
|
||||
}
|
||||
|
||||
func getOrDefault[T any](envVar string, defaultValue T, fn func(string) (T, error)) T {
|
||||
v, err := fn(GetOrFile(envVar))
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
@ -161,3 +161,26 @@ func GetOrFile(envVar string) string {
|
|||
|
||||
return strings.TrimSuffix(string(fileContents), "\n")
|
||||
}
|
||||
|
||||
// ParseSecond parses env var value (string) to a second (time.Duration).
|
||||
func ParseSecond(s string) (time.Duration, error) {
|
||||
v, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if v < 0 {
|
||||
return 0, fmt.Errorf("unsupported value: %d", v)
|
||||
}
|
||||
|
||||
return time.Duration(v) * time.Second, nil
|
||||
}
|
||||
|
||||
// ParseString parses env var value (string) to a string but throws an error when the string is empty.
|
||||
func ParseString(s string) (string, error) {
|
||||
if s == "" {
|
||||
return "", errors.New("empty string")
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
|
75
platform/config/env/env_test.go
vendored
75
platform/config/env/env_test.go
vendored
|
@ -15,12 +15,12 @@ func TestGetWithFallback(t *testing.T) {
|
|||
var1Missing := os.Getenv("TEST_LEGO_VAR_MISSING_1")
|
||||
var2Missing := os.Getenv("TEST_LEGO_VAR_MISSING_2")
|
||||
|
||||
defer func() {
|
||||
t.Cleanup(func() {
|
||||
_ = os.Setenv("TEST_LEGO_VAR_EXIST_1", var1Exist)
|
||||
_ = os.Setenv("TEST_LEGO_VAR_EXIST_2", var2Exist)
|
||||
_ = os.Setenv("TEST_LEGO_VAR_MISSING_1", var1Missing)
|
||||
_ = os.Setenv("TEST_LEGO_VAR_MISSING_2", var2Missing)
|
||||
}()
|
||||
})
|
||||
|
||||
err := os.Setenv("TEST_LEGO_VAR_EXIST_1", "VAR1")
|
||||
require.NoError(t, err)
|
||||
|
@ -94,8 +94,10 @@ func TestGetWithFallback(t *testing.T) {
|
|||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
value, err := GetWithFallback(test.groups...)
|
||||
if len(test.expected.error) > 0 {
|
||||
if test.expected.error != "" {
|
||||
assert.EqualError(t, err, test.expected.error)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
|
@ -105,6 +107,73 @@ func TestGetWithFallback(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetOneWithFallback(t *testing.T) {
|
||||
var1Exist := os.Getenv("TEST_LEGO_VAR_EXIST_1")
|
||||
var2Exist := os.Getenv("TEST_LEGO_VAR_EXIST_2")
|
||||
var1Missing := os.Getenv("TEST_LEGO_VAR_MISSING_1")
|
||||
var2Missing := os.Getenv("TEST_LEGO_VAR_MISSING_2")
|
||||
|
||||
t.Cleanup(func() {
|
||||
_ = os.Setenv("TEST_LEGO_VAR_EXIST_1", var1Exist)
|
||||
_ = os.Setenv("TEST_LEGO_VAR_EXIST_2", var2Exist)
|
||||
_ = os.Setenv("TEST_LEGO_VAR_MISSING_1", var1Missing)
|
||||
_ = os.Setenv("TEST_LEGO_VAR_MISSING_2", var2Missing)
|
||||
})
|
||||
|
||||
err := os.Setenv("TEST_LEGO_VAR_EXIST_1", "VAR1")
|
||||
require.NoError(t, err)
|
||||
err = os.Setenv("TEST_LEGO_VAR_EXIST_2", "VAR2")
|
||||
require.NoError(t, err)
|
||||
err = os.Unsetenv("TEST_LEGO_VAR_MISSING_1")
|
||||
require.NoError(t, err)
|
||||
err = os.Unsetenv("TEST_LEGO_VAR_MISSING_2")
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
main string
|
||||
defaultValue string
|
||||
alts []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "with value and no alternative",
|
||||
main: "TEST_LEGO_VAR_EXIST_1",
|
||||
defaultValue: "oops",
|
||||
expected: "VAR1",
|
||||
},
|
||||
{
|
||||
desc: "with value and alternatives",
|
||||
main: "TEST_LEGO_VAR_EXIST_1",
|
||||
defaultValue: "oops",
|
||||
alts: []string{"TEST_LEGO_VAR_MISSING_1"},
|
||||
expected: "VAR1",
|
||||
},
|
||||
{
|
||||
desc: "without value and no alternatives",
|
||||
main: "TEST_LEGO_VAR_MISSING_1",
|
||||
defaultValue: "oops",
|
||||
expected: "oops",
|
||||
},
|
||||
{
|
||||
desc: "without value and alternatives",
|
||||
main: "TEST_LEGO_VAR_MISSING_1",
|
||||
defaultValue: "oops",
|
||||
alts: []string{"TEST_LEGO_VAR_EXIST_1"},
|
||||
expected: "VAR1",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
value := GetOneWithFallback(test.main, test.defaultValue, ParseString, test.alts...)
|
||||
assert.Equal(t, test.expected, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrDefaultInt(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
|
|
@ -3,6 +3,7 @@ package tester
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// EnvTest Environment variables manager for tests.
|
||||
|
@ -143,10 +144,5 @@ func (e *EnvTest) Apply(envVars map[string]string) {
|
|||
}
|
||||
|
||||
func (e *EnvTest) isManagedKey(varName string) bool {
|
||||
for _, key := range e.keys {
|
||||
if key == varName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(e.keys, varName)
|
||||
}
|
||||
|
|
|
@ -28,10 +28,10 @@ const (
|
|||
type acmeDNSClient interface {
|
||||
// UpdateTXTRecord updates the provided account's TXT record
|
||||
// to the given value or returns an error.
|
||||
UpdateTXTRecord(goacmedns.Account, string) error
|
||||
UpdateTXTRecord(account goacmedns.Account, value string) error
|
||||
// RegisterAccount registers and returns a new account
|
||||
// with the given allowFrom restriction or returns an error.
|
||||
RegisterAccount([]string) (goacmedns.Account, error)
|
||||
RegisterAccount(allowFrom []string) (goacmedns.Account, error)
|
||||
}
|
||||
|
||||
// DNSProvider implements the challenge.Provider interface.
|
||||
|
|
|
@ -108,7 +108,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
case config.APIKey != "" && config.SecretKey != "":
|
||||
credential = credentials.NewAccessKeyCredential(config.APIKey, config.SecretKey)
|
||||
default:
|
||||
return nil, fmt.Errorf("alicloud: ram role or credentials missing")
|
||||
return nil, errors.New("alicloud: ram role or credentials missing")
|
||||
}
|
||||
|
||||
conf := sdk.NewConfig().WithTimeout(config.HTTPTimeout)
|
||||
|
@ -198,7 +198,7 @@ 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)
|
||||
return "", fmt.Errorf("could not find zone: %w", err)
|
||||
}
|
||||
|
||||
var hostedZone alidns.DomainInDescribeDomains
|
||||
|
|
|
@ -29,5 +29,5 @@ lego --email you@example.com --dns alidns --domains my.example.org run
|
|||
ALICLOUD_HTTP_TIMEOUT = "API request timeout"
|
||||
|
||||
[Links]
|
||||
API = "https://www.alibabacloud.com/help/doc-detail/42875.htm"
|
||||
API = "https://www.alibabacloud.com/help/en/alibaba-cloud-dns/latest/api-alidns-2015-01-09-dir-parsing-records"
|
||||
GoClient = "https://github.com/aliyun/alibaba-cloud-sdk-go"
|
||||
|
|
|
@ -115,7 +115,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("allinkl: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("allinkl: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/internal/errutils"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
)
|
||||
|
||||
const apiEndpoint = "https://kasapi.kasserver.com/soap/KasApi.php"
|
||||
|
|
|
@ -111,7 +111,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arvancloud: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("arvancloud: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
authZone = dns01.UnFqdn(authZone)
|
||||
|
@ -152,7 +152,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("arvancloud: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("arvancloud: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
authZone = dns01.UnFqdn(authZone)
|
||||
|
@ -166,7 +166,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
}
|
||||
|
||||
if err := d.client.DeleteRecord(context.Background(), authZone, recordID); err != nil {
|
||||
return fmt.Errorf("arvancloud: failed to delate TXT record: id=%s: %w", recordID, err)
|
||||
return fmt.Errorf("arvancloud: failed to delete TXT record: id=%s: %w", recordID, err)
|
||||
}
|
||||
|
||||
// deletes record ID from map
|
||||
|
|
|
@ -108,7 +108,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("aurora: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("aurora: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
// 1. Aurora will happily create the TXT record when it is provided a fqdn,
|
||||
|
@ -160,7 +160,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(info.EffectiveFQDN))
|
||||
if err != nil {
|
||||
return fmt.Errorf("aurora: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("aurora: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
authZone = dns01.UnFqdn(authZone)
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/go-acme/lego/v4/platform/tester"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -133,10 +132,10 @@ func TestLivePresent(t *testing.T) {
|
|||
|
||||
envTest.RestoreEnv()
|
||||
provider, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = provider.Present(envTest.GetDomain(), "", "123d==")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestLiveCleanUp(t *testing.T) {
|
||||
|
@ -146,8 +145,8 @@ func TestLiveCleanUp(t *testing.T) {
|
|||
|
||||
envTest.RestoreEnv()
|
||||
provider, err := NewDNSProvider()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ func (d *dnsProviderPrivate) getHostedZoneID(ctx context.Context, fqdn string) (
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(fqdn)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not find zone for FQDN %q: %w", fqdn, err)
|
||||
return "", fmt.Errorf("could not find zone: %w", err)
|
||||
}
|
||||
|
||||
dc := privatedns.NewPrivateZonesClientWithBaseURI(d.config.ResourceManagerEndpoint, d.config.SubscriptionID)
|
||||
|
|
|
@ -118,7 +118,7 @@ func (d *dnsProviderPublic) getHostedZoneID(ctx context.Context, fqdn string) (s
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(fqdn)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not find zone for FQDN %q: %w", fqdn, err)
|
||||
return "", fmt.Errorf("could not find zone: %w", err)
|
||||
}
|
||||
|
||||
dc := dns.NewZonesClientWithBaseURI(d.config.ResourceManagerEndpoint, d.config.SubscriptionID)
|
||||
|
|
|
@ -3,14 +3,19 @@
|
|||
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"
|
||||
)
|
||||
|
||||
|
@ -28,9 +33,22 @@ const (
|
|||
EnvClientID = envNamespace + "CLIENT_ID"
|
||||
EnvClientSecret = envNamespace + "CLIENT_SECRET"
|
||||
|
||||
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"
|
||||
|
||||
EnvServiceDiscoveryFilter = envNamespace + "SERVICEDISCOVERY_FILTER"
|
||||
|
||||
EnvTTL = envNamespace + "TTL"
|
||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||
|
||||
EnvGitHubOIDCRequestURL = "ACTIONS_ID_TOKEN_REQUEST_URL"
|
||||
EnvGitHubOIDCRequestToken = "ACTIONS_ID_TOKEN_REQUEST_TOKEN"
|
||||
)
|
||||
|
||||
// Config is used to configure the creation of the DNSProvider.
|
||||
|
@ -46,9 +64,20 @@ type Config struct {
|
|||
ClientSecret string
|
||||
TenantID string
|
||||
|
||||
OIDCToken string
|
||||
OIDCTokenFilePath string
|
||||
OIDCRequestURL string
|
||||
OIDCRequestToken string
|
||||
|
||||
AuthMethod string
|
||||
AuthMSITimeout time.Duration
|
||||
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
TTL int
|
||||
HTTPClient *http.Client
|
||||
|
||||
ServiceDiscoveryFilter string
|
||||
}
|
||||
|
||||
// NewDefaultConfig returns a default configuration for the DNSProvider.
|
||||
|
@ -94,6 +123,22 @@ func NewDNSProvider() (*DNSProvider, error) {
|
|||
config.ClientSecret = env.GetOrFile(EnvClientSecret)
|
||||
config.TenantID = env.GetOrFile(EnvTenantID)
|
||||
|
||||
config.OIDCToken = env.GetOrFile(EnvOIDCToken)
|
||||
config.OIDCTokenFilePath = env.GetOrFile(EnvOIDCTokenFilePath)
|
||||
|
||||
config.ServiceDiscoveryFilter = env.GetOrFile(EnvServiceDiscoveryFilter)
|
||||
|
||||
oidcValues, _ := env.GetWithFallback(
|
||||
[]string{EnvOIDCRequestURL, EnvGitHubOIDCRequestURL},
|
||||
[]string{EnvOIDCRequestToken, EnvGitHubOIDCRequestToken},
|
||||
)
|
||||
|
||||
config.OIDCRequestURL = oidcValues[EnvOIDCRequestURL]
|
||||
config.OIDCRequestToken = oidcValues[EnvOIDCRequestToken]
|
||||
|
||||
config.AuthMethod = env.GetOrFile(EnvAuthMethod)
|
||||
config.AuthMSITimeout = env.GetOrDefaultSecond(EnvAuthMSITimeout, 2*time.Second)
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
||||
|
@ -103,38 +148,13 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
|||
return nil, errors.New("azuredns: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
var err error
|
||||
var credentials azcore.TokenCredential
|
||||
if config.ClientID != "" && config.ClientSecret != "" && config.TenantID != "" {
|
||||
options := azidentity.ClientSecretCredentialOptions{
|
||||
ClientOptions: azcore.ClientOptions{
|
||||
Cloud: config.Environment,
|
||||
},
|
||||
}
|
||||
|
||||
credentials, err = azidentity.NewClientSecretCredential(config.TenantID, config.ClientID, config.ClientSecret, &options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
} else {
|
||||
options := azidentity.DefaultAzureCredentialOptions{
|
||||
ClientOptions: azcore.ClientOptions{
|
||||
Cloud: config.Environment,
|
||||
},
|
||||
}
|
||||
|
||||
credentials, err = azidentity.NewDefaultAzureCredential(&options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
if config.HTTPClient == nil {
|
||||
config.HTTPClient = &http.Client{Timeout: 5 * time.Second}
|
||||
}
|
||||
|
||||
if config.SubscriptionID == "" {
|
||||
return nil, errors.New("azuredns: SubscriptionID is missing")
|
||||
}
|
||||
|
||||
if config.ResourceGroup == "" {
|
||||
return nil, errors.New("azuredns: ResourceGroup is missing")
|
||||
credentials, err := getCredentials(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("azuredns: Unable to retrieve valid credentials: %w", err)
|
||||
}
|
||||
|
||||
var dnsProvider challenge.ProviderTimeout
|
||||
|
@ -169,7 +189,89 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
return d.provider.CleanUp(domain, token, keyAuth)
|
||||
}
|
||||
|
||||
func deref[T string | int | int32 | int64](v *T) T {
|
||||
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 getAuthZone(fqdn string) (string, error) {
|
||||
authZone := env.GetOrFile(EnvZoneName)
|
||||
if authZone != "" {
|
||||
return authZone, nil
|
||||
}
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(fqdn)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not find zone: %w", err)
|
||||
}
|
||||
|
||||
return authZone, nil
|
||||
}
|
||||
|
||||
func deref[T any](v *T) T {
|
||||
if v == nil {
|
||||
var zero T
|
||||
return zero
|
||||
|
|
|
@ -27,15 +27,12 @@ lego --domains example.com --email your_example@email.com --dns azuredns run
|
|||
### Using Managed Identity (Azure VM)
|
||||
|
||||
AZURE_TENANT_ID=<your service principal tenant ID> \
|
||||
AZURE_SUBSCRIPTION_ID=<your target zone subscription ID> \
|
||||
AZURE_RESOURCE_GROUP=<your target zone resource group name> \
|
||||
lego --domains example.com --email your_example@email.com --dns azuredns run
|
||||
|
||||
### Using Managed Identity (Azure Arc)
|
||||
|
||||
AZURE_TENANT_ID=<your service principal tenant ID> \
|
||||
AZURE_SUBSCRIPTION_ID=<your target zone subscription ID> \
|
||||
AZURE_RESOURCE_GROUP=<your target zone resource group name> \
|
||||
IMDS_ENDPOINT=http://localhost:40342 \
|
||||
IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token \
|
||||
lego --domains example.com --email your_example@email.com --dns azuredns run
|
||||
|
@ -45,19 +42,75 @@ lego --domains example.com --email your_example@email.com --dns azuredns run
|
|||
Additional = '''
|
||||
## Description
|
||||
|
||||
Azure Credentials are automatically detected in the following locations and prioritized in the following order:
|
||||
Several authentication methods can be used to authenticate against Azure DNS API.
|
||||
|
||||
### Default Azure Credentials (default option)
|
||||
|
||||
Default Azure Credentials automatically detects in the following locations and prioritized in the following order:
|
||||
|
||||
1. Environment variables for client secret: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET`
|
||||
2. Environment variables for client certificate: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_CERTIFICATE_PATH`
|
||||
3. Workload identity for resources hosted in Azure environment (see below)
|
||||
4. Shared credentials file (defaults to `~/.azure`), used by Azure CLI
|
||||
4. Shared credentials (defaults to `~/.azure` folder), used by Azure CLI
|
||||
|
||||
Link:
|
||||
- [Azure Authentication](https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication)
|
||||
|
||||
### Environment variables
|
||||
|
||||
#### Service Discovery
|
||||
|
||||
Lego automatically finds all visible Azure (private) DNS zones using [Azure ResourceGraph query](https://learn.microsoft.com/en-us/azure/governance/resource-graph/).
|
||||
This can be limited by specifying environment variable `AZURE_SUBSCRIPTION_ID` and/or `AZURE_RESOURCE_GROUP` which limits the
|
||||
DNS zones to only a subscription or to one resourceGroup.
|
||||
|
||||
Additionally environment variable `AZURE_SERVICEDISCOVERY_FILTER` can be used to filter DNS zones with an addition Kusto filter eg:
|
||||
|
||||
```
|
||||
resources
|
||||
| where type =~ "microsoft.network/dnszones"
|
||||
| ${AZURE_SERVICEDISCOVERY_FILTER}
|
||||
| project subscriptionId, resourceGroup, name
|
||||
```
|
||||
|
||||
|
||||
#### Client secret
|
||||
|
||||
The Azure Credentials can be configured using the following environment variables:
|
||||
* AZURE_CLIENT_ID = "Client ID"
|
||||
* AZURE_CLIENT_SECRET = "Client secret"
|
||||
* AZURE_TENANT_ID = "Tenant ID"
|
||||
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `env`.
|
||||
|
||||
#### Client certificate
|
||||
|
||||
The Azure Credentials can be configured using the following environment variables:
|
||||
* AZURE_CLIENT_ID = "Client ID"
|
||||
* AZURE_CLIENT_CERTIFICATE_PATH = "Client certificate path"
|
||||
* AZURE_TENANT_ID = "Tenant ID"
|
||||
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `env`.
|
||||
|
||||
### Workload identity
|
||||
|
||||
#### Azure Managed Identity
|
||||
Workload identity allows workloads running Azure Kubernetes Services (AKS) clusters to authenticate as an Azure AD application identity using federated credentials.
|
||||
|
||||
This must be configured in kubernetes workload deployment in one hand and on the Azure AD application registration in the other hand.
|
||||
|
||||
Here is a summary of the steps to follow to use it :
|
||||
* create a `ServiceAccount` resource, add following annotations to reference the targeted Azure AD application registration : `azure.workload.identity/client-id` and `azure.workload.identity/tenant-id`.
|
||||
* on the `Deployment` resource you must reference the previous `ServiceAccount` and add the following label : `azure.workload.identity/use: "true"`.
|
||||
* create a federated credentials of type `Kubernetes accessing Azure resources`, add the cluster issuer URL and add the namespace and name of your kubernetes service account.
|
||||
|
||||
Link :
|
||||
- [Azure AD Workload identity](https://azure.github.io/azure-workload-identity/docs/topics/service-account-labels-and-annotations.html)
|
||||
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `wli`.
|
||||
|
||||
### Azure Managed Identity
|
||||
|
||||
#### Azure Managed Identity (with Azure workload)
|
||||
|
||||
The Azure Managed Identity service allows linking Azure AD identities to Azure resources, without needing to manually manage client IDs and secrets.
|
||||
|
||||
|
@ -87,6 +140,11 @@ az role assignment create \
|
|||
--scope "/subscriptions/${AZURE_SUBSCRIPTION_ID}/resourceGroups/${AZURE_RESOURCE_GROUP}/providers/Microsoft.Network/dnszones/${AZURE_DNS_ZONE}/TXT/${AZ_RECORD_SET}"
|
||||
```
|
||||
|
||||
A timeout wrapper is configured for this authentication method.
|
||||
The duration can be configured by setting the `AZURE_AUTH_MSI_TIMEOUT`.
|
||||
The default timeout is 2 seconds.
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `msi`.
|
||||
|
||||
#### Azure Managed Identity (with Azure Arc)
|
||||
|
||||
The Azure Arc agent provides the ability to use a Managed Identity on resources hosted outside of Azure
|
||||
|
@ -95,22 +153,26 @@ The Azure Arc agent provides the ability to use a Managed Identity on resources
|
|||
While the upstream `azidentity` SDK will try to automatically identify and use the Azure Arc metadata service,
|
||||
if you get `azuredns: DefaultAzureCredential: failed to acquire a token.` error messages,
|
||||
you may need to set the environment variables:
|
||||
* `IMDS_ENDPOINT=http://localhost:40342`
|
||||
* `IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token`
|
||||
* `IMDS_ENDPOINT=http://localhost:40342`
|
||||
* `IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token`
|
||||
|
||||
#### Workload identity for AKS
|
||||
A timeout wrapper is configured for this authentication method.
|
||||
The duration can be configured by setting the `AZURE_AUTH_MSI_TIMEOUT`.
|
||||
The default timeout is 2 seconds.
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `msi`.
|
||||
|
||||
Workload identity allows workloads running Azure Kubernetes Services (AKS) clusters to authenticate as an Azure AD application identity using federated credentials.
|
||||
### Azure CLI
|
||||
|
||||
This must be configured in kubernetes workload deployment in one hand and on the Azure AD application registration in the other hand.
|
||||
The Azure CLI is a command-line tool provided by Microsoft to interact with Azure resources.
|
||||
It provides an easy way to authenticate by simply running `az login` command.
|
||||
The generated token will be cached by default in the `~/.azure` folder.
|
||||
|
||||
Here is a summary of the steps to follow to use it :
|
||||
* create a `ServiceAccount` resource, add following annotations to reference the targeted Azure AD application registration : `azure.workload.identity/client-id` and `azure.workload.identity/tenant-id`.
|
||||
* on the `Deployment` resource you must reference the previous `ServiceAccount` and add the following label : `azure.workload.identity/use: "true"`.
|
||||
* create a fedreated credentials of type `Kubernetes accessing Azure resources`, add the cluster issuer URL and add the namespace and name of your kubernetes service account.
|
||||
This authentication method can be specifically used by setting the `AZURE_AUTH_METHOD` environment variable to `cli`.
|
||||
|
||||
Link :
|
||||
- [Azure AD Workload identity](https://azure.github.io/azure-workload-identity/docs/topics/service-account-labels-and-annotations.html)
|
||||
### Open ID Connect
|
||||
|
||||
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`.
|
||||
|
||||
'''
|
||||
|
||||
|
@ -119,12 +181,16 @@ Link :
|
|||
AZURE_CLIENT_ID = "Client ID"
|
||||
AZURE_CLIENT_SECRET = "Client secret"
|
||||
AZURE_TENANT_ID = "Tenant ID"
|
||||
AZURE_SUBSCRIPTION_ID = "DNS zone subscription ID"
|
||||
AZURE_RESOURCE_GROUP = "DNS zone resource group"
|
||||
AZURE_CLIENT_CERTIFICATE_PATH = "Client certificate path"
|
||||
[Configuration.Additional]
|
||||
AZURE_ENVIRONMENT = "Azure environment, one of: public, usgovernment, and china"
|
||||
AZURE_SUBSCRIPTION_ID = "DNS zone subscription ID"
|
||||
AZURE_RESOURCE_GROUP = "DNS zone resource group"
|
||||
AZURE_SERVICEDISCOVERY_FILTER = "Advanced ServiceDiscovery filter using Kusto query condition"
|
||||
AZURE_PRIVATE_ZONE = "Set to true to use Azure Private DNS Zones and not public"
|
||||
AZURE_ZONE_NAME = "Zone name to use inside Azure DNS service to add the TXT record in"
|
||||
AZURE_AUTH_METHOD = "Specify which authentication method to use"
|
||||
AZURE_AUTH_MSI_TIMEOUT = "Managed Identity timeout duration"
|
||||
AZURE_TTL = "The TTL of the TXT record used for the DNS challenge"
|
||||
AZURE_POLLING_INTERVAL = "Time between DNS propagation check"
|
||||
AZURE_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package azuredns
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -25,20 +23,10 @@ func TestNewDNSProvider(t *testing.T) {
|
|||
envVars map[string]string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "success",
|
||||
envVars: map[string]string{
|
||||
EnvEnvironment: "",
|
||||
EnvSubscriptionID: "A",
|
||||
EnvResourceGroup: "B",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "unknown environment",
|
||||
envVars: map[string]string{
|
||||
EnvEnvironment: "test",
|
||||
EnvSubscriptionID: "A",
|
||||
EnvResourceGroup: "B",
|
||||
EnvEnvironment: "test",
|
||||
},
|
||||
expected: "azuredns: unknown environment test",
|
||||
},
|
||||
|
@ -67,78 +55,6 @@ func TestNewDNSProvider(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewDNSProviderConfig(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
subscriptionID string
|
||||
resourceGroup string
|
||||
privateZone bool
|
||||
handler func(w http.ResponseWriter, r *http.Request)
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "success (public)",
|
||||
subscriptionID: "A",
|
||||
resourceGroup: "B",
|
||||
privateZone: false,
|
||||
},
|
||||
{
|
||||
desc: "success (private)",
|
||||
subscriptionID: "A",
|
||||
resourceGroup: "B",
|
||||
privateZone: true,
|
||||
},
|
||||
{
|
||||
desc: "SubscriptionID missing",
|
||||
subscriptionID: "",
|
||||
resourceGroup: "",
|
||||
expected: "azuredns: SubscriptionID is missing",
|
||||
},
|
||||
{
|
||||
desc: "ResourceGroup missing",
|
||||
subscriptionID: "A",
|
||||
resourceGroup: "",
|
||||
expected: "azuredns: ResourceGroup is missing",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
config := NewDefaultConfig()
|
||||
config.SubscriptionID = test.subscriptionID
|
||||
config.ResourceGroup = test.resourceGroup
|
||||
config.PrivateZone = test.privateZone
|
||||
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
if test.handler == nil {
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {})
|
||||
} else {
|
||||
mux.HandleFunc("/", test.handler)
|
||||
}
|
||||
|
||||
p, err := NewDNSProviderConfig(config)
|
||||
|
||||
if test.expected != "" {
|
||||
require.EqualError(t, err, test.expected)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, p)
|
||||
require.NotNil(t, p.provider)
|
||||
|
||||
if test.privateZone {
|
||||
assert.IsType(t, p.provider, new(DNSProviderPrivate))
|
||||
} else {
|
||||
assert.IsType(t, p.provider, new(DNSProviderPublic))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLivePresent(t *testing.T) {
|
||||
if !envTest.IsLiveTest() {
|
||||
t.Skip("skipping live test")
|
||||
|
|
105
providers/dns/azuredns/oidc.go
Normal file
105
providers/dns/azuredns/oidc.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
package azuredns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func checkOIDCConfig(config *Config) error {
|
||||
if config.TenantID == "" {
|
||||
return errors.New("azuredns: TenantID is missing")
|
||||
}
|
||||
|
||||
if config.ClientID == "" {
|
||||
return errors.New("azuredns: ClientID is missing")
|
||||
}
|
||||
|
||||
if config.OIDCToken == "" && config.OIDCTokenFilePath == "" && (config.OIDCRequestURL == "" || config.OIDCRequestToken == "") {
|
||||
return errors.New("azuredns: OIDCToken, OIDCTokenFilePath or OIDCRequestURL and OIDCRequestToken must be set")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getOIDCAssertion(config *Config) func(ctx context.Context) (string, error) {
|
||||
return func(ctx context.Context) (string, error) {
|
||||
var token string
|
||||
if config.OIDCToken != "" {
|
||||
token = strings.TrimSpace(config.OIDCToken)
|
||||
}
|
||||
|
||||
if config.OIDCTokenFilePath != "" {
|
||||
fileTokenRaw, err := os.ReadFile(config.OIDCTokenFilePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("azuredns: error retrieving token file with path %s: %w", config.OIDCTokenFilePath, err)
|
||||
}
|
||||
|
||||
fileToken := strings.TrimSpace(string(fileTokenRaw))
|
||||
if config.OIDCToken != fileToken {
|
||||
return "", fmt.Errorf("azuredns: token file with path %s does not match token from environment variable", config.OIDCTokenFilePath)
|
||||
}
|
||||
|
||||
token = fileToken
|
||||
}
|
||||
|
||||
if token == "" && config.OIDCRequestURL != "" && config.OIDCRequestToken != "" {
|
||||
return getOIDCToken(config)
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getOIDCToken(config *Config) (string, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, config.OIDCRequestURL, http.NoBody)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("azuredns: failed to build OIDC request: %w", err)
|
||||
}
|
||||
|
||||
query, err := url.ParseQuery(req.URL.RawQuery)
|
||||
if err != nil {
|
||||
return "", errors.New("azuredns: cannot parse OIDC request URL query")
|
||||
}
|
||||
|
||||
if query.Get("audience") == "" {
|
||||
query.Set("audience", "api://AzureADTokenExchange")
|
||||
req.URL.RawQuery = query.Encode()
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", config.OIDCRequestToken))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
resp, err := config.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("azuredns: cannot request OIDC token: %w", err)
|
||||
}
|
||||
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("azuredns: cannot parse OIDC token response: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusNoContent {
|
||||
return "", fmt.Errorf("azuredns: OIDC token request received HTTP status %d with response: %s", resp.StatusCode, body)
|
||||
}
|
||||
|
||||
var returnedToken struct {
|
||||
Count int `json:"count"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &returnedToken); err != nil {
|
||||
return "", fmt.Errorf("azuredns: cannot unmarshal OIDC token response: %w", err)
|
||||
}
|
||||
|
||||
return returnedToken.Value, nil
|
||||
}
|
|
@ -9,40 +9,30 @@ import (
|
|||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/platform/config/env"
|
||||
)
|
||||
|
||||
// DNSProviderPrivate implements the challenge.Provider interface for Azure Private Zone DNS.
|
||||
type DNSProviderPrivate struct {
|
||||
config *Config
|
||||
zoneClient *armprivatedns.PrivateZonesClient
|
||||
recordClient *armprivatedns.RecordSetsClient
|
||||
config *Config
|
||||
credentials azcore.TokenCredential
|
||||
serviceDiscoveryZones map[string]ServiceDiscoveryZone
|
||||
}
|
||||
|
||||
// NewDNSProviderPrivate creates a DNSProviderPrivate structure with initialized Azure clients.
|
||||
// NewDNSProviderPrivate creates a DNSProviderPrivate structure.
|
||||
func NewDNSProviderPrivate(config *Config, credentials azcore.TokenCredential) (*DNSProviderPrivate, error) {
|
||||
options := arm.ClientOptions{
|
||||
ClientOptions: azcore.ClientOptions{
|
||||
Cloud: config.Environment,
|
||||
},
|
||||
}
|
||||
|
||||
zoneClient, err := armprivatedns.NewPrivateZonesClient(config.SubscriptionID, credentials, &options)
|
||||
zones, err := discoverDNSZones(context.Background(), config, credentials)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recordClient, err := armprivatedns.NewRecordSetsClient(config.SubscriptionID, credentials, &options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("discover DNS zones: %w", err)
|
||||
}
|
||||
|
||||
return &DNSProviderPrivate{
|
||||
config: config,
|
||||
zoneClient: zoneClient,
|
||||
recordClient: recordClient,
|
||||
config: config,
|
||||
credentials: credentials,
|
||||
serviceDiscoveryZones: zones,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -57,18 +47,23 @@ func (d *DNSProviderPrivate) Present(domain, _, keyAuth string) error {
|
|||
ctx := context.Background()
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
zone, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
|
||||
zone, err := d.getHostedZone(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
|
||||
client, err := newPrivateZoneClient(zone, d.credentials, d.config.Environment)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
// Get existing record set
|
||||
rset, err := d.recordClient.Get(ctx, d.config.ResourceGroup, zone, armprivatedns.RecordTypeTXT, subDomain, nil)
|
||||
resp, err := client.Get(ctx, subDomain)
|
||||
if err != nil {
|
||||
var respErr *azcore.ResponseError
|
||||
if !errors.As(err, &respErr) || respErr.StatusCode != http.StatusNotFound {
|
||||
|
@ -77,32 +72,22 @@ func (d *DNSProviderPrivate) Present(domain, _, keyAuth string) error {
|
|||
}
|
||||
|
||||
// Construct unique TXT records using map
|
||||
uniqRecords := map[string]struct{}{info.Value: {}}
|
||||
if rset.RecordSet.Properties != nil && rset.RecordSet.Properties.TxtRecords != nil {
|
||||
for _, txtRecord := range rset.RecordSet.Properties.TxtRecords {
|
||||
// Assume Value doesn't contain multiple strings
|
||||
if len(txtRecord.Value) > 0 {
|
||||
uniqRecords[deref(txtRecord.Value[0])] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
uniqRecords := privateUniqueRecords(resp.RecordSet, info.Value)
|
||||
|
||||
var txtRecords []*armprivatedns.TxtRecord
|
||||
for txt := range uniqRecords {
|
||||
txtRecord := txt
|
||||
txtRecords = append(txtRecords, &armprivatedns.TxtRecord{Value: []*string{&txtRecord}})
|
||||
txtRecords = append(txtRecords, &armprivatedns.TxtRecord{Value: to.SliceOfPtrs(txt)})
|
||||
}
|
||||
|
||||
ttlInt64 := int64(d.config.TTL)
|
||||
rec := armprivatedns.RecordSet{
|
||||
Name: &subDomain,
|
||||
Properties: &armprivatedns.RecordSetProperties{
|
||||
TTL: &ttlInt64,
|
||||
TTL: to.Ptr(int64(d.config.TTL)),
|
||||
TxtRecords: txtRecords,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = d.recordClient.CreateOrUpdate(ctx, d.config.ResourceGroup, zone, armprivatedns.RecordTypeTXT, subDomain, rec, nil)
|
||||
_, err = client.CreateOrUpdate(ctx, subDomain, rec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
@ -115,17 +100,22 @@ func (d *DNSProviderPrivate) CleanUp(domain, _, keyAuth string) error {
|
|||
ctx := context.Background()
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
zone, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
|
||||
zone, err := d.getHostedZone(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
|
||||
client, err := newPrivateZoneClient(zone, d.credentials, d.config.Environment)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
_, err = d.recordClient.Delete(ctx, d.config.ResourceGroup, zone, armprivatedns.RecordTypeTXT, subDomain, nil)
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
_, err = client.Delete(ctx, subDomain)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
@ -134,21 +124,67 @@ func (d *DNSProviderPrivate) CleanUp(domain, _, keyAuth string) error {
|
|||
}
|
||||
|
||||
// Checks that azure has a zone for this domain name.
|
||||
func (d *DNSProviderPrivate) getHostedZoneID(ctx context.Context, fqdn string) (string, error) {
|
||||
if zone := env.GetOrFile(EnvZoneName); zone != "" {
|
||||
return zone, nil
|
||||
}
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(fqdn)
|
||||
func (d *DNSProviderPrivate) getHostedZone(fqdn string) (ServiceDiscoveryZone, error) {
|
||||
authZone, err := getAuthZone(fqdn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return ServiceDiscoveryZone{}, err
|
||||
}
|
||||
|
||||
zone, err := d.zoneClient.Get(ctx, d.config.ResourceGroup, dns01.UnFqdn(authZone), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
azureZone, exists := d.serviceDiscoveryZones[dns01.UnFqdn(authZone)]
|
||||
if !exists {
|
||||
return ServiceDiscoveryZone{}, fmt.Errorf("could not find zone (from discovery): %s", authZone)
|
||||
}
|
||||
|
||||
// zone.Name shouldn't have a trailing dot(.)
|
||||
return dns01.UnFqdn(deref(zone.Name)), nil
|
||||
return azureZone, nil
|
||||
}
|
||||
|
||||
// privateZoneClient provides Azure client for one DNS zone.
|
||||
type privateZoneClient struct {
|
||||
zone ServiceDiscoveryZone
|
||||
recordClient *armprivatedns.RecordSetsClient
|
||||
}
|
||||
|
||||
// newPrivateZoneClient creates privateZoneClient structure with initialized Azure client.
|
||||
func newPrivateZoneClient(zone ServiceDiscoveryZone, credential azcore.TokenCredential, environment cloud.Configuration) (*privateZoneClient, error) {
|
||||
options := &arm.ClientOptions{
|
||||
ClientOptions: azcore.ClientOptions{
|
||||
Cloud: environment,
|
||||
},
|
||||
}
|
||||
|
||||
recordClient, err := armprivatedns.NewRecordSetsClient(zone.SubscriptionID, credential, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &privateZoneClient{
|
||||
zone: zone,
|
||||
recordClient: recordClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c privateZoneClient) Get(ctx context.Context, subDomain string) (armprivatedns.RecordSetsClientGetResponse, error) {
|
||||
return c.recordClient.Get(ctx, c.zone.ResourceGroup, c.zone.Name, armprivatedns.RecordTypeTXT, subDomain, nil)
|
||||
}
|
||||
|
||||
func (c privateZoneClient) CreateOrUpdate(ctx context.Context, subDomain string, rec armprivatedns.RecordSet) (armprivatedns.RecordSetsClientCreateOrUpdateResponse, error) {
|
||||
return c.recordClient.CreateOrUpdate(ctx, c.zone.ResourceGroup, c.zone.Name, armprivatedns.RecordTypeTXT, subDomain, rec, nil)
|
||||
}
|
||||
|
||||
func (c privateZoneClient) Delete(ctx context.Context, subDomain string) (armprivatedns.RecordSetsClientDeleteResponse, error) {
|
||||
return c.recordClient.Delete(ctx, c.zone.ResourceGroup, c.zone.Name, armprivatedns.RecordTypeTXT, subDomain, nil)
|
||||
}
|
||||
|
||||
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
|
||||
if len(txtRecord.Value) > 0 {
|
||||
uniqRecords[deref(txtRecord.Value[0])] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uniqRecords
|
||||
}
|
||||
|
|
|
@ -9,40 +9,30 @@ import (
|
|||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/platform/config/env"
|
||||
)
|
||||
|
||||
// DNSProviderPublic implements the challenge.Provider interface for Azure Public Zone DNS.
|
||||
type DNSProviderPublic struct {
|
||||
config *Config
|
||||
zoneClient *armdns.ZonesClient
|
||||
recordClient *armdns.RecordSetsClient
|
||||
config *Config
|
||||
credentials azcore.TokenCredential
|
||||
serviceDiscoveryZones map[string]ServiceDiscoveryZone
|
||||
}
|
||||
|
||||
// NewDNSProviderPublic creates a DNSProviderPublic structure with intialised Azure clients.
|
||||
// NewDNSProviderPublic creates a DNSProviderPublic structure.
|
||||
func NewDNSProviderPublic(config *Config, credentials azcore.TokenCredential) (*DNSProviderPublic, error) {
|
||||
options := arm.ClientOptions{
|
||||
ClientOptions: azcore.ClientOptions{
|
||||
Cloud: config.Environment,
|
||||
},
|
||||
}
|
||||
|
||||
zoneClient, err := armdns.NewZonesClient(config.SubscriptionID, credentials, &options)
|
||||
zones, err := discoverDNSZones(context.Background(), config, credentials)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recordClient, err := armdns.NewRecordSetsClient(config.SubscriptionID, credentials, &options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("discover DNS zones: %w", err)
|
||||
}
|
||||
|
||||
return &DNSProviderPublic{
|
||||
config: config,
|
||||
zoneClient: zoneClient,
|
||||
recordClient: recordClient,
|
||||
config: config,
|
||||
credentials: credentials,
|
||||
serviceDiscoveryZones: zones,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -57,18 +47,23 @@ func (d *DNSProviderPublic) Present(domain, _, keyAuth string) error {
|
|||
ctx := context.Background()
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
zone, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
|
||||
zone, err := d.getHostedZone(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
|
||||
client, err := newPublicZoneClient(zone, d.credentials, d.config.Environment)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
// Get existing record set
|
||||
rset, err := d.recordClient.Get(ctx, d.config.ResourceGroup, zone, subDomain, armdns.RecordTypeTXT, nil)
|
||||
resp, err := client.Get(ctx, subDomain)
|
||||
if err != nil {
|
||||
var respErr *azcore.ResponseError
|
||||
if !errors.As(err, &respErr) || respErr.StatusCode != http.StatusNotFound {
|
||||
|
@ -76,33 +71,22 @@ func (d *DNSProviderPublic) Present(domain, _, keyAuth string) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Construct unique TXT records using map
|
||||
uniqRecords := map[string]struct{}{info.Value: {}}
|
||||
if rset.RecordSet.Properties != nil && rset.RecordSet.Properties.TxtRecords != nil {
|
||||
for _, txtRecord := range rset.RecordSet.Properties.TxtRecords {
|
||||
// Assume Value doesn't contain multiple strings
|
||||
if len(txtRecord.Value) > 0 {
|
||||
uniqRecords[deref(txtRecord.Value[0])] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
uniqRecords := publicUniqueRecords(resp.RecordSet, info.Value)
|
||||
|
||||
var txtRecords []*armdns.TxtRecord
|
||||
for txt := range uniqRecords {
|
||||
txtRecord := txt
|
||||
txtRecords = append(txtRecords, &armdns.TxtRecord{Value: []*string{&txtRecord}})
|
||||
txtRecords = append(txtRecords, &armdns.TxtRecord{Value: to.SliceOfPtrs(txt)})
|
||||
}
|
||||
|
||||
ttlInt64 := int64(d.config.TTL)
|
||||
rec := armdns.RecordSet{
|
||||
Name: &subDomain,
|
||||
Properties: &armdns.RecordSetProperties{
|
||||
TTL: &ttlInt64,
|
||||
TTL: to.Ptr(int64(d.config.TTL)),
|
||||
TxtRecords: txtRecords,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = d.recordClient.CreateOrUpdate(ctx, d.config.ResourceGroup, zone, subDomain, armdns.RecordTypeTXT, rec, nil)
|
||||
_, err = client.CreateOrUpdate(ctx, subDomain, rec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
@ -115,17 +99,22 @@ func (d *DNSProviderPublic) CleanUp(domain, _, keyAuth string) error {
|
|||
ctx := context.Background()
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
zone, err := d.getHostedZoneID(ctx, info.EffectiveFQDN)
|
||||
zone, err := d.getHostedZone(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone)
|
||||
client, err := newPublicZoneClient(zone, d.credentials, d.config.Environment)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
_, err = d.recordClient.Delete(ctx, d.config.ResourceGroup, zone, subDomain, armdns.RecordTypeTXT, nil)
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zone.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
||||
_, err = client.Delete(ctx, subDomain)
|
||||
if err != nil {
|
||||
return fmt.Errorf("azuredns: %w", err)
|
||||
}
|
||||
|
@ -134,21 +123,66 @@ func (d *DNSProviderPublic) CleanUp(domain, _, keyAuth string) error {
|
|||
}
|
||||
|
||||
// Checks that azure has a zone for this domain name.
|
||||
func (d *DNSProviderPublic) getHostedZoneID(ctx context.Context, fqdn string) (string, error) {
|
||||
if zone := env.GetOrFile(EnvZoneName); zone != "" {
|
||||
return zone, nil
|
||||
}
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(fqdn)
|
||||
func (d *DNSProviderPublic) getHostedZone(fqdn string) (ServiceDiscoveryZone, error) {
|
||||
authZone, err := getAuthZone(fqdn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return ServiceDiscoveryZone{}, err
|
||||
}
|
||||
|
||||
zone, err := d.zoneClient.Get(ctx, d.config.ResourceGroup, dns01.UnFqdn(authZone), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
azureZone, exists := d.serviceDiscoveryZones[dns01.UnFqdn(authZone)]
|
||||
if !exists {
|
||||
return ServiceDiscoveryZone{}, fmt.Errorf("could not find zone (from discovery): %s", authZone)
|
||||
}
|
||||
|
||||
// zone.Name shouldn't have a trailing dot(.)
|
||||
return dns01.UnFqdn(deref(zone.Name)), nil
|
||||
return azureZone, nil
|
||||
}
|
||||
|
||||
type publicZoneClient struct {
|
||||
zone ServiceDiscoveryZone
|
||||
recordClient *armdns.RecordSetsClient
|
||||
}
|
||||
|
||||
// newPublicZoneClient creates publicZoneClient structure with initialized Azure client.
|
||||
func newPublicZoneClient(zone ServiceDiscoveryZone, credential azcore.TokenCredential, environment cloud.Configuration) (*publicZoneClient, error) {
|
||||
options := &arm.ClientOptions{
|
||||
ClientOptions: azcore.ClientOptions{
|
||||
Cloud: environment,
|
||||
},
|
||||
}
|
||||
|
||||
recordClient, err := armdns.NewRecordSetsClient(zone.SubscriptionID, credential, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &publicZoneClient{
|
||||
zone: zone,
|
||||
recordClient: recordClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c publicZoneClient) Get(ctx context.Context, subDomain string) (armdns.RecordSetsClientGetResponse, error) {
|
||||
return c.recordClient.Get(ctx, c.zone.ResourceGroup, c.zone.Name, subDomain, armdns.RecordTypeTXT, nil)
|
||||
}
|
||||
|
||||
func (c publicZoneClient) CreateOrUpdate(ctx context.Context, subDomain string, rec armdns.RecordSet) (armdns.RecordSetsClientCreateOrUpdateResponse, error) {
|
||||
return c.recordClient.CreateOrUpdate(ctx, c.zone.ResourceGroup, c.zone.Name, subDomain, armdns.RecordTypeTXT, rec, nil)
|
||||
}
|
||||
|
||||
func (c publicZoneClient) Delete(ctx context.Context, subDomain string) (armdns.RecordSetsClientDeleteResponse, error) {
|
||||
return c.recordClient.Delete(ctx, c.zone.ResourceGroup, c.zone.Name, subDomain, armdns.RecordTypeTXT, nil)
|
||||
}
|
||||
|
||||
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
|
||||
if len(txtRecord.Value) > 0 {
|
||||
uniqRecords[deref(txtRecord.Value[0])] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uniqRecords
|
||||
}
|
||||
|
|
126
providers/dns/azuredns/servicediscovery.go
Normal file
126
providers/dns/azuredns/servicediscovery.go
Normal file
|
@ -0,0 +1,126 @@
|
|||
package azuredns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph"
|
||||
)
|
||||
|
||||
type ServiceDiscoveryZone struct {
|
||||
Name string
|
||||
SubscriptionID string
|
||||
ResourceGroup string
|
||||
}
|
||||
|
||||
const (
|
||||
ResourceGraphTypePublicDNSZone = "microsoft.network/dnszones"
|
||||
ResourceGraphTypePrivateDNSZone = "microsoft.network/privatednszones"
|
||||
)
|
||||
|
||||
const ResourceGraphQueryOptionsTop int32 = 1000
|
||||
|
||||
// discoverDNSZones finds all visible Azure DNS zones based on optional subscriptionID, resourceGroup and serviceDiscovery filter using Kusto query.
|
||||
func discoverDNSZones(ctx context.Context, config *Config, credentials azcore.TokenCredential) (map[string]ServiceDiscoveryZone, error) {
|
||||
options := &arm.ClientOptions{
|
||||
ClientOptions: azcore.ClientOptions{
|
||||
Cloud: config.Environment,
|
||||
},
|
||||
}
|
||||
|
||||
client, err := armresourcegraph.NewClient(credentials, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set options
|
||||
requestOptions := &armresourcegraph.QueryRequestOptions{
|
||||
ResultFormat: to.Ptr(armresourcegraph.ResultFormatObjectArray),
|
||||
Top: to.Ptr(ResourceGraphQueryOptionsTop),
|
||||
Skip: to.Ptr[int32](0),
|
||||
}
|
||||
|
||||
zones := map[string]ServiceDiscoveryZone{}
|
||||
for {
|
||||
// create the query request
|
||||
request := armresourcegraph.QueryRequest{
|
||||
Query: to.Ptr(createGraphQuery(config)),
|
||||
Options: requestOptions,
|
||||
}
|
||||
|
||||
result, err := client.Resources(ctx, request, nil)
|
||||
if err != nil {
|
||||
return zones, err
|
||||
}
|
||||
|
||||
resultList, ok := result.Data.([]any)
|
||||
if !ok {
|
||||
// got invalid or empty data, skipping
|
||||
break
|
||||
}
|
||||
|
||||
for _, row := range resultList {
|
||||
rowData, ok := row.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
zoneName, ok := rowData["name"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exists := zones[zoneName]; exists {
|
||||
return zones, fmt.Errorf(`found duplicate dns zone "%s"`, zoneName)
|
||||
}
|
||||
|
||||
zones[zoneName] = ServiceDiscoveryZone{
|
||||
Name: zoneName,
|
||||
ResourceGroup: rowData["resourceGroup"].(string),
|
||||
SubscriptionID: rowData["subscriptionId"].(string),
|
||||
}
|
||||
}
|
||||
|
||||
*requestOptions.Skip += ResourceGraphQueryOptionsTop
|
||||
|
||||
if result.TotalRecords != nil {
|
||||
if int64(deref(requestOptions.Skip)) >= deref(result.TotalRecords) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
func createGraphQuery(config *Config) string {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteString("\nresources\n")
|
||||
|
||||
resourceType := ResourceGraphTypePublicDNSZone
|
||||
if config.PrivateZone {
|
||||
resourceType = ResourceGraphTypePrivateDNSZone
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(buf, "| where type =~ %q\n", resourceType)
|
||||
|
||||
if config.SubscriptionID != "" {
|
||||
_, _ = fmt.Fprintf(buf, "| where subscriptionId =~ %q\n", config.SubscriptionID)
|
||||
}
|
||||
|
||||
if config.ResourceGroup != "" {
|
||||
_, _ = fmt.Fprintf(buf, "| where resourceGroup =~ %q\n", config.ResourceGroup)
|
||||
}
|
||||
|
||||
if config.ServiceDiscoveryFilter != "" {
|
||||
_, _ = fmt.Fprintf(buf, "| %s\n", config.ServiceDiscoveryFilter)
|
||||
}
|
||||
|
||||
buf.WriteString("| project subscriptionId, resourceGroup, name")
|
||||
|
||||
return buf.String()
|
||||
}
|
129
providers/dns/azuredns/servicediscovery_test.go
Normal file
129
providers/dns/azuredns/servicediscovery_test.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
package azuredns
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_createGraphQuery(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
cfg *Config
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "empty configuration (public)",
|
||||
cfg: &Config{},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/dnszones"
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
{
|
||||
desc: "SubscriptionID (public)",
|
||||
cfg: &Config{
|
||||
SubscriptionID: "123",
|
||||
},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/dnszones"
|
||||
| where subscriptionId =~ "123"
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
{
|
||||
desc: "ResourceGroup (public)",
|
||||
cfg: &Config{
|
||||
ResourceGroup: "123",
|
||||
},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/dnszones"
|
||||
| where resourceGroup =~ "123"
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
{
|
||||
desc: "ServiceDiscoveryFilter (public)",
|
||||
cfg: &Config{
|
||||
ServiceDiscoveryFilter: "123",
|
||||
},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/dnszones"
|
||||
| 123
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
{
|
||||
desc: "empty configuration (private)",
|
||||
cfg: &Config{
|
||||
PrivateZone: true,
|
||||
},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/privatednszones"
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
{
|
||||
desc: "SubscriptionID (private)",
|
||||
cfg: &Config{
|
||||
SubscriptionID: "123",
|
||||
PrivateZone: true,
|
||||
},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/privatednszones"
|
||||
| where subscriptionId =~ "123"
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
{
|
||||
desc: "ResourceGroup (private)",
|
||||
cfg: &Config{
|
||||
ResourceGroup: "123",
|
||||
PrivateZone: true,
|
||||
},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/privatednszones"
|
||||
| where resourceGroup =~ "123"
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
{
|
||||
desc: "ServiceDiscoveryFilter (private)",
|
||||
cfg: &Config{
|
||||
ServiceDiscoveryFilter: "123",
|
||||
PrivateZone: true,
|
||||
},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/privatednszones"
|
||||
| 123
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
{
|
||||
desc: "all (private)",
|
||||
cfg: &Config{
|
||||
SubscriptionID: "123",
|
||||
ResourceGroup: "456",
|
||||
ServiceDiscoveryFilter: "789",
|
||||
PrivateZone: true,
|
||||
},
|
||||
expected: `
|
||||
resources
|
||||
| where type =~ "microsoft.network/privatednszones"
|
||||
| where subscriptionId =~ "123"
|
||||
| where resourceGroup =~ "456"
|
||||
| 789
|
||||
| project subscriptionId, resourceGroup, name`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
query := createGraphQuery(test.cfg)
|
||||
assert.Equal(t, strings.ReplaceAll(test.expected, "\r", ""), query)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -108,7 +108,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("brandit: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("brandit: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
|
||||
|
@ -155,7 +155,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("brandit: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("brandit: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
// gets the record's unique ID
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -58,7 +59,7 @@ func (c *Client) ListRecords(ctx context.Context, account, dnsZone string) (*Lis
|
|||
}
|
||||
|
||||
for len(result.Response.RR) < result.Response.Total[0] {
|
||||
query.Add("first", fmt.Sprint(result.Response.Last[0]+1))
|
||||
query.Add("first", strconv.Itoa(result.Response.Last[0]+1))
|
||||
|
||||
tmp := &Response[*ListRecordsResponse]{}
|
||||
err := c.do(ctx, query, tmp)
|
||||
|
@ -76,7 +77,7 @@ func (c *Client) ListRecords(ctx context.Context, account, dnsZone string) (*Lis
|
|||
// AddRecord adds a DNS record.
|
||||
// https://portal.brandit.com/apidocv3#addDNSRR
|
||||
func (c *Client) AddRecord(ctx context.Context, domainName, account, newRecordID string, record Record) (*AddRecord, error) {
|
||||
value := strings.Join([]string{record.Name, fmt.Sprint(record.TTL), "IN", record.Type, record.Content}, " ")
|
||||
value := strings.Join([]string{record.Name, strconv.Itoa(record.TTL), "IN", record.Type, record.Content}, " ")
|
||||
|
||||
query := url.Values{}
|
||||
query.Add("command", "addDNSRR")
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/platform/config/env"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/nrdcg/bunny-go"
|
||||
)
|
||||
|
||||
|
@ -94,7 +93,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := getZone(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bunny: failed to find zone: fqdn=%s: %w", info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("bunny: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
@ -129,7 +128,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
|
||||
authZone, err := getZone(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bunny: failed to find zone: fqdn=%s: %w", info.EffectiveFQDN, err)
|
||||
return fmt.Errorf("bunny: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
@ -191,30 +190,11 @@ func getZone(fqdn string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
zone, _, err := splitDomain(dns01.UnFqdn(authZone))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
zone := dns01.UnFqdn(authZone)
|
||||
|
||||
return zone, nil
|
||||
}
|
||||
|
||||
func splitDomain(full string) (string, string, error) {
|
||||
split := dns.Split(full)
|
||||
if len(split) < 2 {
|
||||
return "", "", fmt.Errorf("unsupported domain: %s", full)
|
||||
}
|
||||
|
||||
if len(split) == 2 {
|
||||
return full, "", nil
|
||||
}
|
||||
|
||||
domain := full[split[len(split)-2]:]
|
||||
subDomain := full[:split[len(split)-2]-1]
|
||||
|
||||
return domain, subDomain, nil
|
||||
}
|
||||
|
||||
func pointer[T string | int | int32 | int64](v T) *T { return &v }
|
||||
|
||||
func deref[T string | int | int32 | int64](v *T) T {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue