Browse Source

Merge changes from master branch

pull/5180/head
Laurent Grawet 2 months ago
parent
commit
0f805cc366
  1. 3
      .github/workflows/DNS.yml
  2. 2
      .github/workflows/DragonFlyBSD.yml
  3. 4
      .github/workflows/FreeBSD.yml
  4. 4
      .github/workflows/Linux.yml
  5. 2
      .github/workflows/MacOS.yml
  6. 2
      .github/workflows/NetBSD.yml
  7. 4
      .github/workflows/Omnios.yml
  8. 4
      .github/workflows/OpenBSD.yml
  9. 2
      .github/workflows/PebbleStrict.yml
  10. 4
      .github/workflows/Solaris.yml
  11. 4
      .github/workflows/Ubuntu.yml
  12. 2
      .github/workflows/Windows.yml
  13. 17
      .github/workflows/dockerhub.yml
  14. 1
      .github/workflows/pr_dns.yml
  15. 2
      .github/workflows/pr_notify.yml
  16. 12
      Dockerfile
  17. 788
      acme.sh
  18. 88
      deploy/ali_cdn.sh
  19. 88
      deploy/ali_dcdn.sh
  20. 13
      deploy/docker.sh
  21. 1
      deploy/exim4.sh
  22. 2
      deploy/haproxy.sh
  23. 120
      deploy/proxmoxbs.sh
  24. 11
      deploy/routeros.sh
  25. 200
      deploy/ruckus.sh
  26. 111
      deploy/strongswan.sh
  27. 55
      deploy/synology_dsm.sh
  28. 97
      deploy/truenas.sh
  29. 294
      deploy/truenas_ws.sh
  30. 125
      deploy/unifi.sh
  31. 106
      deploy/vault.sh
  32. 2
      deploy/vsftpd.sh
  33. 31
      dnsapi/dns_1984hosting.sh
  34. 28
      dnsapi/dns_acmedns.sh
  35. 18
      dnsapi/dns_acmeproxy.sh
  36. 17
      dnsapi/dns_active24.sh
  37. 21
      dnsapi/dns_ad.sh
  38. 153
      dnsapi/dns_ali.sh
  39. 185
      dnsapi/dns_alviy.sh
  40. 20
      dnsapi/dns_anx.sh
  41. 23
      dnsapi/dns_artfiles.sh
  42. 19
      dnsapi/dns_arvan.sh
  43. 20
      dnsapi/dns_aurora.sh
  44. 27
      dnsapi/dns_autodns.sh
  45. 24
      dnsapi/dns_aws.sh
  46. 18
      dnsapi/dns_azion.sh
  47. 81
      dnsapi/dns_azure.sh
  48. 281
      dnsapi/dns_beget.sh
  49. 21
      dnsapi/dns_bookmyname.sh
  50. 29
      dnsapi/dns_bunny.sh
  51. 25
      dnsapi/dns_cf.sh
  52. 17
      dnsapi/dns_clouddns.sh
  53. 19
      dnsapi/dns_cloudns.sh
  54. 17
      dnsapi/dns_cn.sh
  55. 15
      dnsapi/dns_conoha.sh
  56. 18
      dnsapi/dns_constellix.sh
  57. 26
      dnsapi/dns_cpanel.sh
  58. 18
      dnsapi/dns_curanet.sh
  59. 47
      dnsapi/dns_cyon.sh
  60. 41
      dnsapi/dns_da.sh
  61. 21
      dnsapi/dns_ddnss.sh
  62. 20
      dnsapi/dns_desec.sh
  63. 25
      dnsapi/dns_df.sh
  64. 26
      dnsapi/dns_dgon.sh
  65. 21
      dnsapi/dns_dnsexit.sh
  66. 21
      dnsapi/dns_dnshome.sh
  67. 20
      dnsapi/dns_dnsimple.sh
  68. 17
      dnsapi/dns_dnsservices.sh
  69. 22
      dnsapi/dns_doapi.sh
  70. 13
      dnsapi/dns_domeneshop.sh
  71. 18
      dnsapi/dns_dp.sh
  72. 18
      dnsapi/dns_dpi.sh
  73. 14
      dnsapi/dns_dreamhost.sh
  74. 18
      dnsapi/dns_duckdns.sh
  75. 16
      dnsapi/dns_durabledns.sh
  76. 25
      dnsapi/dns_dyn.sh
  77. 25
      dnsapi/dns_dynu.sh
  78. 28
      dnsapi/dns_dynv6.sh
  79. 23
      dnsapi/dns_easydns.sh
  80. 163
      dnsapi/dns_edgecenter.sh
  81. 25
      dnsapi/dns_edgedns.sh
  82. 28
      dnsapi/dns_euserv.sh
  83. 12
      dnsapi/dns_exoscale.sh
  84. 35
      dnsapi/dns_fornex.sh
  85. 19
      dnsapi/dns_freedns.sh
  86. 105
      dnsapi/dns_freemyip.sh
  87. 21
      dnsapi/dns_gandi_livedns.sh
  88. 10
      dnsapi/dns_gcloud.sh
  89. 18
      dnsapi/dns_gcore.sh
  90. 20
      dnsapi/dns_gd.sh
  91. 18
      dnsapi/dns_geoscaling.sh
  92. 17
      dnsapi/dns_googledomains.sh
  93. 23
      dnsapi/dns_he.sh
  94. 44
      dnsapi/dns_he_ddns.sh
  95. 18
      dnsapi/dns_hetzner.sh
  96. 18
      dnsapi/dns_hexonet.sh
  97. 15
      dnsapi/dns_hostingde.sh
  98. 18
      dnsapi/dns_huaweicloud.sh
  99. 14
      dnsapi/dns_infoblox.sh
  100. 15
      dnsapi/dns_infomaniak.sh

3
.github/workflows/DNS.yml

@ -1,5 +1,6 @@
name: DNS name: DNS
on: on:
workflow_dispatch:
push: push:
paths: paths:
- 'dnsapi/*.sh' - 'dnsapi/*.sh'
@ -280,7 +281,7 @@ jobs:
- uses: vmactions/openbsd-vm@v1 - uses: vmactions/openbsd-vm@v1
with: with:
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
prepare: pkg_add socat curl
prepare: pkg_add socat curl libiconv
usesh: true usesh: true
copyback: false copyback: false
run: | run: |

2
.github/workflows/DragonFlyBSD.yml

@ -29,7 +29,7 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
#- TEST_ACME_Server: "ZeroSSL.com" #- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA" # CA: "ZeroSSL RSA Domain Secure Site CA"

4
.github/workflows/FreeBSD.yml

@ -29,12 +29,12 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
- TEST_ACME_Server: "LetsEncrypt.org_test" - TEST_ACME_Server: "LetsEncrypt.org_test"
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1 ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com" #- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"

4
.github/workflows/Linux.yml

@ -26,11 +26,11 @@ jobs:
Linux: Linux:
strategy: strategy:
matrix: matrix:
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:7", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
TEST_LOCAL: 1 TEST_LOCAL: 1
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
TEST_ACME_Server: "LetsEncrypt.org_test" TEST_ACME_Server: "LetsEncrypt.org_test"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

2
.github/workflows/MacOS.yml

@ -29,7 +29,7 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
#- TEST_ACME_Server: "ZeroSSL.com" #- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA" # CA: "ZeroSSL RSA Domain Secure Site CA"

2
.github/workflows/NetBSD.yml

@ -29,7 +29,7 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
#- TEST_ACME_Server: "ZeroSSL.com" #- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA" # CA: "ZeroSSL RSA Domain Secure Site CA"

4
.github/workflows/Omnios.yml

@ -29,12 +29,12 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
- TEST_ACME_Server: "LetsEncrypt.org_test" - TEST_ACME_Server: "LetsEncrypt.org_test"
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1 ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com" #- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"

4
.github/workflows/OpenBSD.yml

@ -29,12 +29,12 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
- TEST_ACME_Server: "LetsEncrypt.org_test" - TEST_ACME_Server: "LetsEncrypt.org_test"
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1 ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com" #- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"

2
.github/workflows/PebbleStrict.yml

@ -37,7 +37,7 @@ jobs:
- name: Install tools - name: Install tools
run: sudo apt-get install -y socat run: sudo apt-get install -y socat
- name: Run Pebble - name: Run Pebble
run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker-compose up -d
run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker compose up -d
- name: Set up Pebble - name: Set up Pebble
run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4 run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4
- name: Clone acmetest - name: Clone acmetest

4
.github/workflows/Solaris.yml

@ -29,12 +29,12 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
- TEST_ACME_Server: "LetsEncrypt.org_test" - TEST_ACME_Server: "LetsEncrypt.org_test"
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1 ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com" #- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"

4
.github/workflows/Ubuntu.yml

@ -29,12 +29,12 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
- TEST_ACME_Server: "LetsEncrypt.org_test" - TEST_ACME_Server: "LetsEncrypt.org_test"
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1 ACME_USE_WGET: 1
- TEST_ACME_Server: "ZeroSSL.com" - TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"

2
.github/workflows/Windows.yml

@ -29,7 +29,7 @@ jobs:
CA_ECDSA: "" CA_ECDSA: ""
CA: "" CA: ""
CA_EMAIL: "" CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
TEST_PREFERRED_CHAIN: (STAGING)
#- TEST_ACME_Server: "ZeroSSL.com" #- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA" # CA: "ZeroSSL RSA Domain Secure Site CA"

17
.github/workflows/dockerhub.yml

@ -15,6 +15,8 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
env:
DOCKER_IMAGE: neilpang/acme.sh
jobs: jobs:
CheckToken: CheckToken:
@ -42,8 +44,15 @@ jobs:
steps: steps:
- name: checkout code - name: checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5.5.1
with:
images: ${DOCKER_IMAGE}
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: login to docker hub - name: login to docker hub
@ -51,8 +60,6 @@ jobs:
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- name: build and push the image - name: build and push the image
run: | run: |
DOCKER_IMAGE=neilpang/acme.sh
if [[ $GITHUB_REF == refs/tags/* ]]; then if [[ $GITHUB_REF == refs/tags/* ]]; then
DOCKER_IMAGE_TAG=${GITHUB_REF#refs/tags/} DOCKER_IMAGE_TAG=${GITHUB_REF#refs/tags/}
fi fi
@ -66,8 +73,14 @@ jobs:
fi fi
fi fi
DOCKER_LABELS=()
while read -r label; do
DOCKER_LABELS+=(--label "${label}")
done <<<"${DOCKER_METADATA_OUTPUT_LABELS}"
docker buildx build \ docker buildx build \
--tag ${DOCKER_IMAGE}:${DOCKER_IMAGE_TAG} \ --tag ${DOCKER_IMAGE}:${DOCKER_IMAGE_TAG} \
"${DOCKER_LABELS[@]}" \
--output "type=image,push=true" \ --output "type=image,push=true" \
--build-arg AUTO_UPGRADE=${AUTO_UPGRADE} \ --build-arg AUTO_UPGRADE=${AUTO_UPGRADE} \
--platform linux/arm64/v8,linux/amd64,linux/arm/v6,linux/arm/v7,linux/386,linux/ppc64le,linux/s390x . --platform linux/arm64/v8,linux/amd64,linux/arm/v6,linux/arm/v7,linux/386,linux/ppc64le,linux/s390x .

1
.github/workflows/pr_dns.yml

@ -23,6 +23,7 @@ jobs:
First thing: don't send PR to the master branch, please send to the dev branch instead. First thing: don't send PR to the master branch, please send to the dev branch instead.
Please make sure you've read our [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test). Please make sure you've read our [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test).
Then reply on this message, otherwise, your code will not be reviewed or merged. Then reply on this message, otherwise, your code will not be reviewed or merged.
Please also make sure to add/update the usage here: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2
We look forward to reviewing your Pull request shortly ✨ We look forward to reviewing your Pull request shortly ✨
注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试. 注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试.
` `

2
.github/workflows/pr_notify.yml

@ -1,4 +1,4 @@
name: Check dns api
name: Check notify api
on: on:
pull_request_target: pull_request_target:

12
Dockerfile

@ -1,4 +1,4 @@
FROM alpine:3.17
FROM alpine:3.21
RUN apk --no-cache add -f \ RUN apk --no-cache add -f \
openssl \ openssl \
@ -15,14 +15,18 @@ RUN apk --no-cache add -f \
jq \ jq \
cronie cronie
ENV LE_CONFIG_HOME /acme.sh
ENV LE_CONFIG_HOME=/acme.sh
ARG AUTO_UPGRADE=1 ARG AUTO_UPGRADE=1
ENV AUTO_UPGRADE $AUTO_UPGRADE
ENV AUTO_UPGRADE=$AUTO_UPGRADE
#Install #Install
COPY ./ /install_acme.sh/
COPY ./acme.sh /install_acme.sh/acme.sh
COPY ./deploy /install_acme.sh/deploy
COPY ./dnsapi /install_acme.sh/dnsapi
COPY ./notify /install_acme.sh/notify
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/

788
acme.sh
File diff suppressed because it is too large
View File

88
deploy/ali_cdn.sh

@ -0,0 +1,88 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034,SC2154
# Script to create certificate to Alibaba Cloud CDN
#
# Docs: https://github.com/acmesh-official/acme.sh/wiki/deployhooks#33-deploy-your-certificate-to-cdn-or-dcdn-of-alibaba-cloud-aliyun
#
# This deployment required following variables
# export Ali_Key="ALIACCESSKEY"
# export Ali_Secret="ALISECRETKEY"
# The credentials are shared with all the Alibaba Cloud deploy hooks and dnsapi
#
# To specify the CDN domain that is different from the certificate CN, usually used for multi-domain or wildcard certificates
# export DEPLOY_ALI_CDN_DOMAIN="cdn.example.com"
# If you have multiple CDN domains using the same certificate, just
# export DEPLOY_ALI_CDN_DOMAIN="cdn1.example.com cdn2.example.com"
#
# For DCDN, see ali_dcdn deploy hook
Ali_CDN_API="https://cdn.aliyuncs.com/"
ali_cdn_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
# Load dnsapi/dns_ali.sh to reduce the duplicated codes
# https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276
dnsapi_ali="$(_findHook "$_cdomain" "$_SUB_FOLDER_DNSAPI" dns_ali)"
# shellcheck source=/dev/null
if ! . "$dnsapi_ali"; then
_err "Error loading file $dnsapi_ali. Please check your API file and try again."
return 1
fi
_prepare_ali_credentials || return 1
_getdeployconf DEPLOY_ALI_CDN_DOMAIN
if [ "$DEPLOY_ALI_CDN_DOMAIN" ]; then
_savedeployconf DEPLOY_ALI_CDN_DOMAIN "$DEPLOY_ALI_CDN_DOMAIN"
else
DEPLOY_ALI_CDN_DOMAIN="$_cdomain"
fi
# read cert and key files and urlencode both
_cert=$(_url_encode upper-hex <"$_cfullchain")
_key=$(_url_encode upper-hex <"$_ckey")
_debug2 _cert "$_cert"
_debug2 _key "$_key"
## update domain ssl config
for domain in $DEPLOY_ALI_CDN_DOMAIN; do
_set_cdn_domain_ssl_certificate_query "$domain" "$_cert" "$_key"
if _ali_rest "Set CDN domain SSL certificate for $domain" "" POST; then
_info "Domain $domain certificate has been deployed successfully"
fi
done
return 0
}
# domain pub pri
_set_cdn_domain_ssl_certificate_query() {
endpoint=$Ali_CDN_API
query=''
query=$query'AccessKeyId='$Ali_Key
query=$query'&Action=SetCdnDomainSSLCertificate'
query=$query'&CertType=upload'
query=$query'&DomainName='$1
query=$query'&Format=json'
query=$query'&SSLPri='$3
query=$query'&SSLProtocol=on'
query=$query'&SSLPub='$2
query=$query'&SignatureMethod=HMAC-SHA1'
query=$query"&SignatureNonce=$(_ali_nonce)"
query=$query'&SignatureVersion=1.0'
query=$query'&Timestamp='$(_timestamp)
query=$query'&Version=2018-05-10'
}

88
deploy/ali_dcdn.sh

@ -0,0 +1,88 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034,SC2154
# Script to create certificate to Alibaba Cloud DCDN
#
# Docs: https://github.com/acmesh-official/acme.sh/wiki/deployhooks#33-deploy-your-certificate-to-cdn-or-dcdn-of-alibaba-cloud-aliyun
#
# This deployment required following variables
# export Ali_Key="ALIACCESSKEY"
# export Ali_Secret="ALISECRETKEY"
# The credentials are shared with all the Alibaba Cloud deploy hooks and dnsapi
#
# To specify the DCDN domain that is different from the certificate CN, usually used for multi-domain or wildcard certificates
# export DEPLOY_ALI_DCDN_DOMAIN="dcdn.example.com"
# If you have multiple CDN domains using the same certificate, just
# export DEPLOY_ALI_DCDN_DOMAIN="dcdn1.example.com dcdn2.example.com"
#
# For regular CDN, see ali_cdn deploy hook
Ali_DCDN_API="https://dcdn.aliyuncs.com/"
ali_dcdn_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
# Load dnsapi/dns_ali.sh to reduce the duplicated codes
# https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276
dnsapi_ali="$(_findHook "$_cdomain" "$_SUB_FOLDER_DNSAPI" dns_ali)"
# shellcheck source=/dev/null
if ! . "$dnsapi_ali"; then
_err "Error loading file $dnsapi_ali. Please check your API file and try again."
return 1
fi
_prepare_ali_credentials || return 1
_getdeployconf DEPLOY_ALI_DCDN_DOMAIN
if [ "$DEPLOY_ALI_DCDN_DOMAIN" ]; then
_savedeployconf DEPLOY_ALI_DCDN_DOMAIN "$DEPLOY_ALI_DCDN_DOMAIN"
else
DEPLOY_ALI_DCDN_DOMAIN="$_cdomain"
fi
# read cert and key files and urlencode both
_cert=$(_url_encode upper-hex <"$_cfullchain")
_key=$(_url_encode upper-hex <"$_ckey")
_debug2 _cert "$_cert"
_debug2 _key "$_key"
## update domain ssl config
for domain in $DEPLOY_ALI_DCDN_DOMAIN; do
_set_dcdn_domain_ssl_certificate_query "$domain" "$_cert" "$_key"
if _ali_rest "Set DCDN domain SSL certificate for $domain" "" POST; then
_info "Domain $domain certificate has been deployed successfully"
fi
done
return 0
}
# domain pub pri
_set_dcdn_domain_ssl_certificate_query() {
endpoint=$Ali_DCDN_API
query=''
query=$query'AccessKeyId='$Ali_Key
query=$query'&Action=SetDcdnDomainSSLCertificate'
query=$query'&CertType=upload'
query=$query'&DomainName='$1
query=$query'&Format=json'
query=$query'&SSLPri='$3
query=$query'&SSLProtocol=on'
query=$query'&SSLPub='$2
query=$query'&SignatureMethod=HMAC-SHA1'
query=$query"&SignatureNonce=$(_ali_nonce)"
query=$query'&SignatureVersion=1.0'
query=$query'&Timestamp='$(_timestamp)
query=$query'&Version=2018-01-15'
}

13
deploy/docker.sh

@ -18,6 +18,7 @@ docker_deploy() {
_ccert="$3" _ccert="$3"
_cca="$4" _cca="$4"
_cfullchain="$5" _cfullchain="$5"
_cpfx="$6"
_debug _cdomain "$_cdomain" _debug _cdomain "$_cdomain"
_getdeployconf DEPLOY_DOCKER_CONTAINER_LABEL _getdeployconf DEPLOY_DOCKER_CONTAINER_LABEL
_debug2 DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL" _debug2 DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL"
@ -88,6 +89,12 @@ docker_deploy() {
_savedeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" _savedeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE"
fi fi
_getdeployconf DEPLOY_DOCKER_CONTAINER_PFX_FILE
_debug2 DEPLOY_DOCKER_CONTAINER_PFX_FILE "$DEPLOY_DOCKER_CONTAINER_PFX_FILE"
if [ "$DEPLOY_DOCKER_CONTAINER_PFX_FILE" ]; then
_savedeployconf DEPLOY_DOCKER_CONTAINER_PFX_FILE "$DEPLOY_DOCKER_CONTAINER_PFX_FILE"
fi
_getdeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD _getdeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD
_debug2 DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" _debug2 DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"
if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then
@ -125,6 +132,12 @@ docker_deploy() {
fi fi
fi fi
if [ "$DEPLOY_DOCKER_CONTAINER_PFX_FILE" ]; then
if ! _docker_cp "$_cid" "$_cpfx" "$DEPLOY_DOCKER_CONTAINER_PFX_FILE"; then
return 1
fi
fi
if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then
_info "Reloading: $DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" _info "Reloading: $DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"
if ! _docker_exec "$_cid" "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"; then if ! _docker_exec "$_cid" "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"; then

1
deploy/exim4.sh

@ -109,6 +109,5 @@ exim4_deploy() {
fi fi
return 1 return 1
fi fi
return 0
} }

2
deploy/haproxy.sh

@ -359,7 +359,7 @@ haproxy_deploy() {
_info "Update existing certificate '${_pem}' over HAProxy ${_socketname}." _info "Update existing certificate '${_pem}' over HAProxy ${_socketname}."
fi fi
_socat_cert_set_cmd="echo -e '${_cmdpfx}set ssl cert ${_pem} <<\n$(cat "${_pem}")\n' | socat '${_statssock}' - | grep -q 'Transaction created'" _socat_cert_set_cmd="echo -e '${_cmdpfx}set ssl cert ${_pem} <<\n$(cat "${_pem}")\n' | socat '${_statssock}' - | grep -q 'Transaction created'"
_debug _socat_cert_set_cmd "${_socat_cert_set_cmd}"
_secure_debug _socat_cert_set_cmd "${_socat_cert_set_cmd}"
eval "${_socat_cert_set_cmd}" eval "${_socat_cert_set_cmd}"
_ret=$? _ret=$?
if [ "${_ret}" != "0" ]; then if [ "${_ret}" != "0" ]; then

120
deploy/proxmoxbs.sh

@ -0,0 +1,120 @@
#!/usr/bin/env sh
# Deploy certificates to a proxmox backup server using the API.
#
# Environment variables that can be set are:
# `DEPLOY_PROXMOXBS_SERVER`: The hostname of the proxmox backup server. Defaults to
# _cdomain.
# `DEPLOY_PROXMOXBS_SERVER_PORT`: The port number the management interface is on.
# Defaults to 8007.
# `DEPLOY_PROXMOXBS_USER`: The user we'll connect as. Defaults to root.
# `DEPLOY_PROXMOXBS_USER_REALM`: The authentication realm the user authenticates
# with. Defaults to pam.
# `DEPLOY_PROXMOXBS_API_TOKEN_NAME`: The name of the API token created for the
# user account. Defaults to acme.
# `DEPLOY_PROXMOXBS_API_TOKEN_KEY`: The API token. Required.
proxmoxbs_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug2 _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
# "Sane" defaults.
_getdeployconf DEPLOY_PROXMOXBS_SERVER
if [ -z "$DEPLOY_PROXMOXBS_SERVER" ]; then
_target_hostname="$_cdomain"
else
_target_hostname="$DEPLOY_PROXMOXBS_SERVER"
_savedeployconf DEPLOY_PROXMOXBS_SERVER "$DEPLOY_PROXMOXBS_SERVER"
fi
_debug2 DEPLOY_PROXMOXBS_SERVER "$_target_hostname"
_getdeployconf DEPLOY_PROXMOXBS_SERVER_PORT
if [ -z "$DEPLOY_PROXMOXBS_SERVER_PORT" ]; then
_target_port="8007"
else
_target_port="$DEPLOY_PROXMOXBS_SERVER_PORT"
_savedeployconf DEPLOY_PROXMOXBS_SERVER_PORT "$DEPLOY_PROXMOXBS_SERVER_PORT"
fi
_debug2 DEPLOY_PROXMOXBS_SERVER_PORT "$_target_port"
# Complete URL.
_target_url="https://${_target_hostname}:${_target_port}/api2/json/nodes/localhost/certificates/custom"
_debug TARGET_URL "$_target_url"
# More "sane" defaults.
_getdeployconf DEPLOY_PROXMOXBS_USER
if [ -z "$DEPLOY_PROXMOXBS_USER" ]; then
_proxmoxbs_user="root"
else
_proxmoxbs_user="$DEPLOY_PROXMOXBS_USER"
_savedeployconf DEPLOY_PROXMOXBS_USER "$DEPLOY_PROXMOXBS_USER"
fi
_debug2 DEPLOY_PROXMOXBS_USER "$_proxmoxbs_user"
_getdeployconf DEPLOY_PROXMOXBS_USER_REALM
if [ -z "$DEPLOY_PROXMOXBS_USER_REALM" ]; then
_proxmoxbs_user_realm="pam"
else
_proxmoxbs_user_realm="$DEPLOY_PROXMOXBS_USER_REALM"
_savedeployconf DEPLOY_PROXMOXBS_USER_REALM "$DEPLOY_PROXMOXBS_USER_REALM"
fi
_debug2 DEPLOY_PROXMOXBS_USER_REALM "$_proxmoxbs_user_realm"
_getdeployconf DEPLOY_PROXMOXBS_API_TOKEN_NAME
if [ -z "$DEPLOY_PROXMOXBS_API_TOKEN_NAME" ]; then
_proxmoxbs_api_token_name="acme"
else
_proxmoxbs_api_token_name="$DEPLOY_PROXMOXBS_API_TOKEN_NAME"
_savedeployconf DEPLOY_PROXMOXBS_API_TOKEN_NAME "$DEPLOY_PROXMOXBS_API_TOKEN_NAME"
fi
_debug2 DEPLOY_PROXMOXBS_API_TOKEN_NAME "$_proxmoxbs_api_token_name"
# This is required.
_getdeployconf DEPLOY_PROXMOXBS_API_TOKEN_KEY
if [ -z "$DEPLOY_PROXMOXBS_API_TOKEN_KEY" ]; then
_err "API key not provided."
return 1
else
_proxmoxbs_api_token_key="$DEPLOY_PROXMOXBS_API_TOKEN_KEY"
_savedeployconf DEPLOY_PROXMOXBS_API_TOKEN_KEY "$DEPLOY_PROXMOXBS_API_TOKEN_KEY"
fi
_debug2 DEPLOY_PROXMOXBS_API_TOKEN_KEY "$_proxmoxbs_api_token_key"
# PBS API Token header value. Used in "Authorization: PBSAPIToken".
_proxmoxbs_header_api_token="${_proxmoxbs_user}@${_proxmoxbs_user_realm}!${_proxmoxbs_api_token_name}:${_proxmoxbs_api_token_key}"
_debug2 "Auth Header" "$_proxmoxbs_header_api_token"
# Ugly. I hate putting heredocs inside functions because heredocs don't
# account for whitespace correctly but it _does_ work and is several times
# cleaner than anything else I had here.
#
# This dumps the json payload to a variable that should be passable to the
# _psot function.
_json_payload=$(
cat <<HEREDOC
{
"certificates": "$(tr '\n' ':' <"$_cfullchain" | sed 's/:/\\n/g')",
"key": "$(tr '\n' ':' <"$_ckey" | sed 's/:/\\n/g')",
"node":"localhost",
"restart":true,
"force":true
}
HEREDOC
)
_debug2 Payload "$_json_payload"
_info "Push certificates to server"
export HTTPS_INSECURE=1
export _H1="Authorization: PBSAPIToken=${_proxmoxbs_header_api_token}"
_post "$_json_payload" "$_target_url" "" POST "application/json"
}

11
deploy/routeros.sh

@ -137,17 +137,18 @@ routeros_deploy() {
return $_err_code return $_err_code
fi fi
DEPLOY_SCRIPT_CMD="/system script add name=\"LECertDeploy-$_cdomain\" owner=$ROUTER_OS_USERNAME \
DEPLOY_SCRIPT_CMD=":do {/system script remove \"LECertDeploy-$_cdomain\" } on-error={ }; \
/system script add name=\"LECertDeploy-$_cdomain\" owner=$ROUTER_OS_USERNAME \
comment=\"generated by routeros deploy script in acme.sh\" \ comment=\"generated by routeros deploy script in acme.sh\" \
source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\ source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
\n/certificate remove [ find name=$_cdomain.cer_1 ];\ \n/certificate remove [ find name=$_cdomain.cer_1 ];\
\n/certificate remove [ find name=$_cdomain.cer_2 ];\ \n/certificate remove [ find name=$_cdomain.cer_2 ];\
\ndelay 1;\ \ndelay 1;\
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
\n/certificate import file-name=\\\"$_cdomain.cer\\\" passphrase=\\\"\\\";\
\n/certificate import file-name=\\\"$_cdomain.key\\\" passphrase=\\\"\\\";\
\ndelay 1;\ \ndelay 1;\
\n/file remove $_cdomain.cer;\
\n/file remove $_cdomain.key;\
\n:do {/file remove $_cdomain.cer; } on-error={ }\
\n:do {/file remove $_cdomain.key; } on-error={ }\
\ndelay 2;\ \ndelay 2;\
\n/ip service set www-ssl certificate=$_cdomain.cer_0;\ \n/ip service set www-ssl certificate=$_cdomain.cer_0;\
\n$ROUTER_OS_ADDITIONAL_SERVICES;\ \n$ROUTER_OS_ADDITIONAL_SERVICES;\

200
deploy/ruckus.sh

@ -0,0 +1,200 @@
#!/usr/bin/env sh
# Here is a script to deploy cert to Ruckus ZoneDirector / Unleashed.
#
# Public domain, 2024, Tony Rielly <https://github.com/ms264556>
#
# ```sh
# acme.sh --deploy -d ruckus.example.com --deploy-hook ruckus
# ```
#
# Then you need to set the environment variables for the
# deploy script to work.
#
# ```sh
# export RUCKUS_HOST=myruckus.example.com
# export RUCKUS_USER=myruckususername
# export RUCKUS_PASS=myruckuspassword
#
# acme.sh --deploy -d myruckus.example.com --deploy-hook ruckus
# ```
#
# returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
ruckus_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_err_code=0
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_getdeployconf RUCKUS_HOST
_getdeployconf RUCKUS_USER
_getdeployconf RUCKUS_PASS
if [ -z "$RUCKUS_HOST" ]; then
_debug "Using _cdomain as RUCKUS_HOST, please set if not correct."
RUCKUS_HOST="$_cdomain"
fi
if [ -z "$RUCKUS_USER" ]; then
_err "Need to set the env variable RUCKUS_USER"
return 1
fi
if [ -z "$RUCKUS_PASS" ]; then
_err "Need to set the env variable RUCKUS_PASS"
return 1
fi
_savedeployconf RUCKUS_HOST "$RUCKUS_HOST"
_savedeployconf RUCKUS_USER "$RUCKUS_USER"
_savedeployconf RUCKUS_PASS "$RUCKUS_PASS"
_debug RUCKUS_HOST "$RUCKUS_HOST"
_debug RUCKUS_USER "$RUCKUS_USER"
_secure_debug RUCKUS_PASS "$RUCKUS_PASS"
export ACME_HTTP_NO_REDIRECTS=1
_info "Discovering the login URL"
_get "https://$RUCKUS_HOST" >/dev/null
_login_url="$(_response_header 'Location')"
if [ -n "$_login_url" ]; then
_login_path=$(echo "$_login_url" | sed 's|https\?://[^/]\+||')
if [ -z "$_login_path" ]; then
# redirect was to a different host
_err "Connection failed: redirected to a different host. Configure Unleashed with a Preferred Master or Management Interface."
return 1
fi
fi
if [ -z "${_login_url}" ]; then
_err "Connection failed: couldn't find login page."
return 1
fi
_base_url=$(dirname "$_login_url")
_login_page=$(basename "$_login_url")
if [ "$_login_page" = "index.html" ]; then
_err "Connection temporarily unavailable: Unleashed Rebuilding."
return 1
fi
if [ "$_login_page" = "wizard.jsp" ]; then
_err "Connection failed: Setup Wizard not complete."
return 1
fi
_info "Login"
_username_encoded="$(printf "%s" "$RUCKUS_USER" | _url_encode)"
_password_encoded="$(printf "%s" "$RUCKUS_PASS" | _url_encode)"
_login_query="$(printf "%s" "username=${_username_encoded}&password=${_password_encoded}&ok=Log+In")"
_post "$_login_query" "$_login_url" >/dev/null
_login_code="$(_response_code)"
if [ "$_login_code" = "200" ]; then
_err "Login failed: incorrect credentials."
return 1
fi
_info "Collect Session Cookie"
_H1="Cookie: $(_response_cookie)"
export _H1
_info "Collect CSRF Token"
_H2="X-CSRF-Token: $(_response_header 'HTTP_X_CSRF_TOKEN')"
export _H2
if _isRSA "$_ckey" >/dev/null 2>&1; then
_debug "Using RSA certificate."
else
_info "Verifying ECC certificate support."
_ul_version="$(_get_unleashed_version)"
if [ -z "$_ul_version" ]; then
_err "Your controller doesn't support ECC certificates. Please deploy an RSA certificate."
return 1
fi
_ul_version_major="$(echo "$_ul_version" | cut -d . -f 1)"
_ul_version_minor="$(echo "$_ul_version" | cut -d . -f 2)"
if [ "$_ul_version_major" -lt "200" ]; then
_err "ZoneDirector doesn't support ECC certificates. Please deploy an RSA certificate."
return 1
elif [ "$_ul_version_minor" -lt "13" ]; then
_err "Unleashed $_ul_version_major.$_ul_version_minor doesn't support ECC certificates. Please deploy an RSA certificate or upgrade to Unleashed 200.13+."
return 1
fi
_debug "ECC certificates OK for Unleashed $_ul_version_major.$_ul_version_minor."
fi
_info "Uploading certificate"
_post_upload "uploadcert" "$_cfullchain"
_info "Uploading private key"
_post_upload "uploadprivatekey" "$_ckey"
_info "Replacing certificate"
_replace_cert_ajax='<ajax-request action="docmd" comp="system" updater="rid.0.5" xcmd="replace-cert" checkAbility="6" timeout="-1"><xcmd cmd="replace-cert" cn="'$RUCKUS_HOST'"/></ajax-request>'
_post "$_replace_cert_ajax" "$_base_url/_cmdstat.jsp" >/dev/null
_info "Rebooting"
_cert_reboot_ajax='<ajax-request action="docmd" comp="worker" updater="rid.0.5" xcmd="cert-reboot" checkAbility="6"><xcmd cmd="cert-reboot" action="undefined"/></ajax-request>'
_post "$_cert_reboot_ajax" "$_base_url/_cmdstat.jsp" >/dev/null
return 0
}
_response_code() {
_egrep_o <"$HTTP_HEADER" "^HTTP[^ ]* .*$" | cut -d " " -f 2-100 | tr -d "\f\n" | _egrep_o "^[0-9]*"
}
_response_header() {
grep <"$HTTP_HEADER" -i "^$1:" | cut -d ':' -f 2- | tr -d "\r\n\t "
}
_response_cookie() {
_response_header 'Set-Cookie' | sed 's/;.*//'
}
_get_unleashed_version() {
_post '<ajax-request action="getstat" comp="system"><sysinfo/></ajax-request>' "$_base_url/_cmdstat.jsp" | _egrep_o "version-num=\"[^\"]*\"" | cut -d '"' -f 2
}
_post_upload() {
_post_action="$1"
_post_file="$2"
_post_boundary="----FormBoundary$(date "+%s%N")"
_post_data="$({
printf -- "--%s\r\n" "$_post_boundary"
printf -- "Content-Disposition: form-data; name=\"u\"; filename=\"%s\"\r\n" "$_post_action"
printf -- "Content-Type: application/octet-stream\r\n\r\n"
printf -- "%s\r\n" "$(cat "$_post_file")"
printf -- "--%s\r\n" "$_post_boundary"
printf -- "Content-Disposition: form-data; name=\"action\"\r\n\r\n"
printf -- "%s\r\n" "$_post_action"
printf -- "--%s\r\n" "$_post_boundary"
printf -- "Content-Disposition: form-data; name=\"callback\"\r\n\r\n"
printf -- "%s\r\n" "uploader_$_post_action"
printf -- "--%s--\r\n\r\n" "$_post_boundary"
})"
_post "$_post_data" "$_base_url/_upload.jsp?request_type=xhr" "" "" "multipart/form-data; boundary=$_post_boundary" >/dev/null
}

111
deploy/strongswan.sh

@ -10,46 +10,89 @@
#domain keyfile certfile cafile fullchain #domain keyfile certfile cafile fullchain
strongswan_deploy() { strongswan_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_cdomain="${1}"
_ckey="${2}"
_ccert="${3}"
_cca="${4}"
_cfullchain="${5}"
_info "Using strongswan" _info "Using strongswan"
if [ -x /usr/sbin/ipsec ]; then
_ipsec=/usr/sbin/ipsec
elif [ -x /usr/sbin/strongswan ]; then
_ipsec=/usr/sbin/strongswan
elif [ -x /usr/local/sbin/ipsec ]; then
_ipsec=/usr/local/sbin/ipsec
else
if _exists ipsec; then
_ipsec=ipsec
elif _exists strongswan; then
_ipsec=strongswan
fi
if _exists swanctl; then
_swanctl=swanctl
fi
# For legacy stroke mode
if [ -n "${_ipsec}" ]; then
_info "${_ipsec} command detected"
_confdir=$(${_ipsec} --confdir)
if [ -z "${_confdir}" ]; then
_err "no strongswan --confdir is detected"
return 1
fi
_info _confdir "${_confdir}"
__deploy_cert "$@" "stroke" "${_confdir}"
${_ipsec} reload
fi
# For modern vici mode
if [ -n "${_swanctl}" ]; then
_info "${_swanctl} command detected"
for _dir in /usr/local/etc/swanctl /etc/swanctl /etc/strongswan/swanctl; do
if [ -d ${_dir} ]; then
_confdir=${_dir}
_info _confdir "${_confdir}"
break
fi
done
if [ -z "${_confdir}" ]; then
_err "no swanctl config dir is found"
return 1
fi
__deploy_cert "$@" "vici" "${_confdir}"
${_swanctl} --load-creds
fi
if [ -z "${_swanctl}" ] && [ -z "${_ipsec}" ]; then
_err "no strongswan or ipsec command is detected" _err "no strongswan or ipsec command is detected"
_err "no swanctl is detected"
return 1 return 1
fi fi
}
_info _ipsec "$_ipsec"
#################### Private functions below ##################################
_confdir=$($_ipsec --confdir)
if [ $? -ne 0 ] || [ -z "$_confdir" ]; then
_err "no strongswan --confdir is detected"
__deploy_cert() {
_cdomain="${1}"
_ckey="${2}"
_ccert="${3}"
_cca="${4}"
_cfullchain="${5}"
_swan_mode="${6}"
_confdir="${7}"
_debug _cdomain "${_cdomain}"
_debug _ckey "${_ckey}"
_debug _ccert "${_ccert}"
_debug _cca "${_cca}"
_debug _cfullchain "${_cfullchain}"
_debug _swan_mode "${_swan_mode}"
_debug _confdir "${_confdir}"
if [ "${_swan_mode}" = "vici" ]; then
_dir_private="private"
_dir_cert="x509"
_dir_ca="x509ca"
elif [ "${_swan_mode}" = "stroke" ]; then
_dir_private="ipsec.d/private"
_dir_cert="ipsec.d/certs"
_dir_ca="ipsec.d/cacerts"
else
_err "unknown StrongSwan mode ${_swan_mode}"
return 1 return 1
fi fi
_info _confdir "$_confdir"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
cat "$_ckey" >"${_confdir}/ipsec.d/private/$(basename "$_ckey")"
cat "$_ccert" >"${_confdir}/ipsec.d/certs/$(basename "$_ccert")"
cat "$_cca" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cca")"
cat "$_cfullchain" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cfullchain")"
$_ipsec reload
cat "${_ckey}" >"${_confdir}/${_dir_private}/$(basename "${_ckey}")"
cat "${_ccert}" >"${_confdir}/${_dir_cert}/$(basename "${_ccert}")"
cat "${_cca}" >"${_confdir}/${_dir_ca}/$(basename "${_cca}")"
if [ "${_swan_mode}" = "stroke" ]; then
cat "${_cfullchain}" >"${_confdir}/${_dir_ca}/$(basename "${_cfullchain}")"
fi
} }

55
deploy/synology_dsm.sh

@ -39,7 +39,7 @@
################################################################################ ################################################################################
# Dependencies: # Dependencies:
# - curl # - curl
# - synouser & synogroup (When available and SYNO_USE_TEMP_ADMIN is set)
# - synouser & synogroup & synosetkeyvalue (Required for SYNO_USE_TEMP_ADMIN=1)
################################################################################ ################################################################################
# Return value: # Return value:
# 0 means success, otherwise error. # 0 means success, otherwise error.
@ -66,14 +66,18 @@ synology_dsm_deploy() {
_getdeployconf SYNO_DEVICE_NAME _getdeployconf SYNO_DEVICE_NAME
# Prepare to use temp admin if SYNO_USE_TEMP_ADMIN is set # Prepare to use temp admin if SYNO_USE_TEMP_ADMIN is set
_debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
_getdeployconf SYNO_USE_TEMP_ADMIN _getdeployconf SYNO_USE_TEMP_ADMIN
_check2cleardeployconfexp SYNO_USE_TEMP_ADMIN _check2cleardeployconfexp SYNO_USE_TEMP_ADMIN
_debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN" _debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
if ! _exists synouser || ! _exists synogroup; then
_err "Tools are missing for creating temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
if ! _exists synouser || ! _exists synogroup || ! _exists synosetkeyvalue; then
_err "Missing required tools to creat temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
_err "Notice: temp admin user authorization method only supports local deployment on DSM."
return 1
fi
if synouser --help 2>&1 | grep -q 'Permission denied'; then
_err "For creating temp admin user, the deploy script must be run as root."
return 1 return 1
fi fi
@ -109,9 +113,9 @@ synology_dsm_deploy() {
# Default values for scheme, hostname and port # Default values for scheme, hostname and port
# Defaulting to localhost and http, because it's localhost… # Defaulting to localhost and http, because it's localhost…
[ -n "$SYNO_SCHEME" ] || SYNO_SCHEME="http"
[ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME="localhost"
[ -n "$SYNO_PORT" ] || SYNO_PORT="5000"
[ -n "$SYNO_SCHEME" ] || SYNO_SCHEME=http
[ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME=localhost
[ -n "$SYNO_PORT" ] || SYNO_PORT=5000
_savedeployconf SYNO_SCHEME "$SYNO_SCHEME" _savedeployconf SYNO_SCHEME "$SYNO_SCHEME"
_savedeployconf SYNO_HOSTNAME "$SYNO_HOSTNAME" _savedeployconf SYNO_HOSTNAME "$SYNO_HOSTNAME"
_savedeployconf SYNO_PORT "$SYNO_PORT" _savedeployconf SYNO_PORT "$SYNO_PORT"
@ -169,7 +173,7 @@ synology_dsm_deploy() {
_debug3 H1 "${_H1}" _debug3 H1 "${_H1}"
fi fi
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$DEPRECATED_otp_code&device_name=certrenewal&device_id=$SYNO_DEVICE_ID" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$DEPRECATED_otp_code&device_name=certrenewal&device_id=$SYNO_DEVICE_ID" "$_base_url/webapi/$api_path?enable_syno_token=yes")
_debug3 response "$response" _debug3 response "$response"
# ## END ## - DEPRECATED, for backward compatibility # ## END ## - DEPRECATED, for backward compatibility
# If SYNO_DEVICE_ID or SYNO_OTP_CODE is set, we treat current account enabled 2FA-OTP. # If SYNO_DEVICE_ID or SYNO_OTP_CODE is set, we treat current account enabled 2FA-OTP.
@ -182,9 +186,9 @@ synology_dsm_deploy() {
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
_getdeployconf SYNO_LOCAL_HOSTNAME _getdeployconf SYNO_LOCAL_HOSTNAME
_debug SYNO_LOCAL_HOSTNAME "${SYNO_LOCAL_HOSTNAME:-}" _debug SYNO_LOCAL_HOSTNAME "${SYNO_LOCAL_HOSTNAME:-}"
if [ "$SYNO_LOCAL_HOSTNAME" != "1" ] && [ "$SYNO_LOCAL_HOSTNAME" == "$SYNO_HOSTNAME" ]; then
if [ "$SYNO_HOSTNAME" != "localhost" ] && [ "$SYNO_HOSTNAME" != "127.0.0.1" ]; then if [ "$SYNO_HOSTNAME" != "localhost" ] && [ "$SYNO_HOSTNAME" != "127.0.0.1" ]; then
_err "SYNO_USE_TEMP_ADMIN=1 Only support locally deployment, if you are sure that hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
if [ "$SYNO_LOCAL_HOSTNAME" != "1" ]; then
_err "SYNO_USE_TEMP_ADMIN=1 only support local deployment, though if you are sure that the hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
return 1 return 1
fi fi
fi fi
@ -201,24 +205,27 @@ synology_dsm_deploy() {
# shellcheck disable=SC2086 # shellcheck disable=SC2086
synogroup --member administrators $cur_admins $SYNO_USERNAME >/dev/null synogroup --member administrators $cur_admins $SYNO_USERNAME >/dev/null
else else
_err "Tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
_err "The tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
return 1 return 1
fi fi
else else
_err "Unsupported synogroup tool detected, please set SYNO_USERNAME and SYNO_PASSWORD instead." _err "Unsupported synogroup tool detected, please set SYNO_USERNAME and SYNO_PASSWORD instead."
return 1 return 1
fi fi
# havig a workaround to temporary disable enforce 2FA-OTP
# havig a workaround to temporary disable enforce 2FA-OTP, will restore
# it soon (after a single request), though if any accident occurs like
# unexpected interruption, this setting can be easily reverted manually.
otp_enforce_option=$(synogetkeyvalue /etc/synoinfo.conf otp_enforce_option) otp_enforce_option=$(synogetkeyvalue /etc/synoinfo.conf otp_enforce_option)
if [ -n "$otp_enforce_option" ] && [ "${otp_enforce_option:-"none"}" != "none" ]; then if [ -n "$otp_enforce_option" ] && [ "${otp_enforce_option:-"none"}" != "none" ]; then
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option none synosetkeyvalue /etc/synoinfo.conf otp_enforce_option none
_info "Temporary disabled enforce 2FA-OTP to complete authentication."
_info "Enforcing 2FA-OTP has been disabled to complete temp admin authentication."
_info "Notice: it will be restored soon, if not, you can restore it manually via Control Panel."
_info "previous_otp_enforce_option" "$otp_enforce_option" _info "previous_otp_enforce_option" "$otp_enforce_option"
else else
otp_enforce_option="" otp_enforce_option=""
fi fi
fi fi
response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
if [ -n "$SYNO_USE_TEMP_ADMIN" ] && [ -n "$otp_enforce_option" ]; then if [ -n "$SYNO_USE_TEMP_ADMIN" ] && [ -n "$otp_enforce_option" ]; then
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option "$otp_enforce_option" synosetkeyvalue /etc/synoinfo.conf otp_enforce_option "$otp_enforce_option"
_info "Restored previous enforce 2FA-OTP option." _info "Restored previous enforce 2FA-OTP option."
@ -230,7 +237,7 @@ synology_dsm_deploy() {
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*') error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
_debug2 error_code "$error_code" _debug2 error_code "$error_code"
# Account has 2FA-OTP enabled, since error 403 reported. # Account has 2FA-OTP enabled, since error 403 reported.
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Firmware/DSM/All/enu/Synology_DiskStation_Administration_CLI_Guide.pdf
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Os/DSM/All/enu/DSM_Login_Web_API_Guide_enu.pdf
if [ "$error_code" == "403" ]; then if [ "$error_code" == "403" ]; then
if [ -z "$SYNO_DEVICE_NAME" ]; then if [ -z "$SYNO_DEVICE_NAME" ]; then
printf "Enter device name or leave empty for default (CertRenewal): " printf "Enter device name or leave empty for default (CertRenewal): "
@ -274,12 +281,16 @@ synology_dsm_deploy() {
_err "Failed to authenticate with provided 2FA-OTP code, please try again in a new terminal window." _err "Failed to authenticate with provided 2FA-OTP code, please try again in a new terminal window."
elif [ "$error_code" == "406" ]; then elif [ "$error_code" == "406" ]; then
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
_err "SYNO_USE_TEMP_ADMIN=1 is not supported if enforce auth with 2FA-OTP is enabled."
_err "Failed with unexcepted error, please report this by providing full log with '--debug 3'."
else else
_err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue." _err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue."
fi fi
elif [ "$error_code" == "400" ] || [ "$error_code" == "401" ] || [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
_err "Failed to authenticate with a non-existent or disabled account, or the account password is incorrect or has expired."
elif [ "$error_code" == "400" ]; then
_err "Failed to authenticate, no such account or incorrect password."
elif [ "$error_code" == "401" ]; then
_err "Failed to authenticate with a non-existent account."
elif [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
_err "Failed to authenticate, the account password has expired or must be changed."
else else
_err "Failed to authenticate with error: $error_code." _err "Failed to authenticate with error: $error_code."
fi fi
@ -293,7 +304,7 @@ synology_dsm_deploy() {
_debug SynoToken "$token" _debug SynoToken "$token"
if [ -z "$sid" ] || [ -z "$token" ]; then if [ -z "$sid" ] || [ -z "$token" ]; then
# Still can't get necessary info even got no errors, may Synology have API updated? # Still can't get necessary info even got no errors, may Synology have API updated?
_err "Unable to authenticate to $_base_url, you may report the full log to the community."
_err "Unable to authenticate to $_base_url, you may report this by providing full log with '--debug 3'."
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME" _temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
return 1 return 1
fi fi
@ -309,7 +320,7 @@ synology_dsm_deploy() {
_cleardeployconf SYNO_DEVICE_ID _cleardeployconf SYNO_DEVICE_ID
_cleardeployconf SYNO_DEVICE_NAME _cleardeployconf SYNO_DEVICE_NAME
_savedeployconf SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN" _savedeployconf SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
_savedeployconf SYNO_LOCAL_HOSTNAME "$SYNO_HOSTNAME"
_savedeployconf SYNO_LOCAL_HOSTNAME "$SYNO_LOCAL_HOSTNAME"
else else
_savedeployconf SYNO_USERNAME "$SYNO_USERNAME" _savedeployconf SYNO_USERNAME "$SYNO_USERNAME"
_savedeployconf SYNO_PASSWORD "$SYNO_PASSWORD" _savedeployconf SYNO_PASSWORD "$SYNO_PASSWORD"
@ -331,7 +342,7 @@ synology_dsm_deploy() {
if [ "$error_code" -eq 105 ]; then if [ "$error_code" -eq 105 ]; then
_err "Current user is not administrator and does not have sufficient permission for deploying." _err "Current user is not administrator and does not have sufficient permission for deploying."
else else
_err "Failed to fetch certificate info with error: $error_code, please try again or contact Synology to learn more."
_err "Failed to fetch certificate info: $error_code, please try again or contact Synology to learn more."
fi fi
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME" _temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
return 1 return 1
@ -400,7 +411,7 @@ _temp_admin_create() {
_username="$1" _username="$1"
_password="$2" _password="$2"
synouser --del "$_username" >/dev/null 2>/dev/null synouser --del "$_username" >/dev/null 2>/dev/null
synouser --add "$_username" "$_password" "" 0 "scruelt@hotmail.com" 0 >/dev/null
synouser --add "$_username" "$_password" "" 0 "" 0 >/dev/null
} }
_temp_admin_cleanup() { _temp_admin_cleanup() {

97
deploy/truenas.sh

@ -9,7 +9,7 @@
# #
# Following environment variables must be set: # Following environment variables must be set:
# #
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI>"
# #
# The following environmental variables may be set if you don't like their # The following environmental variables may be set if you don't like their
# default values: # default values:
@ -64,6 +64,20 @@ truenas_deploy() {
_response=$(_get "$_api_url/system/state") _response=$(_get "$_api_url/system/state")
_info "TrueNAS system state: $_response." _info "TrueNAS system state: $_response."
_info "Getting TrueNAS version"
_response=$(_get "$_api_url/system/version")
if echo "$_response" | grep -q "SCALE"; then
_truenas_os=$(echo "$_response" | cut -d '-' -f 2)
_truenas_version=$(echo "$_response" | cut -d '-' -f 3 | tr -d '"' | cut -d '.' -f 1,2)
else
_truenas_os="unknown"
_truenas_version="unknown"
fi
_info "Detected TrueNAS system os: $_truenas_os"
_info "Detected TrueNAS system version: $_truenas_version"
if [ -z "$_response" ]; then if [ -z "$_response" ]; then
_err "Unable to authenticate to $_api_url." _err "Unable to authenticate to $_api_url."
_err 'Check your connection settings are correct, e.g.' _err 'Check your connection settings are correct, e.g.'
@ -115,6 +129,11 @@ truenas_deploy() {
_debug3 _activate_result "$_activate_result" _debug3 _activate_result "$_activate_result"
_truenas_version_23_10="23.10"
_truenas_version_24_10="24.10"
_check_version=$(printf "%s\n%s" "$_truenas_version_23_10" "$_truenas_version" | sort -V | head -n 1)
if [ "$_truenas_os" != "SCALE" ] || [ "$_check_version" != "$_truenas_version_23_10" ]; then
_info "Checking if WebDAV certificate is the same as the TrueNAS web UI" _info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
_webdav_list=$(_get "$_api_url/webdav") _webdav_list=$(_get "$_api_url/webdav")
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,') _webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
@ -138,29 +157,6 @@ truenas_deploy() {
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI" _info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
fi fi
_info "Checking if FTP certificate is the same as the TrueNAS web UI"
_ftp_list=$(_get "$_api_url/ftp")
_ftp_cert_id=$(echo "$_ftp_list" | grep '"ssltls_certificate":' | tr -d -- '"certislfa:_ ,')
if [ "$_ftp_cert_id" = "$_active_cert_id" ]; then
_info "Updating the FTP certificate"
_debug _ftp_cert_id "$_ftp_cert_id"
_ftp_data="{\"ssltls_certificate\": \"${_cert_id}\"}"
_activate_ftp_cert="$(_post "$_ftp_data" "$_api_url/ftp" "" "PUT" "application/json")"
_ftp_new_cert_id=$(echo "$_activate_ftp_cert" | _json_decode | grep '"ssltls_certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_ftp_new_cert_id" -eq "$_cert_id" ]; then
_info "FTP certificate updated successfully"
else
_err "Unable to set FTP certificate"
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
_debug3 _ftp_new_cert_id "$_ftp_new_cert_id"
return 1
fi
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
else
_info "FTP certificate is not configured or is not the same as TrueNAS web UI"
fi
_info "Checking if S3 certificate is the same as the TrueNAS web UI" _info "Checking if S3 certificate is the same as the TrueNAS web UI"
_s3_list=$(_get "$_api_url/s3") _s3_list=$(_get "$_api_url/s3")
_s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,') _s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
@ -183,7 +179,11 @@ truenas_deploy() {
else else
_info "S3 certificate is not configured or is not the same as TrueNAS web UI" _info "S3 certificate is not configured or is not the same as TrueNAS web UI"
fi fi
fi
if [ "$_truenas_os" = "SCALE" ]; then
_check_version=$(printf "%s\n%s" "$_truenas_version_24_10" "$_truenas_version" | sort -V | head -n 1)
if [ "$_check_version" != "$_truenas_version_24_10" ]; then
_info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required" _info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
if _exists jq; then if _exists jq; then
_info "Query all chart release" _info "Query all chart release"
@ -204,6 +204,55 @@ truenas_deploy() {
else else
_info "Tool 'jq' does not exists, skip chart release checking" _info "Tool 'jq' does not exists, skip chart release checking"
fi fi
else
_info "Checking if any app is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
if _exists jq; then
_info "Query all apps"
_app_list=$(_get "$_api_url/app")
_app_id_list=$(printf "%s" "$_app_list" | jq -r '.[].name')
_app_length=$(echo "$_app_id_list" | wc -l)
_info "Found $_app_length apps"
_info "Checking for each app if an update is needed"
for i in $(seq 1 "$_app_length"); do
_app_id=$(echo "$_app_id_list" | sed -n "${i}p")
_app_config="$(_post "\"$_app_id\"" "$_api_url/app/config" "" "POST" "application/json")"
# Check if the app use the same certificate TrueNAS web UI
_app_active_cert_config=$(echo "$_app_config" | tr -d '\000-\037' | _json_decode | jq -r ".ix_certificates[\"$_active_cert_id\"]")
if [ "$_app_active_cert_config" != "null" ]; then
_info "Updating certificate from $_active_cert_id to $_cert_id for app: $_app_id"
#Replace the old certificate id with the new one in path
_update_app_result="$(_post "{\"values\" : { \"network\": { \"certificate_id\": $_cert_id } } }" "$_api_url/app/id/$_app_id" "" "PUT" "application/json")"
_debug3 _update_app_result "$_update_app_result"
fi
done
else
_info "Tool 'jq' does not exists, skip app checking"
fi
fi
fi
_info "Checking if FTP certificate is the same as the TrueNAS web UI"
_ftp_list=$(_get "$_api_url/ftp")
_ftp_cert_id=$(echo "$_ftp_list" | grep '"ssltls_certificate":' | tr -d -- '"certislfa:_ ,')
if [ "$_ftp_cert_id" = "$_active_cert_id" ]; then
_info "Updating the FTP certificate"
_debug _ftp_cert_id "$_ftp_cert_id"
_ftp_data="{\"ssltls_certificate\": \"${_cert_id}\"}"
_activate_ftp_cert="$(_post "$_ftp_data" "$_api_url/ftp" "" "PUT" "application/json")"
_ftp_new_cert_id=$(echo "$_activate_ftp_cert" | _json_decode | grep '"ssltls_certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_ftp_new_cert_id" -eq "$_cert_id" ]; then
_info "FTP certificate updated successfully"
else
_err "Unable to set FTP certificate"
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
_debug3 _ftp_new_cert_id "$_ftp_new_cert_id"
return 1
fi
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
else
_info "FTP certificate is not configured or is not the same as TrueNAS web UI"
fi
_info "Deleting old certificate" _info "Deleting old certificate"
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")" _delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"

294
deploy/truenas_ws.sh

@ -0,0 +1,294 @@
#!/usr/bin/env sh
# TrueNAS deploy script for SCALE/CORE using websocket
# It is recommend to use a wildcard certificate
#
# Websocket Documentation: https://www.truenas.com/docs/api/scale_websocket_api.html
#
# Tested with TrueNAS Scale - Electric Eel 24.10
# Changes certificate in the following services:
# - Web UI
# - FTP
# - iX Apps
#
# The following environment variables must be set:
# ------------------------------------------------
#
# # API KEY
# # Use the folowing URL to create a new API token: <TRUENAS_HOSTNAME OR IP>/ui/apikeys
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
#
### Private functions
# Call websocket method
# Usage:
# _ws_response=$(_ws_call "math.dummycalc" "'{"x": 4, "y": 5}'")
# _info "$_ws_response"
#
# Output:
# {"z": 9}
#
# Arguments:
# $@ - midclt arguments for call
#
# Returns:
# JSON/JOBID
_ws_call() {
_debug "_ws_call arg1" "$1"
_debug "_ws_call arg2" "$2"
_debug "_ws_call arg3" "$3"
if [ $# -eq 3 ]; then
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2" "$3")
fi
if [ $# -eq 2 ]; then
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2")
fi
if [ $# -eq 1 ]; then
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1")
fi
_debug "_ws_response" "$_ws_response"
printf "%s" "$_ws_response"
return 0
}
# Check argument is a number
# Usage:
#
# Output:
# n/a
#
# Arguments:
# $1 - Anything
#
# Returns:
# 0: true
# 1: false
_ws_check_jobid() {
case "$1" in
[0-9]*)
return 0
;;
esac
return 1
}
# Wait for job to finish and return result as JSON
# Usage:
# _ws_result=$(_ws_get_job_result "$_ws_jobid")
# _new_certid=$(printf "%s" "$_ws_result" | jq -r '."id"')
#
# Output:
# JSON result of the job
#
# Arguments:
# $1 - JobID
#
# Returns:
# n/a
_ws_get_job_result() {
while true; do
sleep 2
_ws_response=$(_ws_call "core.get_jobs" "[[\"id\", \"=\", $1]]")
if [ "$(printf "%s" "$_ws_response" | jq -r '.[]."state"')" != "RUNNING" ]; then
_ws_result="$(printf "%s" "$_ws_response" | jq '.[]."result"')"
_debug "_ws_result" "$_ws_result"
printf "%s" "$_ws_result"
_ws_error="$(printf "%s" "$_ws_response" | jq '.[]."error"')"
if [ "$_ws_error" != "null" ]; then
_err "Job $1 failed:"
_err "$_ws_error"
return 7
fi
break
fi
done
return 0
}
########################
### Public functions ###
########################
# truenas_ws_deploy
#
# Deploy new certificate to TrueNAS services
#
# Arguments
# 1: Domain
# 2: Key-File
# 3: Certificate-File
# 4: CA-File
# 5: FullChain-File
# Returns:
# 0: Success
# 1: Missing API Key
# 2: TrueNAS not ready
# 3: Not a JobID
# 4: FTP cert error
# 5: WebUI cert error
# 6: Job error
# 7: WS call error
# 10: No CORE or SCALE detected
#
truenas_ws_deploy() {
_domain="$1"
_file_key="$2"
_file_cert="$3"
_file_ca="$4"
_file_fullchain="$5"
_debug _domain "$_domain"
_debug _file_key "$_file_key"
_debug _file_cert "$_file_cert"
_debug _file_ca "$_file_ca"
_debug _file_fullchain "$_file_fullchain"
########## Environment check
_info "Checking environment variables..."
_getdeployconf DEPLOY_TRUENAS_APIKEY
# Check API Key
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then
_err "TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable."
return 1
fi
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
_info "Environment variables: OK"
########## Health check
_info "Checking TrueNAS health..."
_ws_response=$(_ws_call "system.ready" | tr '[:lower:]' '[:upper:]')
_ws_ret=$?
if [ $_ws_ret -gt 0 ]; then
_err "Error calling system.ready:"
_err "$_ws_response"
return $_ws_ret
fi
if [ "$_ws_response" != "TRUE" ]; then
_err "TrueNAS is not ready."
_err "Please check environment variables DEPLOY_TRUENAS_APIKEY, DEPLOY_TRUENAS_HOSTNAME and DEPLOY_TRUENAS_PROTOCOL."
_err "Verify API key."
return 2
fi
_savedeployconf DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
_info "TrueNAS health: OK"
########## System info
_info "Gather system info..."
_ws_response=$(_ws_call "system.info")
_truenas_system=$(printf "%s" "$_ws_response" | jq -r '."version"' | cut -d '-' -f 2 | tr '[:lower:]' '[:upper:]')
_truenas_version=$(printf "%s" "$_ws_response" | jq -r '."version"' | cut -d '-' -f 3)
_info "TrueNAS system: $_truenas_system"
_info "TrueNAS version: $_truenas_version"
if [ "$_truenas_system" != "SCALE" ] && [ "$_truenas_system" != "CORE" ]; then
_err "Cannot gather TrueNAS system. Nor CORE oder SCALE detected."
return 10
fi
########## Gather current certificate
_info "Gather current WebUI certificate..."
_ws_response="$(_ws_call "system.general.config")"
_ui_certificate_id=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."id"')
_ui_certificate_name=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."name"')
_info "Current WebUI certificate ID: $_ui_certificate_id"
_info "Current WebUI certificate name: $_ui_certificate_name"
########## Upload new certificate
_info "Upload new certificate..."
_certname="acme_$(_utc_date | tr -d '\-\:' | tr ' ' '_')"
_info "New WebUI certificate name: $_certname"
_debug _certname "$_certname"
_ws_jobid=$(_ws_call "certificate.create" "{\"name\": \"${_certname}\", \"create_type\": \"CERTIFICATE_CREATE_IMPORTED\", \"certificate\": \"$(_json_encode <"$_file_fullchain")\", \"privatekey\": \"$(_json_encode <"$_file_key")\", \"passphrase\": \"\"}")
_debug "_ws_jobid" "$_ws_jobid"
if ! _ws_check_jobid "$_ws_jobid"; then
_err "No JobID returned from websocket method."
return 3
fi
_ws_result=$(_ws_get_job_result "$_ws_jobid")
_ws_ret=$?
if [ $_ws_ret -gt 0 ]; then
return $_ws_ret
fi
_debug "_ws_result" "$_ws_result"
_new_certid=$(printf "%s" "$_ws_result" | jq -r '."id"')
_info "New certificate ID: $_new_certid"
########## FTP
_info "Replace FTP certificate..."
_ws_response=$(_ws_call "ftp.update" "{\"ssltls_certificate\": $_new_certid}")
_ftp_certid=$(printf "%s" "$_ws_response" | jq -r '."ssltls_certificate"')
if [ "$_ftp_certid" != "$_new_certid" ]; then
_err "Cannot set FTP certificate."
_debug "_ws_response" "$_ws_response"
return 4
fi
########## ix Apps (SCALE only)
if [ "$_truenas_system" = "SCALE" ]; then
_info "Replace app certificates..."
_ws_response=$(_ws_call "app.query")
for _app_name in $(printf "%s" "$_ws_response" | jq -r '.[]."name"'); do
_info "Checking app $_app_name..."
_ws_response=$(_ws_call "app.config" "$_app_name")
if [ "$(printf "%s" "$_ws_response" | jq -r '."network" | has("certificate_id")')" = "true" ]; then
_info "App has certificate option, setup new certificate..."
_info "App will be redeployed after updating the certificate."
_ws_jobid=$(_ws_call "app.update" "$_app_name" "{\"values\": {\"network\": {\"certificate_id\": $_new_certid}}}")
_debug "_ws_jobid" "$_ws_jobid"
if ! _ws_check_jobid "$_ws_jobid"; then
_err "No JobID returned from websocket method."
return 3
fi
_ws_result=$(_ws_get_job_result "$_ws_jobid")
_ws_ret=$?
if [ $_ws_ret -gt 0 ]; then
return $_ws_ret
fi
_debug "_ws_result" "$_ws_result"
_info "App certificate replaced."
else
_info "App has no certificate option, skipping..."
fi
done
fi
########## WebUI
_info "Replace WebUI certificate..."
_ws_response=$(_ws_call "system.general.update" "{\"ui_certificate\": $_new_certid}")
_changed_certid=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."id"')
if [ "$_changed_certid" != "$_new_certid" ]; then
_err "WebUI certificate change error.."
return 5
else
_info "WebUI certificate replaced."
fi
_info "Restarting WebUI..."
_ws_response=$(_ws_call "system.general.ui_restart")
_info "Waiting for UI restart..."
sleep 6
########## Certificates
_info "Deleting old certificate..."
_ws_jobid=$(_ws_call "certificate.delete" "$_ui_certificate_id")
if ! _ws_check_jobid "$_ws_jobid"; then
_err "No JobID returned from websocket method."
return 3
fi
_ws_result=$(_ws_get_job_result "$_ws_jobid")
_ws_ret=$?
if [ $_ws_ret -gt 0 ]; then
return $_ws_ret
fi
_info "Have a nice day...bye!"
}

125
deploy/unifi.sh

@ -5,6 +5,15 @@
# - self-hosted Unifi Controller # - self-hosted Unifi Controller
# - Unifi Cloud Key (Gen1/2/2+) # - Unifi Cloud Key (Gen1/2/2+)
# - Unifi Cloud Key running UnifiOS (v2.0.0+, Gen2/2+ only) # - Unifi Cloud Key running UnifiOS (v2.0.0+, Gen2/2+ only)
# - Unifi Dream Machine
# This has not been tested on other "all-in-one" devices such as
# UDM Pro or Unifi Express.
#
# OS Version v2.0.0+
# Network Application version 7.0.0+
# OS version ~3.1 removed java and keytool from the UnifiOS.
# Using PKCS12 format keystore appears to work fine.
#
# Please report bugs to https://github.com/acmesh-official/acme.sh/issues/3359 # Please report bugs to https://github.com/acmesh-official/acme.sh/issues/3359
#returns 0 means success, otherwise error. #returns 0 means success, otherwise error.
@ -21,7 +30,9 @@
# Keystore password (built into Unifi Controller, not a user-set password): # Keystore password (built into Unifi Controller, not a user-set password):
#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise" #DEPLOY_UNIFI_KEYPASS="aircontrolenterprise"
# Command to restart Unifi Controller: # Command to restart Unifi Controller:
#DEPLOY_UNIFI_RELOAD="service unifi restart"
# DEPLOY_UNIFI_RELOAD="systemctl restart unifi"
# System Properties file location for controller
#DEPLOY_UNIFI_SYSTEM_PROPERTIES="/usr/lib/unifi/data/system.properties"
# #
# Settings for Unifi Cloud Key Gen1 (nginx admin pages): # Settings for Unifi Cloud Key Gen1 (nginx admin pages):
# Directory where cloudkey.crt and cloudkey.key live: # Directory where cloudkey.crt and cloudkey.key live:
@ -34,7 +45,7 @@
# Directory where unifi-core.crt and unifi-core.key live: # Directory where unifi-core.crt and unifi-core.key live:
#DEPLOY_UNIFI_CORE_CONFIG="/data/unifi-core/config/" #DEPLOY_UNIFI_CORE_CONFIG="/data/unifi-core/config/"
# Command to restart unifi-core: # Command to restart unifi-core:
#DEPLOY_UNIFI_RELOAD="systemctl restart unifi-core"
# DEPLOY_UNIFI_OS_RELOAD="systemctl restart unifi-core"
# #
# At least one of DEPLOY_UNIFI_KEYSTORE, DEPLOY_UNIFI_CLOUDKEY_CERTDIR, # At least one of DEPLOY_UNIFI_KEYSTORE, DEPLOY_UNIFI_CLOUDKEY_CERTDIR,
# or DEPLOY_UNIFI_CORE_CONFIG must exist to receive the deployed certs. # or DEPLOY_UNIFI_CORE_CONFIG must exist to receive the deployed certs.
@ -60,12 +71,16 @@ unifi_deploy() {
_getdeployconf DEPLOY_UNIFI_CLOUDKEY_CERTDIR _getdeployconf DEPLOY_UNIFI_CLOUDKEY_CERTDIR
_getdeployconf DEPLOY_UNIFI_CORE_CONFIG _getdeployconf DEPLOY_UNIFI_CORE_CONFIG
_getdeployconf DEPLOY_UNIFI_RELOAD _getdeployconf DEPLOY_UNIFI_RELOAD
_getdeployconf DEPLOY_UNIFI_SYSTEM_PROPERTIES
_getdeployconf DEPLOY_UNIFI_OS_RELOAD
_debug2 DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE" _debug2 DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE"
_debug2 DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS" _debug2 DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS"
_debug2 DEPLOY_UNIFI_CLOUDKEY_CERTDIR "$DEPLOY_UNIFI_CLOUDKEY_CERTDIR" _debug2 DEPLOY_UNIFI_CLOUDKEY_CERTDIR "$DEPLOY_UNIFI_CLOUDKEY_CERTDIR"
_debug2 DEPLOY_UNIFI_CORE_CONFIG "$DEPLOY_UNIFI_CORE_CONFIG" _debug2 DEPLOY_UNIFI_CORE_CONFIG "$DEPLOY_UNIFI_CORE_CONFIG"
_debug2 DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD" _debug2 DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD"
_debug2 DEPLOY_UNIFI_OS_RELOAD "$DEPLOY_UNIFI_OS_RELOAD"
_debug2 DEPLOY_UNIFI_SYSTEM_PROPERTIES "$DEPLOY_UNIFI_SYSTEM_PROPERTIES"
# Space-separated list of environments detected and installed: # Space-separated list of environments detected and installed:
_services_updated="" _services_updated=""
@ -74,14 +89,16 @@ unifi_deploy() {
_reload_cmd="" _reload_cmd=""
# Unifi Controller environment (self hosted or any Cloud Key) -- # Unifi Controller environment (self hosted or any Cloud Key) --
# auto-detect by file /usr/lib/unifi/data/keystore:
# auto-detect by file /usr/lib/unifi/data/keystore
_unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-/usr/lib/unifi/data/keystore}" _unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-/usr/lib/unifi/data/keystore}"
if [ -f "$_unifi_keystore" ]; then if [ -f "$_unifi_keystore" ]; then
_info "Installing certificate for Unifi Controller (Java keystore)"
_debug _unifi_keystore "$_unifi_keystore" _debug _unifi_keystore "$_unifi_keystore"
if ! _exists keytool; then if ! _exists keytool; then
_err "keytool not found"
return 1
_do_keytool=0
_info "Installing certificate for Unifi Controller (PKCS12 keystore)."
else
_do_keytool=1
_info "Installing certificate for Unifi Controller (Java keystore)"
fi fi
if [ ! -w "$_unifi_keystore" ]; then if [ ! -w "$_unifi_keystore" ]; then
_err "The file $_unifi_keystore is not writable, please change the permission." _err "The file $_unifi_keystore is not writable, please change the permission."
@ -92,6 +109,7 @@ unifi_deploy() {
_debug "Generate import pkcs12" _debug "Generate import pkcs12"
_import_pkcs12="$(_mktemp)" _import_pkcs12="$(_mktemp)"
_debug "_toPkcs $_import_pkcs12 $_ckey $_ccert $_cca $_unifi_keypass unifi root"
_toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root _toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
# shellcheck disable=SC2181 # shellcheck disable=SC2181
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
@ -99,22 +117,77 @@ unifi_deploy() {
return 1 return 1
fi fi
# Save the existing keystore in case something goes wrong.
mv -f "${_unifi_keystore}" "${_unifi_keystore}"_original
_info "Previous keystore saved to ${_unifi_keystore}_original."
if [ "$_do_keytool" -eq 1 ]; then
_debug "Import into keystore: $_unifi_keystore" _debug "Import into keystore: $_unifi_keystore"
if keytool -importkeystore \ if keytool -importkeystore \
-deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \ -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
-srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \ -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
-alias unifi -noprompt; then -alias unifi -noprompt; then
_debug "Import keystore success!" _debug "Import keystore success!"
rm "$_import_pkcs12"
else else
_err "Error importing into Unifi Java keystore." _err "Error importing into Unifi Java keystore."
_err "Please re-run with --debug and report a bug." _err "Please re-run with --debug and report a bug."
_info "Restoring original keystore."
mv -f "${_unifi_keystore}"_original "${_unifi_keystore}"
rm "$_import_pkcs12" rm "$_import_pkcs12"
return 1 return 1
fi fi
else
_debug "Copying new keystore to $_unifi_keystore"
cp -f "$_import_pkcs12" "$_unifi_keystore"
fi
# correct file ownership according to the directory, the keystore is placed in
_unifi_keystore_dir=$(dirname "${_unifi_keystore}")
_unifi_keystore_dir_owner=$(find "${_unifi_keystore_dir}" -maxdepth 0 -printf '%u\n')
_unifi_keystore_owner=$(find "${_unifi_keystore}" -maxdepth 0 -printf '%u\n')
if ! [ "${_unifi_keystore_owner}" = "${_unifi_keystore_dir_owner}" ]; then
_debug "Changing keystore owner to ${_unifi_keystore_dir_owner}"
chown "$_unifi_keystore_dir_owner" "${_unifi_keystore}" >/dev/null 2>&1 # fail quietly if we're not running as root
fi
if systemctl -q is-active unifi; then
_reload_cmd="${_reload_cmd:+$_reload_cmd && }service unifi restart"
# Update unifi service for certificate cipher compatibility
_unifi_system_properties="${DEPLOY_UNIFI_SYSTEM_PROPERTIES:-/usr/lib/unifi/data/system.properties}"
if ${ACME_OPENSSL_BIN:-openssl} pkcs12 \
-in "$_import_pkcs12" \
-password pass:aircontrolenterprise \
-nokeys | ${ACME_OPENSSL_BIN:-openssl} x509 -text \
-noout | grep -i "signature" | grep -iq ecdsa >/dev/null 2>&1; then
if [ -f "$(dirname "${DEPLOY_UNIFI_KEYSTORE}")/system.properties" ]; then
_unifi_system_properties="$(dirname "${DEPLOY_UNIFI_KEYSTORE}")/system.properties"
else
_unifi_system_properties="/usr/lib/unifi/data/system.properties"
fi
if [ -f "${_unifi_system_properties}" ]; then
cp -f "${_unifi_system_properties}" "${_unifi_system_properties}"_original
_info "Updating system configuration for cipher compatibility."
_info "Saved original system config to ${_unifi_system_properties}_original"
sed -i '/unifi\.https\.ciphers/d' "${_unifi_system_properties}"
echo "unifi.https.ciphers=ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES128-GCM-SHA256" >>"${_unifi_system_properties}"
sed -i '/unifi\.https\.sslEnabledProtocols/d' "${_unifi_system_properties}"
echo "unifi.https.sslEnabledProtocols=TLSv1.3,TLSv1.2" >>"${_unifi_system_properties}"
_info "System configuration updated."
fi
fi
rm "$_import_pkcs12"
# Restarting unifi-core will bring up unifi, doing it out of order results in
# a certificate error, and breaks wifiman.
# Restart if we aren't doing Unifi OS (e.g. unifi-core service), otherwise stop for later restart.
_unifi_reload="${DEPLOY_UNIFI_RELOAD:-systemctl restart unifi}"
if [ ! -f "${DEPLOY_UNIFI_CORE_CONFIG:-/data/unifi-core/config}/unifi-core.key" ]; then
_reload_cmd="${_reload_cmd:+$_reload_cmd && }$_unifi_reload"
else
_info "Stopping Unifi Controller for later restart."
_unifi_stop=$(echo "${_unifi_reload}" | sed -e 's/restart/stop/')
$_unifi_stop
_reload_cmd="${_reload_cmd:+$_reload_cmd && }$_unifi_reload"
_info "Unifi Controller stopped."
fi fi
_services_updated="${_services_updated} unifi" _services_updated="${_services_updated} unifi"
_info "Install Unifi Controller certificate success!" _info "Install Unifi Controller certificate success!"
@ -134,12 +207,23 @@ unifi_deploy() {
return 1 return 1
fi fi
# Cloud Key expects to load the keystore from /etc/ssl/private/unifi.keystore.jks. # Cloud Key expects to load the keystore from /etc/ssl/private/unifi.keystore.jks.
# Normally /usr/lib/unifi/data/keystore is a symlink there (so the keystore was
# updated above), but if not, we don't know how to handle this installation:
if ! cmp -s "$_unifi_keystore" "${_cloudkey_certdir}/unifi.keystore.jks"; then
_err "Unsupported Cloud Key configuration: keystore not found at '${_cloudkey_certdir}/unifi.keystore.jks'"
return 1
# It appears that unifi won't start if this is a symlink, so we'll copy it instead.
# if ! cmp -s "$_unifi_keystore" "${_cloudkey_certdir}/unifi.keystore.jks"; then
# _err "Unsupported Cloud Key configuration: keystore not found at '${_cloudkey_certdir}/unifi.keystore.jks'"
# return 1
# fi
_info "Updating ${_cloudkey_certdir}/unifi.keystore.jks"
if [ -e "${_cloudkey_certdir}/unifi.keystore.jks" ]; then
if [ -L "${_cloudkey_certdir}/unifi.keystore.jks" ]; then
rm -f "${_cloudkey_certdir}/unifi.keystore.jks"
else
mv "${_cloudkey_certdir}/unifi.keystore.jks" "${_cloudkey_certdir}/unifi.keystore.jks_original"
fi fi
fi
cp "${_unifi_keystore}" "${_cloudkey_certdir}/unifi.keystore.jks"
cat "$_cfullchain" >"${_cloudkey_certdir}/cloudkey.crt" cat "$_cfullchain" >"${_cloudkey_certdir}/cloudkey.crt"
cat "$_ckey" >"${_cloudkey_certdir}/cloudkey.key" cat "$_ckey" >"${_cloudkey_certdir}/cloudkey.key"
@ -165,12 +249,17 @@ unifi_deploy() {
return 1 return 1
fi fi
# Save the existing certs in case something goes wrong.
cp -f "${_unifi_core_config}"/unifi-core.crt "${_unifi_core_config}"/unifi-core_original.crt
cp -f "${_unifi_core_config}"/unifi-core.key "${_unifi_core_config}"/unifi-core_original.key
_info "Previous certificate and key saved to ${_unifi_core_config}/unifi-core_original.crt.key."
cat "$_cfullchain" >"${_unifi_core_config}/unifi-core.crt" cat "$_cfullchain" >"${_unifi_core_config}/unifi-core.crt"
cat "$_ckey" >"${_unifi_core_config}/unifi-core.key" cat "$_ckey" >"${_unifi_core_config}/unifi-core.key"
if systemctl -q is-active unifi-core; then
_reload_cmd="${_reload_cmd:+$_reload_cmd && }systemctl restart unifi-core"
fi
_unifi_os_reload="${DEPLOY_UNIFI_OS_RELOAD:-systemctl restart unifi-core}"
_reload_cmd="${_reload_cmd:+$_reload_cmd && }$_unifi_os_reload"
_info "Install UnifiOS certificate success!" _info "Install UnifiOS certificate success!"
_services_updated="${_services_updated} unifi-core" _services_updated="${_services_updated} unifi-core"
elif [ "$DEPLOY_UNIFI_CORE_CONFIG" ]; then elif [ "$DEPLOY_UNIFI_CORE_CONFIG" ]; then
@ -209,6 +298,8 @@ unifi_deploy() {
_savedeployconf DEPLOY_UNIFI_CLOUDKEY_CERTDIR "$DEPLOY_UNIFI_CLOUDKEY_CERTDIR" _savedeployconf DEPLOY_UNIFI_CLOUDKEY_CERTDIR "$DEPLOY_UNIFI_CLOUDKEY_CERTDIR"
_savedeployconf DEPLOY_UNIFI_CORE_CONFIG "$DEPLOY_UNIFI_CORE_CONFIG" _savedeployconf DEPLOY_UNIFI_CORE_CONFIG "$DEPLOY_UNIFI_CORE_CONFIG"
_savedeployconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD" _savedeployconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD"
_savedeployconf DEPLOY_UNIFI_OS_RELOAD "$DEPLOY_UNIFI_OS_RELOAD"
_savedeployconf DEPLOY_UNIFI_SYSTEM_PROPERTIES "$DEPLOY_UNIFI_SYSTEM_PROPERTIES"
return 0 return 0
} }

106
deploy/vault.sh

@ -70,20 +70,25 @@ vault_deploy() {
# JSON does not allow multiline strings. # JSON does not allow multiline strings.
# So replacing new-lines with "\n" here # So replacing new-lines with "\n" here
_ckey=$(sed -z 's/\n/\\n/g' <"$2")
_ccert=$(sed -z 's/\n/\\n/g' <"$3")
_cca=$(sed -z 's/\n/\\n/g' <"$4")
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
_ckey=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$2")
_ccert=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$3")
_cca=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$4")
_cfullchain=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$5")
export _H1="X-Vault-Token: $VAULT_TOKEN" export _H1="X-Vault-Token: $VAULT_TOKEN"
if [ -n "$VAULT_RENEW_TOKEN" ]; then if [ -n "$VAULT_RENEW_TOKEN" ]; then
URL="$VAULT_ADDR/v1/auth/token/renew-self" URL="$VAULT_ADDR/v1/auth/token/renew-self"
_info "Renew the Vault token to default TTL" _info "Renew the Vault token to default TTL"
if ! _post "" "$URL" >/dev/null; then
_response=$(_post "" "$URL")
if [ "$?" != "0" ]; then
_err "Failed to renew the Vault token" _err "Failed to renew the Vault token"
return 1 return 1
fi fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Failed to renew the Vault token: $_response"
return 1
fi
fi fi
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain" URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
@ -91,29 +96,85 @@ vault_deploy() {
if [ -n "$VAULT_FABIO_MODE" ]; then if [ -n "$VAULT_FABIO_MODE" ]; then
_info "Writing certificate and key to $URL in Fabio mode" _info "Writing certificate and key to $URL in Fabio mode"
if [ -n "$VAULT_KV_V2" ]; then if [ -n "$VAULT_KV_V2" ]; then
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL" >/dev/null || return 1
_response=$(_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error: $_response"
return 1
fi
else else
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
_response=$(_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error: $_response"
return 1
fi
fi fi
else else
if [ -n "$VAULT_KV_V2" ]; then if [ -n "$VAULT_KV_V2" ]; then
_info "Writing certificate to $URL/cert.pem" _info "Writing certificate to $URL/cert.pem"
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem" >/dev/null || return 1
_response=$(_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing cert.pem: $_response"
return 1
fi
_info "Writing key to $URL/cert.key" _info "Writing key to $URL/cert.key"
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key" >/dev/null || return 1
_response=$(_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing cert.key: $_response"
return 1
fi
_info "Writing CA certificate to $URL/ca.pem" _info "Writing CA certificate to $URL/ca.pem"
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem" >/dev/null || return 1
_response=$(_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing ca.pem: $_response"
return 1
fi
_info "Writing full-chain certificate to $URL/fullchain.pem" _info "Writing full-chain certificate to $URL/fullchain.pem"
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem" >/dev/null || return 1
_response=$(_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing fullchain.pem: $_response"
return 1
fi
else else
_info "Writing certificate to $URL/cert.pem" _info "Writing certificate to $URL/cert.pem"
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" >/dev/null || return 1
_response=$(_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing cert.pem: $_response"
return 1
fi
_info "Writing key to $URL/cert.key" _info "Writing key to $URL/cert.key"
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key" >/dev/null || return 1
_response=$(_post "{\"value\": \"$_ckey\"}" "$URL/cert.key")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing cert.key: $_response"
return 1
fi
_info "Writing CA certificate to $URL/ca.pem" _info "Writing CA certificate to $URL/ca.pem"
_post "{\"value\": \"$_cca\"}" "$URL/ca.pem" >/dev/null || return 1
_response=$(_post "{\"value\": \"$_cca\"}" "$URL/ca.pem")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing ca.pem: $_response"
return 1
fi
_info "Writing full-chain certificate to $URL/fullchain.pem" _info "Writing full-chain certificate to $URL/fullchain.pem"
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem" >/dev/null || return 1
_response=$(_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing fullchain.pem: $_response"
return 1
fi
fi fi
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions # To make it compatible with the wrong ca path `chain.pem` which was used in former versions
@ -121,11 +182,20 @@ vault_deploy() {
_err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning" _err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
_info "Updating CA certificate to $URL/chain.pem for backward compatibility" _info "Updating CA certificate to $URL/chain.pem for backward compatibility"
if [ -n "$VAULT_KV_V2" ]; then if [ -n "$VAULT_KV_V2" ]; then
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem" >/dev/null || return 1
_response=$(_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing chain.pem: $_response"
return 1
fi
else else
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem" >/dev/null || return 1
_response=$(_post "{\"value\": \"$_cca\"}" "$URL/chain.pem")
if [ "$?" != "0" ]; then return 1; fi
if echo "$_response" | grep -q '"errors":\['; then
_err "Vault error writing chain.pem: $_response"
return 1
fi
fi fi
fi fi
fi fi
} }

2
deploy/vsftpd.sh

@ -106,5 +106,5 @@ vsftpd_deploy() {
fi fi
return 1 return 1
fi fi
return 0
} }

31
dnsapi/dns_1984hosting.sh

@ -1,22 +1,18 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# This file name is "dns_1984hosting.sh"
# So, here must be a method dns_1984hosting_add()
# Which will be called by acme.sh to add the txt record to your api system.
# returns 0 means success, otherwise error.
# Author: Adrian Fedoreanu
# Report Bugs here: https://github.com/acmesh-official/acme.sh
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
# shellcheck disable=SC2034
dns_1984hosting_info='1984.hosting
Domains: 1984.is
Site: 1984.hosting
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_1984hosting
Options:
One984HOSTING_Username Username
One984HOSTING_Password Password
Issues: github.com/acmesh-official/acme.sh/issues/2851
Author: Adrian Fedoreanu
'
######## Public functions ##################### ######## Public functions #####################
# Export 1984HOSTING username and password in following variables
#
# One984HOSTING_Username=username
# One984HOSTING_Password=password
#
# username/password and csrftoken/sessionid cookies are saved in ~/.acme.sh/account.conf
# Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" # Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Add a text record. # Add a text record.
dns_1984hosting_add() { dns_1984hosting_add() {
@ -215,8 +211,8 @@ _get_root() {
return 1 return 1
fi fi
_authget "https://1984.hosting/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
if _contains "$_response" "serial" && ! _contains "$_response" "null"; then
_authget "https://1984.hosting/domains/zonestatus/$h/?cached=no"
if _contains "$_response" '"ok": true'; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain="$h" _domain="$h"
return 0 return 0
@ -250,7 +246,6 @@ _authget() {
} }
# Truncate huge HTML response # Truncate huge HTML response
# Echo: Argument list too long
_htmlget() { _htmlget() {
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE" export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
_response=$(_get "$1" | grep "$2") _response=$(_get "$1" | grep "$2")

28
dnsapi/dns_acmedns.sh

@ -1,18 +1,18 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#Author: Wolfgang Ebner
#Author: Sven Neubuaer
#Report Bugs here: https://github.com/dampfklon/acme.sh
#
# Usage:
# export ACMEDNS_BASE_URL="https://auth.acme-dns.io"
#
# You can optionally define an already existing account:
#
# export ACMEDNS_USERNAME="<username>"
# export ACMEDNS_PASSWORD="<password>"
# export ACMEDNS_SUBDOMAIN="<subdomain>"
#
# shellcheck disable=SC2034
dns_acmedns_info='acme-dns Server API
The acme-dns is a limited DNS server with RESTful API to handle ACME DNS challenges.
Site: github.com/joohoi/acme-dns
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_acmedns
Options:
ACMEDNS_USERNAME Username. Optional.
ACMEDNS_PASSWORD Password. Optional.
ACMEDNS_SUBDOMAIN Subdomain. Optional.
ACMEDNS_BASE_URL API endpoint. Default: "https://auth.acme-dns.io".
Issues: github.com/dampfklon/acme.sh
Author: Wolfgang Ebner, Sven Neubuaer
'
######## Public functions ##################### ######## Public functions #####################
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" #Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"

18
dnsapi/dns_acmeproxy.sh

@ -1,9 +1,17 @@
#!/usr/bin/env sh #!/usr/bin/env sh
## Acmeproxy DNS provider to be used with acmeproxy (https://github.com/mdbraber/acmeproxy)
## API integration by Maarten den Braber
##
## Report any bugs via https://github.com/mdbraber/acme.sh
# shellcheck disable=SC2034
dns_acmeproxy_info='AcmeProxy Server API
AcmeProxy can be used to as a single host in your network to request certificates through a DNS API.
Clients can connect with the one AcmeProxy host so you do not need to store DNS API credentials on every single host.
Site: github.com/mdbraber/acmeproxy
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_acmeproxy
Options:
ACMEPROXY_ENDPOINT API Endpoint
ACMEPROXY_USERNAME Username
ACMEPROXY_PASSWORD Password
Issues: github.com/acmesh-official/acme.sh/issues/2251
Author: Maarten den Braber
'
dns_acmeproxy_add() { dns_acmeproxy_add() {
fulldomain="${1}" fulldomain="${1}"

17
dnsapi/dns_active24.sh

@ -1,6 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
# shellcheck disable=SC2034
dns_active24_info='Active24.com
Site: Active24.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_active24
Options:
ACTIVE24_Token API Token
Issues: github.com/acmesh-official/acme.sh/issues/2059
Author: Milan Pála
'
ACTIVE24_Api="https://api.active24.com" ACTIVE24_Api="https://api.active24.com"
@ -76,10 +83,10 @@ _get_root() {
return 1 return 1
fi fi
i=2
i=1
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug "h" "$h" _debug "h" "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -87,7 +94,7 @@ _get_root() {
fi fi
if _contains "$response" "\"$h\"" >/dev/null; then if _contains "$response" "\"$h\"" >/dev/null; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

21
dnsapi/dns_ad.sh

@ -1,12 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
#This is the Alwaysdata api wrapper for acme.sh
#
#Author: Paul Koppen
#Report Bugs here: https://github.com/wpk-/acme.sh
# shellcheck disable=SC2034
dns_ad_info='AlwaysData.com
Site: AlwaysData.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ad
Options:
AD_API_KEY API Key
Issues: github.com/acmesh-official/acme.sh/pull/503
Author: Paul Koppen
'
AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1"
@ -94,7 +95,7 @@ _get_root() {
if _ad_rest GET "domain/"; then if _ad_rest GET "domain/"; then
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -105,7 +106,7 @@ _get_root() {
if [ "$hostedzone" ]; then if [ "$hostedzone" ]; then
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

153
dnsapi/dns_ali.sh

@ -1,27 +1,27 @@
#!/usr/bin/env sh #!/usr/bin/env sh
Ali_API="https://alidns.aliyuncs.com/"
#Ali_Key="LTqIA87hOKdjevsf5"
#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2"
# shellcheck disable=SC2034
dns_ali_info='AlibabaCloud.com
Domains: Aliyun.com
Site: AlibabaCloud.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ali
Options:
Ali_Key API Key
Ali_Secret API Secret
'
# NOTICE:
# This file is referenced by Alibaba Cloud Services deploy hooks
# https://github.com/acmesh-official/acme.sh/pull/5205#issuecomment-2357867276
# Be careful when modifying this file, especially when making breaking changes for common functions
Ali_DNS_API="https://alidns.aliyuncs.com/"
#Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" #Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_ali_add() { dns_ali_add() {
fulldomain=$1 fulldomain=$1
txtvalue=$2 txtvalue=$2
Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}"
Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}"
if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then
Ali_Key=""
Ali_Secret=""
_err "You don't specify aliyun api key and secret yet."
return 1
fi
#save the api key and secret to the account conf file.
_saveaccountconf_mutable Ali_Key "$Ali_Key"
_saveaccountconf_mutable Ali_Secret "$Ali_Secret"
_prepare_ali_credentials || return 1
_debug "First detect the root zone" _debug "First detect the root zone"
if ! _get_root "$fulldomain"; then if ! _get_root "$fulldomain"; then
@ -46,14 +46,74 @@ dns_ali_rm() {
_clean _clean
} }
#################### Private functions below ##################################
#################### Alibaba Cloud common functions below ####################
_prepare_ali_credentials() {
Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}"
Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}"
if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then
Ali_Key=""
Ali_Secret=""
_err "You don't specify aliyun api key and secret yet."
return 1
fi
#save the api key and secret to the account conf file.
_saveaccountconf_mutable Ali_Key "$Ali_Key"
_saveaccountconf_mutable Ali_Secret "$Ali_Secret"
}
# act ign mtd
_ali_rest() {
act="$1"
ign="$2"
mtd="${3:-GET}"
signature=$(printf "%s" "$mtd&%2F&$(printf "%s" "$query" | _url_encode upper-hex)" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64)
signature=$(printf "%s" "$signature" | _url_encode upper-hex)
url="$endpoint?Signature=$signature"
if [ "$mtd" = "GET" ]; then
url="$url&$query"
response="$(_get "$url")"
else
response="$(_post "$query" "$url" "" "$mtd" "application/x-www-form-urlencoded")"
fi
_ret="$?"
_debug2 response "$response"
if [ "$_ret" != "0" ]; then
_err "Error <$act>"
return 1
fi
if [ -z "$ign" ]; then
message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
if [ "$message" ]; then
_err "$message"
return 1
fi
fi
}
_ali_nonce() {
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
#Not so good...
date +"%s%N" | sed 's/%N//g'
}
_timestamp() {
date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ"
}
#################### Private functions below ####################
_get_root() { _get_root() {
domain=$1 domain=$1
i=2
i=1
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
return 1 return 1
@ -65,7 +125,7 @@ _get_root() {
fi fi
if _contains "$response" "PageNumber"; then if _contains "$response" "PageNumber"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_debug _sub_domain "$_sub_domain" _debug _sub_domain "$_sub_domain"
_domain="$h" _domain="$h"
_debug _domain "$_domain" _debug _domain "$_domain"
@ -77,52 +137,10 @@ _get_root() {
return 1 return 1
} }
_ali_rest() {
signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64)
signature=$(_ali_urlencode "$signature")
url="$Ali_API?$query&Signature=$signature"
if ! response="$(_get "$url")"; then
_err "Error <$1>"
return 1
fi
_debug2 response "$response"
if [ -z "$2" ]; then
message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
if [ "$message" ]; then
_err "$message"
return 1
fi
fi
}
_ali_urlencode() {
_str="$1"
_str_len=${#_str}
_u_i=1
while [ "$_u_i" -le "$_str_len" ]; do
_str_c="$(printf "%s" "$_str" | cut -c "$_u_i")"
case $_str_c in [a-zA-Z0-9.~_-])
printf "%s" "$_str_c"
;;
*)
printf "%%%02X" "'$_str_c"
;;
esac
_u_i="$(_math "$_u_i" + 1)"
done
}
_ali_nonce() {
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
#Not so good...
date +"%s%N" | sed 's/%N//g'
}
_check_exist_query() { _check_exist_query() {
_qdomain="$1" _qdomain="$1"
_qsubdomain="$2" _qsubdomain="$2"
endpoint=$Ali_DNS_API
query='' query=''
query=$query'AccessKeyId='$Ali_Key query=$query'AccessKeyId='$Ali_Key
query=$query'&Action=DescribeDomainRecords' query=$query'&Action=DescribeDomainRecords'
@ -138,6 +156,7 @@ _check_exist_query() {
} }
_add_record_query() { _add_record_query() {
endpoint=$Ali_DNS_API
query='' query=''
query=$query'AccessKeyId='$Ali_Key query=$query'AccessKeyId='$Ali_Key
query=$query'&Action=AddDomainRecord' query=$query'&Action=AddDomainRecord'
@ -154,6 +173,7 @@ _add_record_query() {
} }
_delete_record_query() { _delete_record_query() {
endpoint=$Ali_DNS_API
query='' query=''
query=$query'AccessKeyId='$Ali_Key query=$query'AccessKeyId='$Ali_Key
query=$query'&Action=DeleteDomainRecord' query=$query'&Action=DeleteDomainRecord'
@ -167,6 +187,7 @@ _delete_record_query() {
} }
_describe_records_query() { _describe_records_query() {
endpoint=$Ali_DNS_API
query='' query=''
query=$query'AccessKeyId='$Ali_Key query=$query'AccessKeyId='$Ali_Key
query=$query'&Action=DescribeDomainRecords' query=$query'&Action=DescribeDomainRecords'
@ -197,7 +218,3 @@ _clean() {
fi fi
} }
_timestamp() {
date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ"
}

185
dnsapi/dns_alviy.sh

@ -0,0 +1,185 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034
dns_alviy_info='Alviy.com
Site: Alviy.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_alviy
Options:
Alviy_token API token. Get it from the https://cloud.alviy.com/token
Issues: github.com/acmesh-official/acme.sh/issues/5115
'
Alviy_Api="https://cloud.alviy.com/api/v1"
######## Public functions #####################
#Usage: dns_alviy_add _acme-challenge.www.domain.com "content"
dns_alviy_add() {
fulldomain=$1
txtvalue=$2
Alviy_token="${Alviy_token:-$(_readaccountconf_mutable Alviy_token)}"
if [ -z "$Alviy_token" ]; then
Alviy_token=""
_err "Please specify Alviy token."
return 1
fi
#save the api key and email to the account conf file.
_saveaccountconf_mutable Alviy_token "$Alviy_token"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_debug "Getting existing records"
if _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then
_info "This record already exists, skipping"
return 0
fi
_add_data="{\"content\":\"$txtvalue\",\"type\":\"TXT\"}"
_debug2 _add_data "$_add_data"
_info "Adding record"
if _alviy_rest POST "zone/$_domain/domain/$fulldomain/" "$_add_data"; then
_debug "Checking updated records of '${fulldomain}'"
if ! _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then
_err "TXT record '${txtvalue}' for '${fulldomain}', value wasn't set!"
return 1
fi
else
_err "Add txt record error, value '${txtvalue}' for '${fulldomain}' was not set."
return 1
fi
_sleep 10
_info "Added TXT record '${txtvalue}' for '${fulldomain}'."
return 0
}
#fulldomain
dns_alviy_rm() {
fulldomain=$1
txtvalue=$2
Alviy_token="${Alviy_token:-$(_readaccountconf_mutable Alviy_token)}"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
if ! _alviy_txt_exists "$_domain" "$fulldomain" "$txtvalue"; then
_info "The record does not exist, skip"
return 0
fi
_add_data=""
uuid=$(echo "$response" | tr "{" "\n" | grep "$txtvalue" | tr "," "\n" | grep uuid | cut -d \" -f4)
# delete record
_debug "Delete TXT record for '${fulldomain}'"
if ! _alviy_rest DELETE "zone/$_domain/record/$uuid" "{\"confirm\":1}"; then
_err "Cannot delete empty TXT record for '$fulldomain'"
return 1
fi
_info "The record '$fulldomain'='$txtvalue' deleted"
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain=$1
i=3
a="init"
while [ -n "$a" ]; do
a=$(printf "%s" "$domain" | cut -d . -f $i-)
i=$((i + 1))
done
n=$((i - 3))
h=$(printf "%s" "$domain" | cut -d . -f $n-)
if [ -z "$h" ]; then
#not valid
_alviy_rest GET "zone/$domain/"
_debug "can't get host from $domain"
return 1
fi
if ! _alviy_rest GET "zone/$h/"; then
return 1
fi
if _contains "$response" '"code":"NOT_FOUND"'; then
_debug "$h not found"
else
s=$((n - 1))
_sub_domain=$(printf "%s" "$domain" | cut -d . -f -$s)
_domain="$h"
return 0
fi
return 1
}
_alviy_txt_exists() {
zone=$1
domain=$2
content_data=$3
_debug "Getting existing records"
if ! _alviy_rest GET "zone/$zone/domain/$domain/TXT/"; then
_info "The record does not exist"
return 1
fi
if ! _contains "$response" "$3"; then
_info "The record has other value"
return 1
fi
# GOOD code return - TRUE function
return 0
}
_alviy_rest() {
method=$1
path="$2"
content_data="$3"
_debug "$path"
export _H1="Authorization: Bearer $Alviy_token"
export _H2="Content-Type: application/json"
if [ "$content_data" ] || [ "$method" = "DELETE" ]; then
_debug "data ($method): " "$content_data"
response="$(_post "$content_data" "$Alviy_Api/$path" "" "$method")"
else
response="$(_get "$Alviy_Api/$path")"
fi
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
if [ "$_code" = "401" ]; then
_err "It seems that your api key or secret is not correct."
return 1
fi
if [ "$_code" != "200" ]; then
_err "API call error ($method): $path Response code $_code"
fi
if [ "$?" != "0" ]; then
_err "error on rest call ($method): $path. Response:"
_err "$response"
return 1
fi
_debug2 response "$response"
return 0
}

20
dnsapi/dns_anx.sh

@ -1,9 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Anexia CloudDNS acme.sh hook
# Author: MA
#ANX_Token="xxxx"
# shellcheck disable=SC2034
dns_anx_info='Anexia.com CloudDNS
Site: Anexia.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_anx
Options:
ANX_Token API Token
Issues: github.com/acmesh-official/acme.sh/issues/3238
'
ANX_API='https://engine.anexia-it.com/api/clouddns/v1' ANX_API='https://engine.anexia-it.com/api/clouddns/v1'
@ -127,18 +130,17 @@ _get_root() {
i=1 i=1
p=1 p=1
_anx_rest GET "zone.json"
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
return 1 return 1
fi fi
_anx_rest GET "zone.json/${h}"
if _contains "$response" "\"name\":\"$h\""; then if _contains "$response" "\"name\":\"$h\""; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

23
dnsapi/dns_artfiles.sh

@ -1,17 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
################################################################################
# ACME.sh 3rd party DNS API plugin for ArtFiles.de
################################################################################
# Author: Martin Arndt, https://troublezone.net/
# Released: 2022-02-27
# Issues: https://github.com/acmesh-official/acme.sh/issues/4718
################################################################################
# Usage:
# 1. export AF_API_USERNAME='api12345678'
# 2. export AF_API_PASSWORD='apiPassword'
# 3. acme.sh --issue -d example.com --dns dns_artfiles
################################################################################
# shellcheck disable=SC2034
dns_artfiles_info='ArtFiles.de
Site: ArtFiles.de
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_artfiles
Options:
AF_API_USERNAME API Username
AF_API_PASSWORD API Password
Issues: github.com/acmesh-official/acme.sh/issues/4718
Author: Martin Arndt <https://troublezone.net/>
'
########## API configuration ################################################### ########## API configuration ###################################################

19
dnsapi/dns_arvan.sh

@ -1,11 +1,16 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Arvan_Token="Apikey xxxx"
# shellcheck disable=SC2034
dns_arvan_info='ArvanCloud.ir
Site: ArvanCloud.ir
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_arvan
Options:
Arvan_Token API Token
Issues: github.com/acmesh-official/acme.sh/issues/2796
Author: Vahid Fardi
'
ARVAN_API_URL="https://napi.arvancloud.ir/cdn/4.0/domains" ARVAN_API_URL="https://napi.arvancloud.ir/cdn/4.0/domains"
# Author: Vahid Fardi
# Report Bugs here: https://github.com/Neilpang/acme.sh
#
######## Public functions ##################### ######## Public functions #####################
#Usage: dns_arvan_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" #Usage: dns_arvan_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
@ -102,7 +107,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -115,7 +120,7 @@ _get_root() {
if _contains "$response" "\"domain\":\"$h\""; then if _contains "$response" "\"domain\":\"$h\""; then
_domain_id=$(echo "$response" | cut -d : -f 3 | cut -d , -f 1 | tr -d \") _domain_id=$(echo "$response" | cut -d : -f 3 | cut -d , -f 1 | tr -d \")
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

20
dnsapi/dns_aurora.sh

@ -1,9 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#AURORA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
#
#AURORA_Secret="sdfsdfsdfljlbjkljlkjsdfoiwje"
# shellcheck disable=SC2034
dns_aurora_info='versio.nl AuroraDNS
Domains: pcextreme.nl
Site: versio.nl
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_aurora
Options:
AURORA_Key API Key
AURORA_Secret API Secret
Issues: github.com/acmesh-official/acme.sh/issues/3459
Author: Jasper Zonneveld
'
AURORA_Api="https://api.auroradns.eu" AURORA_Api="https://api.auroradns.eu"
@ -111,7 +117,7 @@ _get_root() {
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -126,7 +132,7 @@ _get_root() {
_domain_id=$(echo "$response" | _normalizeJson | tr -d "{}" | tr "," "\n" | grep "\"id\": *\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ") _domain_id=$(echo "$response" | _normalizeJson | tr -d "{}" | tr "," "\n" | grep "\"id\": *\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ")
_debug _domain_id "$_domain_id" _debug _domain_id "$_domain_id"
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

27
dnsapi/dns_autodns.sh

@ -1,16 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
# This is the InternetX autoDNS xml api wrapper for acme.sh
# Author: auerswald@gmail.com
# Created: 2018-01-14
#
# export AUTODNS_USER="username"
# export AUTODNS_PASSWORD="password"
# export AUTODNS_CONTEXT="context"
#
# Usage:
# acme.sh --issue --dns dns_autodns -d example.com
# shellcheck disable=SC2034
dns_autodns_info='InternetX autoDNS
InternetX autoDNS XML API
Site: InternetX.com/autodns/
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_autodns
Options:
AUTODNS_USER Username
AUTODNS_PASSWORD Password
AUTODNS_CONTEXT Context
Author: <auerswald@gmail.com>
'
AUTODNS_API="https://gateway.autodns.com" AUTODNS_API="https://gateway.autodns.com"
@ -111,7 +110,7 @@ _get_autodns_zone() {
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
@ -129,7 +128,7 @@ _get_autodns_zone() {
if _contains "$autodns_response" "<summary>1</summary>" >/dev/null; then if _contains "$autodns_response" "<summary>1</summary>" >/dev/null; then
_zone="$(echo "$autodns_response" | _egrep_o '<name>[^<]*</name>' | cut -d '>' -f 2 | cut -d '<' -f 1)" _zone="$(echo "$autodns_response" | _egrep_o '<name>[^<]*</name>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
_system_ns="$(echo "$autodns_response" | _egrep_o '<system_ns>[^<]*</system_ns>' | cut -d '>' -f 2 | cut -d '<' -f 1)" _system_ns="$(echo "$autodns_response" | _egrep_o '<system_ns>[^<]*</system_ns>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
return 0 return 0
fi fi

24
dnsapi/dns_aws.sh

@ -1,13 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#AWS_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje"
#
#AWS_SECRET_ACCESS_KEY="xxxxxxx"
#This is the Amazon Route53 api wrapper for acme.sh
#All `_sleep` commands are included to avoid Route53 throttling, see
#https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
# shellcheck disable=SC2034
dns_aws_info='Amazon AWS Route53 domain API
Site: docs.aws.amazon.com/route53/
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_aws
Options:
AWS_ACCESS_KEY_ID API Key ID
AWS_SECRET_ACCESS_KEY API Secret
'
# All `_sleep` commands are included to avoid Route53 throttling, see
# https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
AWS_HOST="route53.amazonaws.com" AWS_HOST="route53.amazonaws.com"
AWS_URL="https://$AWS_HOST" AWS_URL="https://$AWS_HOST"
@ -156,7 +158,7 @@ _get_root() {
# iterate over names (a.b.c.d -> b.c.d -> c.d -> d) # iterate over names (a.b.c.d -> b.c.d -> c.d -> d)
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100 | sed 's/\./\\./g')
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100 | sed 's/\./\\./g')
_debug "Checking domain: $h" _debug "Checking domain: $h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
_error "invalid domain" _error "invalid domain"
@ -172,7 +174,7 @@ _get_root() {
if [ "$hostedzone" ]; then if [ "$hostedzone" ]; then
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

18
dnsapi/dns_azion.sh

@ -1,9 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#AZION_Email=""
#AZION_Password=""
#
# shellcheck disable=SC2034
dns_azion_info='Azion.om
Site: Azion.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_azion
Options:
AZION_Email Email
AZION_Password Password
Issues: github.com/acmesh-official/acme.sh/issues/3555
'
AZION_Api="https://api.azionapi.net" AZION_Api="https://api.azionapi.net"
@ -96,7 +100,7 @@ _get_root() {
fi fi
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
# not valid # not valid
@ -107,7 +111,7 @@ _get_root() {
_domain_id=$(echo "$response" | tr '{' "\n" | grep "\"domain\":\"$h\"" | _egrep_o "\"id\":[0-9]*" | _head_n 1 | cut -d : -f 2 | tr -d \") _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"domain\":\"$h\"" | _egrep_o "\"id\":[0-9]*" | _head_n 1 | cut -d : -f 2 | tr -d \")
_debug _domain_id "$_domain_id" _debug _domain_id "$_domain_id"
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

81
dnsapi/dns_azure.sh

@ -1,13 +1,25 @@
#!/usr/bin/env sh #!/usr/bin/env sh
WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
# shellcheck disable=SC2034
dns_azure_info='Azure
Site: Azure.microsoft.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_azure
Options:
AZUREDNS_SUBSCRIPTIONID Subscription ID
AZUREDNS_TENANTID Tenant ID
AZUREDNS_APPID App ID. App ID of the service principal
AZUREDNS_CLIENTSECRET Client Secret. Secret from creating the service principal
AZUREDNS_MANAGEDIDENTITY Use Managed Identity. Use Managed Identity assigned to a resource instead of a service principal. "true"/"false"
AZUREDNS_BEARERTOKEN Bearer Token. Used instead of service principal credentials or managed identity. Optional.
'
wiki=https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS
######## Public functions ##################### ######## Public functions #####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record # Used to add txt record
# #
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate
# Ref: https://learn.microsoft.com/en-us/rest/api/dns/record-sets/create-or-update?view=rest-dns-2018-05-01&tabs=HTTP
# #
dns_azure_add() { dns_azure_add() {
@ -20,6 +32,7 @@ dns_azure_add() {
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Subscription ID" _err "You didn't specify the Azure Subscription ID"
return 1 return 1
fi fi
@ -34,17 +47,20 @@ dns_azure_add() {
_saveaccountconf_mutable AZUREDNS_TENANTID "" _saveaccountconf_mutable AZUREDNS_TENANTID ""
_saveaccountconf_mutable AZUREDNS_APPID "" _saveaccountconf_mutable AZUREDNS_APPID ""
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "" _saveaccountconf_mutable AZUREDNS_CLIENTSECRET ""
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN ""
else else
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
_info "You didn't ask to use Azure managed identity, checking service principal credentials or provided bearer token"
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
AZUREDNS_BEARERTOKEN="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
if [ -z "$AZUREDNS_TENANTID" ]; then if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Tenant ID " _err "You didn't specify the Azure Tenant ID "
return 1 return 1
fi fi
@ -54,6 +70,7 @@ dns_azure_add() {
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure App ID" _err "You didn't specify the Azure App ID"
return 1 return 1
fi fi
@ -63,18 +80,27 @@ dns_azure_add() {
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Client Secret" _err "You didn't specify the Azure Client Secret"
return 1 return 1
fi fi
else
_info "Using provided bearer token"
fi
#save account details to account conf file, don't opt in for azure manages identity check. #save account details to account conf file, don't opt in for azure manages identity check.
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "false" _saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "false"
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID" _saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID" _saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET" _saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$AZUREDNS_BEARERTOKEN"
fi fi
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
else
accesstoken=$(echo "$AZUREDNS_BEARERTOKEN" | sed "s/Bearer //g")
fi
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
_err "invalid domain" _err "invalid domain"
@ -124,7 +150,7 @@ dns_azure_add() {
# Usage: fulldomain txtvalue # Usage: fulldomain txtvalue
# Used to remove the txt record after validation # Used to remove the txt record after validation
# #
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete
# Ref: https://learn.microsoft.com/en-us/rest/api/dns/record-sets/delete?view=rest-dns-2018-05-01&tabs=HTTP
# #
dns_azure_rm() { dns_azure_rm() {
fulldomain=$1 fulldomain=$1
@ -136,6 +162,7 @@ dns_azure_rm() {
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Subscription ID " _err "You didn't specify the Azure Subscription ID "
return 1 return 1
fi fi
@ -144,16 +171,18 @@ dns_azure_rm() {
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
_info "Using Azure managed identity" _info "Using Azure managed identity"
else else
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
_info "You didn't ask to use Azure managed identity, checking service principal credentials or provided bearer token"
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
AZUREDNS_BEARERTOKEN="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
if [ -z "$AZUREDNS_TENANTID" ]; then if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Tenant ID " _err "You didn't specify the Azure Tenant ID "
return 1 return 1
fi fi
@ -163,6 +192,7 @@ dns_azure_rm() {
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure App ID" _err "You didn't specify the Azure App ID"
return 1 return 1
fi fi
@ -172,12 +202,20 @@ dns_azure_rm() {
AZUREDNS_TENANTID="" AZUREDNS_TENANTID=""
AZUREDNS_APPID="" AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET="" AZUREDNS_CLIENTSECRET=""
AZUREDNS_BEARERTOKEN=""
_err "You didn't specify the Azure Client Secret" _err "You didn't specify the Azure Client Secret"
return 1 return 1
fi fi
else
_info "Using provided bearer token"
fi
fi fi
if [ -z "$AZUREDNS_BEARERTOKEN" ]; then
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
else
accesstoken=$(echo "$AZUREDNS_BEARERTOKEN" | sed "s/Bearer //g")
fi
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
_err "invalid domain" _err "invalid domain"
@ -256,10 +294,10 @@ _azure_rest() {
if [ "$_code" = "401" ]; then if [ "$_code" = "401" ]; then
# we have an invalid access token set to expired # we have an invalid access token set to expired
_saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "0" _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "0"
_err "access denied make sure your Azure settings are correct. See $WIKI"
_err "Access denied. Invalid access token. Make sure your Azure settings are correct. See: $wiki"
return 1 return 1
fi fi
# See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes
# See https://learn.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes
if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then
_request_retry_times="$(_math "$_request_retry_times" + 1)" _request_retry_times="$(_math "$_request_retry_times" + 1)"
_info "REST call error $_code retrying $ep in $_request_retry_times s" _info "REST call error $_code retrying $ep in $_request_retry_times s"
@ -277,14 +315,14 @@ _azure_rest() {
return 0 return 0
} }
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
## Ref: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#request-an-access-token
_azure_getaccess_token() { _azure_getaccess_token() {
managedIdentity=$1 managedIdentity=$1
tenantID=$2 tenantID=$2
clientID=$3 clientID=$3
clientSecret=$4 clientSecret=$4
accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
accesstoken="${AZUREDNS_ACCESSTOKEN:-$(_readaccountconf_mutable AZUREDNS_ACCESSTOKEN)}"
expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}" expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}"
# can we reuse the bearer token? # can we reuse the bearer token?
@ -301,7 +339,7 @@ _azure_getaccess_token() {
_debug "getting new bearer token" _debug "getting new bearer token"
if [ "$managedIdentity" = true ]; then if [ "$managedIdentity" = true ]; then
# https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
# https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
export _H1="Metadata: true" export _H1="Metadata: true"
response="$(_get http://169.254.169.254/metadata/identity/oauth2/token\?api-version=2018-02-01\&resource=https://management.azure.com/)" response="$(_get http://169.254.169.254/metadata/identity/oauth2/token\?api-version=2018-02-01\&resource=https://management.azure.com/)"
response="$(echo "$response" | _normalizeJson)" response="$(echo "$response" | _normalizeJson)"
@ -321,14 +359,14 @@ _azure_getaccess_token() {
fi fi
if [ -z "$accesstoken" ]; then if [ -z "$accesstoken" ]; then
_err "no acccess token received. Check your Azure settings see $WIKI"
_err "No acccess token received. Check your Azure settings. See: $wiki"
return 1 return 1
fi fi
if [ "$_ret" != "0" ]; then if [ "$_ret" != "0" ]; then
_err "error $response" _err "error $response"
return 1 return 1
fi fi
_saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$accesstoken"
_saveaccountconf_mutable AZUREDNS_ACCESSTOKEN "$accesstoken"
_saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on" _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on"
printf "%s" "$accesstoken" printf "%s" "$accesstoken"
return 0 return 0
@ -341,15 +379,18 @@ _get_root() {
i=1 i=1
p=1 p=1
## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list
## returns up to 100 zones in one response therefore handling more results is not not implemented
## Ref: https://learn.microsoft.com/en-us/rest/api/dns/zones/list?view=rest-dns-2018-05-01&tabs=HTTP
## returns up to 100 zones in one response. Handling more results is not implemented
## (ZoneListResult with continuation token for the next page of results) ## (ZoneListResult with continuation token for the next page of results)
## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways
##
## TODO: handle more than 100 results, as per:
## https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-dns-limits
## The new limit is 250 Public DNS zones per subscription, while the old limit was only 100
## ##
_azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken" _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken"
# Find matching domain name in Json response # Find matching domain name in Json response
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug2 "Checking domain: $h" _debug2 "Checking domain: $h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -364,7 +405,7 @@ _get_root() {
#create the record at the domain apex (@) if only the domain name was provided as --domain-alias #create the record at the domain apex (@) if only the domain name was provided as --domain-alias
_sub_domain="@" _sub_domain="@"
else else
_sub_domain=$(echo "$domain" | cut -d . -f 1-$p)
_sub_domain=$(echo "$domain" | cut -d . -f 1-"$p")
fi fi
_domain=$h _domain=$h
return 0 return 0

281
dnsapi/dns_beget.sh

@ -0,0 +1,281 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034
dns_beget_info='Beget.com
Site: Beget.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_beget
Options:
BEGET_User API user
BEGET_Password API password
Issues: github.com/acmesh-official/acme.sh/issues/6200
Author: ARNik arnik@arnik.ru
'
Beget_Api="https://api.beget.com/api"
#################### Public functions ####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_beget_add() {
fulldomain=$1
txtvalue=$2
_debug "dns_beget_add() $fulldomain $txtvalue"
fulldomain=$(echo "$fulldomain" | _lower_case)
Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
if [ -z "$Beget_Username" ] || [ -z "$Beget_Password" ]; then
Beget_Username=""
Beget_Password=""
_err "You must export variables: Beget_Username, and Beget_Password"
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable Beget_Username "$Beget_Username"
_saveaccountconf_mutable Beget_Password "$Beget_Password"
_info "Prepare subdomain."
if ! _prepare_subdomain "$fulldomain"; then
_err "Can't prepare subdomain."
return 1
fi
_info "Get domain records"
data="{\"fqdn\":\"$fulldomain\"}"
res=$(_api_call "$Beget_Api/dns/getData" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't get domain records."
return 1
fi
_info "Add new TXT record"
data="{\"fqdn\":\"$fulldomain\",\"records\":{"
data=${data}$(_parce_records "$res" "A")
data=${data}$(_parce_records "$res" "AAAA")
data=${data}$(_parce_records "$res" "CAA")
data=${data}$(_parce_records "$res" "MX")
data=${data}$(_parce_records "$res" "SRV")
data=${data}$(_parce_records "$res" "TXT")
data=$(echo "$data" | sed 's/,$//')
data=${data}'}}'
str=$(_txt_to_dns_json "$txtvalue")
data=$(_add_record "$data" "TXT" "$str")
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't change domain records."
return 1
fi
return 0
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
dns_beget_rm() {
fulldomain=$1
txtvalue=$2
_debug "dns_beget_rm() $fulldomain $txtvalue"
fulldomain=$(echo "$fulldomain" | _lower_case)
Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
_info "Get current domain records"
data="{\"fqdn\":\"$fulldomain\"}"
res=$(_api_call "$Beget_Api/dns/getData" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't get domain records."
return 1
fi
_info "Remove TXT record"
data="{\"fqdn\":\"$fulldomain\",\"records\":{"
data=${data}$(_parce_records "$res" "A")
data=${data}$(_parce_records "$res" "AAAA")
data=${data}$(_parce_records "$res" "CAA")
data=${data}$(_parce_records "$res" "MX")
data=${data}$(_parce_records "$res" "SRV")
data=${data}$(_parce_records "$res" "TXT")
data=$(echo "$data" | sed 's/,$//')
data=${data}'}}'
str=$(_txt_to_dns_json "$txtvalue")
data=$(_rm_record "$data" "$str")
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't change domain records."
return 1
fi
return 0
}
#################### Private functions below ####################
# Create subdomain if needed
# Usage: _prepare_subdomain [fulldomain]
_prepare_subdomain() {
fulldomain=$1
_info "Detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
if [ -z "$_sub_domain" ]; then
_debug "$fulldomain is a root domain."
return 0
fi
_info "Get subdomain list"
res=$(_api_call "$Beget_Api/domain/getSubdomainList")
if ! _is_api_reply_ok "$res"; then
_err "Can't get subdomain list."
return 1
fi
if _contains "$res" "\"fqdn\":\"$fulldomain\""; then
_debug "Subdomain $fulldomain already exist."
return 0
fi
_info "Subdomain $fulldomain does not exist. Let's create one."
data="{\"subdomain\":\"$_sub_domain\",\"domain_id\":$_domain_id}"
res=$(_api_call "$Beget_Api/domain/addSubdomainVirtual" "$data")
if ! _is_api_reply_ok "$res"; then
_err "Can't create subdomain."
return 1
fi
_debug "Cleanup subdomen records"
data="{\"fqdn\":\"$fulldomain\",\"records\":{}}"
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
if ! _is_api_reply_ok "$res"; then
_debug "Can't cleanup $fulldomain records."
fi
data="{\"fqdn\":\"www.$fulldomain\",\"records\":{}}"
res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
if ! _is_api_reply_ok "$res"; then
_debug "Can't cleanup www.$fulldomain records."
fi
return 0
}
# Usage: _get_root _acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=32436365
_get_root() {
fulldomain=$1
i=1
p=1
_debug "Get domain list"
res=$(_api_call "$Beget_Api/domain/getList")
if ! _is_api_reply_ok "$res"; then
_err "Can't get domain list."
return 1
fi
while true; do
h=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100)
_debug h "$h"
if [ -z "$h" ]; then
return 1
fi
if _contains "$res" "$h"; then
_domain_id=$(echo "$res" | _egrep_o "\"id\":[0-9]*,\"fqdn\":\"$h\"" | cut -d , -f1 | cut -d : -f2)
if [ "$_domain_id" ]; then
if [ "$h" != "$fulldomain" ]; then
_sub_domain=$(echo "$fulldomain" | cut -d . -f 1-"$p")
else
_sub_domain=""
fi
_domain=$h
return 0
fi
return 1
fi
p="$i"
i=$(_math "$i" + 1)
done
return 1
}
# Parce DNS records from json string
# Usage: _parce_records [j_str] [record_name]
_parce_records() {
j_str=$1
record_name=$2
res="\"$record_name\":["
res=${res}$(echo "$j_str" | _egrep_o "\"$record_name\":\[.*" | cut -d '[' -f2 | cut -d ']' -f1)
res=${res}"],"
echo "$res"
}
# Usage: _add_record [data] [record_name] [record_data]
_add_record() {
data=$1
record_name=$2
record_data=$3
echo "$data" | sed "s/\"$record_name\":\[/\"$record_name\":\[$record_data,/" | sed "s/,\]/\]/"
}
# Usage: _rm_record [data] [record_data]
_rm_record() {
data=$1
record_data=$2
echo "$data" | sed "s/$record_data//g" | sed "s/,\+/,/g" |
sed "s/{,/{/g" | sed "s/,}/}/g" |
sed "s/\[,/\[/g" | sed "s/,\]/\]/g"
}
_txt_to_dns_json() {
echo "{\"ttl\":600,\"txtdata\":\"$1\"}"
}
# Usage: _api_call [api_url] [input_data]
_api_call() {
api_url="$1"
input_data="$2"
_debug "_api_call $api_url"
_debug "Request: $input_data"
# res=$(curl -s -L -D ./http.header \
# "$api_url" \
# --data-urlencode login=$Beget_Username \
# --data-urlencode passwd=$Beget_Password \
# --data-urlencode input_format=json \
# --data-urlencode output_format=json \
# --data-urlencode "input_data=$input_data")
url="$api_url?login=$Beget_Username&passwd=$Beget_Password&input_format=json&output_format=json"
if [ -n "$input_data" ]; then
url=${url}"&input_data="
url=${url}$(echo "$input_data" | _url_encode)
fi
res=$(_get "$url")
_debug "Reply: $res"
echo "$res"
}
# Usage: _is_api_reply_ok [api_reply]
_is_api_reply_ok() {
_contains "$1" '^{"status":"success","answer":{"status":"success","result":.*}}$'
}

21
dnsapi/dns_bookmyname.sh

@ -1,18 +1,17 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_bookmyname_info='BookMyName.com
Site: BookMyName.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bookmyname
Options:
BOOKMYNAME_USERNAME Username
BOOKMYNAME_PASSWORD Password
Issues: github.com/acmesh-official/acme.sh/issues/3209
Author: Neilpang
'
#Here is a sample custom api script.
#This file name is "dns_bookmyname.sh"
#So, here must be a method dns_bookmyname_add()
#Which will be called by acme.sh to add the txt record to your api system.
#returns 0 means success, otherwise error.
#
#Author: Neilpang
#Report Bugs here: https://github.com/acmesh-official/acme.sh
#
######## Public functions ##################### ######## Public functions #####################
# Please Read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
# BookMyName urls: # BookMyName urls:
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=add&value="XXXXXXXX"' # https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=add&value="XXXXXXXX"'
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=remove&value="XXXXXXXX"' # https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=remove&value="XXXXXXXX"'

29
dnsapi/dns_bunny.sh

@ -1,16 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
## Will be called by acme.sh to add the TXT record via the Bunny DNS API.
## returns 0 means success, otherwise error.
## Author: nosilver4u <nosilver4u at ewww.io>
## GitHub: https://github.com/nosilver4u/acme.sh
##
## Environment Variables Required:
##
## BUNNY_API_KEY="75310dc4-ca77-9ac3-9a19-f6355db573b49ce92ae1-2655-3ebd-61ac-3a3ae34834cc"
##
# shellcheck disable=SC2034
dns_bunny_info='Bunny.net
Site: Bunny.net/dns/
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bunny
Options:
BUNNY_API_KEY API Key
Issues: github.com/acmesh-official/acme.sh/issues/4296
Author: <nosilver4u@ewww.io>
'
##################### Public functions ##################### ##################### Public functions #####################
@ -199,7 +196,7 @@ _get_base_domain() {
_debug2 domain_list "$domain_list" _debug2 domain_list "$domain_list"
i=1 i=1
while [ $i -gt 0 ]; do
while [ "$i" -gt 0 ]; do
## get next longest domain ## get next longest domain
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
## check we got something back from our cut (or are we at the end) ## check we got something back from our cut (or are we at the end)
@ -211,7 +208,7 @@ _get_base_domain() {
## check if it exists ## check if it exists
if [ -n "$found" ]; then if [ -n "$found" ]; then
## exists - exit loop returning the parts ## exists - exit loop returning the parts
sub_point=$(_math $i - 1)
sub_point=$(_math "$i" - 1)
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
_domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")" _domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
_debug _domain_id "$_domain_id" _debug _domain_id "$_domain_id"
@ -221,11 +218,11 @@ _get_base_domain() {
return 0 return 0
fi fi
## increment cut point $i ## increment cut point $i
i=$(_math $i + 1)
i=$(_math "$i" + 1)
done done
if [ -z "$found" ]; then if [ -z "$found" ]; then
page=$(_math $page + 1)
page=$(_math "$page" + 1)
nextpage="https://api.bunny.net/dnszone?page=$page" nextpage="https://api.bunny.net/dnszone?page=$page"
## Find the next page if we don't have a match. ## Find the next page if we don't have a match.
hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")" hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")"

25
dnsapi/dns_cf.sh

@ -1,13 +1,16 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
#
#CF_Email="xxxx@sss.com"
#CF_Token="xxxx"
#CF_Account_ID="xxxx"
#CF_Zone_ID="xxxx"
# shellcheck disable=SC2034
dns_cf_info='CloudFlare
Site: CloudFlare.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf
Options:
CF_Key API Key
CF_Email Your account email
OptionsAlt:
CF_Token API Token
CF_Account_ID Account ID
CF_Zone_ID Zone ID. Optional.
'
CF_Api="https://api.cloudflare.com/client/v4" CF_Api="https://api.cloudflare.com/client/v4"
@ -183,7 +186,7 @@ _get_root() {
fi fi
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -203,7 +206,7 @@ _get_root() {
if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; then if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; then
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ") _domain_id=$(echo "$response" | _egrep_o "\[.\"id\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ")
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

17
dnsapi/dns_clouddns.sh

@ -1,10 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Author: Radek Sprta <sprta@vshosting.cz>
#CLOUDDNS_EMAIL=XXXXX
#CLOUDDNS_PASSWORD="YYYYYYYYY"
#CLOUDDNS_CLIENT_ID=XXXXX
# shellcheck disable=SC2034
dns_clouddns_info='vshosting.cz CloudDNS
Site: github.com/vshosting/clouddns
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_clouddns
Options:
CLOUDDNS_EMAIL Email
CLOUDDNS_PASSWORD Password
CLOUDDNS_CLIENT_ID Client ID
Issues: github.com/acmesh-official/acme.sh/issues/2699
Author: Radek Sprta <sprta@vshosting.cz>
'
CLOUDDNS_API='https://admin.vshosting.cloud/clouddns' CLOUDDNS_API='https://admin.vshosting.cloud/clouddns'
CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login' CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'

19
dnsapi/dns_cloudns.sh

@ -1,12 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_cloudns_info='ClouDNS.net
Site: ClouDNS.net
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cloudns
Options:
CLOUDNS_AUTH_ID Regular auth ID
CLOUDNS_SUB_AUTH_ID Sub auth ID
CLOUDNS_AUTH_PASSWORD Auth Password
Author: Boyan Peychev <boyan@cloudns.net>
'
# Author: Boyan Peychev <boyan at cloudns dot net>
# Repository: https://github.com/ClouDNS/acme.sh/
# Editor: I Komang Suryadana
#CLOUDNS_AUTH_ID=XXXXX
#CLOUDNS_SUB_AUTH_ID=XXXXX
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
CLOUDNS_API="https://api.cloudns.net" CLOUDNS_API="https://api.cloudns.net"
DOMAIN_TYPE= DOMAIN_TYPE=
DOMAIN_MASTER= DOMAIN_MASTER=
@ -161,7 +164,7 @@ _dns_cloudns_get_zone_info() {
_dns_cloudns_get_zone_name() { _dns_cloudns_get_zone_name() {
i=2 i=2
while true; do while true; do
zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100)
zoneForCheck=$(printf "%s" "$1" | cut -d . -f "$i"-100)
if [ -z "$zoneForCheck" ]; then if [ -z "$zoneForCheck" ]; then
return 1 return 1

17
dnsapi/dns_cn.sh

@ -1,7 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/).
# created by 5ll and francis
# shellcheck disable=SC2034
dns_cn_info='Core-Networks.de
Site: beta.api.Core-Networks.de/doc/
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cn
Options:
CN_User User
CN_Password Password
Issues: github.com/acmesh-official/acme.sh/issues/2142
Author: 5ll, francis
'
CN_API="https://beta.api.core-networks.de" CN_API="https://beta.api.core-networks.de"
@ -124,7 +131,7 @@ _cn_get_root() {
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
_debug _H1 "${_H1}" _debug _H1 "${_H1}"
@ -142,7 +149,7 @@ _cn_get_root() {
fi fi
if _contains "$_cn_zonelist" "\"name\":\"$h\"" >/dev/null; then if _contains "$_cn_zonelist" "\"name\":\"$h\"" >/dev/null; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
else else

15
dnsapi/dns_conoha.sh

@ -1,4 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_conoha_info='ConoHa.jp
Domains: ConoHa.io
Site: ConoHa.jp
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_conoha
Options:
CONOHA_Username Username
CONOHA_Password Password
CONOHA_TenantId TenantId
CONOHA_IdentityServiceApi Identity Service API. E.g. "https://identity.xxxx.conoha.io/v2.0"
'
CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\." CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\."
@ -226,7 +237,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100).
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100).
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -240,7 +251,7 @@ _get_root() {
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

18
dnsapi/dns_constellix.sh

@ -1,10 +1,16 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Author: Wout Decre <wout@canodus.be>
# shellcheck disable=SC2034
dns_constellix_info='Constellix.com
Site: Constellix.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_constellix
Options:
CONSTELLIX_Key API Key
CONSTELLIX_Secret API Secret
Issues: github.com/acmesh-official/acme.sh/issues/2724
Author: Wout Decre <wout@canodus.be>
'
CONSTELLIX_Api="https://api.dns.constellix.com/v1" CONSTELLIX_Api="https://api.dns.constellix.com/v1"
#CONSTELLIX_Key="XXX"
#CONSTELLIX_Secret="XXX"
######## Public functions ##################### ######## Public functions #####################
@ -116,7 +122,7 @@ _get_root() {
p=1 p=1
_debug "Detecting root zone" _debug "Detecting root zone"
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then if [ -z "$h" ]; then
return 1 return 1
fi fi
@ -128,7 +134,7 @@ _get_root() {
if _contains "$response" "\"name\":\"$h\""; then if _contains "$response" "\"name\":\"$h\""; then
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]*" | cut -d ':' -f 2) _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]*" | cut -d ':' -f 2)
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-"$p")
_domain="$h" _domain="$h"
_debug _domain_id "$_domain_id" _debug _domain_id "$_domain_id"

26
dnsapi/dns_cpanel.sh

@ -1,18 +1,18 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#Author: Bjarne Saltbaek
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/3732
#
#
# shellcheck disable=SC2034
dns_cpanel_info='cPanel Server API
Manage DNS via cPanel Dashboard.
Site: cPanel.net
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_cpanel
Options:
cPanel_Username Username
cPanel_Apitoken API Token
cPanel_Hostname Server URL. E.g. "https://hostname:port"
Issues: github.com/acmesh-official/acme.sh/issues/3732
Author: Bjarne Saltbaek
'
######## Public functions ##################### ######## Public functions #####################
#
# Export CPANEL username,api token and hostname in the following variables
#
# cPanel_Username=username
# cPanel_Apitoken=apitoken
# cPanel_Hostname=hostname
#
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record # Used to add txt record
dns_cpanel_add() { dns_cpanel_add() {

18
dnsapi/dns_curanet.sh

@ -1,9 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Script to use with curanet.dk, scannet.dk, wannafind.dk, dandomain.dk DNS management.
#Requires api credentials with scope: dns
#Author: Peter L. Hansen <peter@r12.dk>
#Version 1.0
# shellcheck disable=SC2034
dns_curanet_info='Curanet.dk
Domains: scannet.dk wannafind.dk dandomain.dk
Site: Curanet.dk
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_curanet
Options:
CURANET_AUTHCLIENTID Auth ClientID. Requires scope dns
CURANET_AUTHSECRET Auth Secret
Issues: github.com/acmesh-official/acme.sh/issues/3933
Author: Peter L. Hansen <peter@r12.dk>
'
CURANET_REST_URL="https://api.curanet.dk/dns/v1/Domains" CURANET_REST_URL="https://api.curanet.dk/dns/v1/Domains"
CURANET_AUTH_URL="https://apiauth.dk.team.blue/auth/realms/Curanet/protocol/openid-connect/token" CURANET_AUTH_URL="https://apiauth.dk.team.blue/auth/realms/Curanet/protocol/openid-connect/token"
@ -136,7 +142,7 @@ _get_root() {
i=1 i=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid

47
dnsapi/dns_cyon.sh

@ -1,21 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
########
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/acmesh-official/acme.sh)
#
# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com
#
# Dependencies:
# -------------
# - oathtool (When using 2 Factor Authentication)
#
# Issues:
# -------
# Any issues / questions / suggestions can be posted here:
# https://github.com/noplanman/cyon-api/issues
#
# Author: Armando Lüscher <armando@noplanman.ch>
########
# shellcheck disable=SC2034
dns_cyon_info='cyon.ch
Site: cyon.ch
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cyon
Options:
CY_Username Username
CY_Password API Token
CY_OTP_Secret OTP token. Only required if using 2FA
Issues: github.com/noplanman/cyon-api/issues
Author: Armando Lüscher <armando@noplanman.ch>
'
dns_cyon_add() { dns_cyon_add() {
_cyon_load_credentials && _cyon_load_credentials &&
@ -221,10 +215,8 @@ _cyon_change_domain_env() {
if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi
domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)"
# Bail if domain environment change fails. # Bail if domain environment change fails.
if [ "${domain_env_success}" != "true" ]; then
if [ "$(printf "%s" "${domain_env_response}" | _cyon_get_environment_change_status)" != "true" ]; then
_err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)" _err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)"
_err "" _err ""
return 1 return 1
@ -238,7 +230,7 @@ _cyon_add_txt() {
_info " - Adding DNS TXT entry..." _info " - Adding DNS TXT entry..."
add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async" add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async"
add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}"
add_txt_data="name=${fulldomain_idn}.&ttl=900&type=TXT&dnscontent=${txtvalue}"
add_txt_response="$(_post "$add_txt_data" "$add_txt_url")" add_txt_response="$(_post "$add_txt_data" "$add_txt_url")"
_debug add_txt_response "${add_txt_response}" _debug add_txt_response "${add_txt_response}"
@ -247,9 +239,10 @@ _cyon_add_txt() {
add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)" add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)"
add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)" add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)"
add_txt_validation="$(printf "%s" "${add_txt_response}" | _cyon_get_validation_status)"
# Bail if adding TXT entry fails. # Bail if adding TXT entry fails.
if [ "${add_txt_status}" != "true" ]; then
if [ "${add_txt_status}" != "true" ] || [ "${add_txt_validation}" != "true" ]; then
_err " ${add_txt_message}" _err " ${add_txt_message}"
_err "" _err ""
return 1 return 1
@ -311,13 +304,21 @@ _cyon_get_response_message() {
} }
_cyon_get_response_status() { _cyon_get_response_status() {
_egrep_o '"status":\w*' | cut -d : -f 2
_egrep_o '"status":[a-zA-z0-9]*' | cut -d : -f 2
}
_cyon_get_validation_status() {
_egrep_o '"valid":[a-zA-z0-9]*' | cut -d : -f 2
} }
_cyon_get_response_success() { _cyon_get_response_success() {
_egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"'
} }
_cyon_get_environment_change_status() {
_egrep_o '"authenticated":[a-zA-z0-9]*' | cut -d : -f 2
}
_cyon_check_if_2fa_missed() { _cyon_check_if_2fa_missed() {
# Did we miss the 2FA? # Did we miss the 2FA?
if test "${1#*multi_factor_form}" != "${1}"; then if test "${1#*multi_factor_form}" != "${1}"; then

41
dnsapi/dns_da.sh

@ -1,31 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
# vim: et ts=2 sw=2
#
# DirectAdmin 1.41.0 API
# The DirectAdmin interface has it's own Let's encrypt functionality, but this
# script can be used to generate certificates for names which are not hosted on
# DirectAdmin
#
# User must provide login data and URL to DirectAdmin incl. port.
# You can create login key, by using the Login Keys function
# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to
# - CMD_API_DNS_CONTROL
# - CMD_API_SHOW_DOMAINS
#
# See also https://www.directadmin.com/api.php and
# https://www.directadmin.com/features.php?id=1298
#
# Report bugs to https://github.com/TigerP/acme.sh/issues
#
# Values to export:
# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443"
# export DA_Api_Insecure=1
#
# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is
# whether ssl cert is checked for validity (0) or whether it is just accepted
# (1)
#
# shellcheck disable=SC2034
dns_da_info='DirectAdmin Server API
Site: DirectAdmin.com/api.php
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_da
Options:
DA_Api API Server URL. E.g. "https://remoteUser:remotePassword@da.domain.tld:8443"
DA_Api_Insecure Insecure TLS. 0: check for cert validity, 1: always accept
Issues: github.com/TigerP/acme.sh/issues
'
######## Public functions ##################### ######## Public functions #####################
# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" # Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
@ -78,7 +61,7 @@ _get_root() {
# response will contain "list[]=example.com&list[]=example.org" # response will contain "list[]=example.com&list[]=example.org"
_da_api CMD_API_SHOW_DOMAINS "" "${domain}" _da_api CMD_API_SHOW_DOMAINS "" "${domain}"
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
# not valid # not valid
@ -86,7 +69,7 @@ _get_root() {
return 1 return 1
fi fi
if _contains "$response" "$h" >/dev/null; then if _contains "$response" "$h" >/dev/null; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

21
dnsapi/dns_ddnss.sh

@ -1,16 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Created by RaidenII, to use DuckDNS's API to add/remove text records
#modified by helbgd @ 03/13/2018 to support ddnss.de
#modified by mod242 @ 04/24/2018 to support different ddnss domains
#Please note: the Wildcard Feature must be turned on for the Host record
#and the checkbox for TXT needs to be enabled
# Pass credentials before "acme.sh --issue --dns dns_ddnss ..."
# --
# export DDNSS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
# --
#
# shellcheck disable=SC2034
dns_ddnss_info='DDNSS.de
Site: DDNSS.de
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ddnss
Options:
DDNSS_Token API Token
Issues: github.com/acmesh-official/acme.sh/issues/2230
Author: RaidenII, helbgd, mod242
'
DDNSS_DNS_API="https://ddnss.de/upd.php" DDNSS_DNS_API="https://ddnss.de/upd.php"

20
dnsapi/dns_desec.sh

@ -1,11 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
# deSEC.io Domain API
#
# Author: Zheng Qian
#
# deSEC API doc
# https://desec.readthedocs.io/en/latest/
# shellcheck disable=SC2034
dns_desec_info='deSEC.io
Site: desec.readthedocs.io/en/latest/
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_desec
Options:
DDNSS_Token API Token
Issues: github.com/acmesh-official/acme.sh/issues/2180
Author: Zheng Qian
'
REST_API="https://desec.io/api/v1/domains" REST_API="https://desec.io/api/v1/domains"
@ -174,7 +176,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -186,7 +188,7 @@ _get_root() {
fi fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

25
dnsapi/dns_df.sh

@ -1,18 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
########################################################################
# https://dyndnsfree.de hook script for acme.sh
#
# Environment variables:
#
# - $DF_user (your dyndnsfree.de username)
# - $DF_password (your dyndnsfree.de password)
#
# Author: Thilo Gass <thilo.gass@gmail.com>
# Git repo: https://github.com/ThiloGa/acme.sh
#-- dns_df_add() - Add TXT record --------------------------------------
# Usage: dns_df_add _acme-challenge.subdomain.domain.com "XyZ123..."
# shellcheck disable=SC2034
dns_df_info='DynDnsFree.de
Domains: dynup.de
Site: DynDnsFree.de
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_df
Options:
DF_user Username
DF_password Password
Issues: github.com/acmesh-official/acme.sh/issues/2897
Author: Thilo Gass <thilo.gass@gmail.com>
'
dyndnsfree_api="https://dynup.de/acme.php" dyndnsfree_api="https://dynup.de/acme.php"

26
dnsapi/dns_dgon.sh

@ -1,16 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
## Will be called by acme.sh to add the txt record to your api system.
## returns 0 means success, otherwise error.
## Author: thewer <github at thewer.com>
## GitHub: https://github.com/gitwer/acme.sh
##
## Environment Variables Required:
##
## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc"
##
# shellcheck disable=SC2034
dns_dgon_info='DigitalOcean.com
Site: DigitalOcean.com/help/api/
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dgon
Options:
DO_API_KEY API Key
Author: <github@thewer.com>
'
##################### Public functions ##################### ##################### Public functions #####################
@ -207,7 +203,7 @@ _get_base_domain() {
_debug2 domain_list "$domain_list" _debug2 domain_list "$domain_list"
i=1 i=1
while [ $i -gt 0 ]; do
while [ "$i" -gt 0 ]; do
## get next longest domain ## get next longest domain
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
## check we got something back from our cut (or are we at the end) ## check we got something back from our cut (or are we at the end)
@ -219,14 +215,14 @@ _get_base_domain() {
## check if it exists ## check if it exists
if [ -n "$found" ]; then if [ -n "$found" ]; then
## exists - exit loop returning the parts ## exists - exit loop returning the parts
sub_point=$(_math $i - 1)
sub_point=$(_math "$i" - 1)
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
_debug _domain "$_domain" _debug _domain "$_domain"
_debug _sub_domain "$_sub_domain" _debug _sub_domain "$_sub_domain"
return 0 return 0
fi fi
## increment cut point $i ## increment cut point $i
i=$(_math $i + 1)
i=$(_math "$i" + 1)
done done
if [ -z "$found" ]; then if [ -z "$found" ]; then

21
dnsapi/dns_dnsexit.sh

@ -1,13 +1,16 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_dnsexit_info='DNSExit.com
Site: DNSExit.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsexit
Options:
DNSEXIT_API_KEY API Key
DNSEXIT_AUTH_USER Username
DNSEXIT_AUTH_PASS Password
Issues: github.com/acmesh-official/acme.sh/issues/4719
Author: Samuel Jimenez
'
#use dns-01 at DNSExit.com
#Author: Samuel Jimenez
#Report Bugs here: https://github.com/acmesh-official/acme.sh
#DNSEXIT_API_KEY=ABCDEFGHIJ0123456789abcdefghij
#DNSEXIT_AUTH_USER=login@email.address
#DNSEXIT_AUTH_PASS=aStrongPassword
DNSEXIT_API_URL="https://api.dnsexit.com/dns/" DNSEXIT_API_URL="https://api.dnsexit.com/dns/"
DNSEXIT_HOSTS_URL="https://update.dnsexit.com/ipupdate/hosts.jsp" DNSEXIT_HOSTS_URL="https://update.dnsexit.com/ipupdate/hosts.jsp"
@ -81,7 +84,7 @@ _get_root() {
domain=$1 domain=$1
i=1 i=1
while true; do while true; do
_domain=$(printf "%s" "$domain" | cut -d . -f $i-100)
_domain=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$_domain" _debug h "$_domain"
if [ -z "$_domain" ]; then if [ -z "$_domain" ]; then
return 1 return 1

21
dnsapi/dns_dnshome.sh

@ -1,15 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# dnsHome.de API for acme.sh
#
# This Script adds the necessary TXT record to a Subdomain
#
# Author dnsHome.de (https://github.com/dnsHome-de)
#
# Report Bugs to https://github.com/acmesh-official/acme.sh/issues/3819
#
# export DNSHOME_Subdomain=""
# export DNSHOME_SubdomainPassword=""
# shellcheck disable=SC2034
dns_dnshome_info='dnsHome.de
Site: dnsHome.de
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnshome
Options:
DNSHOME_Subdomain Subdomain
DNSHOME_SubdomainPassword Subdomain Password
Issues: github.com/acmesh-official/acme.sh/issues/3819
Author: dnsHome.de https://github.com/dnsHome-de
'
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" # Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record # Used to add txt record

20
dnsapi/dns_dnsimple.sh

@ -1,12 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# DNSimple domain api
# https://github.com/pho3nixf1re/acme.sh/issues
#
# This is your oauth token which can be acquired on the account page. Please
# note that this must be an _account_ token and not a _user_ token.
# https://dnsimple.com/a/<your account id>/account/access_tokens
# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
# shellcheck disable=SC2034
dns_dnsimple_info='DNSimple.com
Site: DNSimple.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dnsimple
Options:
DNSimple_OAUTH_TOKEN OAuth Token
Issues: github.com/pho3nixf1re/acme.sh/issues
'
DNSimple_API="https://api.dnsimple.com/v2" DNSimple_API="https://api.dnsimple.com/v2"
@ -92,7 +92,7 @@ _get_root() {
i=2 i=2
previous=1 previous=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then if [ -z "$h" ]; then
# not valid # not valid
return 1 return 1
@ -105,7 +105,7 @@ _get_root() {
if _contains "$response" 'not found'; then if _contains "$response" 'not found'; then
_debug "$h not found" _debug "$h not found"
else else
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$previous")
_domain="$h" _domain="$h"
_debug _domain "$_domain" _debug _domain "$_domain"

17
dnsapi/dns_dnsservices.sh

@ -1,12 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_dnsservices_info='DNS.Services
Site: DNS.Services
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsservices
Options:
DnsServices_Username Username
DnsServices_Password Password
Issues: github.com/acmesh-official/acme.sh/issues/4152
Author: Bjarke Bruun <bbruun@gmail.com>
'
#This file name is "dns_dnsservices.sh"
#Script for Danish DNS registra and DNS hosting provider https://dns.services
#Author: Bjarke Bruun <bbruun@gmail.com>
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/4152
# Global variable to connect to the DNS.Services API
DNSServices_API=https://dns.services/api DNSServices_API=https://dns.services/api
######## Public functions ##################### ######## Public functions #####################

22
dnsapi/dns_doapi.sh

@ -1,14 +1,16 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Official Let's Encrypt API for do.de / Domain-Offensive
#
# This is different from the dns_do adapter, because dns_do is only usable for enterprise customers
# This API is also available to private customers/individuals
#
# Provide the required LetsEncrypt token like this:
# DO_LETOKEN="FmD408PdqT1E269gUK57"
DO_API="https://www.do.de/api/letsencrypt"
# shellcheck disable=SC2034
dns_doapi_info='Domain-Offensive do.de
Official LetsEncrypt API for do.de / Domain-Offensive.
This API is also available to private customers/individuals.
Site: do.de
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_doapi
Options:
DO_LETOKEN LetsEncrypt Token
Issues: github.com/acmesh-official/acme.sh/issues/2057
'
DO_API="https://my.do.de/api/letsencrypt"
######## Public functions ##################### ######## Public functions #####################

13
dnsapi/dns_domeneshop.sh

@ -1,4 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_domeneshop_info='DomeneShop.no
Site: DomeneShop.no
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_domeneshop
Options:
DOMENESHOP_Token Token
DOMENESHOP_Secret Secret
Issues: github.com/acmesh-official/acme.sh/issues/2457
'
DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0" DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0"
@ -84,7 +93,7 @@ _get_domainid() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug "h" "$h" _debug "h" "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -93,7 +102,7 @@ _get_domainid() {
if _contains "$response" "\"$h\"" >/dev/null; then if _contains "$response" "\"$h\"" >/dev/null; then
# We have found the domain name. # We have found the domain name.
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
_domainid=$(printf "%s" "$response" | _egrep_o "[^{]*\"domain\":\"$_domain\"[^}]*" | _egrep_o "\"id\":[0-9]+" | cut -d : -f 2) _domainid=$(printf "%s" "$response" | _egrep_o "[^{]*\"domain\":\"$_domain\"[^}]*" | _egrep_o "\"id\":[0-9]+" | cut -d : -f 2)
return 0 return 0

18
dnsapi/dns_dp.sh

@ -1,10 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Dnspod.cn Domain api
#
#DP_Id="1234"
#
#DP_Key="sADDsdasdgdsf"
# shellcheck disable=SC2034
dns_dp_info='DNSPod.cn
Site: DNSPod.cn
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dp
Options:
DP_Id Id
DP_Key Key
'
REST_API="https://dnsapi.cn" REST_API="https://dnsapi.cn"
@ -107,7 +109,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
return 1 return 1
@ -121,7 +123,7 @@ _get_root() {
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
_debug _domain_id "$_domain_id" _debug _domain_id "$_domain_id"
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_debug _sub_domain "$_sub_domain" _debug _sub_domain "$_sub_domain"
_domain="$h" _domain="$h"
_debug _domain "$_domain" _debug _domain "$_domain"

18
dnsapi/dns_dpi.sh

@ -1,10 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Dnspod.com Domain api
#
#DPI_Id="1234"
#
#DPI_Key="sADDsdasdgdsf"
# shellcheck disable=SC2034
dns_dpi_info='DNSPod.com
Site: DNSPod.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dpi
Options:
DPI_Id Id
DPI_Key Key
'
REST_API="https://api.dnspod.com" REST_API="https://api.dnspod.com"
@ -107,7 +109,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
return 1 return 1
@ -121,7 +123,7 @@ _get_root() {
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
_debug _domain_id "$_domain_id" _debug _domain_id "$_domain_id"
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_debug _sub_domain "$_sub_domain" _debug _sub_domain "$_sub_domain"
_domain="$h" _domain="$h"
_debug _domain "$_domain" _debug _domain "$_domain"

14
dnsapi/dns_dreamhost.sh

@ -1,10 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_dreamhost_info='DreamHost.com
Site: DreamHost.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dreamhost
Options:
DH_API_KEY API Key
Issues: github.com/RhinoLance/acme.sh
Author: RhinoLance
'
#Author: RhinoLance
#Report Bugs here: https://github.com/RhinoLance/acme.sh
#
#define the api endpoint
DH_API_ENDPOINT="https://api.dreamhost.com/" DH_API_ENDPOINT="https://api.dreamhost.com/"
querystring="" querystring=""

18
dnsapi/dns_duckdns.sh

@ -1,14 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Created by RaidenII, to use DuckDNS's API to add/remove text records
#06/27/2017
# Pass credentials before "acme.sh --issue --dns dns_duckdns ..."
# --
# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
# --
#
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh
# shellcheck disable=SC2034
dns_duckdns_info='DuckDNS.org
Site: www.DuckDNS.org
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns
Options:
DuckDNS_Token API Token
Author: RaidenII
'
DuckDNS_API="https://www.duckdns.org/update" DuckDNS_API="https://www.duckdns.org/update"

16
dnsapi/dns_durabledns.sh

@ -1,7 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#DD_API_User="xxxxx"
#DD_API_Key="xxxxxx"
# shellcheck disable=SC2034
dns_durabledns_info='DurableDNS.com
Site: DurableDNS.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_durabledns
Options:
DD_API_User API User
DD_API_Key API Key
Issues: github.com/acmesh-official/acme.sh/issues/2281
'
_DD_BASE="https://durabledns.com/services/dns" _DD_BASE="https://durabledns.com/services/dns"
@ -104,7 +110,7 @@ _get_root() {
i=1 i=1
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -112,7 +118,7 @@ _get_root() {
fi fi
if _contains "$response" ">$h.</origin>"; then if _contains "$response" ">$h.</origin>"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

25
dnsapi/dns_dyn.sh

@ -1,10 +1,16 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
# Dyn.com Domain API
#
# Author: Gerd Naschenweng
# https://github.com/magicdude4eva
#
# shellcheck disable=SC2034
dns_dyn_info='Dyn.com
Domains: dynect.net
Site: Dyn.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dyn
Options:
DYN_Customer Customer
DYN_Username API Username
DYN_Password Secret
Author: Gerd Naschenweng <https://github.com/magicdude4eva>
'
# Dyn Managed DNS API # Dyn Managed DNS API
# https://help.dyn.com/dns-api-knowledge-base/ # https://help.dyn.com/dns-api-knowledge-base/
# #
@ -20,13 +26,6 @@
# ZoneRemoveNode # ZoneRemoveNode
# ZonePublish # ZonePublish
# -- # --
#
# Pass credentials before "acme.sh --issue --dns dns_dyn ..."
# --
# export DYN_Customer="customer"
# export DYN_Username="apiuser"
# export DYN_Password="secret"
# --
DYN_API="https://api.dynect.net/REST" DYN_API="https://api.dynect.net/REST"

25
dnsapi/dns_dynu.sh

@ -1,20 +1,21 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_dynu_info='Dynu.com
Site: Dynu.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dynu
Options:
Dynu_ClientId Client ID
Dynu_Secret Secret
Issues: github.com/shar0119/acme.sh
Author: Dynu Systems Inc
'
#Client ID
#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d"
#
#Secret
#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9"
#
#Token #Token
Dynu_Token="" Dynu_Token=""
# #
#Endpoint #Endpoint
Dynu_EndPoint="https://api.dynu.com/v2" Dynu_EndPoint="https://api.dynu.com/v2"
#
#Author: Dynu Systems, Inc.
#Report Bugs here: https://github.com/shar0119/acme.sh
#
######## Public functions ##################### ######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
@ -125,7 +126,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -139,7 +140,7 @@ _get_root() {
if _contains "$response" "\"domainName\":\"$h\"" >/dev/null; then if _contains "$response" "\"domainName\":\"$h\"" >/dev/null; then
dnsId=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 2 | cut -d : -f 2) dnsId=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 2 | cut -d : -f 2)
_domain_name=$h _domain_name=$h
_node=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_node=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
return 0 return 0
fi fi
p=$i p=$i

28
dnsapi/dns_dynv6.sh

@ -1,16 +1,23 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Author StefanAbl
#Usage specify a private keyfile to use with dynv6 'export KEY="path/to/keyfile"'
#or use the HTTP REST API by by specifying a token 'export DYNV6_TOKEN="value"
#if no keyfile is specified, you will be asked if you want to create one in /home/$USER/.ssh/dynv6 and /home/$USER/.ssh/dynv6.pub
# shellcheck disable=SC2034
dns_dynv6_info='DynV6.com
Site: DynV6.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dynv6
Options:
DYNV6_TOKEN REST API token. Get from https://DynV6.com/keys
OptionsAlt:
KEY Path to SSH private key file. E.g. "/root/.ssh/dynv6"
Issues: github.com/acmesh-official/acme.sh/issues/2702
Author: StefanAbl
'
dynv6_api="https://dynv6.com/api/v2" dynv6_api="https://dynv6.com/api/v2"
######## Public functions ##################### ######## Public functions #####################
# Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide # Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
#Usage: dns_dynv6_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" #Usage: dns_dynv6_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_dynv6_add() { dns_dynv6_add() {
fulldomain=$1
txtvalue=$2
fulldomain="$(echo "$1" | _lower_case)"
txtvalue="$2"
_info "Using dynv6 api" _info "Using dynv6 api"
_debug fulldomain "$fulldomain" _debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue" _debug txtvalue "$txtvalue"
@ -36,15 +43,14 @@ dns_dynv6_add() {
_err "Something went wrong! it does not seem like the record was added successfully" _err "Something went wrong! it does not seem like the record was added successfully"
return 1 return 1
fi fi
return 1
fi fi
return 1
} }
#Usage: fulldomain txtvalue #Usage: fulldomain txtvalue
#Remove the txt record after validation. #Remove the txt record after validation.
dns_dynv6_rm() { dns_dynv6_rm() {
fulldomain=$1
txtvalue=$2
fulldomain="$(echo "$1" | _lower_case)"
txtvalue="$2"
_info "Using dynv6 API" _info "Using dynv6 API"
_debug fulldomain "$fulldomain" _debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue" _debug txtvalue "$txtvalue"
@ -199,7 +205,7 @@ _get_zone_id() {
return 1 return 1
fi fi
zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep id | tr -d '"')"
zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep '"id":' | tr -d '"')"
_zone_id="${zone_id#id:}" _zone_id="${zone_id#id:}"
_debug "zone id: $_zone_id" _debug "zone id: $_zone_id"
} }

23
dnsapi/dns_easydns.sh

@ -1,14 +1,17 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_easydns_info='easyDNS.net
Site: easyDNS.net
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_easydns
Options:
EASYDNS_Token API Token
EASYDNS_Key API Key
Issues: github.com/acmesh-official/acme.sh/issues/2647
Author: Neilpang, wurzelpanzer <wurzelpanzer@maximolider.net>
'
#######################################################
#
# easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh
#
# API Documentation: https://sandbox.rest.easydns.net:3001/ # API Documentation: https://sandbox.rest.easydns.net:3001/
#
# Author: wurzelpanzer [wurzelpanzer@maximolider.net]
# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647
#
#################### Public functions ################# #################### Public functions #################
#EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx" #EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
@ -118,7 +121,7 @@ _get_root() {
i=1 i=1
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -130,7 +133,7 @@ _get_root() {
fi fi
if _contains "$response" "\"status\":200"; then if _contains "$response" "\"status\":200"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

163
dnsapi/dns_edgecenter.sh

@ -0,0 +1,163 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034
# EdgeCenter DNS API integration for acme.sh
# Author: Konstantin Ruchev <konstantin.ruchev@edgecenter.ru>
dns_edgecenter_info='edgecenter DNS API
Site: https://edgecenter.ru
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_edgecenter
Options:
EDGECENTER_API_KEY auth APIKey'
EDGECENTER_API="https://api.edgecenter.ru"
DOMAIN_TYPE=
DOMAIN_MASTER=
######## Public functions #####################
#Usage: dns_edgecenter_add _acme-challenge.www.domain.com "TXT_RECORD_VALUE"
dns_edgecenter_add() {
fulldomain="$1"
txtvalue="$2"
_info "Using EdgeCenter DNS API"
if ! _dns_edgecenter_init_check; then
return 1
fi
_debug "Detecting root zone for $fulldomain"
if ! _get_root "$fulldomain"; then
return 1
fi
subdomain="${fulldomain%."$_zone"}"
subdomain=${subdomain%.}
_debug "Zone: $_zone"
_debug "Subdomain: $subdomain"
_debug "TXT value: $txtvalue"
payload='{"resource_records": [ { "content": ["'"$txtvalue"'"] } ], "ttl": 60 }'
_dns_edgecenter_http_api_call "post" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" "$payload"
if _contains "$response" '"error":"rrset is already exists"'; then
_debug "RRSet exists, merging values"
_dns_edgecenter_http_api_call "get" "dns/v2/zones/$_zone/$subdomain.$_zone/txt"
current="$response"
newlist=""
for v in $(echo "$current" | sed -n 's/.*"content":\["\([^"]*\)"\].*/\1/p'); do
newlist="$newlist {\"content\":[\"$v\"]},"
done
newlist="$newlist{\"content\":[\"$txtvalue\"]}"
putdata="{\"resource_records\":[${newlist}]}
"
_dns_edgecenter_http_api_call "put" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" "$putdata"
_info "Updated existing RRSet with new TXT value."
return 0
fi
if _contains "$response" '"exception":'; then
_err "Record cannot be added."
return 1
fi
_info "TXT record added successfully."
return 0
}
#Usage: dns_edgecenter_rm _acme-challenge.www.domain.com "TXT_RECORD_VALUE"
dns_edgecenter_rm() {
fulldomain="$1"
txtvalue="$2"
_info "Removing TXT record for $fulldomain"
if ! _dns_edgecenter_init_check; then
return 1
fi
if ! _get_root "$fulldomain"; then
return 1
fi
subdomain="${fulldomain%."$_zone"}"
subdomain=${subdomain%.}
_dns_edgecenter_http_api_call "delete" "dns/v2/zones/$_zone/$subdomain.$_zone/txt"
if [ -z "$response" ]; then
_info "TXT record deleted successfully."
else
_info "TXT record may not have been deleted: $response"
fi
return 0
}
#################### Private functions below ##################################
_dns_edgecenter_init_check() {
EDGECENTER_API_KEY="${EDGECENTER_API_KEY:-$(_readaccountconf_mutable EDGECENTER_API_KEY)}"
if [ -z "$EDGECENTER_API_KEY" ]; then
_err "EDGECENTER_API_KEY was not exported."
return 1
fi
_saveaccountconf_mutable EDGECENTER_API_KEY "$EDGECENTER_API_KEY"
export _H1="Authorization: APIKey $EDGECENTER_API_KEY"
_dns_edgecenter_http_api_call "get" "dns/v2/clients/me/features"
if ! _contains "$response" '"id":'; then
_err "Invalid API key."
return 1
fi
return 0
}
_get_root() {
domain="$1"
i=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f "$i"-)
if [ -z "$h" ]; then
return 1
fi
_dns_edgecenter_http_api_call "get" "dns/v2/zones/$h"
if ! _contains "$response" 'zone is not found'; then
_zone="$h"
return 0
fi
i=$((i + 1))
done
return 1
}
_dns_edgecenter_http_api_call() {
mtd="$1"
endpoint="$2"
data="$3"
export _H1="Authorization: APIKey $EDGECENTER_API_KEY"
case "$mtd" in
get)
response="$(_get "$EDGECENTER_API/$endpoint")"
;;
post)
response="$(_post "$data" "$EDGECENTER_API/$endpoint")"
;;
delete)
response="$(_post "" "$EDGECENTER_API/$endpoint" "" "DELETE")"
;;
put)
response="$(_post "$data" "$EDGECENTER_API/$endpoint" "" "PUT")"
;;
*)
_err "Unknown HTTP method $mtd"
return 1
;;
esac
_debug "HTTP $mtd response: $response"
return 0
}

25
dnsapi/dns_edgedns.sh

@ -1,4 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_edgedns_info='Akamai.com Edge DNS
Site: techdocs.Akamai.com/edge-dns/reference/edge-dns-api
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_edgedns
Options: Specify individual credentials
AKAMAI_HOST Host
AKAMAI_ACCESS_TOKEN Access token
AKAMAI_CLIENT_TOKEN Client token
AKAMAI_CLIENT_SECRET Client secret
Issues: github.com/acmesh-official/acme.sh/issues/3157
'
# Akamai Edge DNS v2 API # Akamai Edge DNS v2 API
# User must provide Open Edgegrid API credentials to the EdgeDNS installation. The remote user in EdgeDNS must have CRUD access to # User must provide Open Edgegrid API credentials to the EdgeDNS installation. The remote user in EdgeDNS must have CRUD access to
@ -6,18 +17,10 @@
# Report bugs to https://control.akamai.com/apps/support-ui/#/contact-support # Report bugs to https://control.akamai.com/apps/support-ui/#/contact-support
# Values to export:
# --EITHER--
# *** TBD. NOT IMPLEMENTED YET *** # *** TBD. NOT IMPLEMENTED YET ***
# specify Edgegrid credentials file and section
# AKAMAI_EDGERC=<full file path>
# AKAMAI_EDGERC_SECTION="default"
## --OR--
# specify indiviual credentials
# export AKAMAI_HOST = <host>
# export AKAMAI_ACCESS_TOKEN = <access token>
# export AKAMAI_CLIENT_TOKEN = <client token>
# export AKAMAI_CLIENT_SECRET = <client secret>
# Specify Edgegrid credentials file and section.
# AKAMAI_EDGERC Edge RC. Full file path
# AKAMAI_EDGERC_SECTION Edge RC Section. E.g. "default"
ACME_EDGEDNS_VERSION="0.1.0" ACME_EDGEDNS_VERSION="0.1.0"

28
dnsapi/dns_euserv.sh

@ -1,18 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#This is the euserv.eu api wrapper for acme.sh
#
#Author: Michael Brueckner
#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de
#
#EUSERV_Username="username"
#
#EUSERV_Password="password"
#
# Dependencies:
# -------------
# - none -
# shellcheck disable=SC2034
dns_euserv_info='EUserv.com
Domains: EUserv.eu
Site: EUserv.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_euserv
Options:
EUSERV_Username Username
EUSERV_Password Password
Author: Michael Brueckner
'
EUSERV_Api="https://api.euserv.net" EUSERV_Api="https://api.euserv.net"
@ -155,7 +151,7 @@ _get_root() {
response="$_euserv_domain_orders" response="$_euserv_domain_orders"
while true; do while true; do
h=$(echo "$domain" | cut -d . -f $i-100)
h=$(echo "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -163,7 +159,7 @@ _get_root() {
fi fi
if _contains "$response" "$h"; then if _contains "$response" "$h"; then
_sub_domain=$(echo "$domain" | cut -d . -f 1-$p)
_sub_domain=$(echo "$domain" | cut -d . -f 1-"$p")
_domain="$h" _domain="$h"
if ! _euserv_get_domain_id "$_domain"; then if ! _euserv_get_domain_id "$_domain"; then
_err "invalid domain" _err "invalid domain"

12
dnsapi/dns_exoscale.sh

@ -1,4 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_exoscale_info='Exoscale.com
Site: Exoscale.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_exoscale
Options:
EXOSCALE_API_KEY API Key
EXOSCALE_SECRET_KEY API Secret key
'
EXOSCALE_API=https://api.exoscale.com/dns/v1 EXOSCALE_API=https://api.exoscale.com/dns/v1
@ -111,7 +119,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -122,7 +130,7 @@ _get_root() {
_domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \")
_domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") _domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_token" ] && [ "$_domain_id" ]; then if [ "$_domain_token" ] && [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

35
dnsapi/dns_fornex.sh

@ -1,8 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Author: Timur Umarov <inbox@tumarov.com>
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
# shellcheck disable=SC2034
dns_fornex_info='Fornex.com
Site: Fornex.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_fornex
Options:
FORNEX_API_KEY API Key
Issues: github.com/acmesh-official/acme.sh/issues/3998
Author: Timur Umarov <inbox@tumarov.com>
'
FORNEX_API_URL="https://fornex.com/api"
######## Public functions ##################### ######## Public functions #####################
@ -23,13 +30,11 @@ dns_fornex_add() {
fi fi
_info "Adding record" _info "Adding record"
if _rest POST "$_domain/entry_set/add/" "host=$fulldomain&type=TXT&value=$txtvalue&apikey=$FORNEX_API_KEY"; then
if _rest POST "dns/domain/$_domain/entry_set/" "{\"host\" : \"${fulldomain}\" , \"type\" : \"TXT\" , \"value\" : \"${txtvalue}\" , \"ttl\" : null}"; then
_debug _response "$response" _debug _response "$response"
if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then
_info "Added, OK" _info "Added, OK"
return 0 return 0
fi fi
fi
_err "Add txt record error." _err "Add txt record error."
return 1 return 1
} }
@ -51,21 +56,21 @@ dns_fornex_rm() {
fi fi
_debug "Getting txt records" _debug "Getting txt records"
_rest GET "$_domain/entry_set.json?apikey=$FORNEX_API_KEY"
_rest GET "dns/domain/$_domain/entry_set?type=TXT&q=$fulldomain"
if ! _contains "$response" "$txtvalue"; then if ! _contains "$response" "$txtvalue"; then
_err "Txt record not found" _err "Txt record not found"
return 1 return 1
fi fi
_record_id="$(echo "$response" | _egrep_o "{[^{]*\"value\"*:*\"$txtvalue\"[^}]*}" | sed -n -e 's#.*"id": \([0-9]*\).*#\1#p')"
_record_id="$(echo "$response" | _egrep_o "\{[^\{]*\"value\"*:*\"$txtvalue\"[^\}]*\}" | sed -n -e 's#.*"id":\([0-9]*\).*#\1#p')"
_debug "_record_id" "$_record_id" _debug "_record_id" "$_record_id"
if [ -z "$_record_id" ]; then if [ -z "$_record_id" ]; then
_err "can not find _record_id" _err "can not find _record_id"
return 1 return 1
fi fi
if ! _rest POST "$_domain/entry_set/$_record_id/delete/" "apikey=$FORNEX_API_KEY"; then
if ! _rest DELETE "dns/domain/$_domain/entry_set/$_record_id/"; then
_err "Delete record error." _err "Delete record error."
return 1 return 1
fi fi
@ -83,18 +88,18 @@ _get_root() {
i=1 i=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
return 1 return 1
fi fi
if ! _rest GET "domain_list.json?q=$h&apikey=$FORNEX_API_KEY"; then
if ! _rest GET "dns/domain/"; then
return 1 return 1
fi fi
if _contains "$response" "\"$h\"" >/dev/null; then
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain=$h _domain=$h
return 0 return 0
else else
@ -127,7 +132,9 @@ _rest() {
data="$3" data="$3"
_debug "$ep" _debug "$ep"
export _H1="Accept: application/json"
export _H1="Authorization: Api-Key $FORNEX_API_KEY"
export _H2="Content-Type: application/json"
export _H3="Accept: application/json"
if [ "$m" != "GET" ]; then if [ "$m" != "GET" ]; then
_debug data "$data" _debug data "$data"

19
dnsapi/dns_freedns.sh

@ -1,14 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_freedns_info='FreeDNS
Site: FreeDNS.afraid.org
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_freedns
Options:
FREEDNS_User Username
FREEDNS_Password Password
Issues: github.com/acmesh-official/acme.sh/issues/2305
Author: David Kerr <https://github.com/dkerr64>
'
#This file name is "dns_freedns.sh"
#So, here must be a method dns_freedns_add()
#Which will be called by acme.sh to add the txt record to your api system.
#returns 0 means success, otherwise error.
#
#Author: David Kerr
#Report Bugs here: https://github.com/dkerr64/acme.sh
#or here... https://github.com/acmesh-official/acme.sh/issues/2305
#
######## Public functions ##################### ######## Public functions #####################
# Export FreeDNS userid and password in following variables... # Export FreeDNS userid and password in following variables...

105
dnsapi/dns_freemyip.sh

@ -0,0 +1,105 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034
dns_freemyip_info='FreeMyIP.com
Site: freemyip.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_freemyip
Options:
FREEMYIP_Token API Token
Issues: github.com/acmesh-official/acme.sh/issues/{XXXX}
Author: Recolic Keghart <root@recolic.net>, @Giova96
'
FREEMYIP_DNS_API="https://freemyip.com/update?"
################ Public functions ################
#Usage: dns_freemyip_add fulldomain txtvalue
dns_freemyip_add() {
fulldomain="$1"
txtvalue="$2"
_info "Add TXT record $txtvalue for $fulldomain using freemyip.com api"
FREEMYIP_Token="${FREEMYIP_Token:-$(_readaccountconf_mutable FREEMYIP_Token)}"
if [ -z "$FREEMYIP_Token" ]; then
FREEMYIP_Token=""
_err "You don't specify FREEMYIP_Token yet."
_err "Please specify your token and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable FREEMYIP_Token "$FREEMYIP_Token"
if _is_root_domain_published "$fulldomain"; then
_err "freemyip API don't allow you to set multiple TXT record for the same subdomain!"
_err "You must apply certificate for only one domain at a time!"
_err "===="
_err "For example, aaa.yourdomain.freemyip.com and bbb.yourdomain.freemyip.com and yourdomain.freemyip.com ALWAYS share the same TXT record. They will overwrite each other if you apply multiple domain at the same time."
_debug "If you are testing this workflow in github pipeline or acmetest, please set TEST_DNS_NO_SUBDOMAIN=1 and TEST_DNS_NO_WILDCARD=1"
return 1
fi
# txtvalue must be url-encoded. But it's not necessary for acme txt value.
_freemyip_get_until_ok "${FREEMYIP_DNS_API}token=$FREEMYIP_Token&domain=$fulldomain&txt=$txtvalue" 2>&1
return $?
}
#Usage: dns_freemyip_rm fulldomain txtvalue
dns_freemyip_rm() {
fulldomain="$1"
txtvalue="$2"
_info "Delete TXT record $txtvalue for $fulldomain using freemyip.com api"
FREEMYIP_Token="${FREEMYIP_Token:-$(_readaccountconf_mutable FREEMYIP_Token)}"
if [ -z "$FREEMYIP_Token" ]; then
FREEMYIP_Token=""
_err "You don't specify FREEMYIP_Token yet."
_err "Please specify your token and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable FREEMYIP_Token "$FREEMYIP_Token"
# Leave the TXT record as empty or "null" to delete the record.
_freemyip_get_until_ok "${FREEMYIP_DNS_API}token=$FREEMYIP_Token&domain=$fulldomain&txt=" 2>&1
return $?
}
################ Private functions below ################
_get_root() {
_fmi_d="$1"
echo "$_fmi_d" | rev | cut -d '.' -f 1-3 | rev
}
# There is random failure while calling freemyip API too fast. This function automatically retry until success.
_freemyip_get_until_ok() {
_fmi_url="$1"
for i in $(seq 1 8); do
_debug "HTTP GET freemyip.com API '$_fmi_url', retry $i/8..."
_get "$_fmi_url" | tee /dev/fd/2 | grep OK && return 0
_sleep 1 # DO NOT send the request too fast
done
_err "Failed to request freemyip API: $_fmi_url . Server does not say 'OK'"
return 1
}
# Verify in public dns if domain is already there.
_is_root_domain_published() {
_fmi_d="$1"
_webroot="$(_get_root "$_fmi_d")"
_info "Verifying '""$_fmi_d""' freemyip webroot (""$_webroot"") is not published yet"
for i in $(seq 1 3); do
_debug "'$_webroot' ns lookup, retry $i/3..."
if [ "$(_ns_lookup "$_fmi_d" TXT)" ]; then
_debug "'$_webroot' already has a TXT record published!"
return 0
fi
_sleep 10 # Give it some time to propagate the TXT record
done
return 1
}

21
dnsapi/dns_gandi_livedns.sh

@ -1,16 +1,19 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_gandi_livedns_info='Gandi.net LiveDNS
Site: Gandi.net/domain/dns
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gandi_livedns
Options:
GANDI_LIVEDNS_KEY API Key
Issues: github.com/fcrozat/acme.sh
Author: Frédéric Crozat <fcrozat@suse.com>, Dominik Röttsches <drott@google.com>
'
# Gandi LiveDNS v5 API # Gandi LiveDNS v5 API
# https://api.gandi.net/docs/livedns/ # https://api.gandi.net/docs/livedns/
# https://api.gandi.net/docs/authentication/ for token + apikey (deprecated) authentication # https://api.gandi.net/docs/authentication/ for token + apikey (deprecated) authentication
# currently under beta # currently under beta
#
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
#
#Author: Frédéric Crozat <fcrozat@suse.com>
# Dominik Röttsches <drott@google.com>
#Report Bugs here: https://github.com/fcrozat/acme.sh
#
######## Public functions ##################### ######## Public functions #####################
GANDI_LIVEDNS_API="https://api.gandi.net/v5/livedns" GANDI_LIVEDNS_API="https://api.gandi.net/v5/livedns"
@ -92,7 +95,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -109,7 +112,7 @@ _get_root() {
elif _contains "$response" '"code": 404'; then elif _contains "$response" '"code": 404'; then
_debug "$h not found" _debug "$h not found"
else else
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain="$h" _domain="$h"
return 0 return 0
fi fi

10
dnsapi/dns_gcloud.sh

@ -1,6 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# Author: Janos Lenart <janos@lenart.io>
# shellcheck disable=SC2034
dns_gcloud_info='Google Cloud DNS
Site: Cloud.Google.com/dns
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcloud
Options:
CLOUDSDK_ACTIVE_CONFIG_NAME Active config name. E.g. "default"
Author: Janos Lenart <janos@lenart.io>
'
######## Public functions ##################### ######## Public functions #####################

18
dnsapi/dns_gcore.sh

@ -1,8 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#GCORE_Key='773$7b7adaf2a2b32bfb1b83787b4ff32a67eb178e3ada1af733e47b1411f2461f7f4fa7ed7138e2772a46124377bad7384b3bb8d87748f87b3f23db4b8bbe41b2bb'
#
# shellcheck disable=SC2034
dns_gcore_info='Gcore.com
Site: Gcore.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcore
Options:
GCORE_Key API Key
Issues: github.com/acmesh-official/acme.sh/issues/4460
'
GCORE_Api="https://api.gcore.com/dns/v2" GCORE_Api="https://api.gcore.com/dns/v2"
GCORE_Doc="https://api.gcore.com/docs/dns" GCORE_Doc="https://api.gcore.com/docs/dns"
@ -24,7 +28,7 @@ dns_gcore_add() {
fi fi
#save the api key to the account conf file. #save the api key to the account conf file.
_saveaccountconf_mutable GCORE_Key "$GCORE_Key"
_saveaccountconf_mutable GCORE_Key "$GCORE_Key" "base64"
_debug "First detect the zone name" _debug "First detect the zone name"
if ! _get_root "$fulldomain"; then if ! _get_root "$fulldomain"; then
@ -134,7 +138,7 @@ _get_root() {
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -148,7 +152,7 @@ _get_root() {
if _contains "$response" "\"name\":\"$h\""; then if _contains "$response" "\"name\":\"$h\""; then
_zone_name=$h _zone_name=$h
if [ "$_zone_name" ]; then if [ "$_zone_name" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

20
dnsapi/dns_gd.sh

@ -1,12 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Godaddy domain api
# Get API key and secret from https://developer.godaddy.com/
#
# GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
# GD_Secret="asdfsdfsfsdfsdfdfsdf"
#
# Ex.: acme.sh --issue --staging --dns dns_gd -d "*.s.example.com" -d "s.example.com"
# shellcheck disable=SC2034
dns_gd_info='GoDaddy.com
Site: GoDaddy.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gd
Options:
GD_Key API Key
GD_Secret API Secret
'
GD_Api="https://api.godaddy.com/v1" GD_Api="https://api.godaddy.com/v1"
@ -148,7 +148,7 @@ _get_root() {
i=2 i=2
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
return 1 return 1
@ -161,7 +161,7 @@ _get_root() {
if _contains "$response" '"code":"NOT_FOUND"'; then if _contains "$response" '"code":"NOT_FOUND"'; then
_debug "$h not found" _debug "$h not found"
else else
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain="$h" _domain="$h"
return 0 return 0
fi fi

18
dnsapi/dns_geoscaling.sh

@ -1,12 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
########################################################################
# Geoscaling hook script for acme.sh
#
# Environment variables:
#
# - $GEOSCALING_Username (your Geoscaling username - this is usually NOT an amail address)
# - $GEOSCALING_Password (your Geoscaling password)
# shellcheck disable=SC2034
dns_geoscaling_info='GeoScaling.com
Site: GeoScaling.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_geoscaling
Options:
GEOSCALING_Username Username. This is usually NOT an email address
GEOSCALING_Password Password
'
#-- dns_geoscaling_add() - Add TXT record -------------------------------------- #-- dns_geoscaling_add() - Add TXT record --------------------------------------
# Usage: dns_geoscaling_add _acme-challenge.subdomain.domain.com "XyZ123..." # Usage: dns_geoscaling_add _acme-challenge.subdomain.domain.com "XyZ123..."
@ -202,7 +202,7 @@ find_zone() {
# Walk through all possible zone names # Walk through all possible zone names
strip_counter=1 strip_counter=1
while true; do while true; do
attempted_zone=$(echo "${domain}" | cut -d . -f ${strip_counter}-)
attempted_zone=$(echo "${domain}" | cut -d . -f "${strip_counter}"-)
# All possible zone names have been tried # All possible zone names have been tried
if [ -z "${attempted_zone}" ]; then if [ -z "${attempted_zone}" ]; then

17
dnsapi/dns_googledomains.sh

@ -1,10 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_googledomains_info='Google Domains
Site: Domains.Google.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_googledomains
Options:
GOOGLEDOMAINS_ACCESS_TOKEN API Access Token
GOOGLEDOMAINS_ZONE Zone
Issues: github.com/acmesh-official/acme.sh/issues/4545
Author: Alex Leigh <leigh@alexleigh.me>
'
# Author: Alex Leigh <leigh at alexleigh dot me>
# Created: 2023-03-02
#GOOGLEDOMAINS_ACCESS_TOKEN="xxxx"
#GOOGLEDOMAINS_ZONE="xxxx"
GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets" GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets"
######## Public functions ######## ######## Public functions ########
@ -127,7 +132,7 @@ _dns_googledomains_get_zone() {
i=2 i=2
while true; do while true; do
curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
curr=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug curr "$curr" _debug curr "$curr"
if [ -z "$curr" ]; then if [ -z "$curr" ]; then

23
dnsapi/dns_he.sh

@ -1,15 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
########################################################################
# Hurricane Electric hook script for acme.sh
#
# Environment variables:
#
# - $HE_Username (your dns.he.net username)
# - $HE_Password (your dns.he.net password)
#
# Author: Ondrej Simek <me@ondrejsimek.com>
# Git repo: https://github.com/angel333/acme.sh
# shellcheck disable=SC2034
dns_he_info='Hurricane Electric HE.net
Site: dns.he.net
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_he
Options:
HE_Username Username
HE_Password Password
Issues: github.com/angel333/acme.sh/issues/
Author: Ondrej Simek <me@ondrejsimek.com>
'
#-- dns_he_add() - Add TXT record -------------------------------------- #-- dns_he_add() - Add TXT record --------------------------------------
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..." # Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
@ -144,7 +143,7 @@ _find_zone() {
# Walk through all possible zone names # Walk through all possible zone names
_strip_counter=1 _strip_counter=1
while true; do while true; do
_attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-)
_attempted_zone=$(echo "$_domain" | cut -d . -f "${_strip_counter}"-)
# All possible zone names have been tried # All possible zone names have been tried
if [ -z "$_attempted_zone" ]; then if [ -z "$_attempted_zone" ]; then

44
dnsapi/dns_he_ddns.sh

@ -0,0 +1,44 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034
dns_he_ddns_info='Hurricane Electric HE.net DDNS
Site: dns.he.net
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_he_ddns
Options:
HE_DDNS_KEY The DDNS key
Author: Markku Leiniö
'
HE_DDNS_URL="https://dyn.dns.he.net/nic/update"
######## Public functions #####################
#Usage: dns_he_ddns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_he_ddns_add() {
fulldomain=$1
txtvalue=$2
HE_DDNS_KEY="${HE_DDNS_KEY:-$(_readaccountconf_mutable HE_DDNS_KEY)}"
if [ -z "$HE_DDNS_KEY" ]; then
HE_DDNS_KEY=""
_err "You didn't specify a DDNS key for accessing the TXT record in HE API."
return 1
fi
#Save the DDNS key to the account conf file.
_saveaccountconf_mutable HE_DDNS_KEY "$HE_DDNS_KEY"
_info "Using Hurricane Electric DDNS API"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
response="$(_post "hostname=$fulldomain&password=$HE_DDNS_KEY&txt=$txtvalue" "$HE_DDNS_URL")"
_info "Response: $response"
_contains "$response" "good" && return 0 || return 1
}
# dns_he_ddns_rm() is not doing anything because the API call always updates the
# contents of the existing record (that the API key gives access to).
dns_he_ddns_rm() {
fulldomain=$1
_debug "Delete TXT record called for '${fulldomain}', not doing anything."
return 0
}

18
dnsapi/dns_hetzner.sh

@ -1,8 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
#HETZNER_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
#
# shellcheck disable=SC2034
dns_hetzner_info='Hetzner.com
Site: Hetzner.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hetzner
Options:
HETZNER_Token API Token
Issues: github.com/acmesh-official/acme.sh/issues/2943
'
HETZNER_Api="https://dns.hetzner.com/api/v1" HETZNER_Api="https://dns.hetzner.com/api/v1"
@ -177,7 +181,7 @@ _get_root() {
_debug "Trying to get zone id by domain name for '$domain_without_acme'." _debug "Trying to get zone id by domain name for '$domain_without_acme'."
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
return 1 return 1
@ -189,7 +193,7 @@ _get_root() {
if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_entries":1'; then if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_entries":1'; then
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") _domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
HETZNER_Zone_ID=$_domain_id HETZNER_Zone_ID=$_domain_id
_savedomainconf "$domain_param_name" "$HETZNER_Zone_ID" _savedomainconf "$domain_param_name" "$HETZNER_Zone_ID"
@ -208,7 +212,7 @@ _get_root() {
_response_has_error() { _response_has_error() {
unset _response_error unset _response_error
err_part="$(echo "$response" | _egrep_o '"error":{[^}]*}')"
err_part="$(echo "$response" | _egrep_o '"error":\{[^\}]*\}')"
if [ -n "$err_part" ]; then if [ -n "$err_part" ]; then
err_code=$(echo "$err_part" | _egrep_o '"code":[0-9]+' | cut -d : -f 2) err_code=$(echo "$err_part" | _egrep_o '"code":[0-9]+' | cut -d : -f 2)

18
dnsapi/dns_hexonet.sh

@ -1,9 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
# Hexonet_Login="username!roleId"
#
# Hexonet_Password="rolePassword"
# shellcheck disable=SC2034
dns_hexonet_info='Hexonet.com
Site: Hexonet.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_hexonet
Options:
Hexonet_Login Login. E.g. "username!roleId"
Hexonet_Password Role Password
Issues: github.com/acmesh-official/acme.sh/issues/2389
'
Hexonet_Api="https://coreapi.1api.net/api/call.cgi" Hexonet_Api="https://coreapi.1api.net/api/call.cgi"
@ -119,7 +123,7 @@ _get_root() {
i=1 i=1
p=1 p=1
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
_debug h "$h" _debug h "$h"
if [ -z "$h" ]; then if [ -z "$h" ]; then
#not valid #not valid
@ -131,7 +135,7 @@ _get_root() {
fi fi
if _contains "$response" "CODE=200"; then if _contains "$response" "CODE=200"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
_domain=$h _domain=$h
return 0 return 0
fi fi

15
dnsapi/dns_hostingde.sh

@ -1,10 +1,13 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# hosting.de API
# Values to export:
# export HOSTINGDE_ENDPOINT='https://secure.hosting.de'
# export HOSTINGDE_APIKEY='xxxxx'
# shellcheck disable=SC2034
dns_hostingde_info='Hosting.de
Site: Hosting.de
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hostingde
Options:
HOSTINGDE_ENDPOINT Endpoint. E.g. "https://secure.hosting.de"
HOSTINGDE_APIKEY API Key
Issues: github.com/acmesh-official/acme.sh/issues/2058
'
######## Public functions ##################### ######## Public functions #####################

18
dnsapi/dns_huaweicloud.sh

@ -1,8 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# HUAWEICLOUD_Username
# HUAWEICLOUD_Password
# HUAWEICLOUD_DomainName
# shellcheck disable=SC2034
dns_huaweicloud_info='HuaweiCloud.com
Site: HuaweiCloud.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_huaweicloud
Options:
HUAWEICLOUD_Username Username
HUAWEICLOUD_Password Password
HUAWEICLOUD_DomainName DomainName
Issues: github.com/acmesh-official/acme.sh/issues/3265
'
iam_api="https://iam.myhuaweicloud.com" iam_api="https://iam.myhuaweicloud.com"
dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
@ -204,7 +210,7 @@ _get_recordset_id() {
_zoneid=$3 _zoneid=$3
export _H1="X-Auth-Token: ${_token}" export _H1="X-Auth-Token: ${_token}"
response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}")
response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}&status=ACTIVE")
if _contains "${response}" '"id"'; then if _contains "${response}" '"id"'; then
_id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")" _id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")"
printf "%s" "${_id}" printf "%s" "${_id}"
@ -221,7 +227,7 @@ _add_record() {
# Get Existing Records # Get Existing Records
export _H1="X-Auth-Token: ${_token}" export _H1="X-Auth-Token: ${_token}"
response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}")
response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}&status=ACTIVE")
_debug2 "${response}" _debug2 "${response}"
_exist_record=$(echo "${response}" | _egrep_o '"records":[^]]*' | sed 's/\"records\"\:\[//g') _exist_record=$(echo "${response}" | _egrep_o '"records":[^]]*' | sed 's/\"records\"\:\[//g')

14
dnsapi/dns_infoblox.sh

@ -1,8 +1,14 @@
#!/usr/bin/env sh #!/usr/bin/env sh
## Infoblox API integration by Jason Keller and Elijah Tenai
##
## Report any bugs via https://github.com/jasonkeller/acme.sh
# shellcheck disable=SC2034
dns_infoblox_info='Infoblox.com
Site: Infoblox.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_infoblox
Options:
Infoblox_Creds Credentials. E.g. "username:password"
Infoblox_Server Server hostname. IP or FQDN of infoblox appliance
Issues: github.com/jasonkeller/acme.sh
Author: Jason Keller, Elijah Tenai
'
dns_infoblox_add() { dns_infoblox_add() {

15
dnsapi/dns_infomaniak.sh

@ -1,19 +1,20 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC2034
dns_infomaniak_info='Infomaniak.com
Site: Infomaniak.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_infomaniak
Options:
INFOMANIAK_API_TOKEN API Token
Issues: github.com/acmesh-official/acme.sh/issues/3188
'
###############################################################################
# Infomaniak API integration
#
# To use this API you need visit the API dashboard of your account # To use this API you need visit the API dashboard of your account
# once logged into https://manager.infomaniak.com add /api/dashboard to the URL # once logged into https://manager.infomaniak.com add /api/dashboard to the URL
# #
# Please report bugs to
# https://github.com/acmesh-official/acme.sh/issues/3188
#
# Note: the URL looks like this: # Note: the URL looks like this:
# https://manager.infomaniak.com/v3/<account_id>/api/dashboard # https://manager.infomaniak.com/v3/<account_id>/api/dashboard
# Then generate a token with the scope Domain # Then generate a token with the scope Domain
# this is given as an environment variable INFOMANIAK_API_TOKEN # this is given as an environment variable INFOMANIAK_API_TOKEN
###############################################################################
# base variables # base variables

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save