├── dnsapi ├── README.md ├── dns_myapi.sh ├── dns_tele3.sh ├── dns_doapi.sh ├── dns_acmedns.sh ├── dns_knot.sh ├── dns_zonomi.sh ├── dns_dreamhost.sh ├── dns_nsupdate.sh ├── dns_mydevil.sh ├── dns_lexicon.sh ├── dns_nederhost.sh ├── dns_yandex.sh ├── dns_infoblox.sh ├── dns_active24.sh ├── dns_zilore.sh ├── dns_kinghost.sh ├── dns_ad.sh ├── dns_duckdns.sh ├── dns_namesilo.sh ├── dns_do.sh ├── dns_vscale.sh ├── dns_selectel.sh ├── dns_cn.sh ├── dns_zone.sh ├── dns_dp.sh ├── dns_dpi.sh ├── dns_me.sh ├── dns_nsone.sh ├── dns_lua.sh ├── dns_cx.sh ├── dns_pointhq.sh ├── dns_gd.sh ├── dns_exoscale.sh ├── dns_servercow.sh ├── dns_netcup.sh ├── dns_neodigit.sh ├── dns_ultra.sh ├── dns_unoeuro.sh ├── dns_gcloud.sh ├── dns_gandi_livedns.sh ├── dns_gdnsdk.sh └── dns_linode.sh ├── deploy ├── README.md ├── dovecot.sh ├── nginx.sh ├── apache.sh ├── mysqld.sh ├── opensshd.sh ├── pureftpd.sh ├── myapi.sh ├── keychain.sh ├── strongswan.sh ├── mailcow.sh ├── mydevil.sh ├── haproxy.sh ├── vault_cli.sh ├── cpanel_uapi.sh ├── gitlab.sh ├── qiniu.sh ├── kong.sh ├── unifi.sh ├── vsftpd.sh ├── exim4.sh ├── fritzbox.sh └── gcore_cdn.sh ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── .travis.yml └── Dockerfile /dnsapi/README.md: -------------------------------------------------------------------------------- 1 | # How to use DNS API 2 | DNS api usage: 3 | 4 | https://github.com/Neilpang/acme.sh/wiki/dnsapi -------------------------------------------------------------------------------- /deploy/README.md: -------------------------------------------------------------------------------- 1 | # Using deploy api 2 | 3 | deploy hook usage: 4 | 5 | https://github.com/Neilpang/acme.sh/wiki/deployhooks 6 | 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deploy/dovecot.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to dovecot server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | dovecot_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | 17 | _debug _cdomain "$_cdomain" 18 | _debug _ckey "$_ckey" 19 | _debug _ccert "$_ccert" 20 | _debug _cca "$_cca" 21 | _debug _cfullchain "$_cfullchain" 22 | 23 | _err "Not implemented yet" 24 | return 1 25 | 26 | } 27 | -------------------------------------------------------------------------------- /deploy/nginx.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to nginx server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | nginx_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | 17 | _debug _cdomain "$_cdomain" 18 | _debug _ckey "$_ckey" 19 | _debug _ccert "$_ccert" 20 | _debug _cca "$_cca" 21 | _debug _cfullchain "$_cfullchain" 22 | 23 | _err "deploy cert to nginx server, Not implemented yet" 24 | return 1 25 | 26 | } 27 | -------------------------------------------------------------------------------- /deploy/apache.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to apache server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | apache_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | 17 | _debug _cdomain "$_cdomain" 18 | _debug _ckey "$_ckey" 19 | _debug _ccert "$_ccert" 20 | _debug _cca "$_cca" 21 | _debug _cfullchain "$_cfullchain" 22 | 23 | _err "Deploy cert to apache server, Not implemented yet" 24 | return 1 25 | 26 | } 27 | -------------------------------------------------------------------------------- /deploy/mysqld.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to mysqld server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | mysqld_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | 17 | _debug _cdomain "$_cdomain" 18 | _debug _ckey "$_ckey" 19 | _debug _ccert "$_ccert" 20 | _debug _cca "$_cca" 21 | _debug _cfullchain "$_cfullchain" 22 | 23 | _err "deploy cert to mysqld server, Not implemented yet" 24 | return 1 25 | 26 | } 27 | -------------------------------------------------------------------------------- /deploy/opensshd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to opensshd server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | opensshd_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | 17 | _debug _cdomain "$_cdomain" 18 | _debug _ckey "$_ckey" 19 | _debug _ccert "$_ccert" 20 | _debug _cca "$_cca" 21 | _debug _cfullchain "$_cfullchain" 22 | 23 | _err "deploy cert to opensshd server, Not implemented yet" 24 | return 1 25 | 26 | } 27 | -------------------------------------------------------------------------------- /deploy/pureftpd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to pureftpd server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | pureftpd_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | 17 | _debug _cdomain "$_cdomain" 18 | _debug _ckey "$_ckey" 19 | _debug _ccert "$_ccert" 20 | _debug _cca "$_cca" 21 | _debug _cfullchain "$_cfullchain" 22 | 23 | _err "deploy cert to pureftpd server, Not implemented yet" 24 | return 1 25 | 26 | } 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 14 | 15 | Steps to reproduce 16 | ------------------ 17 | 18 | Debug log 19 | ----------------- 20 | 21 | ``` 22 | acme.sh --issue ..... --debug 2 23 | ``` 24 | 25 | 26 | -------------------------------------------------------------------------------- /deploy/myapi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a sample custom api script. 4 | #This file name is "myapi.sh" 5 | #So, here must be a method myapi_deploy() 6 | #Which will be called by acme.sh to deploy the cert 7 | #returns 0 means success, otherwise error. 8 | 9 | ######## Public functions ##################### 10 | 11 | #domain keyfile certfile cafile fullchain 12 | myapi_deploy() { 13 | _cdomain="$1" 14 | _ckey="$2" 15 | _ccert="$3" 16 | _cca="$4" 17 | _cfullchain="$5" 18 | 19 | _debug _cdomain "$_cdomain" 20 | _debug _ckey "$_ckey" 21 | _debug _ccert "$_ccert" 22 | _debug _cca "$_cca" 23 | _debug _cfullchain "$_cfullchain" 24 | 25 | _err "Not implemented yet" 26 | return 1 27 | 28 | } 29 | -------------------------------------------------------------------------------- /deploy/keychain.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ######## Public functions ##################### 4 | 5 | #domain keyfile certfile cafile fullchain 6 | keychain_deploy() { 7 | _cdomain="$1" 8 | _ckey="$2" 9 | _ccert="$3" 10 | _cca="$4" 11 | _cfullchain="$5" 12 | 13 | _debug _cdomain "$_cdomain" 14 | _debug _ckey "$_ckey" 15 | _debug _ccert "$_ccert" 16 | _debug _cca "$_cca" 17 | _debug _cfullchain "$_cfullchain" 18 | 19 | /usr/bin/security import "$_ckey" -k "/Library/Keychains/System.keychain" 20 | /usr/bin/security import "$_ccert" -k "/Library/Keychains/System.keychain" 21 | /usr/bin/security import "$_cca" -k "/Library/Keychains/System.keychain" 22 | /usr/bin/security import "$_cfullchain" -k "/Library/Keychains/System.keychain" 23 | 24 | return 0 25 | } 26 | -------------------------------------------------------------------------------- /dnsapi/dns_myapi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a sample custom api script. 4 | #This file name is "dns_myapi.sh" 5 | #So, here must be a method dns_myapi_add() 6 | #Which will be called by acme.sh to add the txt record to your api system. 7 | #returns 0 means success, otherwise error. 8 | # 9 | #Author: Neilpang 10 | #Report Bugs here: https://github.com/Neilpang/acme.sh 11 | # 12 | ######## Public functions ##################### 13 | 14 | #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 15 | dns_myapi_add() { 16 | fulldomain=$1 17 | txtvalue=$2 18 | _info "Using myapi" 19 | _debug fulldomain "$fulldomain" 20 | _debug txtvalue "$txtvalue" 21 | _err "Not implemented!" 22 | return 1 23 | } 24 | 25 | #Usage: fulldomain txtvalue 26 | #Remove the txt record after validation. 27 | dns_myapi_rm() { 28 | fulldomain=$1 29 | txtvalue=$2 30 | _info "Using myapi" 31 | _debug fulldomain "$fulldomain" 32 | _debug txtvalue "$txtvalue" 33 | } 34 | 35 | #################### Private functions below ################################## 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: shell 2 | sudo: required 3 | dist: trusty 4 | 5 | os: 6 | - linux 7 | - osx 8 | 9 | services: 10 | - docker 11 | 12 | env: 13 | global: 14 | - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 15 | 16 | 17 | install: 18 | - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then 19 | brew update && brew install socat; 20 | export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" ; 21 | fi 22 | 23 | script: 24 | - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" 25 | - command -V openssl && openssl version 26 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt && chmod +x ~/shfmt && ~/shfmt -l -w -i 2 . ; fi 27 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi 28 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi 29 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi 30 | - cd .. 31 | - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest 32 | - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi 33 | - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi 34 | 35 | matrix: 36 | fast_finish: true 37 | 38 | 39 | -------------------------------------------------------------------------------- /deploy/strongswan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a sample custom api script. 4 | #This file name is "myapi.sh" 5 | #So, here must be a method myapi_deploy() 6 | #Which will be called by acme.sh to deploy the cert 7 | #returns 0 means success, otherwise error. 8 | 9 | ######## Public functions ##################### 10 | 11 | #domain keyfile certfile cafile fullchain 12 | strongswan_deploy() { 13 | _cdomain="$1" 14 | _ckey="$2" 15 | _ccert="$3" 16 | _cca="$4" 17 | _cfullchain="$5" 18 | 19 | _info "Using strongswan" 20 | 21 | if [ -x /usr/sbin/ipsec ]; then 22 | _ipsec=/usr/sbin/ipsec 23 | elif [ -x /usr/sbin/strongswan ]; then 24 | _ipsec=/usr/sbin/strongswan 25 | elif [ -x /usr/local/sbin/ipsec ]; then 26 | _ipsec=/usr/local/sbin/ipsec 27 | else 28 | _err "no strongswan or ipsec command is detected" 29 | return 1 30 | fi 31 | 32 | _info _ipsec "$_ipsec" 33 | 34 | _confdir=$($_ipsec --confdir) 35 | if [ $? -ne 0 ] || [ -z "$_confdir" ]; then 36 | _err "no strongswan --confdir is detected" 37 | return 1 38 | fi 39 | 40 | _info _confdir "$_confdir" 41 | 42 | _debug _cdomain "$_cdomain" 43 | _debug _ckey "$_ckey" 44 | _debug _ccert "$_ccert" 45 | _debug _cca "$_cca" 46 | _debug _cfullchain "$_cfullchain" 47 | 48 | cat "$_ckey" >"${_confdir}/ipsec.d/private/$(basename "$_ckey")" 49 | cat "$_ccert" >"${_confdir}/ipsec.d/certs/$(basename "$_ccert")" 50 | cat "$_cca" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cca")" 51 | cat "$_cfullchain" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cfullchain")" 52 | 53 | $_ipsec reload 54 | 55 | } 56 | -------------------------------------------------------------------------------- /deploy/mailcow.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to mailcow. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | mailcow_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | 17 | _debug _cdomain "$_cdomain" 18 | _debug _ckey "$_ckey" 19 | _debug _ccert "$_ccert" 20 | _debug _cca "$_cca" 21 | _debug _cfullchain "$_cfullchain" 22 | 23 | _mailcow_path="${DEPLOY_MAILCOW_PATH}" 24 | 25 | if [ -z "$_mailcow_path" ]; then 26 | _err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH." 27 | return 1 28 | fi 29 | 30 | _ssl_path="${_mailcow_path}/data/assets/ssl/" 31 | if [ ! -d "$_ssl_path" ]; then 32 | _err "Cannot find mailcow ssl path: $_ssl_path" 33 | return 1 34 | fi 35 | 36 | _info "Copying key and cert" 37 | _real_key="$_ssl_path/key.pem" 38 | if ! cat "$_ckey" >"$_real_key"; then 39 | _err "Error: write key file to: $_real_key" 40 | return 1 41 | fi 42 | 43 | _real_fullchain="$_ssl_path/cert.pem" 44 | if ! cat "$_cfullchain" >"$_real_fullchain"; then 45 | _err "Error: write cert file to: $_real_fullchain" 46 | return 1 47 | fi 48 | 49 | DEFAULT_MAILCOW_RELOAD="cd ${_mailcow_path} && docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow" 50 | _reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}" 51 | 52 | _info "Run reload: $_reload" 53 | if eval "$_reload"; then 54 | _info "Reload success!" 55 | fi 56 | return 0 57 | 58 | } 59 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.9 2 | 3 | RUN apk update -f \ 4 | && apk --no-cache add -f \ 5 | openssl \ 6 | coreutils \ 7 | bind-tools \ 8 | curl \ 9 | socat \ 10 | tzdata \ 11 | && rm -rf /var/cache/apk/* 12 | 13 | ENV LE_CONFIG_HOME /acme.sh 14 | 15 | ENV AUTO_UPGRADE 1 16 | 17 | #Install 18 | ADD ./ /install_acme.sh/ 19 | RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ 20 | 21 | 22 | RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab - 23 | 24 | RUN for verb in help \ 25 | version \ 26 | install \ 27 | uninstall \ 28 | upgrade \ 29 | issue \ 30 | signcsr \ 31 | deploy \ 32 | install-cert \ 33 | renew \ 34 | renew-all \ 35 | revoke \ 36 | remove \ 37 | list \ 38 | showcsr \ 39 | install-cronjob \ 40 | uninstall-cronjob \ 41 | cron \ 42 | toPkcs \ 43 | toPkcs8 \ 44 | update-account \ 45 | register-account \ 46 | create-account-key \ 47 | create-domain-key \ 48 | createCSR \ 49 | deactivate \ 50 | deactivate-account \ 51 | ; do \ 52 | 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} \ 53 | ; done 54 | 55 | RUN printf "%b" '#!'"/usr/bin/env sh\n \ 56 | if [ \"\$1\" = \"daemon\" ]; then \n \ 57 | trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \ 58 | crond && while true; do sleep 1; done;\n \ 59 | else \n \ 60 | exec -- \"\$@\"\n \ 61 | fi" >/entry.sh && chmod +x /entry.sh 62 | 63 | VOLUME /acme.sh 64 | 65 | ENTRYPOINT ["/entry.sh"] 66 | CMD ["--help"] 67 | -------------------------------------------------------------------------------- /deploy/mydevil.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # MyDevil.net API (2019-02-03) 4 | # 5 | # MyDevil.net already supports automatic Let's Encrypt certificates, 6 | # except for wildcard domains. 7 | # 8 | # This script depends on `devil` command that MyDevil.net provides, 9 | # which means that it works only on server side. 10 | # 11 | # Author: Marcin Konicki 12 | # 13 | ######## Public functions ##################### 14 | 15 | # Usage: mydevil_deploy domain keyfile certfile cafile fullchain 16 | mydevil_deploy() { 17 | _cdomain="$1" 18 | _ckey="$2" 19 | _ccert="$3" 20 | _cca="$4" 21 | _cfullchain="$5" 22 | ip="" 23 | 24 | _debug _cdomain "$_cdomain" 25 | _debug _ckey "$_ckey" 26 | _debug _ccert "$_ccert" 27 | _debug _cca "$_cca" 28 | _debug _cfullchain "$_cfullchain" 29 | 30 | if ! _exists "devil"; then 31 | _err "Could not find 'devil' command." 32 | return 1 33 | fi 34 | 35 | ip=$(mydevil_get_ip "$_cdomain") 36 | if [ -z "$ip" ]; then 37 | _err "Could not find IP for domain $_cdomain." 38 | return 1 39 | fi 40 | 41 | # Delete old certificate first 42 | _info "Removing old certificate for $_cdomain at $ip" 43 | devil ssl www del "$ip" "$_cdomain" 44 | 45 | # Add new certificate 46 | _info "Adding new certificate for $_cdomain at $ip" 47 | devil ssl www add "$ip" "$_cfullchain" "$_ckey" "$_cdomain" || return 1 48 | 49 | return 0 50 | } 51 | 52 | #################### Private functions below ################################## 53 | 54 | # Usage: ip=$(mydevil_get_ip domain.com) 55 | # echo $ip 56 | mydevil_get_ip() { 57 | devil dns list "$1" | cut -w -s -f 3,7 | grep "^A$(printf '\t')" | cut -w -s -f 2 || return 1 58 | return 0 59 | } 60 | -------------------------------------------------------------------------------- /deploy/haproxy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to haproxy server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | haproxy_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | 17 | _debug _cdomain "$_cdomain" 18 | _debug _ckey "$_ckey" 19 | _debug _ccert "$_ccert" 20 | _debug _cca "$_cca" 21 | _debug _cfullchain "$_cfullchain" 22 | 23 | # handle reload preference 24 | DEFAULT_HAPROXY_RELOAD="/usr/sbin/service haproxy restart" 25 | if [ -z "${DEPLOY_HAPROXY_RELOAD}" ]; then 26 | _reload="${DEFAULT_HAPROXY_RELOAD}" 27 | _cleardomainconf DEPLOY_HAPROXY_RELOAD 28 | else 29 | _reload="${DEPLOY_HAPROXY_RELOAD}" 30 | _savedomainconf DEPLOY_HAPROXY_RELOAD "$DEPLOY_HAPROXY_RELOAD" 31 | fi 32 | _savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH" 33 | 34 | # work out the path where the PEM file should go 35 | _pem_path="${DEPLOY_HAPROXY_PEM_PATH}" 36 | if [ -z "$_pem_path" ]; then 37 | _err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH." 38 | return 1 39 | fi 40 | _pem_full_path="$_pem_path/$_cdomain.pem" 41 | _info "Full path to PEM $_pem_full_path" 42 | 43 | # combine the key and fullchain into a single pem and install 44 | cat "$_cfullchain" "$_ckey" >"$_pem_full_path" 45 | chmod 600 "$_pem_full_path" 46 | _info "Certificate successfully deployed" 47 | 48 | # restart HAProxy 49 | _info "Run reload: $_reload" 50 | if eval "$_reload"; then 51 | _info "Reload success!" 52 | return 0 53 | else 54 | _err "Reload error" 55 | return 1 56 | fi 57 | 58 | } 59 | -------------------------------------------------------------------------------- /dnsapi/dns_tele3.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | # tele3.cz DNS API 4 | # 5 | # Author: Roman Blizik 6 | # Report Bugs here: https://github.com/par-pa/acme.sh 7 | # 8 | # -- 9 | # export TELE3_Key="MS2I4uPPaI..." 10 | # export TELE3_Secret="kjhOIHGJKHg" 11 | # -- 12 | 13 | TELE3_API="https://www.tele3.cz/acme/" 14 | 15 | ######## Public functions ##################### 16 | 17 | dns_tele3_add() { 18 | _info "Using TELE3 DNS" 19 | data="\"ope\":\"add\", \"domain\":\"$1\", \"value\":\"$2\"" 20 | if ! _tele3_call; then 21 | _err "Publish zone failed" 22 | return 1 23 | fi 24 | 25 | _info "Zone published" 26 | } 27 | 28 | dns_tele3_rm() { 29 | _info "Using TELE3 DNS" 30 | data="\"ope\":\"rm\", \"domain\":\"$1\", \"value\":\"$2\"" 31 | if ! _tele3_call; then 32 | _err "delete TXT record failed" 33 | return 1 34 | fi 35 | 36 | _info "TXT record successfully deleted" 37 | } 38 | 39 | #################### Private functions below ################################## 40 | 41 | _tele3_init() { 42 | TELE3_Key="${TELE3_Key:-$(_readaccountconf_mutable TELE3_Key)}" 43 | TELE3_Secret="${TELE3_Secret:-$(_readaccountconf_mutable TELE3_Secret)}" 44 | if [ -z "$TELE3_Key" ] || [ -z "$TELE3_Secret" ]; then 45 | TELE3_Key="" 46 | TELE3_Secret="" 47 | _err "You must export variables: TELE3_Key and TELE3_Secret" 48 | return 1 49 | fi 50 | 51 | #save the config variables to the account conf file. 52 | _saveaccountconf_mutable TELE3_Key "$TELE3_Key" 53 | _saveaccountconf_mutable TELE3_Secret "$TELE3_Secret" 54 | } 55 | 56 | _tele3_call() { 57 | _tele3_init 58 | data="{\"key\":\"$TELE3_Key\", \"secret\":\"$TELE3_Secret\", $data}" 59 | 60 | _debug data "$data" 61 | 62 | response="$(_post "$data" "$TELE3_API" "" "POST")" 63 | _debug response "$response" 64 | 65 | if [ "$response" != "success" ]; then 66 | _err "$response" 67 | return 1 68 | fi 69 | } 70 | -------------------------------------------------------------------------------- /dnsapi/dns_doapi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Official Let's Encrypt API for do.de / Domain-Offensive 4 | # 5 | # This is different from the dns_do adapter, because dns_do is only usable for enterprise customers 6 | # This API is also available to private customers/individuals 7 | # 8 | # Provide the required LetsEncrypt token like this: 9 | # DO_LETOKEN="FmD408PdqT1E269gUK57" 10 | 11 | DO_API="https://www.do.de/api/letsencrypt" 12 | 13 | ######## Public functions ##################### 14 | 15 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 16 | dns_doapi_add() { 17 | fulldomain=$1 18 | txtvalue=$2 19 | 20 | DO_LETOKEN="${DO_LETOKEN:-$(_readaccountconf_mutable DO_LETOKEN)}" 21 | if [ -z "$DO_LETOKEN" ]; then 22 | DO_LETOKEN="" 23 | _err "You didn't configure a do.de API token yet." 24 | _err "Please set DO_LETOKEN and try again." 25 | return 1 26 | fi 27 | _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" 28 | 29 | _info "Adding TXT record to ${fulldomain}" 30 | response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&value=${txtvalue}")" 31 | if _contains "${response}" 'success'; then 32 | return 0 33 | fi 34 | _err "Could not create resource record, check logs" 35 | _err "${response}" 36 | return 1 37 | } 38 | 39 | dns_doapi_rm() { 40 | fulldomain=$1 41 | 42 | DO_LETOKEN="${DO_LETOKEN:-$(_readaccountconf_mutable DO_LETOKEN)}" 43 | if [ -z "$DO_LETOKEN" ]; then 44 | DO_LETOKEN="" 45 | _err "You didn't configure a do.de API token yet." 46 | _err "Please set DO_LETOKEN and try again." 47 | return 1 48 | fi 49 | _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" 50 | 51 | _info "Deleting resource record $fulldomain" 52 | response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&action=delete")" 53 | if _contains "${response}" 'success'; then 54 | return 0 55 | fi 56 | _err "Could not delete resource record, check logs" 57 | _err "${response}" 58 | return 1 59 | } 60 | -------------------------------------------------------------------------------- /deploy/vault_cli.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Here is a script to deploy cert to hashicorp vault 4 | # (https://www.vaultproject.io/) 5 | # 6 | # it requires the vault binary to be available in PATH, and the following 7 | # environment variables: 8 | # 9 | # VAULT_PREFIX - this contains the prefix path in vault 10 | # VAULT_ADDR - vault requires this to find your vault server 11 | # 12 | # additionally, you need to ensure that VAULT_TOKEN is avialable or 13 | # `vault auth` has applied the appropriate authorization for the vault binary 14 | # to access the vault server 15 | 16 | #returns 0 means success, otherwise error. 17 | 18 | ######## Public functions ##################### 19 | 20 | #domain keyfile certfile cafile fullchain 21 | vault_cli_deploy() { 22 | 23 | _cdomain="$1" 24 | _ckey="$2" 25 | _ccert="$3" 26 | _cca="$4" 27 | _cfullchain="$5" 28 | 29 | _debug _cdomain "$_cdomain" 30 | _debug _ckey "$_ckey" 31 | _debug _ccert "$_ccert" 32 | _debug _cca "$_cca" 33 | _debug _cfullchain "$_cfullchain" 34 | 35 | # validate required env vars 36 | if [ -z "$VAULT_PREFIX" ]; then 37 | _err "VAULT_PREFIX needs to be defined (contains prefix path in vault)" 38 | return 1 39 | fi 40 | 41 | if [ -z "$VAULT_ADDR" ]; then 42 | _err "VAULT_ADDR needs to be defined (contains vault connection address)" 43 | return 1 44 | fi 45 | 46 | VAULT_CMD=$(which vault) 47 | if [ ! $? ]; then 48 | _err "cannot find vault binary!" 49 | return 1 50 | fi 51 | 52 | if [ -n "$FABIO" ]; then 53 | $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1 54 | else 55 | $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 56 | $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 57 | $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1 58 | $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 59 | fi 60 | 61 | } 62 | -------------------------------------------------------------------------------- /dnsapi/dns_acmedns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | #Author: Wolfgang Ebner 4 | #Report Bugs here: https://github.com/webner/acme.sh 5 | # 6 | ######## Public functions ##################### 7 | 8 | #Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 9 | dns_acmedns_add() { 10 | fulldomain=$1 11 | txtvalue=$2 12 | _info "Using acme-dns" 13 | _debug fulldomain "$fulldomain" 14 | _debug txtvalue "$txtvalue" 15 | 16 | ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}" 17 | ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}" 18 | ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}" 19 | ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}" 20 | 21 | if [ "$ACMEDNS_UPDATE_URL" = "" ]; then 22 | ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update" 23 | fi 24 | 25 | _saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL" 26 | _saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME" 27 | _saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD" 28 | _saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN" 29 | 30 | export _H1="X-Api-User: $ACMEDNS_USERNAME" 31 | export _H2="X-Api-Key: $ACMEDNS_PASSWORD" 32 | data="{\"subdomain\":\"$ACMEDNS_SUBDOMAIN\", \"txt\": \"$txtvalue\"}" 33 | 34 | _debug data "$data" 35 | response="$(_post "$data" "$ACMEDNS_UPDATE_URL" "" "POST")" 36 | _debug response "$response" 37 | 38 | if ! echo "$response" | grep "\"$txtvalue\"" >/dev/null; then 39 | _err "invalid response of acme-dns" 40 | return 1 41 | fi 42 | 43 | } 44 | 45 | #Usage: fulldomain txtvalue 46 | #Remove the txt record after validation. 47 | dns_acmedns_rm() { 48 | fulldomain=$1 49 | txtvalue=$2 50 | _info "Using acme-dns" 51 | _debug fulldomain "$fulldomain" 52 | _debug txtvalue "$txtvalue" 53 | } 54 | 55 | #################### Private functions below ################################## 56 | -------------------------------------------------------------------------------- /deploy/cpanel_uapi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # Here is the script to deploy the cert to your cpanel using the cpanel API. 3 | # Uses command line uapi. --user option is needed only if run as root. 4 | # Returns 0 when success. 5 | # 6 | # Please note that I am no longer using Github. If you want to report an issue 7 | # or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/ 8 | # 9 | # Written by Santeri Kannisto 10 | # Public domain, 2017-2018 11 | 12 | #export DEPLOY_CPANEL_USER=myusername 13 | 14 | ######## Public functions ##################### 15 | 16 | #domain keyfile certfile cafile fullchain 17 | 18 | cpanel_uapi_deploy() { 19 | _cdomain="$1" 20 | _ckey="$2" 21 | _ccert="$3" 22 | _cca="$4" 23 | _cfullchain="$5" 24 | 25 | _debug _cdomain "$_cdomain" 26 | _debug _ckey "$_ckey" 27 | _debug _ccert "$_ccert" 28 | _debug _cca "$_cca" 29 | _debug _cfullchain "$_cfullchain" 30 | 31 | if ! _exists uapi; then 32 | _err "The command uapi is not found." 33 | return 1 34 | fi 35 | # read cert and key files and urlencode both 36 | _cert=$(_url_encode <"$_ccert") 37 | _key=$(_url_encode <"$_ckey") 38 | 39 | _debug _cert "$_cert" 40 | _debug _key "$_key" 41 | 42 | if [ "$(id -u)" = 0 ]; then 43 | if [ -z "$DEPLOY_CPANEL_USER" ]; then 44 | _err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username" 45 | return 1 46 | fi 47 | _savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER" 48 | _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") 49 | else 50 | _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") 51 | fi 52 | error_response="status: 0" 53 | if test "${_response#*$error_response}" != "$_response"; then 54 | _err "Error in deploying certificate:" 55 | _err "$_response" 56 | return 1 57 | fi 58 | 59 | _debug response "$_response" 60 | _info "Certificate successfully deployed" 61 | return 0 62 | } 63 | -------------------------------------------------------------------------------- /dnsapi/dns_knot.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ######## Public functions ##################### 4 | 5 | #Usage: dns_knot_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 6 | dns_knot_add() { 7 | fulldomain=$1 8 | txtvalue=$2 9 | _checkKey || return 1 10 | [ -n "${KNOT_SERVER}" ] || KNOT_SERVER="localhost" 11 | # save the dns server and key to the account.conf file. 12 | _saveaccountconf KNOT_SERVER "${KNOT_SERVER}" 13 | _saveaccountconf KNOT_KEY "${KNOT_KEY}" 14 | 15 | if ! _get_root "$fulldomain"; then 16 | _err "Domain does not exist." 17 | return 1 18 | fi 19 | 20 | _info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\"" 21 | 22 | knsupdate -y "${KNOT_KEY}" <' | tr "<" "\n" | grep record | grep 'type="TXT"' | cut -d '"' -f 6); do 40 | _debug2 t "$t" 41 | _qstr="$_qstr&action[$_qindex]=SET&type[$_qindex]=TXT&name[$_qindex]=$fulldomain&value[$_qindex]=$t" 42 | _qindex="$(_math "$_qindex" + 1)" 43 | done 44 | _zm_request "$_qstr" 45 | else 46 | _debug "Just add record" 47 | _zm_request "action=SET&type=TXT&name=$fulldomain&value=$txtvalue" 48 | fi 49 | 50 | } 51 | 52 | #fulldomain txtvalue 53 | dns_zonomi_rm() { 54 | fulldomain=$1 55 | txtvalue=$2 56 | 57 | ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}" 58 | if [ -z "$ZM_Key" ]; then 59 | ZM_Key="" 60 | _err "You don't specify zonomi api key yet." 61 | _err "Please create your key and try again." 62 | return 1 63 | fi 64 | 65 | _zm_request "action=DELETE&type=TXT&name=$fulldomain" 66 | 67 | } 68 | 69 | #################### Private functions below ################################## 70 | #qstr 71 | _zm_request() { 72 | qstr="$1" 73 | 74 | _debug2 "qstr" "$qstr" 75 | 76 | _zm_url="$ZM_Api?api_key=$ZM_Key&$qstr" 77 | _debug2 "_zm_url" "$_zm_url" 78 | response="$(_get "$_zm_url")" 79 | 80 | if [ "$?" != "0" ]; then 81 | return 1 82 | fi 83 | _debug2 response "$response" 84 | _contains "$response" "OK:" 85 | } 86 | -------------------------------------------------------------------------------- /dnsapi/dns_dreamhost.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Author: RhinoLance 4 | #Report Bugs here: https://github.com/RhinoLance/acme.sh 5 | # 6 | 7 | #define the api endpoint 8 | DH_API_ENDPOINT="https://api.dreamhost.com/" 9 | querystring="" 10 | 11 | ######## Public functions ##################### 12 | 13 | #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 14 | dns_dreamhost_add() { 15 | fulldomain=$1 16 | txtvalue=$2 17 | 18 | if ! validate "$fulldomain" "$txtvalue"; then 19 | return 1 20 | fi 21 | 22 | querystring="key=$DH_API_KEY&cmd=dns-add_record&record=$fulldomain&type=TXT&value=$txtvalue" 23 | if ! submit "$querystring"; then 24 | return 1 25 | fi 26 | 27 | return 0 28 | } 29 | 30 | #Usage: fulldomain txtvalue 31 | #Remove the txt record after validation. 32 | dns_dreamhost_rm() { 33 | fulldomain=$1 34 | txtvalue=$2 35 | 36 | if ! validate "$fulldomain" "$txtvalue"; then 37 | return 1 38 | fi 39 | 40 | querystring="key=$DH_API_KEY&cmd=dns-remove_record&record=$fulldomain&type=TXT&value=$txtvalue" 41 | if ! submit "$querystring"; then 42 | return 1 43 | fi 44 | 45 | return 0 46 | } 47 | 48 | #################### Private functions below ################################## 49 | 50 | #send the command to the api endpoint. 51 | submit() { 52 | querystring=$1 53 | 54 | url="$DH_API_ENDPOINT?$querystring" 55 | 56 | _debug url "$url" 57 | 58 | if ! response="$(_get "$url")"; then 59 | _err "Error <$1>" 60 | return 1 61 | fi 62 | 63 | if [ -z "$2" ]; then 64 | message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" 65 | if [ -n "$message" ]; then 66 | _err "$message" 67 | return 1 68 | fi 69 | fi 70 | 71 | _debug response "$response" 72 | 73 | return 0 74 | } 75 | 76 | #check that we have a valid API Key 77 | validate() { 78 | fulldomain=$1 79 | txtvalue=$2 80 | 81 | _info "Using dreamhost" 82 | _debug fulldomain "$fulldomain" 83 | _debug txtvalue "$txtvalue" 84 | 85 | #retrieve the API key from the environment variable if it exists, otherwise look for a saved key. 86 | DH_API_KEY="${DH_API_KEY:-$(_readaccountconf_mutable DH_API_KEY)}" 87 | 88 | if [ -z "$DH_API_KEY" ]; then 89 | DH_API_KEY="" 90 | _err "You didn't specify the DreamHost api key yet (export DH_API_KEY=\"\")" 91 | _err "Please login to your control panel, create a key and try again." 92 | return 1 93 | fi 94 | 95 | #save the api key to the account conf file. 96 | _saveaccountconf_mutable DH_API_KEY "$DH_API_KEY" 97 | } 98 | -------------------------------------------------------------------------------- /dnsapi/dns_nsupdate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ######## Public functions ##################### 4 | 5 | #Usage: dns_nsupdate_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 6 | dns_nsupdate_add() { 7 | fulldomain=$1 8 | txtvalue=$2 9 | _checkKeyFile || return 1 10 | [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" 11 | [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 12 | # save the dns server and key to the account conf file. 13 | _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" 14 | _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" 15 | _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" 16 | _saveaccountconf NSUPDATE_ZONE "${NSUPDATE_ZONE}" 17 | _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" 18 | [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" 19 | [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" 20 | if [ -z "${NSUPDATE_ZONE}" ]; then 21 | nsupdate -k "${NSUPDATE_KEY}" $nsdebug < 12 | # 13 | ######## Public functions ##################### 14 | 15 | #Usage: dns_mydevil_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 16 | dns_mydevil_add() { 17 | fulldomain=$1 18 | txtvalue=$2 19 | domain="" 20 | 21 | if ! _exists "devil"; then 22 | _err "Could not find 'devil' command." 23 | return 1 24 | fi 25 | 26 | _info "Using mydevil" 27 | 28 | domain=$(mydevil_get_domain "$fulldomain") 29 | if [ -z "$domain" ]; then 30 | _err "Invalid domain name: could not find root domain of $fulldomain." 31 | return 1 32 | fi 33 | 34 | # No need to check if record name exists, `devil` always adds new record. 35 | # In worst case scenario, we end up with multiple identical records. 36 | 37 | _info "Adding $fulldomain record for domain $domain" 38 | if devil dns add "$domain" "$fulldomain" TXT "$txtvalue"; then 39 | _info "Successfully added TXT record, ready for validation." 40 | return 0 41 | else 42 | _err "Unable to add DNS record." 43 | return 1 44 | fi 45 | } 46 | 47 | #Usage: fulldomain txtvalue 48 | #Remove the txt record after validation. 49 | dns_mydevil_rm() { 50 | fulldomain=$1 51 | txtvalue=$2 52 | domain="" 53 | 54 | if ! _exists "devil"; then 55 | _err "Could not find 'devil' command." 56 | return 1 57 | fi 58 | 59 | _info "Using mydevil" 60 | 61 | domain=$(mydevil_get_domain "$fulldomain") 62 | if [ -z "$domain" ]; then 63 | _err "Invalid domain name: could not find root domain of $fulldomain." 64 | return 1 65 | fi 66 | 67 | # catch one or more numbers 68 | num='[0-9][0-9]*' 69 | # catch one or more whitespace 70 | w=$(printf '[\t ][\t ]*') 71 | # catch anything, except newline 72 | any='.*' 73 | # filter to make sure we do not delete other records 74 | validRecords="^${num}${w}${fulldomain}${w}TXT${w}${any}${txtvalue}$" 75 | for id in $(devil dns list "$domain" | tail -n+2 | grep "${validRecords}" | cut -w -s -f 1); do 76 | _info "Removing record $id from domain $domain" 77 | devil dns del "$domain" "$id" || _err "Could not remove DNS record." 78 | done 79 | } 80 | 81 | #################### Private functions below ################################## 82 | 83 | # Usage: domain=$(mydevil_get_domain "_acme-challenge.www.domain.com" || _err "Invalid domain name") 84 | # echo $domain 85 | mydevil_get_domain() { 86 | fulldomain=$1 87 | domain="" 88 | 89 | for domain in $(devil dns list | cut -w -s -f 1 | tail -n+2); do 90 | if _endswith "$fulldomain" "$domain"; then 91 | printf -- "%s" "$domain" 92 | return 0 93 | fi 94 | done 95 | 96 | return 1 97 | } 98 | -------------------------------------------------------------------------------- /deploy/qiniu.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Script to create certificate to qiniu.com 4 | # 5 | # This deployment required following variables 6 | # export QINIU_AK="QINIUACCESSKEY" 7 | # export QINIU_SK="QINIUSECRETKEY" 8 | # export QINIU_CDN_DOMAIN="cdn.example.com" 9 | 10 | QINIU_API_BASE="https://api.qiniu.com" 11 | 12 | qiniu_deploy() { 13 | _cdomain="$1" 14 | _ckey="$2" 15 | _ccert="$3" 16 | _cca="$4" 17 | _cfullchain="$5" 18 | 19 | _debug _cdomain "$_cdomain" 20 | _debug _ckey "$_ckey" 21 | _debug _ccert "$_ccert" 22 | _debug _cca "$_cca" 23 | _debug _cfullchain "$_cfullchain" 24 | 25 | if [ -z "$QINIU_AK" ]; then 26 | _err "QINIU_AK is not defined." 27 | return 1 28 | else 29 | _savedomainconf QINIU_AK "$QINIU_AK" 30 | fi 31 | 32 | if [ -z "$QINIU_SK" ]; then 33 | _err "QINIU_SK is not defined." 34 | return 1 35 | else 36 | _savedomainconf QINIU_SK "$QINIU_SK" 37 | fi 38 | 39 | if [ "$QINIU_CDN_DOMAIN" ]; then 40 | _savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN" 41 | else 42 | QINIU_CDN_DOMAIN="$_cdomain" 43 | fi 44 | 45 | ## upload certificate 46 | string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') 47 | string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') 48 | 49 | sslcert_path="/sslcert" 50 | sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$QINIU_CDN_DOMAIN\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" 51 | sslcert_access_token="$(_make_access_token "$sslcert_path")" 52 | _debug sslcert_access_token "$sslcert_access_token" 53 | export _H1="Authorization: QBox $sslcert_access_token" 54 | sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline") 55 | 56 | if ! _contains "$sslcert_response" "certID"; then 57 | _err "Error in creating certificate:" 58 | _err "$sslcert_response" 59 | return 1 60 | fi 61 | 62 | _debug sslcert_response "$sslcert_response" 63 | _info "Certificate successfully uploaded, updating domain $_cdomain" 64 | 65 | ## extract certId 66 | _certId="$(printf "%s" "$sslcert_response" | _normalizeJson | _egrep_o "certID\": *\"[^\"]*\"" | cut -d : -f 2)" 67 | _debug certId "$_certId" 68 | 69 | ## update domain ssl config 70 | update_path="/domain/$QINIU_CDN_DOMAIN/httpsconf" 71 | update_body="{\"certid\":$_certId,\"forceHttps\":false}" 72 | update_access_token="$(_make_access_token "$update_path")" 73 | _debug update_access_token "$update_access_token" 74 | export _H1="Authorization: QBox $update_access_token" 75 | update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline") 76 | 77 | if _contains "$update_response" "error"; then 78 | _err "Error in updating domain httpsconf:" 79 | _err "$update_response" 80 | return 1 81 | fi 82 | 83 | _debug update_response "$update_response" 84 | _info "Certificate successfully deployed" 85 | 86 | return 0 87 | } 88 | 89 | _make_access_token() { 90 | _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$QINIU_SK" | _hex_dump | tr -d " ")" | _base64 | tr -- '+/' '-_')" 91 | echo "$QINIU_AK:$_token" 92 | } 93 | -------------------------------------------------------------------------------- /deploy/kong.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # If certificate already exist it will update only cert and key not touching other parameter 3 | # If certificate doesn't exist it will only upload cert and key and not set other parameter 4 | # Note that we deploy full chain 5 | # Written by Geoffroi Genot 6 | 7 | ######## Public functions ##################### 8 | 9 | #domain keyfile certfile cafile fullchain 10 | kong_deploy() { 11 | _cdomain="$1" 12 | _ckey="$2" 13 | _ccert="$3" 14 | _cca="$4" 15 | _cfullchain="$5" 16 | _info "Deploying certificate on Kong instance" 17 | if [ -z "$KONG_URL" ]; then 18 | _debug "KONG_URL Not set, using default http://localhost:8001" 19 | KONG_URL="http://localhost:8001" 20 | fi 21 | 22 | _debug _cdomain "$_cdomain" 23 | _debug _ckey "$_ckey" 24 | _debug _ccert "$_ccert" 25 | _debug _cca "$_cca" 26 | _debug _cfullchain "$_cfullchain" 27 | 28 | #Get ssl_uuid linked to the domain 29 | ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') 30 | if [ -z "$ssl_uuid" ]; then 31 | _debug "Unable to get Kong ssl_uuid for domain $_cdomain" 32 | _debug "Make sure that KONG_URL is correctly configured" 33 | _debug "Make sure that a Kong certificate match the sni" 34 | _debug "Kong url: $KONG_URL" 35 | _info "No existing certificate, creating..." 36 | #return 1 37 | fi 38 | #Save kong url if it's succesful (First run case) 39 | _saveaccountconf KONG_URL "$KONG_URL" 40 | #Generate DEIM 41 | delim="-----MultipartDelimiter$(date "+%s%N")" 42 | nl="\015\012" 43 | #Set Header 44 | _H1="Content-Type: multipart/form-data; boundary=$delim" 45 | #Generate data for request (Multipart/form-data with mixed content) 46 | if [ -z "$ssl_uuid" ]; then 47 | #set sni to domain 48 | content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" 49 | fi 50 | #add key 51 | content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" 52 | #Add cert 53 | content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" 54 | #Close multipart 55 | content="$content${nl}--$delim--${nl}" 56 | #Convert CRLF 57 | content=$(printf %b "$content") 58 | #DEBUG 59 | _debug header "$_H1" 60 | _debug content "$content" 61 | #Check if sslcreated (if not => POST else => PATCH) 62 | 63 | if [ -z "$ssl_uuid" ]; then 64 | #Post certificate to Kong 65 | response=$(_post "$content" "$KONG_URL/certificates" "" "POST") 66 | else 67 | #patch 68 | response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH") 69 | fi 70 | if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then 71 | _err "An error occurred with cert upload. Check response:" 72 | _err "$response" 73 | return 1 74 | fi 75 | _debug response "$response" 76 | _info "Certificate successfully deployed" 77 | } 78 | -------------------------------------------------------------------------------- /deploy/unifi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to unifi server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | #DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" 8 | #DEPLOY_UNIFI_KEYPASS="aircontrolenterprise" 9 | #DEPLOY_UNIFI_RELOAD="service unifi restart" 10 | 11 | ######## Public functions ##################### 12 | 13 | #domain keyfile certfile cafile fullchain 14 | unifi_deploy() { 15 | _cdomain="$1" 16 | _ckey="$2" 17 | _ccert="$3" 18 | _cca="$4" 19 | _cfullchain="$5" 20 | 21 | _debug _cdomain "$_cdomain" 22 | _debug _ckey "$_ckey" 23 | _debug _ccert "$_ccert" 24 | _debug _cca "$_cca" 25 | _debug _cfullchain "$_cfullchain" 26 | 27 | if ! _exists keytool; then 28 | _err "keytool not found" 29 | return 1 30 | fi 31 | 32 | DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" 33 | _unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}" 34 | DEFAULT_UNIFI_KEYPASS="aircontrolenterprise" 35 | _unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}" 36 | DEFAULT_UNIFI_RELOAD="service unifi restart" 37 | _reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}" 38 | 39 | _debug _unifi_keystore "$_unifi_keystore" 40 | if [ ! -f "$_unifi_keystore" ]; then 41 | if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then 42 | _err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE" 43 | return 1 44 | else 45 | _err "It seems that the specified unifi keystore is not valid, please check." 46 | return 1 47 | fi 48 | fi 49 | if [ ! -w "$_unifi_keystore" ]; then 50 | _err "The file $_unifi_keystore is not writable, please change the permission." 51 | return 1 52 | fi 53 | 54 | _info "Generate import pkcs12" 55 | _import_pkcs12="$(_mktemp)" 56 | _toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root 57 | if [ "$?" != "0" ]; then 58 | _err "Oops, error creating import pkcs12, please report bug to us." 59 | return 1 60 | fi 61 | 62 | _info "Modify unifi keystore: $_unifi_keystore" 63 | if keytool -importkeystore \ 64 | -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \ 65 | -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \ 66 | -alias unifi -noprompt; then 67 | _info "Import keystore success!" 68 | rm "$_import_pkcs12" 69 | else 70 | _err "Import unifi keystore error, please report bug to us." 71 | rm "$_import_pkcs12" 72 | return 1 73 | fi 74 | 75 | _info "Run reload: $_reload" 76 | if eval "$_reload"; then 77 | _info "Reload success!" 78 | if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then 79 | _savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE" 80 | else 81 | _cleardomainconf DEPLOY_UNIFI_KEYSTORE 82 | fi 83 | if [ "$DEPLOY_UNIFI_KEYPASS" ]; then 84 | _savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS" 85 | else 86 | _cleardomainconf DEPLOY_UNIFI_KEYPASS 87 | fi 88 | if [ "$DEPLOY_UNIFI_RELOAD" ]; then 89 | _savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD" 90 | else 91 | _cleardomainconf DEPLOY_UNIFI_RELOAD 92 | fi 93 | return 0 94 | else 95 | _err "Reload error" 96 | return 1 97 | fi 98 | return 0 99 | 100 | } 101 | -------------------------------------------------------------------------------- /dnsapi/dns_lexicon.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # dns api wrapper of lexicon for acme.sh 4 | 5 | # https://github.com/AnalogJ/lexicon 6 | lexicon_cmd="lexicon" 7 | 8 | wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" 9 | 10 | _lexicon_init() { 11 | if ! _exists "$lexicon_cmd"; then 12 | _err "Please install $lexicon_cmd first: $wiki" 13 | return 1 14 | fi 15 | 16 | PROVIDER="${PROVIDER:-$(_readdomainconf PROVIDER)}" 17 | if [ -z "$PROVIDER" ]; then 18 | PROVIDER="" 19 | _err "Please define env PROVIDER first: $wiki" 20 | return 1 21 | fi 22 | 23 | _savedomainconf PROVIDER "$PROVIDER" 24 | export PROVIDER 25 | 26 | # e.g. busybox-ash does not know [:upper:] 27 | # shellcheck disable=SC2018,SC2019 28 | Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') 29 | eval "$Lx_name=\${$Lx_name:-$(_readaccountconf_mutable "$Lx_name")}" 30 | Lx_name_v=$(eval echo \$"$Lx_name") 31 | _secure_debug "$Lx_name" "$Lx_name_v" 32 | if [ "$Lx_name_v" ]; then 33 | _saveaccountconf_mutable "$Lx_name" "$Lx_name_v" 34 | eval export "$Lx_name" 35 | fi 36 | 37 | # shellcheck disable=SC2018,SC2019 38 | Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') 39 | eval "$Lx_token=\${$Lx_token:-$(_readaccountconf_mutable "$Lx_token")}" 40 | Lx_token_v=$(eval echo \$"$Lx_token") 41 | _secure_debug "$Lx_token" "$Lx_token_v" 42 | if [ "$Lx_token_v" ]; then 43 | _saveaccountconf_mutable "$Lx_token" "$Lx_token_v" 44 | eval export "$Lx_token" 45 | fi 46 | 47 | # shellcheck disable=SC2018,SC2019 48 | Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') 49 | eval "$Lx_password=\${$Lx_password:-$(_readaccountconf_mutable "$Lx_password")}" 50 | Lx_password_v=$(eval echo \$"$Lx_password") 51 | _secure_debug "$Lx_password" "$Lx_password_v" 52 | if [ "$Lx_password_v" ]; then 53 | _saveaccountconf_mutable "$Lx_password" "$Lx_password_v" 54 | eval export "$Lx_password" 55 | fi 56 | 57 | # shellcheck disable=SC2018,SC2019 58 | Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') 59 | eval "$Lx_domaintoken=\${$Lx_domaintoken:-$(_readaccountconf_mutable "$Lx_domaintoken")}" 60 | Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") 61 | _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v" 62 | if [ "$Lx_domaintoken_v" ]; then 63 | _saveaccountconf_mutable "$Lx_domaintoken" "$Lx_domaintoken_v" 64 | eval export "$Lx_domaintoken" 65 | fi 66 | } 67 | 68 | ######## Public functions ##################### 69 | 70 | #Usage: dns_lexicon_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 71 | dns_lexicon_add() { 72 | fulldomain=$1 73 | txtvalue=$2 74 | 75 | if ! _lexicon_init; then 76 | return 1 77 | fi 78 | 79 | domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) 80 | 81 | _secure_debug LEXICON_OPTS "$LEXICON_OPTS" 82 | _savedomainconf LEXICON_OPTS "$LEXICON_OPTS" 83 | 84 | # shellcheck disable=SC2086 85 | $lexicon_cmd "$PROVIDER" $LEXICON_OPTS create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" 86 | 87 | } 88 | 89 | #Usage: dns_lexicon_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 90 | dns_lexicon_rm() { 91 | fulldomain=$1 92 | txtvalue=$2 93 | 94 | if ! _lexicon_init; then 95 | return 1 96 | fi 97 | 98 | domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) 99 | 100 | # shellcheck disable=SC2086 101 | $lexicon_cmd "$PROVIDER" $LEXICON_OPTS delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" 102 | 103 | } 104 | -------------------------------------------------------------------------------- /deploy/vsftpd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to vsftpd server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | #DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" 8 | #DEPLOY_VSFTPD_RELOAD="service vsftpd restart" 9 | 10 | ######## Public functions ##################### 11 | 12 | #domain keyfile certfile cafile fullchain 13 | vsftpd_deploy() { 14 | _cdomain="$1" 15 | _ckey="$2" 16 | _ccert="$3" 17 | _cca="$4" 18 | _cfullchain="$5" 19 | 20 | _debug _cdomain "$_cdomain" 21 | _debug _ckey "$_ckey" 22 | _debug _ccert "$_ccert" 23 | _debug _cca "$_cca" 24 | _debug _cfullchain "$_cfullchain" 25 | 26 | _ssl_path="/etc/acme.sh/vsftpd" 27 | if ! mkdir -p "$_ssl_path"; then 28 | _err "Can not create folder:$_ssl_path" 29 | return 1 30 | fi 31 | 32 | _info "Copying key and cert" 33 | _real_key="$_ssl_path/vsftpd.key" 34 | if ! cat "$_ckey" >"$_real_key"; then 35 | _err "Error: write key file to: $_real_key" 36 | return 1 37 | fi 38 | _real_fullchain="$_ssl_path/vsftpd.chain.pem" 39 | if ! cat "$_cfullchain" >"$_real_fullchain"; then 40 | _err "Error: write key file to: $_real_fullchain" 41 | return 1 42 | fi 43 | 44 | DEFAULT_VSFTPD_RELOAD="service vsftpd restart" 45 | _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" 46 | 47 | if [ -z "$IS_RENEW" ]; then 48 | DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" 49 | _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" 50 | if [ ! -f "$_vsftpd_conf" ]; then 51 | if [ -z "$DEPLOY_VSFTPD_CONF" ]; then 52 | _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" 53 | return 1 54 | else 55 | _err "It seems that the specified vsftpd conf is not valid, please check." 56 | return 1 57 | fi 58 | fi 59 | if [ ! -w "$_vsftpd_conf" ]; then 60 | _err "The file $_vsftpd_conf is not writable, please change the permission." 61 | return 1 62 | fi 63 | _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" 64 | _info "Backup $_vsftpd_conf to $_backup_conf" 65 | cp "$_vsftpd_conf" "$_backup_conf" 66 | 67 | _info "Modify vsftpd conf: $_vsftpd_conf" 68 | if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ 69 | && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \ 70 | && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then 71 | _info "Set config success!" 72 | else 73 | _err "Config vsftpd server error, please report bug to us." 74 | _info "Restoring vsftpd conf" 75 | if cat "$_backup_conf" >"$_vsftpd_conf"; then 76 | _info "Restore conf success" 77 | eval "$_reload" 78 | else 79 | _err "Oops, error restore vsftpd conf, please report bug to us." 80 | fi 81 | return 1 82 | fi 83 | fi 84 | 85 | _info "Run reload: $_reload" 86 | if eval "$_reload"; then 87 | _info "Reload success!" 88 | if [ "$DEPLOY_VSFTPD_CONF" ]; then 89 | _savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF" 90 | else 91 | _cleardomainconf DEPLOY_VSFTPD_CONF 92 | fi 93 | if [ "$DEPLOY_VSFTPD_RELOAD" ]; then 94 | _savedomainconf DEPLOY_VSFTPD_RELOAD "$DEPLOY_VSFTPD_RELOAD" 95 | else 96 | _cleardomainconf DEPLOY_VSFTPD_RELOAD 97 | fi 98 | return 0 99 | else 100 | _err "Reload error, restoring" 101 | if cat "$_backup_conf" >"$_vsftpd_conf"; then 102 | _info "Restore conf success" 103 | eval "$_reload" 104 | else 105 | _err "Oops, error restore vsftpd conf, please report bug to us." 106 | fi 107 | return 1 108 | fi 109 | return 0 110 | } 111 | -------------------------------------------------------------------------------- /deploy/exim4.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to exim4 server. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | #DEPLOY_EXIM4_CONF="/etc/exim/exim.conf" 8 | #DEPLOY_EXIM4_RELOAD="service exim4 restart" 9 | 10 | ######## Public functions ##################### 11 | 12 | #domain keyfile certfile cafile fullchain 13 | exim4_deploy() { 14 | _cdomain="$1" 15 | _ckey="$2" 16 | _ccert="$3" 17 | _cca="$4" 18 | _cfullchain="$5" 19 | 20 | _debug _cdomain "$_cdomain" 21 | _debug _ckey "$_ckey" 22 | _debug _ccert "$_ccert" 23 | _debug _cca "$_cca" 24 | _debug _cfullchain "$_cfullchain" 25 | 26 | _ssl_path="/etc/acme.sh/exim4" 27 | if ! mkdir -p "$_ssl_path"; then 28 | _err "Can not create folder:$_ssl_path" 29 | return 1 30 | fi 31 | 32 | _info "Copying key and cert" 33 | _real_key="$_ssl_path/exim4.key" 34 | if ! cat "$_ckey" >"$_real_key"; then 35 | _err "Error: write key file to: $_real_key" 36 | return 1 37 | fi 38 | _real_fullchain="$_ssl_path/exim4.pem" 39 | if ! cat "$_cfullchain" >"$_real_fullchain"; then 40 | _err "Error: write key file to: $_real_fullchain" 41 | return 1 42 | fi 43 | 44 | DEFAULT_EXIM4_RELOAD="service exim4 restart" 45 | _reload="${DEPLOY_EXIM4_RELOAD:-$DEFAULT_EXIM4_RELOAD}" 46 | 47 | if [ -z "$IS_RENEW" ]; then 48 | DEFAULT_EXIM4_CONF="/etc/exim/exim.conf" 49 | if [ ! -f "$DEFAULT_EXIM4_CONF" ]; then 50 | DEFAULT_EXIM4_CONF="/etc/exim4/exim4.conf.template" 51 | fi 52 | _exim4_conf="${DEPLOY_EXIM4_CONF:-$DEFAULT_EXIM4_CONF}" 53 | _debug _exim4_conf "$_exim4_conf" 54 | if [ ! -f "$_exim4_conf" ]; then 55 | if [ -z "$DEPLOY_EXIM4_CONF" ]; then 56 | _err "exim4 conf is not found, please define DEPLOY_EXIM4_CONF" 57 | return 1 58 | else 59 | _err "It seems that the specified exim4 conf is not valid, please check." 60 | return 1 61 | fi 62 | fi 63 | if [ ! -w "$_exim4_conf" ]; then 64 | _err "The file $_exim4_conf is not writable, please change the permission." 65 | return 1 66 | fi 67 | _backup_conf="$DOMAIN_BACKUP_PATH/exim4.conf.bak" 68 | _info "Backup $_exim4_conf to $_backup_conf" 69 | cp "$_exim4_conf" "$_backup_conf" 70 | 71 | _info "Modify exim4 conf: $_exim4_conf" 72 | if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" \ 73 | && _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then 74 | _info "Set config success!" 75 | else 76 | _err "Config exim4 server error, please report bug to us." 77 | _info "Restoring exim4 conf" 78 | if cat "$_backup_conf" >"$_exim4_conf"; then 79 | _info "Restore conf success" 80 | eval "$_reload" 81 | else 82 | _err "Oops, error restore exim4 conf, please report bug to us." 83 | fi 84 | return 1 85 | fi 86 | fi 87 | 88 | _info "Run reload: $_reload" 89 | if eval "$_reload"; then 90 | _info "Reload success!" 91 | if [ "$DEPLOY_EXIM4_CONF" ]; then 92 | _savedomainconf DEPLOY_EXIM4_CONF "$DEPLOY_EXIM4_CONF" 93 | else 94 | _cleardomainconf DEPLOY_EXIM4_CONF 95 | fi 96 | if [ "$DEPLOY_EXIM4_RELOAD" ]; then 97 | _savedomainconf DEPLOY_EXIM4_RELOAD "$DEPLOY_EXIM4_RELOAD" 98 | else 99 | _cleardomainconf DEPLOY_EXIM4_RELOAD 100 | fi 101 | return 0 102 | else 103 | _err "Reload error, restoring" 104 | if cat "$_backup_conf" >"$_exim4_conf"; then 105 | _info "Restore conf success" 106 | eval "$_reload" 107 | else 108 | _err "Oops, error restore exim4 conf, please report bug to us." 109 | fi 110 | return 1 111 | fi 112 | return 0 113 | 114 | } 115 | -------------------------------------------------------------------------------- /dnsapi/dns_nederhost.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #NederHost_Key="sdfgikogfdfghjklkjhgfcdcfghjk" 4 | 5 | NederHost_Api="https://api.nederhost.nl/dns/v1" 6 | 7 | ######## Public functions ##################### 8 | 9 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 10 | dns_nederhost_add() { 11 | fulldomain=$1 12 | txtvalue=$2 13 | 14 | NederHost_Key="${NederHost_Key:-$(_readaccountconf_mutable NederHost_Key)}" 15 | if [ -z "$NederHost_Key" ]; then 16 | NederHost_Key="" 17 | _err "You didn't specify a NederHost api key." 18 | _err "You can get yours from https://www.nederhost.nl/mijn_nederhost" 19 | return 1 20 | fi 21 | 22 | #save the api key and email to the account conf file. 23 | _saveaccountconf_mutable NederHost_Key "$NederHost_Key" 24 | 25 | _debug "First detect the root zone" 26 | if ! _get_root "$fulldomain"; then 27 | _err "invalid domain" 28 | return 1 29 | fi 30 | _debug _sub_domain "$_sub_domain" 31 | _debug _domain "$_domain" 32 | 33 | _info "Adding record" 34 | if _nederhost_rest PATCH "zones/$_domain/records/$fulldomain/TXT" "[{\"content\":\"$txtvalue\",\"ttl\":60}]"; then 35 | if _contains "$response" "$fulldomain"; then 36 | _info "Added, OK" 37 | return 0 38 | else 39 | _err "Add txt record error." 40 | return 1 41 | fi 42 | fi 43 | _err "Add txt record error." 44 | return 1 45 | 46 | } 47 | 48 | #fulldomain txtvalue 49 | dns_nederhost_rm() { 50 | fulldomain=$1 51 | txtvalue=$2 52 | 53 | NederHost_Key="${NederHost_Key:-$(_readaccountconf_mutable NederHost_Key)}" 54 | if [ -z "$NederHost_Key" ]; then 55 | NederHost_Key="" 56 | _err "You didn't specify a NederHost api key." 57 | _err "You can get yours from https://www.nederhost.nl/mijn_nederhost" 58 | return 1 59 | fi 60 | 61 | _debug "First detect the root zone" 62 | if ! _get_root "$fulldomain"; then 63 | _err "invalid domain" 64 | return 1 65 | fi 66 | 67 | _debug _sub_domain "$_sub_domain" 68 | _debug _domain "$_domain" 69 | 70 | _debug "Removing txt record" 71 | _nederhost_rest DELETE "zones/${_domain}/records/$fulldomain/TXT?content=$txtvalue" 72 | 73 | } 74 | 75 | #################### Private functions below ################################## 76 | #_acme-challenge.www.domain.com 77 | #returns 78 | # _sub_domain=_acme-challenge.www 79 | # _domain=domain.com 80 | _get_root() { 81 | domain=$1 82 | i=2 83 | p=1 84 | while true; do 85 | _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) 86 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 87 | _debug _domain "$_domain" 88 | if [ -z "$_domain" ]; then 89 | #not valid 90 | return 1 91 | fi 92 | 93 | if _nederhost_rest GET "zones/${_domain}"; then 94 | if [ "${_code}" = "204" ]; then 95 | return 0 96 | fi 97 | else 98 | return 1 99 | fi 100 | p=$i 101 | i=$(_math "$i" + 1) 102 | done 103 | return 1 104 | } 105 | 106 | _nederhost_rest() { 107 | m=$1 108 | ep="$2" 109 | data="$3" 110 | _debug "$ep" 111 | 112 | export _H1="Authorization: Bearer $NederHost_Key" 113 | export _H2="Content-Type: application/json" 114 | 115 | if [ "$m" != "GET" ]; then 116 | _debug data "$data" 117 | response="$(_post "$data" "$NederHost_Api/$ep" "" "$m")" 118 | else 119 | response="$(_get "$NederHost_Api/$ep")" 120 | fi 121 | 122 | _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" 123 | _debug "http response code $_code" 124 | 125 | if [ "$?" != "0" ]; then 126 | _err "error $ep" 127 | return 1 128 | fi 129 | _debug2 response "$response" 130 | return 0 131 | } 132 | -------------------------------------------------------------------------------- /dnsapi/dns_yandex.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # Author: non7top@gmail.com 3 | # 07 Jul 2017 4 | # report bugs at https://github.com/non7top/acme.sh 5 | 6 | # Values to export: 7 | # export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 8 | 9 | ######## Public functions ##################### 10 | 11 | #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 12 | dns_yandex_add() { 13 | fulldomain="${1}" 14 | txtvalue="${2}" 15 | _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" 16 | _PDD_credentials || return 1 17 | export _H1="PddToken: $PDD_Token" 18 | 19 | _PDD_get_domain "$fulldomain" 20 | _debug "Found suitable domain in pdd: $curDomain" 21 | curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" 22 | curUri="https://pddimp.yandex.ru/api2/admin/dns/add" 23 | curResult="$(_post "${curData}" "${curUri}")" 24 | _debug "Result: $curResult" 25 | } 26 | 27 | #Usage: dns_myapi_rm _acme-challenge.www.domain.com 28 | dns_yandex_rm() { 29 | fulldomain="${1}" 30 | _debug "Calling: dns_yandex_rm() '${fulldomain}'" 31 | _PDD_credentials || return 1 32 | export _H1="PddToken: $PDD_Token" 33 | record_id=$(pdd_get_record_id "${fulldomain}") 34 | _debug "Result: $record_id" 35 | 36 | _PDD_get_domain "$fulldomain" 37 | _debug "Found suitable domain in pdd: $curDomain" 38 | 39 | curUri="https://pddimp.yandex.ru/api2/admin/dns/del" 40 | curData="domain=${curDomain}&record_id=${record_id}" 41 | curResult="$(_post "${curData}" "${curUri}")" 42 | _debug "Result: $curResult" 43 | } 44 | 45 | #################### Private functions below ################################## 46 | 47 | _PDD_get_domain() { 48 | fulldomain="${1}" 49 | __page=1 50 | __last=0 51 | while [ $__last -eq 0 ]; do 52 | uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" 53 | res1="$(_get "$uri1" | _normalizeJson)" 54 | _debug2 "res1" "$res1" 55 | __found="$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')" 56 | _debug "found: $__found results on page" 57 | if [ "$__found" -lt 20 ]; then 58 | _debug "last page: $__page" 59 | __last=1 60 | fi 61 | 62 | __all_domains="$__all_domains $(echo "$res1" | tr "," "\n" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" 63 | 64 | __page=$(_math $__page + 1) 65 | done 66 | 67 | k=2 68 | while [ $k -lt 10 ]; do 69 | __t=$(echo "$fulldomain" | cut -d . -f $k-100) 70 | _debug "finding zone for domain $__t" 71 | for d in $__all_domains; do 72 | if [ "$d" = "$__t" ]; then 73 | p=$(_math $k - 1) 74 | curSubdomain="$(echo "$fulldomain" | cut -d . -f "1-$p")" 75 | curDomain="$__t" 76 | return 0 77 | fi 78 | done 79 | k=$(_math $k + 1) 80 | done 81 | _err "No suitable domain found in your account" 82 | return 1 83 | } 84 | 85 | _PDD_credentials() { 86 | if [ -z "${PDD_Token}" ]; then 87 | PDD_Token="" 88 | _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx" 89 | _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token" 90 | return 1 91 | else 92 | _saveaccountconf PDD_Token "${PDD_Token}" 93 | fi 94 | } 95 | 96 | pdd_get_record_id() { 97 | fulldomain="${1}" 98 | 99 | _PDD_get_domain "$fulldomain" 100 | _debug "Found suitable domain in pdd: $curDomain" 101 | 102 | curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" 103 | curResult="$(_get "${curUri}" | _normalizeJson)" 104 | _debug "Result: $curResult" 105 | echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' 106 | } 107 | -------------------------------------------------------------------------------- /dnsapi/dns_infoblox.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ## Infoblox API integration by Jason Keller and Elijah Tenai 4 | ## 5 | ## Report any bugs via https://github.com/jasonkeller/acme.sh 6 | 7 | dns_infoblox_add() { 8 | 9 | ## Nothing to see here, just some housekeeping 10 | fulldomain=$1 11 | txtvalue=$2 12 | baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View" 13 | 14 | _info "Using Infoblox API" 15 | _debug fulldomain "$fulldomain" 16 | _debug txtvalue "$txtvalue" 17 | 18 | ## Check for the credentials 19 | if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then 20 | Infoblox_Creds="" 21 | Infoblox_Server="" 22 | _err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)." 23 | _err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again." 24 | return 1 25 | fi 26 | 27 | if [ -z "$Infoblox_View" ]; then 28 | Infoblox_View="default" 29 | fi 30 | 31 | ## Save the credentials to the account file 32 | _saveaccountconf Infoblox_Creds "$Infoblox_Creds" 33 | _saveaccountconf Infoblox_Server "$Infoblox_Server" 34 | _saveaccountconf Infoblox_View "$Infoblox_View" 35 | 36 | ## Base64 encode the credentials 37 | Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) 38 | 39 | ## Construct the HTTP Authorization header 40 | export _H1="Accept-Language:en-US" 41 | export _H2="Authorization: Basic $Infoblox_CredsEncoded" 42 | 43 | ## Add the challenge record to the Infoblox grid member 44 | result="$(_post "" "$baseurlnObject" "" "POST")" 45 | 46 | ## Let's see if we get something intelligible back from the unit 47 | if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then 48 | _info "Successfully created the txt record" 49 | return 0 50 | else 51 | _err "Error encountered during record addition" 52 | _err "$result" 53 | return 1 54 | fi 55 | 56 | } 57 | 58 | dns_infoblox_rm() { 59 | 60 | ## Nothing to see here, just some housekeeping 61 | fulldomain=$1 62 | txtvalue=$2 63 | 64 | _info "Using Infoblox API" 65 | _debug fulldomain "$fulldomain" 66 | _debug txtvalue "$txtvalue" 67 | 68 | ## Base64 encode the credentials 69 | Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)" 70 | 71 | ## Construct the HTTP Authorization header 72 | export _H1="Accept-Language:en-US" 73 | export _H2="Authorization: Basic $Infoblox_CredsEncoded" 74 | 75 | ## Does the record exist? Let's check. 76 | baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty" 77 | result="$(_get "$baseurlnObject")" 78 | 79 | ## Let's see if we get something intelligible back from the grid 80 | if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then 81 | ## Extract the object reference 82 | objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" 83 | objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" 84 | ## Delete them! All the stale records! 85 | rmResult="$(_post "" "$objRmUrl" "" "DELETE")" 86 | ## Let's see if that worked 87 | if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then 88 | _info "Successfully deleted $objRef" 89 | return 0 90 | else 91 | _err "Error occurred during txt record delete" 92 | _err "$rmResult" 93 | return 1 94 | fi 95 | else 96 | _err "Record to delete didn't match an existing record" 97 | _err "$result" 98 | return 1 99 | fi 100 | } 101 | 102 | #################### Private functions below ################################## 103 | -------------------------------------------------------------------------------- /dnsapi/dns_active24.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje" 4 | 5 | ACTIVE24_Api="https://api.active24.com" 6 | 7 | ######## Public functions ##################### 8 | 9 | # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 10 | # Used to add txt record 11 | dns_active24_add() { 12 | fulldomain=$1 13 | txtvalue=$2 14 | 15 | _active24_init 16 | 17 | _info "Adding txt record" 18 | if _active24_rest POST "dns/$_domain/txt/v1" "{\"name\":\"$_sub_domain\",\"text\":\"$txtvalue\",\"ttl\":0}"; then 19 | if _contains "$response" "errors"; then 20 | _err "Add txt record error." 21 | return 1 22 | else 23 | _info "Added, OK" 24 | return 0 25 | fi 26 | fi 27 | _err "Add txt record error." 28 | return 1 29 | } 30 | 31 | # Usage: fulldomain txtvalue 32 | # Used to remove the txt record after validation 33 | dns_active24_rm() { 34 | fulldomain=$1 35 | txtvalue=$2 36 | 37 | _active24_init 38 | 39 | _debug "Getting txt records" 40 | _active24_rest GET "dns/$_domain/records/v1" 41 | 42 | if _contains "$response" "errors"; then 43 | _err "Error" 44 | return 1 45 | fi 46 | 47 | hash_ids=$(echo "$response" | _egrep_o "[^{]+${txtvalue}[^}]+" | _egrep_o "hashId\":\"[^\"]+" | cut -c10-) 48 | 49 | for hash_id in $hash_ids; do 50 | _debug "Removing hash_id" "$hash_id" 51 | if _active24_rest DELETE "dns/$_domain/$hash_id/v1" ""; then 52 | if _contains "$response" "errors"; then 53 | _err "Unable to remove txt record." 54 | return 1 55 | else 56 | _info "Removed txt record." 57 | return 0 58 | fi 59 | fi 60 | done 61 | 62 | _err "No txt records found." 63 | return 1 64 | } 65 | 66 | #################### Private functions below ################################## 67 | #_acme-challenge.www.domain.com 68 | #returns 69 | # _sub_domain=_acme-challenge.www 70 | # _domain=domain.com 71 | # _domain_id=sdjkglgdfewsdfg 72 | _get_root() { 73 | domain=$1 74 | 75 | if ! _active24_rest GET "dns/domains/v1"; then 76 | return 1 77 | fi 78 | 79 | i=2 80 | p=1 81 | while true; do 82 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 83 | _debug "h" "$h" 84 | if [ -z "$h" ]; then 85 | #not valid 86 | return 1 87 | fi 88 | 89 | if _contains "$response" "\"$h\"" >/dev/null; then 90 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 91 | _domain=$h 92 | return 0 93 | fi 94 | p=$i 95 | i=$(_math "$i" + 1) 96 | done 97 | return 1 98 | } 99 | 100 | _active24_rest() { 101 | m=$1 102 | ep="$2" 103 | data="$3" 104 | _debug "$ep" 105 | 106 | export _H1="Authorization: Bearer $ACTIVE24_Token" 107 | 108 | if [ "$m" != "GET" ]; then 109 | _debug "data" "$data" 110 | response="$(_post "$data" "$ACTIVE24_Api/$ep" "" "$m" "application/json")" 111 | else 112 | response="$(_get "$ACTIVE24_Api/$ep")" 113 | fi 114 | 115 | if [ "$?" != "0" ]; then 116 | _err "error $ep" 117 | return 1 118 | fi 119 | _debug2 response "$response" 120 | return 0 121 | } 122 | 123 | _active24_init() { 124 | ACTIVE24_Token="${ACTIVE24_Token:-$(_readaccountconf_mutable ACTIVE24_Token)}" 125 | if [ -z "$ACTIVE24_Token" ]; then 126 | ACTIVE24_Token="" 127 | _err "You didn't specify a Active24 api token yet." 128 | _err "Please create the token and try again." 129 | return 1 130 | fi 131 | 132 | _saveaccountconf_mutable ACTIVE24_Token "ACTIVE24_Token" 133 | 134 | _debug "First detect the root zone" 135 | if ! _get_root "$fulldomain"; then 136 | _err "invalid domain" 137 | return 1 138 | fi 139 | _debug _sub_domain "$_sub_domain" 140 | _debug _domain "$_domain" 141 | } 142 | -------------------------------------------------------------------------------- /dnsapi/dns_zilore.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | Zilore_API="https://api.zilore.com/dns/v1" 4 | # Zilore_Key="YOUR-ZILORE-API-KEY" 5 | 6 | ######## Public functions ##################### 7 | 8 | dns_zilore_add() { 9 | fulldomain=$1 10 | txtvalue=$2 11 | 12 | _info "Using Zilore" 13 | _debug fulldomain "$fulldomain" 14 | _debug txtvalue "$txtvalue" 15 | 16 | Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}" 17 | if [ -z "$Zilore_Key" ]; then 18 | Zilore_Key="" 19 | _err "Please define Zilore API key" 20 | return 1 21 | fi 22 | _saveaccountconf_mutable Zilore_Key "$Zilore_Key" 23 | 24 | if ! _get_root "$fulldomain"; then 25 | _err "Unable to determine root domain" 26 | return 1 27 | else 28 | _debug _domain "$_domain" 29 | fi 30 | 31 | if _zilore_rest POST "domains/$_domain/records?record_type=TXT&record_ttl=600&record_name=$fulldomain&record_value=\"$txtvalue\""; then 32 | if _contains "$response" '"added"' >/dev/null; then 33 | _info "Added TXT record, waiting for validation" 34 | return 0 35 | else 36 | _debug response "$response" 37 | _err "Error while adding DNS records" 38 | return 1 39 | fi 40 | fi 41 | 42 | return 1 43 | } 44 | 45 | dns_zilore_rm() { 46 | fulldomain=$1 47 | txtvalue=$2 48 | 49 | _info "Using Zilore" 50 | _debug fulldomain "$fulldomain" 51 | _debug txtvalue "$txtvalue" 52 | 53 | Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}" 54 | if [ -z "$Zilore_Key" ]; then 55 | Zilore_Key="" 56 | _err "Please define Zilore API key" 57 | return 1 58 | fi 59 | _saveaccountconf_mutable Zilore_Key "$Zilore_Key" 60 | 61 | if ! _get_root "$fulldomain"; then 62 | _err "Unable to determine root domain" 63 | return 1 64 | else 65 | _debug _domain "$_domain" 66 | fi 67 | 68 | _debug "Getting TXT records" 69 | _zilore_rest GET "domains/${_domain}/records?search_text=$txtvalue&search_record_type=TXT" 70 | _debug response "$response" 71 | 72 | if ! _contains "$response" '"ok"' >/dev/null; then 73 | _err "Error while getting records list" 74 | return 1 75 | else 76 | _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | _head_n 1) 77 | if [ -z "$_record_id" ]; then 78 | _err "Cannot determine _record_id" 79 | return 1 80 | else 81 | _debug _record_id "$_record_id" 82 | fi 83 | if ! _zilore_rest DELETE "domains/${_domain}/records?record_id=$_record_id"; then 84 | _err "Error while deleting chosen record" 85 | return 1 86 | fi 87 | _contains "$response" '"ok"' 88 | fi 89 | } 90 | 91 | #################### Private functions below ################################## 92 | 93 | _get_root() { 94 | domain=$1 95 | i=2 96 | while true; do 97 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 98 | _debug h "$h" 99 | if [ -z "$h" ]; then 100 | #not valid 101 | return 1 102 | fi 103 | 104 | if ! _zilore_rest GET "domains?search_text=$h"; then 105 | return 1 106 | fi 107 | 108 | if _contains "$response" "\"$h\"" >/dev/null; then 109 | _domain=$h 110 | return 0 111 | else 112 | _debug "$h not found" 113 | fi 114 | i=$(_math "$i" + 1) 115 | done 116 | return 1 117 | } 118 | 119 | _zilore_rest() { 120 | method=$1 121 | param=$2 122 | data=$3 123 | 124 | export _H1="X-Auth-Key: $Zilore_Key" 125 | 126 | if [ "$method" != "GET" ]; then 127 | response="$(_post "$data" "$Zilore_API/$param" "" "$method")" 128 | else 129 | response="$(_get "$Zilore_API/$param")" 130 | fi 131 | 132 | if [ "$?" != "0" ]; then 133 | _err "error $param" 134 | return 1 135 | fi 136 | 137 | _debug2 response "$response" 138 | return 0 139 | } 140 | -------------------------------------------------------------------------------- /dnsapi/dns_kinghost.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################ 4 | # KingHost API support # 5 | # http://api.kinghost.net/doc/ # 6 | # # 7 | # Author: Felipe Keller Braz # 8 | # Report Bugs here: https://github.com/kinghost/acme.sh # 9 | # # 10 | # Values to export: # 11 | # export KINGHOST_Username="email@provider.com" # 12 | # export KINGHOST_Password="xxxxxxxxxx" # 13 | ############################################################ 14 | 15 | KING_Api="https://api.kinghost.net/acme" 16 | 17 | # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 18 | # Used to add txt record 19 | dns_kinghost_add() { 20 | fulldomain=$1 21 | txtvalue=$2 22 | 23 | KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" 24 | KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" 25 | if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then 26 | KINGHOST_Username="" 27 | KINGHOST_Password="" 28 | _err "You don't specify KingHost api password and email yet." 29 | _err "Please create you key and try again." 30 | return 1 31 | fi 32 | 33 | #save the credentials to the account conf file. 34 | _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" 35 | _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" 36 | 37 | _debug "Getting txt records" 38 | _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" 39 | 40 | #This API call returns "status":"ok" if dns record does not exists 41 | #We are creating a new txt record here, so we expect the "ok" status 42 | if ! echo "$response" | grep '"status":"ok"' >/dev/null; then 43 | _err "Error" 44 | _err "$response" 45 | return 1 46 | fi 47 | 48 | _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" 49 | if ! echo "$response" | grep '"status":"ok"' >/dev/null; then 50 | _err "Error" 51 | _err "$response" 52 | return 1 53 | fi 54 | 55 | return 0 56 | } 57 | 58 | # Usage: fulldomain txtvalue 59 | # Used to remove the txt record after validation 60 | dns_kinghost_rm() { 61 | fulldomain=$1 62 | txtvalue=$2 63 | 64 | KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" 65 | KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" 66 | if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then 67 | KINGHOST_Password="" 68 | KINGHOST_Username="" 69 | _err "You don't specify KingHost api key and email yet." 70 | _err "Please create you key and try again." 71 | return 1 72 | fi 73 | 74 | _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" 75 | if ! echo "$response" | grep '"status":"ok"' >/dev/null; then 76 | _err "Error" 77 | _err "$response" 78 | return 1 79 | fi 80 | 81 | return 0 82 | } 83 | 84 | #################### Private functions below ################################## 85 | _kinghost_rest() { 86 | method=$1 87 | uri="$2" 88 | data="$3" 89 | _debug "$uri" 90 | 91 | export _H1="X-Auth-Email: $KINGHOST_Username" 92 | export _H2="X-Auth-Key: $KINGHOST_Password" 93 | 94 | if [ "$method" != "GET" ]; then 95 | _debug data "$data" 96 | response="$(_post "$data" "$KING_Api/$uri.json" "" "$method")" 97 | else 98 | response="$(_get "$KING_Api/$uri.json?$data")" 99 | fi 100 | 101 | if [ "$?" != "0" ]; then 102 | _err "error $uri" 103 | return 1 104 | fi 105 | _debug2 response "$response" 106 | return 0 107 | } 108 | -------------------------------------------------------------------------------- /dnsapi/dns_ad.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | #AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" 5 | 6 | #This is the Alwaysdata api wrapper for acme.sh 7 | # 8 | #Author: Paul Koppen 9 | #Report Bugs here: https://github.com/wpk-/acme.sh 10 | 11 | AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" 12 | 13 | ######## Public functions ##################### 14 | 15 | #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 16 | dns_ad_add() { 17 | fulldomain=$1 18 | txtvalue=$2 19 | 20 | if [ -z "$AD_API_KEY" ]; then 21 | AD_API_KEY="" 22 | _err "You didn't specify the AD api key yet." 23 | _err "Please create you key and try again." 24 | return 1 25 | fi 26 | 27 | _saveaccountconf AD_API_KEY "$AD_API_KEY" 28 | 29 | _debug "First detect the root zone" 30 | if ! _get_root "$fulldomain"; then 31 | _err "invalid domain" 32 | return 1 33 | fi 34 | _debug _domain_id "$_domain_id" 35 | _debug _sub_domain "$_sub_domain" 36 | _debug _domain "$_domain" 37 | 38 | _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" 39 | 40 | if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then 41 | _info "txt record updated success." 42 | return 0 43 | fi 44 | 45 | return 1 46 | } 47 | 48 | #fulldomain txtvalue 49 | dns_ad_rm() { 50 | fulldomain=$1 51 | txtvalue=$2 52 | 53 | _debug "First detect the root zone" 54 | if ! _get_root "$fulldomain"; then 55 | _err "invalid domain" 56 | return 1 57 | fi 58 | _debug _domain_id "$_domain_id" 59 | _debug _sub_domain "$_sub_domain" 60 | _debug _domain "$_domain" 61 | 62 | _debug "Getting txt records" 63 | _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" 64 | 65 | if [ -n "$response" ]; then 66 | record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) 67 | _debug record_id "$record_id" 68 | if [ -z "$record_id" ]; then 69 | _err "Can not get record id to remove." 70 | return 1 71 | fi 72 | if _ad_rest DELETE "record/$record_id/" && [ -z "$response" ]; then 73 | _info "txt record deleted success." 74 | return 0 75 | fi 76 | _debug response "$response" 77 | return 1 78 | fi 79 | 80 | return 1 81 | } 82 | 83 | #################### Private functions below ################################## 84 | #_acme-challenge.www.domain.com 85 | #returns 86 | # _sub_domain=_acme-challenge.www 87 | # _domain=domain.com 88 | # _domain_id=12345 89 | _get_root() { 90 | domain=$1 91 | i=2 92 | p=1 93 | 94 | if _ad_rest GET "domain/"; then 95 | response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" 96 | while true; do 97 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 98 | _debug h "$h" 99 | if [ -z "$h" ]; then 100 | #not valid 101 | return 1 102 | fi 103 | 104 | hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" 105 | if [ "$hostedzone" ]; then 106 | _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) 107 | if [ "$_domain_id" ]; then 108 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 109 | _domain=$h 110 | return 0 111 | fi 112 | return 1 113 | fi 114 | p=$i 115 | i=$(_math "$i" + 1) 116 | done 117 | fi 118 | return 1 119 | } 120 | 121 | #method uri qstr data 122 | _ad_rest() { 123 | mtd="$1" 124 | ep="$2" 125 | data="$3" 126 | 127 | _debug mtd "$mtd" 128 | _debug ep "$ep" 129 | 130 | export _H1="Accept: application/json" 131 | export _H2="Content-Type: application/json" 132 | 133 | if [ "$mtd" != "GET" ]; then 134 | # both POST and DELETE. 135 | _debug data "$data" 136 | response="$(_post "$data" "$AD_API_URL/$ep" "" "$mtd")" 137 | else 138 | response="$(_get "$AD_API_URL/$ep")" 139 | fi 140 | 141 | if [ "$?" != "0" ]; then 142 | _err "error $ep" 143 | return 1 144 | fi 145 | _debug2 response "$response" 146 | return 0 147 | } 148 | -------------------------------------------------------------------------------- /dnsapi/dns_duckdns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Created by RaidenII, to use DuckDNS's API to add/remove text records 4 | #06/27/2017 5 | 6 | # Pass credentials before "acme.sh --issue --dns dns_duckdns ..." 7 | # -- 8 | # export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" 9 | # -- 10 | # 11 | # Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh 12 | 13 | DuckDNS_API="https://www.duckdns.org/update" 14 | 15 | ######## Public functions ##################### 16 | 17 | #Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 18 | dns_duckdns_add() { 19 | fulldomain=$1 20 | txtvalue=$2 21 | 22 | DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" 23 | if [ -z "$DuckDNS_Token" ]; then 24 | _err "You must export variable: DuckDNS_Token" 25 | _err "The token for your DuckDNS account is necessary." 26 | _err "You can look it up in your DuckDNS account." 27 | return 1 28 | fi 29 | 30 | # Now save the credentials. 31 | _saveaccountconf_mutable DuckDNS_Token "$DuckDNS_Token" 32 | 33 | # Unfortunately, DuckDNS does not seems to support lookup domain through API 34 | # So I assume your credentials (which are your domain and token) are correct 35 | # If something goes wrong, we will get a KO response from DuckDNS 36 | 37 | if ! _duckdns_get_domain; then 38 | return 1 39 | fi 40 | 41 | # Now add the TXT record to DuckDNS 42 | _info "Trying to add TXT record" 43 | if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=$txtvalue"; then 44 | if [ "$response" = "OK" ]; then 45 | _info "TXT record has been successfully added to your DuckDNS domain." 46 | _info "Note that all subdomains under this domain uses the same TXT record." 47 | return 0 48 | else 49 | _err "Errors happened during adding the TXT record, response=$response" 50 | return 1 51 | fi 52 | else 53 | _err "Errors happened during adding the TXT record." 54 | return 1 55 | fi 56 | } 57 | 58 | #Usage: fulldomain txtvalue 59 | #Remove the txt record after validation. 60 | dns_duckdns_rm() { 61 | fulldomain=$1 62 | txtvalue=$2 63 | 64 | DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" 65 | if [ -z "$DuckDNS_Token" ]; then 66 | _err "You must export variable: DuckDNS_Token" 67 | _err "The token for your DuckDNS account is necessary." 68 | _err "You can look it up in your DuckDNS account." 69 | return 1 70 | fi 71 | 72 | if ! _duckdns_get_domain; then 73 | return 1 74 | fi 75 | 76 | # Now remove the TXT record from DuckDNS 77 | _info "Trying to remove TXT record" 78 | if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=&clear=true"; then 79 | if [ "$response" = "OK" ]; then 80 | _info "TXT record has been successfully removed from your DuckDNS domain." 81 | return 0 82 | else 83 | _err "Errors happened during removing the TXT record, response=$response" 84 | return 1 85 | fi 86 | else 87 | _err "Errors happened during removing the TXT record." 88 | return 1 89 | fi 90 | } 91 | 92 | #################### Private functions below ################################## 93 | 94 | #fulldomain=_acme-challenge.domain.duckdns.org 95 | #returns 96 | # _duckdns_domain=domain 97 | _duckdns_get_domain() { 98 | 99 | # We'll extract the domain/username from full domain 100 | _duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.]duckdns.org' | cut -d . -f 2)" 101 | 102 | if [ -z "$_duckdns_domain" ]; then 103 | _err "Error extracting the domain." 104 | return 1 105 | fi 106 | 107 | return 0 108 | } 109 | 110 | #Usage: method URI 111 | _duckdns_rest() { 112 | method=$1 113 | param="$2" 114 | _debug param "$param" 115 | url="$DuckDNS_API?$param" 116 | _debug url "$url" 117 | 118 | # DuckDNS uses GET to update domain info 119 | if [ "$method" = "GET" ]; then 120 | response="$(_get "$url")" 121 | else 122 | _err "Unsupported method" 123 | return 1 124 | fi 125 | 126 | _debug2 response "$response" 127 | return 0 128 | } 129 | -------------------------------------------------------------------------------- /dnsapi/dns_namesilo.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Author: meowthink 4 | #Created 01/14/2017 5 | #Utilize namesilo.com API to finish dns-01 verifications. 6 | 7 | Namesilo_API="https://www.namesilo.com/api" 8 | 9 | ######## Public functions ##################### 10 | 11 | #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 12 | dns_namesilo_add() { 13 | fulldomain=$1 14 | txtvalue=$2 15 | 16 | if [ -z "$Namesilo_Key" ]; then 17 | Namesilo_Key="" 18 | _err "API token for namesilo.com is missing." 19 | _err "Please specify that in your environment variable." 20 | return 1 21 | fi 22 | 23 | #save the api key and email to the account conf file. 24 | _saveaccountconf Namesilo_Key "$Namesilo_Key" 25 | 26 | if ! _get_root "$fulldomain"; then 27 | _err "Unable to find domain specified." 28 | return 1 29 | fi 30 | 31 | _debug _sub_domain "$_sub_domain" 32 | _debug _domain "$_domain" 33 | 34 | _debug txtvalue "$txtvalue" 35 | if _namesilo_rest GET "dnsAddRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrtype=TXT&rrhost=$_sub_domain&rrvalue=$txtvalue"; then 36 | retcode=$(printf "%s\n" "$response" | _egrep_o "300") 37 | if [ "$retcode" ]; then 38 | _info "Successfully added TXT record, ready for validation." 39 | return 0 40 | else 41 | _err "Unable to add the DNS record." 42 | return 1 43 | fi 44 | fi 45 | } 46 | 47 | #Usage: fulldomain txtvalue 48 | #Remove the txt record after validation. 49 | dns_namesilo_rm() { 50 | fulldomain=$1 51 | txtvalue=$2 52 | 53 | if ! _get_root "$fulldomain"; then 54 | _err "Unable to find domain specified." 55 | return 1 56 | fi 57 | 58 | # Get the record id. 59 | if _namesilo_rest GET "dnsListRecords?version=1&type=xml&key=$Namesilo_Key&domain=$_domain"; then 60 | retcode=$(printf "%s\n" "$response" | _egrep_o "300") 61 | if [ "$retcode" ]; then 62 | _record_id=$(printf "%s\n" "$response" | _egrep_o "([^<]*)TXT$fulldomain" | _egrep_o "([^<]*)" | sed -r "s/([^<]*)<\/record_id>/\1/" | tail -n 1) 63 | _debug record_id "$_record_id" 64 | _info "Successfully retrieved the record id for ACME challenge." 65 | else 66 | _err "Unable to retrieve the record id." 67 | return 1 68 | fi 69 | fi 70 | 71 | # Remove the DNS record using record id. 72 | if _namesilo_rest GET "dnsDeleteRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrid=$_record_id"; then 73 | retcode=$(printf "%s\n" "$response" | _egrep_o "300") 74 | if [ "$retcode" ]; then 75 | _info "Successfully removed the TXT record." 76 | return 0 77 | else 78 | _err "Unable to remove the DNS record." 79 | return 1 80 | fi 81 | fi 82 | } 83 | 84 | #################### Private functions below ################################## 85 | 86 | # _acme-challenge.www.domain.com 87 | # returns 88 | # _sub_domain=_acme-challenge.www 89 | # _domain=domain.com 90 | _get_root() { 91 | domain=$1 92 | i=2 93 | p=1 94 | 95 | if ! _namesilo_rest GET "listDomains?version=1&type=xml&key=$Namesilo_Key"; then 96 | return 1 97 | fi 98 | 99 | # Need to exclude the last field (tld) 100 | numfields=$(echo "$domain" | _egrep_o "\." | wc -l) 101 | while [ $i -le "$numfields" ]; do 102 | host=$(printf "%s" "$domain" | cut -d . -f $i-100) 103 | _debug host "$host" 104 | if [ -z "$host" ]; then 105 | return 1 106 | fi 107 | 108 | if _contains "$response" "$host"; then 109 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 110 | _domain="$host" 111 | return 0 112 | fi 113 | p=$i 114 | i=$(_math "$i" + 1) 115 | done 116 | return 1 117 | } 118 | 119 | _namesilo_rest() { 120 | method=$1 121 | param=$2 122 | data=$3 123 | 124 | if [ "$method" != "GET" ]; then 125 | response="$(_post "$data" "$Namesilo_API/$param" "" "$method")" 126 | else 127 | response="$(_get "$Namesilo_API/$param")" 128 | fi 129 | 130 | if [ "$?" != "0" ]; then 131 | _err "error $param" 132 | return 1 133 | fi 134 | 135 | _debug2 response "$response" 136 | return 0 137 | } 138 | -------------------------------------------------------------------------------- /dnsapi/dns_do.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # DNS API for Domain-Offensive / Resellerinterface / Domainrobot 4 | 5 | # Report bugs at https://github.com/seidler2547/acme.sh/issues 6 | 7 | # set these environment variables to match your customer ID and password: 8 | # DO_PID="KD-1234567" 9 | # DO_PW="cdfkjl3n2" 10 | 11 | DO_URL="https://soap.resellerinterface.de/" 12 | 13 | ######## Public functions ##################### 14 | 15 | #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 16 | dns_do_add() { 17 | fulldomain=$1 18 | txtvalue=$2 19 | if _dns_do_authenticate; then 20 | _info "Adding TXT record to ${_domain} as ${fulldomain}" 21 | _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300 22 | if _contains "${response}" '>success<'; then 23 | return 0 24 | fi 25 | _err "Could not create resource record, check logs" 26 | fi 27 | return 1 28 | } 29 | 30 | #fulldomain 31 | dns_do_rm() { 32 | fulldomain=$1 33 | if _dns_do_authenticate; then 34 | if _dns_do_list_rrs; then 35 | _dns_do_had_error=0 36 | for _rrid in ${_rr_list}; do 37 | _info "Deleting resource record $_rrid for $_domain" 38 | _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}" 39 | if ! _contains "${response}" '>success<'; then 40 | _dns_do_had_error=1 41 | _err "Could not delete resource record for ${_domain}, id ${_rrid}" 42 | fi 43 | done 44 | return $_dns_do_had_error 45 | fi 46 | fi 47 | return 1 48 | } 49 | 50 | #################### Private functions below ################################## 51 | _dns_do_authenticate() { 52 | _info "Authenticating as ${DO_PID}" 53 | _dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}" 54 | if _contains "${response}" '>success<'; then 55 | _get_root "$fulldomain" 56 | _debug "_domain $_domain" 57 | return 0 58 | else 59 | _err "Authentication failed, are DO_PID and DO_PW set correctly?" 60 | fi 61 | return 1 62 | } 63 | 64 | _dns_do_list_rrs() { 65 | _dns_do_soap getRRList origin "${_domain}" 66 | if ! _contains "${response}" 'SOAP-ENC:Array'; then 67 | _err "getRRList origin ${_domain} failed" 68 | return 1 69 | fi 70 | _rr_list="$(echo "${response}" \ 71 | | tr -d "\n\r\t" \ 72 | | sed -e 's//\n/g' \ 73 | | grep ">$(_regexcape "$fulldomain")" \ 74 | | sed -e 's/<\/item>/\n/g' \ 75 | | grep '>id[0-9]{1,16}<' \ 77 | | tr -d '><')" 78 | [ "${_rr_list}" ] 79 | } 80 | 81 | _dns_do_soap() { 82 | func="$1" 83 | shift 84 | # put the parameters to xml 85 | body="" 86 | while [ "$1" ]; do 87 | _k="$1" 88 | shift 89 | _v="$1" 90 | shift 91 | body="$body<$_k>$_v" 92 | done 93 | body="$body" 94 | _debug2 "SOAP request ${body}" 95 | 96 | # build SOAP XML 97 | _xml=' 98 | 99 | '"$body"' 100 | ' 101 | 102 | # set SOAP headers 103 | export _H1="SOAPAction: ${DO_URL}#${func}" 104 | 105 | if ! response="$(_post "${_xml}" "${DO_URL}")"; then 106 | _err "Error <$1>" 107 | return 1 108 | fi 109 | _debug2 "SOAP response $response" 110 | 111 | # retrieve cookie header 112 | _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" 113 | export _H2 114 | 115 | return 0 116 | } 117 | 118 | _get_root() { 119 | domain=$1 120 | i=1 121 | 122 | _dns_do_soap getDomainList 123 | _all_domains="$(echo "${response}" \ 124 | | tr -d "\n\r\t " \ 125 | | _egrep_o 'domain]+>[^<]+' \ 126 | | sed -e 's/^domain<\/key>]*>//g')" 127 | 128 | while true; do 129 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 130 | if [ -z "$h" ]; then 131 | return 1 132 | fi 133 | 134 | if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then 135 | _domain="$h" 136 | return 0 137 | fi 138 | 139 | i=$(_math $i + 1) 140 | done 141 | _debug "$domain not found" 142 | 143 | return 1 144 | } 145 | 146 | _regexcape() { 147 | echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g' 148 | } 149 | -------------------------------------------------------------------------------- /dnsapi/dns_vscale.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #This is the vscale.io api wrapper for acme.sh 4 | # 5 | #Author: Alex Loban 6 | #Report Bugs here: https://github.com/LAV45/acme.sh 7 | 8 | #VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" 9 | VSCALE_API_URL="https://api.vscale.io/v1" 10 | 11 | ######## Public functions ##################### 12 | 13 | #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 14 | dns_vscale_add() { 15 | fulldomain=$1 16 | txtvalue=$2 17 | 18 | if [ -z "$VSCALE_API_KEY" ]; then 19 | VSCALE_API_KEY="" 20 | _err "You didn't specify the VSCALE api key yet." 21 | _err "Please create you key and try again." 22 | return 1 23 | fi 24 | 25 | _saveaccountconf VSCALE_API_KEY "$VSCALE_API_KEY" 26 | 27 | _debug "First detect the root zone" 28 | if ! _get_root "$fulldomain"; then 29 | _err "invalid domain" 30 | return 1 31 | fi 32 | _debug _domain_id "$_domain_id" 33 | _debug _sub_domain "$_sub_domain" 34 | _debug _domain "$_domain" 35 | 36 | _vscale_tmpl_json="{\"type\":\"TXT\",\"name\":\"$_sub_domain.$_domain\",\"content\":\"$txtvalue\"}" 37 | 38 | if _vscale_rest POST "domains/$_domain_id/records/" "$_vscale_tmpl_json"; then 39 | response=$(printf "%s\n" "$response" | _egrep_o "{\"error\": \".+\"" | cut -d : -f 2) 40 | if [ -z "$response" ]; then 41 | _info "txt record updated success." 42 | return 0 43 | fi 44 | fi 45 | 46 | return 1 47 | } 48 | 49 | #fulldomain txtvalue 50 | dns_vscale_rm() { 51 | fulldomain=$1 52 | txtvalue=$2 53 | 54 | _debug "First detect the root zone" 55 | if ! _get_root "$fulldomain"; then 56 | _err "invalid domain" 57 | return 1 58 | fi 59 | _debug _domain_id "$_domain_id" 60 | _debug _sub_domain "$_sub_domain" 61 | _debug _domain "$_domain" 62 | 63 | _debug "Getting txt records" 64 | _vscale_rest GET "domains/$_domain_id/records/" 65 | 66 | if [ -n "$response" ]; then 67 | record_id=$(printf "%s\n" "$response" | _egrep_o "\"TXT\", \"id\": [0-9]+, \"name\": \"$_sub_domain.$_domain\"" | cut -d : -f 2 | tr -d ", \"name\"") 68 | _debug record_id "$record_id" 69 | if [ -z "$record_id" ]; then 70 | _err "Can not get record id to remove." 71 | return 1 72 | fi 73 | if _vscale_rest DELETE "domains/$_domain_id/records/$record_id" && [ -z "$response" ]; then 74 | _info "txt record deleted success." 75 | return 0 76 | fi 77 | _debug response "$response" 78 | return 1 79 | fi 80 | 81 | return 1 82 | } 83 | 84 | #################### Private functions below ################################## 85 | #_acme-challenge.www.domain.com 86 | #returns 87 | # _sub_domain=_acme-challenge.www 88 | # _domain=domain.com 89 | # _domain_id=12345 90 | _get_root() { 91 | domain=$1 92 | i=2 93 | p=1 94 | 95 | if _vscale_rest GET "domains/"; then 96 | response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" 97 | while true; do 98 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 99 | _debug h "$h" 100 | if [ -z "$h" ]; then 101 | #not valid 102 | return 1 103 | fi 104 | 105 | hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" 106 | if [ "$hostedzone" ]; then 107 | _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) 108 | if [ "$_domain_id" ]; then 109 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 110 | _domain=$h 111 | return 0 112 | fi 113 | return 1 114 | fi 115 | p=$i 116 | i=$(_math "$i" + 1) 117 | done 118 | fi 119 | return 1 120 | } 121 | 122 | #method uri qstr data 123 | _vscale_rest() { 124 | mtd="$1" 125 | ep="$2" 126 | data="$3" 127 | 128 | _debug mtd "$mtd" 129 | _debug ep "$ep" 130 | 131 | export _H1="Accept: application/json" 132 | export _H2="Content-Type: application/json" 133 | export _H3="X-Token: ${VSCALE_API_KEY}" 134 | 135 | if [ "$mtd" != "GET" ]; then 136 | # both POST and DELETE. 137 | _debug data "$data" 138 | response="$(_post "$data" "$VSCALE_API_URL/$ep" "" "$mtd")" 139 | else 140 | response="$(_get "$VSCALE_API_URL/$ep")" 141 | fi 142 | 143 | if [ "$?" != "0" ]; then 144 | _err "error $ep" 145 | return 1 146 | fi 147 | _debug2 response "$response" 148 | return 0 149 | } 150 | -------------------------------------------------------------------------------- /dnsapi/dns_selectel.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | #SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" 5 | # 6 | 7 | SL_Api="https://api.selectel.ru/domains/v1" 8 | 9 | ######## Public functions ##################### 10 | 11 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 12 | dns_selectel_add() { 13 | fulldomain=$1 14 | txtvalue=$2 15 | 16 | SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}" 17 | 18 | if [ -z "$SL_Key" ]; then 19 | SL_Key="" 20 | _err "You don't specify selectel.ru api key yet." 21 | _err "Please create you key and try again." 22 | return 1 23 | fi 24 | 25 | #save the api key to the account conf file. 26 | _saveaccountconf_mutable SL_Key "$SL_Key" 27 | 28 | _debug "First detect the root zone" 29 | if ! _get_root "$fulldomain"; then 30 | _err "invalid domain" 31 | return 1 32 | fi 33 | _debug _domain_id "$_domain_id" 34 | _debug _sub_domain "$_sub_domain" 35 | _debug _domain "$_domain" 36 | 37 | _info "Adding record" 38 | if _sl_rest POST "/$_domain_id/records/" "{\"type\": \"TXT\", \"ttl\": 60, \"name\": \"$fulldomain\", \"content\": \"$txtvalue\"}"; then 39 | if _contains "$response" "$txtvalue" || _contains "$response" "record_already_exists"; then 40 | _info "Added, OK" 41 | return 0 42 | fi 43 | fi 44 | _err "Add txt record error." 45 | return 1 46 | } 47 | 48 | #fulldomain txtvalue 49 | dns_selectel_rm() { 50 | fulldomain=$1 51 | txtvalue=$2 52 | 53 | SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}" 54 | 55 | if [ -z "$SL_Key" ]; then 56 | SL_Key="" 57 | _err "You don't specify slectel api key yet." 58 | _err "Please create you key and try again." 59 | return 1 60 | fi 61 | 62 | _debug "First detect the root zone" 63 | if ! _get_root "$fulldomain"; then 64 | _err "invalid domain" 65 | return 1 66 | fi 67 | _debug _domain_id "$_domain_id" 68 | _debug _sub_domain "$_sub_domain" 69 | _debug _domain "$_domain" 70 | 71 | _debug "Getting txt records" 72 | _sl_rest GET "/${_domain_id}/records/" 73 | 74 | if ! _contains "$response" "$txtvalue"; then 75 | _err "Txt record not found" 76 | return 1 77 | fi 78 | 79 | _record_seg="$(echo "$response" | _egrep_o "\"content\" *: *\"$txtvalue\"[^}]*}")" 80 | _debug2 "_record_seg" "$_record_seg" 81 | if [ -z "$_record_seg" ]; then 82 | _err "can not find _record_seg" 83 | return 1 84 | fi 85 | 86 | _record_id="$(echo "$_record_seg" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\"" | cut -d : -f 2)" 87 | _debug2 "_record_id" "$_record_id" 88 | if [ -z "$_record_id" ]; then 89 | _err "can not find _record_id" 90 | return 1 91 | fi 92 | 93 | if ! _sl_rest DELETE "/$_domain_id/records/$_record_id"; then 94 | _err "Delete record error." 95 | return 1 96 | fi 97 | return 0 98 | } 99 | 100 | #################### Private functions below ################################## 101 | #_acme-challenge.www.domain.com 102 | #returns 103 | # _sub_domain=_acme-challenge.www 104 | # _domain=domain.com 105 | # _domain_id=sdjkglgdfewsdfg 106 | _get_root() { 107 | domain=$1 108 | 109 | if ! _sl_rest GET "/"; then 110 | return 1 111 | fi 112 | 113 | i=2 114 | p=1 115 | while true; do 116 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 117 | _debug h "$h" 118 | if [ -z "$h" ]; then 119 | #not valid 120 | return 1 121 | fi 122 | 123 | if _contains "$response" "\"name\": \"$h\","; then 124 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 125 | _domain=$h 126 | _debug "Getting domain id for $h" 127 | if ! _sl_rest GET "/$h"; then 128 | return 1 129 | fi 130 | _domain_id="$(echo "$response" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\":" | cut -d : -f 2)" 131 | return 0 132 | fi 133 | p=$i 134 | i=$(_math "$i" + 1) 135 | done 136 | return 1 137 | } 138 | 139 | _sl_rest() { 140 | m=$1 141 | ep="$2" 142 | data="$3" 143 | _debug "$ep" 144 | 145 | export _H1="X-Token: $SL_Key" 146 | export _H2="Content-Type: application/json" 147 | 148 | if [ "$m" != "GET" ]; then 149 | _debug data "$data" 150 | response="$(_post "$data" "$SL_Api/$ep" "" "$m")" 151 | else 152 | response="$(_get "$SL_Api/$ep")" 153 | fi 154 | 155 | if [ "$?" != "0" ]; then 156 | _err "error $ep" 157 | return 1 158 | fi 159 | _debug2 response "$response" 160 | return 0 161 | } 162 | -------------------------------------------------------------------------------- /dnsapi/dns_cn.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/). 4 | # created by 5ll and francis 5 | 6 | CN_API="https://beta.api.core-networks.de" 7 | 8 | ######## Public functions ##################### 9 | 10 | dns_cn_add() { 11 | fulldomain=$1 12 | txtvalue=$2 13 | 14 | if ! _cn_login; then 15 | _err "login failed" 16 | return 1 17 | fi 18 | 19 | _debug "First detect the root zone" 20 | if ! _cn_get_root "$fulldomain"; then 21 | _err "invalid domain" 22 | return 1 23 | fi 24 | 25 | _debug "_sub_domain $_sub_domain" 26 | _debug "_domain $_domain" 27 | 28 | _info "Adding record" 29 | curData="{\"name\":\"$_sub_domain\",\"ttl\":120,\"type\":\"TXT\",\"data\":\"$txtvalue\"}" 30 | curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/")" 31 | 32 | _debug "curData $curData" 33 | _debug "curResult $curResult" 34 | 35 | if _contains "$curResult" ""; then 36 | _info "Added, OK" 37 | 38 | if ! _cn_commit; then 39 | _err "commiting changes failed" 40 | return 1 41 | fi 42 | return 0 43 | 44 | else 45 | _err "Add txt record error." 46 | _debug "curData is $curData" 47 | _debug "curResult is $curResult" 48 | _err "error adding text record, response was $curResult" 49 | return 1 50 | fi 51 | } 52 | 53 | dns_cn_rm() { 54 | fulldomain=$1 55 | txtvalue=$2 56 | 57 | if ! _cn_login; then 58 | _err "login failed" 59 | return 1 60 | fi 61 | 62 | _debug "First detect the root zone" 63 | if ! _cn_get_root "$fulldomain"; then 64 | _err "invalid domain" 65 | return 1 66 | fi 67 | 68 | _info "Deleting record" 69 | curData="{\"name\":\"$_sub_domain\",\"data\":\"$txtvalue\"}" 70 | curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/delete")" 71 | _debug curData is "$curData" 72 | 73 | _info "commiting changes" 74 | if ! _cn_commit; then 75 | _err "commiting changes failed" 76 | return 1 77 | fi 78 | 79 | _info "Deletet txt record" 80 | return 0 81 | } 82 | 83 | ################### Private functions below ################################## 84 | _cn_login() { 85 | CN_User="${CN_User:-$(_readaccountconf_mutable CN_User)}" 86 | CN_Password="${CN_Password:-$(_readaccountconf_mutable CN_Password)}" 87 | if [ -z "$CN_User" ] || [ -z "$CN_Password" ]; then 88 | CN_User="" 89 | CN_Password="" 90 | _err "You must export variables: CN_User and CN_Password" 91 | return 1 92 | fi 93 | 94 | #save the config variables to the account conf file. 95 | _saveaccountconf_mutable CN_User "$CN_User" 96 | _saveaccountconf_mutable CN_Password "$CN_Password" 97 | 98 | _info "Getting an AUTH-Token" 99 | curData="{\"login\":\"${CN_User}\",\"password\":\"${CN_Password}\"}" 100 | curResult="$(_post "${curData}" "${CN_API}/auth/token")" 101 | _debug "Calling _CN_login: '${curData}' '${CN_API}/auth/token'" 102 | 103 | if _contains "${curResult}" '"token":"'; then 104 | authToken=$(echo "${curResult}" | cut -d ":" -f2 | cut -d "," -f1 | sed 's/^.\(.*\).$/\1/') 105 | export _H1="Authorization: Bearer $authToken" 106 | _info "Successfully acquired AUTH-Token" 107 | _debug "AUTH-Token: '${authToken}'" 108 | _debug "_H1 '${_H1}'" 109 | else 110 | _err "Couldn't acquire an AUTH-Token" 111 | return 1 112 | fi 113 | } 114 | 115 | # Commit changes 116 | _cn_commit() { 117 | _info "Commiting changes" 118 | _post "" "${CN_API}/dnszones/$h/records/commit" 119 | } 120 | 121 | _cn_get_root() { 122 | domain=$1 123 | i=2 124 | p=1 125 | while true; do 126 | 127 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 128 | _debug h "$h" 129 | _debug _H1 "${_H1}" 130 | 131 | if [ -z "$h" ]; then 132 | #not valid 133 | return 1 134 | fi 135 | 136 | _cn_zonelist="$(_get ${CN_API}/dnszones/)" 137 | _debug _cn_zonelist "${_cn_zonelist}" 138 | 139 | if [ "$?" != "0" ]; then 140 | _err "something went wrong while getting the zone list" 141 | return 1 142 | fi 143 | 144 | if _contains "$_cn_zonelist" "\"name\":\"$h\"" >/dev/null; then 145 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 146 | _domain=$h 147 | return 0 148 | else 149 | _debug "Zonelist does not contain domain - iterating " 150 | fi 151 | p=$i 152 | i=$(_math "$i" + 1) 153 | 154 | done 155 | _err "Zonelist does not contain domain - exiting" 156 | return 1 157 | } 158 | -------------------------------------------------------------------------------- /dnsapi/dns_zone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Zone.ee dns API 4 | # https://help.zone.eu/kb/zoneid-api-v2/ 5 | # required ZONE_Username and ZONE_Key 6 | 7 | ZONE_Api="https://api.zone.eu/v2" 8 | ######## Public functions ##################### 9 | 10 | #Usage: dns_zone_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 11 | dns_zone_add() { 12 | fulldomain=$1 13 | txtvalue=$2 14 | _info "Using zone.ee dns api" 15 | _debug fulldomain "$fulldomain" 16 | _debug txtvalue "$txtvalue" 17 | ZONE_Username="${ZONE_Username:-$(_readaccountconf_mutable ZONE_Username)}" 18 | ZONE_Key="${ZONE_Key:-$(_readaccountconf_mutable ZONE_Key)}" 19 | if [ -z "$ZONE_Username" ] || [ -z "$ZONE_Key" ]; then 20 | ZONE_Username="" 21 | ZONE_Key="" 22 | _err "Zone api key and username must be present." 23 | return 1 24 | fi 25 | _saveaccountconf_mutable ZONE_Username "$ZONE_Username" 26 | _saveaccountconf_mutable ZONE_Key "$ZONE_Key" 27 | _debug "First detect the root zone" 28 | if ! _get_root "$fulldomain"; then 29 | _err "invalid domain" 30 | return 1 31 | fi 32 | 33 | _debug "Adding txt record" 34 | 35 | if _zone_rest POST "dns/${_domain}/txt" "{\"name\": \"$fulldomain\", \"destination\": \"$txtvalue\"}"; then 36 | if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then 37 | _info "Added, OK" 38 | return 0 39 | else 40 | _err "Adding txt record error." 41 | return 1 42 | fi 43 | else 44 | _err "Adding txt record error." 45 | fi 46 | } 47 | 48 | #Usage: fulldomain txtvalue 49 | #Remove the txt record after validation. 50 | dns_zone_rm() { 51 | fulldomain=$1 52 | txtvalue=$2 53 | _info "Using zone.ee dns api" 54 | _debug fulldomain "$fulldomain" 55 | _debug txtvalue "$txtvalue" 56 | ZONE_Username="${ZONE_Username:-$(_readaccountconf_mutable ZONE_Username)}" 57 | ZONE_Key="${ZONE_Key:-$(_readaccountconf_mutable ZONE_Key)}" 58 | if [ -z "$ZONE_Username" ] || [ -z "$ZONE_Key" ]; then 59 | ZONE_Username="" 60 | ZONE_Key="" 61 | _err "Zone api key and username must be present." 62 | return 1 63 | fi 64 | _saveaccountconf_mutable ZONE_Username "$ZONE_Username" 65 | _saveaccountconf_mutable ZONE_Key "$ZONE_Key" 66 | _debug "First detect the root zone" 67 | if ! _get_root "$fulldomain"; then 68 | _err "invalid domain" 69 | return 1 70 | fi 71 | 72 | _debug "Getting txt records" 73 | _debug _domain "$_domain" 74 | 75 | _zone_rest GET "dns/${_domain}/txt" 76 | 77 | if printf "%s" "$response" | grep \"error\" >/dev/null; then 78 | _err "Error" 79 | return 1 80 | fi 81 | 82 | count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l) 83 | _debug count "$count" 84 | if [ "$count" = "0" ]; then 85 | _info "Nothing to remove." 86 | else 87 | record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\",\"resource_url\":\"[^\"]*\",\"name\":\"$fulldomain\"," | cut -d : -f2 | cut -d , -f1 | tr -d \" | _head_n 1) 88 | if [ -z "$record_id" ]; then 89 | _err "No id found to remove." 90 | return 1 91 | fi 92 | if ! _zone_rest DELETE "dns/${_domain}/txt/$record_id"; then 93 | _err "Record deleting error." 94 | return 1 95 | fi 96 | _info "Record deleted" 97 | return 0 98 | fi 99 | 100 | } 101 | 102 | #################### Private functions below ################################## 103 | 104 | _zone_rest() { 105 | m=$1 106 | ep="$2" 107 | data="$3" 108 | _debug "$ep" 109 | 110 | realm="$(printf "%s" "$ZONE_Username:$ZONE_Key" | _base64)" 111 | 112 | export _H1="Authorization: Basic $realm" 113 | export _H2="Content-Type: application/json" 114 | 115 | if [ "$m" != "GET" ]; then 116 | _debug data "$data" 117 | response="$(_post "$data" "$ZONE_Api/$ep" "" "$m")" 118 | else 119 | response="$(_get "$ZONE_Api/$ep")" 120 | fi 121 | 122 | if [ "$?" != "0" ]; then 123 | _err "error $ep" 124 | return 1 125 | fi 126 | _debug2 response "$response" 127 | return 0 128 | } 129 | 130 | _get_root() { 131 | domain=$1 132 | i=2 133 | while true; do 134 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 135 | _debug h "$h" 136 | if [ -z "$h" ]; then 137 | return 1 138 | fi 139 | if ! _zone_rest GET "dns/$h/a"; then 140 | return 1 141 | fi 142 | if _contains "$response" "\"name\":\"$h\"" >/dev/null; then 143 | _domain=$h 144 | return 0 145 | fi 146 | i=$(_math "$i" + 1) 147 | done 148 | return 0 149 | } 150 | -------------------------------------------------------------------------------- /dnsapi/dns_dp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Dnspod.cn Domain api 4 | # 5 | #DP_Id="1234" 6 | # 7 | #DP_Key="sADDsdasdgdsf" 8 | 9 | REST_API="https://dnsapi.cn" 10 | 11 | ######## Public functions ##################### 12 | 13 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 14 | dns_dp_add() { 15 | fulldomain=$1 16 | txtvalue=$2 17 | 18 | DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}" 19 | DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}" 20 | if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then 21 | DP_Id="" 22 | DP_Key="" 23 | _err "You don't specify dnspod api key and key id yet." 24 | _err "Please create you key and try again." 25 | return 1 26 | fi 27 | 28 | #save the api key and email to the account conf file. 29 | _saveaccountconf_mutable DP_Id "$DP_Id" 30 | _saveaccountconf_mutable DP_Key "$DP_Key" 31 | 32 | _debug "First detect the root zone" 33 | if ! _get_root "$fulldomain"; then 34 | _err "invalid domain" 35 | return 1 36 | fi 37 | 38 | add_record "$_domain" "$_sub_domain" "$txtvalue" 39 | 40 | } 41 | 42 | #fulldomain txtvalue 43 | dns_dp_rm() { 44 | fulldomain=$1 45 | txtvalue=$2 46 | 47 | DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}" 48 | DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}" 49 | 50 | _debug "First detect the root zone" 51 | if ! _get_root "$fulldomain"; then 52 | _err "invalid domain" 53 | return 1 54 | fi 55 | 56 | if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then 57 | _err "Record.Lis error." 58 | return 1 59 | fi 60 | 61 | if _contains "$response" 'No records'; then 62 | _info "Don't need to remove." 63 | return 0 64 | fi 65 | 66 | record_id=$(echo "$response" | tr "{" "\n" | grep "$txtvalue" | grep '^"id"' | cut -d : -f 2 | cut -d '"' -f 2) 67 | _debug record_id "$record_id" 68 | if [ -z "$record_id" ]; then 69 | _err "Can not get record id." 70 | return 1 71 | fi 72 | 73 | if ! _rest POST "Record.Remove" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then 74 | _err "Record.Remove error." 75 | return 1 76 | fi 77 | 78 | _contains "$response" "Action completed successful" 79 | 80 | } 81 | 82 | #add the txt record. 83 | #usage: root sub txtvalue 84 | add_record() { 85 | root=$1 86 | sub=$2 87 | txtvalue=$3 88 | fulldomain="$sub.$root" 89 | 90 | _info "Adding record" 91 | 92 | if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then 93 | return 1 94 | fi 95 | 96 | _contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists" 97 | } 98 | 99 | #################### Private functions below ################################## 100 | #_acme-challenge.www.domain.com 101 | #returns 102 | # _sub_domain=_acme-challenge.www 103 | # _domain=domain.com 104 | # _domain_id=sdjkglgdfewsdfg 105 | _get_root() { 106 | domain=$1 107 | i=2 108 | p=1 109 | while true; do 110 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 111 | if [ -z "$h" ]; then 112 | #not valid 113 | return 1 114 | fi 115 | 116 | if ! _rest POST "Domain.Info" "login_token=$DP_Id,$DP_Key&format=json&domain=$h"; then 117 | return 1 118 | fi 119 | 120 | if _contains "$response" "Action completed successful"; then 121 | _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") 122 | _debug _domain_id "$_domain_id" 123 | if [ "$_domain_id" ]; then 124 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 125 | _debug _sub_domain "$_sub_domain" 126 | _domain="$h" 127 | _debug _domain "$_domain" 128 | return 0 129 | fi 130 | return 1 131 | fi 132 | p="$i" 133 | i=$(_math "$i" + 1) 134 | done 135 | return 1 136 | } 137 | 138 | #Usage: method URI data 139 | _rest() { 140 | m="$1" 141 | ep="$2" 142 | data="$3" 143 | _debug "$ep" 144 | url="$REST_API/$ep" 145 | 146 | _debug url "$url" 147 | 148 | if [ "$m" = "GET" ]; then 149 | response="$(_get "$url" | tr -d '\r')" 150 | else 151 | _debug2 data "$data" 152 | response="$(_post "$data" "$url" | tr -d '\r')" 153 | fi 154 | 155 | if [ "$?" != "0" ]; then 156 | _err "error $ep" 157 | return 1 158 | fi 159 | _debug2 response "$response" 160 | return 0 161 | } 162 | -------------------------------------------------------------------------------- /deploy/fritzbox.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Here is a script to deploy cert to an AVM FRITZ!Box router. 4 | 5 | #returns 0 means success, otherwise error. 6 | 7 | #DEPLOY_FRITZBOX_USERNAME="username" 8 | #DEPLOY_FRITZBOX_PASSWORD="password" 9 | #DEPLOY_FRITZBOX_URL="https://fritz.box" 10 | 11 | # Kudos to wikrie at Github for his FRITZ!Box update script: 12 | # https://gist.github.com/wikrie/f1d5747a714e0a34d0582981f7cb4cfb 13 | 14 | ######## Public functions ##################### 15 | 16 | #domain keyfile certfile cafile fullchain 17 | fritzbox_deploy() { 18 | _cdomain="$1" 19 | _ckey="$2" 20 | _ccert="$3" 21 | _cca="$4" 22 | _cfullchain="$5" 23 | 24 | _debug _cdomain "$_cdomain" 25 | _debug _ckey "$_ckey" 26 | _debug _ccert "$_ccert" 27 | _debug _cca "$_cca" 28 | _debug _cfullchain "$_cfullchain" 29 | 30 | if ! _exists iconv; then 31 | if ! _exists perl; then 32 | _err "iconv or perl not found" 33 | return 1 34 | fi 35 | fi 36 | 37 | _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" 38 | _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" 39 | _fritzbox_url="${DEPLOY_FRITZBOX_URL}" 40 | 41 | _debug _fritzbox_url "$_fritzbox_url" 42 | _debug _fritzbox_username "$_fritzbox_username" 43 | _secure_debug _fritzbox_password "$_fritzbox_password" 44 | if [ -z "$_fritzbox_username" ]; then 45 | _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." 46 | return 1 47 | fi 48 | if [ -z "$_fritzbox_password" ]; then 49 | _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." 50 | return 1 51 | fi 52 | if [ -z "$_fritzbox_url" ]; then 53 | _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." 54 | return 1 55 | fi 56 | 57 | _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" 58 | _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" 59 | _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" 60 | 61 | # Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate 62 | export HTTPS_INSECURE=1 63 | 64 | _info "Log in to the FRITZ!Box" 65 | _fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" 66 | if _exists iconv; then 67 | _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" 68 | else 69 | _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | md5sum | awk '{print $1}')" 70 | fi 71 | _fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" 72 | 73 | if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then 74 | _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." 75 | return 1 76 | fi 77 | 78 | _info "Generate form POST request" 79 | _post_request="$(_mktemp)" 80 | _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" 81 | # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it! 82 | _CERTPASSWORD_= 83 | { 84 | printf -- "--" 85 | printf -- "%s\r\n" "${_post_boundary}" 86 | printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" 87 | printf -- "--" 88 | printf -- "%s\r\n" "${_post_boundary}" 89 | printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" 90 | printf -- "--" 91 | printf -- "%s\r\n" "${_post_boundary}" 92 | printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" 93 | printf "Content-Type: application/octet-stream\r\n\r\n" 94 | cat "${_ckey}" "${_cfullchain}" 95 | printf "\r\n" 96 | printf -- "--" 97 | printf -- "%s--" "${_post_boundary}" 98 | } >>"${_post_request}" 99 | 100 | _info "Upload certificate to the FRITZ!Box" 101 | 102 | export _H1="Content-type: multipart/form-data boundary=${_post_boundary}" 103 | _post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL 104 | 105 | retval=$? 106 | if [ $retval = 0 ]; then 107 | _info "Upload successful" 108 | else 109 | _err "Upload failed" 110 | fi 111 | rm "${_post_request}" 112 | 113 | return $retval 114 | } 115 | -------------------------------------------------------------------------------- /dnsapi/dns_dpi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Dnspod.com Domain api 4 | # 5 | #DPI_Id="1234" 6 | # 7 | #DPI_Key="sADDsdasdgdsf" 8 | 9 | REST_API="https://api.dnspod.com" 10 | 11 | ######## Public functions ##################### 12 | 13 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 14 | dns_dpi_add() { 15 | fulldomain=$1 16 | txtvalue=$2 17 | 18 | DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}" 19 | DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}" 20 | if [ -z "$DPI_Id" ] || [ -z "$DPI_Key" ]; then 21 | DPI_Id="" 22 | DPI_Key="" 23 | _err "You don't specify dnspod api key and key id yet." 24 | _err "Please create you key and try again." 25 | return 1 26 | fi 27 | 28 | #save the api key and email to the account conf file. 29 | _saveaccountconf_mutable DPI_Id "$DPI_Id" 30 | _saveaccountconf_mutable DPI_Key "$DPI_Key" 31 | 32 | _debug "First detect the root zone" 33 | if ! _get_root "$fulldomain"; then 34 | _err "invalid domain" 35 | return 1 36 | fi 37 | 38 | add_record "$_domain" "$_sub_domain" "$txtvalue" 39 | 40 | } 41 | 42 | #fulldomain txtvalue 43 | dns_dpi_rm() { 44 | fulldomain=$1 45 | txtvalue=$2 46 | 47 | DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}" 48 | DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}" 49 | 50 | _debug "First detect the root zone" 51 | if ! _get_root "$fulldomain"; then 52 | _err "invalid domain" 53 | return 1 54 | fi 55 | 56 | if ! _rest POST "Record.List" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then 57 | _err "Record.Lis error." 58 | return 1 59 | fi 60 | 61 | if _contains "$response" 'No records'; then 62 | _info "Don't need to remove." 63 | return 0 64 | fi 65 | 66 | record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") 67 | _debug record_id "$record_id" 68 | if [ -z "$record_id" ]; then 69 | _err "Can not get record id." 70 | return 1 71 | fi 72 | 73 | if ! _rest POST "Record.Remove" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then 74 | _err "Record.Remove error." 75 | return 1 76 | fi 77 | 78 | _contains "$response" "Action completed successful" 79 | 80 | } 81 | 82 | #add the txt record. 83 | #usage: root sub txtvalue 84 | add_record() { 85 | root=$1 86 | sub=$2 87 | txtvalue=$3 88 | fulldomain="$sub.$root" 89 | 90 | _info "Adding record" 91 | 92 | if ! _rest POST "Record.Create" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=default"; then 93 | return 1 94 | fi 95 | 96 | _contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists" 97 | } 98 | 99 | #################### Private functions below ################################## 100 | #_acme-challenge.www.domain.com 101 | #returns 102 | # _sub_domain=_acme-challenge.www 103 | # _domain=domain.com 104 | # _domain_id=sdjkglgdfewsdfg 105 | _get_root() { 106 | domain=$1 107 | i=2 108 | p=1 109 | while true; do 110 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 111 | if [ -z "$h" ]; then 112 | #not valid 113 | return 1 114 | fi 115 | 116 | if ! _rest POST "Domain.Info" "user_token=$DPI_Id,$DPI_Key&format=json&domain=$h"; then 117 | return 1 118 | fi 119 | 120 | if _contains "$response" "Action completed successful"; then 121 | _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") 122 | _debug _domain_id "$_domain_id" 123 | if [ "$_domain_id" ]; then 124 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 125 | _debug _sub_domain "$_sub_domain" 126 | _domain="$h" 127 | _debug _domain "$_domain" 128 | return 0 129 | fi 130 | return 1 131 | fi 132 | p="$i" 133 | i=$(_math "$i" + 1) 134 | done 135 | return 1 136 | } 137 | 138 | #Usage: method URI data 139 | _rest() { 140 | m="$1" 141 | ep="$2" 142 | data="$3" 143 | _debug "$ep" 144 | url="$REST_API/$ep" 145 | 146 | _debug url "$url" 147 | 148 | if [ "$m" = "GET" ]; then 149 | response="$(_get "$url" | tr -d '\r')" 150 | else 151 | _debug2 data "$data" 152 | response="$(_post "$data" "$url" | tr -d '\r')" 153 | fi 154 | 155 | if [ "$?" != "0" ]; then 156 | _err "error $ep" 157 | return 1 158 | fi 159 | _debug2 response "$response" 160 | return 0 161 | } 162 | -------------------------------------------------------------------------------- /dnsapi/dns_me.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # bug reports to dev@1e.ca 4 | 5 | # ME_Key=qmlkdjflmkqdjf 6 | # ME_Secret=qmsdlkqmlksdvnnpae 7 | 8 | ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed 9 | 10 | ######## Public functions ##################### 11 | 12 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 13 | dns_me_add() { 14 | fulldomain=$1 15 | txtvalue=$2 16 | 17 | if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ]; then 18 | ME_Key="" 19 | ME_Secret="" 20 | _err "You didn't specify DNSMadeEasy api key and secret yet." 21 | _err "Please create you key and try again." 22 | return 1 23 | fi 24 | 25 | #save the api key and email to the account conf file. 26 | _saveaccountconf ME_Key "$ME_Key" 27 | _saveaccountconf ME_Secret "$ME_Secret" 28 | 29 | _debug "First detect the root zone" 30 | if ! _get_root "$fulldomain"; then 31 | _err "invalid domain" 32 | return 1 33 | fi 34 | _debug _domain_id "$_domain_id" 35 | _debug _sub_domain "$_sub_domain" 36 | _debug _domain "$_domain" 37 | 38 | _debug "Getting txt records" 39 | _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" 40 | 41 | if ! _contains "$response" "\"totalRecords\":"; then 42 | _err "Error" 43 | return 1 44 | fi 45 | 46 | _info "Adding record" 47 | if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then 48 | if printf -- "%s" "$response" | grep \"id\": >/dev/null; then 49 | _info "Added" 50 | #todo: check if the record takes effect 51 | return 0 52 | else 53 | _err "Add txt record error." 54 | return 1 55 | fi 56 | fi 57 | 58 | } 59 | 60 | #fulldomain 61 | dns_me_rm() { 62 | fulldomain=$1 63 | txtvalue=$2 64 | _debug "First detect the root zone" 65 | if ! _get_root "$fulldomain"; then 66 | _err "invalid domain" 67 | return 1 68 | fi 69 | _debug _domain_id "$_domain_id" 70 | _debug _sub_domain "$_sub_domain" 71 | _debug _domain "$_domain" 72 | 73 | _debug "Getting txt records" 74 | _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" 75 | 76 | count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) 77 | _debug count "$count" 78 | if [ "$count" = "0" ]; then 79 | _info "Don't need to remove." 80 | else 81 | record_id=$(printf "%s\n" "$response" | _egrep_o ",\"value\":\"..$txtvalue..\",\"id\":[^,]*" | cut -d : -f 3 | head -n 1) 82 | _debug "record_id" "$record_id" 83 | if [ -z "$record_id" ]; then 84 | _err "Can not get record id to remove." 85 | return 1 86 | fi 87 | if ! _me_rest DELETE "$_domain_id/records/$record_id"; then 88 | _err "Delete record error." 89 | return 1 90 | fi 91 | _contains "$response" '' 92 | fi 93 | } 94 | 95 | #################### Private functions below ################################## 96 | #_acme-challenge.www.domain.com 97 | #returns 98 | # _sub_domain=_acme-challenge.www 99 | # _domain=domain.com 100 | # _domain_id=sdjkglgdfewsdfg 101 | _get_root() { 102 | domain=$1 103 | i=2 104 | p=1 105 | while true; do 106 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 107 | if [ -z "$h" ]; then 108 | #not valid 109 | return 1 110 | fi 111 | 112 | if ! _me_rest GET "name?domainname=$h"; then 113 | return 1 114 | fi 115 | 116 | if _contains "$response" "\"name\":\"$h\""; then 117 | _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | head -n 1 | cut -d : -f 2 | tr -d '}') 118 | if [ "$_domain_id" ]; then 119 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 120 | _domain="$h" 121 | return 0 122 | fi 123 | return 1 124 | fi 125 | p=$i 126 | i=$(_math "$i" + 1) 127 | done 128 | return 1 129 | } 130 | 131 | _me_rest() { 132 | m=$1 133 | ep="$2" 134 | data="$3" 135 | _debug "$ep" 136 | 137 | cdate=$(LANG=C date -u +"%a, %d %b %Y %T %Z") 138 | hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex) 139 | 140 | export _H1="x-dnsme-apiKey: $ME_Key" 141 | export _H2="x-dnsme-requestDate: $cdate" 142 | export _H3="x-dnsme-hmac: $hmac" 143 | 144 | if [ "$m" != "GET" ]; then 145 | _debug data "$data" 146 | response="$(_post "$data" "$ME_Api/$ep" "" "$m")" 147 | else 148 | response="$(_get "$ME_Api/$ep")" 149 | fi 150 | 151 | if [ "$?" != "0" ]; then 152 | _err "error $ep" 153 | return 1 154 | fi 155 | _debug2 response "$response" 156 | return 0 157 | } 158 | -------------------------------------------------------------------------------- /dnsapi/dns_nsone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # bug reports to dev@1e.ca 4 | 5 | # 6 | #NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" 7 | # 8 | 9 | NS1_Api="https://api.nsone.net/v1" 10 | 11 | ######## Public functions ##################### 12 | 13 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 14 | dns_nsone_add() { 15 | fulldomain=$1 16 | txtvalue=$2 17 | 18 | if [ -z "$NS1_Key" ]; then 19 | NS1_Key="" 20 | _err "You didn't specify nsone dns api key yet." 21 | _err "Please create you key and try again." 22 | return 1 23 | fi 24 | 25 | #save the api key and email to the account conf file. 26 | _saveaccountconf NS1_Key "$NS1_Key" 27 | 28 | _debug "First detect the root zone" 29 | if ! _get_root "$fulldomain"; then 30 | _err "invalid domain" 31 | return 1 32 | fi 33 | _debug _sub_domain "$_sub_domain" 34 | _debug _domain "$_domain" 35 | 36 | _debug "Getting txt records" 37 | _nsone_rest GET "zones/${_domain}" 38 | 39 | if ! _contains "$response" "\"records\":"; then 40 | _err "Error" 41 | return 1 42 | fi 43 | 44 | count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") 45 | _debug count "$count" 46 | if [ "$count" = "0" ]; then 47 | _info "Adding record" 48 | 49 | if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\",\"ttl\":0}"; then 50 | if _contains "$response" "$fulldomain"; then 51 | _info "Added" 52 | #todo: check if the record takes effect 53 | return 0 54 | else 55 | _err "Add txt record error." 56 | return 1 57 | fi 58 | fi 59 | _err "Add txt record error." 60 | else 61 | _info "Updating record" 62 | prev_txt=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",\"short_answers\":\[\"[^,]*\]" | _head_n 1 | cut -d: -f3 | cut -d, -f1) 63 | _debug "prev_txt" "$prev_txt" 64 | 65 | _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]},{\"answer\": $prev_txt}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\",\"ttl\":0}" 66 | if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then 67 | _info "Updated!" 68 | #todo: check if the record takes effect 69 | return 0 70 | fi 71 | _err "Update error" 72 | return 1 73 | fi 74 | 75 | } 76 | 77 | #fulldomain 78 | dns_nsone_rm() { 79 | fulldomain=$1 80 | txtvalue=$2 81 | _debug "First detect the root zone" 82 | if ! _get_root "$fulldomain"; then 83 | _err "invalid domain" 84 | return 1 85 | fi 86 | _debug _sub_domain "$_sub_domain" 87 | _debug _domain "$_domain" 88 | 89 | _debug "Getting txt records" 90 | _nsone_rest GET "zones/${_domain}/$fulldomain/TXT" 91 | 92 | count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ") 93 | _debug count "$count" 94 | if [ "$count" = "0" ]; then 95 | _info "Don't need to remove." 96 | else 97 | if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then 98 | _err "Delete record error." 99 | return 1 100 | fi 101 | _contains "$response" "" 102 | fi 103 | } 104 | 105 | #################### Private functions below ################################## 106 | #_acme-challenge.www.domain.com 107 | #returns 108 | # _sub_domain=_acme-challenge.www 109 | # _domain=domain.com 110 | # _domain_id=sdjkglgdfewsdfg 111 | _get_root() { 112 | domain=$1 113 | i=2 114 | p=1 115 | if ! _nsone_rest GET "zones"; then 116 | return 1 117 | fi 118 | while true; do 119 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 120 | _debug h "$h" 121 | if [ -z "$h" ]; then 122 | #not valid 123 | return 1 124 | fi 125 | 126 | if _contains "$response" "\"zone\":\"$h\""; then 127 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 128 | _domain="$h" 129 | return 0 130 | fi 131 | p=$i 132 | i=$(_math "$i" + 1) 133 | done 134 | return 1 135 | } 136 | 137 | _nsone_rest() { 138 | m=$1 139 | ep="$2" 140 | data="$3" 141 | _debug "$ep" 142 | 143 | export _H1="Accept: application/json" 144 | export _H2="X-NSONE-Key: $NS1_Key" 145 | if [ "$m" != "GET" ]; then 146 | _debug data "$data" 147 | response="$(_post "$data" "$NS1_Api/$ep" "" "$m")" 148 | else 149 | response="$(_get "$NS1_Api/$ep")" 150 | fi 151 | 152 | if [ "$?" != "0" ]; then 153 | _err "error $ep" 154 | return 1 155 | fi 156 | _debug2 response "$response" 157 | return 0 158 | } 159 | -------------------------------------------------------------------------------- /dnsapi/dns_lua.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # bug reports to dev@1e.ca 4 | 5 | # 6 | #LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" 7 | # 8 | #LUA_Email="user@luadns.net" 9 | 10 | LUA_Api="https://api.luadns.com/v1" 11 | 12 | ######## Public functions ##################### 13 | 14 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 15 | dns_lua_add() { 16 | fulldomain=$1 17 | txtvalue=$2 18 | 19 | LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}" 20 | LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}" 21 | LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) 22 | 23 | if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then 24 | LUA_Key="" 25 | LUA_Email="" 26 | _err "You don't specify luadns api key and email yet." 27 | _err "Please create you key and try again." 28 | return 1 29 | fi 30 | 31 | #save the api key and email to the account conf file. 32 | _saveaccountconf_mutable LUA_Key "$LUA_Key" 33 | _saveaccountconf_mutable LUA_Email "$LUA_Email" 34 | 35 | _debug "First detect the root zone" 36 | if ! _get_root "$fulldomain"; then 37 | _err "invalid domain" 38 | return 1 39 | fi 40 | _debug _domain_id "$_domain_id" 41 | _debug _sub_domain "$_sub_domain" 42 | _debug _domain "$_domain" 43 | 44 | _info "Adding record" 45 | if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then 46 | if _contains "$response" "$fulldomain"; then 47 | _info "Added" 48 | #todo: check if the record takes effect 49 | return 0 50 | else 51 | _err "Add txt record error." 52 | return 1 53 | fi 54 | fi 55 | } 56 | 57 | #fulldomain 58 | dns_lua_rm() { 59 | fulldomain=$1 60 | txtvalue=$2 61 | 62 | LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}" 63 | LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}" 64 | LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) 65 | _debug "First detect the root zone" 66 | if ! _get_root "$fulldomain"; then 67 | _err "invalid domain" 68 | return 1 69 | fi 70 | _debug _domain_id "$_domain_id" 71 | _debug _sub_domain "$_sub_domain" 72 | _debug _domain "$_domain" 73 | 74 | _debug "Getting txt records" 75 | _LUA_rest GET "zones/${_domain_id}/records" 76 | 77 | count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") 78 | _debug count "$count" 79 | if [ "$count" = "0" ]; then 80 | _info "Don't need to remove." 81 | else 82 | record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) 83 | _debug "record_id" "$record_id" 84 | if [ -z "$record_id" ]; then 85 | _err "Can not get record id to remove." 86 | return 1 87 | fi 88 | if ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then 89 | _err "Delete record error." 90 | return 1 91 | fi 92 | _contains "$response" "$record_id" 93 | fi 94 | } 95 | 96 | #################### Private functions below ################################## 97 | #_acme-challenge.www.domain.com 98 | #returns 99 | # _sub_domain=_acme-challenge.www 100 | # _domain=domain.com 101 | # _domain_id=sdjkglgdfewsdfg 102 | _get_root() { 103 | domain=$1 104 | i=2 105 | p=1 106 | if ! _LUA_rest GET "zones"; then 107 | return 1 108 | fi 109 | while true; do 110 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 111 | _debug h "$h" 112 | if [ -z "$h" ]; then 113 | #not valid 114 | return 1 115 | fi 116 | 117 | if _contains "$response" "\"name\":\"$h\""; then 118 | _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) 119 | _debug _domain_id "$_domain_id" 120 | if [ "$_domain_id" ]; then 121 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 122 | _domain="$h" 123 | return 0 124 | fi 125 | return 1 126 | fi 127 | p=$i 128 | i=$(_math "$i" + 1) 129 | done 130 | return 1 131 | } 132 | 133 | _LUA_rest() { 134 | m=$1 135 | ep="$2" 136 | data="$3" 137 | _debug "$ep" 138 | 139 | export _H1="Accept: application/json" 140 | export _H2="Authorization: Basic $LUA_auth" 141 | if [ "$m" != "GET" ]; then 142 | _debug data "$data" 143 | response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" 144 | else 145 | response="$(_get "$LUA_Api/$ep")" 146 | fi 147 | 148 | if [ "$?" != "0" ]; then 149 | _err "error $ep" 150 | return 1 151 | fi 152 | _debug2 response "$response" 153 | return 0 154 | } 155 | -------------------------------------------------------------------------------- /dnsapi/dns_cx.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # CloudXNS Domain api 4 | # 5 | #CX_Key="1234" 6 | # 7 | #CX_Secret="sADDsdasdgdsf" 8 | 9 | CX_Api="https://www.cloudxns.net/api2" 10 | 11 | #REST_API 12 | ######## Public functions ##################### 13 | 14 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 15 | dns_cx_add() { 16 | fulldomain=$1 17 | txtvalue=$2 18 | 19 | if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then 20 | CX_Key="" 21 | CX_Secret="" 22 | _err "You don't specify cloudxns.net api key or secret yet." 23 | _err "Please create you key and try again." 24 | return 1 25 | fi 26 | 27 | REST_API="$CX_Api" 28 | 29 | #save the api key and email to the account conf file. 30 | _saveaccountconf CX_Key "$CX_Key" 31 | _saveaccountconf CX_Secret "$CX_Secret" 32 | 33 | _debug "First detect the root zone" 34 | if ! _get_root "$fulldomain"; then 35 | _err "invalid domain" 36 | return 1 37 | fi 38 | 39 | add_record "$_domain" "$_sub_domain" "$txtvalue" 40 | } 41 | 42 | #fulldomain txtvalue 43 | dns_cx_rm() { 44 | fulldomain=$1 45 | txtvalue=$2 46 | REST_API="$CX_Api" 47 | if _get_root "$fulldomain"; then 48 | record_id="" 49 | existing_records "$_domain" "$_sub_domain" "$txtvalue" 50 | if [ "$record_id" ]; then 51 | _rest DELETE "record/$record_id/$_domain_id" "{}" 52 | _info "Deleted record ${fulldomain}" 53 | fi 54 | fi 55 | } 56 | 57 | #usage: root sub 58 | #return if the sub record already exists. 59 | #echos the existing records count. 60 | # '0' means doesn't exist 61 | existing_records() { 62 | _debug "Getting txt records" 63 | root=$1 64 | sub=$2 65 | if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then 66 | return 1 67 | fi 68 | 69 | seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}') 70 | _debug seg "$seg" 71 | if [ -z "$seg" ]; then 72 | return 0 73 | fi 74 | 75 | if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then 76 | record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1) 77 | _debug record_id "$record_id" 78 | return 0 79 | fi 80 | 81 | } 82 | 83 | #add the txt record. 84 | #usage: root sub txtvalue 85 | add_record() { 86 | root=$1 87 | sub=$2 88 | txtvalue=$3 89 | fulldomain="$sub.$root" 90 | 91 | _info "Adding record" 92 | 93 | if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then 94 | return 1 95 | fi 96 | 97 | return 0 98 | } 99 | 100 | #################### Private functions below ################################## 101 | #_acme-challenge.www.domain.com 102 | #returns 103 | # _sub_domain=_acme-challenge.www 104 | # _domain=domain.com 105 | # _domain_id=sdjkglgdfewsdfg 106 | _get_root() { 107 | domain=$1 108 | i=2 109 | p=1 110 | 111 | if ! _rest GET "domain"; then 112 | return 1 113 | fi 114 | 115 | while true; do 116 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 117 | _debug h "$h" 118 | if [ -z "$h" ]; then 119 | #not valid 120 | return 1 121 | fi 122 | 123 | if _contains "$response" "$h."; then 124 | seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}') 125 | _debug seg "$seg" 126 | _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") 127 | _debug _domain_id "$_domain_id" 128 | if [ "$_domain_id" ]; then 129 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 130 | _debug _sub_domain "$_sub_domain" 131 | _domain="$h" 132 | _debug _domain "$_domain" 133 | return 0 134 | fi 135 | return 1 136 | fi 137 | p="$i" 138 | i=$(_math "$i" + 1) 139 | done 140 | return 1 141 | } 142 | 143 | #Usage: method URI data 144 | _rest() { 145 | m=$1 146 | ep="$2" 147 | _debug ep "$ep" 148 | url="$REST_API/$ep" 149 | _debug url "$url" 150 | 151 | cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC") 152 | _debug cdate "$cdate" 153 | 154 | data="$3" 155 | _debug data "$data" 156 | 157 | sec="$CX_Key$url$data$cdate$CX_Secret" 158 | _debug sec "$sec" 159 | hmac=$(printf "%s" "$sec" | _digest md5 hex) 160 | _debug hmac "$hmac" 161 | 162 | export _H1="API-KEY: $CX_Key" 163 | export _H2="API-REQUEST-DATE: $cdate" 164 | export _H3="API-HMAC: $hmac" 165 | export _H4="Content-Type: application/json" 166 | 167 | if [ "$data" ]; then 168 | response="$(_post "$data" "$url" "" "$m")" 169 | else 170 | response="$(_get "$url")" 171 | fi 172 | 173 | if [ "$?" != "0" ]; then 174 | _err "error $ep" 175 | return 1 176 | fi 177 | _debug2 response "$response" 178 | 179 | _contains "$response" '"code":1' 180 | 181 | } 182 | -------------------------------------------------------------------------------- /dnsapi/dns_pointhq.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | #PointHQ_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" 5 | # 6 | #PointHQ_Email="xxxx@sss.com" 7 | 8 | PointHQ_Api="https://api.pointhq.com" 9 | 10 | ######## Public functions ##################### 11 | 12 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 13 | dns_pointhq_add() { 14 | fulldomain=$1 15 | txtvalue=$2 16 | 17 | PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}" 18 | PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}" 19 | if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then 20 | PointHQ_Key="" 21 | PointHQ_Email="" 22 | _err "You didn't specify a PointHQ API key and email yet." 23 | _err "Please create the key and try again." 24 | return 1 25 | fi 26 | 27 | if ! _contains "$PointHQ_Email" "@"; then 28 | _err "It seems that the PointHQ_Email=$PointHQ_Email is not a valid email address." 29 | _err "Please check and retry." 30 | return 1 31 | fi 32 | 33 | #save the api key and email to the account conf file. 34 | _saveaccountconf_mutable PointHQ_Key "$PointHQ_Key" 35 | _saveaccountconf_mutable PointHQ_Email "$PointHQ_Email" 36 | 37 | _debug "First detect the root zone" 38 | if ! _get_root "$fulldomain"; then 39 | _err "invalid domain" 40 | return 1 41 | fi 42 | _debug _sub_domain "$_sub_domain" 43 | _debug _domain "$_domain" 44 | 45 | _info "Adding record" 46 | if _pointhq_rest POST "zones/$_domain/records" "{\"zone_record\": {\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":3600}}"; then 47 | if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then 48 | _info "Added, OK" 49 | return 0 50 | else 51 | _err "Add txt record error." 52 | return 1 53 | fi 54 | fi 55 | _err "Add txt record error." 56 | return 1 57 | } 58 | 59 | #fulldomain txtvalue 60 | dns_pointhq_rm() { 61 | fulldomain=$1 62 | txtvalue=$2 63 | 64 | PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}" 65 | PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}" 66 | if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then 67 | PointHQ_Key="" 68 | PointHQ_Email="" 69 | _err "You didn't specify a PointHQ API key and email yet." 70 | _err "Please create the key and try again." 71 | return 1 72 | fi 73 | 74 | _debug "First detect the root zone" 75 | if ! _get_root "$fulldomain"; then 76 | _err "invalid domain" 77 | return 1 78 | fi 79 | _debug _sub_domain "$_sub_domain" 80 | _debug _domain "$_domain" 81 | 82 | _debug "Getting txt records" 83 | _pointhq_rest GET "zones/${_domain}/records?record_type=TXT&name=$_sub_domain" 84 | 85 | if ! printf "%s" "$response" | grep "^\[" >/dev/null; then 86 | _err "Error" 87 | return 1 88 | fi 89 | 90 | if [ "$response" = "[]" ]; then 91 | _info "No records to remove." 92 | else 93 | record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | tr -d \" | head -n 1) 94 | _debug "record_id" "$record_id" 95 | if [ -z "$record_id" ]; then 96 | _err "Can not get record id to remove." 97 | return 1 98 | fi 99 | if ! _pointhq_rest DELETE "zones/$_domain/records/$record_id"; then 100 | _err "Delete record error." 101 | return 1 102 | fi 103 | _contains "$response" '"status":"OK"' 104 | fi 105 | } 106 | 107 | #################### Private functions below ################################## 108 | #_acme-challenge.www.domain.com 109 | #returns 110 | # _sub_domain=_acme-challenge.www 111 | # _domain=domain.com 112 | _get_root() { 113 | domain=$1 114 | i=2 115 | p=1 116 | while true; do 117 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 118 | _debug h "$h" 119 | if [ -z "$h" ]; then 120 | #not valid 121 | return 1 122 | fi 123 | 124 | if ! _pointhq_rest GET "zones"; then 125 | return 1 126 | fi 127 | 128 | if _contains "$response" "\"name\":\"$h\"" >/dev/null; then 129 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 130 | _domain=$h 131 | return 0 132 | fi 133 | p=$i 134 | i=$(_math "$i" + 1) 135 | done 136 | return 1 137 | } 138 | 139 | _pointhq_rest() { 140 | m=$1 141 | ep="$2" 142 | data="$3" 143 | _debug "$ep" 144 | 145 | _pointhq_auth=$(printf "%s:%s" "$PointHQ_Email" "$PointHQ_Key" | _base64) 146 | 147 | export _H1="Authorization: Basic $_pointhq_auth" 148 | export _H2="Content-Type: application/json" 149 | export _H3="Accept: application/json" 150 | 151 | if [ "$m" != "GET" ]; then 152 | _debug data "$data" 153 | response="$(_post "$data" "$PointHQ_Api/$ep" "" "$m")" 154 | else 155 | response="$(_get "$PointHQ_Api/$ep")" 156 | fi 157 | 158 | if [ "$?" != "0" ]; then 159 | _err "error $ep" 160 | return 1 161 | fi 162 | _debug2 response "$response" 163 | return 0 164 | } 165 | -------------------------------------------------------------------------------- /dnsapi/dns_gd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Godaddy domain api 4 | # 5 | #GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" 6 | # 7 | #GD_Secret="asdfsdfsfsdfsdfdfsdf" 8 | 9 | GD_Api="https://api.godaddy.com/v1" 10 | 11 | ######## Public functions ##################### 12 | 13 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 14 | dns_gd_add() { 15 | fulldomain=$1 16 | txtvalue=$2 17 | 18 | GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}" 19 | GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}" 20 | if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then 21 | GD_Key="" 22 | GD_Secret="" 23 | _err "You don't specify godaddy api key and secret yet." 24 | _err "Please create you key and try again." 25 | return 1 26 | fi 27 | 28 | #save the api key and email to the account conf file. 29 | _saveaccountconf_mutable GD_Key "$GD_Key" 30 | _saveaccountconf_mutable GD_Secret "$GD_Secret" 31 | 32 | _debug "First detect the root zone" 33 | if ! _get_root "$fulldomain"; then 34 | _err "invalid domain" 35 | return 1 36 | fi 37 | 38 | _debug _sub_domain "$_sub_domain" 39 | _debug _domain "$_domain" 40 | 41 | _debug "Getting existing records" 42 | if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then 43 | return 1 44 | fi 45 | 46 | if _contains "$response" "$txtvalue"; then 47 | _info "The record is existing, skip" 48 | return 0 49 | fi 50 | 51 | _add_data="{\"data\":\"$txtvalue\"}" 52 | for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do 53 | _debug2 t "$t" 54 | if [ "$t" ]; then 55 | _add_data="$_add_data,{\"data\":$t}" 56 | fi 57 | done 58 | _debug2 _add_data "$_add_data" 59 | 60 | _info "Adding record" 61 | if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then 62 | _info "Added, sleeping 10 seconds" 63 | _sleep 10 64 | #todo: check if the record takes effect 65 | return 0 66 | fi 67 | _err "Add txt record error." 68 | return 1 69 | } 70 | 71 | #fulldomain 72 | dns_gd_rm() { 73 | fulldomain=$1 74 | txtvalue=$2 75 | 76 | GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}" 77 | GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}" 78 | 79 | _debug "First detect the root zone" 80 | if ! _get_root "$fulldomain"; then 81 | _err "invalid domain" 82 | return 1 83 | fi 84 | 85 | _debug _sub_domain "$_sub_domain" 86 | _debug _domain "$_domain" 87 | 88 | _debug "Getting existing records" 89 | if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then 90 | return 1 91 | fi 92 | 93 | if ! _contains "$response" "$txtvalue"; then 94 | _info "The record is not existing, skip" 95 | return 0 96 | fi 97 | 98 | _add_data="" 99 | for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do 100 | _debug2 t "$t" 101 | if [ "$t" ] && [ "$t" != "\"$txtvalue\"" ]; then 102 | if [ "$_add_data" ]; then 103 | _add_data="$_add_data,{\"data\":$t}" 104 | else 105 | _add_data="{\"data\":$t}" 106 | fi 107 | fi 108 | done 109 | if [ -z "$_add_data" ]; then 110 | _add_data="{\"data\":\"\"}" 111 | fi 112 | _debug2 _add_data "$_add_data" 113 | 114 | _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]" 115 | } 116 | 117 | #################### Private functions below ################################## 118 | #_acme-challenge.www.domain.com 119 | #returns 120 | # _sub_domain=_acme-challenge.www 121 | # _domain=domain.com 122 | _get_root() { 123 | domain=$1 124 | i=2 125 | p=1 126 | while true; do 127 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 128 | if [ -z "$h" ]; then 129 | #not valid 130 | return 1 131 | fi 132 | 133 | if ! _gd_rest GET "domains/$h"; then 134 | return 1 135 | fi 136 | 137 | if _contains "$response" '"code":"NOT_FOUND"'; then 138 | _debug "$h not found" 139 | else 140 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 141 | _domain="$h" 142 | return 0 143 | fi 144 | p="$i" 145 | i=$(_math "$i" + 1) 146 | done 147 | return 1 148 | } 149 | 150 | _gd_rest() { 151 | m=$1 152 | ep="$2" 153 | data="$3" 154 | _debug "$ep" 155 | 156 | export _H1="Authorization: sso-key $GD_Key:$GD_Secret" 157 | export _H2="Content-Type: application/json" 158 | 159 | if [ "$data" ]; then 160 | _debug data "$data" 161 | response="$(_post "$data" "$GD_Api/$ep" "" "$m")" 162 | else 163 | response="$(_get "$GD_Api/$ep")" 164 | fi 165 | 166 | if [ "$?" != "0" ]; then 167 | _err "error $ep" 168 | return 1 169 | fi 170 | _debug2 response "$response" 171 | if _contains "$response" "UNABLE_TO_AUTHENTICATE"; then 172 | _err "It seems that your api key or secret is not correct." 173 | return 1 174 | fi 175 | return 0 176 | } 177 | -------------------------------------------------------------------------------- /dnsapi/dns_exoscale.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | EXOSCALE_API=https://api.exoscale.com/dns/v1 4 | 5 | ######## Public functions ##################### 6 | 7 | # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 8 | # Used to add txt record 9 | dns_exoscale_add() { 10 | fulldomain=$1 11 | txtvalue=$2 12 | 13 | if ! _checkAuth; then 14 | return 1 15 | fi 16 | 17 | _debug "First detect the root zone" 18 | if ! _get_root "$fulldomain"; then 19 | _err "invalid domain" 20 | return 1 21 | fi 22 | 23 | _debug _sub_domain "$_sub_domain" 24 | _debug _domain "$_domain" 25 | 26 | _info "Adding record" 27 | if _exoscale_rest POST "domains/$_domain_id/records" "{\"record\":{\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":120}}" "$_domain_token"; then 28 | if _contains "$response" "$txtvalue"; then 29 | _info "Added, OK" 30 | return 0 31 | fi 32 | fi 33 | _err "Add txt record error." 34 | return 1 35 | 36 | } 37 | 38 | # Usage: fulldomain txtvalue 39 | # Used to remove the txt record after validation 40 | dns_exoscale_rm() { 41 | fulldomain=$1 42 | txtvalue=$2 43 | 44 | if ! _checkAuth; then 45 | return 1 46 | fi 47 | 48 | _debug "First detect the root zone" 49 | if ! _get_root "$fulldomain"; then 50 | _err "invalid domain" 51 | return 1 52 | fi 53 | 54 | _debug _sub_domain "$_sub_domain" 55 | _debug _domain "$_domain" 56 | 57 | _debug "Getting txt records" 58 | _exoscale_rest GET "domains/${_domain_id}/records?type=TXT&name=$_sub_domain" "" "$_domain_token" 59 | if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then 60 | _record_id=$(echo "$response" | tr '{' "\n" | grep "\"content\":\"$txtvalue\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") 61 | fi 62 | 63 | if [ -z "$_record_id" ]; then 64 | _err "Can not get record id to remove." 65 | return 1 66 | fi 67 | 68 | _debug "Deleting record $_record_id" 69 | 70 | if ! _exoscale_rest DELETE "domains/$_domain_id/records/$_record_id" "" "$_domain_token"; then 71 | _err "Delete record error." 72 | return 1 73 | fi 74 | 75 | return 0 76 | } 77 | 78 | #################### Private functions below ################################## 79 | 80 | _checkAuth() { 81 | EXOSCALE_API_KEY="${EXOSCALE_API_KEY:-$(_readaccountconf_mutable EXOSCALE_API_KEY)}" 82 | EXOSCALE_SECRET_KEY="${EXOSCALE_SECRET_KEY:-$(_readaccountconf_mutable EXOSCALE_SECRET_KEY)}" 83 | 84 | if [ -z "$EXOSCALE_API_KEY" ] || [ -z "$EXOSCALE_SECRET_KEY" ]; then 85 | EXOSCALE_API_KEY="" 86 | EXOSCALE_SECRET_KEY="" 87 | _err "You don't specify Exoscale application key and application secret yet." 88 | _err "Please create you key and try again." 89 | return 1 90 | fi 91 | 92 | _saveaccountconf_mutable EXOSCALE_API_KEY "$EXOSCALE_API_KEY" 93 | _saveaccountconf_mutable EXOSCALE_SECRET_KEY "$EXOSCALE_SECRET_KEY" 94 | 95 | return 0 96 | } 97 | 98 | #_acme-challenge.www.domain.com 99 | #returns 100 | # _sub_domain=_acme-challenge.www 101 | # _domain=domain.com 102 | # _domain_id=sdjkglgdfewsdfg 103 | # _domain_token=sdjkglgdfewsdfg 104 | _get_root() { 105 | 106 | if ! _exoscale_rest GET "domains"; then 107 | return 1 108 | fi 109 | 110 | domain=$1 111 | i=2 112 | p=1 113 | while true; do 114 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 115 | _debug h "$h" 116 | if [ -z "$h" ]; then 117 | #not valid 118 | return 1 119 | fi 120 | 121 | if _contains "$response" "\"name\":\"$h\"" >/dev/null; then 122 | _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") 123 | _domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") 124 | if [ "$_domain_token" ] && [ "$_domain_id" ]; then 125 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 126 | _domain=$h 127 | return 0 128 | fi 129 | return 1 130 | fi 131 | p=$i 132 | i=$(_math "$i" + 1) 133 | done 134 | return 1 135 | } 136 | 137 | # returns response 138 | _exoscale_rest() { 139 | method=$1 140 | path="$2" 141 | data="$3" 142 | token="$4" 143 | request_url="$EXOSCALE_API/$path" 144 | _debug "$path" 145 | 146 | export _H1="Accept: application/json" 147 | 148 | if [ "$token" ]; then 149 | export _H2="X-DNS-Domain-Token: $token" 150 | else 151 | export _H2="X-DNS-Token: $EXOSCALE_API_KEY:$EXOSCALE_SECRET_KEY" 152 | fi 153 | 154 | if [ "$data" ] || [ "$method" = "DELETE" ]; then 155 | export _H3="Content-Type: application/json" 156 | _debug data "$data" 157 | response="$(_post "$data" "$request_url" "" "$method")" 158 | else 159 | response="$(_get "$request_url" "" "" "$method")" 160 | fi 161 | 162 | if [ "$?" != "0" ]; then 163 | _err "error $request_url" 164 | return 1 165 | fi 166 | _debug2 response "$response" 167 | return 0 168 | } 169 | -------------------------------------------------------------------------------- /dnsapi/dns_servercow.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ########## 4 | # Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/Neilpang/acme.sh) 5 | # 6 | # Usage: 7 | # export SERVERCOW_API_Username=username 8 | # export SERVERCOW_API_Password=password 9 | # acme.sh --issue -d example.com --dns dns_servercow 10 | # 11 | # Issues: 12 | # Any issues / questions / suggestions can be posted here: 13 | # https://github.com/jhartlep/servercow-dns-api/issues 14 | # 15 | # Author: Jens Hartlep 16 | ########## 17 | 18 | SERVERCOW_API="https://api.servercow.de/dns/v1/domains" 19 | 20 | # Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz" 21 | dns_servercow_add() { 22 | fulldomain=$1 23 | txtvalue=$2 24 | 25 | _info "Using servercow" 26 | _debug fulldomain "$fulldomain" 27 | _debug txtvalue "$txtvalue" 28 | 29 | SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" 30 | SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" 31 | if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then 32 | SERVERCOW_API_Username="" 33 | SERVERCOW_API_Password="" 34 | _err "You don't specify servercow api username and password yet." 35 | _err "Please create your username and password and try again." 36 | return 1 37 | fi 38 | 39 | # save the credentials to the account conf file 40 | _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" 41 | _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password" 42 | 43 | _debug "First detect the root zone" 44 | if ! _get_root "$fulldomain"; then 45 | _err "invalid domain" 46 | return 1 47 | fi 48 | 49 | _debug _sub_domain "$_sub_domain" 50 | _debug _domain "$_domain" 51 | 52 | if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then 53 | if printf -- "%s" "$response" | grep "ok" >/dev/null; then 54 | _info "Added, OK" 55 | return 0 56 | else 57 | _err "add txt record error." 58 | return 1 59 | fi 60 | fi 61 | _err "add txt record error." 62 | 63 | return 1 64 | } 65 | 66 | # Usage fulldomain txtvalue 67 | # Remove the txt record after validation 68 | dns_servercow_rm() { 69 | fulldomain=$1 70 | txtvalue=$2 71 | 72 | _info "Using servercow" 73 | _debug fulldomain "$fulldomain" 74 | _debug txtvalue "$fulldomain" 75 | 76 | SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" 77 | SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" 78 | if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then 79 | SERVERCOW_API_Username="" 80 | SERVERCOW_API_Password="" 81 | _err "You don't specify servercow api username and password yet." 82 | _err "Please create your username and password and try again." 83 | return 1 84 | fi 85 | 86 | _debug "First detect the root zone" 87 | if ! _get_root "$fulldomain"; then 88 | _err "invalid domain" 89 | return 1 90 | fi 91 | 92 | _debug _sub_domain "$_sub_domain" 93 | _debug _domain "$_domain" 94 | 95 | if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then 96 | if printf -- "%s" "$response" | grep "ok" >/dev/null; then 97 | _info "Deleted, OK" 98 | _contains "$response" '"message":"ok"' 99 | else 100 | _err "delete txt record error." 101 | return 1 102 | fi 103 | fi 104 | 105 | } 106 | 107 | #################### Private functions below ################################## 108 | 109 | # _acme-challenge.www.domain.com 110 | # returns 111 | # _sub_domain=_acme-challenge.www 112 | # _domain=domain.com 113 | _get_root() { 114 | fulldomain=$1 115 | i=2 116 | p=1 117 | 118 | while true; do 119 | _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) 120 | 121 | _debug _domain "$_domain" 122 | if [ -z "$_domain" ]; then 123 | # not valid 124 | return 1 125 | fi 126 | 127 | if ! _servercow_api GET "$_domain"; then 128 | return 1 129 | fi 130 | 131 | if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then 132 | _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) 133 | if [ -z "$_sub_domain" ]; then 134 | # not valid 135 | return 1 136 | fi 137 | 138 | return 0 139 | fi 140 | 141 | p=$i 142 | i=$(_math "$i" + 1) 143 | done 144 | 145 | return 1 146 | } 147 | 148 | _servercow_api() { 149 | method=$1 150 | domain=$2 151 | data="$3" 152 | 153 | export _H1="Content-Type: application/json" 154 | export _H2="X-Auth-Username: $SERVERCOW_API_Username" 155 | export _H3="X-Auth-Password: $SERVERCOW_API_Password" 156 | 157 | if [ "$method" != "GET" ]; then 158 | _debug data "$data" 159 | response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" 160 | else 161 | response="$(_get "$SERVERCOW_API/$domain")" 162 | fi 163 | 164 | if [ "$?" != "0" ]; then 165 | _err "error $domain" 166 | return 1 167 | fi 168 | _debug2 response "$response" 169 | return 0 170 | } 171 | -------------------------------------------------------------------------------- /deploy/gcore_cdn.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). 4 | # Uses command line curl for send requests and jq for parse responses. 5 | # Returns 0 when success. 6 | # 7 | # Written by temoffey 8 | # Public domain, 2019 9 | 10 | #export DEPLOY_GCORE_CDN_USERNAME=myusername 11 | #export DEPLOY_GCORE_CDN_PASSWORD=mypassword 12 | 13 | ######## Public functions ##################### 14 | 15 | #domain keyfile certfile cafile fullchain 16 | 17 | gcore_cdn_deploy() { 18 | _cdomain="$1" 19 | _ckey="$2" 20 | _ccert="$3" 21 | _cca="$4" 22 | _cfullchain="$5" 23 | 24 | _debug _cdomain "$_cdomain" 25 | _debug _ckey "$_ckey" 26 | _debug _ccert "$_ccert" 27 | _debug _cca "$_cca" 28 | _debug _cfullchain "$_cfullchain" 29 | 30 | _fullchain=$(tr '\n\r' '@#' <"$_cfullchain" | sed 's/@/\\n/g;s/#/\\r/g') 31 | _key=$(tr '\n\r' '@#' <"$_ckey" | sed 's/@/\\n/g;s/#/\\r/g') 32 | 33 | _debug _fullchain "$_fullchain" 34 | _debug _key "$_key" 35 | 36 | if [ -z "$DEPLOY_GCORE_CDN_USERNAME" ]; then 37 | if [ -z "$Le_Deploy_gcore_cdn_username" ]; then 38 | _err "Please define the target username: export DEPLOY_GCORE_CDN_USERNAME=username" 39 | return 1 40 | fi 41 | else 42 | Le_Deploy_gcore_cdn_username="$DEPLOY_GCORE_CDN_USERNAME" 43 | _savedomainconf Le_Deploy_gcore_cdn_username "$Le_Deploy_gcore_cdn_username" 44 | fi 45 | 46 | if [ -z "$DEPLOY_GCORE_CDN_PASSWORD" ]; then 47 | if [ -z "$Le_Deploy_gcore_cdn_password" ]; then 48 | _err "Please define the target password: export DEPLOY_GCORE_CDN_PASSWORD=password" 49 | return 1 50 | fi 51 | else 52 | Le_Deploy_gcore_cdn_password="$DEPLOY_GCORE_CDN_PASSWORD" 53 | _savedomainconf Le_Deploy_gcore_cdn_password "$Le_Deploy_gcore_cdn_password" 54 | fi 55 | 56 | _info "Get authorization token" 57 | _request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}" 58 | _debug _request "$_request" 59 | export _H1="Content-Type:application/json" 60 | _response=$(_post "$_request" "https://api.gcdn.co/auth/signin") 61 | _debug _response "$_response" 62 | _regex=".*\"token\":\"\([-._0-9A-Za-z]*\)\".*$" 63 | _debug _regex "$_regex" 64 | _token=$(echo "$_response" | sed -n "s/$_regex/\1/p") 65 | _debug _token "$_token" 66 | 67 | if [ -z "$_token" ]; then 68 | _err "Error G-Core Labs API authorization" 69 | return 1 70 | fi 71 | 72 | _info "Find CDN resource with cname $_cdomain" 73 | export _H2="Authorization:Token $_token" 74 | _response=$(_get "https://api.gcdn.co/resources") 75 | _debug _response "$_response" 76 | _regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})" 77 | _regex="\"cname\":\"$_cdomain\"" 78 | _debug _regex "$_regex" 79 | _resource=$(echo "$_response" | sed 's/},{/},\n{/g' | grep -E "$_regex") 80 | _debug _resource "$_resource" 81 | _regex=".*\"id\":\([0-9]*\),.*$" 82 | _debug _regex "$_regex" 83 | _resourceId=$(echo "$_resource" | sed -n "s/$_regex/\1/p") 84 | _debug _resourceId "$_resourceId" 85 | _regex=".*\"sslData\":\([0-9]*\)}.*$" 86 | _debug _regex "$_regex" 87 | _sslDataOld=$(echo "$_resource" | sed -n "s/$_regex/\1/p") 88 | _debug _sslDataOld "$_sslDataOld" 89 | _regex=".*\"originGroup\":\([0-9]*\),.*$" 90 | _debug _regex "$_regex" 91 | _originGroup=$(echo "$_resource" | sed -n "s/$_regex/\1/p") 92 | _debug _originGroup "$_originGroup" 93 | 94 | if [ -z "$_resourceId" ] || [ -z "$_originGroup" ]; then 95 | _err "Not found CDN resource with cname $_cdomain" 96 | return 1 97 | fi 98 | 99 | _info "Add new SSL certificate" 100 | _date=$(date "+%d.%m.%Y %H:%M:%S") 101 | _request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}" 102 | _debug _request "$_request" 103 | _response=$(_post "$_request" "https://api.gcdn.co/sslData") 104 | _debug _response "$_response" 105 | _regex=".*\"id\":\([0-9]*\),.*$" 106 | _debug _regex "$_regex" 107 | _sslDataAdd=$(echo "$_response" | sed -n "s/$_regex/\1/p") 108 | _debug _sslDataAdd "$_sslDataAdd" 109 | 110 | if [ -z "$_sslDataAdd" ]; then 111 | _err "Error new SSL certificate add" 112 | return 1 113 | fi 114 | 115 | _info "Update CDN resource" 116 | _request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}" 117 | _debug _request "$_request" 118 | _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") 119 | _debug _response "$_response" 120 | _regex=".*\"sslData\":\([0-9]*\)}.*$" 121 | _debug _regex "$_regex" 122 | _sslDataNew=$(echo "$_response" | sed -n "s/$_regex/\1/p") 123 | _debug _sslDataNew "$_sslDataNew" 124 | 125 | if [ "$_sslDataNew" != "$_sslDataAdd" ]; then 126 | _err "Error CDN resource update" 127 | return 1 128 | fi 129 | 130 | if [ -z "$_sslDataOld" ] || [ "$_sslDataOld" = "null" ]; then 131 | _info "Not found old SSL certificate" 132 | else 133 | _info "Delete old SSL certificate" 134 | _response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE") 135 | _debug _response "$_response" 136 | fi 137 | 138 | _info "Certificate successfully deployed" 139 | return 0 140 | } 141 | -------------------------------------------------------------------------------- /dnsapi/dns_netcup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | #developed by linux-insideDE 3 | 4 | NC_Apikey="${NC_Apikey:-$(_readaccountconf_mutable NC_Apikey)}" 5 | NC_Apipw="${NC_Apipw:-$(_readaccountconf_mutable NC_Apipw)}" 6 | NC_CID="${NC_CID:-$(_readaccountconf_mutable NC_CID)}" 7 | end="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON" 8 | client="" 9 | 10 | dns_netcup_add() { 11 | _debug NC_Apikey "$NC_Apikey" 12 | login 13 | if [ "$NC_Apikey" = "" ] || [ "$NC_Apipw" = "" ] || [ "$NC_CID" = "" ]; then 14 | _err "No Credentials given" 15 | return 1 16 | fi 17 | _saveaccountconf_mutable NC_Apikey "$NC_Apikey" 18 | _saveaccountconf_mutable NC_Apipw "$NC_Apipw" 19 | _saveaccountconf_mutable NC_CID "$NC_CID" 20 | fulldomain=$1 21 | txtvalue=$2 22 | domain="" 23 | exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) 24 | exit=$(_math "$exit" + 1) 25 | i=$exit 26 | 27 | while 28 | [ "$exit" -gt 0 ] 29 | do 30 | tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") 31 | if [ "$(_math "$i" - "$exit")" -eq 0 ]; then 32 | domain="$tmp" 33 | else 34 | domain="$tmp.$domain" 35 | fi 36 | if [ "$(_math "$i" - "$exit")" -ge 1 ]; then 37 | msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") 38 | _debug "$msg" 39 | if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then 40 | if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then 41 | _err "$msg" 42 | return 1 43 | else 44 | break 45 | fi 46 | fi 47 | fi 48 | exit=$(_math "$exit" - 1) 49 | done 50 | logout 51 | } 52 | 53 | dns_netcup_rm() { 54 | login 55 | fulldomain=$1 56 | txtvalue=$2 57 | 58 | domain="" 59 | exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) 60 | exit=$(_math "$exit" + 1) 61 | i=$exit 62 | rec="" 63 | 64 | while 65 | [ "$exit" -gt 0 ] 66 | do 67 | tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") 68 | if [ "$(_math "$i" - "$exit")" -eq 0 ]; then 69 | domain="$tmp" 70 | else 71 | domain="$tmp.$domain" 72 | fi 73 | if [ "$(_math "$i" - "$exit")" -ge 1 ]; then 74 | msg=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$domain\"}}" "$end" "" "POST") 75 | rec=$(echo "$msg" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') 76 | _debug "$msg" 77 | if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then 78 | if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then 79 | _err "$msg" 80 | return 1 81 | else 82 | break 83 | fi 84 | fi 85 | fi 86 | exit=$(_math "$exit" - 1) 87 | done 88 | 89 | ida=0000 90 | idv=0001 91 | ids=0000000000 92 | i=1 93 | while 94 | [ "$i" -ne 0 ] 95 | do 96 | specrec=$(_getfield "$rec" "$i" ";") 97 | idv="$ida" 98 | ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g') 99 | txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g') 100 | i=$(_math "$i" + 1) 101 | if [ "$txtvalue" = "$txtv" ]; then 102 | i=0 103 | ids="$ida" 104 | fi 105 | if [ "$ida" = "$idv" ]; then 106 | i=0 107 | fi 108 | done 109 | msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") 110 | _debug "$msg" 111 | if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then 112 | _err "$msg" 113 | return 1 114 | fi 115 | logout 116 | } 117 | 118 | login() { 119 | tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") 120 | sid=$(_getfield "$tmp" "8" | sed s/\"responsedata\":\{\"apisessionid\":\"//g | sed 's/\"\}\}//g') 121 | _debug "$tmp" 122 | if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then 123 | _err "$msg" 124 | return 1 125 | fi 126 | } 127 | logout() { 128 | tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") 129 | _debug "$tmp" 130 | if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then 131 | _err "$msg" 132 | return 1 133 | fi 134 | } 135 | -------------------------------------------------------------------------------- /dnsapi/dns_neodigit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # NEODIGIT_API_TOKEN="jasdfhklsjadhflnhsausdfas" 5 | 6 | # This is Neodigit.net api wrapper for acme.sh 7 | # 8 | # Author: Adrian Almenar 9 | # Report Bugs here: https://github.com/tecnocratica/acme.sh 10 | # 11 | NEODIGIT_API_URL="https://api.neodigit.net/v1" 12 | # 13 | ######## Public functions ##################### 14 | 15 | # Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 16 | dns_neodigit_add() { 17 | fulldomain=$1 18 | txtvalue=$2 19 | 20 | NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" 21 | if [ -z "$NEODIGIT_API_TOKEN" ]; then 22 | NEODIGIT_API_TOKEN="" 23 | _err "You haven't specified a Token api key." 24 | _err "Please create the key and try again." 25 | return 1 26 | fi 27 | 28 | #save the api key and email to the account conf file. 29 | _saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN" 30 | 31 | _debug "First detect the root zone" 32 | if ! _get_root "$fulldomain"; then 33 | _err "invalid domain" 34 | return 1 35 | fi 36 | 37 | _debug fulldomain "$fulldomain" 38 | _debug txtvalue "$txtvalue" 39 | _debug domain "$_domain" 40 | _debug sub_domain "$_sub_domain" 41 | 42 | _debug "Getting txt records" 43 | _neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain" 44 | 45 | _debug _code "$_code" 46 | 47 | if [ "$_code" != "200" ]; then 48 | _err "error retrieving data!" 49 | return 1 50 | fi 51 | 52 | _debug fulldomain "$fulldomain" 53 | _debug txtvalue "$txtvalue" 54 | _debug domain "$_domain" 55 | _debug sub_domain "$_sub_domain" 56 | 57 | _info "Adding record" 58 | if _neo_rest POST "dns/zones/$_domain_id/records" "{\"record\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":60}}"; then 59 | if printf -- "%s" "$response" | grep "$_sub_domain" >/dev/null; then 60 | _info "Added, OK" 61 | return 0 62 | else 63 | _err "Add txt record error." 64 | return 1 65 | fi 66 | fi 67 | _err "Add txt record error." 68 | return 1 69 | } 70 | 71 | #fulldomain txtvalue 72 | dns_neodigit_rm() { 73 | fulldomain=$1 74 | txtvalue=$2 75 | 76 | NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" 77 | if [ -z "$NEODIGIT_API_TOKEN" ]; then 78 | NEODIGIT_API_TOKEN="" 79 | _err "You haven't specified a Token api key." 80 | _err "Please create the key and try again." 81 | return 1 82 | fi 83 | 84 | #save the api key and email to the account conf file. 85 | _saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN" 86 | 87 | _debug "First detect the root zone" 88 | if ! _get_root "$fulldomain"; then 89 | _err "invalid domain" 90 | return 1 91 | fi 92 | 93 | _debug _domain_id "$_domain_id" 94 | _debug _sub_domain "$_sub_domain" 95 | _debug _domain "$_domain" 96 | 97 | _debug "Getting txt records" 98 | _neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain&content=$txtvalue" 99 | 100 | if [ "$_code" != "200" ]; then 101 | _err "error retrieving data!" 102 | return 1 103 | fi 104 | 105 | record_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) 106 | _debug "record_id" "$record_id" 107 | if [ -z "$record_id" ]; then 108 | _err "Can not get record id to remove." 109 | return 1 110 | fi 111 | if ! _neo_rest DELETE "dns/zones/$_domain_id/records/$record_id"; then 112 | _err "Delete record error." 113 | return 1 114 | fi 115 | 116 | } 117 | 118 | #################### Private functions below ################################## 119 | #_acme-challenge.www.domain.com 120 | #returns 121 | # _sub_domain=_acme-challenge.www 122 | # _domain=domain.com 123 | # _domain_id=dasfdsafsadg5ythd 124 | _get_root() { 125 | domain=$1 126 | i=2 127 | p=1 128 | while true; do 129 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 130 | _debug h "$h" 131 | if [ -z "$h" ]; then 132 | #not valid 133 | return 1 134 | fi 135 | 136 | if ! _neo_rest GET "dns/zones?name=$h"; then 137 | return 1 138 | fi 139 | 140 | _debug p "$p" 141 | 142 | if _contains "$response" "\"name\":\"$h\"" >/dev/null; then 143 | _domain_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) 144 | if [ "$_domain_id" ]; then 145 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 146 | _domain=$h 147 | return 0 148 | fi 149 | return 1 150 | fi 151 | p=$i 152 | i=$(_math "$i" + 1) 153 | done 154 | return 1 155 | } 156 | 157 | _neo_rest() { 158 | m=$1 159 | ep="$2" 160 | data="$3" 161 | _debug "$ep" 162 | 163 | export _H1="X-TCPanel-Token: $NEODIGIT_API_TOKEN" 164 | export _H2="Content-Type: application/json" 165 | 166 | if [ "$m" != "GET" ]; then 167 | _debug data "$data" 168 | response="$(_post "$data" "$NEODIGIT_API_URL/$ep" "" "$m")" 169 | else 170 | response="$(_get "$NEODIGIT_API_URL/$ep")" 171 | fi 172 | 173 | _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" 174 | 175 | if [ "$?" != "0" ]; then 176 | _err "error $ep" 177 | return 1 178 | fi 179 | _debug2 response "$response" 180 | return 0 181 | } 182 | -------------------------------------------------------------------------------- /dnsapi/dns_ultra.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # ULTRA_USR="your_user_goes_here" 5 | # 6 | # ULTRA_PWD="some_password_goes_here" 7 | 8 | ULTRA_API="https://restapi.ultradns.com/v2/" 9 | 10 | #Usage: add _acme-challenge.www.domain.com "some_long_string_of_characters_go_here_from_lets_encrypt" 11 | dns_ultra_add() { 12 | fulldomain=$1 13 | txtvalue=$2 14 | export txtvalue 15 | ULTRA_USR="${ULTRA_USR:-$(_readaccountconf_mutable ULTRA_USR)}" 16 | ULTRA_PWD="${ULTRA_PWD:-$(_readaccountconf_mutable ULTRA_PWD)}" 17 | if [ -z "$ULTRA_USR" ] || [ -z "$ULTRA_PWD" ]; then 18 | ULTRA_USR="" 19 | ULTRA_PWD="" 20 | _err "You didn't specify an UltraDNS username and password yet" 21 | return 1 22 | fi 23 | # save the username and password to the account conf file. 24 | _saveaccountconf_mutable ULTRA_USR "$ULTRA_USR" 25 | _saveaccountconf_mutable ULTRA_PWD "$ULTRA_PWD" 26 | _debug "First detect the root zone" 27 | if ! _get_root "$fulldomain"; then 28 | _err "invalid domain" 29 | return 1 30 | fi 31 | _debug _domain_id "${_domain_id}" 32 | _debug _sub_domain "${_sub_domain}" 33 | _debug _domain "${_domain}" 34 | _debug "Getting txt records" 35 | _ultra_rest GET "zones/${_domain_id}/rrsets/TXT?q=value:${fulldomain}" 36 | if printf "%s" "$response" | grep \"totalCount\" >/dev/null; then 37 | _err "Error, it would appear that this record already exists. Please review existing TXT records for this domain." 38 | return 1 39 | fi 40 | 41 | _info "Adding record" 42 | if _ultra_rest POST "zones/$_domain_id/rrsets/TXT/${_sub_domain}" '{"ttl":300,"rdata":["'"${txtvalue}"'"]}'; then 43 | if _contains "$response" "Successful"; then 44 | _info "Added, OK" 45 | return 0 46 | elif _contains "$response" "Resource Record of type 16 with these attributes already exists"; then 47 | _info "Already exists, OK" 48 | return 0 49 | else 50 | _err "Add txt record error." 51 | return 1 52 | fi 53 | fi 54 | _err "Add txt record error." 55 | 56 | } 57 | 58 | dns_ultra_rm() { 59 | fulldomain=$1 60 | txtvalue=$2 61 | export txtvalue 62 | ULTRA_USR="${ULTRA_USR:-$(_readaccountconf_mutable ULTRA_USR)}" 63 | ULTRA_PWD="${ULTRA_PWD:-$(_readaccountconf_mutable ULTRA_PWD)}" 64 | if [ -z "$ULTRA_USR" ] || [ -z "$ULTRA_PWD" ]; then 65 | ULTRA_USR="" 66 | ULTRA_PWD="" 67 | _err "You didn't specify an UltraDNS username and password yet" 68 | return 1 69 | fi 70 | 71 | _debug "First detect the root zone" 72 | if ! _get_root "$fulldomain"; then 73 | _err "invalid domain" 74 | return 1 75 | fi 76 | _debug _domain_id "${_domain_id}" 77 | _debug _sub_domain "${_sub_domain}" 78 | _debug _domain "${domain}" 79 | 80 | _debug "Getting TXT records" 81 | _ultra_rest GET "zones/${_domain_id}/rrsets?q=kind:RECORDS+owner:${_sub_domain}" 82 | 83 | if ! printf "%s" "$response" | grep \"resultInfo\" >/dev/null; then 84 | _err "There was an error in obtaining the resource records for ${_domain_id}" 85 | return 1 86 | fi 87 | 88 | count=$(echo "$response" | _egrep_o "\"returnedCount\":[^,]*" | cut -d: -f2 | cut -d'}' -f1) 89 | _debug count "${count}" 90 | if [ "${count}" = "" ]; then 91 | _info "Text record is not present, will not delete anything." 92 | else 93 | if ! _ultra_rest DELETE "zones/$_domain_id/rrsets/TXT/${_sub_domain}" '{"ttl":300,"rdata":["'"${txtvalue}"'"]}'; then 94 | _err "Deleting the record did not succeed, please verify/check." 95 | return 1 96 | fi 97 | _contains "$response" "" 98 | fi 99 | 100 | } 101 | 102 | #################### Private functions below ################################## 103 | #_acme-challenge.www.domain.com 104 | #returns 105 | # _sub_domain=_acme-challenge.www 106 | # _domain=domain.com 107 | # _domain_id=sdjkglgdfewsdfg 108 | _get_root() { 109 | domain=$1 110 | i=2 111 | p=1 112 | while true; do 113 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 114 | _debug h "$h" 115 | _debug response "$response" 116 | if [ -z "$h" ]; then 117 | #not valid 118 | return 1 119 | fi 120 | if ! _ultra_rest GET "zones"; then 121 | return 1 122 | fi 123 | if _contains "${response}" "${h}." >/dev/null; then 124 | _domain_id=$(echo "$response" | _egrep_o "${h}") 125 | if [ "$_domain_id" ]; then 126 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 127 | _domain="${h}" 128 | _debug sub_domain "${_sub_domain}" 129 | _debug domain "${_domain}" 130 | return 0 131 | fi 132 | return 1 133 | fi 134 | p=$i 135 | i=$(_math "$i" + 1) 136 | done 137 | return 1 138 | } 139 | 140 | _ultra_rest() { 141 | m=$1 142 | ep="$2" 143 | data="$3" 144 | _debug "$ep" 145 | _debug TOKEN "${AUTH_TOKEN}" 146 | 147 | _ultra_login 148 | export _H1="Content-Type: application/json" 149 | export _H2="Authorization: Bearer ${AUTH_TOKEN}" 150 | 151 | if [ "$m" != "GET" ]; then 152 | _debug data "${data}" 153 | response="$(_post "${data}" "${ULTRA_API}"/"${ep}" "" "${m}")" 154 | else 155 | response="$(_get "$ULTRA_API/$ep")" 156 | fi 157 | } 158 | 159 | _ultra_login() { 160 | export _H1="" 161 | export _H2="" 162 | AUTH_TOKEN=$(_post "grant_type=password&username=${ULTRA_USR}&password=${ULTRA_PWD}" "${ULTRA_API}authorization/token" | cut -d, -f3 | cut -d\" -f4) 163 | export AUTH_TOKEN 164 | } 165 | -------------------------------------------------------------------------------- /dnsapi/dns_unoeuro.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | #UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" 5 | # 6 | #UNO_User="UExxxxxx" 7 | 8 | Uno_Api="https://api.unoeuro.com/1" 9 | 10 | ######## Public functions ##################### 11 | 12 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 13 | dns_unoeuro_add() { 14 | fulldomain=$1 15 | txtvalue=$2 16 | 17 | UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" 18 | UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" 19 | if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then 20 | UNO_Key="" 21 | UNO_User="" 22 | _err "You haven't specified a UnoEuro api key and account yet." 23 | _err "Please create your key and try again." 24 | return 1 25 | fi 26 | 27 | if ! _contains "$UNO_User" "UE"; then 28 | _err "It seems that the UNO_User=$UNO_User is not a valid username." 29 | _err "Please check and retry." 30 | return 1 31 | fi 32 | 33 | #save the api key and email to the account conf file. 34 | _saveaccountconf_mutable UNO_Key "$UNO_Key" 35 | _saveaccountconf_mutable UNO_User "$UNO_User" 36 | 37 | _debug "First detect the root zone" 38 | if ! _get_root "$fulldomain"; then 39 | _err "invalid domain" 40 | return 1 41 | fi 42 | _debug _domain_id "$_domain_id" 43 | _debug _sub_domain "$_sub_domain" 44 | _debug _domain "$_domain" 45 | 46 | _debug "Getting txt records" 47 | _uno_rest GET "my/products/$h/dns/records" 48 | 49 | if ! _contains "$response" "\"status\": 200" >/dev/null; then 50 | _err "Error" 51 | return 1 52 | fi 53 | _info "Adding record" 54 | 55 | if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then 56 | if _contains "$response" "\"status\": 200" >/dev/null; then 57 | _info "Added, OK" 58 | return 0 59 | else 60 | _err "Add txt record error." 61 | return 1 62 | fi 63 | fi 64 | } 65 | 66 | #fulldomain txtvalue 67 | dns_unoeuro_rm() { 68 | fulldomain=$1 69 | txtvalue=$2 70 | 71 | UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" 72 | UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" 73 | if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then 74 | UNO_Key="" 75 | UNO_User="" 76 | _err "You haven't specified a UnoEuro api key and account yet." 77 | _err "Please create your key and try again." 78 | return 1 79 | fi 80 | 81 | if ! _contains "$UNO_User" "UE"; then 82 | _err "It seems that the UNO_User=$UNO_User is not a valid username." 83 | _err "Please check and retry." 84 | return 1 85 | fi 86 | 87 | _debug "First detect the root zone" 88 | if ! _get_root "$fulldomain"; then 89 | _err "invalid domain" 90 | return 1 91 | fi 92 | _debug _domain_id "$_domain_id" 93 | _debug _sub_domain "$_sub_domain" 94 | _debug _domain "$_domain" 95 | 96 | _debug "Getting txt records" 97 | _uno_rest GET "my/products/$h/dns/records" 98 | 99 | if ! _contains "$response" "\"status\": 200"; then 100 | _err "Error" 101 | return 1 102 | fi 103 | 104 | if ! _contains "$response" "$_sub_domain"; then 105 | _info "Don't need to remove." 106 | else 107 | for record_line_number in $(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1); do 108 | record_line_number=$(_math "$record_line_number" - 1) 109 | _debug "record_line_number" "$record_line_number" 110 | record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") 111 | _debug "record_id" "$record_id" 112 | 113 | if [ -z "$record_id" ]; then 114 | _err "Can not get record id to remove." 115 | return 1 116 | fi 117 | 118 | if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then 119 | _err "Delete record error." 120 | return 1 121 | fi 122 | _contains "$response" "\"status\": 200" 123 | done 124 | fi 125 | } 126 | 127 | #################### Private functions below ################################## 128 | #_acme-challenge.www.domain.com 129 | #returns 130 | # _sub_domain=_acme-challenge.www 131 | # _domain=domain.com 132 | # _domain_id=sdjkglgdfewsdfg 133 | _get_root() { 134 | domain=$1 135 | i=2 136 | p=1 137 | while true; do 138 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 139 | _debug h "$h" 140 | if [ -z "$h" ]; then 141 | #not valid 142 | return 1 143 | fi 144 | 145 | if ! _uno_rest GET "my/products/$h/dns/records"; then 146 | return 1 147 | fi 148 | 149 | if _contains "$response" "\"status\": 200"; then 150 | _domain_id=$h 151 | if [ "$_domain_id" ]; then 152 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 153 | _domain=$h 154 | return 0 155 | fi 156 | return 1 157 | fi 158 | p=$i 159 | i=$(_math "$i" + 1) 160 | done 161 | return 1 162 | } 163 | 164 | _uno_rest() { 165 | m=$1 166 | ep="$2" 167 | data="$3" 168 | _debug "$ep" 169 | 170 | export _H1="Content-Type: application/json" 171 | 172 | if [ "$m" != "GET" ]; then 173 | _debug data "$data" 174 | response="$(_post "$data" "$Uno_Api/$UNO_User/$UNO_Key/$ep" "" "$m")" 175 | else 176 | response="$(_get "$Uno_Api/$UNO_User/$UNO_Key/$ep")" 177 | fi 178 | 179 | if [ "$?" != "0" ]; then 180 | _err "error $ep" 181 | return 1 182 | fi 183 | _debug2 response "$response" 184 | return 0 185 | } 186 | -------------------------------------------------------------------------------- /dnsapi/dns_gcloud.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Author: Janos Lenart 4 | 5 | ######## Public functions ##################### 6 | 7 | # Usage: dns_gcloud_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 8 | dns_gcloud_add() { 9 | fulldomain=$1 10 | txtvalue=$2 11 | _info "Using gcloud" 12 | _debug fulldomain "$fulldomain" 13 | _debug txtvalue "$txtvalue" 14 | 15 | _dns_gcloud_find_zone || return $? 16 | 17 | # Add an extra RR 18 | _dns_gcloud_start_tr || return $? 19 | _dns_gcloud_get_rrdatas || return $? 20 | echo "$rrdatas" | _dns_gcloud_remove_rrs || return $? 21 | printf "%s\n%s\n" "$rrdatas" "\"$txtvalue\"" | grep -v '^$' | _dns_gcloud_add_rrs || return $? 22 | _dns_gcloud_execute_tr || return $? 23 | 24 | _info "$fulldomain record added" 25 | } 26 | 27 | # Usage: dns_gcloud_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 28 | # Remove the txt record after validation. 29 | dns_gcloud_rm() { 30 | fulldomain=$1 31 | txtvalue=$2 32 | _info "Using gcloud" 33 | _debug fulldomain "$fulldomain" 34 | _debug txtvalue "$txtvalue" 35 | 36 | _dns_gcloud_find_zone || return $? 37 | 38 | # Remove one RR 39 | _dns_gcloud_start_tr || return $? 40 | _dns_gcloud_get_rrdatas || return $? 41 | echo "$rrdatas" | _dns_gcloud_remove_rrs || return $? 42 | echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $? 43 | _dns_gcloud_execute_tr || return $? 44 | 45 | _info "$fulldomain record added" 46 | } 47 | 48 | #################### Private functions below ################################## 49 | 50 | _dns_gcloud_start_tr() { 51 | if ! trd=$(mktemp -d); then 52 | _err "_dns_gcloud_start_tr: failed to create temporary directory" 53 | return 1 54 | fi 55 | tr="$trd/tr.yaml" 56 | _debug tr "$tr" 57 | 58 | if ! gcloud dns record-sets transaction start \ 59 | --transaction-file="$tr" \ 60 | --zone="$managedZone"; then 61 | rm -r "$trd" 62 | _err "_dns_gcloud_start_tr: failed to execute transaction" 63 | return 1 64 | fi 65 | } 66 | 67 | _dns_gcloud_execute_tr() { 68 | if ! gcloud dns record-sets transaction execute \ 69 | --transaction-file="$tr" \ 70 | --zone="$managedZone"; then 71 | _debug tr "$(cat "$tr")" 72 | rm -r "$trd" 73 | _err "_dns_gcloud_execute_tr: failed to execute transaction" 74 | return 1 75 | fi 76 | rm -r "$trd" 77 | 78 | for i in $(seq 1 120); do 79 | if gcloud dns record-sets changes list \ 80 | --zone="$managedZone" \ 81 | --filter='status != done' \ 82 | | grep -q '^.*'; then 83 | _info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..." 84 | sleep 5 85 | else 86 | return 0 87 | fi 88 | done 89 | 90 | _err "_dns_gcloud_execute_tr: transaction is still pending after 10 minutes" 91 | rm -r "$trd" 92 | return 1 93 | } 94 | 95 | _dns_gcloud_remove_rrs() { 96 | if ! xargs --no-run-if-empty gcloud dns record-sets transaction remove \ 97 | --name="$fulldomain." \ 98 | --ttl="$ttl" \ 99 | --type=TXT \ 100 | --zone="$managedZone" \ 101 | --transaction-file="$tr"; then 102 | _debug tr "$(cat "$tr")" 103 | rm -r "$trd" 104 | _err "_dns_gcloud_remove_rrs: failed to remove RRs" 105 | return 1 106 | fi 107 | } 108 | 109 | _dns_gcloud_add_rrs() { 110 | ttl=60 111 | if ! xargs --no-run-if-empty gcloud dns record-sets transaction add \ 112 | --name="$fulldomain." \ 113 | --ttl="$ttl" \ 114 | --type=TXT \ 115 | --zone="$managedZone" \ 116 | --transaction-file="$tr"; then 117 | _debug tr "$(cat "$tr")" 118 | rm -r "$trd" 119 | _err "_dns_gcloud_add_rrs: failed to add RRs" 120 | return 1 121 | fi 122 | } 123 | 124 | _dns_gcloud_find_zone() { 125 | # Prepare a filter that matches zones that are suiteable for this entry. 126 | # For example, _acme-challenge.something.domain.com might need to go into something.domain.com or domain.com; 127 | # this function finds the longest postfix that has a managed zone. 128 | part="$fulldomain" 129 | filter="dnsName=( " 130 | while [ "$part" != "" ]; do 131 | filter="$filter$part. " 132 | part="$(echo "$part" | sed 's/[^.]*\.*//')" 133 | done 134 | filter="$filter)" 135 | _debug filter "$filter" 136 | 137 | # List domains and find the longest match (in case of some levels of delegation) 138 | if ! match=$(gcloud dns managed-zones list \ 139 | --format="value(name, dnsName)" \ 140 | --filter="$filter" \ 141 | | while read -r dnsName name; do 142 | printf "%s\t%s\t%s\n" "${#dnsName}" "$dnsName" "$name" 143 | done \ 144 | | sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then 145 | _err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?" 146 | return 1 147 | fi 148 | 149 | dnsName=$(echo "$match" | cut -f2) 150 | _debug dnsName "$dnsName" 151 | managedZone=$(echo "$match" | cut -f1) 152 | _debug managedZone "$managedZone" 153 | } 154 | 155 | _dns_gcloud_get_rrdatas() { 156 | if ! rrdatas=$(gcloud dns record-sets list \ 157 | --zone="$managedZone" \ 158 | --name="$fulldomain." \ 159 | --type=TXT \ 160 | --format="value(ttl,rrdatas)"); then 161 | _err "_dns_gcloud_get_rrdatas: Failed to list record-sets" 162 | rm -r "$trd" 163 | return 1 164 | fi 165 | ttl=$(echo "$rrdatas" | cut -f1) 166 | rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/","/"\n"/g') 167 | } 168 | -------------------------------------------------------------------------------- /dnsapi/dns_gandi_livedns.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Gandi LiveDNS v5 API 4 | # http://doc.livedns.gandi.net/ 5 | # currently under beta 6 | # 7 | # Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable 8 | # 9 | #Author: Frédéric Crozat 10 | # Dominik Röttsches 11 | #Report Bugs here: https://github.com/fcrozat/acme.sh 12 | # 13 | ######## Public functions ##################### 14 | 15 | GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5" 16 | 17 | #Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 18 | dns_gandi_livedns_add() { 19 | fulldomain=$1 20 | txtvalue=$2 21 | 22 | if [ -z "$GANDI_LIVEDNS_KEY" ]; then 23 | _err "No API key specified for Gandi LiveDNS." 24 | _err "Create your key and export it as GANDI_LIVEDNS_KEY" 25 | return 1 26 | fi 27 | 28 | _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY" 29 | 30 | _debug "First detect the root zone" 31 | if ! _get_root "$fulldomain"; then 32 | _err "invalid domain" 33 | return 1 34 | fi 35 | _debug fulldomain "$fulldomain" 36 | _debug txtvalue "$txtvalue" 37 | _debug domain "$_domain" 38 | _debug sub_domain "$_sub_domain" 39 | 40 | _dns_gandi_append_record "$_domain" "$_sub_domain" "$txtvalue" 41 | } 42 | 43 | #Usage: fulldomain txtvalue 44 | #Remove the txt record after validation. 45 | dns_gandi_livedns_rm() { 46 | fulldomain=$1 47 | txtvalue=$2 48 | 49 | _debug "First detect the root zone" 50 | if ! _get_root "$fulldomain"; then 51 | _err "invalid domain" 52 | return 1 53 | fi 54 | 55 | _debug fulldomain "$fulldomain" 56 | _debug domain "$_domain" 57 | _debug sub_domain "$_sub_domain" 58 | _debug txtvalue "$txtvalue" 59 | 60 | if ! _dns_gandi_existing_rrset_values "$_domain" "$_sub_domain"; then 61 | return 1 62 | fi 63 | _new_rrset_values=$(echo "$_rrset_values" | sed "s/...$txtvalue...//g") 64 | # Cleanup dangling commata. 65 | _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, ,/ ,/g") 66 | _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, *\]/\]/g") 67 | _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/\[ *,/\[/g") 68 | _debug "New rrset_values" "$_new_rrset_values" 69 | 70 | _gandi_livedns_rest PUT \ 71 | "domains/$_domain/records/$_sub_domain/TXT" \ 72 | "{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" \ 73 | && _contains "$response" '{"message": "DNS Record Created"}' \ 74 | && _info "Removing record $(__green "success")" 75 | } 76 | 77 | #################### Private functions below ################################## 78 | #_acme-challenge.www.domain.com 79 | #returns 80 | # _sub_domain=_acme-challenge.www 81 | # _domain=domain.com 82 | _get_root() { 83 | domain=$1 84 | i=2 85 | p=1 86 | while true; do 87 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 88 | _debug h "$h" 89 | if [ -z "$h" ]; then 90 | #not valid 91 | return 1 92 | fi 93 | 94 | if ! _gandi_livedns_rest GET "domains/$h"; then 95 | return 1 96 | fi 97 | 98 | if _contains "$response" '"code": 401'; then 99 | _err "$response" 100 | return 1 101 | elif _contains "$response" '"code": 404'; then 102 | _debug "$h not found" 103 | else 104 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 105 | _domain="$h" 106 | return 0 107 | fi 108 | p="$i" 109 | i=$(_math "$i" + 1) 110 | done 111 | return 1 112 | } 113 | 114 | _dns_gandi_append_record() { 115 | domain=$1 116 | sub_domain=$2 117 | txtvalue=$3 118 | 119 | if _dns_gandi_existing_rrset_values "$domain" "$sub_domain"; then 120 | _debug "Appending new value" 121 | _rrset_values=$(echo "$_rrset_values" | sed "s/\"]/\",\"$txtvalue\"]/") 122 | else 123 | _debug "Creating new record" "$_rrset_values" 124 | _rrset_values="[\"$txtvalue\"]" 125 | fi 126 | _debug new_rrset_values "$_rrset_values" 127 | _gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \ 128 | "{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" \ 129 | && _contains "$response" '{"message": "DNS Record Created"}' \ 130 | && _info "Adding record $(__green "success")" 131 | } 132 | 133 | _dns_gandi_existing_rrset_values() { 134 | domain=$1 135 | sub_domain=$2 136 | if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then 137 | return 1 138 | fi 139 | if ! _contains "$response" '"rrset_type": "TXT"'; then 140 | _debug "Does not have a _acme-challenge TXT record yet." 141 | return 1 142 | fi 143 | if _contains "$response" '"rrset_values": \[\]'; then 144 | _debug "Empty rrset_values for TXT record, no previous TXT record." 145 | return 1 146 | fi 147 | _debug "Already has TXT record." 148 | _rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' \ 149 | | _egrep_o '\[".*\"]') 150 | return 0 151 | } 152 | 153 | _gandi_livedns_rest() { 154 | m=$1 155 | ep="$2" 156 | data="$3" 157 | _debug "$ep" 158 | 159 | export _H1="Content-Type: application/json" 160 | export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY" 161 | 162 | if [ "$m" = "GET" ]; then 163 | response="$(_get "$GANDI_LIVEDNS_API/$ep")" 164 | else 165 | _debug data "$data" 166 | response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")" 167 | fi 168 | 169 | if [ "$?" != "0" ]; then 170 | _err "error $ep" 171 | return 1 172 | fi 173 | _debug2 response "$response" 174 | return 0 175 | } 176 | -------------------------------------------------------------------------------- /dnsapi/dns_gdnsdk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | #Author: Herman Sletteng 3 | #Report Bugs here: https://github.com/loial/acme.sh 4 | # 5 | # 6 | # Note, gratisdns requires a login first, so the script needs to handle 7 | # temporary cookies. Since acme.sh _get/_post currently don't directly support 8 | # cookies, I've defined wrapper functions _myget/_mypost to set the headers 9 | 10 | GDNSDK_API="https://admin.gratisdns.com" 11 | ######## Public functions ##################### 12 | #Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 13 | dns_gdnsdk_add() { 14 | fulldomain=$1 15 | txtvalue=$2 16 | _info "Using gratisdns.dk" 17 | _debug fulldomain "$fulldomain" 18 | _debug txtvalue "$txtvalue" 19 | if ! _gratisdns_login; then 20 | _err "Login failed!" 21 | return 1 22 | fi 23 | #finding domain zone 24 | if ! _get_domain; then 25 | _err "No matching root domain for $fulldomain found" 26 | return 1 27 | fi 28 | # adding entry 29 | _info "Adding the entry" 30 | _mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1" 31 | if _successful_update; then return 0; fi 32 | _err "Couldn't create entry!" 33 | return 1 34 | } 35 | 36 | #Usage: fulldomain txtvalue 37 | #Remove the txt record after validation. 38 | dns_gdnsdk_rm() { 39 | fulldomain=$1 40 | txtvalue=$2 41 | _info "Using gratisdns.dk" 42 | _debug fulldomain "$fulldomain" 43 | _debug txtvalue "$txtvalue" 44 | if ! _gratisdns_login; then 45 | _err "Login failed!" 46 | return 1 47 | fi 48 | if ! _get_domain; then 49 | _err "No matching root domain for $fulldomain found" 50 | return 1 51 | fi 52 | _findentry "$fulldomain" "$txtvalue" 53 | if [ -z "$_id" ]; then 54 | _info "Entry doesn't exist, nothing to delete" 55 | return 0 56 | fi 57 | _debug "Deleting record..." 58 | _mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id" 59 | # removing entry 60 | 61 | if _successful_update; then return 0; fi 62 | _err "Couldn't delete entry!" 63 | return 1 64 | } 65 | 66 | #################### Private functions below ################################## 67 | 68 | _checkcredentials() { 69 | GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}" 70 | GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}" 71 | 72 | if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then 73 | GDNSDK_Username="" 74 | GDNSDK_Password="" 75 | _err "You haven't specified gratisdns.dk username and password yet." 76 | _err "Please add credentials and try again." 77 | return 1 78 | fi 79 | #save the credentials to the account conf file. 80 | _saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username" 81 | _saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password" 82 | return 0 83 | } 84 | 85 | _checkcookie() { 86 | GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}" 87 | if [ -z "$GDNSDK_Cookie" ]; then 88 | _debug "No cached cookie found" 89 | return 1 90 | fi 91 | _myget "action=" 92 | if (echo "$_result" | grep -q "logmeout"); then 93 | _debug "Cached cookie still valid" 94 | return 0 95 | fi 96 | _debug "Cached cookie no longer valid" 97 | GDNSDK_Cookie="" 98 | _saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie" 99 | return 1 100 | } 101 | 102 | _gratisdns_login() { 103 | if ! _checkcredentials; then return 1; fi 104 | 105 | if _checkcookie; then 106 | _debug "Already logged in" 107 | return 0 108 | fi 109 | _debug "Logging into GratisDNS with user $GDNSDK_Username" 110 | 111 | if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then 112 | _err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post" 113 | return 1 114 | fi 115 | 116 | GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)" 117 | 118 | if [ -z "$GDNSDK_Cookie" ]; then 119 | _err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file" 120 | return 1 121 | fi 122 | export GDNSDK_Cookie 123 | _saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie" 124 | return 0 125 | } 126 | 127 | _myget() { 128 | #Adds cookie to request 129 | export _H1="Cookie: $GDNSDK_Cookie" 130 | _result=$(_get "$GDNSDK_API?$1") 131 | } 132 | _mypost() { 133 | #Adds cookie to request 134 | export _H1="Cookie: $GDNSDK_Cookie" 135 | _result=$(_post "$1" "$GDNSDK_API") 136 | } 137 | 138 | _get_domain() { 139 | _myget 'action=dns_primarydns' 140 | _domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:]._-]+' | sed 's/^.*"//') 141 | if [ -z "$_domains" ]; then 142 | _err "Primary domain list not found!" 143 | return 1 144 | fi 145 | for _domain in $_domains; do 146 | if (_endswith "$fulldomain" "$_domain"); then 147 | _debug "Root domain: $_domain" 148 | return 0 149 | fi 150 | done 151 | return 1 152 | } 153 | 154 | _successful_update() { 155 | if (echo "$_result" | grep -q 'table-success'); then return 0; fi 156 | return 1 157 | } 158 | 159 | _findentry() { 160 | #returns id of dns entry, if it exists 161 | _myget "action=dns_primary_changeDNSsetup&user_domain=$_domain" 162 | _id=$(echo "$_result" | _egrep_o "$1\s*$2[^?]*[^&]*&id=[^&]*" | sed 's/^.*=//') 163 | if [ -n "$_id" ]; then 164 | _debug "Entry found with _id=$_id" 165 | return 0 166 | fi 167 | return 1 168 | } 169 | -------------------------------------------------------------------------------- /dnsapi/dns_linode.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | #Author: Philipp Grosswiler 4 | 5 | LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" 6 | 7 | ######## Public functions ##################### 8 | 9 | #Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 10 | dns_linode_add() { 11 | fulldomain="${1}" 12 | txtvalue="${2}" 13 | 14 | if ! _Linode_API; then 15 | return 1 16 | fi 17 | 18 | _info "Using Linode" 19 | _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" 20 | 21 | _debug "First detect the root zone" 22 | if ! _get_root "$fulldomain"; then 23 | _err "Domain does not exist." 24 | return 1 25 | fi 26 | _debug _domain_id "$_domain_id" 27 | _debug _sub_domain "$_sub_domain" 28 | _debug _domain "$_domain" 29 | 30 | _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue" 31 | 32 | if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then 33 | _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) 34 | _debug _resource_id "$_resource_id" 35 | 36 | if [ -z "$_resource_id" ]; then 37 | _err "Error adding the domain resource." 38 | return 1 39 | fi 40 | 41 | _info "Domain resource successfully added." 42 | return 0 43 | fi 44 | 45 | return 1 46 | } 47 | 48 | #Usage: dns_linode_rm _acme-challenge.www.domain.com 49 | dns_linode_rm() { 50 | fulldomain="${1}" 51 | 52 | if ! _Linode_API; then 53 | return 1 54 | fi 55 | 56 | _info "Using Linode" 57 | _debug "Calling: dns_linode_rm() '${fulldomain}'" 58 | 59 | _debug "First detect the root zone" 60 | if ! _get_root "$fulldomain"; then 61 | _err "Domain does not exist." 62 | return 1 63 | fi 64 | _debug _domain_id "$_domain_id" 65 | _debug _sub_domain "$_sub_domain" 66 | _debug _domain "$_domain" 67 | 68 | _parameters="&DomainID=$_domain_id" 69 | 70 | if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then 71 | response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" 72 | 73 | resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" 74 | if [ "$resource" ]; then 75 | _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) 76 | if [ "$_resource_id" ]; then 77 | _debug _resource_id "$_resource_id" 78 | 79 | _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id" 80 | 81 | if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then 82 | _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) 83 | _debug _resource_id "$_resource_id" 84 | 85 | if [ -z "$_resource_id" ]; then 86 | _err "Error deleting the domain resource." 87 | return 1 88 | fi 89 | 90 | _info "Domain resource successfully deleted." 91 | return 0 92 | fi 93 | fi 94 | 95 | return 1 96 | fi 97 | 98 | return 0 99 | fi 100 | 101 | return 1 102 | } 103 | 104 | #################### Private functions below ################################## 105 | 106 | _Linode_API() { 107 | if [ -z "$LINODE_API_KEY" ]; then 108 | LINODE_API_KEY="" 109 | 110 | _err "You didn't specify the Linode API key yet." 111 | _err "Please create your key and try again." 112 | 113 | return 1 114 | fi 115 | 116 | _saveaccountconf LINODE_API_KEY "$LINODE_API_KEY" 117 | } 118 | 119 | #################### Private functions below ################################## 120 | #_acme-challenge.www.domain.com 121 | #returns 122 | # _sub_domain=_acme-challenge.www 123 | # _domain=domain.com 124 | # _domain_id=12345 125 | _get_root() { 126 | domain=$1 127 | i=2 128 | p=1 129 | 130 | if _rest GET "domain.list"; then 131 | response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" 132 | while true; do 133 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) 134 | _debug h "$h" 135 | if [ -z "$h" ]; then 136 | #not valid 137 | return 1 138 | fi 139 | 140 | hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")" 141 | if [ "$hostedzone" ]; then 142 | _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) 143 | if [ "$_domain_id" ]; then 144 | _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) 145 | _domain=$h 146 | return 0 147 | fi 148 | return 1 149 | fi 150 | p=$i 151 | i=$(_math "$i" + 1) 152 | done 153 | fi 154 | return 1 155 | } 156 | 157 | #method method action data 158 | _rest() { 159 | mtd="$1" 160 | ep="$2" 161 | data="$3" 162 | 163 | _debug mtd "$mtd" 164 | _debug ep "$ep" 165 | 166 | export _H1="Accept: application/json" 167 | export _H2="Content-Type: application/json" 168 | 169 | if [ "$mtd" != "GET" ]; then 170 | # both POST and DELETE. 171 | _debug data "$data" 172 | response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")" 173 | else 174 | response="$(_get "$LINODE_API_URL$ep$data")" 175 | fi 176 | 177 | if [ "$?" != "0" ]; then 178 | _err "error $ep" 179 | return 1 180 | fi 181 | _debug2 response "$response" 182 | return 0 183 | } 184 | --------------------------------------------------------------------------------