forked from Github/acme.sh
raidenii
7 years ago
39 changed files with 4003 additions and 798 deletions
-
22.travis.yml
-
7Dockerfile
-
177README.md
-
748acme.sh
-
46deploy/README.md
-
29deploy/cpanel.sh
-
64deploy/cpanel_uapi.sh
-
108deploy/fritzbox.sh
-
55deploy/strongswan.sh
-
100deploy/unifi.sh
-
230dnsapi/README.md
-
43dnsapi/dns_ali.sh
-
264dnsapi/dns_autodns.sh
-
62dnsapi/dns_aws.sh
-
249dnsapi/dns_azure.sh
-
33dnsapi/dns_cf.sh
-
33dnsapi/dns_cloudns.sh
-
42dnsapi/dns_cx.sh
-
82dnsapi/dns_dp.sh
-
97dnsapi/dns_dreamhost.sh
-
69dnsapi/dns_duckdns.sh
-
339dnsapi/dns_dyn.sh
-
77dnsapi/dns_freedns.sh
-
2dnsapi/dns_gandi_livedns.sh
-
67dnsapi/dns_gd.sh
-
158dnsapi/dns_he.sh
-
16dnsapi/dns_infoblox.sh
-
311dnsapi/dns_inwx.sh
-
1dnsapi/dns_ispconfig.sh
-
4dnsapi/dns_linode.sh
-
40dnsapi/dns_lua.sh
-
137dnsapi/dns_namesilo.sh
-
6dnsapi/dns_nsone.sh
-
107dnsapi/dns_ovh.sh
-
161dnsapi/dns_selectel.sh
-
170dnsapi/dns_servercow.sh
-
202dnsapi/dns_unoeuro.sh
-
106dnsapi/dns_yandex.sh
-
85dnsapi/dns_zonomi.sh
748
acme.sh
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,29 +0,0 @@ |
|||||
#!/usr/bin/env sh |
|
||||
|
|
||||
#Here is the script to deploy the cert to your cpanel account by the cpanel APIs. |
|
||||
|
|
||||
#returns 0 means success, otherwise error. |
|
||||
|
|
||||
#export DEPLOY_CPANEL_USER=myusername |
|
||||
#export DEPLOY_CPANEL_PASSWORD=PASSWORD |
|
||||
|
|
||||
######## Public functions ##################### |
|
||||
|
|
||||
#domain keyfile certfile cafile fullchain |
|
||||
cpanel_deploy() { |
|
||||
_cdomain="$1" |
|
||||
_ckey="$2" |
|
||||
_ccert="$3" |
|
||||
_cca="$4" |
|
||||
_cfullchain="$5" |
|
||||
|
|
||||
_debug _cdomain "$_cdomain" |
|
||||
_debug _ckey "$_ckey" |
|
||||
_debug _ccert "$_ccert" |
|
||||
_debug _cca "$_cca" |
|
||||
_debug _cfullchain "$_cfullchain" |
|
||||
|
|
||||
_err "Not implemented yet" |
|
||||
return 1 |
|
||||
|
|
||||
} |
|
@ -0,0 +1,64 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
# Here is the script to deploy the cert to your cpanel using the cpanel API. |
||||
|
# Uses command line uapi. --user option is needed only if run as root. |
||||
|
# Returns 0 when success. |
||||
|
# Written by Santeri Kannisto <santeri.kannisto@2globalnomads.info> |
||||
|
# Public domain, 2017 |
||||
|
|
||||
|
#export DEPLOY_CPANEL_USER=myusername |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
|
||||
|
cpanel_uapi_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
if ! _exists uapi; then |
||||
|
_err "The command uapi is not found." |
||||
|
return 1 |
||||
|
fi |
||||
|
if ! _exists php; then |
||||
|
_err "The command php is not found." |
||||
|
return 1 |
||||
|
fi |
||||
|
# read cert and key files and urlencode both |
||||
|
_certstr=$(cat "$_ccert") |
||||
|
_keystr=$(cat "$_ckey") |
||||
|
_cert=$(php -r "echo urlencode(\"$_certstr\");") |
||||
|
_key=$(php -r "echo urlencode(\"$_keystr\");") |
||||
|
|
||||
|
_debug _cert "$_cert" |
||||
|
_debug _key "$_key" |
||||
|
|
||||
|
if [ "$(id -u)" = 0 ]; then |
||||
|
if [ -z "$DEPLOY_CPANEL_USER" ]; then |
||||
|
_err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username" |
||||
|
return 1 |
||||
|
fi |
||||
|
_savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER" |
||||
|
_response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") |
||||
|
else |
||||
|
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") |
||||
|
fi |
||||
|
error_response="status: 0" |
||||
|
if test "${_response#*$error_response}" != "$_response"; then |
||||
|
_err "Error in deploying certificate:" |
||||
|
_err "$_response" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug response "$_response" |
||||
|
_info "Certificate successfully deployed" |
||||
|
return 0 |
||||
|
} |
@ -0,0 +1,108 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
#Here is a script to deploy cert to an AVM FRITZ!Box router. |
||||
|
|
||||
|
#returns 0 means success, otherwise error. |
||||
|
|
||||
|
#DEPLOY_FRITZBOX_USERNAME="username" |
||||
|
#DEPLOY_FRITZBOX_PASSWORD="password" |
||||
|
#DEPLOY_FRITZBOX_URL="https://fritz.box" |
||||
|
|
||||
|
# Kudos to wikrie at Github for his FRITZ!Box update script: |
||||
|
# https://gist.github.com/wikrie/f1d5747a714e0a34d0582981f7cb4cfb |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
fritzbox_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
if ! _exists iconv; then |
||||
|
_err "iconv not found" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" |
||||
|
_fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" |
||||
|
_fritzbox_url="${DEPLOY_FRITZBOX_URL}" |
||||
|
|
||||
|
_debug _fritzbox_url "$_fritzbox_url" |
||||
|
_debug _fritzbox_username "$_fritzbox_username" |
||||
|
_secure_debug _fritzbox_password "$_fritzbox_password" |
||||
|
if [ -z "$_fritzbox_username" ]; then |
||||
|
_err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." |
||||
|
return 1 |
||||
|
fi |
||||
|
if [ -z "$_fritzbox_password" ]; then |
||||
|
_err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." |
||||
|
return 1 |
||||
|
fi |
||||
|
if [ -z "$_fritzbox_url" ]; then |
||||
|
_err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" |
||||
|
_saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" |
||||
|
_saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" |
||||
|
|
||||
|
# Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate |
||||
|
export HTTPS_INSECURE=1 |
||||
|
|
||||
|
_info "Log in to the FRITZ!Box" |
||||
|
_fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')" |
||||
|
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" |
||||
|
_fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')" |
||||
|
|
||||
|
if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then |
||||
|
_err "Logging in to the FRITZ!Box failed. Please check username, password and URL." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info "Generate form POST request" |
||||
|
_post_request="$(_mktemp)" |
||||
|
_post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" |
||||
|
# _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! |
||||
|
_CERTPASSWORD_= |
||||
|
{ |
||||
|
printf -- "--" |
||||
|
printf -- "%s\r\n" "${_post_boundary}" |
||||
|
printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" |
||||
|
printf -- "--" |
||||
|
printf -- "%s\r\n" "${_post_boundary}" |
||||
|
printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" |
||||
|
printf -- "--" |
||||
|
printf -- "%s\r\n" "${_post_boundary}" |
||||
|
printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" |
||||
|
printf "Content-Type: application/octet-stream\r\n\r\n" |
||||
|
cat "${_ckey}" "${_cfullchain}" |
||||
|
printf "\r\n" |
||||
|
printf -- "--" |
||||
|
printf -- "%s--" "${_post_boundary}" |
||||
|
} >>"${_post_request}" |
||||
|
|
||||
|
_info "Upload certificate to the FRITZ!Box" |
||||
|
|
||||
|
export _H1="Content-type: multipart/form-data boundary=${_post_boundary}" |
||||
|
_post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL |
||||
|
|
||||
|
retval=$? |
||||
|
if [ $retval = 0 ]; then |
||||
|
_info "Upload successful" |
||||
|
else |
||||
|
_err "Upload failed" |
||||
|
fi |
||||
|
rm "${_post_request}" |
||||
|
|
||||
|
return $retval |
||||
|
} |
@ -0,0 +1,55 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
#Here is a sample custom api script. |
||||
|
#This file name is "myapi.sh" |
||||
|
#So, here must be a method myapi_deploy() |
||||
|
#Which will be called by acme.sh to deploy the cert |
||||
|
#returns 0 means success, otherwise error. |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
strongswan_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_info "Using strongswan" |
||||
|
|
||||
|
if [ -x /usr/sbin/ipsec ]; then |
||||
|
_ipsec=/usr/sbin/ipsec |
||||
|
elif [ -x /usr/sbin/strongswan ]; then |
||||
|
_ipsec=/usr/sbin/strongswan |
||||
|
elif [ -x /usr/local/sbin/ipsec ]; then |
||||
|
_ipsec=/usr/local/sbin/ipsec |
||||
|
else |
||||
|
_err "no strongswan or ipsec command is detected" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info _ipsec "$_ipsec" |
||||
|
|
||||
|
_confdir=$($_ipsec --confdir) |
||||
|
if [ $? -ne 0 ] || [ -z "$_confdir" ]; then |
||||
|
_err "no strongswan --confdir is detected" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info _confdir "$_confdir" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
cat "$_ckey" >"${_confdir}/ipsec.d/private/$(basename "$_ckey")" |
||||
|
cat "$_ccert" >"${_confdir}/ipsec.d/certs/$(basename "$_ccert")" |
||||
|
cat "$_cca" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cca")" |
||||
|
cat "$_cfullchain" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cfullchain")" |
||||
|
|
||||
|
$_ipsec reload |
||||
|
|
||||
|
} |
@ -0,0 +1,100 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
#Here is a script to deploy cert to unifi server. |
||||
|
|
||||
|
#returns 0 means success, otherwise error. |
||||
|
|
||||
|
#DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" |
||||
|
#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise" |
||||
|
#DEPLOY_UNIFI_RELOAD="service unifi restart" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
unifi_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
if ! _exists keytool; then |
||||
|
_err "keytool not found" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" |
||||
|
_unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}" |
||||
|
DEFAULT_UNIFI_KEYPASS="aircontrolenterprise" |
||||
|
_unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}" |
||||
|
DEFAULT_UNIFI_RELOAD="service unifi restart" |
||||
|
_reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}" |
||||
|
|
||||
|
_debug _unifi_keystore "$_unifi_keystore" |
||||
|
if [ ! -f "$_unifi_keystore" ]; then |
||||
|
if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then |
||||
|
_err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE" |
||||
|
return 1 |
||||
|
else |
||||
|
_err "It seems that the specified unifi keystore is not valid, please check." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
if [ ! -w "$_unifi_keystore" ]; then |
||||
|
_err "The file $_unifi_keystore is not writable, please change the permission." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info "Generate import pkcs12" |
||||
|
_import_pkcs12="$(_mktemp)" |
||||
|
_toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root |
||||
|
if [ "$?" != "0" ]; then |
||||
|
_err "Oops, error creating import pkcs12, please report bug to us." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info "Modify unifi keystore: $_unifi_keystore" |
||||
|
if keytool -importkeystore \ |
||||
|
-deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \ |
||||
|
-srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \ |
||||
|
-alias unifi -noprompt; then |
||||
|
_info "Import keystore success!" |
||||
|
rm "$_import_pkcs12" |
||||
|
else |
||||
|
_err "Import unifi keystore error, please report bug to us." |
||||
|
rm "$_import_pkcs12" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info "Run reload: $_reload" |
||||
|
if eval "$_reload"; then |
||||
|
_info "Reload success!" |
||||
|
if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then |
||||
|
_savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE" |
||||
|
else |
||||
|
_cleardomainconf DEPLOY_UNIFI_KEYSTORE |
||||
|
fi |
||||
|
if [ "$DEPLOY_UNIFI_KEYPASS" ]; then |
||||
|
_savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS" |
||||
|
else |
||||
|
_cleardomainconf DEPLOY_UNIFI_KEYPASS |
||||
|
fi |
||||
|
if [ "$DEPLOY_UNIFI_RELOAD" ]; then |
||||
|
_savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD" |
||||
|
else |
||||
|
_cleardomainconf DEPLOY_UNIFI_RELOAD |
||||
|
fi |
||||
|
return 0 |
||||
|
else |
||||
|
_err "Reload error" |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
|
||||
|
} |
@ -0,0 +1,264 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- |
||||
|
|
||||
|
# This is the InternetX autoDNS xml api wrapper for acme.sh |
||||
|
# Author: auerswald@gmail.com |
||||
|
# Created: 2018-01-14 |
||||
|
# |
||||
|
# export AUTODNS_USER="username" |
||||
|
# export AUTODNS_PASSWORD="password" |
||||
|
# export AUTODNS_CONTEXT="context" |
||||
|
# |
||||
|
# Usage: |
||||
|
# acme.sh --issue --dns dns_autodns -d example.com |
||||
|
|
||||
|
AUTODNS_API="https://gateway.autodns.com" |
||||
|
|
||||
|
# Arguments: |
||||
|
# txtdomain |
||||
|
# txt |
||||
|
dns_autodns_add() { |
||||
|
fulldomain="$1" |
||||
|
txtvalue="$2" |
||||
|
|
||||
|
AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" |
||||
|
AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" |
||||
|
AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}" |
||||
|
|
||||
|
if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then |
||||
|
_err "You don't specify autodns user, password and context." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_saveaccountconf_mutable AUTODNS_USER "$AUTODNS_USER" |
||||
|
_saveaccountconf_mutable AUTODNS_PASSWORD "$AUTODNS_PASSWORD" |
||||
|
_saveaccountconf_mutable AUTODNS_CONTEXT "$AUTODNS_CONTEXT" |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
|
||||
|
if ! _get_autodns_zone "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _zone "$_zone" |
||||
|
_debug _system_ns "$_system_ns" |
||||
|
|
||||
|
_info "Adding TXT record" |
||||
|
|
||||
|
autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" |
||||
|
|
||||
|
if [ "$?" -eq "0" ]; then |
||||
|
_info "Added, OK" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
# Arguments: |
||||
|
# txtdomain |
||||
|
# txt |
||||
|
dns_autodns_rm() { |
||||
|
fulldomain="$1" |
||||
|
txtvalue="$2" |
||||
|
|
||||
|
AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" |
||||
|
AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" |
||||
|
AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}" |
||||
|
|
||||
|
if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then |
||||
|
_err "You don't specify autodns user, password and context." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
|
||||
|
if ! _get_autodns_zone "$fulldomain"; then |
||||
|
_err "zone not found" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _zone "$_zone" |
||||
|
_debug _system_ns "$_system_ns" |
||||
|
|
||||
|
_info "Delete TXT record" |
||||
|
|
||||
|
autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" |
||||
|
|
||||
|
if [ "$?" -eq "0" ]; then |
||||
|
_info "Deleted, OK" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
|
||||
|
# Arguments: |
||||
|
# fulldomain |
||||
|
# Returns: |
||||
|
# _sub_domain=_acme-challenge.www |
||||
|
# _zone=domain.com |
||||
|
# _system_ns |
||||
|
_get_autodns_zone() { |
||||
|
domain="$1" |
||||
|
|
||||
|
i=2 |
||||
|
p=1 |
||||
|
|
||||
|
while true; do |
||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100) |
||||
|
_debug h "$h" |
||||
|
|
||||
|
if [ -z "$h" ]; then |
||||
|
# not valid |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
autodns_response="$(_autodns_zone_inquire "$h")" |
||||
|
|
||||
|
if [ "$?" -ne "0" ]; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$autodns_response" "<summary>1</summary>" >/dev/null; then |
||||
|
_zone="$(echo "$autodns_response" | _egrep_o '<name>[^<]*</name>' | cut -d '>' -f 2 | cut -d '<' -f 1)" |
||||
|
_system_ns="$(echo "$autodns_response" | _egrep_o '<system_ns>[^<]*</system_ns>' | cut -d '>' -f 2 | cut -d '<' -f 1)" |
||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
p=$i |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
|
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
_build_request_auth_xml() { |
||||
|
printf "<auth> |
||||
|
<user>%s</user> |
||||
|
<password>%s</password> |
||||
|
<context>%s</context> |
||||
|
</auth>" "$AUTODNS_USER" "$AUTODNS_PASSWORD" "$AUTODNS_CONTEXT" |
||||
|
} |
||||
|
|
||||
|
# Arguments: |
||||
|
# zone |
||||
|
_build_zone_inquire_xml() { |
||||
|
printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?> |
||||
|
<request> |
||||
|
%s |
||||
|
<task> |
||||
|
<code>0205</code> |
||||
|
<view> |
||||
|
<children>1</children> |
||||
|
<limit>1</limit> |
||||
|
</view> |
||||
|
<where> |
||||
|
<key>name</key> |
||||
|
<operator>eq</operator> |
||||
|
<value>%s</value> |
||||
|
</where> |
||||
|
</task> |
||||
|
</request>" "$(_build_request_auth_xml)" "$1" |
||||
|
} |
||||
|
|
||||
|
# Arguments: |
||||
|
# zone |
||||
|
# subdomain |
||||
|
# txtvalue |
||||
|
# system_ns |
||||
|
_build_zone_update_xml() { |
||||
|
printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?> |
||||
|
<request> |
||||
|
%s |
||||
|
<task> |
||||
|
<code>0202001</code> |
||||
|
<default> |
||||
|
<rr_add> |
||||
|
<name>%s</name> |
||||
|
<ttl>600</ttl> |
||||
|
<type>TXT</type> |
||||
|
<value>%s</value> |
||||
|
</rr_add> |
||||
|
</default> |
||||
|
<zone> |
||||
|
<name>%s</name> |
||||
|
<system_ns>%s</system_ns> |
||||
|
</zone> |
||||
|
</task> |
||||
|
</request>" "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4" |
||||
|
} |
||||
|
|
||||
|
# Arguments: |
||||
|
# zone |
||||
|
_autodns_zone_inquire() { |
||||
|
request_data="$(_build_zone_inquire_xml "$1")" |
||||
|
autodns_response="$(_autodns_api_call "$request_data")" |
||||
|
ret="$?" |
||||
|
|
||||
|
printf "%s" "$autodns_response" |
||||
|
return "$ret" |
||||
|
} |
||||
|
|
||||
|
# Arguments: |
||||
|
# zone |
||||
|
# subdomain |
||||
|
# txtvalue |
||||
|
# system_ns |
||||
|
_autodns_zone_update() { |
||||
|
request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" |
||||
|
autodns_response="$(_autodns_api_call "$request_data")" |
||||
|
ret="$?" |
||||
|
|
||||
|
printf "%s" "$autodns_response" |
||||
|
return "$ret" |
||||
|
} |
||||
|
|
||||
|
# Arguments: |
||||
|
# zone |
||||
|
# subdomain |
||||
|
# txtvalue |
||||
|
# system_ns |
||||
|
_autodns_zone_cleanup() { |
||||
|
request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" |
||||
|
# replace 'rr_add>' with 'rr_rem>' in request_data |
||||
|
request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')" |
||||
|
autodns_response="$(_autodns_api_call "$request_data")" |
||||
|
ret="$?" |
||||
|
|
||||
|
printf "%s" "$autodns_response" |
||||
|
return "$ret" |
||||
|
} |
||||
|
|
||||
|
# Arguments: |
||||
|
# request_data |
||||
|
_autodns_api_call() { |
||||
|
request_data="$1" |
||||
|
|
||||
|
_debug request_data "$request_data" |
||||
|
|
||||
|
autodns_response="$(_post "$request_data" "$AUTODNS_API")" |
||||
|
ret="$?" |
||||
|
|
||||
|
_debug autodns_response "$autodns_response" |
||||
|
|
||||
|
if [ "$ret" -ne "0" ]; then |
||||
|
_err "error" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$autodns_response" "<type>success</type>" >/dev/null; then |
||||
|
_info "success" |
||||
|
printf "%s" "$autodns_response" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
return 1 |
||||
|
} |
@ -0,0 +1,249 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
# Used to add txt record |
||||
|
# |
||||
|
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate |
||||
|
# |
||||
|
dns_azure_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" |
||||
|
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" |
||||
|
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" |
||||
|
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" |
||||
|
|
||||
|
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then |
||||
|
AZUREDNS_SUBSCRIPTIONID="" |
||||
|
AZUREDNS_TENANTID="" |
||||
|
AZUREDNS_APPID="" |
||||
|
AZUREDNS_CLIENTSECRET="" |
||||
|
_err "You didn't specify the Azure Subscription ID " |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$AZUREDNS_TENANTID" ]; then |
||||
|
AZUREDNS_SUBSCRIPTIONID="" |
||||
|
AZUREDNS_TENANTID="" |
||||
|
AZUREDNS_APPID="" |
||||
|
AZUREDNS_CLIENTSECRET="" |
||||
|
_err "You didn't specify the Azure Tenant ID " |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$AZUREDNS_APPID" ]; then |
||||
|
AZUREDNS_SUBSCRIPTIONID="" |
||||
|
AZUREDNS_TENANTID="" |
||||
|
AZUREDNS_APPID="" |
||||
|
AZUREDNS_CLIENTSECRET="" |
||||
|
_err "You didn't specify the Azure App ID" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then |
||||
|
AZUREDNS_SUBSCRIPTIONID="" |
||||
|
AZUREDNS_TENANTID="" |
||||
|
AZUREDNS_APPID="" |
||||
|
AZUREDNS_CLIENTSECRET="" |
||||
|
_err "You didn't specify the Azure Client Secret" |
||||
|
return 1 |
||||
|
fi |
||||
|
#save account details to account conf file. |
||||
|
_saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID" |
||||
|
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID" |
||||
|
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID" |
||||
|
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET" |
||||
|
|
||||
|
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") |
||||
|
|
||||
|
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug _domain_id "$_domain_id" |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" |
||||
|
_debug "$acmeRecordURI" |
||||
|
body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" |
||||
|
_azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" |
||||
|
if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then |
||||
|
_info "validation record added" |
||||
|
else |
||||
|
_err "error adding validation record ($_code)" |
||||
|
return 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Usage: fulldomain txtvalue |
||||
|
# Used to remove the txt record after validation |
||||
|
# |
||||
|
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete |
||||
|
# |
||||
|
dns_azure_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" |
||||
|
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" |
||||
|
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" |
||||
|
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" |
||||
|
|
||||
|
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then |
||||
|
AZUREDNS_SUBSCRIPTIONID="" |
||||
|
AZUREDNS_TENANTID="" |
||||
|
AZUREDNS_APPID="" |
||||
|
AZUREDNS_CLIENTSECRET="" |
||||
|
_err "You didn't specify the Azure Subscription ID " |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$AZUREDNS_TENANTID" ]; then |
||||
|
AZUREDNS_SUBSCRIPTIONID="" |
||||
|
AZUREDNS_TENANTID="" |
||||
|
AZUREDNS_APPID="" |
||||
|
AZUREDNS_CLIENTSECRET="" |
||||
|
_err "You didn't specify the Azure Tenant ID " |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$AZUREDNS_APPID" ]; then |
||||
|
AZUREDNS_SUBSCRIPTIONID="" |
||||
|
AZUREDNS_TENANTID="" |
||||
|
AZUREDNS_APPID="" |
||||
|
AZUREDNS_CLIENTSECRET="" |
||||
|
_err "You didn't specify the Azure App ID" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then |
||||
|
AZUREDNS_SUBSCRIPTIONID="" |
||||
|
AZUREDNS_TENANTID="" |
||||
|
AZUREDNS_APPID="" |
||||
|
AZUREDNS_CLIENTSECRET="" |
||||
|
_err "You didn't specify the Azure Client Secret" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") |
||||
|
|
||||
|
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug _domain_id "$_domain_id" |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" |
||||
|
_debug "$acmeRecordURI" |
||||
|
body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" |
||||
|
_azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" |
||||
|
if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then |
||||
|
_info "validation record removed" |
||||
|
else |
||||
|
_err "error removing validation record ($_code)" |
||||
|
return 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
################### Private functions below ################################## |
||||
|
|
||||
|
_azure_rest() { |
||||
|
m=$1 |
||||
|
ep="$2" |
||||
|
data="$3" |
||||
|
accesstoken="$4" |
||||
|
|
||||
|
export _H1="authorization: Bearer $accesstoken" |
||||
|
export _H2="accept: application/json" |
||||
|
export _H3="Content-Type: application/json" |
||||
|
|
||||
|
_debug "$ep" |
||||
|
if [ "$m" != "GET" ]; then |
||||
|
_debug data "$data" |
||||
|
response="$(_post "$data" "$ep" "" "$m")" |
||||
|
else |
||||
|
response="$(_get "$ep")" |
||||
|
fi |
||||
|
_debug2 response "$response" |
||||
|
|
||||
|
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" |
||||
|
_debug2 "http response code $_code" |
||||
|
|
||||
|
if [ "$?" != "0" ]; then |
||||
|
_err "error $ep" |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token |
||||
|
_azure_getaccess_token() { |
||||
|
TENANTID=$1 |
||||
|
clientID=$2 |
||||
|
clientSecret=$3 |
||||
|
|
||||
|
export _H1="accept: application/json" |
||||
|
export _H2="Content-Type: application/x-www-form-urlencoded" |
||||
|
|
||||
|
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials" |
||||
|
_debug data "$body" |
||||
|
response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST")" |
||||
|
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") |
||||
|
_debug2 "response $response" |
||||
|
|
||||
|
if [ -z "$accesstoken" ]; then |
||||
|
_err "no acccess token received" |
||||
|
return 1 |
||||
|
fi |
||||
|
if [ "$?" != "0" ]; then |
||||
|
_err "error $response" |
||||
|
return 1 |
||||
|
fi |
||||
|
printf "%s" "$accesstoken" |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_get_root() { |
||||
|
domain=$1 |
||||
|
subscriptionId=$2 |
||||
|
accesstoken=$3 |
||||
|
i=2 |
||||
|
p=1 |
||||
|
|
||||
|
## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list |
||||
|
## returns up to 100 zones in one response therefore handling more results is not not implemented |
||||
|
## (ZoneListResult with continuation token for the next page of results) |
||||
|
## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways |
||||
|
## |
||||
|
_azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?api-version=2017-09-01" "" "$accesstoken" |
||||
|
|
||||
|
# Find matching domain name is Json response |
||||
|
while true; do |
||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100) |
||||
|
_debug2 "Checking domain: $h" |
||||
|
if [ -z "$h" ]; then |
||||
|
#not valid |
||||
|
_err "Invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then |
||||
|
_domain_id=$(echo "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \") |
||||
|
if [ "$_domain_id" ]; then |
||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |
||||
|
_domain=$h |
||||
|
return 0 |
||||
|
fi |
||||
|
return 1 |
||||
|
fi |
||||
|
p=$i |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
return 1 |
||||
|
} |
@ -0,0 +1,97 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
#Author: RhinoLance |
||||
|
#Report Bugs here: https://github.com/RhinoLance/acme.sh |
||||
|
# |
||||
|
|
||||
|
#define the api endpoint |
||||
|
DH_API_ENDPOINT="https://api.dreamhost.com/" |
||||
|
querystring="" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_dreamhost_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
if ! validate "$fulldomain" "$txtvalue"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
querystring="key=$DH_API_KEY&cmd=dns-add_record&record=$fulldomain&type=TXT&value=$txtvalue" |
||||
|
if ! submit "$querystring"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
#Usage: fulldomain txtvalue |
||||
|
#Remove the txt record after validation. |
||||
|
dns_dreamhost_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
if ! validate "$fulldomain" "$txtvalue"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
querystring="key=$DH_API_KEY&cmd=dns-remove_record&record=$fulldomain&type=TXT&value=$txtvalue" |
||||
|
if ! submit "$querystring"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
|
||||
|
#send the command to the api endpoint. |
||||
|
submit() { |
||||
|
querystring=$1 |
||||
|
|
||||
|
url="$DH_API_ENDPOINT?$querystring" |
||||
|
|
||||
|
_debug url "$url" |
||||
|
|
||||
|
if ! response="$(_get "$url")"; then |
||||
|
_err "Error <$1>" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$2" ]; then |
||||
|
message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" |
||||
|
if [ -n "$message" ]; then |
||||
|
_err "$message" |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
_debug response "$response" |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
#check that we have a valid API Key |
||||
|
validate() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
_info "Using dreamhost" |
||||
|
_debug fulldomain "$fulldomain" |
||||
|
_debug txtvalue "$txtvalue" |
||||
|
|
||||
|
#retrieve the API key from the environment variable if it exists, otherwise look for a saved key. |
||||
|
DH_API_KEY="${DH_API_KEY:-$(_readaccountconf_mutable DH_API_KEY)}" |
||||
|
|
||||
|
if [ -z "$DH_API_KEY" ]; then |
||||
|
DH_API_KEY="" |
||||
|
_err "You didn't specify the DreamHost api key yet (export DH_API_KEY=\"<api key>\")" |
||||
|
_err "Please login to your control panel, create a key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the api key to the account conf file. |
||||
|
_saveaccountconf_mutable DH_API_KEY "$DH_API_KEY" |
||||
|
} |
@ -0,0 +1,339 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
# |
||||
|
# Dyn.com Domain API |
||||
|
# |
||||
|
# Author: Gerd Naschenweng |
||||
|
# https://github.com/magicdude4eva |
||||
|
# |
||||
|
# Dyn Managed DNS API |
||||
|
# https://help.dyn.com/dns-api-knowledge-base/ |
||||
|
# |
||||
|
# It is recommended to add a "Dyn Managed DNS" user specific for API access. |
||||
|
# The "Zones & Records Permissions" required by this script are: |
||||
|
# -- |
||||
|
# RecordAdd |
||||
|
# RecordUpdate |
||||
|
# RecordDelete |
||||
|
# RecordGet |
||||
|
# ZoneGet |
||||
|
# ZoneAddNode |
||||
|
# ZoneRemoveNode |
||||
|
# ZonePublish |
||||
|
# -- |
||||
|
# |
||||
|
# Pass credentials before "acme.sh --issue --dns dns_dyn ..." |
||||
|
# -- |
||||
|
# export DYN_Customer="customer" |
||||
|
# export DYN_Username="apiuser" |
||||
|
# export DYN_Password="secret" |
||||
|
# -- |
||||
|
|
||||
|
DYN_API="https://api.dynect.net/REST" |
||||
|
|
||||
|
#REST_API |
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: add _acme-challenge.www.domain.com "Challenge-code" |
||||
|
dns_dyn_add() { |
||||
|
fulldomain="$1" |
||||
|
txtvalue="$2" |
||||
|
|
||||
|
DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" |
||||
|
DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" |
||||
|
DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" |
||||
|
if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then |
||||
|
DYN_Customer="" |
||||
|
DYN_Username="" |
||||
|
DYN_Password="" |
||||
|
_err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the config variables to the account conf file. |
||||
|
_saveaccountconf_mutable DYN_Customer "$DYN_Customer" |
||||
|
_saveaccountconf_mutable DYN_Username "$DYN_Username" |
||||
|
_saveaccountconf_mutable DYN_Password "$DYN_Password" |
||||
|
|
||||
|
if ! _dyn_get_authtoken; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$_dyn_authtoken" ]; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _dyn_get_zone; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _dyn_add_record; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _dyn_publish_zone; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_dyn_end_session |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
#Usage: fulldomain txtvalue |
||||
|
#Remove the txt record after validation. |
||||
|
dns_dyn_rm() { |
||||
|
fulldomain="$1" |
||||
|
txtvalue="$2" |
||||
|
|
||||
|
DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" |
||||
|
DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" |
||||
|
DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" |
||||
|
if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then |
||||
|
DYN_Customer="" |
||||
|
DYN_Username="" |
||||
|
DYN_Password="" |
||||
|
_err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _dyn_get_authtoken; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$_dyn_authtoken" ]; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _dyn_get_zone; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _dyn_get_record_id; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$_dyn_record_id" ]; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _dyn_rm_record; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _dyn_publish_zone; then |
||||
|
_dyn_end_session |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_dyn_end_session |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
|
||||
|
#get Auth-Token |
||||
|
_dyn_get_authtoken() { |
||||
|
|
||||
|
_info "Start Dyn API Session" |
||||
|
|
||||
|
data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}" |
||||
|
dyn_url="$DYN_API/Session/" |
||||
|
method="POST" |
||||
|
|
||||
|
_debug data "$data" |
||||
|
_debug dyn_url "$dyn_url" |
||||
|
|
||||
|
export _H1="Content-Type: application/json" |
||||
|
|
||||
|
response="$(_post "$data" "$dyn_url" "" "$method")" |
||||
|
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" |
||||
|
|
||||
|
_debug response "$response" |
||||
|
_debug sessionstatus "$sessionstatus" |
||||
|
|
||||
|
if [ "$sessionstatus" = "success" ]; then |
||||
|
_dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" |
||||
|
_info "Token received" |
||||
|
_debug _dyn_authtoken "$_dyn_authtoken" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
_dyn_authtoken="" |
||||
|
_err "get token failed" |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#fulldomain=_acme-challenge.www.domain.com |
||||
|
#returns |
||||
|
# _dyn_zone=domain.com |
||||
|
_dyn_get_zone() { |
||||
|
i=2 |
||||
|
while true; do |
||||
|
domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")" |
||||
|
if [ -z "$domain" ]; then |
||||
|
break |
||||
|
fi |
||||
|
|
||||
|
dyn_url="$DYN_API/Zone/$domain/" |
||||
|
|
||||
|
export _H1="Auth-Token: $_dyn_authtoken" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
response="$(_get "$dyn_url" "" "")" |
||||
|
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" |
||||
|
|
||||
|
_debug dyn_url "$dyn_url" |
||||
|
_debug response "$response" |
||||
|
_debug sessionstatus "$sessionstatus" |
||||
|
|
||||
|
if [ "$sessionstatus" = "success" ]; then |
||||
|
_dyn_zone="$domain" |
||||
|
return 0 |
||||
|
fi |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
|
||||
|
_dyn_zone="" |
||||
|
_err "get zone failed" |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#add TXT record |
||||
|
_dyn_add_record() { |
||||
|
|
||||
|
_info "Adding TXT record" |
||||
|
|
||||
|
data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}" |
||||
|
dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" |
||||
|
method="POST" |
||||
|
|
||||
|
export _H1="Auth-Token: $_dyn_authtoken" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
response="$(_post "$data" "$dyn_url" "" "$method")" |
||||
|
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" |
||||
|
|
||||
|
_debug response "$response" |
||||
|
_debug sessionstatus "$sessionstatus" |
||||
|
|
||||
|
if [ "$sessionstatus" = "success" ]; then |
||||
|
_info "TXT Record successfully added" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
_err "add TXT record failed" |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#publish the zone |
||||
|
_dyn_publish_zone() { |
||||
|
|
||||
|
_info "Publishing zone" |
||||
|
|
||||
|
data="{\"publish\":\"true\"}" |
||||
|
dyn_url="$DYN_API/Zone/$_dyn_zone/" |
||||
|
method="PUT" |
||||
|
|
||||
|
export _H1="Auth-Token: $_dyn_authtoken" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
response="$(_post "$data" "$dyn_url" "" "$method")" |
||||
|
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" |
||||
|
|
||||
|
_debug response "$response" |
||||
|
_debug sessionstatus "$sessionstatus" |
||||
|
|
||||
|
if [ "$sessionstatus" = "success" ]; then |
||||
|
_info "Zone published" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
_err "publish zone failed" |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#get record_id of TXT record so we can delete the record |
||||
|
_dyn_get_record_id() { |
||||
|
|
||||
|
_info "Getting record_id of TXT record" |
||||
|
|
||||
|
dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" |
||||
|
|
||||
|
export _H1="Auth-Token: $_dyn_authtoken" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
response="$(_get "$dyn_url" "" "")" |
||||
|
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" |
||||
|
|
||||
|
_debug response "$response" |
||||
|
_debug sessionstatus "$sessionstatus" |
||||
|
|
||||
|
if [ "$sessionstatus" = "success" ]; then |
||||
|
_dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" |
||||
|
_debug _dyn_record_id "$_dyn_record_id" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
_dyn_record_id="" |
||||
|
_err "getting record_id failed" |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#delete TXT record |
||||
|
_dyn_rm_record() { |
||||
|
|
||||
|
_info "Deleting TXT record" |
||||
|
|
||||
|
dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/" |
||||
|
method="DELETE" |
||||
|
|
||||
|
_debug dyn_url "$dyn_url" |
||||
|
|
||||
|
export _H1="Auth-Token: $_dyn_authtoken" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
response="$(_post "" "$dyn_url" "" "$method")" |
||||
|
sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" |
||||
|
|
||||
|
_debug response "$response" |
||||
|
_debug sessionstatus "$sessionstatus" |
||||
|
|
||||
|
if [ "$sessionstatus" = "success" ]; then |
||||
|
_info "TXT record successfully deleted" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
_err "delete TXT record failed" |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#logout |
||||
|
_dyn_end_session() { |
||||
|
|
||||
|
_info "End Dyn API Session" |
||||
|
|
||||
|
dyn_url="$DYN_API/Session/" |
||||
|
method="DELETE" |
||||
|
|
||||
|
_debug dyn_url "$dyn_url" |
||||
|
|
||||
|
export _H1="Auth-Token: $_dyn_authtoken" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
response="$(_post "" "$dyn_url" "" "$method")" |
||||
|
|
||||
|
_debug response "$response" |
||||
|
|
||||
|
_dyn_authtoken="" |
||||
|
return 0 |
||||
|
} |
@ -0,0 +1,158 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
######################################################################## |
||||
|
# Hurricane Electric hook script for acme.sh |
||||
|
# |
||||
|
# Environment variables: |
||||
|
# |
||||
|
# - $HE_Username (your dns.he.net username) |
||||
|
# - $HE_Password (your dns.he.net password) |
||||
|
# |
||||
|
# Author: Ondrej Simek <me@ondrejsimek.com> |
||||
|
# Git repo: https://github.com/angel333/acme.sh |
||||
|
|
||||
|
#-- dns_he_add() - Add TXT record -------------------------------------- |
||||
|
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..." |
||||
|
|
||||
|
dns_he_add() { |
||||
|
_full_domain=$1 |
||||
|
_txt_value=$2 |
||||
|
_info "Using DNS-01 Hurricane Electric hook" |
||||
|
|
||||
|
HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}" |
||||
|
HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}" |
||||
|
if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then |
||||
|
HE_Username= |
||||
|
HE_Password= |
||||
|
_err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables." |
||||
|
return 1 |
||||
|
fi |
||||
|
_saveaccountconf_mutable HE_Username "$HE_Username" |
||||
|
_saveaccountconf_mutable HE_Password "$HE_Password" |
||||
|
|
||||
|
# Fills in the $_zone_id |
||||
|
_find_zone "$_full_domain" || return 1 |
||||
|
_debug "Zone id \"$_zone_id\" will be used." |
||||
|
|
||||
|
body="email=${HE_Username}&pass=${HE_Password}" |
||||
|
body="$body&account=" |
||||
|
body="$body&menu=edit_zone" |
||||
|
body="$body&Type=TXT" |
||||
|
body="$body&hosted_dns_zoneid=$_zone_id" |
||||
|
body="$body&hosted_dns_recordid=" |
||||
|
body="$body&hosted_dns_editzone=1" |
||||
|
body="$body&Priority=" |
||||
|
body="$body&Name=$_full_domain" |
||||
|
body="$body&Content=$_txt_value" |
||||
|
body="$body&TTL=300" |
||||
|
body="$body&hosted_dns_editrecord=Submit" |
||||
|
response="$(_post "$body" "https://dns.he.net/")" |
||||
|
exit_code="$?" |
||||
|
if [ "$exit_code" -eq 0 ]; then |
||||
|
_info "TXT record added successfully." |
||||
|
else |
||||
|
_err "Couldn't add the TXT record." |
||||
|
fi |
||||
|
_debug2 response "$response" |
||||
|
return "$exit_code" |
||||
|
} |
||||
|
|
||||
|
#-- dns_he_rm() - Remove TXT record ------------------------------------ |
||||
|
# Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..." |
||||
|
|
||||
|
dns_he_rm() { |
||||
|
_full_domain=$1 |
||||
|
_txt_value=$2 |
||||
|
_info "Cleaning up after DNS-01 Hurricane Electric hook" |
||||
|
HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}" |
||||
|
HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}" |
||||
|
# fills in the $_zone_id |
||||
|
_find_zone "$_full_domain" || return 1 |
||||
|
_debug "Zone id \"$_zone_id\" will be used." |
||||
|
|
||||
|
# Find the record id to clean |
||||
|
body="email=${HE_Username}&pass=${HE_Password}" |
||||
|
body="$body&hosted_dns_zoneid=$_zone_id" |
||||
|
body="$body&menu=edit_zone" |
||||
|
body="$body&hosted_dns_editzone=" |
||||
|
|
||||
|
response="$(_post "$body" "https://dns.he.net/")" |
||||
|
_debug2 "response" "$response" |
||||
|
if ! _contains "$response" "$_txt_value"; then |
||||
|
_debug "The txt record is not found, just skip" |
||||
|
return 0 |
||||
|
fi |
||||
|
_record_id="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep "$_txt_value" | cut -d '"' -f 4)" |
||||
|
_debug2 _record_id "$_record_id" |
||||
|
if [ -z "$_record_id" ]; then |
||||
|
_err "Can not find record id" |
||||
|
return 1 |
||||
|
fi |
||||
|
# Remove the record |
||||
|
body="email=${HE_Username}&pass=${HE_Password}" |
||||
|
body="$body&menu=edit_zone" |
||||
|
body="$body&hosted_dns_zoneid=$_zone_id" |
||||
|
body="$body&hosted_dns_recordid=$_record_id" |
||||
|
body="$body&hosted_dns_editzone=1" |
||||
|
body="$body&hosted_dns_delrecord=1" |
||||
|
body="$body&hosted_dns_delconfirm=delete" |
||||
|
_post "$body" "https://dns.he.net/" \ |
||||
|
| grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \ |
||||
|
>/dev/null |
||||
|
exit_code="$?" |
||||
|
if [ "$exit_code" -eq 0 ]; then |
||||
|
_info "Record removed successfully." |
||||
|
else |
||||
|
_err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." |
||||
|
return "$exit_code" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
########################## PRIVATE FUNCTIONS ########################### |
||||
|
|
||||
|
_find_zone() { |
||||
|
_domain="$1" |
||||
|
body="email=${HE_Username}&pass=${HE_Password}" |
||||
|
response="$(_post "$body" "https://dns.he.net/")" |
||||
|
_debug2 response "$response" |
||||
|
_table="$(echo "$response" | tr -d "#" | sed "s/<table/#<table/g" | tr -d "\n" | tr "#" "\n" | grep 'id="domains_table"')" |
||||
|
_debug2 _table "$_table" |
||||
|
_matches="$(echo "$_table" | sed "s/<tr/#<tr/g" | tr "#" "\n" | grep 'alt="edit"' | tr -d " " | sed "s/<td/#<td/g" | tr "#" "\n" | sed -n 3p)" |
||||
|
_debug2 _matches "$_matches" |
||||
|
# Zone names and zone IDs are in same order |
||||
|
_zone_ids=$(echo "$_matches" | _egrep_o "hosted_dns_zoneid=[0-9]*&" | cut -d = -f 2 | tr -d '&') |
||||
|
_zone_names=$(echo "$_matches" | _egrep_o "name=.*onclick" | cut -d '"' -f 2) |
||||
|
_debug2 "These are the zones on this HE account:" |
||||
|
_debug2 "$_zone_names" |
||||
|
_debug2 "And these are their respective IDs:" |
||||
|
_debug2 "$_zone_ids" |
||||
|
if [ -z "$_zone_names" ] || [ -z "$_zone_ids" ]; then |
||||
|
_err "Can not get zone names." |
||||
|
return 1 |
||||
|
fi |
||||
|
# Walk through all possible zone names |
||||
|
_strip_counter=1 |
||||
|
while true; do |
||||
|
_attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-) |
||||
|
|
||||
|
# All possible zone names have been tried |
||||
|
if [ -z "$_attempted_zone" ]; then |
||||
|
_err "No zone for domain \"$_domain\" found." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug "Looking for zone \"${_attempted_zone}\"" |
||||
|
|
||||
|
line_num="$(echo "$_zone_names" | grep -n "$_attempted_zone" | cut -d : -f 1)" |
||||
|
|
||||
|
if [ "$line_num" ]; then |
||||
|
_zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p") |
||||
|
_debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"." |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
_debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone." |
||||
|
_strip_counter=$(_math "$_strip_counter" + 1) |
||||
|
done |
||||
|
} |
||||
|
# vim: et:ts=2:sw=2: |
@ -0,0 +1,311 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# |
||||
|
#INWX_User="username" |
||||
|
# |
||||
|
#INWX_Password="password" |
||||
|
|
||||
|
INWX_Api="https://api.domrobot.com/xmlrpc/" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_inwx_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" |
||||
|
INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" |
||||
|
if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then |
||||
|
INWX_User="" |
||||
|
INWX_Password="" |
||||
|
_err "You don't specify inwx user and password yet." |
||||
|
_err "Please create you key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the api key and email to the account conf file. |
||||
|
_saveaccountconf_mutable INWX_User "$INWX_User" |
||||
|
_saveaccountconf_mutable INWX_Password "$INWX_Password" |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
_info "Adding record" |
||||
|
_inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#fulldomain txtvalue |
||||
|
dns_inwx_rm() { |
||||
|
|
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" |
||||
|
INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" |
||||
|
if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then |
||||
|
INWX_User="" |
||||
|
INWX_Password="" |
||||
|
_err "You don't specify inwx user and password yet." |
||||
|
_err "Please create you key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the api key and email to the account conf file. |
||||
|
_saveaccountconf_mutable INWX_User "$INWX_User" |
||||
|
_saveaccountconf_mutable INWX_Password "$INWX_Password" |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
_debug "Getting txt records" |
||||
|
|
||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<methodCall> |
||||
|
<methodName>nameserver.info</methodName> |
||||
|
<params> |
||||
|
<param> |
||||
|
<value> |
||||
|
<struct> |
||||
|
<member> |
||||
|
<name>domain</name> |
||||
|
<value> |
||||
|
<string>%s</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
<member> |
||||
|
<name>type</name> |
||||
|
<value> |
||||
|
<string>TXT</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
<member> |
||||
|
<name>name</name> |
||||
|
<value> |
||||
|
<string>%s</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
</struct> |
||||
|
</value> |
||||
|
</param> |
||||
|
</params> |
||||
|
</methodCall>' "$_domain" "$_sub_domain") |
||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" |
||||
|
|
||||
|
if ! _contains "$response" "Command completed successfully"; then |
||||
|
_err "Error could not get txt records" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! printf "%s" "$response" | grep "count" >/dev/null; then |
||||
|
_info "Do not need to delete record" |
||||
|
else |
||||
|
_record_id=$(printf '%s' "$response" | _egrep_o '.*(<member><name>record){1}(.*)([0-9]+){1}' | _egrep_o '<name>id<\/name><value><int>[0-9]+' | _egrep_o '[0-9]+') |
||||
|
_info "Deleting record" |
||||
|
_inwx_delete_record "$_record_id" |
||||
|
fi |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
|
||||
|
_inwx_login() { |
||||
|
|
||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<methodCall> |
||||
|
<methodName>account.login</methodName> |
||||
|
<params> |
||||
|
<param> |
||||
|
<value> |
||||
|
<struct> |
||||
|
<member> |
||||
|
<name>user</name> |
||||
|
<value> |
||||
|
<string>%s</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
<member> |
||||
|
<name>pass</name> |
||||
|
<value> |
||||
|
<string>%s</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
</struct> |
||||
|
</value> |
||||
|
</param> |
||||
|
</params> |
||||
|
</methodCall>' $INWX_User $INWX_Password) |
||||
|
|
||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" |
||||
|
|
||||
|
printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')" |
||||
|
|
||||
|
} |
||||
|
|
||||
|
_get_root() { |
||||
|
domain=$1 |
||||
|
_debug "get root" |
||||
|
|
||||
|
domain=$1 |
||||
|
i=2 |
||||
|
p=1 |
||||
|
|
||||
|
_H1=$(_inwx_login) |
||||
|
export _H1 |
||||
|
xml_content='<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<methodCall> |
||||
|
<methodName>nameserver.list</methodName> |
||||
|
</methodCall>' |
||||
|
|
||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" |
||||
|
while true; do |
||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100) |
||||
|
_debug h "$h" |
||||
|
if [ -z "$h" ]; then |
||||
|
#not valid |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$response" "$h"; then |
||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |
||||
|
_domain="$h" |
||||
|
return 0 |
||||
|
fi |
||||
|
p=$i |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
return 1 |
||||
|
|
||||
|
} |
||||
|
|
||||
|
_inwx_delete_record() { |
||||
|
record_id=$1 |
||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<methodCall> |
||||
|
<methodName>nameserver.deleteRecord</methodName> |
||||
|
<params> |
||||
|
<param> |
||||
|
<value> |
||||
|
<struct> |
||||
|
<member> |
||||
|
<name>id</name> |
||||
|
<value> |
||||
|
<int>%s</int> |
||||
|
</value> |
||||
|
</member> |
||||
|
</struct> |
||||
|
</value> |
||||
|
</param> |
||||
|
</params> |
||||
|
</methodCall>' "$record_id") |
||||
|
|
||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" |
||||
|
|
||||
|
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then |
||||
|
_err "Error" |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
|
||||
|
} |
||||
|
|
||||
|
_inwx_update_record() { |
||||
|
record_id=$1 |
||||
|
txtval=$2 |
||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<methodCall> |
||||
|
<methodName>nameserver.updateRecord</methodName> |
||||
|
<params> |
||||
|
<param> |
||||
|
<value> |
||||
|
<struct> |
||||
|
<member> |
||||
|
<name>content</name> |
||||
|
<value> |
||||
|
<string>%s</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
<member> |
||||
|
<name>id</name> |
||||
|
<value> |
||||
|
<int>%s</int> |
||||
|
</value> |
||||
|
</member> |
||||
|
</struct> |
||||
|
</value> |
||||
|
</param> |
||||
|
</params> |
||||
|
</methodCall>' "$txtval" "$record_id") |
||||
|
|
||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" |
||||
|
|
||||
|
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then |
||||
|
_err "Error" |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
|
||||
|
} |
||||
|
|
||||
|
_inwx_add_record() { |
||||
|
|
||||
|
domain=$1 |
||||
|
sub_domain=$2 |
||||
|
txtval=$3 |
||||
|
|
||||
|
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<methodCall> |
||||
|
<methodName>nameserver.createRecord</methodName> |
||||
|
<params> |
||||
|
<param> |
||||
|
<value> |
||||
|
<struct> |
||||
|
<member> |
||||
|
<name>domain</name> |
||||
|
<value> |
||||
|
<string>%s</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
<member> |
||||
|
<name>type</name> |
||||
|
<value> |
||||
|
<string>TXT</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
<member> |
||||
|
<name>content</name> |
||||
|
<value> |
||||
|
<string>%s</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
<member> |
||||
|
<name>name</name> |
||||
|
<value> |
||||
|
<string>%s</string> |
||||
|
</value> |
||||
|
</member> |
||||
|
</struct> |
||||
|
</value> |
||||
|
</param> |
||||
|
</params> |
||||
|
</methodCall>' "$domain" "$txtval" "$sub_domain") |
||||
|
|
||||
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" |
||||
|
|
||||
|
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then |
||||
|
_err "Error" |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
} |
@ -0,0 +1,137 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
#Author: meowthink |
||||
|
#Created 01/14/2017 |
||||
|
#Utilize namesilo.com API to finish dns-01 verifications. |
||||
|
|
||||
|
Namesilo_API="https://www.namesilo.com/api" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_namesilo_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
if [ -z "$Namesilo_Key" ]; then |
||||
|
Namesilo_Key="" |
||||
|
_err "API token for namesilo.com is missing." |
||||
|
_err "Please specify that in your environment variable." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the api key and email to the account conf file. |
||||
|
_saveaccountconf Namesilo_Key "$Namesilo_Key" |
||||
|
|
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "Unable to find domain specified." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
_debug txtvalue "$txtvalue" |
||||
|
if _namesilo_rest GET "dnsAddRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrtype=TXT&rrhost=$_sub_domain&rrvalue=$txtvalue"; then |
||||
|
retcode=$(printf "%s\n" "$response" | _egrep_o "<code>300") |
||||
|
if [ "$retcode" ]; then |
||||
|
_info "Successfully added TXT record, ready for validation." |
||||
|
return 0 |
||||
|
else |
||||
|
_err "Unable to add the DNS record." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
#Usage: fulldomain txtvalue |
||||
|
#Remove the txt record after validation. |
||||
|
dns_namesilo_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "Unable to find domain specified." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
# Get the record id. |
||||
|
if _namesilo_rest GET "dnsListRecords?version=1&type=xml&key=$Namesilo_Key&domain=$_domain"; then |
||||
|
retcode=$(printf "%s\n" "$response" | _egrep_o "<code>300") |
||||
|
if [ "$retcode" ]; then |
||||
|
_record_id=$(printf "%s\n" "$response" | _egrep_o "<record_id>([^<]*)</record_id><type>TXT</type><host>$fulldomain</host>" | _egrep_o "<record_id>([^<]*)</record_id>" | sed -r "s/<record_id>([^<]*)<\/record_id>/\1/" | tail -n 1) |
||||
|
_debug record_id "$_record_id" |
||||
|
_info "Successfully retrieved the record id for ACME challenge." |
||||
|
else |
||||
|
_err "Unable to retrieve the record id." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
# Remove the DNS record using record id. |
||||
|
if _namesilo_rest GET "dnsDeleteRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrid=$_record_id"; then |
||||
|
retcode=$(printf "%s\n" "$response" | _egrep_o "<code>300") |
||||
|
if [ "$retcode" ]; then |
||||
|
_info "Successfully removed the TXT record." |
||||
|
return 0 |
||||
|
else |
||||
|
_err "Unable to remove the DNS record." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
|
||||
|
# _acme-challenge.www.domain.com |
||||
|
# returns |
||||
|
# _sub_domain=_acme-challenge.www |
||||
|
# _domain=domain.com |
||||
|
_get_root() { |
||||
|
domain=$1 |
||||
|
i=2 |
||||
|
p=1 |
||||
|
|
||||
|
if ! _namesilo_rest GET "listDomains?version=1&type=xml&key=$Namesilo_Key"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
# Need to exclude the last field (tld) |
||||
|
numfields=$(echo "$domain" | _egrep_o "\." | wc -l) |
||||
|
while [ $i -le "$numfields" ]; do |
||||
|
host=$(printf "%s" "$domain" | cut -d . -f $i-100) |
||||
|
_debug host "$host" |
||||
|
if [ -z "$host" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$response" "$host"; then |
||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |
||||
|
_domain="$host" |
||||
|
return 0 |
||||
|
fi |
||||
|
p=$i |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
_namesilo_rest() { |
||||
|
method=$1 |
||||
|
param=$2 |
||||
|
data=$3 |
||||
|
|
||||
|
if [ "$method" != "GET" ]; then |
||||
|
response="$(_post "$data" "$Namesilo_API/$param" "" "$method")" |
||||
|
else |
||||
|
response="$(_get "$Namesilo_API/$param")" |
||||
|
fi |
||||
|
|
||||
|
if [ "$?" != "0" ]; then |
||||
|
_err "error $param" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug2 response "$response" |
||||
|
return 0 |
||||
|
} |
@ -0,0 +1,161 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# |
||||
|
#SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" |
||||
|
# |
||||
|
|
||||
|
SL_Api="https://api.selectel.ru/domains/v1" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_selectel_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}" |
||||
|
|
||||
|
if [ -z "$SL_Key" ]; then |
||||
|
SL_Key="" |
||||
|
_err "You don't specify selectel.ru api key yet." |
||||
|
_err "Please create you key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the api key to the account conf file. |
||||
|
_saveaccountconf_mutable SL_Key "$SL_Key" |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug _domain_id "$_domain_id" |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
_info "Adding record" |
||||
|
if _sl_rest POST "/$_domain_id/records/" "{\"type\": \"TXT\", \"ttl\": 60, \"name\": \"$fulldomain\", \"content\": \"$txtvalue\"}"; then |
||||
|
if _contains "$response" "$txtvalue" || _contains "$response" "record_already_exists"; then |
||||
|
_info "Added, OK" |
||||
|
return 0 |
||||
|
fi |
||||
|
fi |
||||
|
_err "Add txt record error." |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#fulldomain txtvalue |
||||
|
dns_selectel_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}" |
||||
|
|
||||
|
if [ -z "$SL_Key" ]; then |
||||
|
SL_Key="" |
||||
|
_err "You don't specify slectel api key yet." |
||||
|
_err "Please create you key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug _domain_id "$_domain_id" |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
_debug "Getting txt records" |
||||
|
_sl_rest GET "/${_domain_id}/records/" |
||||
|
|
||||
|
if ! _contains "$response" "$txtvalue"; then |
||||
|
_err "Txt record not found" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_record_seg="$(echo "$response" | _egrep_o "\"content\" *: *\"$txtvalue\"[^}]*}")" |
||||
|
_debug2 "_record_seg" "$_record_seg" |
||||
|
if [ -z "$_record_seg" ]; then |
||||
|
_err "can not find _record_seg" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_record_id="$(echo "$_record_seg" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\"" | cut -d : -f 2)" |
||||
|
_debug2 "_record_id" "$_record_id" |
||||
|
if [ -z "$_record_id" ]; then |
||||
|
_err "can not find _record_id" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _sl_rest DELETE "/$_domain_id/records/$_record_id"; then |
||||
|
_err "Delete record error." |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
#_acme-challenge.www.domain.com |
||||
|
#returns |
||||
|
# _sub_domain=_acme-challenge.www |
||||
|
# _domain=domain.com |
||||
|
# _domain_id=sdjkglgdfewsdfg |
||||
|
_get_root() { |
||||
|
domain=$1 |
||||
|
|
||||
|
if ! _sl_rest GET "/"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
i=2 |
||||
|
p=1 |
||||
|
while true; do |
||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100) |
||||
|
_debug h "$h" |
||||
|
if [ -z "$h" ]; then |
||||
|
#not valid |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$response" "\"name\": \"$h\","; then |
||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |
||||
|
_domain=$h |
||||
|
_debug "Getting domain id for $h" |
||||
|
if ! _sl_rest GET "/$h"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
_domain_id="$(echo "$response" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\":" | cut -d : -f 2)" |
||||
|
return 0 |
||||
|
fi |
||||
|
p=$i |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
_sl_rest() { |
||||
|
m=$1 |
||||
|
ep="$2" |
||||
|
data="$3" |
||||
|
_debug "$ep" |
||||
|
|
||||
|
export _H1="X-Token: $SL_Key" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
if [ "$m" != "GET" ]; then |
||||
|
_debug data "$data" |
||||
|
response="$(_post "$data" "$SL_Api/$ep" "" "$m")" |
||||
|
else |
||||
|
response="$(_get "$SL_Api/$ep")" |
||||
|
fi |
||||
|
|
||||
|
if [ "$?" != "0" ]; then |
||||
|
_err "error $ep" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug2 response "$response" |
||||
|
return 0 |
||||
|
} |
@ -0,0 +1,170 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
########## |
||||
|
# Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/Neilpang/acme.sh) |
||||
|
# |
||||
|
# Usage: |
||||
|
# export SERVERCOW_API_Username=username |
||||
|
# export SERVERCOW_API_Password=password |
||||
|
# acme.sh --issue -d example.com --dns dns_servercow |
||||
|
# |
||||
|
# Issues: |
||||
|
# Any issues / questions / suggestions can be posted here: |
||||
|
# https://github.com/jhartlep/servercow-dns-api/issues |
||||
|
# |
||||
|
# Author: Jens Hartlep |
||||
|
########## |
||||
|
|
||||
|
SERVERCOW_API="https://api.servercow.de/dns/v1/domains" |
||||
|
|
||||
|
# Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz" |
||||
|
dns_servercow_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
_info "Using servercow" |
||||
|
_debug fulldomain "$fulldomain" |
||||
|
_debug txtvalue "$txtvalue" |
||||
|
|
||||
|
SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" |
||||
|
SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" |
||||
|
if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then |
||||
|
SERVERCOW_API_Username="" |
||||
|
SERVERCOW_API_Password="" |
||||
|
_err "You don't specify servercow api username and password yet." |
||||
|
_err "Please create your username and password and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
# save the credentials to the account conf file |
||||
|
_saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" |
||||
|
_saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password" |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then |
||||
|
if printf -- "%s" "$response" | grep "ok" >/dev/null; then |
||||
|
_info "Added, OK" |
||||
|
return 0 |
||||
|
else |
||||
|
_err "add txt record error." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
_err "add txt record error." |
||||
|
|
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
# Usage fulldomain txtvalue |
||||
|
# Remove the txt record after validation |
||||
|
dns_servercow_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
_info "Using servercow" |
||||
|
_debug fulldomain "$fulldomain" |
||||
|
_debug txtvalue "$fulldomain" |
||||
|
|
||||
|
SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" |
||||
|
SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" |
||||
|
if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then |
||||
|
SERVERCOW_API_Username="" |
||||
|
SERVERCOW_API_Password="" |
||||
|
_err "You don't specify servercow api username and password yet." |
||||
|
_err "Please create your username and password and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then |
||||
|
if printf -- "%s" "$response" | grep "ok" >/dev/null; then |
||||
|
_info "Deleted, OK" |
||||
|
_contains "$response" '"message":"ok"' |
||||
|
else |
||||
|
_err "delete txt record error." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
|
||||
|
# _acme-challenge.www.domain.com |
||||
|
# returns |
||||
|
# _sub_domain=_acme-challenge.www |
||||
|
# _domain=domain.com |
||||
|
_get_root() { |
||||
|
fulldomain=$1 |
||||
|
i=2 |
||||
|
p=1 |
||||
|
|
||||
|
while true; do |
||||
|
_domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) |
||||
|
|
||||
|
_debug _domain "$_domain" |
||||
|
if [ -z "$_domain" ]; then |
||||
|
# not valid |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _servercow_api GET "$_domain"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then |
||||
|
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) |
||||
|
if [ -z "$_sub_domain" ]; then |
||||
|
# not valid |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
p=$i |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
|
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
_servercow_api() { |
||||
|
method=$1 |
||||
|
domain=$2 |
||||
|
data="$3" |
||||
|
|
||||
|
export _H1="Content-Type: application/json" |
||||
|
export _H2="X-Auth-Username: $SERVERCOW_API_Username" |
||||
|
export _H3="X-Auth-Password: $SERVERCOW_API_Password" |
||||
|
|
||||
|
if [ "$method" != "GET" ]; then |
||||
|
_debug data "$data" |
||||
|
response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" |
||||
|
else |
||||
|
response="$(_get "$SERVERCOW_API/$domain")" |
||||
|
fi |
||||
|
|
||||
|
if [ "$?" != "0" ]; then |
||||
|
_err "error $domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug2 response "$response" |
||||
|
return 0 |
||||
|
} |
@ -0,0 +1,202 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# |
||||
|
#UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" |
||||
|
# |
||||
|
#UNO_User="UExxxxxx" |
||||
|
|
||||
|
Uno_Api="https://api.unoeuro.com/1" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_unoeuro_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" |
||||
|
UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" |
||||
|
if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then |
||||
|
UNO_Key="" |
||||
|
UNO_User="" |
||||
|
_err "You haven't specified a UnoEuro api key and account yet." |
||||
|
_err "Please create your key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _contains "$UNO_User" "UE"; then |
||||
|
_err "It seems that the UNO_User=$UNO_User is not a valid username." |
||||
|
_err "Please check and retry." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the api key and email to the account conf file. |
||||
|
_saveaccountconf_mutable UNO_Key "$UNO_Key" |
||||
|
_saveaccountconf_mutable UNO_User "$UNO_User" |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug _domain_id "$_domain_id" |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
_debug "Getting txt records" |
||||
|
_uno_rest GET "my/products/$h/dns/records" |
||||
|
|
||||
|
if ! _contains "$response" "\"status\": 200" >/dev/null; then |
||||
|
_err "Error" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _contains "$response" "$_sub_domain" >/dev/null; then |
||||
|
_info "Adding record" |
||||
|
|
||||
|
if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then |
||||
|
if _contains "$response" "\"status\": 200" >/dev/null; then |
||||
|
_info "Added, OK" |
||||
|
return 0 |
||||
|
else |
||||
|
_err "Add txt record error." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
_err "Add txt record error." |
||||
|
else |
||||
|
_info "Updating record" |
||||
|
record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) |
||||
|
record_line_number=$(_math "$record_line_number" - 1) |
||||
|
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") |
||||
|
_debug "record_id" "$record_id" |
||||
|
|
||||
|
_uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}" |
||||
|
if _contains "$response" "\"status\": 200" >/dev/null; then |
||||
|
_info "Updated, OK" |
||||
|
return 0 |
||||
|
fi |
||||
|
_err "Update error" |
||||
|
return 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
#fulldomain txtvalue |
||||
|
dns_unoeuro_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" |
||||
|
UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" |
||||
|
if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then |
||||
|
UNO_Key="" |
||||
|
UNO_User="" |
||||
|
_err "You haven't specified a UnoEuro api key and account yet." |
||||
|
_err "Please create your key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _contains "$UNO_User" "UE"; then |
||||
|
_err "It seems that the UNO_User=$UNO_User is not a valid username." |
||||
|
_err "Please check and retry." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug "First detect the root zone" |
||||
|
if ! _get_root "$fulldomain"; then |
||||
|
_err "invalid domain" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug _domain_id "$_domain_id" |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
_debug _domain "$_domain" |
||||
|
|
||||
|
_debug "Getting txt records" |
||||
|
_uno_rest GET "my/products/$h/dns/records" |
||||
|
|
||||
|
if ! _contains "$response" "\"status\": 200"; then |
||||
|
_err "Error" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _contains "$response" "$_sub_domain"; then |
||||
|
_info "Don't need to remove." |
||||
|
else |
||||
|
record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) |
||||
|
record_line_number=$(_math "$record_line_number" - 1) |
||||
|
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") |
||||
|
_debug "record_id" "$record_id" |
||||
|
|
||||
|
if [ -z "$record_id" ]; then |
||||
|
_err "Can not get record id to remove." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then |
||||
|
_err "Delete record error." |
||||
|
return 1 |
||||
|
fi |
||||
|
_contains "$response" "\"status\": 200" |
||||
|
fi |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
#_acme-challenge.www.domain.com |
||||
|
#returns |
||||
|
# _sub_domain=_acme-challenge.www |
||||
|
# _domain=domain.com |
||||
|
# _domain_id=sdjkglgdfewsdfg |
||||
|
_get_root() { |
||||
|
domain=$1 |
||||
|
i=2 |
||||
|
p=1 |
||||
|
while true; do |
||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100) |
||||
|
_debug h "$h" |
||||
|
if [ -z "$h" ]; then |
||||
|
#not valid |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _uno_rest GET "my/products/$h/dns/records"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$response" "\"status\": 200"; then |
||||
|
_domain_id=$h |
||||
|
if [ "$_domain_id" ]; then |
||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) |
||||
|
_domain=$h |
||||
|
return 0 |
||||
|
fi |
||||
|
return 1 |
||||
|
fi |
||||
|
p=$i |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
_uno_rest() { |
||||
|
m=$1 |
||||
|
ep="$2" |
||||
|
data="$3" |
||||
|
_debug "$ep" |
||||
|
|
||||
|
export _H1="Content-Type: application/json" |
||||
|
|
||||
|
if [ "$m" != "GET" ]; then |
||||
|
_debug data "$data" |
||||
|
response="$(_post "$data" "$Uno_Api/$UNO_User/$UNO_Key/$ep" "" "$m")" |
||||
|
else |
||||
|
response="$(_get "$Uno_Api/$UNO_User/$UNO_Key/$ep")" |
||||
|
fi |
||||
|
|
||||
|
if [ "$?" != "0" ]; then |
||||
|
_err "error $ep" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug2 response "$response" |
||||
|
return 0 |
||||
|
} |
@ -0,0 +1,106 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
# Author: non7top@gmail.com |
||||
|
# 07 Jul 2017 |
||||
|
# report bugs at https://github.com/non7top/acme.sh |
||||
|
|
||||
|
# Values to export: |
||||
|
# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_yandex_add() { |
||||
|
fulldomain="${1}" |
||||
|
txtvalue="${2}" |
||||
|
_debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" |
||||
|
_PDD_credentials || return 1 |
||||
|
export _H1="PddToken: $PDD_Token" |
||||
|
|
||||
|
_PDD_get_domain "$fulldomain" |
||||
|
_debug "Found suitable domain in pdd: $curDomain" |
||||
|
curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" |
||||
|
curUri="https://pddimp.yandex.ru/api2/admin/dns/add" |
||||
|
curResult="$(_post "${curData}" "${curUri}")" |
||||
|
_debug "Result: $curResult" |
||||
|
} |
||||
|
|
||||
|
#Usage: dns_myapi_rm _acme-challenge.www.domain.com |
||||
|
dns_yandex_rm() { |
||||
|
fulldomain="${1}" |
||||
|
_debug "Calling: dns_yandex_rm() '${fulldomain}'" |
||||
|
_PDD_credentials || return 1 |
||||
|
export _H1="PddToken: $PDD_Token" |
||||
|
record_id=$(pdd_get_record_id "${fulldomain}") |
||||
|
_debug "Result: $record_id" |
||||
|
|
||||
|
_PDD_get_domain "$fulldomain" |
||||
|
_debug "Found suitable domain in pdd: $curDomain" |
||||
|
|
||||
|
curUri="https://pddimp.yandex.ru/api2/admin/dns/del" |
||||
|
curData="domain=${curDomain}&record_id=${record_id}" |
||||
|
curResult="$(_post "${curData}" "${curUri}")" |
||||
|
_debug "Result: $curResult" |
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
|
||||
|
_PDD_get_domain() { |
||||
|
fulldomain="${1}" |
||||
|
__page=1 |
||||
|
__last=0 |
||||
|
while [ $__last -eq 0 ]; do |
||||
|
uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" |
||||
|
res1=$(_get "$uri1" | _normalizeJson) |
||||
|
#_debug "$res1" |
||||
|
__found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') |
||||
|
_debug "found: $__found results on page" |
||||
|
if [ "$__found" -lt 20 ]; then |
||||
|
_debug "last page: $__page" |
||||
|
__last=1 |
||||
|
fi |
||||
|
|
||||
|
__all_domains="$__all_domains $(echo "$res1" | tr "," "\n" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" |
||||
|
|
||||
|
__page=$(_math $__page + 1) |
||||
|
done |
||||
|
|
||||
|
k=2 |
||||
|
while [ $k -lt 10 ]; do |
||||
|
__t=$(echo "$fulldomain" | cut -d . -f $k-100) |
||||
|
_debug "finding zone for domain $__t" |
||||
|
for d in $__all_domains; do |
||||
|
if [ "$d" = "$__t" ]; then |
||||
|
p=$(_math $k - 1) |
||||
|
curSubdomain="$(echo "$fulldomain" | cut -d . -f "1-$p")" |
||||
|
curDomain="$__t" |
||||
|
return 0 |
||||
|
fi |
||||
|
done |
||||
|
k=$(_math $k + 1) |
||||
|
done |
||||
|
_err "No suitable domain found in your account" |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
_PDD_credentials() { |
||||
|
if [ -z "${PDD_Token}" ]; then |
||||
|
PDD_Token="" |
||||
|
_err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx" |
||||
|
_err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token" |
||||
|
return 1 |
||||
|
else |
||||
|
_saveaccountconf PDD_Token "${PDD_Token}" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
pdd_get_record_id() { |
||||
|
fulldomain="${1}" |
||||
|
|
||||
|
_PDD_get_domain "$fulldomain" |
||||
|
_debug "Found suitable domain in pdd: $curDomain" |
||||
|
|
||||
|
curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" |
||||
|
curResult="$(_get "${curUri}" | _normalizeJson)" |
||||
|
_debug "Result: $curResult" |
||||
|
echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' |
||||
|
} |
@ -0,0 +1,85 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# |
||||
|
#ZM_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" |
||||
|
# |
||||
|
#https://zonomi.com dns api |
||||
|
|
||||
|
ZM_Api="https://zonomi.com/app/dns/dyndns.jsp" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_zonomi_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}" |
||||
|
|
||||
|
if [ -z "$ZM_Key" ]; then |
||||
|
ZM_Key="" |
||||
|
_err "You don't specify zonomi api key yet." |
||||
|
_err "Please create your key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the api key to the account conf file. |
||||
|
_saveaccountconf_mutable ZM_Key "$ZM_Key" |
||||
|
|
||||
|
_info "Get existing txt records for $fulldomain" |
||||
|
if ! _zm_request "action=QUERY&name=$fulldomain"; then |
||||
|
_err "error" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$response" "<record"; then |
||||
|
_debug "get and update records" |
||||
|
_qstr="action[1]=SET&type[1]=TXT&name[1]=$fulldomain&value[1]=$txtvalue" |
||||
|
_qindex=2 |
||||
|
for t in $(echo "$response" | tr -d "\r\n" | _egrep_o '<action.*</action>' | tr "<" "\n" | grep record | grep 'type="TXT"' | cut -d '"' -f 6); do |
||||
|
_debug2 t "$t" |
||||
|
_qstr="$_qstr&action[$_qindex]=SET&type[$_qindex]=TXT&name[$_qindex]=$fulldomain&value[$_qindex]=$t" |
||||
|
_qindex="$(_math "$_qindex" + 1)" |
||||
|
done |
||||
|
_zm_request "$_qstr" |
||||
|
else |
||||
|
_debug "Just add record" |
||||
|
_zm_request "action=SET&type=TXT&name=$fulldomain&value=$txtvalue" |
||||
|
fi |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#fulldomain txtvalue |
||||
|
dns_zonomi_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}" |
||||
|
if [ -z "$ZM_Key" ]; then |
||||
|
ZM_Key="" |
||||
|
_err "You don't specify zonomi api key yet." |
||||
|
_err "Please create your key and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_zm_request "action=DELETE&type=TXT&name=$fulldomain" |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
#qstr |
||||
|
_zm_request() { |
||||
|
qstr="$1" |
||||
|
|
||||
|
_debug2 "qstr" "$qstr" |
||||
|
|
||||
|
_zm_url="$ZM_Api?api_key=$ZM_Key&$qstr" |
||||
|
_debug2 "_zm_url" "$_zm_url" |
||||
|
response="$(_get "$_zm_url")" |
||||
|
|
||||
|
if [ "$?" != "0" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug2 response "$response" |
||||
|
_contains "$response" "<is_ok>OK:" |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue