Compare commits

..
370 Commits
62 changed files with 3517 additions and 880 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: acmesh
ko_fi: # Replace with a single Ko-fi username
ko_fi: neilpang
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
+18 -13
View File
@@ -37,7 +37,7 @@ jobs:
- name: "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
run: |
echo "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
if [ "${{github.actor}}" != "Neilpang" ]; then
if [ "${{github.repository_owner}}" != "acmesh-official" ]; then
false
fi
@@ -49,6 +49,7 @@ jobs:
TEST_DNS : ${{ secrets.TEST_DNS }}
TestingDomain: ${{ secrets.TestingDomain }}
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
CASE: le_test_dnsapi
TEST_LOCAL: 1
@@ -61,22 +62,22 @@ jobs:
run: |
cd ../acmetest
if [ "${{ secrets.TokenName1}}" ] ; then
echo "${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}" >> env.list
echo "${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}" >> docker.env
fi
if [ "${{ secrets.TokenName2}}" ] ; then
echo "${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}" >> env.list
echo "${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}" >> docker.env
fi
if [ "${{ secrets.TokenName3}}" ] ; then
echo "${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}" >> env.list
echo "${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}" >> docker.env
fi
if [ "${{ secrets.TokenName4}}" ] ; then
echo "${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}" >> env.list
echo "${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}" >> docker.env
fi
if [ "${{ secrets.TokenName5}}" ] ; then
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> env.list
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> docker.env
fi
echo "TEST_DNS_NO_WILDCARD" >> env.list
echo "TEST_DNS_SLEEP" >> env.list
echo "TEST_DNS_NO_WILDCARD" >> docker.env
echo "TEST_DNS_SLEEP" >> docker.env
- name: Run acmetest
run: cd ../acmetest && ./rundocker.sh testall
@@ -87,6 +88,7 @@ jobs:
TEST_DNS : ${{ secrets.TEST_DNS }}
TestingDomain: ${{ secrets.TestingDomain }}
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
CASE: le_test_dnsapi
TEST_LOCAL: 1
@@ -124,6 +126,7 @@ jobs:
TEST_DNS : ${{ secrets.TEST_DNS }}
TestingDomain: ${{ secrets.TestingDomain }}
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
CASE: le_test_dnsapi
TEST_LOCAL: 1
@@ -170,12 +173,13 @@ jobs:
./letest.sh
FreeBSD:
runs-on: macos-latest
runs-on: macos-10.15
needs: Windows
env:
TEST_DNS : ${{ secrets.TEST_DNS }}
TestingDomain: ${{ secrets.TestingDomain }}
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
CASE: le_test_dnsapi
TEST_LOCAL: 1
@@ -186,7 +190,7 @@ jobs:
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/freebsd-vm@v0.1.4
with:
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ 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 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
prepare: pkg install -y socat curl
usesh: true
run: |
@@ -209,12 +213,13 @@ jobs:
./letest.sh
Solaris:
runs-on: macos-latest
runs-on: macos-10.15
needs: FreeBSD
env:
TEST_DNS : ${{ secrets.TEST_DNS }}
TestingDomain: ${{ secrets.TestingDomain }}
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
CASE: le_test_dnsapi
TEST_LOCAL: 1
@@ -223,9 +228,9 @@ jobs:
- uses: actions/checkout@v2
- name: Clone acmetest
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/solaris-vm@v0.0.3
- uses: vmactions/solaris-vm@v0.0.5
with:
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ 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 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
prepare: pkgutil -y -i socat
run: |
pkg set-mediator -v -I default@1.1 openssl
+11 -8
View File
@@ -24,20 +24,23 @@ jobs:
CA_ECDSA: ""
CA: ""
CA_EMAIL: ""
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
runs-on: macos-latest
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
#- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: macos-10.15
env:
TEST_LOCAL: 1
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
CA_ECDSA: ${{ matrix.CA_ECDSA }}
CA: ${{ matrix.CA }}
CA_EMAIL: ${{ matrix.CA_EMAIL }}
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
steps:
- uses: actions/checkout@v2
- uses: vmactions/cf-tunnel@v0.0.2
- uses: vmactions/cf-tunnel@v0.0.3
id: tunnel
with:
protocol: http
@@ -46,9 +49,9 @@ jobs:
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
- name: Clone acmetest
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/freebsd-vm@v0.1.4
- uses: vmactions/freebsd-vm@v0.1.5
with:
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL'
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
nat: |
"8080": "80"
prepare: pkg install -y socat curl
+2 -1
View File
@@ -20,10 +20,11 @@ jobs:
Linux:
strategy:
matrix:
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3-amd64", "clearlinux:latest"]
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"]
runs-on: ubuntu-latest
env:
TEST_LOCAL: 1
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
steps:
- uses: actions/checkout@v2
- name: Clone acmetest
+7 -4
View File
@@ -24,10 +24,12 @@ jobs:
CA_ECDSA: ""
CA: ""
CA_EMAIL: ""
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
#- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: macos-latest
env:
TEST_LOCAL: 1
@@ -35,6 +37,7 @@ jobs:
CA_ECDSA: ${{ matrix.CA_ECDSA }}
CA: ${{ matrix.CA }}
CA_EMAIL: ${{ matrix.CA_EMAIL }}
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
steps:
- uses: actions/checkout@v2
- name: Install tools
+23
View File
@@ -35,5 +35,28 @@ jobs:
run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4
- name: Clone acmetest
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- name: Run acmetest
run: cd ../acmetest && ./letest.sh
PebbleStrict_IPCert:
runs-on: ubuntu-latest
env:
TestingDomain: 10.30.50.1
ACME_DIRECTORY: https://localhost:14000/dir
HTTPS_INSECURE: 1
Le_HTTPPort: 5002
Le_TLSPort: 5001
TEST_LOCAL: 1
TEST_CA: "Pebble Intermediate CA"
TEST_IPCERT: 1
steps:
- uses: actions/checkout@v2
- name: Install tools
run: sudo apt-get install -y socat
- name: Run Pebble
run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker-compose up -d
- name: Clone acmetest
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- name: Run acmetest
run: cd ../acmetest && ./letest.sh
+11 -8
View File
@@ -24,20 +24,23 @@ jobs:
CA_ECDSA: ""
CA: ""
CA_EMAIL: ""
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
runs-on: macos-latest
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
#- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: macos-10.15
env:
TEST_LOCAL: 1
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
CA_ECDSA: ${{ matrix.CA_ECDSA }}
CA: ${{ matrix.CA }}
CA_EMAIL: ${{ matrix.CA_EMAIL }}
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
steps:
- uses: actions/checkout@v2
- uses: vmactions/cf-tunnel@v0.0.2
- uses: vmactions/cf-tunnel@v0.0.3
id: tunnel
with:
protocol: http
@@ -46,9 +49,9 @@ jobs:
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
- name: Clone acmetest
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/solaris-vm@v0.0.3
- uses: vmactions/solaris-vm@v0.0.5
with:
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL'
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
nat: |
"8080": "80"
prepare: pkgutil -y -i socat curl
+32
View File
@@ -24,10 +24,26 @@ jobs:
CA_ECDSA: ""
CA: ""
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
TEST_PREFERRED_CHAIN: ""
- TEST_ACME_Server: "https://localhost:9000/acme/acme/directory"
CA_ECDSA: "Smallstep Intermediate CA"
CA: "Smallstep Intermediate CA"
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: ""
NO_REVOKE: 1
- TEST_ACME_Server: "https://localhost:9000/acme/acme/directory"
CA_ECDSA: "Smallstep Intermediate CA"
CA: "Smallstep Intermediate CA"
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: ""
NO_REVOKE: 1
TEST_IPCERT: 1
TestingDomain: "172.17.0.1"
runs-on: ubuntu-latest
env:
@@ -37,10 +53,26 @@ jobs:
CA: ${{ matrix.CA }}
CA_EMAIL: ${{ matrix.CA_EMAIL }}
NO_ECC_384: ${{ matrix.NO_ECC_384 }}
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
NO_REVOKE: ${{ matrix.NO_REVOKE }}
TEST_IPCERT: ${{ matrix.TEST_IPCERT }}
TestingDomain: ${{ matrix.TestingDomain }}
steps:
- uses: actions/checkout@v2
- name: Install tools
run: sudo apt-get install -y socat
- name: Start StepCA
if: ${{ matrix.TEST_ACME_Server=='https://localhost:9000/acme/acme/directory' }}
run: |
docker run --rm -d \
-p 9000:9000 \
-e "DOCKER_STEPCA_INIT_NAME=Smallstep" \
-e "DOCKER_STEPCA_INIT_DNS_NAMES=localhost,$(hostname -f)" \
--name stepca \
smallstep/step-ca \
&& sleep 5 && docker exec stepca step ca provisioner add acme --type ACME \
&& docker exec stepca kill -1 1 \
&& docker exec stepca cat /home/step/certs/root_ca.crt | sudo bash -c "cat - >>/etc/ssl/certs/ca-certificates.crt"
- name: Clone acmetest
run: |
cd .. \
+9 -6
View File
@@ -24,10 +24,12 @@ jobs:
CA_ECDSA: ""
CA: ""
CA_EMAIL: ""
- TEST_ACME_Server: "ZeroSSL.com"
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
CA: "ZeroSSL RSA Domain Secure Site CA"
CA_EMAIL: "githubtest@acme.sh"
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
#- TEST_ACME_Server: "ZeroSSL.com"
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
# CA: "ZeroSSL RSA Domain Secure Site CA"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: windows-latest
env:
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
@@ -37,6 +39,7 @@ jobs:
TEST_LOCAL: 1
#The 80 port is used by Windows server, we have to use a custom port, tunnel will also use this port.
Le_HTTPPort: 8888
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
steps:
- name: Set git to use LF
run: |
@@ -49,12 +52,12 @@ jobs:
shell: cmd
- name: Install cygwin additional packages
run: |
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git,xxd
shell: cmd
- name: Set ENV
shell: cmd
run: |
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin >> %GITHUB_ENV%
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin;%PATH% >> %GITHUB_ENV%
- name: Check ENV
shell: cmd
run: |
+7 -3
View File
@@ -1,4 +1,4 @@
FROM alpine:3.12
FROM alpine:3.15
RUN apk --no-cache add -f \
openssl \
@@ -11,7 +11,8 @@ RUN apk --no-cache add -f \
tzdata \
oath-toolkit-oathtool \
tar \
libidn
libidn \
jq
ENV LE_CONFIG_HOME /acme.sh
@@ -40,6 +41,7 @@ RUN for verb in help \
revoke \
remove \
list \
info \
showcsr \
install-cronjob \
uninstall-cronjob \
@@ -55,6 +57,7 @@ RUN for verb in help \
deactivate-account \
set-notify \
set-default-ca \
set-default-chain \
; do \
printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \
; done
@@ -62,7 +65,8 @@ RUN for verb in help \
RUN printf "%b" '#!'"/usr/bin/env sh\n \
if [ \"\$1\" = \"daemon\" ]; then \n \
trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
crond && while true; do sleep 1; done;\n \
crond && sleep infinity &\n \
wait \n \
else \n \
exec -- \"\$@\"\n \
fi" >/entry.sh && chmod +x /entry.sh
+1
View File
@@ -95,6 +95,7 @@ https://github.com/acmesh-official/acmetest
- Letsencrypt.org CA
- [BuyPass.com CA](https://github.com/acmesh-official/acme.sh/wiki/BuyPass.com-CA)
- [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA)
- [Google.com Public CA](https://github.com/acmesh-official/acme.sh/wiki/Google-Public-CA)
- [Pebble strict Mode](https://github.com/letsencrypt/pebble)
- Any other [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA
+458 -176
View File
File diff suppressed because it is too large Load Diff
+26 -18
View File
@@ -36,43 +36,51 @@ fritzbox_deploy() {
fi
fi
_fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}"
_fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}"
_fritzbox_url="${DEPLOY_FRITZBOX_URL}"
# Clear traces of incorrectly stored values
_clearaccountconf DEPLOY_FRITZBOX_USERNAME
_clearaccountconf DEPLOY_FRITZBOX_PASSWORD
_clearaccountconf DEPLOY_FRITZBOX_URL
_debug _fritzbox_url "$_fritzbox_url"
_debug _fritzbox_username "$_fritzbox_username"
_secure_debug _fritzbox_password "$_fritzbox_password"
if [ -z "$_fritzbox_username" ]; then
# Read config from saved values or env
_getdeployconf DEPLOY_FRITZBOX_USERNAME
_getdeployconf DEPLOY_FRITZBOX_PASSWORD
_getdeployconf DEPLOY_FRITZBOX_URL
_debug DEPLOY_FRITZBOX_URL "$DEPLOY_FRITZBOX_URL"
_debug DEPLOY_FRITZBOX_USERNAME "$DEPLOY_FRITZBOX_USERNAME"
_secure_debug DEPLOY_FRITZBOX_PASSWORD "$DEPLOY_FRITZBOX_PASSWORD"
if [ -z "$DEPLOY_FRITZBOX_USERNAME" ]; then
_err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME."
return 1
fi
if [ -z "$_fritzbox_password" ]; then
if [ -z "$DEPLOY_FRITZBOX_PASSWORD" ]; then
_err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD."
return 1
fi
if [ -z "$_fritzbox_url" ]; then
if [ -z "$DEPLOY_FRITZBOX_URL" ]; then
_err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL."
return 1
fi
_saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}"
_saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}"
_saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}"
# Save current values
_savedeployconf DEPLOY_FRITZBOX_USERNAME "$DEPLOY_FRITZBOX_USERNAME"
_savedeployconf DEPLOY_FRITZBOX_PASSWORD "$DEPLOY_FRITZBOX_PASSWORD"
_savedeployconf DEPLOY_FRITZBOX_URL "$DEPLOY_FRITZBOX_URL"
# Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate
export HTTPS_INSECURE=1
_info "Log in to the FRITZ!Box"
_fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
_fritzbox_challenge="$(_get "${DEPLOY_FRITZBOX_URL}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
if _exists iconv; then
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | _digest md5 hex)"
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | iconv -f ASCII -t UTF16LE | _digest md5 hex)"
elif _exists uconv; then
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | uconv -f ASCII -t UTF16LE | _digest md5 hex)"
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | uconv -f ASCII -t UTF16LE | _digest md5 hex)"
else
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | _digest md5 hex)"
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | _digest md5 hex)"
fi
_fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
_fritzbox_sid="$(_get "${DEPLOY_FRITZBOX_URL}/login_sid.lua?sid=0000000000000000&username=${DEPLOY_FRITZBOX_USERNAME}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then
_err "Logging in to the FRITZ!Box failed. Please check username, password and URL."
@@ -104,7 +112,7 @@ fritzbox_deploy() {
_info "Upload certificate to the FRITZ!Box"
export _H1="Content-type: multipart/form-data boundary=${_post_boundary}"
_post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL
_post "$(cat "${_post_request}")" "${DEPLOY_FRITZBOX_URL}/cgi-bin/firmwarecfg" | grep SSL
retval=$?
if [ $retval = 0 ]; then
+15 -10
View File
@@ -54,11 +54,6 @@ haproxy_deploy() {
DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
if [ -f "${DOMAIN_CONF}" ]; then
# shellcheck disable=SC1090
. "${DOMAIN_CONF}"
fi
_debug _cdomain "${_cdomain}"
_debug _ckey "${_ckey}"
_debug _ccert "${_ccert}"
@@ -66,6 +61,8 @@ haproxy_deploy() {
_debug _cfullchain "${_cfullchain}"
# PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}"
_getdeployconf DEPLOY_HAPROXY_PEM_PATH
_debug2 DEPLOY_HAPROXY_PEM_PATH "${DEPLOY_HAPROXY_PEM_PATH}"
if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then
Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}"
_savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}"
@@ -82,6 +79,8 @@ haproxy_deploy() {
fi
# PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
_getdeployconf DEPLOY_HAPROXY_PEM_NAME
_debug2 DEPLOY_HAPROXY_PEM_NAME "${DEPLOY_HAPROXY_PEM_NAME}"
if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then
Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}"
_savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
@@ -90,6 +89,8 @@ haproxy_deploy() {
fi
# BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
_getdeployconf DEPLOY_HAPROXY_BUNDLE
_debug2 DEPLOY_HAPROXY_BUNDLE "${DEPLOY_HAPROXY_BUNDLE}"
if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then
Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}"
_savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}"
@@ -98,6 +99,8 @@ haproxy_deploy() {
fi
# ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}"
_getdeployconf DEPLOY_HAPROXY_ISSUER
_debug2 DEPLOY_HAPROXY_ISSUER "${DEPLOY_HAPROXY_ISSUER}"
if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then
Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}"
_savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}"
@@ -106,6 +109,8 @@ haproxy_deploy() {
fi
# RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
_getdeployconf DEPLOY_HAPROXY_RELOAD
_debug2 DEPLOY_HAPROXY_RELOAD "${DEPLOY_HAPROXY_RELOAD}"
if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then
Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}"
_savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}"
@@ -190,7 +195,7 @@ haproxy_deploy() {
_info "Updating OCSP stapling info"
_debug _ocsp "${_ocsp}"
_info "Extracting OCSP URL"
_ocsp_url=$(openssl x509 -noout -ocsp_uri -in "${_pem}")
_ocsp_url=$(${ACME_OPENSSL_BIN:-openssl} x509 -noout -ocsp_uri -in "${_pem}")
_debug _ocsp_url "${_ocsp_url}"
# Only process OCSP if URL was present
@@ -203,9 +208,9 @@ haproxy_deploy() {
# Only process the certificate if we have a .issuer file
if [ -r "${_issuer}" ]; then
# Check if issuer cert is also a root CA cert
_subjectdn=$(openssl x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
_subjectdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
_debug _subjectdn "${_subjectdn}"
_issuerdn=$(openssl x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
_issuerdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
_debug _issuerdn "${_issuerdn}"
_info "Requesting OCSP response"
# If the issuer is a CA cert then our command line has "-CAfile" added
@@ -216,7 +221,7 @@ haproxy_deploy() {
fi
_debug _cafile_argument "${_cafile_argument}"
# if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
_openssl_version=$(openssl version | cut -d' ' -f2)
_openssl_version=$(${ACME_OPENSSL_BIN:-openssl} version | cut -d' ' -f2)
_debug _openssl_version "${_openssl_version}"
_openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
_openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
@@ -226,7 +231,7 @@ haproxy_deploy() {
_header_sep=" "
fi
# Request the OCSP response from the issuer and store it
_openssl_ocsp_cmd="openssl ocsp \
_openssl_ocsp_cmd="${ACME_OPENSSL_BIN:-openssl} ocsp \
-issuer \"${_issuer}\" \
-cert \"${_pem}\" \
-url \"${_ocsp_url}\" \
+1 -1
View File
@@ -45,7 +45,7 @@ kong_deploy() {
#Generate data for request (Multipart/form-data with mixed content)
if [ -z "$ssl_uuid" ]; then
#set sni to domain
content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain"
content="--$delim${nl}Content-Disposition: form-data; name=\"snis[]\"${nl}${nl}$_cdomain"
fi
#add key
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
+280
View File
@@ -0,0 +1,280 @@
#!/usr/bin/env sh
# Script for acme.sh to deploy certificates to lighttpd
#
# The following variables can be exported:
#
# export DEPLOY_LIGHTTPD_PEM_NAME="${domain}.pem"
#
# Defines the name of the PEM file.
# Defaults to "<domain>.pem"
#
# export DEPLOY_LIGHTTPD_PEM_PATH="/etc/lighttpd"
#
# Defines location of PEM file for Lighttpd.
# Defaults to /etc/lighttpd
#
# export DEPLOY_LIGHTTPD_RELOAD="systemctl reload lighttpd"
#
# OPTIONAL: Reload command used post deploy
# This defaults to be a no-op (ie "true").
# It is strongly recommended to set this something that makes sense
# for your distro.
#
# export DEPLOY_LIGHTTPD_ISSUER="yes"
#
# OPTIONAL: Places CA file as "${DEPLOY_LIGHTTPD_PEM}.issuer"
# Note: Required for OCSP stapling to work
#
# export DEPLOY_LIGHTTPD_BUNDLE="no"
#
# OPTIONAL: Deploy this certificate as part of a multi-cert bundle
# This adds a suffix to the certificate based on the certificate type
# eg RSA certificates will have .rsa as a suffix to the file name
# Lighttpd will load all certificates and provide one or the other
# depending on client capabilities
# Note: This functionality requires Lighttpd was compiled against
# a version of OpenSSL that supports this.
#
######## Public functions #####################
#domain keyfile certfile cafile fullchain
lighttpd_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
# Some defaults
DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT="/etc/lighttpd"
DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT="${_cdomain}.pem"
DEPLOY_LIGHTTPD_BUNDLE_DEFAULT="no"
DEPLOY_LIGHTTPD_ISSUER_DEFAULT="yes"
DEPLOY_LIGHTTPD_RELOAD_DEFAULT="true"
_debug _cdomain "${_cdomain}"
_debug _ckey "${_ckey}"
_debug _ccert "${_ccert}"
_debug _cca "${_cca}"
_debug _cfullchain "${_cfullchain}"
# PEM_PATH is optional. If not provided then assume "${DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT}"
_getdeployconf DEPLOY_LIGHTTPD_PEM_PATH
_debug2 DEPLOY_LIGHTTPD_PEM_PATH "${DEPLOY_LIGHTTPD_PEM_PATH}"
if [ -n "${DEPLOY_LIGHTTPD_PEM_PATH}" ]; then
Le_Deploy_lighttpd_pem_path="${DEPLOY_LIGHTTPD_PEM_PATH}"
_savedomainconf Le_Deploy_lighttpd_pem_path "${Le_Deploy_lighttpd_pem_path}"
elif [ -z "${Le_Deploy_lighttpd_pem_path}" ]; then
Le_Deploy_lighttpd_pem_path="${DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT}"
fi
# Ensure PEM_PATH exists
if [ -d "${Le_Deploy_lighttpd_pem_path}" ]; then
_debug "PEM_PATH ${Le_Deploy_lighttpd_pem_path} exists"
else
_err "PEM_PATH ${Le_Deploy_lighttpd_pem_path} does not exist"
return 1
fi
# PEM_NAME is optional. If not provided then assume "${DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT}"
_getdeployconf DEPLOY_LIGHTTPD_PEM_NAME
_debug2 DEPLOY_LIGHTTPD_PEM_NAME "${DEPLOY_LIGHTTPD_PEM_NAME}"
if [ -n "${DEPLOY_LIGHTTPD_PEM_NAME}" ]; then
Le_Deploy_lighttpd_pem_name="${DEPLOY_LIGHTTPD_PEM_NAME}"
_savedomainconf Le_Deploy_lighttpd_pem_name "${Le_Deploy_lighttpd_pem_name}"
elif [ -z "${Le_Deploy_lighttpd_pem_name}" ]; then
Le_Deploy_lighttpd_pem_name="${DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT}"
fi
# BUNDLE is optional. If not provided then assume "${DEPLOY_LIGHTTPD_BUNDLE_DEFAULT}"
_getdeployconf DEPLOY_LIGHTTPD_BUNDLE
_debug2 DEPLOY_LIGHTTPD_BUNDLE "${DEPLOY_LIGHTTPD_BUNDLE}"
if [ -n "${DEPLOY_LIGHTTPD_BUNDLE}" ]; then
Le_Deploy_lighttpd_bundle="${DEPLOY_LIGHTTPD_BUNDLE}"
_savedomainconf Le_Deploy_lighttpd_bundle "${Le_Deploy_lighttpd_bundle}"
elif [ -z "${Le_Deploy_lighttpd_bundle}" ]; then
Le_Deploy_lighttpd_bundle="${DEPLOY_LIGHTTPD_BUNDLE_DEFAULT}"
fi
# ISSUER is optional. If not provided then assume "${DEPLOY_LIGHTTPD_ISSUER_DEFAULT}"
_getdeployconf DEPLOY_LIGHTTPD_ISSUER
_debug2 DEPLOY_LIGHTTPD_ISSUER "${DEPLOY_LIGHTTPD_ISSUER}"
if [ -n "${DEPLOY_LIGHTTPD_ISSUER}" ]; then
Le_Deploy_lighttpd_issuer="${DEPLOY_LIGHTTPD_ISSUER}"
_savedomainconf Le_Deploy_lighttpd_issuer "${Le_Deploy_lighttpd_issuer}"
elif [ -z "${Le_Deploy_lighttpd_issuer}" ]; then
Le_Deploy_lighttpd_issuer="${DEPLOY_LIGHTTPD_ISSUER_DEFAULT}"
fi
# RELOAD is optional. If not provided then assume "${DEPLOY_LIGHTTPD_RELOAD_DEFAULT}"
_getdeployconf DEPLOY_LIGHTTPD_RELOAD
_debug2 DEPLOY_LIGHTTPD_RELOAD "${DEPLOY_LIGHTTPD_RELOAD}"
if [ -n "${DEPLOY_LIGHTTPD_RELOAD}" ]; then
Le_Deploy_lighttpd_reload="${DEPLOY_LIGHTTPD_RELOAD}"
_savedomainconf Le_Deploy_lighttpd_reload "${Le_Deploy_lighttpd_reload}"
elif [ -z "${Le_Deploy_lighttpd_reload}" ]; then
Le_Deploy_lighttpd_reload="${DEPLOY_LIGHTTPD_RELOAD_DEFAULT}"
fi
# Set the suffix depending if we are creating a bundle or not
if [ "${Le_Deploy_lighttpd_bundle}" = "yes" ]; then
_info "Bundle creation requested"
# Initialise $Le_Keylength if its not already set
if [ -z "${Le_Keylength}" ]; then
Le_Keylength=""
fi
if _isEccKey "${Le_Keylength}"; then
_info "ECC key type detected"
_suffix=".ecdsa"
else
_info "RSA key type detected"
_suffix=".rsa"
fi
else
_suffix=""
fi
_debug _suffix "${_suffix}"
# Set variables for later
_pem="${Le_Deploy_lighttpd_pem_path}/${Le_Deploy_lighttpd_pem_name}${_suffix}"
_issuer="${_pem}.issuer"
_ocsp="${_pem}.ocsp"
_reload="${Le_Deploy_lighttpd_reload}"
_info "Deploying PEM file"
# Create a temporary PEM file
_temppem="$(_mktemp)"
_debug _temppem "${_temppem}"
cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
_ret="$?"
# Check that we could create the temporary file
if [ "${_ret}" != "0" ]; then
_err "Error code ${_ret} returned during PEM file creation"
[ -f "${_temppem}" ] && rm -f "${_temppem}"
return ${_ret}
fi
# Move PEM file into place
_info "Moving new certificate into place"
_debug _pem "${_pem}"
cat "${_temppem}" >"${_pem}"
_ret=$?
# Clean up temp file
[ -f "${_temppem}" ] && rm -f "${_temppem}"
# Deal with any failure of moving PEM file into place
if [ "${_ret}" != "0" ]; then
_err "Error code ${_ret} returned while moving new certificate into place"
return ${_ret}
fi
# Update .issuer file if requested
if [ "${Le_Deploy_lighttpd_issuer}" = "yes" ]; then
_info "Updating .issuer file"
_debug _issuer "${_issuer}"
cat "${_cca}" >"${_issuer}"
_ret="$?"
if [ "${_ret}" != "0" ]; then
_err "Error code ${_ret} returned while copying issuer/CA certificate into place"
return ${_ret}
fi
else
[ -f "${_issuer}" ] && _err "Issuer file update not requested but .issuer file exists"
fi
# Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option
if [ -z "${Le_OCSP_Staple}" ]; then
Le_OCSP_Staple="0"
fi
if [ "${Le_OCSP_Staple}" = "1" ]; then
_info "Updating OCSP stapling info"
_debug _ocsp "${_ocsp}"
_info "Extracting OCSP URL"
_ocsp_url=$(${ACME_OPENSSL_BIN:-openssl} x509 -noout -ocsp_uri -in "${_pem}")
_debug _ocsp_url "${_ocsp_url}"
# Only process OCSP if URL was present
if [ "${_ocsp_url}" != "" ]; then
# Extract the hostname from the OCSP URL
_info "Extracting OCSP URL"
_ocsp_host=$(echo "${_ocsp_url}" | cut -d/ -f3)
_debug _ocsp_host "${_ocsp_host}"
# Only process the certificate if we have a .issuer file
if [ -r "${_issuer}" ]; then
# Check if issuer cert is also a root CA cert
_subjectdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
_debug _subjectdn "${_subjectdn}"
_issuerdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
_debug _issuerdn "${_issuerdn}"
_info "Requesting OCSP response"
# If the issuer is a CA cert then our command line has "-CAfile" added
if [ "${_subjectdn}" = "${_issuerdn}" ]; then
_cafile_argument="-CAfile \"${_issuer}\""
else
_cafile_argument=""
fi
_debug _cafile_argument "${_cafile_argument}"
# if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
_openssl_version=$(${ACME_OPENSSL_BIN:-openssl} version | cut -d' ' -f2)
_debug _openssl_version "${_openssl_version}"
_openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
_openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
if [ "${_openssl_major}" -eq "1" ] && [ "${_openssl_minor}" -ge "1" ] || [ "${_openssl_major}" -ge "2" ]; then
_header_sep="="
else
_header_sep=" "
fi
# Request the OCSP response from the issuer and store it
_openssl_ocsp_cmd="${ACME_OPENSSL_BIN:-openssl} ocsp \
-issuer \"${_issuer}\" \
-cert \"${_pem}\" \
-url \"${_ocsp_url}\" \
-header Host${_header_sep}\"${_ocsp_host}\" \
-respout \"${_ocsp}\" \
-verify_other \"${_issuer}\" \
${_cafile_argument} \
| grep -q \"${_pem}: good\""
_debug _openssl_ocsp_cmd "${_openssl_ocsp_cmd}"
eval "${_openssl_ocsp_cmd}"
_ret=$?
else
# Non fatal: No issuer file was present so no OCSP stapling file created
_err "OCSP stapling in use but no .issuer file was present"
fi
else
# Non fatal: No OCSP url was found int the certificate
_err "OCSP update requested but no OCSP URL was found in certificate"
fi
# Non fatal: Check return code of openssl command
if [ "${_ret}" != "0" ]; then
_err "Updating OCSP stapling failed with return code ${_ret}"
fi
else
# An OCSP file was already present but certificate did not have OCSP extension
if [ -f "${_ocsp}" ]; then
_err "OCSP was not requested but .ocsp file exists."
# Could remove the file at this step, although Lighttpd just ignores it in this case
# rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file"
fi
fi
# Reload Lighttpd
_debug _reload "${_reload}"
eval "${_reload}"
_ret=$?
if [ "${_ret}" != "0" ]; then
_err "Error code ${_ret} during reload"
return ${_ret}
else
_info "Reload successful"
fi
return 0
}
+16 -12
View File
@@ -20,18 +20,23 @@ mailcow_deploy() {
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_mailcow_path="${DEPLOY_MAILCOW_PATH}"
_getdeployconf DEPLOY_MAILCOW_PATH
_getdeployconf DEPLOY_MAILCOW_RELOAD
if [ -z "$_mailcow_path" ]; then
_debug DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
_debug DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
if [ -z "$DEPLOY_MAILCOW_PATH" ]; then
_err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH."
return 1
fi
#Tests if _ssl_path is the mailcow root directory.
if [ -f "${_mailcow_path}/generate_config.sh" ]; then
_ssl_path="${_mailcow_path}/data/assets/ssl/"
else
_ssl_path="${_mailcow_path}"
_savedeployconf DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
[ -n "$DEPLOY_MAILCOW_RELOAD" ] && _savedeployconf DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
_ssl_path="$DEPLOY_MAILCOW_PATH"
if [ -f "$DEPLOY_MAILCOW_PATH/generate_config.sh" ]; then
_ssl_path="$DEPLOY_MAILCOW_PATH/data/assets/ssl/"
fi
if [ ! -d "$_ssl_path" ]; then
@@ -40,16 +45,15 @@ mailcow_deploy() {
fi
# ECC or RSA
if [ -z "${Le_Keylength}" ]; then
Le_Keylength=""
fi
if _isEccKey "${Le_Keylength}"; then
length=$(_readdomainconf Le_Keylength)
if _isEccKey "$length"; then
_info "ECC key type detected"
_cert_name_prefix="ecdsa-"
else
_info "RSA key type detected"
_cert_name_prefix=""
fi
_info "Copying key and cert"
_real_key="$_ssl_path/${_cert_name_prefix}key.pem"
if ! cat "$_ckey" >"$_real_key"; then
@@ -63,7 +67,7 @@ mailcow_deploy() {
return 1
fi
DEFAULT_MAILCOW_RELOAD="docker restart $(docker ps -qaf name=postfix-mailcow); docker restart $(docker ps -qaf name=nginx-mailcow); docker restart $(docker ps -qaf name=dovecot-mailcow)"
DEFAULT_MAILCOW_RELOAD="docker restart \$(docker ps --quiet --filter name=nginx-mailcow --filter name=dovecot-mailcow)"
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
_info "Run reload: $_reload"
+156
View File
@@ -0,0 +1,156 @@
#!/usr/bin/env sh
# This deploy hook is tested on OpenMediaVault 5.x. It supports both local and remote deployment.
# The way it works is that if a cert with the matching domain name is not found, it will firstly create a dummy cert to get its uuid, and then replace it with your cert.
#
# DEPLOY_OMV_WEBUI_ADMIN - This is OMV web gui admin account. Default value is admin. It's required as the user parameter (-u) for the omv-rpc command.
# DEPLOY_OMV_HOST and DEPLOY_OMV_SSH_USER are optional. They are used for remote deployment through ssh (support public key authentication only). Per design, OMV web gui admin doesn't have ssh permission, so another account is needed for ssh.
#
# returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
openmediavault_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"
_getdeployconf DEPLOY_OMV_WEBUI_ADMIN
if [ -z "$DEPLOY_OMV_WEBUI_ADMIN" ]; then
DEPLOY_OMV_WEBUI_ADMIN="admin"
fi
_savedeployconf DEPLOY_OMV_WEBUI_ADMIN "$DEPLOY_OMV_WEBUI_ADMIN"
_getdeployconf DEPLOY_OMV_HOST
_getdeployconf DEPLOY_OMV_SSH_USER
if [ -n "$DEPLOY_OMV_HOST" ] && [ -n "$DEPLOY_OMV_SSH_USER" ]; then
_info "[OMV deploy-hook] Deploy certificate remotely through ssh."
_savedeployconf DEPLOY_OMV_HOST "$DEPLOY_OMV_HOST"
_savedeployconf DEPLOY_OMV_SSH_USER "$DEPLOY_OMV_SSH_USER"
else
_info "[OMV deploy-hook] Deploy certificate locally."
fi
if [ -n "$DEPLOY_OMV_HOST" ] && [ -n "$DEPLOY_OMV_SSH_USER" ]; then
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'getList' '{\"start\": 0, \"limit\": -1}' | jq -r '.data[] | select(.name==\"/CN='$_cdomain'\") | .uuid'"
# shellcheck disable=SC2029
_uuid=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
_debug _command "$_command"
if [ -z "$_uuid" ]; then
_info "[OMV deploy-hook] Domain $_cdomain has no certificate in openmediavault, creating it!"
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'create' '{\"cn\": \"test.example.com\", \"size\": 4096, \"days\": 3650, \"c\": \"\", \"st\": \"\", \"l\": \"\", \"o\": \"\", \"ou\": \"\", \"email\": \"\"}' | jq -r '.uuid'"
# shellcheck disable=SC2029
_uuid=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
_debug _command "$_command"
if [ -z "$_uuid" ]; then
_err "[OMV deploy-hook] An error occured while creating the certificate"
return 1
fi
fi
_info "[OMV deploy-hook] Domain $_cdomain has uuid: $_uuid"
_fullchain=$(jq <"$_cfullchain" -aRs .)
_key=$(jq <"$_ckey" -aRs .)
_debug _fullchain "$_fullchain"
_debug _key "$_key"
_info "[OMV deploy-hook] Updating key and certificate in openmediavault"
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'set' '{\"uuid\":\"$_uuid\", \"certificate\":$_fullchain, \"privatekey\":$_key, \"comment\":\"acme.sh deployed $(date)\"}'"
# shellcheck disable=SC2029
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
_debug _command "$_command"
_debug _result "$_result"
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'setSettings' \$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'getSettings' | jq -c '.sslcertificateref=\"$_uuid\"')"
# shellcheck disable=SC2029
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
_debug _command "$_command"
_debug _result "$_result"
_info "[OMV deploy-hook] Asking openmediavault to apply changes... (this could take some time, hang in there)"
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'Config' 'applyChanges' '{\"modules\":[], \"force\": false}'"
# shellcheck disable=SC2029
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
_debug _command "$_command"
_debug _result "$_result"
_info "[OMV deploy-hook] Asking nginx to reload"
_command="nginx -s reload"
# shellcheck disable=SC2029
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
_debug _command "$_command"
_debug _result "$_result"
else
# shellcheck disable=SC2086
_uuid=$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'getList' '{"start": 0, "limit": -1}' | jq -r '.data[] | select(.name=="/CN='$_cdomain'") | .uuid')
if [ -z "$_uuid" ]; then
_info "[OMV deploy-hook] Domain $_cdomain has no certificate in openmediavault, creating it!"
# shellcheck disable=SC2086
_uuid=$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'create' '{"cn": "test.example.com", "size": 4096, "days": 3650, "c": "", "st": "", "l": "", "o": "", "ou": "", "email": ""}' | jq -r '.uuid')
if [ -z "$_uuid" ]; then
_err "[OMB deploy-hook] An error occured while creating the certificate"
return 1
fi
fi
_info "[OMV deploy-hook] Domain $_cdomain has uuid: $_uuid"
_fullchain=$(jq <"$_cfullchain" -aRs .)
_key=$(jq <"$_ckey" -aRs .)
_debug _fullchain "$_fullchain"
_debug _key "$_key"
_info "[OMV deploy-hook] Updating key and certificate in openmediavault"
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'set' '{\"uuid\":\"$_uuid\", \"certificate\":$_fullchain, \"privatekey\":$_key, \"comment\":\"acme.sh deployed $(date)\"}'"
_result=$(eval "$_command")
_debug _command "$_command"
_debug _result "$_result"
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'setSettings' \$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'getSettings' | jq -c '.sslcertificateref=\"$_uuid\"')"
_result=$(eval "$_command")
_debug _command "$_command"
_debug _result "$_result"
_info "[OMV deploy-hook] Asking openmediavault to apply changes... (this could take some time, hang in there)"
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'Config' 'applyChanges' '{\"modules\":[], \"force\": false}'"
_result=$(eval "$_command")
_debug _command "$_command"
_debug _result "$_result"
_info "[OMV deploy-hook] Asking nginx to reload"
_command="nginx -s reload"
_result=$(eval "$_command")
_debug _command "$_command"
_debug _result "$_result"
fi
return 0
}
+105 -13
View File
@@ -23,6 +23,7 @@
# ```sh
# export ROUTER_OS_USERNAME=certuser
# export ROUTER_OS_HOST=router.example.com
# export ROUTER_OS_PORT=22
#
# acme.sh --deploy -d ftp.example.com --deploy-hook routeros
# ```
@@ -48,6 +49,16 @@
# One optional thing to do as well is to create a script that updates
# all the required services and run that script in a single command.
#
# To adopt parameters to `scp` and/or `ssh` set the optional
# `ROUTER_OS_SSH_CMD` and `ROUTER_OS_SCP_CMD` variables accordingly,
# see ssh(1) and scp(1) for parameters to those commands.
#
# Example:
# ```ssh
# export ROUTER_OS_SSH_CMD="ssh -i /acme.sh/.ssh/router.example.com -o UserKnownHostsFile=/acme.sh/.ssh/known_hosts"
# export ROUTER_OS_SCP_CMD="scp -i /acme.sh/.ssh/router.example.com -o UserKnownHostsFile=/acme.sh/.ssh/known_hosts"
# ````
#
# returns 0 means success, otherwise error.
######## Public functions #####################
@@ -59,6 +70,7 @@ routeros_deploy() {
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_err_code=0
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
@@ -66,29 +78,70 @@ routeros_deploy() {
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_getdeployconf ROUTER_OS_HOST
if [ -z "$ROUTER_OS_HOST" ]; then
_debug "Using _cdomain as ROUTER_OS_HOST, please set if not correct."
ROUTER_OS_HOST="$_cdomain"
fi
_getdeployconf ROUTER_OS_USERNAME
if [ -z "$ROUTER_OS_USERNAME" ]; then
_err "Need to set the env variable ROUTER_OS_USERNAME"
return 1
fi
_getdeployconf ROUTER_OS_PORT
if [ -z "$ROUTER_OS_PORT" ]; then
_debug "Using default port 22 as ROUTER_OS_PORT, please set if not correct."
ROUTER_OS_PORT=22
fi
_getdeployconf ROUTER_OS_SSH_CMD
if [ -z "$ROUTER_OS_SSH_CMD" ]; then
_debug "Use default ssh setup."
ROUTER_OS_SSH_CMD="ssh -p $ROUTER_OS_PORT"
fi
_getdeployconf ROUTER_OS_SCP_CMD
if [ -z "$ROUTER_OS_SCP_CMD" ]; then
_debug "USe default scp setup."
ROUTER_OS_SCP_CMD="scp -P $ROUTER_OS_PORT"
fi
_getdeployconf ROUTER_OS_ADDITIONAL_SERVICES
if [ -z "$ROUTER_OS_ADDITIONAL_SERVICES" ]; then
_debug "Not enabling additional services"
ROUTER_OS_ADDITIONAL_SERVICES=""
fi
_info "Trying to push key '$_ckey' to router"
scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"
_info "Trying to push cert '$_cfullchain' to router"
scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive \
source=\"## generated by routeros deploy script in acme.sh;\
\n/certificate remove [ find name=$_cdomain.cer_0 ];\
_savedeployconf ROUTER_OS_HOST "$ROUTER_OS_HOST"
_savedeployconf ROUTER_OS_USERNAME "$ROUTER_OS_USERNAME"
_savedeployconf ROUTER_OS_PORT "$ROUTER_OS_PORT"
_savedeployconf ROUTER_OS_SSH_CMD "$ROUTER_OS_SSH_CMD"
_savedeployconf ROUTER_OS_SCP_CMD "$ROUTER_OS_SCP_CMD"
_savedeployconf ROUTER_OS_ADDITIONAL_SERVICES "$ROUTER_OS_ADDITIONAL_SERVICES"
# push key to routeros
if ! _scp_certificate "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"; then
return $_err_code
fi
# push certificate chain to routeros
if ! _scp_certificate "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"; then
return $_err_code
fi
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=$ROUTER_OS_USERNAME \
comment=\"generated by routeros deploy script in acme.sh\" \
source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
\n/certificate remove [ find name=$_cdomain.cer_1 ];\
\n/certificate remove [ find name=$_cdomain.cer_2 ];\
\ndelay 1;\
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
@@ -100,12 +153,51 @@ source=\"## generated by routeros deploy script in acme.sh;\
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
\n\"
"
# shellcheck disable=SC2029
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$DEPLOY_SCRIPT_CMD"
# shellcheck disable=SC2029
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\""
# shellcheck disable=SC2029
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script remove \"LE Cert Deploy - $_cdomain\""
if ! _ssh_remote_cmd "$DEPLOY_SCRIPT_CMD"; then
return $_err_code
fi
if ! _ssh_remote_cmd "/system script run \"LE Cert Deploy - $_cdomain\""; then
return $_err_code
fi
if ! _ssh_remote_cmd "/system script remove \"LE Cert Deploy - $_cdomain\""; then
return $_err_code
fi
return 0
}
# inspired by deploy/ssh.sh
_ssh_remote_cmd() {
_cmd="$1"
_secure_debug "Remote commands to execute: $_cmd"
_info "Submitting sequence of commands to routeros"
# quotations in bash cmd below intended. Squash travis spellcheck error
# shellcheck disable=SC2029
$ROUTER_OS_SSH_CMD "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$_cmd"
_err_code="$?"
if [ "$_err_code" != "0" ]; then
_err "Error code $_err_code returned from routeros"
fi
return $_err_code
}
_scp_certificate() {
_src="$1"
_dst="$2"
_secure_debug "scp '$_src' to '$_dst'"
_info "Push key '$_src' to routeros"
$ROUTER_OS_SCP_CMD "$_src" "$_dst"
_err_code="$?"
if [ "$_err_code" != "0" ]; then
_err "Error code $_err_code returned from scp"
fi
return $_err_code
}
+22 -5
View File
@@ -35,11 +35,6 @@ ssh_deploy() {
_cfullchain="$5"
_deploy_ssh_servers=""
if [ -f "$DOMAIN_CONF" ]; then
# shellcheck disable=SC1090
. "$DOMAIN_CONF"
fi
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
@@ -47,6 +42,8 @@ ssh_deploy() {
_debug _cfullchain "$_cfullchain"
# USER is required to login by SSH to remote host.
_getdeployconf DEPLOY_SSH_USER
_debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
if [ -z "$DEPLOY_SSH_USER" ]; then
if [ -z "$Le_Deploy_ssh_user" ]; then
_err "DEPLOY_SSH_USER not defined."
@@ -58,6 +55,8 @@ ssh_deploy() {
fi
# SERVER is optional. If not provided then use _cdomain
_getdeployconf DEPLOY_SSH_SERVER
_debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
if [ -n "$DEPLOY_SSH_SERVER" ]; then
Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
_savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
@@ -66,6 +65,8 @@ ssh_deploy() {
fi
# CMD is optional. If not provided then use ssh
_getdeployconf DEPLOY_SSH_CMD
_debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
if [ -n "$DEPLOY_SSH_CMD" ]; then
Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
_savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
@@ -74,6 +75,8 @@ ssh_deploy() {
fi
# BACKUP is optional. If not provided then default to previously saved value or yes.
_getdeployconf DEPLOY_SSH_BACKUP
_debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
Le_Deploy_ssh_backup="no"
elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
@@ -82,6 +85,8 @@ ssh_deploy() {
_savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
# BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
_getdeployconf DEPLOY_SSH_BACKUP_PATH
_debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
@@ -91,6 +96,8 @@ ssh_deploy() {
# MULTI_CALL is optional. If not provided then default to previously saved
# value (which may be undefined... equivalent to "no").
_getdeployconf DEPLOY_SSH_MULTI_CALL
_debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
Le_Deploy_ssh_multi_call="yes"
_savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
@@ -141,6 +148,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
# KEYFILE is optional.
# If provided then private key will be copied to provided filename.
_getdeployconf DEPLOY_SSH_KEYFILE
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
_savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
@@ -163,6 +172,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
# CERTFILE is optional.
# If provided then certificate will be copied or appended to provided filename.
_getdeployconf DEPLOY_SSH_CERTFILE
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
_savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
@@ -189,6 +200,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
# CAFILE is optional.
# If provided then CA intermediate certificate will be copied or appended to provided filename.
_getdeployconf DEPLOY_SSH_CAFILE
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
_savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
@@ -216,6 +229,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
# FULLCHAIN is optional.
# If provided then fullchain certificate will be copied or appended to provided filename.
_getdeployconf DEPLOY_SSH_FULLCHAIN
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
_savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
@@ -244,6 +259,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
# REMOTE_CMD is optional.
# If provided then this command will be executed on remote host.
_getdeployconf DEPLOY_SSH_REMOTE_CMD
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
_savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
+21 -3
View File
@@ -2,8 +2,7 @@
# Here is a script to deploy cert to Synology DSM
#
# it requires the jq and curl are in the $PATH and the following
# environment variables must be set:
# It requires following environment variables:
#
# SYNO_Username - Synology Username to login (must be an administrator)
# SYNO_Password - Synology Password to login
@@ -16,6 +15,12 @@
# SYNO_Hostname - defaults to localhost
# SYNO_Port - defaults to 5000
# SYNO_DID - device ID to skip OTP - defaults to empty
# SYNO_TOTP_SECRET - TOTP secret to generate OTP - defaults to empty
#
# Dependencies:
# -------------
# - jq and curl
# - oathtool (When using 2 Factor Authentication and SYNO_TOTP_SECRET is set)
#
#returns 0 means success, otherwise error.
@@ -36,6 +41,7 @@ synology_dsm_deploy() {
_getdeployconf SYNO_Password
_getdeployconf SYNO_Create
_getdeployconf SYNO_DID
_getdeployconf SYNO_TOTP_SECRET
if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then
_err "SYNO_Username & SYNO_Password must be set"
return 1
@@ -86,13 +92,23 @@ synology_dsm_deploy() {
encoded_username="$(printf "%s" "$SYNO_Username" | _url_encode)"
encoded_password="$(printf "%s" "$SYNO_Password" | _url_encode)"
otp_code=""
if [ -n "$SYNO_TOTP_SECRET" ]; then
if _exists oathtool; then
otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)"
else
_err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET"
return 1
fi
fi
if [ -n "$SYNO_DID" ]; then
_H1="Cookie: did=$SYNO_DID"
export _H1
_debug3 H1 "${_H1}"
fi
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes" "$_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=$otp_code" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
_debug3 response "$response"
_debug token "$token"
@@ -100,6 +116,7 @@ synology_dsm_deploy() {
if [ -z "$token" ]; then
_err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
_err "Check your username and password."
_err "If two-factor authentication is enabled for the user, set SYNO_TOTP_SECRET."
return 1
fi
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
@@ -112,6 +129,7 @@ synology_dsm_deploy() {
_savedeployconf SYNO_Username "$SYNO_Username"
_savedeployconf SYNO_Password "$SYNO_Password"
_savedeployconf SYNO_DID "$SYNO_DID"
_savedeployconf SYNO_TOTP_SECRET "$SYNO_TOTP_SECRET"
_info "Getting certificates in Synology DSM"
response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid=$sid" "$_base_url/webapi/entry.cgi")
+202
View File
@@ -0,0 +1,202 @@
#!/usr/bin/env sh
# Here is a scipt to deploy the cert to your TrueNAS using the REST API.
# https://www.truenas.com/docs/hub/additional-topics/api/rest_api.html
#
# Written by Frank Plass github@f-plass.de
# https://github.com/danb35/deploy-freenas/blob/master/deploy_freenas.py
# Thanks to danb35 for your template!
#
# Following environment variables must be set:
#
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
#
# The following environmental variables may be set if you don't like their
# default values:
#
# DEPLOY_TRUENAS_HOSTNAME - defaults to localhost
# DEPLOY_TRUENAS_SCHEME - defaults to http, set alternatively to https
#
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
truenas_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"
_getdeployconf DEPLOY_TRUENAS_APIKEY
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"
# Optional hostname, scheme for TrueNAS
_getdeployconf DEPLOY_TRUENAS_HOSTNAME
_getdeployconf DEPLOY_TRUENAS_SCHEME
# default values for hostname and scheme
[ -n "${DEPLOY_TRUENAS_HOSTNAME}" ] || DEPLOY_TRUENAS_HOSTNAME="localhost"
[ -n "${DEPLOY_TRUENAS_SCHEME}" ] || DEPLOY_TRUENAS_SCHEME="http"
_debug2 DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
_debug2 DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
_debug _api_url "$_api_url"
_H1="Authorization: Bearer $DEPLOY_TRUENAS_APIKEY"
_secure_debug3 _H1 "$_H1"
_info "Testing Connection TrueNAS"
_response=$(_get "$_api_url/system/state")
_info "TrueNAS system state: $_response."
if [ -z "$_response" ]; then
_err "Unable to authenticate to $_api_url."
_err 'Check your connection settings are correct, e.g.'
_err 'DEPLOY_TRUENAS_HOSTNAME="192.168.x.y" or DEPLOY_TRUENAS_HOSTNAME="truenas.example.com".'
_err 'DEPLOY_TRUENAS_SCHEME="https" or DEPLOY_TRUENAS_SCHEME="http".'
_err "Verify your TrueNAS API key is valid and set correctly, e.g. DEPLOY_TRUENAS_APIKEY=xxxx...."
return 1
fi
_savedeployconf DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
_savedeployconf DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
_info "Getting current active certificate from TrueNAS"
_response=$(_get "$_api_url/system/general")
_active_cert_id=$(echo "$_response" | grep -B2 '"name":' | grep 'id' | tr -d -- '"id: ,')
_active_cert_name=$(echo "$_response" | grep '"name":' | sed -n 's/.*: "\(.\{1,\}\)",$/\1/p')
_param_httpsredirect=$(echo "$_response" | grep '"ui_httpsredirect":' | sed -n 's/.*": \(.\{1,\}\),$/\1/p')
_debug Active_UI_Certificate_ID "$_active_cert_id"
_debug Active_UI_Certificate_Name "$_active_cert_name"
_debug Active_UI_http_redirect "$_param_httpsredirect"
if [ "$DEPLOY_TRUENAS_SCHEME" = "http" ] && [ "$_param_httpsredirect" = "true" ]; then
_info "HTTP->HTTPS redirection is enabled"
_info "Setting DEPLOY_TRUENAS_SCHEME to 'https'"
DEPLOY_TRUENAS_SCHEME="https"
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
fi
_info "Uploading new certificate to TrueNAS"
_certname="Letsencrypt_$(_utc_date | tr ' ' '_' | tr -d -- ':')"
_debug3 _certname "$_certname"
_certData="{\"create_type\": \"CERTIFICATE_CREATE_IMPORTED\", \"name\": \"${_certname}\", \"certificate\": \"$(_json_encode <"$_cfullchain")\", \"privatekey\": \"$(_json_encode <"$_ckey")\"}"
_add_cert_result="$(_post "$_certData" "$_api_url/certificate" "" "POST" "application/json")"
_debug3 _add_cert_result "$_add_cert_result"
_info "Fetching list of installed certificates"
_cert_list=$(_get "$_api_url/system/general/ui_certificate_choices")
_cert_id=$(echo "$_cert_list" | grep "$_certname" | sed -n 's/.*"\([0-9]\{1,\}\)".*$/\1/p')
_debug3 _cert_id "$_cert_id"
_info "Current activate certificate ID: $_cert_id"
_activateData="{\"ui_certificate\": \"${_cert_id}\"}"
_activate_result="$(_post "$_activateData" "$_api_url/system/general" "" "PUT" "application/json")"
_debug3 _activate_result "$_activate_result"
_info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
_webdav_list=$(_get "$_api_url/webdav")
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
_info "Updating the WebDAV certificate"
_debug _webdav_cert_id "$_webdav_cert_id"
_webdav_data="{\"certssl\": \"${_cert_id}\"}"
_activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
_info "WebDAV certificate updated successfully"
else
_err "Unable to set WebDAV certificate"
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
return 1
fi
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
else
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
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"
_s3_list=$(_get "$_api_url/s3")
_s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
if [ "$_s3_cert_id" = "$_active_cert_id" ]; then
_info "Updating the S3 certificate"
_debug _s3_cert_id "$_s3_cert_id"
_s3_data="{\"certificate\": \"${_cert_id}\"}"
_activate_s3_cert="$(_post "$_s3_data" "$_api_url/s3" "" "PUT" "application/json")"
_s3_new_cert_id=$(echo "$_activate_s3_cert" | _json_decode | grep '"certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
if [ "$_s3_new_cert_id" -eq "$_cert_id" ]; then
_info "S3 certificate updated successfully"
else
_err "Unable to set S3 certificate"
_debug3 _activate_s3_cert "$_activate_s3_cert"
_debug3 _s3_new_cert_id "$_s3_new_cert_id"
return 1
fi
_debug3 _activate_s3_cert "$_activate_s3_cert"
else
_info "S3 certificate is not configured or is not the same as TrueNAS web UI"
fi
_info "Deleting old certificate"
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
_debug3 _delete_result "$_delete_result"
_info "Reloading TrueNAS web UI"
_restart_UI=$(_get "$_api_url/system/general/ui_restart")
_debug2 _restart_UI "$_restart_UI"
if [ -n "$_add_cert_result" ] && [ -n "$_activate_result" ]; then
return 0
else
_err "Certificate update was not succesful, please try again with --debug"
return 1
fi
}
+16 -5
View File
@@ -56,12 +56,23 @@ vault_deploy() {
export _H1="X-Vault-Token: $VAULT_TOKEN"
if [ -n "$FABIO" ]; then
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
if [ -n "$VAULT_KV_V2" ]; then
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL"
else
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
fi
else
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
if [ -n "$VAULT_KV_V2" ]; then
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem"
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key"
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem"
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem"
else
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
fi
fi
}
+55 -30
View File
@@ -42,11 +42,11 @@ dns_1984hosting_add() {
_debug "Add TXT record $fulldomain with value '$txtvalue'"
value="$(printf '%s' "$txtvalue" | _url_encode)"
url="https://management.1984hosting.com/domains/entry/"
url="https://1984.hosting/domains/entry/"
postdata="entry=new"
postdata="$postdata&type=TXT"
postdata="$postdata&ttl=3600"
postdata="$postdata&ttl=900"
postdata="$postdata&zone=$_domain"
postdata="$postdata&host=$_sub_domain"
postdata="$postdata&rdata=%22$value%22"
@@ -93,20 +93,15 @@ dns_1984hosting_rm() {
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_debug "Delete $fulldomain TXT record"
url="https://management.1984hosting.com/domains"
_htmlget "$url" "$_domain"
_debug2 _response "$_response"
zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+')"
_debug2 zone_id "$zone_id"
if [ -z "$zone_id" ]; then
_err "Error getting zone_id for $1"
url="https://1984.hosting/domains"
if ! _get_zone_id "$url" "$_domain"; then
_err "invalid zone" "$_domain"
return 1
fi
_htmlget "$url/$zone_id" "$_sub_domain"
_htmlget "$url/$_zone_id" "$txtvalue"
_debug2 _response "$_response"
entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')"
_debug2 entry_id "$entry_id"
@@ -135,7 +130,7 @@ dns_1984hosting_rm() {
_1984hosting_login() {
if ! _check_credentials; then return 1; fi
if _check_cookie; then
if _check_cookies; then
_debug "Already logged in"
return 0
fi
@@ -143,16 +138,19 @@ _1984hosting_login() {
_debug "Login to 1984Hosting as user $One984HOSTING_Username"
username=$(printf '%s' "$One984HOSTING_Username" | _url_encode)
password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
url="https://management.1984hosting.com/accounts/checkuserauth/"
url="https://1984.hosting/accounts/checkuserauth/"
response="$(_post "username=$username&password=$password&otpkey=" $url)"
response="$(echo "$response" | _normalizeJson)"
_debug2 response "$response"
if _contains "$response" '"loggedin": true'; then
One984HOSTING_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _tail_n 1 | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
export One984HOSTING_COOKIE
_saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE"
One984HOSTING_SESSIONID_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
One984HOSTING_CSRFTOKEN_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
export One984HOSTING_SESSIONID_COOKIE
export One984HOSTING_CSRFTOKEN_COOKIE
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
return 0
fi
return 1
@@ -169,21 +167,24 @@ _check_credentials() {
return 0
}
_check_cookie() {
One984HOSTING_COOKIE="${One984HOSTING_COOKIE:-$(_readaccountconf_mutable One984HOSTING_COOKIE)}"
if [ -z "$One984HOSTING_COOKIE" ]; then
_debug "No cached cookie found"
_check_cookies() {
One984HOSTING_SESSIONID_COOKIE="${One984HOSTING_SESSIONID_COOKIE:-$(_readaccountconf_mutable One984HOSTING_SESSIONID_COOKIE)}"
One984HOSTING_CSRFTOKEN_COOKIE="${One984HOSTING_CSRFTOKEN_COOKIE:-$(_readaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE)}"
if [ -z "$One984HOSTING_SESSIONID_COOKIE" ] || [ -z "$One984HOSTING_CSRFTOKEN_COOKIE" ]; then
_debug "No cached cookie(s) found"
return 1
fi
_authget "https://management.1984hosting.com/accounts/loginstatus/"
_authget "https://1984.hosting/accounts/loginstatus/"
if _contains "$response" '"ok": true'; then
_debug "Cached cookie still valid"
_debug "Cached cookies still valid"
return 0
fi
_debug "Cached cookie no longer valid"
One984HOSTING_COOKIE=""
_saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE"
_debug "Cached cookies no longer valid"
One984HOSTING_SESSIONID_COOKIE=""
One984HOSTING_CSRFTOKEN_COOKIE=""
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
return 1
}
@@ -203,7 +204,7 @@ _get_root() {
return 1
fi
_authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
_authget "https://1984.hosting/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
if _contains "$_response" "serial" && ! _contains "$_response" "null"; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="$h"
@@ -215,9 +216,25 @@ _get_root() {
return 1
}
#usage: _get_zone_id url domain.com
#returns zone id for domain.com
_get_zone_id() {
url=$1
domain=$2
_htmlget "$url" "$domain"
_debug2 _response "$_response"
_zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+' | _head_n 1)"
_debug2 _zone_id "$_zone_id"
if [ -z "$_zone_id" ]; then
_err "Error getting _zone_id for $2"
return 1
fi
return 0
}
# add extra headers to request
_authget() {
export _H1="Cookie: $One984HOSTING_COOKIE"
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
_response=$(_get "$1" | _normalizeJson)
_debug2 _response "$_response"
}
@@ -225,12 +242,20 @@ _authget() {
# truncate huge HTML response
# echo: Argument list too long
_htmlget() {
export _H1="Cookie: $One984HOSTING_COOKIE"
_response=$(_get "$1" | grep "$2" | _head_n 1)
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
_response=$(_get "$1" | grep "$2")
if _contains "$_response" "@$2"; then
_response=$(echo "$_response" | grep -v "[@]" | _head_n 1)
fi
}
# add extra headers to request
_authpost() {
export _H1="Cookie: $One984HOSTING_COOKIE"
url="https://1984.hosting/domains"
_get_zone_id "$url" "$_domain"
csrf_header="$(echo "$One984HOSTING_CSRFTOKEN_COOKIE" | _egrep_o "=[^=][0-9a-zA-Z]*" | tr -d "=")"
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
export _H2="Referer: https://1984.hosting/domains/$_zone_id"
export _H3="X-CSRFToken: $csrf_header"
_response=$(_post "$1" "$2")
}
Regular → Executable
+51 -12
View File
@@ -1,31 +1,70 @@
#!/usr/bin/env sh
#
#Author: Wolfgang Ebner
#Report Bugs here: https://github.com/webner/acme.sh
#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>"
#
######## Public functions #####################
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_acmedns_add() {
fulldomain=$1
txtvalue=$2
_info "Using acme-dns"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_debug "fulldomain $fulldomain"
_debug "txtvalue $txtvalue"
ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}"
#for compatiblity from account conf
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}"
_clearaccountconf_mutable ACMEDNS_USERNAME
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}"
_clearaccountconf_mutable ACMEDNS_PASSWORD
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}"
_clearaccountconf_mutable ACMEDNS_SUBDOMAIN
if [ "$ACMEDNS_UPDATE_URL" = "" ]; then
ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update"
ACMEDNS_BASE_URL="${ACMEDNS_BASE_URL:-$(_readdomainconf ACMEDNS_BASE_URL)}"
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readdomainconf ACMEDNS_USERNAME)}"
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readdomainconf ACMEDNS_PASSWORD)}"
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readdomainconf ACMEDNS_SUBDOMAIN)}"
if [ "$ACMEDNS_BASE_URL" = "" ]; then
ACMEDNS_BASE_URL="https://auth.acme-dns.io"
fi
_saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL"
_saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME"
_saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD"
_saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN"
ACMEDNS_UPDATE_URL="$ACMEDNS_BASE_URL/update"
ACMEDNS_REGISTER_URL="$ACMEDNS_BASE_URL/register"
if [ -z "$ACMEDNS_USERNAME" ] || [ -z "$ACMEDNS_PASSWORD" ]; then
response="$(_post "" "$ACMEDNS_REGISTER_URL" "" "POST")"
_debug response "$response"
ACMEDNS_USERNAME=$(echo "$response" | sed -n 's/^{.*\"username\":[ ]*\"\([^\"]*\)\".*}/\1/p')
_debug "received username: $ACMEDNS_USERNAME"
ACMEDNS_PASSWORD=$(echo "$response" | sed -n 's/^{.*\"password\":[ ]*\"\([^\"]*\)\".*}/\1/p')
_debug "received password: $ACMEDNS_PASSWORD"
ACMEDNS_SUBDOMAIN=$(echo "$response" | sed -n 's/^{.*\"subdomain\":[ ]*\"\([^\"]*\)\".*}/\1/p')
_debug "received subdomain: $ACMEDNS_SUBDOMAIN"
ACMEDNS_FULLDOMAIN=$(echo "$response" | sed -n 's/^{.*\"fulldomain\":[ ]*\"\([^\"]*\)\".*}/\1/p')
_info "##########################################################"
_info "# Create $fulldomain CNAME $ACMEDNS_FULLDOMAIN DNS entry #"
_info "##########################################################"
_info "Press enter to continue... "
read -r _
fi
_savedomainconf ACMEDNS_BASE_URL "$ACMEDNS_BASE_URL"
_savedomainconf ACMEDNS_USERNAME "$ACMEDNS_USERNAME"
_savedomainconf ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD"
_savedomainconf ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN"
export _H1="X-Api-User: $ACMEDNS_USERNAME"
export _H2="X-Api-Key: $ACMEDNS_PASSWORD"
@@ -48,8 +87,8 @@ dns_acmedns_rm() {
fulldomain=$1
txtvalue=$2
_info "Using acme-dns"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_debug "fulldomain $fulldomain"
_debug "txtvalue $txtvalue"
}
#################### Private functions below ##################################
+1 -1
View File
@@ -32,7 +32,7 @@ dns_aws_add() {
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
AWS_ACCESS_KEY_ID=""
AWS_SECRET_ACCESS_KEY=""
_err "You haven't specifed the aws route53 api key id and and api key secret yet."
_err "You haven't specified the aws route53 api key id and and api key secret yet."
_err "Please create your key and try again. see $(__green $AWS_WIKI)"
return 1
fi
+111 -81
View File
@@ -9,57 +9,72 @@ WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
#
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate
#
dns_azure_add() {
fulldomain=$1
txtvalue=$2
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Subscription ID "
_err "You didn't specify the Azure Subscription ID"
return 1
fi
if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Tenant ID "
return 1
fi
if [ -z "$AZUREDNS_APPID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure App ID"
return 1
fi
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Client Secret"
return 1
fi
#save account details to account conf file.
#save subscription id to account conf file.
_saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID"
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
_info "Using Azure managed identity"
#save managed identity as preferred authentication method, clear service principal credentials from conf file.
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "$AZUREDNS_MANAGEDIDENTITY"
_saveaccountconf_mutable AZUREDNS_TENANTID ""
_saveaccountconf_mutable AZUREDNS_APPID ""
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET ""
else
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Tenant ID "
return 1
fi
if [ -z "$AZUREDNS_APPID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure App ID"
return 1
fi
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Client Secret"
return 1
fi
#save account details to account conf file, don't opt in for azure manages identity check.
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "false"
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
fi
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
_err "invalid domain"
@@ -116,10 +131,6 @@ dns_azure_rm() {
txtvalue=$2
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
@@ -129,34 +140,44 @@ dns_azure_rm() {
return 1
fi
if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Tenant ID "
return 1
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
_info "Using Azure managed identity"
else
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
if [ -z "$AZUREDNS_TENANTID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Tenant ID "
return 1
fi
if [ -z "$AZUREDNS_APPID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure App ID"
return 1
fi
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Client Secret"
return 1
fi
fi
if [ -z "$AZUREDNS_APPID" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure App ID"
return 1
fi
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
AZUREDNS_SUBSCRIPTIONID=""
AZUREDNS_TENANTID=""
AZUREDNS_APPID=""
AZUREDNS_CLIENTSECRET=""
_err "You didn't specify the Azure Client Secret"
return 1
fi
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
_err "invalid domain"
@@ -258,9 +279,10 @@ _azure_rest() {
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
_azure_getaccess_token() {
tenantID=$1
clientID=$2
clientSecret=$3
managedIdentity=$1
tenantID=$2
clientID=$3
clientSecret=$4
accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}"
@@ -278,17 +300,25 @@ _azure_getaccess_token() {
fi
_debug "getting new bearer token"
export _H1="accept: application/json"
export _H2="Content-Type: application/x-www-form-urlencoded"
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
_secure_debug2 "data $body"
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
_ret="$?"
_secure_debug2 "response $response"
response="$(echo "$response" | _normalizeJson)"
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
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
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="$(echo "$response" | _normalizeJson)"
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
else
export _H1="accept: application/json"
export _H2="Content-Type: application/x-www-form-urlencoded"
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
_secure_debug2 "data $body"
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
_ret="$?"
_secure_debug2 "response $response"
response="$(echo "$response" | _normalizeJson)"
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
fi
if [ -z "$accesstoken" ]; then
_err "no acccess token received. Check your Azure settings see $WIKI"
+9 -3
View File
@@ -25,9 +25,15 @@ dns_cf_add() {
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
if [ "$CF_Token" ]; then
_saveaccountconf_mutable CF_Token "$CF_Token"
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
_saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
if [ "$CF_Zone_ID" ]; then
_savedomainconf CF_Token "$CF_Token"
_savedomainconf CF_Account_ID "$CF_Account_ID"
_savedomainconf CF_Zone_ID "$CF_Zone_ID"
else
_saveaccountconf_mutable CF_Token "$CF_Token"
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
_saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
fi
else
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key=""
+24
View File
@@ -2,11 +2,14 @@
# 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"
DOMAIN_TYPE=
DOMAIN_MASTER=
######## Public functions #####################
@@ -61,6 +64,15 @@ dns_cloudns_rm() {
host="$(echo "$1" | sed "s/\.$zone\$//")"
record=$2
_dns_cloudns_get_zone_info "$zone"
_debug "Type" "$DOMAIN_TYPE"
_debug "Cloud Master" "$DOMAIN_MASTER"
if _contains "$DOMAIN_TYPE" "cloud"; then
zone=$DOMAIN_MASTER
fi
_debug "ZONE" "$zone"
_dns_cloudns_http_api_call "dns/records.json" "domain-name=$zone&host=$host&type=TXT"
if ! _contains "$response" "\"id\":"; then
return 1
@@ -134,6 +146,18 @@ _dns_cloudns_init_check() {
return 0
}
_dns_cloudns_get_zone_info() {
zone=$1
_dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zone"
if ! _contains "$response" "\"status\":\"Failed\""; then
DOMAIN_TYPE=$(echo "$response" | _egrep_o '"type":"[^"]*"' | cut -d : -f 2 | tr -d '"')
if _contains "$DOMAIN_TYPE" "cloud"; then
DOMAIN_MASTER=$(echo "$response" | _egrep_o '"cloud-master":"[^"]*"' | cut -d : -f 2 | tr -d '"')
fi
fi
return 0
}
_dns_cloudns_get_zone_name() {
i=2
while true; do
+159
View File
@@ -0,0 +1,159 @@
#!/usr/bin/env sh
#
#Author: Bjarne Saltbaek
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/3732
#
#
######## 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
dns_cpanel_add() {
fulldomain=$1
txtvalue=$2
_info "Adding TXT record to cPanel based system"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
_debug cPanel_Username "$cPanel_Username"
_debug cPanel_Apitoken "$cPanel_Apitoken"
_debug cPanel_Hostname "$cPanel_Hostname"
if ! _cpanel_login; then
_err "cPanel Login failed for user $cPanel_Username. Check $HTTP_HEADER file"
return 1
fi
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "No matching root domain for $fulldomain found"
return 1
fi
# adding entry
_info "Adding the entry"
stripped_fulldomain=$(echo "$fulldomain" | sed "s/.$_domain//")
_debug "Adding $stripped_fulldomain to $_domain zone"
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=add_zone_record&domain=$_domain&name=$stripped_fulldomain&type=TXT&txtdata=$txtvalue&ttl=1"
if _successful_update; then return 0; fi
_err "Couldn't create entry!"
return 1
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
dns_cpanel_rm() {
fulldomain=$1
txtvalue=$2
_info "Using cPanel based system"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _cpanel_login; then
_err "cPanel Login failed for user $cPanel_Username. Check $HTTP_HEADER file"
return 1
fi
if ! _get_root; then
_err "No matching root domain for $fulldomain found"
return 1
fi
_findentry "$fulldomain" "$txtvalue"
if [ -z "$_id" ]; then
_info "Entry doesn't exist, nothing to delete"
return 0
fi
_debug "Deleting record..."
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=remove_zone_record&domain=$_domain&line=$_id"
# removing entry
_debug "_result is: $_result"
if _successful_update; then return 0; fi
_err "Couldn't delete entry!"
return 1
}
#################### Private functions below ##################################
_checkcredentials() {
cPanel_Username="${cPanel_Username:-$(_readaccountconf_mutable cPanel_Username)}"
cPanel_Apitoken="${cPanel_Apitoken:-$(_readaccountconf_mutable cPanel_Apitoken)}"
cPanel_Hostname="${cPanel_Hostname:-$(_readaccountconf_mutable cPanel_Hostname)}"
if [ -z "$cPanel_Username" ] || [ -z "$cPanel_Apitoken" ] || [ -z "$cPanel_Hostname" ]; then
cPanel_Username=""
cPanel_Apitoken=""
cPanel_Hostname=""
_err "You haven't specified cPanel username, apitoken and hostname yet."
_err "Please add credentials and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable cPanel_Username "$cPanel_Username"
_saveaccountconf_mutable cPanel_Apitoken "$cPanel_Apitoken"
_saveaccountconf_mutable cPanel_Hostname "$cPanel_Hostname"
return 0
}
_cpanel_login() {
if ! _checkcredentials; then return 1; fi
if ! _myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=CustInfo&cpanel_jsonapi_func=displaycontactinfo"; then
_err "cPanel login failed for user $cPanel_Username."
return 1
fi
return 0
}
_myget() {
#Adds auth header to request
export _H1="Authorization: cpanel $cPanel_Username:$cPanel_Apitoken"
_result=$(_get "$cPanel_Hostname/$1")
}
_get_root() {
_myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
_domains=$(echo "$_result" | sed 's/.*\(zones.*\[\).*/\1/' | cut -d':' -f2 | sed 's/"//g' | sed 's/{//g')
_debug "_result is: $_result"
_debug "_domains is: $_domains"
if [ -z "$_domains" ]; then
_err "Primary domain list not found!"
return 1
fi
for _domain in $_domains; do
_debug "Checking if $fulldomain ends with $_domain"
if (_endswith "$fulldomain" "$_domain"); then
_debug "Root domain: $_domain"
return 0
fi
done
return 1
}
_successful_update() {
if (echo "$_result" | grep -q 'newserial'); then return 0; fi
return 1
}
_findentry() {
_debug "In _findentry"
#returns id of dns entry, if it exists
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone_records&domain=$_domain"
_id=$(echo "$_result" | sed "s/.*\(line.*$fulldomain.*$txtvalue\).*/\1/" | cut -d ':' -f 2 | cut -d ',' -f 1)
_debug "_result is: $_result"
_debug "fulldomain. is $fulldomain."
_debug "txtvalue is $txtvalue"
_debug "_id is: $_id"
if [ -n "$_id" ]; then
_debug "Entry found with _id=$_id"
return 0
fi
return 1
}
+159
View File
@@ -0,0 +1,159 @@
#!/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
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_ACCESS_TOKEN=""
######## Public functions #####################
#Usage: dns_curanet_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_curanet_add() {
fulldomain=$1
txtvalue=$2
_info "Using curanet"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
CURANET_AUTHCLIENTID="${CURANET_AUTHCLIENTID:-$(_readaccountconf_mutable CURANET_AUTHCLIENTID)}"
CURANET_AUTHSECRET="${CURANET_AUTHSECRET:-$(_readaccountconf_mutable CURANET_AUTHSECRET)}"
if [ -z "$CURANET_AUTHCLIENTID" ] || [ -z "$CURANET_AUTHSECRET" ]; then
CURANET_AUTHCLIENTID=""
CURANET_AUTHSECRET=""
_err "You don't specify curanet api client and secret."
_err "Please create your auth info and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable CURANET_AUTHCLIENTID "$CURANET_AUTHCLIENTID"
_saveaccountconf_mutable CURANET_AUTHSECRET "$CURANET_AUTHSECRET"
if ! _get_token; then
_err "Unable to get token"
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Invalid domain"
return 1
fi
export _H1="Content-Type: application/json-patch+json"
export _H2="Accept: application/json"
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
data="{\"name\": \"$fulldomain\",\"type\": \"TXT\",\"ttl\": 60,\"priority\": 0,\"data\": \"$txtvalue\"}"
response="$(_post "$data" "$CURANET_REST_URL/${_domain}/Records" "" "")"
if _contains "$response" "$txtvalue"; then
_debug "TXT record added OK"
else
_err "Unable to add TXT record"
return 1
fi
return 0
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_curanet_rm() {
fulldomain=$1
txtvalue=$2
_info "Using curanet"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
CURANET_AUTHCLIENTID="${CURANET_AUTHCLIENTID:-$(_readaccountconf_mutable CURANET_AUTHCLIENTID)}"
CURANET_AUTHSECRET="${CURANET_AUTHSECRET:-$(_readaccountconf_mutable CURANET_AUTHSECRET)}"
if ! _get_token; then
_err "Unable to get token"
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Invalid domain"
return 1
fi
_debug "Getting current record list to identify TXT to delete"
export _H1="Content-Type: application/json"
export _H2="Accept: application/json"
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
response="$(_get "$CURANET_REST_URL/${_domain}/Records" "" "")"
if ! _contains "$response" "$txtvalue"; then
_err "Unable to delete record (does not contain $txtvalue )"
return 1
fi
recordid=$(echo "$response" | _egrep_o "{\"id\":[0-9]+,\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":60,\"priority\":0,\"data\":\"..$txtvalue" | _egrep_o "id\":[0-9]+" | cut -c 5-)
if [ -z "$recordid" ]; then
_err "Unable to get recordid"
_debug "regex {\"id\":[0-9]+,\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":60,\"priority\":0,\"data\":\"..$txtvalue"
_debug "response $response"
return 1
fi
_debug "Deleting recordID $recordid"
response="$(_post "" "$CURANET_REST_URL/${_domain}/Records/$recordid" "" "DELETE")"
return 0
}
#################### Private functions below ##################################
_get_token() {
response="$(_post "grant_type=client_credentials&client_id=$CURANET_AUTHCLIENTID&client_secret=$CURANET_AUTHSECRET&scope=dns" "$CURANET_AUTH_URL" "" "")"
if ! _contains "$response" "access_token"; then
_err "Unable get access token"
return 1
fi
CURANET_ACCESS_TOKEN=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]+" | cut -c 17-)
if [ -z "$CURANET_ACCESS_TOKEN" ]; then
_err "Unable to get token"
return 1
fi
return 0
}
#_acme-challenge.www.domain.com
#returns
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
i=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
export _H1="Content-Type: application/json"
export _H2="Accept: application/json"
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
response="$(_get "$CURANET_REST_URL/$h/Records" "" "")"
if [ ! "$(echo "$response" | _egrep_o "Entity not found")" ]; then
_domain=$h
return 0
fi
i=$(_math "$i" + 1)
done
return 1
}
-185
View File
@@ -1,185 +0,0 @@
#!/usr/bin/env sh
# CloudXNS Domain api
#
#CX_Key="1234"
#
#CX_Secret="sADDsdasdgdsf"
CX_Api="https://www.cloudxns.net/api2"
#REST_API
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_cx_add() {
fulldomain=$1
txtvalue=$2
CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}"
CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}"
if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then
CX_Key=""
CX_Secret=""
_err "You don't specify cloudxns.net api key or secret yet."
_err "Please create you key and try again."
return 1
fi
REST_API="$CX_Api"
#save the api key and email to the account conf file.
_saveaccountconf_mutable CX_Key "$CX_Key"
_saveaccountconf_mutable CX_Secret "$CX_Secret"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
add_record "$_domain" "$_sub_domain" "$txtvalue"
}
#fulldomain txtvalue
dns_cx_rm() {
fulldomain=$1
txtvalue=$2
CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}"
CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}"
REST_API="$CX_Api"
if _get_root "$fulldomain"; then
record_id=""
existing_records "$_domain" "$_sub_domain" "$txtvalue"
if [ "$record_id" ]; then
_rest DELETE "record/$record_id/$_domain_id" "{}"
_info "Deleted record ${fulldomain}"
fi
fi
}
#usage: root sub
#return if the sub record already exists.
#echos the existing records count.
# '0' means doesn't exist
existing_records() {
_debug "Getting txt records"
root=$1
sub=$2
if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
return 1
fi
seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}')
_debug seg "$seg"
if [ -z "$seg" ]; then
return 0
fi
if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
_debug record_id "$record_id"
return 0
fi
}
#add the txt record.
#usage: root sub txtvalue
add_record() {
root=$1
sub=$2
txtvalue=$3
fulldomain="$sub.$root"
_info "Adding record"
if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
return 1
fi
return 0
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
i=2
p=1
if ! _rest GET "domain"; then
return 1
fi
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if _contains "$response" "$h."; then
seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}')
_debug seg "$seg"
_domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
_debug _domain_id "$_domain_id"
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_debug _sub_domain "$_sub_domain"
_domain="$h"
_debug _domain "$_domain"
return 0
fi
return 1
fi
p="$i"
i=$(_math "$i" + 1)
done
return 1
}
#Usage: method URI data
_rest() {
m=$1
ep="$2"
_debug ep "$ep"
url="$REST_API/$ep"
_debug url "$url"
cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
_debug cdate "$cdate"
data="$3"
_debug data "$data"
sec="$CX_Key$url$data$cdate$CX_Secret"
_debug sec "$sec"
hmac=$(printf "%s" "$sec" | _digest md5 hex)
_debug hmac "$hmac"
export _H1="API-KEY: $CX_Key"
export _H2="API-REQUEST-DATE: $cdate"
export _H3="API-HMAC: $hmac"
export _H4="Content-Type: application/json"
if [ "$data" ]; then
response="$(_post "$data" "$url" "" "$m")"
else
response="$(_get "$url")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
_contains "$response" '"code":1'
}
+2 -2
View File
@@ -12,7 +12,7 @@
# --
#
DDNSS_DNS_API="https://ip4.ddnss.de/upd.php"
DDNSS_DNS_API="https://ddnss.de/upd.php"
######## Public functions #####################
@@ -77,7 +77,7 @@ dns_ddnss_rm() {
# Now remove the TXT record from DDNS DNS
_info "Trying to remove TXT record"
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=."; then
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=2"; then
if [ "$response" = "Updated 1 hostname." ]; then
_info "TXT record has been successfully removed from your DDNSS domain."
return 0
+87
View File
@@ -0,0 +1,87 @@
#!/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=""
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_dnshome_add() {
txtvalue=$2
DNSHOME_Subdomain="${DNSHOME_Subdomain:-$(_readdomainconf DNSHOME_Subdomain)}"
DNSHOME_SubdomainPassword="${DNSHOME_SubdomainPassword:-$(_readdomainconf DNSHOME_SubdomainPassword)}"
if [ -z "$DNSHOME_Subdomain" ] || [ -z "$DNSHOME_SubdomainPassword" ]; then
DNSHOME_Subdomain=""
DNSHOME_SubdomainPassword=""
_err "Please specify/export your dnsHome.de Subdomain and Password"
return 1
fi
#save the credentials to the account conf file.
_savedomainconf DNSHOME_Subdomain "$DNSHOME_Subdomain"
_savedomainconf DNSHOME_SubdomainPassword "$DNSHOME_SubdomainPassword"
DNSHOME_Api="https://$DNSHOME_Subdomain:$DNSHOME_SubdomainPassword@www.dnshome.de/dyndns.php"
_DNSHOME_rest POST "acme=add&txt=$txtvalue"
if ! echo "$response" | grep 'successfully' >/dev/null; then
_err "Error"
_err "$response"
return 1
fi
return 0
}
# Usage: txtvalue
# Used to remove the txt record after validation
dns_dnshome_rm() {
txtvalue=$2
DNSHOME_Subdomain="${DNSHOME_Subdomain:-$(_readdomainconf DNSHOME_Subdomain)}"
DNSHOME_SubdomainPassword="${DNSHOME_SubdomainPassword:-$(_readdomainconf DNSHOME_SubdomainPassword)}"
DNSHOME_Api="https://$DNSHOME_Subdomain:$DNSHOME_SubdomainPassword@www.dnshome.de/dyndns.php"
if [ -z "$DNSHOME_Subdomain" ] || [ -z "$DNSHOME_SubdomainPassword" ]; then
DNSHOME_Subdomain=""
DNSHOME_SubdomainPassword=""
_err "Please specify/export your dnsHome.de Subdomain and Password"
return 1
fi
_DNSHOME_rest POST "acme=rm&txt=$txtvalue"
if ! echo "$response" | grep 'successfully' >/dev/null; then
_err "Error"
_err "$response"
return 1
fi
return 0
}
#################### Private functions below ##################################
_DNSHOME_rest() {
method=$1
data="$2"
_debug "$data"
_debug data "$data"
response="$(_post "$data" "$DNSHOME_Api" "" "$method")"
if [ "$?" != "0" ]; then
_err "error $data"
return 1
fi
_debug2 response "$response"
return 0
}
+146
View File
@@ -0,0 +1,146 @@
#!/usr/bin/env sh
#Author: Timur Umarov <inbox@tumarov.com>
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
######## Public functions #####################
#Usage: dns_fornex_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_fornex_add() {
fulldomain=$1
txtvalue=$2
if ! _Fornex_API; then
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Unable to determine root domain"
return 1
else
_debug _domain "$_domain"
fi
_info "Adding record"
if _rest POST "$_domain/entry_set/add/" "host=$fulldomain&type=TXT&value=$txtvalue&apikey=$FORNEX_API_KEY"; then
_debug _response "$response"
if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then
_info "Added, OK"
return 0
fi
fi
_err "Add txt record error."
return 1
}
#Usage: dns_fornex_rm _acme-challenge.www.domain.com
dns_fornex_rm() {
fulldomain=$1
txtvalue=$2
if ! _Fornex_API; then
return 1
fi
if ! _get_root "$fulldomain"; then
_err "Unable to determine root domain"
return 1
else
_debug _domain "$_domain"
fi
_debug "Getting txt records"
_rest GET "$_domain/entry_set.json?apikey=$FORNEX_API_KEY"
if ! _contains "$response" "$txtvalue"; then
_err "Txt record not found"
return 1
fi
_record_id="$(echo "$response" | _egrep_o "{[^{]*\"value\"*:*\"$txtvalue\"[^}]*}" | sed -n -e 's#.*"id": \([0-9]*\).*#\1#p')"
_debug "_record_id" "$_record_id"
if [ -z "$_record_id" ]; then
_err "can not find _record_id"
return 1
fi
if ! _rest POST "$_domain/entry_set/$_record_id/delete/" "apikey=$FORNEX_API_KEY"; then
_err "Delete record error."
return 1
fi
return 0
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain=$1
i=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if ! _rest GET "domain_list.json?q=$h&apikey=$FORNEX_API_KEY"; then
return 1
fi
if _contains "$response" "\"$h\"" >/dev/null; then
_domain=$h
return 0
else
_debug "$h not found"
fi
i=$(_math "$i" + 1)
done
return 1
}
_Fornex_API() {
FORNEX_API_KEY="${FORNEX_API_KEY:-$(_readaccountconf_mutable FORNEX_API_KEY)}"
if [ -z "$FORNEX_API_KEY" ]; then
FORNEX_API_KEY=""
_err "You didn't specify the Fornex API key yet."
_err "Please create your key and try again."
return 1
fi
_saveaccountconf_mutable FORNEX_API_KEY "$FORNEX_API_KEY"
}
#method method action data
_rest() {
m=$1
ep="$2"
data="$3"
_debug "$ep"
export _H1="Accept: application/json"
if [ "$m" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "$FORNEX_API_URL/$ep" "" "$m")"
else
response="$(_get "$FORNEX_API_URL/$ep" | _normalizeJson)"
fi
_ret="$?"
if [ "$_ret" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}
+4 -1
View File
@@ -163,5 +163,8 @@ _dns_gcloud_get_rrdatas() {
return 1
fi
ttl=$(echo "$rrdatas" | cut -f1)
rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/","/"\n"/g')
# starting with version 353.0.0 gcloud seems to
# separate records with a semicolon instead of commas
# see also https://cloud.google.com/sdk/docs/release-notes#35300_2021-08-17
rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/"[,;]"/"\n"/g')
}
-177
View File
@@ -1,177 +0,0 @@
#!/usr/bin/env sh
#Author: Herman Sletteng
#Report Bugs here: https://github.com/loial/acme.sh
#
#
# Note, gratisdns requires a login first, so the script needs to handle
# temporary cookies. Since acme.sh _get/_post currently don't directly support
# cookies, I've defined wrapper functions _myget/_mypost to set the headers
GDNSDK_API="https://admin.gratisdns.com"
######## Public functions #####################
#Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_gdnsdk_add() {
fulldomain=$1
txtvalue=$2
_info "Using gratisdns.dk"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _gratisdns_login; then
_err "Login failed!"
return 1
fi
#finding domain zone
if ! _get_domain; then
_err "No matching root domain for $fulldomain found"
return 1
fi
# adding entry
_info "Adding the entry"
_mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1"
if _successful_update; then return 0; fi
_err "Couldn't create entry!"
return 1
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_gdnsdk_rm() {
fulldomain=$1
txtvalue=$2
_info "Using gratisdns.dk"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
if ! _gratisdns_login; then
_err "Login failed!"
return 1
fi
if ! _get_domain; then
_err "No matching root domain for $fulldomain found"
return 1
fi
_findentry "$fulldomain" "$txtvalue"
if [ -z "$_id" ]; then
_info "Entry doesn't exist, nothing to delete"
return 0
fi
_debug "Deleting record..."
_mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id"
# removing entry
if _successful_update; then return 0; fi
_err "Couldn't delete entry!"
return 1
}
#################### Private functions below ##################################
_checkcredentials() {
GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}"
GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}"
if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then
GDNSDK_Username=""
GDNSDK_Password=""
_err "You haven't specified gratisdns.dk username and password yet."
_err "Please add credentials and try again."
return 1
fi
#save the credentials to the account conf file.
_saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username"
_saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password"
return 0
}
_checkcookie() {
GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}"
if [ -z "$GDNSDK_Cookie" ]; then
_debug "No cached cookie found"
return 1
fi
_myget "action="
if (echo "$_result" | grep -q "logmeout"); then
_debug "Cached cookie still valid"
return 0
fi
_debug "Cached cookie no longer valid"
GDNSDK_Cookie=""
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
return 1
}
_gratisdns_login() {
if ! _checkcredentials; then return 1; fi
if _checkcookie; then
_debug "Already logged in"
return 0
fi
_debug "Logging into GratisDNS with user $GDNSDK_Username"
if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then
_err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post"
return 1
fi
GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)"
if [ -z "$GDNSDK_Cookie" ]; then
_err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file"
return 1
fi
export GDNSDK_Cookie
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
return 0
}
_myget() {
#Adds cookie to request
export _H1="Cookie: $GDNSDK_Cookie"
_result=$(_get "$GDNSDK_API?$1")
}
_mypost() {
#Adds cookie to request
export _H1="Cookie: $GDNSDK_Cookie"
_result=$(_post "$1" "$GDNSDK_API")
}
_get_domain() {
_myget 'action=dns_primarydns'
_domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:]._-]+' | sed 's/^.*"//')
if [ -z "$_domains" ]; then
_err "Primary domain list not found!"
return 1
fi
for _domain in $_domains; do
if (_endswith "$fulldomain" "$_domain"); then
_debug "Root domain: $_domain"
return 0
fi
done
return 1
}
_successful_update() {
if (echo "$_result" | grep -q 'table-success'); then return 0; fi
return 1
}
_findentry() {
#args $1: fulldomain, $2: txtvalue
#returns id of dns entry, if it exists
_myget "action=dns_primary_changeDNSsetup&user_domain=$_domain"
_debug3 "_result: $_result"
_tmp_result=$(echo "$_result" | tr -d '\n\r' | _egrep_o "<td>$1</td>\s*<td>$2</td>[^?]*[^&]*&id=[^&]*")
_debug _tmp_result "$_tmp_result"
if [ -z "${_tmp_result:-}" ]; then
_debug "The variable is _tmp_result is not supposed to be empty, there may be something wrong with the script"
fi
_id=$(echo "$_tmp_result" | sed 's/^.*=//')
if [ -n "$_id" ]; then
_debug "Entry found with _id=$_id"
return 0
fi
return 1
}
+232
View File
@@ -0,0 +1,232 @@
#!/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)
#-- dns_geoscaling_add() - Add TXT record --------------------------------------
# Usage: dns_geoscaling_add _acme-challenge.subdomain.domain.com "XyZ123..."
dns_geoscaling_add() {
full_domain=$1
txt_value=$2
_info "Using DNS-01 Geoscaling DNS2 hook"
GEOSCALING_Username="${GEOSCALING_Username:-$(_readaccountconf_mutable GEOSCALING_Username)}"
GEOSCALING_Password="${GEOSCALING_Password:-$(_readaccountconf_mutable GEOSCALING_Password)}"
if [ -z "$GEOSCALING_Username" ] || [ -z "$GEOSCALING_Password" ]; then
GEOSCALING_Username=
GEOSCALING_Password=
_err "No auth details provided. Please set user credentials using the \$GEOSCALING_Username and \$GEOSCALING_Password environment variables."
return 1
fi
_saveaccountconf_mutable GEOSCALING_Username "${GEOSCALING_Username}"
_saveaccountconf_mutable GEOSCALING_Password "${GEOSCALING_Password}"
# Fills in the $zone_id and $zone_name
find_zone "${full_domain}" || return 1
_debug "Zone id '${zone_id}' will be used."
# We're logged in here
# we should add ${full_domain} minus the trailing ${zone_name}
prefix=$(echo "${full_domain}" | sed "s|\\.${zone_name}\$||")
body="id=${zone_id}&name=${prefix}&type=TXT&content=${txt_value}&ttl=300&prio=0"
do_post "$body" "https://www.geoscaling.com/dns2/ajax/add_record.php"
exit_code="$?"
if [ "${exit_code}" -eq 0 ]; then
_info "TXT record added successfully."
else
_err "Couldn't add the TXT record."
fi
do_logout
return "${exit_code}"
}
#-- dns_geoscaling_rm() - Remove TXT record ------------------------------------
# Usage: dns_geoscaling_rm _acme-challenge.subdomain.domain.com "XyZ123..."
dns_geoscaling_rm() {
full_domain=$1
txt_value=$2
_info "Cleaning up after DNS-01 Geoscaling DNS2 hook"
GEOSCALING_Username="${GEOSCALING_Username:-$(_readaccountconf_mutable GEOSCALING_Username)}"
GEOSCALING_Password="${GEOSCALING_Password:-$(_readaccountconf_mutable GEOSCALING_Password)}"
if [ -z "$GEOSCALING_Username" ] || [ -z "$GEOSCALING_Password" ]; then
GEOSCALING_Username=
GEOSCALING_Password=
_err "No auth details provided. Please set user credentials using the \$GEOSCALING_Username and \$GEOSCALING_Password environment variables."
return 1
fi
_saveaccountconf_mutable GEOSCALING_Username "${GEOSCALING_Username}"
_saveaccountconf_mutable GEOSCALING_Password "${GEOSCALING_Password}"
# fills in the $zone_id
find_zone "${full_domain}" || return 1
_debug "Zone id '${zone_id}' will be used."
# Here we're logged in
# Find the record id to clean
# get the domain
response=$(do_get "https://www.geoscaling.com/dns2/index.php?module=domain&id=${zone_id}")
_debug2 "response" "$response"
table="$(echo "${response}" | tr -d '\n' | sed 's|.*<div class="box"><div class="boxtitle">Basic Records</div><div class="boxtext"><table|<table|; s|</table>.*|</table>|')"
_debug2 table "${table}"
names=$(echo "${table}" | _egrep_o 'id="[0-9]+\.name">[^<]*</td>' | sed 's|</td>||; s|.*>||')
ids=$(echo "${table}" | _egrep_o 'id="[0-9]+\.name">[^<]*</td>' | sed 's|\.name">.*||; s|id="||')
types=$(echo "${table}" | _egrep_o 'id="[0-9]+\.type">[^<]*</td>' | sed 's|</td>||; s|.*>||')
values=$(echo "${table}" | _egrep_o 'id="[0-9]+\.content">[^<]*</td>' | sed 's|</td>||; s|.*>||')
_debug2 names "${names}"
_debug2 ids "${ids}"
_debug2 types "${types}"
_debug2 values "${values}"
# look for line whose name is ${full_domain}, whose type is TXT, and whose value is ${txt_value}
line_num="$(echo "${values}" | grep -F -n -- "${txt_value}" | _head_n 1 | cut -d ':' -f 1)"
_debug2 line_num "${line_num}"
found_id=
if [ -n "$line_num" ]; then
type=$(echo "${types}" | sed -n "${line_num}p")
name=$(echo "${names}" | sed -n "${line_num}p")
id=$(echo "${ids}" | sed -n "${line_num}p")
_debug2 type "$type"
_debug2 name "$name"
_debug2 id "$id"
_debug2 full_domain "$full_domain"
if [ "${type}" = "TXT" ] && [ "${name}" = "${full_domain}" ]; then
found_id=${id}
fi
fi
if [ "${found_id}" = "" ]; then
_err "Can not find record id."
return 0
fi
# Remove the record
body="id=${zone_id}&record_id=${found_id}"
response=$(do_post "$body" "https://www.geoscaling.com/dns2/ajax/delete_record.php")
exit_code="$?"
if [ "$exit_code" -eq 0 ]; then
_info "Record removed successfully."
else
_err "Could not clean (remove) up the record. Please go to Geoscaling administration interface and clean it by hand."
fi
do_logout
return "${exit_code}"
}
########################## PRIVATE FUNCTIONS ###########################
do_get() {
_url=$1
export _H1="Cookie: $geoscaling_phpsessid_cookie"
_get "${_url}"
}
do_post() {
_body=$1
_url=$2
export _H1="Cookie: $geoscaling_phpsessid_cookie"
_post "${_body}" "${_url}"
}
do_login() {
_info "Logging in..."
username_encoded="$(printf "%s" "${GEOSCALING_Username}" | _url_encode)"
password_encoded="$(printf "%s" "${GEOSCALING_Password}" | _url_encode)"
body="username=${username_encoded}&password=${password_encoded}"
response=$(_post "$body" "https://www.geoscaling.com/dns2/index.php?module=auth")
_debug2 response "${response}"
#retcode=$(grep '^HTTP[^ ]*' "${HTTP_HEADER}" | _head_n 1 | _egrep_o '[0-9]+$')
retcode=$(grep '^HTTP[^ ]*' "${HTTP_HEADER}" | _head_n 1 | cut -d ' ' -f 2)
if [ "$retcode" != "302" ]; then
_err "Geoscaling login failed for user ${GEOSCALING_Username}. Check ${HTTP_HEADER} file"
return 1
fi
geoscaling_phpsessid_cookie="$(grep -i '^set-cookie:' "${HTTP_HEADER}" | _egrep_o 'PHPSESSID=[^;]*;' | tr -d ';')"
return 0
}
do_logout() {
_info "Logging out."
response="$(do_get "https://www.geoscaling.com/dns2/index.php?module=auth")"
_debug2 response "$response"
return 0
}
find_zone() {
domain="$1"
# do login
do_login || return 1
# get zones
response="$(do_get "https://www.geoscaling.com/dns2/index.php?module=domains")"
table="$(echo "${response}" | tr -d '\n' | sed 's|.*<div class="box"><div class="boxtitle">Your domains</div><div class="boxtext"><table|<table|; s|</table>.*|</table>|')"
_debug2 table "${table}"
zone_names="$(echo "${table}" | _egrep_o '<b>[^<]*</b>' | sed 's|<b>||;s|</b>||')"
_debug2 _matches "${zone_names}"
# Zone names and zone IDs are in same order
zone_ids=$(echo "${table}" | _egrep_o '<a href=.index\.php\?module=domain&id=[0-9]+. onclick="javascript:show_loader\(\);">' | sed 's|.*id=||;s|. .*||')
_debug2 "These are the zones on this Geoscaling account:"
_debug2 "zone_names" "${zone_names}"
_debug2 "And these are their respective IDs:"
_debug2 "zone_ids" "${zone_ids}"
if [ -z "${zone_names}" ] || [ -z "${zone_ids}" ]; then
_err "Can not get zone names or IDs."
return 1
fi
# Walk through all possible zone names
strip_counter=1
while true; do
attempted_zone=$(echo "${domain}" | cut -d . -f ${strip_counter}-)
# All possible zone names have been tried
if [ -z "${attempted_zone}" ]; then
_err "No zone for domain '${domain}' found."
return 1
fi
_debug "Looking for zone '${attempted_zone}'"
line_num="$(echo "${zone_names}" | grep -n "^${attempted_zone}\$" | _head_n 1 | cut -d : -f 1)"
_debug2 line_num "${line_num}"
if [ "$line_num" ]; then
zone_id=$(echo "${zone_ids}" | sed -n "${line_num}p")
zone_name=$(echo "${zone_names}" | sed -n "${line_num}p")
if [ -z "${zone_id}" ]; then
_err "Can not find zone id."
return 1
fi
_debug "Found relevant zone '${attempted_zone}' with id '${zone_id}' - will be used for domain '${domain}'."
return 0
fi
_debug "Zone '${attempted_zone}' doesn't exist, let's try a less specific zone."
strip_counter=$(_math "${strip_counter}" + 1)
done
}
# vim: et:ts=2:sw=2:
+1 -1
View File
@@ -85,7 +85,7 @@ dns_he_rm() {
_debug "The txt record is not found, just skip"
return 0
fi
_record_id="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep "$_txt_value" | cut -d '"' -f 4)"
_record_id="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep -- "$_txt_value" | cut -d '"' -f 4)"
_debug2 _record_id "$_record_id"
if [ -z "$_record_id" ]; then
_err "Can not find record id"
+28 -14
View File
@@ -35,7 +35,7 @@ dns_huaweicloud_add() {
_err "dns_api(dns_huaweicloud): Error getting token."
return 1
fi
_debug "Access token is: ${token}"
_secure_debug "Access token is:" "${token}"
unset zoneid
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
@@ -43,7 +43,7 @@ dns_huaweicloud_add() {
_err "dns_api(dns_huaweicloud): Error getting zone id."
return 1
fi
_debug "Zone ID is: ${zoneid}"
_debug "Zone ID is:" "${zoneid}"
_debug "Adding Record"
_add_record "${token}" "${fulldomain}" "${txtvalue}"
@@ -86,7 +86,7 @@ dns_huaweicloud_rm() {
_err "dns_api(dns_huaweicloud): Error getting token."
return 1
fi
_debug "Access token is: ${token}"
_secure_debug "Access token is:" "${token}"
unset zoneid
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
@@ -94,7 +94,7 @@ dns_huaweicloud_rm() {
_err "dns_api(dns_huaweicloud): Error getting zone id."
return 1
fi
_debug "Zone ID is: ${zoneid}"
_debug "Zone ID is:" "${zoneid}"
# Remove all records
# Therotically HuaweiCloud does not allow more than one record set
@@ -129,14 +129,28 @@ _get_zoneid() {
fi
_debug "$h"
response=$(_get "${dns_api}/v2/zones?name=${h}")
if _contains "${response}" "id"; then
_debug "Get Zone ID Success."
_zoneid=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
printf "%s" "${_zoneid}"
return 0
_debug2 "$response"
if _contains "${response}" '"id"'; then
zoneidlist=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
zonenamelist=$(echo "${response}" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
_debug2 "Return Zone ID(s):" "${zoneidlist}"
_debug2 "Return Zone Name(s):" "${zonenamelist}"
zoneidnum=0
zoneidcount=$(echo "${zoneidlist}" | grep -c '^')
_debug "Retund Zone ID(s) Count:" "${zoneidcount}"
while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do
zoneidnum=$(_math "$zoneidnum" + 1)
_zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p")
zonename=$(echo "${zonenamelist}" | sed -n "${zoneidnum}p")
_debug "Check Zone Name" "${zonename}"
if [ "${zonename}" = "${h}." ]; then
_debug "Get Zone ID Success."
_debug "ZoneID:" "${_zoneid}"
printf "%s" "${_zoneid}"
return 0
fi
done
fi
i=$(_math "$i" + 1)
done
return 1
@@ -149,7 +163,7 @@ _get_recordset_id() {
export _H1="X-Auth-Token: ${_token}"
response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}")
if _contains "${response}" "id"; then
if _contains "${response}" '"id"'; then
_id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")"
printf "%s" "${_id}"
return 0
@@ -197,7 +211,7 @@ _add_record() {
fi
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
_debug "Record Set ID is: ${_record_id}"
_debug "Record Set ID is:" "${_record_id}"
# Remove all records
while [ "${_record_id}" != "0" ]; do
@@ -269,7 +283,7 @@ _get_token() {
_post "${body}" "${iam_api}/v3/auth/tokens" >/dev/null
_code=$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")
_token=$(grep "^X-Subject-Token" "$HTTP_HEADER" | cut -d " " -f 2-)
_debug2 "${_code}"
_secure_debug "${_code}"
printf "%s" "${_token}"
return 0
}
+1 -1
View File
@@ -32,7 +32,7 @@ dns_ispconfig_rm() {
#################### Private functions below ##################################
_ISPC_credentials() {
if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then
if [ -z "${ISPC_User}" ] || [ -z "${ISPC_Password}" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then
ISPC_User=""
ISPC_Password=""
ISPC_Api=""
+4 -2
View File
@@ -19,8 +19,9 @@ dns_knot_add() {
_info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\""
knsupdate -y "${KNOT_KEY}" <<EOF
knsupdate <<EOF
server ${KNOT_SERVER}
key ${KNOT_KEY}
zone ${_domain}.
update add ${fulldomain}. 60 TXT "${txtvalue}"
send
@@ -49,8 +50,9 @@ dns_knot_rm() {
_info "Removing ${fulldomain}. TXT"
knsupdate -y "${KNOT_KEY}" <<EOF
knsupdate <<EOF
server ${KNOT_SERVER}
key ${KNOT_KEY}
zone ${_domain}.
update del ${fulldomain}. TXT
send
+54 -30
View File
@@ -32,8 +32,12 @@ dns_loopia_add() {
_info "Adding record"
_loopia_add_sub_domain "$_domain" "$_sub_domain"
_loopia_add_record "$_domain" "$_sub_domain" "$txtvalue"
if ! _loopia_add_sub_domain "$_domain" "$_sub_domain"; then
return 1
fi
if ! _loopia_add_record "$_domain" "$_sub_domain" "$txtvalue"; then
return 1
fi
}
@@ -70,12 +74,13 @@ dns_loopia_rm() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' "$LOOPIA_User" "$LOOPIA_Password" "$_domain" "$_sub_domain")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$_domain" "$_sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error could not get txt records"
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
_err "Error could not get txt records: $err_response"
return 1
fi
}
@@ -101,6 +106,12 @@ _loopia_load_config() {
return 1
fi
if _contains "$LOOPIA_Password" "'" || _contains "$LOOPIA_Password" '"'; then
_err "Password contains quoute or double quoute and this is not supported by dns_loopia.sh"
return 1
fi
Encoded_Password=$(_xml_encode "$LOOPIA_Password")
return 0
}
@@ -133,11 +144,12 @@ _loopia_get_records() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "<array>"; then
_err "Error"
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
_err "Error: $err_response"
return 1
fi
return 0
@@ -162,7 +174,7 @@ _get_root() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password)
</methodCall>' "$LOOPIA_User" "$Encoded_Password")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
while true; do
@@ -206,32 +218,35 @@ _loopia_add_record() {
<value><string>%s</string></value>
</param>
<param>
<struct>
<member>
<name>type</name>
<value><string>TXT</string></value>
</member>
<member>
<name>priority</name>
<value><int>0</int></value>
</member>
<member>
<name>ttl</name>
<value><int>300</int></value>
</member>
<member>
<name>rdata</name>
<value><string>%s</string></value>
</member>
</struct>
<value>
<struct>
<member>
<name>type</name>
<value><string>TXT</string></value>
</member>
<member>
<name>priority</name>
<value><int>0</int></value>
</member>
<member>
<name>ttl</name>
<value><int>300</int></value>
</member>
<member>
<name>rdata</name>
<value><string>%s</string></value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain" "$txtval")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain" "$txtval")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error"
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
_err "Error: $err_response"
return 1
fi
return 0
@@ -255,7 +270,7 @@ _sub_domain_exists() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
@@ -290,13 +305,22 @@ _loopia_add_sub_domain() {
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "OK"; then
_err "Error"
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
_err "Error: $err_response"
return 1
fi
return 0
}
_xml_encode() {
encoded_string=$1
encoded_string=$(echo "$encoded_string" | sed 's/&/\&amp;/')
encoded_string=$(echo "$encoded_string" | sed 's/</\&lt;/')
encoded_string=$(echo "$encoded_string" | sed 's/>/\&gt;/')
printf "%s" "$encoded_string"
}
+3 -1
View File
@@ -74,7 +74,7 @@ dns_mydevil_rm() {
validRecords="^${num}${w}${fulldomain}${w}TXT${w}${any}${txtvalue}$"
for id in $(devil dns list "$domain" | tail -n+2 | grep "${validRecords}" | cut -w -s -f 1); do
_info "Removing record $id from domain $domain"
devil dns del "$domain" "$id" || _err "Could not remove DNS record."
echo "y" | devil dns del "$domain" "$id" || _err "Could not remove DNS record."
done
}
@@ -87,7 +87,9 @@ mydevil_get_domain() {
domain=""
for domain in $(devil dns list | cut -w -s -f 1 | tail -n+2); do
_debug "Checking domain: $domain"
if _endswith "$fulldomain" "$domain"; then
_debug "Fulldomain '$fulldomain' matches '$domain'"
printf -- "%s" "$domain"
return 0
fi
+261
View File
@@ -0,0 +1,261 @@
#!/usr/bin/env sh
# Mythic Beasts is a long-standing UK service provider using standards-based OAuth2 authentication
# To test: ./acme.sh --dns dns_mythic_beasts --test --debug 1 --output-insecure --issue --domain domain.com
# Cannot retest once cert is issued
# OAuth2 tokens only valid for 300 seconds so we do not store
# NOTE: This will remove all TXT records matching the fulldomain, not just the added ones (_acme-challenge.www.domain.com)
# Test OAuth2 credentials
#MB_AK="aaaaaaaaaaaaaaaa"
#MB_AS="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
# URLs
MB_API='https://api.mythic-beasts.com/dns/v2/zones'
MB_AUTH='https://auth.mythic-beasts.com/login'
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_mythic_beasts_add() {
fulldomain=$1
txtvalue=$2
_info "MYTHIC BEASTS Adding record $fulldomain = $txtvalue"
if ! _initAuth; then
return 1
fi
if ! _get_root "$fulldomain"; then
return 1
fi
# method path body_data
if _mb_rest POST "$_domain/records/$_sub_domain/TXT" "$txtvalue"; then
if _contains "$response" "1 records added"; then
_info "Added, verifying..."
# Max 120 seconds to publish
for i in $(seq 1 6); do
# Retry on error
if ! _mb_rest GET "$_domain/records/$_sub_domain/TXT?verify"; then
_sleep 20
else
_info "Record published!"
return 0
fi
done
else
_err "\n$response"
fi
fi
_err "Add txt record error."
return 1
}
#Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_mythic_beasts_rm() {
fulldomain=$1
txtvalue=$2
_info "MYTHIC BEASTS Removing record $fulldomain = $txtvalue"
if ! _initAuth; then
return 1
fi
if ! _get_root "$fulldomain"; then
return 1
fi
# method path body_data
if _mb_rest DELETE "$_domain/records/$_sub_domain/TXT" "$txtvalue"; then
_info "Record removed"
return 0
fi
_err "Remove txt record error."
return 1
}
#################### Private functions below ##################################
#Possible formats:
# _acme-challenge.www.example.com
# _acme-challenge.example.com
# _acme-challenge.example.co.uk
# _acme-challenge.www.example.co.uk
# _acme-challenge.sub1.sub2.www.example.co.uk
# sub1.sub2.example.co.uk
# example.com
# example.co.uk
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain=$1
i=1
p=1
_debug "Detect the root zone"
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
if [ -z "$h" ]; then
_err "Domain exhausted"
return 1
fi
# Use the status errors to find the domain, continue on 403 Access denied
# method path body_data
_mb_rest GET "$h/records"
ret="$?"
if [ "$ret" -eq 0 ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="$h"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
return 0
elif [ "$ret" -eq 1 ]; then
return 1
fi
p=$i
i=$(_math "$i" + 1)
if [ "$i" -gt 50 ]; then
break
fi
done
_err "Domain too long"
return 1
}
_initAuth() {
MB_AK="${MB_AK:-$(_readaccountconf_mutable MB_AK)}"
MB_AS="${MB_AS:-$(_readaccountconf_mutable MB_AS)}"
if [ -z "$MB_AK" ] || [ -z "$MB_AS" ]; then
MB_AK=""
MB_AS=""
_err "Please specify an OAuth2 Key & Secret"
return 1
fi
_saveaccountconf_mutable MB_AK "$MB_AK"
_saveaccountconf_mutable MB_AS "$MB_AS"
if ! _oauth2; then
return 1
fi
_info "Checking authentication"
_secure_debug access_token "$MB_TK"
_sleep 1
# GET a list of zones
# method path body_data
if ! _mb_rest GET ""; then
_err "The token is invalid"
return 1
fi
_info "Token OK"
return 0
}
# Github appears to use an outbound proxy for requests which means subsequent requests may not have the same
# source IP. The standard Mythic Beasts OAuth2 tokens are tied to an IP, meaning github test requests fail
# authentication. This is a work around using an undocumented MB API to obtain a token not tied to an
# IP just for the github tests.
_oauth2() {
if [ "$GITHUB_ACTIONS" = "true" ]; then
_oauth2_github
else
_oauth2_std
fi
return $?
}
_oauth2_std() {
# HTTP Basic Authentication
_H1="Authorization: Basic $(echo "$MB_AK:$MB_AS" | _base64)"
_H2="Accepts: application/json"
export _H1 _H2
body="grant_type=client_credentials"
_info "Getting OAuth2 token..."
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
response="$(_post "$body" "$MB_AUTH" "" "POST" "application/x-www-form-urlencoded")"
if _contains "$response" "\"token_type\":\"bearer\""; then
MB_TK="$(echo "$response" | _egrep_o "access_token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')"
if [ -z "$MB_TK" ]; then
_err "Unable to get access_token"
_err "\n$response"
return 1
fi
else
_err "OAuth2 token_type not Bearer"
_err "\n$response"
return 1
fi
_debug2 response "$response"
return 0
}
_oauth2_github() {
_H1="Accepts: application/json"
export _H1
body="{\"login\":{\"handle\":\"$MB_AK\",\"pass\":\"$MB_AS\",\"floating\":1}}"
_info "Getting Floating token..."
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
response="$(_post "$body" "$MB_AUTH" "" "POST" "application/json")"
MB_TK="$(echo "$response" | _egrep_o "\"token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')"
if [ -z "$MB_TK" ]; then
_err "Unable to get token"
_err "\n$response"
return 1
fi
_debug2 response "$response"
return 0
}
# method path body_data
_mb_rest() {
# URL encoded body for single API operations
m="$1"
ep="$2"
data="$3"
if [ -z "$ep" ]; then
_mb_url="$MB_API"
else
_mb_url="$MB_API/$ep"
fi
_H1="Authorization: Bearer $MB_TK"
_H2="Accepts: application/json"
export _H1 _H2
if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
response="$(_post "data=$data" "$_mb_url" "" "$m" "application/x-www-form-urlencoded")"
else
response="$(_get "$_mb_url")"
fi
if [ "$?" != "0" ]; then
_err "Request error"
return 1
fi
header="$(cat "$HTTP_HEADER")"
status="$(echo "$header" | _egrep_o "^HTTP[^ ]* .*$" | cut -d " " -f 2-100 | tr -d "\f\n")"
code="$(echo "$status" | _egrep_o "^[0-9]*")"
if [ "$code" -ge 400 ] || _contains "$response" "\"error\"" || _contains "$response" "invalid_client"; then
_err "error $status"
_err "\n$response"
_debug "\n$header"
return 2
fi
_debug2 response "$response"
return 0
}
+4 -4
View File
@@ -119,16 +119,16 @@ login() {
tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST")
sid=$(echo "$tmp" | tr '{}' '\n' | grep apisessionid | cut -d '"' -f 4)
_debug "$tmp"
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$msg"
if [ "$(_getfield "$tmp" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$tmp"
return 1
fi
}
logout() {
tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST")
_debug "$tmp"
if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$msg"
if [ "$(_getfield "$tmp" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then
_err "$tmp"
return 1
fi
}
+1 -1
View File
@@ -114,7 +114,7 @@ _get_root() {
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(echo "$response" | _egrep_o "\"[^\"]*\",\"name\":\"$h" | cut -d , -f 1 | tr -d \")
_domain_id=$(echo "$response" | _egrep_o "\"[^\"]*\",\"name\":\"$h\"" | cut -d , -f 1 | tr -d \")
if [ "$_domain_id" ]; then
if [ "$i" = 1 ]; then
#create the record at the domain apex (@) if only the domain name was provided as --domain-alias
+1 -2
View File
@@ -150,8 +150,7 @@ _get_root() {
return 1
fi
_debug h "$h"
id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":\"[^\"]*\"(,\"allownotifyslave\":{\"\":{[^}]*}},|,)\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2)
id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":{\"[^\"]*\":{[^}]*}},\"transferkeyalgo\":{[^{]*{[^{]*{[^{]*{[^{]*{[^{]*{[^{]*{[^{]*{[^}]*}},\"transferkey\":\"[^\"]*\"(,\"allownotifyslave\":{\"\":{[^}]*}},|,)\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2)
if [ -n "$id" ]; then
_debug id "$id"
_host=$(printf "%s" "$domain" | cut -d . -f 1-$p)
+2
View File
@@ -198,6 +198,8 @@ dns_ovh_rm() {
if ! _ovh_rest DELETE "domain/zone/$_domain/record/$rid"; then
return 1
fi
_ovh_rest POST "domain/zone/$_domain/refresh"
_debug "Refresh:$response"
return 0
fi
done
+3 -2
View File
@@ -7,6 +7,7 @@
RACKSPACE_Endpoint="https://dns.api.rackspacecloud.com/v1.0"
# 20210923 - RS changed the fields in the API response; fix sed
# 20190213 - The name & id fields swapped in the API response; fix sed
# 20190101 - Duplicating file for new pull request to dev branch
# Original - tcocca:rackspace_dnsapi https://github.com/acmesh-official/acme.sh/pull/1297
@@ -79,8 +80,8 @@ _get_root_zone() {
_debug2 response "$response"
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
# Response looks like:
# {"ttl":300,"accountId":12345,"id":1111111,"name":"example.com","emailAddress": ...<and so on>
_domain_id=$(echo "$response" | sed -n "s/^.*\"id\":\([^,]*\),\"name\":\"$h\",.*/\1/p")
# {"id":"12345","accountId":"1111111","name": "example.com","ttl":3600,"emailAddress": ... <and so on>
_domain_id=$(echo "$response" | sed -n "s/^.*\"id\":\"\([^,]*\)\",\"accountId\":\"[0-9]*\",\"name\":\"$h\",.*/\1/p")
_debug2 domain_id "$_domain_id"
if [ -n "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
+3 -2
View File
@@ -92,9 +92,10 @@ _get_root() {
domains_list=$(echo "${response}" | grep dname | sed -r "s/.*dname=\"([^\"]+)\".*/\\1/g")
for ITEM in ${domains_list}; do
IDN_ITEM="$(_idn "${ITEM}")"
case "${domain}" in
*${ITEM}*)
_domain=${ITEM}
*${IDN_ITEM}*)
_domain=${IDN_ITEM}
_debug _domain "${_domain}"
return 0
;;
+23 -15
View File
@@ -1,15 +1,15 @@
#!/usr/bin/env sh
#
# API-integration for Simply.com (https://www.simply.com)
#SIMPLY_AccountName="accountname"
#
#SIMPLY_ApiKey="apikey"
#
#SIMPLY_Api="https://api.simply.com/1/[ACCOUNTNAME]/[APIKEY]"
SIMPLY_Api_Default="https://api.simply.com/1"
#SIMPLY_Api="https://api.simply.com/2/"
SIMPLY_Api_Default="https://api.simply.com/2"
#This is used for determining success of REST call
SIMPLY_SUCCESS_CODE='"status": 200'
SIMPLY_SUCCESS_CODE='"status":200'
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
@@ -51,7 +51,7 @@ dns_simply_rm() {
_simply_save_config
_debug "First detect the root zone"
_debug "Find the DNS zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
@@ -77,8 +77,8 @@ dns_simply_rm() {
for record in $records; do
_debug record "$record"
record_data=$(echo "$record" | cut -d "," -f 3 | sed 's/"//g' | grep "data" | cut -d ":" -f 2)
record_type=$(echo "$record" | cut -d "," -f 4 | sed 's/"//g' | grep "type" | cut -d ":" -f 2)
record_data=$(echo "$record" | sed -n "s/.*\"data\":\"\([^\"]*\)\".*/\1/p")
record_type=$(echo "$record" | sed -n "s/.*\"type\":\"\([^\"]*\)\".*/\1/p")
_debug2 record_data "$record_data"
_debug2 record_type "$record_type"
@@ -151,7 +151,7 @@ _simply_save_config() {
_simply_get_all_records() {
domain=$1
if ! _simply_rest GET "my/products/$domain/dns/records"; then
if ! _simply_rest GET "my/products/$domain/dns/records/"; then
return 1
fi
@@ -169,7 +169,7 @@ _get_root() {
return 1
fi
if ! _simply_rest GET "my/products/$h/dns"; then
if ! _simply_rest GET "my/products/$h/dns/"; then
return 1
fi
@@ -193,7 +193,7 @@ _simply_add_record() {
data="{\"name\": \"$sub_domain\", \"type\":\"TXT\", \"data\": \"$txtval\", \"priority\":0, \"ttl\": 3600}"
if ! _simply_rest POST "my/products/$domain/dns/records" "$data"; then
if ! _simply_rest POST "my/products/$domain/dns/records/" "$data"; then
_err "Adding record not successfull!"
return 1
fi
@@ -214,7 +214,7 @@ _simply_delete_record() {
_debug record_id "Delete record with id $record_id"
if ! _simply_rest DELETE "my/products/$domain/dns/records/$record_id"; then
if ! _simply_rest DELETE "my/products/$domain/dns/records/$record_id/"; then
_err "Deleting record not successfull!"
return 1
fi
@@ -237,12 +237,18 @@ _simply_rest() {
_debug2 ep "$ep"
_debug2 m "$m"
export _H1="Content-Type: application/json"
basicauth=$(printf "%s:%s" "$SIMPLY_AccountName" "$SIMPLY_ApiKey" | _base64)
if [ "$basicauth" ]; then
export _H1="Authorization: Basic $basicauth"
fi
export _H2="Content-Type: application/json"
if [ "$m" != "GET" ]; then
response="$(_post "$data" "$SIMPLY_Api/$SIMPLY_AccountName/$SIMPLY_ApiKey/$ep" "" "$m")"
response="$(_post "$data" "$SIMPLY_Api/$ep" "" "$m")"
else
response="$(_get "$SIMPLY_Api/$SIMPLY_AccountName/$SIMPLY_ApiKey/$ep")"
response="$(_get "$SIMPLY_Api/$ep")"
fi
if [ "$?" != "0" ]; then
@@ -250,6 +256,8 @@ _simply_rest() {
return 1
fi
response="$(echo "$response" | _normalizeJson)"
_debug2 response "$response"
if _contains "$response" "Invalid account authorization"; then
+160
View File
@@ -0,0 +1,160 @@
#!/usr/bin/env sh
# united-domains Reselling (https://www.ud-reselling.com/) DNS API
# Author: Andreas Scherer (https://github.com/andischerer)
# Created: 2021-02-01
#
# Set the environment variables as below:
#
# export UDR_USER="your_username_goes_here"
# export UDR_PASS="some_password_goes_here"
#
UDR_API="https://api.domainreselling.de/api/call.cgi"
UDR_TTL="30"
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "some_long_string_of_characters_go_here_from_lets_encrypt"
dns_udr_add() {
fulldomain=$1
txtvalue=$2
UDR_USER="${UDR_USER:-$(_readaccountconf_mutable UDR_USER)}"
UDR_PASS="${UDR_PASS:-$(_readaccountconf_mutable UDR_PASS)}"
if [ -z "$UDR_USER" ] || [ -z "$UDR_PASS" ]; then
UDR_USER=""
UDR_PASS=""
_err "You didn't specify an UD-Reselling username and password yet"
return 1
fi
# save the username and password to the account conf file.
_saveaccountconf_mutable UDR_USER "$UDR_USER"
_saveaccountconf_mutable UDR_PASS "$UDR_PASS"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _dnszone "${_dnszone}"
_debug "Getting txt records"
if ! _udr_rest "QueryDNSZoneRRList" "dnszone=${_dnszone}"; then
return 1
fi
rr="${fulldomain}. ${UDR_TTL} IN TXT ${txtvalue}"
_debug resource_record "${rr}"
if _contains "$response" "$rr" >/dev/null; then
_err "Error, it would appear that this record already exists. Please review existing TXT records for this domain."
return 1
fi
_info "Adding record"
if ! _udr_rest "UpdateDNSZone" "dnszone=${_dnszone}&addrr0=${rr}"; then
_err "Adding the record did not succeed, please verify/check."
return 1
fi
_info "Added, OK"
return 0
}
dns_udr_rm() {
fulldomain=$1
txtvalue=$2
UDR_USER="${UDR_USER:-$(_readaccountconf_mutable UDR_USER)}"
UDR_PASS="${UDR_PASS:-$(_readaccountconf_mutable UDR_PASS)}"
if [ -z "$UDR_USER" ] || [ -z "$UDR_PASS" ]; then
UDR_USER=""
UDR_PASS=""
_err "You didn't specify an UD-Reselling username and password yet"
return 1
fi
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _dnszone "${_dnszone}"
_debug "Getting txt records"
if ! _udr_rest "QueryDNSZoneRRList" "dnszone=${_dnszone}"; then
return 1
fi
rr="${fulldomain}. ${UDR_TTL} IN TXT ${txtvalue}"
_debug resource_record "${rr}"
if _contains "$response" "$rr" >/dev/null; then
if ! _udr_rest "UpdateDNSZone" "dnszone=${_dnszone}&delrr0=${rr}"; then
_err "Deleting the record did not succeed, please verify/check."
return 1
fi
_info "Removed, OK"
return 0
else
_info "Text record is not present, will not delete anything."
return 0
fi
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain=$1
i=1
if ! _udr_rest "QueryDNSZoneList" ""; then
return 1
fi
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if _contains "${response}" "${h}." >/dev/null; then
_dnszone=$(echo "$response" | _egrep_o "${h}")
if [ "$_dnszone" ]; then
return 0
fi
return 1
fi
i=$(_math "$i" + 1)
done
return 1
}
_udr_rest() {
if [ -n "$2" ]; then
data="command=$1&$2"
else
data="command=$1"
fi
_debug data "${data}"
response="$(_post "${data}" "${UDR_API}?s_login=${UDR_USER}&s_pw=${UDR_PASS}" "" "POST")"
_code=$(echo "$response" | _egrep_o "code = ([0-9]+)" | _head_n 1 | cut -d = -f 2 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
_description=$(echo "$response" | _egrep_o "description = .*" | _head_n 1 | cut -d = -f 2 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
_debug response_code "$_code"
_debug response_description "$_description"
if [ ! "$_code" = "200" ]; then
_err "DNS-API-Error: $_description"
return 1
fi
return 0
}
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env sh
# bug reports to stepan@plyask.in
#
# export VEESP_User="username"
# export VEESP_Password="password"
VEESP_Api="https://secure.veesp.com/api"
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_veesp_add() {
fulldomain=$1
txtvalue=$2
VEESP_Password="${VEESP_Password:-$(_readaccountconf_mutable VEESP_Password)}"
VEESP_User="${VEESP_User:-$(_readaccountconf_mutable VEESP_User)}"
VEESP_auth=$(printf "%s" "$VEESP_User:$VEESP_Password" | _base64)
if [ -z "$VEESP_Password" ] || [ -z "$VEESP_User" ]; then
VEESP_Password=""
VEESP_User=""
_err "You don't specify veesp api key and email yet."
_err "Please create you key and try again."
return 1
fi
#save the api key and email to the account conf file.
_saveaccountconf_mutable VEESP_Password "$VEESP_Password"
_saveaccountconf_mutable VEESP_User "$VEESP_User"
_debug "First 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"
_info "Adding record"
if VEESP_rest POST "service/$_service_id/dns/$_domain_id/records" "{\"name\":\"$fulldomain\",\"ttl\":1,\"priority\":0,\"type\":\"TXT\",\"content\":\"$txtvalue\"}"; then
if _contains "$response" "\"success\":true"; then
_info "Added"
#todo: check if the record takes effect
return 0
else
_err "Add txt record error."
return 1
fi
fi
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
dns_veesp_rm() {
fulldomain=$1
txtvalue=$2
VEESP_Password="${VEESP_Password:-$(_readaccountconf_mutable VEESP_Password)}"
VEESP_User="${VEESP_User:-$(_readaccountconf_mutable VEESP_User)}"
VEESP_auth=$(printf "%s" "$VEESP_User:$VEESP_Password" | _base64)
_debug "First 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"
_debug "Getting txt records"
VEESP_rest GET "service/$_service_id/dns/$_domain_id"
count=$(printf "%s\n" "$response" | _egrep_o "\"type\":\"TXT\",\"content\":\".\"$txtvalue.\"\"" | wc -l | tr -d " ")
_debug count "$count"
if [ "$count" = "0" ]; then
_info "Don't need to remove."
else
record_id=$(printf "%s\n" "$response" | _egrep_o "{\"id\":[^}]*\"type\":\"TXT\",\"content\":\".\"$txtvalue.\"\"" | cut -d\" -f4)
_debug "record_id" "$record_id"
if [ -z "$record_id" ]; then
_err "Can not get record id to remove."
return 1
fi
if ! VEESP_rest DELETE "service/$_service_id/dns/$_domain_id/records/$record_id"; then
_err "Delete record error."
return 1
fi
_contains "$response" "\"success\":true"
fi
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
i=2
p=1
if ! VEESP_rest GET "dns"; then
return 1
fi
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if _contains "$response" "\"name\":\"$h\""; then
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\"domain_id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1 | cut -d '"' -f 2)
_debug _domain_id "$_domain_id"
_service_id=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$h\",\"service_id\":[^}]*" | cut -d : -f 3 | cut -d '"' -f 2)
_debug _service_id "$_service_id"
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain="$h"
return 0
fi
return 1
fi
p=$i
i=$(_math "$i" + 1)
done
return 1
}
VEESP_rest() {
m=$1
ep="$2"
data="$3"
_debug "$ep"
export _H1="Accept: application/json"
export _H2="Authorization: Basic $VEESP_auth"
if [ "$m" != "GET" ]; then
_debug data "$data"
export _H3="Content-Type: application/json"
response="$(_post "$data" "$VEESP_Api/$ep" "" "$m")"
else
response="$(_get "$VEESP_Api/$ep")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}
+17 -25
View File
@@ -24,7 +24,7 @@ dns_world4you_add() {
fi
export _H1="Cookie: W4YSESSID=$sessid"
form=$(_get "$WORLD4YOU_API/dashboard/paketuebersicht")
form=$(_get "$WORLD4YOU_API/")
_get_paketnr "$fqdn" "$form"
paketnr="$PAKETNR"
if [ -z "$paketnr" ]; then
@@ -36,7 +36,6 @@ dns_world4you_add() {
export _H1="Cookie: W4YSESSID=$sessid"
form=$(_get "$WORLD4YOU_API/$paketnr/dns")
formiddp=$(echo "$form" | grep 'AddDnsRecordForm\[uniqueFormIdDP\]' | sed 's/^.*name="AddDnsRecordForm\[uniqueFormIdDP\]" value="\([^"]*\)".*$/\1/')
formidttl=$(echo "$form" | grep 'AddDnsRecordForm\[uniqueFormIdTTL\]' | sed 's/^.*name="AddDnsRecordForm\[uniqueFormIdTTL\]" value="\([^"]*\)".*$/\1/')
form_token=$(echo "$form" | grep 'AddDnsRecordForm\[_token\]' | sed 's/^.*name="AddDnsRecordForm\[_token\]" value="\([^"]*\)".*$/\1/')
if [ -z "$formiddp" ]; then
_err "Unable to parse form"
@@ -45,9 +44,7 @@ dns_world4you_add() {
_resethttp
export ACME_HTTP_NO_REDIRECTS=1
body="AddDnsRecordForm[name]=$RECORD&AddDnsRecordForm[dnsType][type]=TXT&\
AddDnsRecordForm[value]=$value&AddDnsRecordForm[aktivPaket]=$paketnr&AddDnsRecordForm[uniqueFormIdDP]=$formiddp&\
AddDnsRecordForm[uniqueFormIdTTL]=$formidttl&AddDnsRecordForm[_token]=$form_token"
body="AddDnsRecordForm[name]=$RECORD&AddDnsRecordForm[dnsType][type]=TXT&AddDnsRecordForm[value]=$value&AddDnsRecordForm[uniqueFormIdDP]=$formiddp&AddDnsRecordForm[_token]=$form_token"
_info "Adding record..."
ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/dns" '' POST 'application/x-www-form-urlencoded')
_resethttp
@@ -57,15 +54,14 @@ AddDnsRecordForm[uniqueFormIdTTL]=$formidttl&AddDnsRecordForm[_token]=$form_toke
if _contains "$res" "successfully"; then
return 0
else
msg=$(echo "$res" | tr '\n' '\t' | sed 's/.*<h3 class="mb-5">[^\t]*\t *\([^\t]*\)\t.*/\1/')
if _contains "$msg" '^<\!DOCTYPE html>'; then
msg='Unknown error'
fi
_err "Unable to add record: $msg"
if _contains "$msg" '^<\!DOCTYPE html>'; then
msg=$(echo "$res" | grep -A 15 'data-type="danger"' | grep "<h3[^>]*>[^<]" | sed 's/<[^>]*>\|^\s*//g')
if [ "$msg" = '' ]; then
_err "Unable to add record: Unknown error"
echo "$ret" >'error-01.html'
echo "$res" >'error-02.html'
_err "View error-01.html and error-02.html for debugging"
else
_err "Unable to add record: my.world4you.com: $msg"
fi
return 1
fi
@@ -90,7 +86,7 @@ dns_world4you_rm() {
fi
export _H1="Cookie: W4YSESSID=$sessid"
form=$(_get "$WORLD4YOU_API/dashboard/paketuebersicht")
form=$(_get "$WORLD4YOU_API/")
_get_paketnr "$fqdn" "$form"
paketnr="$PAKETNR"
if [ -z "$paketnr" ]; then
@@ -101,7 +97,6 @@ dns_world4you_rm() {
form=$(_get "$WORLD4YOU_API/$paketnr/dns")
formiddp=$(echo "$form" | grep 'DeleteDnsRecordForm\[uniqueFormIdDP\]' | sed 's/^.*name="DeleteDnsRecordForm\[uniqueFormIdDP\]" value="\([^"]*\)".*$/\1/')
formidttl=$(echo "$form" | grep 'DeleteDnsRecordForm\[uniqueFormIdTTL\]' | sed 's/^.*name="DeleteDnsRecordForm\[uniqueFormIdTTL\]" value="\([^"]*\)".*$/\1/')
form_token=$(echo "$form" | grep 'DeleteDnsRecordForm\[_token\]' | sed 's/^.*name="DeleteDnsRecordForm\[_token\]" value="\([^"]*\)".*$/\1/')
if [ -z "$formiddp" ]; then
_err "Unable to parse form"
@@ -113,11 +108,9 @@ dns_world4you_rm() {
_resethttp
export ACME_HTTP_NO_REDIRECTS=1
body="DeleteDnsRecordForm[recordId]=$recordid&DeleteDnsRecordForm[aktivPaket]=$paketnr&\
DeleteDnsRecordForm[uniqueFormIdDP]=$formiddp&DeleteDnsRecordForm[uniqueFormIdTTL]=$formidttl&\
DeleteDnsRecordForm[_token]=$form_token"
body="DeleteDnsRecordForm[recordId]=$recordid&DeleteDnsRecordForm[uniqueFormIdDP]=$formiddp&DeleteDnsRecordForm[_token]=$form_token"
_info "Removing record..."
ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/deleteRecord" '' POST 'application/x-www-form-urlencoded')
ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/dns/record/delete" '' POST 'application/x-www-form-urlencoded')
_resethttp
if _contains "$(_head_n 3 <"$HTTP_HEADER")" '302'; then
@@ -125,15 +118,14 @@ DeleteDnsRecordForm[_token]=$form_token"
if _contains "$res" "successfully"; then
return 0
else
msg=$(echo "$res" | tr '\n' '\t' | sed 's/.*<h3 class="mb-5">[^\t]*\t *\([^\t]*\)\t.*/\1/')
if _contains "$msg" '^<\!DOCTYPE html>'; then
msg='Unknown error'
fi
_err "Unable to remove record: $msg"
if _contains "$msg" '^<\!DOCTYPE html>'; then
msg=$(echo "$res" | grep -A 15 'data-type="danger"' | grep "<h3[^>]*>[^<]" | sed 's/<[^>]*>\|^\s*//g')
if [ "$msg" = '' ]; then
_err "Unable to remove record: Unknown error"
echo "$ret" >'error-01.html'
echo "$res" >'error-02.html'
_err "View error-01.html and error-02.html for debugging"
else
_err "Unable to remove record: my.world4you.com: $msg"
fi
return 1
fi
@@ -190,7 +182,7 @@ _get_paketnr() {
fqdn="$1"
form="$2"
domains=$(echo "$form" | grep '^ *[A-Za-z0-9_\.-]*\.[A-Za-z0-9_-]*$' | sed 's/^\s*\(\S*\)$/\1/')
domains=$(echo "$form" | grep 'header-paket-domain' | sed 's/<[^>]*>//g' | sed 's/^.*>\([^>]*\)$/\1/')
domain=''
for domain in $domains; do
if _contains "$fqdn" "$domain\$"; then
@@ -205,6 +197,6 @@ _get_paketnr() {
TLD="$domain"
_debug domain "$domain"
RECORD=$(echo "$fqdn" | cut -c"1-$((${#fqdn} - ${#TLD} - 1))")
PAKETNR=$(echo "$form" | grep "data-textfilter=\".* $domain " | _head_n 1 | sed 's/^.* \([0-9]*\) .*$/\1/')
PAKETNR=$(echo "$form" | grep "data-textfilter=\".* $domain " | _tail_n 1 | sed "s|.*$WORLD4YOU_API/\\([0-9]*\\)/.*|\\1|")
return 0
}
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env sh
#Support iOS Bark Notification
#BARK_API_URL="https://api.day.app/xxxx"
#BARK_SOUND="yyyy"
#BARK_GROUP="zzzz"
# subject content statusCode
bark_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_subject" "$_subject"
_debug "_content" "$_content"
_debug "_statusCode" "$_statusCode"
BARK_API_URL="${BARK_API_URL:-$(_readaccountconf_mutable BARK_API_URL)}"
if [ -z "$BARK_API_URL" ]; then
BARK_API_URL=""
_err "You didn't specify a Bark API URL BARK_API_URL yet."
_err "You can download Bark from App Store and get yours."
return 1
fi
_saveaccountconf_mutable BARK_API_URL "$BARK_API_URL"
BARK_SOUND="${BARK_SOUND:-$(_readaccountconf_mutable BARK_SOUND)}"
_saveaccountconf_mutable BARK_SOUND "$BARK_SOUND"
BARK_GROUP="${BARK_GROUP:-$(_readaccountconf_mutable BARK_GROUP)}"
if [ -z "$BARK_GROUP" ]; then
BARK_GROUP="ACME"
_info "The BARK_GROUP is not set, so use the default ACME as group name."
else
_saveaccountconf_mutable BARK_GROUP "$BARK_GROUP"
fi
_content=$(echo "$_content" | _url_encode)
_subject=$(echo "$_subject" | _url_encode)
response="$(_get "$BARK_API_URL/$_subject/$_content?sound=$BARK_SOUND&group=$BARK_GROUP")"
if [ "$?" = "0" ] && _contains "$response" "success"; then
_info "Bark API fired success."
return 0
fi
_err "Bark API fired error."
_err "$response"
return 1
}
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env sh
#Support Discord webhooks
# Required:
#DISCORD_WEBHOOK_URL=""
# Optional:
#DISCORD_USERNAME=""
#DISCORD_AVATAR_URL=""
discord_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_statusCode" "$_statusCode"
DISCORD_WEBHOOK_URL="${DISCORD_WEBHOOK_URL:-$(_readaccountconf_mutable DISCORD_WEBHOOK_URL)}"
if [ -z "$DISCORD_WEBHOOK_URL" ]; then
DISCORD_WEBHOOK_URL=""
_err "You didn't specify a Discord webhook url DISCORD_WEBHOOK_URL yet."
return 1
fi
_saveaccountconf_mutable DISCORD_WEBHOOK_URL "$DISCORD_WEBHOOK_URL"
DISCORD_USERNAME="${DISCORD_USERNAME:-$(_readaccountconf_mutable DISCORD_USERNAME)}"
if [ "$DISCORD_USERNAME" ]; then
_saveaccountconf_mutable DISCORD_USERNAME "$DISCORD_USERNAME"
fi
DISCORD_AVATAR_URL="${DISCORD_AVATAR_URL:-$(_readaccountconf_mutable DISCORD_AVATAR_URL)}"
if [ "$DISCORD_AVATAR_URL" ]; then
_saveaccountconf_mutable DISCORD_AVATAR_URL "$DISCORD_AVATAR_URL"
fi
export _H1="Content-Type: application/json"
_content="$(printf "**%s**\n%s" "$_subject" "$_content" | _json_encode)"
_data="{\"content\": \"$_content\" "
if [ "$DISCORD_USERNAME" ]; then
_data="$_data, \"username\": \"$DISCORD_USERNAME\" "
fi
if [ "$DISCORD_AVATAR_URL" ]; then
_data="$_data, \"avatar_url\": \"$DISCORD_AVATAR_URL\" "
fi
_data="$_data}"
if _post "$_data" "$DISCORD_WEBHOOK_URL?wait=true"; then
# shellcheck disable=SC2154
if [ "$response" ]; then
_info "discord send success."
return 0
fi
fi
_err "discord send error."
_err "$response"
return 1
}
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env sh
#Support feishu webhooks api
#required
#FEISHU_WEBHOOK="xxxx"
#optional
#FEISHU_KEYWORD="yyyy"
# subject content statusCode
feishu_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_subject" "$_subject"
_debug "_content" "$_content"
_debug "_statusCode" "$_statusCode"
FEISHU_WEBHOOK="${FEISHU_WEBHOOK:-$(_readaccountconf_mutable FEISHU_WEBHOOK)}"
if [ -z "$FEISHU_WEBHOOK" ]; then
FEISHU_WEBHOOK=""
_err "You didn't specify a feishu webhooks FEISHU_WEBHOOK yet."
_err "You can get yours from https://www.feishu.cn"
return 1
fi
_saveaccountconf_mutable FEISHU_WEBHOOK "$FEISHU_WEBHOOK"
FEISHU_KEYWORD="${FEISHU_KEYWORD:-$(_readaccountconf_mutable FEISHU_KEYWORD)}"
if [ "$FEISHU_KEYWORD" ]; then
_saveaccountconf_mutable FEISHU_KEYWORD "$FEISHU_KEYWORD"
fi
_content=$(echo "$_content" | _json_encode)
_subject=$(echo "$_subject" | _json_encode)
_data="{\"msg_type\": \"text\", \"content\": {\"text\": \"[$FEISHU_KEYWORD]\n$_subject\n$_content\"}}"
response="$(_post "$_data" "$FEISHU_WEBHOOK" "" "POST" "application/json")"
if [ "$?" = "0" ] && _contains "$response" "StatusCode\":0"; then
_info "feishu webhooks event fired success."
return 0
fi
_err "feishu webhooks event fired error."
_err "$response"
return 1
}
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env sh
#Support Gotify
#GOTIFY_URL="https://gotify.example.com"
#GOTIFY_TOKEN="123456789ABCDEF"
#optional
#GOTIFY_PRIORITY=0
# subject content statusCode
gotify_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_subject" "$_subject"
_debug "_content" "$_content"
_debug "_statusCode" "$_statusCode"
GOTIFY_URL="${GOTIFY_URL:-$(_readaccountconf_mutable GOTIFY_URL)}"
if [ -z "$GOTIFY_URL" ]; then
GOTIFY_URL=""
_err "You didn't specify the gotify server url GOTIFY_URL."
return 1
fi
_saveaccountconf_mutable GOTIFY_URL "$GOTIFY_URL"
GOTIFY_TOKEN="${GOTIFY_TOKEN:-$(_readaccountconf_mutable GOTIFY_TOKEN)}"
if [ -z "$GOTIFY_TOKEN" ]; then
GOTIFY_TOKEN=""
_err "You didn't specify the gotify token GOTIFY_TOKEN."
return 1
fi
_saveaccountconf_mutable GOTIFY_TOKEN "$GOTIFY_TOKEN"
GOTIFY_PRIORITY="${GOTIFY_PRIORITY:-$(_readaccountconf_mutable GOTIFY_PRIORITY)}"
if [ -z "$GOTIFY_PRIORITY" ]; then
GOTIFY_PRIORITY=0
else
_saveaccountconf_mutable GOTIFY_PRIORITY "$GOTIFY_PRIORITY"
fi
export _H1="X-Gotify-Key: ${GOTIFY_TOKEN}"
export _H2="Content-Type: application/json"
_content=$(echo "$_content" | _json_encode)
_subject=$(echo "$_subject" | _json_encode)
_data="{\"title\": \"${_subject}\", \"message\": \"${_content}\", \"priority\": ${GOTIFY_PRIORITY}}"
response="$(_post "${_data}" "${GOTIFY_URL}/message" "" "POST" "application/json")"
if [ "$?" != "0" ]; then
_err "Failed to send message"
_err "$response"
return 1
fi
_debug2 response "$response"
return 0
}
+2 -1
View File
@@ -62,7 +62,7 @@ mail_send() {
fi
contenttype="text/plain; charset=utf-8"
subject="=?UTF-8?B?$(echo "$_subject" | _base64)?="
subject="=?UTF-8?B?$(printf -- "%b" "$_subject" | _base64)?="
result=$({ _mail_body | eval "$(_mail_cmnd)"; } 2>&1)
# shellcheck disable=SC2181
@@ -131,6 +131,7 @@ _mail_body() {
echo "To: $MAIL_TO"
echo "Subject: $subject"
echo "Content-Type: $contenttype"
echo "MIME-Version: 1.0"
echo
;;
esac
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env sh
#Support for pushbullet.com's api. Push notification, notification sync and message platform for multiple platforms
#PUSHBULLET_TOKEN="" Required, pushbullet application token
#PUSHBULLET_DEVICE="" Optional, Specific device, ignore to send to all devices
PUSHBULLET_URI="https://api.pushbullet.com/v2/pushes"
pushbullet_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_statusCode" "$_statusCode"
PUSHBULLET_TOKEN="${PUSHBULLET_TOKEN:-$(_readaccountconf_mutable PUSHBULLET_TOKEN)}"
if [ -z "$PUSHBULLET_TOKEN" ]; then
PUSHBULLET_TOKEN=""
_err "You didn't specify a Pushbullet application token yet."
return 1
fi
_saveaccountconf_mutable PUSHBULLET_TOKEN "$PUSHBULLET_TOKEN"
PUSHBULLET_DEVICE="${PUSHBULLET_DEVICE:-$(_readaccountconf_mutable PUSHBULLET_DEVICE)}"
if [ -z "$PUSHBULLET_DEVICE" ]; then
_clearaccountconf_mutable PUSHBULLET_DEVICE
else
_saveaccountconf_mutable PUSHBULLET_DEVICE "$PUSHBULLET_DEVICE"
fi
export _H1="Content-Type: application/json"
export _H2="Access-Token: ${PUSHBULLET_TOKEN}"
_content="$(printf "*%s*\n" "$_content" | _json_encode)"
_subject="$(printf "*%s*\n" "$_subject" | _json_encode)"
_data="{\"type\": \"note\",\"title\": \"${_subject}\",\"body\": \"${_content}\",\"device_iden\": \"${PUSHBULLET_DEVICE}\"}"
response="$(_post "$_data" "$PUSHBULLET_URI")"
if [ "$?" != "0" ] || _contains "$response" "\"error_code\""; then
_err "PUSHBULLET send error."
_err "$response"
return 1
fi
_info "PUSHBULLET send success."
return 0
}
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env sh
#Support weixin work webhooks api
#WEIXIN_WORK_WEBHOOK="xxxx"
#optional
#WEIXIN_WORK_KEYWORD="yyyy"
#`WEIXIN_WORK_SIGNING_KEY`="SEC08ffdbd403cbc3fc8a65xxxxxxxxxxxxxxxxxxxx"
# subject content statusCode
weixin_work_send() {
_subject="$1"
_content="$2"
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
_debug "_subject" "$_subject"
_debug "_content" "$_content"
_debug "_statusCode" "$_statusCode"
WEIXIN_WORK_WEBHOOK="${WEIXIN_WORK_WEBHOOK:-$(_readaccountconf_mutable WEIXIN_WORK_WEBHOOK)}"
if [ -z "$WEIXIN_WORK_WEBHOOK" ]; then
WEIXIN_WORK_WEBHOOK=""
_err "You didn't specify a weixin_work webhooks WEIXIN_WORK_WEBHOOK yet."
_err "You can get yours from https://work.weixin.qq.com/api/doc/90000/90136/91770"
return 1
fi
_saveaccountconf_mutable WEIXIN_WORK_WEBHOOK "$WEIXIN_WORK_WEBHOOK"
WEIXIN_WORK_KEYWORD="${WEIXIN_WORK_KEYWORD:-$(_readaccountconf_mutable WEIXIN_WORK_KEYWORD)}"
if [ "$WEIXIN_WORK_KEYWORD" ]; then
_saveaccountconf_mutable WEIXIN_WORK_KEYWORD "$WEIXIN_WORK_KEYWORD"
fi
_content=$(echo "$_content" | _json_encode)
_subject=$(echo "$_subject" | _json_encode)
_data="{\"msgtype\": \"text\", \"text\": {\"content\": \"[$WEIXIN_WORK_KEYWORD]\n$_subject\n$_content\"}}"
response="$(_post "$_data" "$WEIXIN_WORK_WEBHOOK" "" "POST" "application/json")"
if [ "$?" = "0" ] && _contains "$response" "errmsg\":\"ok"; then
_info "weixin_work webhooks event fired success."
return 0
fi
_err "weixin_work webhooks event fired error."
_err "$response"
return 1
}