#!/usr/bin/env sh # shellcheck disable=SC2034 dns_inwx_info='INWX.de Site: INWX.de Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_inwx Options: INWX_User Username INWX_Password Password ' # Dependencies: # ------------- # - oathtool (When using 2 Factor Authentication) 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)}" INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}" 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" _saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret" if ! _inwx_login; then 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" _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)}" INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}" 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 if ! _inwx_login; then 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" _debug "Getting txt records" xml_content=$(printf ' nameserver.info domain %s type TXT name %s ' "$_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 '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | _egrep_o '[0-9]+') _info "Deleting record" _inwx_delete_record "$_record_id" fi } #################### Private functions below ################################## _inwx_check_cookie() { INWX_Cookie="${INWX_Cookie:-$(_readaccountconf_mutable INWX_Cookie)}" if [ -z "$INWX_Cookie" ]; then _debug "No cached cookie found" return 1 fi _H1="$INWX_Cookie" export _H1 xml_content=$(printf ' account.info ') response="$(_post "$xml_content" "$INWX_Api" "" "POST")" if _contains "$response" "code1000"; then _debug "Cached cookie still valid" return 0 fi _debug "Cached cookie no longer valid" _H1="" export _H1 INWX_Cookie="" _saveaccountconf_mutable INWX_Cookie "$INWX_Cookie" return 1 } _htmlEscape() { _s="$1" _s=$(echo "$_s" | sed "s/&/&/g") _s=$(echo "$_s" | sed "s//\>/g") _s=$(echo "$_s" | sed 's/"/\"/g') printf -- %s "$_s" } _inwx_login() { if _inwx_check_cookie; then _debug "Already logged in" return 0 fi XML_PASS=$(_htmlEscape "$INWX_Password") xml_content=$(printf ' account.login user %s pass %s ' "$INWX_User" "$XML_PASS") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep -i "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')") _H1=$INWX_Cookie export _H1 export INWX_Cookie _saveaccountconf_mutable INWX_Cookie "$INWX_Cookie" if ! _contains "$response" "code1000"; then _err "INWX API: Authentication error (username/password correct?)" return 1 fi #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71 if _contains "$response" "tfaGOOGLE-AUTH"; then if [ -z "$INWX_Shared_Secret" ]; then _err "INWX API: Mobile TAN detected." _err "Please define a shared secret." return 1 fi if ! _exists oathtool; then _err "Please install oathtool to use 2 Factor Authentication." _err "" return 1 fi tan="$(oathtool --base32 --totp "${INWX_Shared_Secret}" 2>/dev/null)" xml_content=$(printf ' account.unlock tan %s ' "$tan") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" if ! _contains "$response" "code1000"; then _err "INWX API: Mobile TAN not correct." return 1 fi fi } _get_root() { domain=$1 _debug "get root" domain=$1 i=2 p=1 xml_content=' nameserver.list pagelimit 9999 ' 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 ' nameserver.deleteRecord id %s ' "$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 ' nameserver.updateRecord content %s id %s ' "$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 ' nameserver.createRecord domain %s type TXT content %s name %s ' "$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 }