Return instead of exit.

Clear OTP secret if environment variable is set to empty. This is for when the 2FA is disabled.
Rename `_is_idn` function to `_is_idn_cyon`.
Remove usage of curl (except for URL encoding of data).
Instead of cleaning up the cookie jar, get rid of it completely and logout of cyon instead.
This commit is contained in:
Armando Lüscher 2016-11-23 11:16:51 +01:00
parent 46b2ee3bae
commit 2698ef6c5f
No known key found for this signature in database
GPG Key ID: 3D71085D14920359

View File

@ -33,29 +33,23 @@
########
dns_cyon_add() {
_load_credentials
_load_parameters "$@"
_info_header "add"
_login
_domain_env
_add_txt
_cleanup
return 0
_load_credentials \
&& _load_parameters "$@" \
&& _info_header "add" \
&& _login \
&& _domain_env \
&& _add_txt \
&& _logout
}
dns_cyon_rm() {
_load_credentials
_load_parameters "$@"
_info_header "delete"
_login
_domain_env
_delete_txt
_cleanup
return 0
_load_credentials \
&& _load_parameters "$@" \
&& _info_header "delete" \
&& _login \
&& _domain_env \
&& _delete_txt \
&& _logout
}
#########################
@ -65,20 +59,22 @@ dns_cyon_rm() {
_load_credentials() {
# Convert loaded password to/from base64 as needed.
if [ "${cyon_password_b64}" ]; then
cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64)"
cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64 "multiline")"
elif [ "${cyon_password}" ]; then
cyon_password_b64="$(printf "%s" "${cyon_password}" | _base64)"
fi
if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then
# Dummy entries to satify script checker.
cyon_username=""
cyon_password=""
cyon_otp_secret=""
_err ""
_err "You haven't set your cyon.ch login credentials yet."
_err "Please set the required cyon environment variables."
_err ""
exit 1
return 1
fi
# Save the login credentials to the account.conf file.
@ -87,44 +83,52 @@ _load_credentials() {
_saveaccountconf cyon_password_b64 "$cyon_password_b64"
if [ ! -z "${cyon_otp_secret}" ]; then
_saveaccountconf cyon_otp_secret "$cyon_otp_secret"
else
_clearaccountconf cyon_otp_secret
fi
}
_is_idn() {
_idn_temp=$(printf "%s" "$1" | tr -d "[0-9a-zA-Z.,-]")
_idn_temp2="$(printf "%s" "$1" | grep -o "xn--")"
_is_idn_cyon() {
_idn_temp="$(printf "%s" "${1}" | tr -d "[0-9a-zA-Z.,-_]")"
_idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")"
[ "$_idn_temp" ] || [ "$_idn_temp2" ]
}
# comment on https://stackoverflow.com/a/10797966
_urlencode_cyon() {
curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3-
}
_load_parameters() {
# Read the required parameters to add the TXT entry.
fulldomain="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')"
fulldomain="$(printf "%s" "${1}" | tr '[:upper:]' '[:lower:]')"
fulldomain_idn="${fulldomain}"
# Special case for IDNs, as cyon needs a domain environment change,
# which uses the "pretty" instead of the punycode version.
if _is_idn "$1"; then
if _is_idn_cyon "${fulldomain}"; then
if ! _exists idn; then
_fail "Please install idn to process IDN names."
_err "Please install idn to process IDN names."
_err ""
return 1
fi
fulldomain="$(idn -u "${fulldomain}")"
fulldomain_idn="$(idn -a "${fulldomain}")"
fi
_debug fulldomain "$fulldomain"
_debug fulldomain_idn "$fulldomain_idn"
_debug fulldomain "${fulldomain}"
_debug fulldomain_idn "${fulldomain_idn}"
txtvalue="$2"
_debug txtvalue "$txtvalue"
txtvalue="${2}"
_debug txtvalue "${txtvalue}"
# Cookiejar required for login session, as cyon.ch has no official API (yet).
cookiejar=$(tempfile)
_debug cookiejar "$cookiejar"
# This header is required for curl calls.
_H1="X-Requested-With: XMLHttpRequest"
}
_info_header() {
if [ "$1" = "add" ]; then
if [ "${1}" = "add" ]; then
_info ""
_info "+---------------------------------------------+"
_info "| Adding DNS TXT entry to your cyon.ch domain |"
@ -132,42 +136,46 @@ _info_header() {
_info ""
_info " * Full Domain: ${fulldomain}"
_info " * TXT Value: ${txtvalue}"
_info " * Cookie Jar: ${cookiejar}"
_info ""
elif [ "$1" = "delete" ]; then
elif [ "${1}" = "delete" ]; then
_info ""
_info "+-------------------------------------------------+"
_info "| Deleting DNS TXT entry from your cyon.ch domain |"
_info "+-------------------------------------------------+"
_info ""
_info " * Full Domain: ${fulldomain}"
_info " * Cookie Jar: ${cookiejar}"
_info ""
fi
}
_get_cookie_header() {
printf "%s" "$(sed -n 's/Set-\(Cookie:.*cyon=[^;]*\).*/\1/p' "$HTTP_HEADER" | _tail_n 1)"
}
_login() {
_info " - Logging in..."
login_response=$(curl \
"https://my.cyon.ch/auth/index/dologin-async" \
-s \
-c "${cookiejar}" \
-H "X-Requested-With: XMLHttpRequest" \
--data-urlencode "username=${cyon_username}" \
--data-urlencode "password=${cyon_password}" \
--data-urlencode "pathname=/")
username_encoded="$(printf "%s" "${cyon_username}" | _urlencode_cyon)"
password_encoded="$(printf "%s" "${cyon_password}" | _urlencode_cyon)"
login_url="https://my.cyon.ch/auth/index/dologin-async"
login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")"
login_response="$(_post "$login_data" "$login_url")"
_debug login_response "${login_response}"
# Bail if login fails.
if [ "$(printf "%s" "${login_response}" | _get_response_success)" != "success" ]; then
_fail " $(printf "%s" "${login_response}" | _get_response_message)"
_err " $(printf "%s" "${login_response}" | _get_response_message)"
_err ""
return 1
fi
_info " success"
# NECESSARY!! Load the main page after login, before the OTP check.
curl "https://my.cyon.ch/" -s --compressed -b "${cookiejar}" >/dev/null
# NECESSARY!! Load the main page after login, to get the new cookie.
_H2="$(_get_cookie_header)"
_get "https://my.cyon.ch/" > /dev/null
# todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request.
@ -176,26 +184,25 @@ _login() {
_info " - Authorising with OTP code..."
if ! _exists oathtool; then
_fail "Please install oathtool to use 2 Factor Authentication."
_err "Please install oathtool to use 2 Factor Authentication."
_err ""
return 1
fi
# Get OTP code with the defined secret.
otp_code=$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null)
otp_code="$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null)"
otp_response=$(curl \
"https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" \
-s \
--compressed \
-b "${cookiejar}" \
-c "${cookiejar}" \
-H "X-Requested-With: XMLHttpRequest" \
-d "totpcode=${otp_code}&pathname=%2F&rememberme=0")
login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async"
login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0"
_debug otp_response "${otp_response}"
login_otp_response="$(_post "$login_otp_data" "$login_otp_url")"
_debug login_otp_response "${login_otp_response}"
# Bail if OTP authentication fails.
if [ "$(printf "%s" "${otp_response}" | _get_response_success)" != "success" ]; then
_fail " $(printf "%s" "${otp_response}" | _get_response_message)"
if [ "$(printf "%s" "${login_otp_response}" | _get_response_success)" != "success" ]; then
_err " $(printf "%s" "${login_otp_response}" | _get_response_message)"
_err ""
return 1
fi
_info " success"
@ -204,29 +211,36 @@ _login() {
_info ""
}
_logout() {
_info " - Logging out..."
_get "https://my.cyon.ch/auth/index/dologout" > /dev/null
_info " success"
_info ""
}
_domain_env() {
_info " - Changing domain environment..."
# Get the "example.com" part of the full domain name.
domain_env=$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')
domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')"
_debug "Changing domain environment to ${domain_env}"
domain_env_response=$(curl \
"https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" \
-s \
--compressed \
-b "${cookiejar}" \
-H "X-Requested-With: XMLHttpRequest")
domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}"
domain_env_response="$(_get "${domain_env_url}")"
_debug domain_env_response "${domain_env_response}"
_check_2fa_miss "${domain_env_response}"
if ! _check_if_2fa_missed "${domain_env_response}"; then return 1; fi
domain_env_success=$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)
domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)"
# Bail if domain environment change fails.
if [ "${domain_env_success}" != "true" ]; then
_fail " $(printf "%s" "${domain_env_response}" | _get_response_message)"
_err " $(printf "%s" "${domain_env_response}" | _get_response_message)"
_err ""
return 1
fi
_info " success"
@ -235,47 +249,41 @@ _domain_env() {
_add_txt() {
_info " - Adding DNS TXT entry..."
addtxt_response=$(curl \
"https://my.cyon.ch/domain/dnseditor/add-record-async" \
-s \
--compressed \
-b "${cookiejar}" \
-H "X-Requested-With: XMLHttpRequest" \
-d "zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}")
_debug addtxt_response "${addtxt_response}"
add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async"
add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}"
_check_2fa_miss "${addtxt_response}"
add_txt_response="$(_post "$add_txt_data" "$add_txt_url")"
_debug add_txt_response "${add_txt_response}"
addtxt_message=$(printf "%s" "${addtxt_response}" | _get_response_message)
addtxt_status=$(printf "%s" "${addtxt_response}" | _get_response_status)
if ! _check_if_2fa_missed "${add_txt_response}"; then return 1; fi
add_txt_message="$(printf "%s" "${add_txt_response}" | _get_response_message)"
add_txt_status="$(printf "%s" "${add_txt_response}" | _get_response_status)"
# Bail if adding TXT entry fails.
if [ "${addtxt_status}" != "true" ]; then
_fail " ${addtxt_message}"
if [ "${add_txt_status}" != "true" ]; then
_err " ${add_txt_message}"
_err ""
return 1
fi
_info " success"
_info " success (TXT|${fulldomain_idn}.|${txtvalue})"
_info ""
}
_delete_txt() {
_info " - Deleting DNS TXT entry..."
list_txt_response=$(curl \
"https://my.cyon.ch/domain/dnseditor/list-async" \
-s \
-b "${cookiejar}" \
--compressed \
-H "X-Requested-With: XMLHttpRequest" \
| sed -e 's/data-hash/\\ndata-hash/g')
list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async"
list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')"
_debug list_txt_response "${list_txt_response}"
_check_2fa_miss "${list_txt_response}"
if ! _check_if_2fa_missed "${list_txt_response}"; then return 1; fi
# Find and delete all acme challenge entries for the $fulldomain.
_dns_entries=$(printf "%s" "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')
_dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')"
printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do
dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)"
@ -285,21 +293,19 @@ _delete_txt() {
continue
fi
delete_txt_response=$(curl \
"https://my.cyon.ch/domain/dnseditor/delete-record-async" \
-s \
--compressed \
-b "${cookiejar}" \
-H "X-Requested-With: XMLHttpRequest" \
--data-urlencode "hash=${_hash}" \
--data-urlencode "identifier=${_identifier}")
hash_encoded="$(printf "%s" "${_hash}" | _urlencode_cyon)"
identifier_encoded="$(printf "%s" "${_identifier}" | _urlencode_cyon)"
delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async"
delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")"
delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")"
_debug delete_txt_response "${delete_txt_response}"
_check_2fa_miss "${delete_txt_response}"
if ! _check_if_2fa_missed "${delete_txt_response}"; then return 1; fi
delete_txt_message=$(printf "%s" "${delete_txt_response}" | _get_response_message)
delete_txt_status=$(printf "%s" "${delete_txt_response}" | _get_response_status)
delete_txt_message="$(printf "%s" "${delete_txt_response}" | _get_response_message)"
delete_txt_status="$(printf "%s" "${delete_txt_response}" | _get_response_status)"
# Skip if deleting TXT entry fails.
if [ "${delete_txt_status}" != "true" ]; then
@ -325,23 +331,11 @@ _get_response_success() {
_egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"'
}
_check_2fa_miss() {
_check_if_2fa_missed() {
# Did we miss the 2FA?
if test "${1#*multi_factor_form}" != "$1"; then
_fail " Missed OTP authentication!"
if test "${1#*multi_factor_form}" != "${1}"; then
_err " Missed OTP authentication!"
_err ""
return 1
fi
}
_fail() {
_err "$1"
_err ""
_cleanup
exit 1
}
_cleanup() {
_info " - Cleanup."
_debug "Remove cookie jar: ${cookiejar}"
rm "${cookiejar}" 2>/dev/null
_info ""
}