#!/usr/bin/env sh # shellcheck disable=SC2034 dns_joker_info='Joker.com Site: Joker.com Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_joker Options: JOKER_USERNAME Username JOKER_PASSWORD Password Issues: github.com/acmesh-official/acme.sh/issues/2840 Author: @aattww ' JOKER_API="https://svc.joker.com/nic/replace" ######## Public functions ##################### #Usage: dns_joker_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_joker_add() { fulldomain=$1 txtvalue=$2 JOKER_USERNAME="${JOKER_USERNAME:-$(_readaccountconf_mutable JOKER_USERNAME)}" JOKER_PASSWORD="${JOKER_PASSWORD:-$(_readaccountconf_mutable JOKER_PASSWORD)}" if [ -z "$JOKER_USERNAME" ] || [ -z "$JOKER_PASSWORD" ]; then _err "No Joker.com username and password specified." return 1 fi _saveaccountconf_mutable JOKER_USERNAME "$JOKER_USERNAME" _saveaccountconf_mutable JOKER_PASSWORD "$JOKER_PASSWORD" if ! _get_root "$fulldomain"; then _err "Invalid domain" return 1 fi # Joker's /nic/replace overwrites all TXT records at the label on every call, # and the API is not readable, so accumulate the values locally (keyed by the # full record name) and re-send the whole set each time. This is required so a # wildcard cert (base + *.domain both validating under the same # _acme-challenge label) does not overwrite its own first challenge value. _joker_conf_key=$(printf "%s" "JOKER_TXT_${fulldomain}" | tr '.-' '_') _joker_values=$(_readdomainconf "$_joker_conf_key") if [ -z "$_joker_values" ]; then _joker_values="$txtvalue" elif ! _contains " $_joker_values " " $txtvalue "; then _joker_values="$_joker_values $txtvalue" fi _joker_value_params="" for _joker_v in $_joker_values; do _joker_value_params="$_joker_value_params&value=$_joker_v" done _info "Adding TXT record" if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$_domain&label=$_sub_domain&type=TXT$_joker_value_params"; then if _startswith "$response" "OK"; then _savedomainconf "$_joker_conf_key" "$_joker_values" _info "Added, OK" return 0 fi fi _err "Error adding TXT record." return 1 } #fulldomain txtvalue dns_joker_rm() { fulldomain=$1 txtvalue=$2 JOKER_USERNAME="${JOKER_USERNAME:-$(_readaccountconf_mutable JOKER_USERNAME)}" JOKER_PASSWORD="${JOKER_PASSWORD:-$(_readaccountconf_mutable JOKER_PASSWORD)}" if ! _get_root "$fulldomain"; then _err "Invalid domain" return 1 fi # Remove only this value from the accumulated set and replace the label with # whatever remains (an empty value clears the label's TXT records entirely). _joker_conf_key=$(printf "%s" "JOKER_TXT_${fulldomain}" | tr '.-' '_') _joker_values=$(_readdomainconf "$_joker_conf_key") _joker_remaining="" for _joker_v in $_joker_values; do if [ "$_joker_v" != "$txtvalue" ]; then _joker_remaining="$_joker_remaining $_joker_v" fi done _joker_remaining=$(printf "%s" "$_joker_remaining" | sed 's/^ *//') _joker_value_params="" for _joker_v in $_joker_remaining; do _joker_value_params="$_joker_value_params&value=$_joker_v" done if [ -z "$_joker_value_params" ]; then _joker_value_params="&value=" fi _info "Removing TXT record" # TXT record is removed by replacing the label with the remaining values # (or an empty value, which clears all TXT records at the label). if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$_domain&label=$_sub_domain&type=TXT$_joker_value_params"; then if _startswith "$response" "OK"; then if [ -z "$_joker_remaining" ]; then _cleardomainconf "$_joker_conf_key" else _savedomainconf "$_joker_conf_key" "$_joker_remaining" fi _info "Removed, OK" return 0 fi fi _err "Error removing TXT record." return 1 } #################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www # _domain=domain.com _get_root() { fulldomain=$1 i=1 while true; do h=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100) _debug h "$h" if [ -z "$h" ]; then return 1 fi # Try to remove a test record. With correct root domain, username and password this will return "OK: ..." regardless # of record in question existing or not. if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$h&label=jokerTXTUpdateTest&type=TXT&value="; then if _startswith "$response" "OK"; then _sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")" _domain=$h return 0 fi fi i=$(_math "$i" + 1) done _debug "Root domain not found" return 1 } _joker_rest() { data="$1" _debug data "$data" if ! response="$(_post "$data" "$JOKER_API" "" "POST")"; then _err "Error POSTing" return 1 fi _debug response "$response" return 0 }