From b481ffb81b7b1d3300c0bff4f939bb821c2d2989 Mon Sep 17 00:00:00 2001 From: Fabian Lesniak Date: Sat, 22 Aug 2026 04:13:58 +0200 Subject: [PATCH] Merge pull request #5194 from flesniak/myloc Add dnsapi script for myloc.de/webtropia.com --- dnsapi/dns_myloc.sh | 121 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100755 dnsapi/dns_myloc.sh diff --git a/dnsapi/dns_myloc.sh b/dnsapi/dns_myloc.sh new file mode 100755 index 00000000..49d800c1 --- /dev/null +++ b/dnsapi/dns_myloc.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_myloc_info='myloc.de +Site: myloc.de +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_myloc +Issues: github.com/acmesh-official/acme.sh/issues/5193 +Options: + MYLOC_token API token +' + +# updater for the (experimental) API of myloc.de / webtropia.com +# usage: acme.sh --issue -d example.com --dns dns_myloc --dnssleep 60 +# API documentation at https://apidoc.myloc.de/ +# As the API does not support quering available zones yet, the zone for a given +# fulldomain is searched recursively by removing prefixes one-by-one. + +_myloc_api="https://zkm.myloc.de/api" + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_myloc_add() { + _myloc_fulldomain=$1 + _myloc_txtvalue=$2 + + _myloc_token="${MYLOC_token:-$(_readaccountconf_mutable MYLOC_token)}" + if [ -z "$_myloc_token" ]; then + _err "You didn't specify MYLOC_token" + return 1 + fi + + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $_myloc_token" + + _myloc_zone="$(_myloc_get_zone "$_myloc_fulldomain")" + if [ $? -ne 0 ]; then + return 1 + fi + + # save token if the previous request was successful + _saveaccountconf_mutable MYLOC_token "$_myloc_token" + + _info "Adding record" + _myloc_record="{\"type\":\"TXT\",\"name\":\"${_myloc_fulldomain}\",\"content\":\"\\\"${_myloc_txtvalue}\\\"\",\"ttl\":60}" + _debug "add record request $_myloc_record to ${_myloc_api}/dns/zone/${_myloc_zone}" + _myloc_response="$(_post "$_myloc_record" "${_myloc_api}/dns/zone/${_myloc_zone}" "" "PUT")" + _myloc_status=$? + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug "add record response $_code $_myloc_response" + if [ $_myloc_status -ne 0 ]; then + _err "Add txt record curl error." + return 1 + elif [ "$_code" = "204" ] && [ -z "$_myloc_response" ]; then + _info "Add txt record success" + return 0 + elif _contains "$_myloc_response" "error" || _contains "$_myloc_response" "unexpected"; then + _err "Add txt record api error." + return 1 + else + _err "Add txt record unknown response." + return 1 + fi +} + +#_myloc_fulldomain _myloc_txtvalue +dns_myloc_rm() { + _myloc_fulldomain=$1 + _myloc_txtvalue=$2 + + _myloc_token="${MYLOC_token:-$(_readaccountconf_mutable MYLOC_token)}" + if [ -z "$_myloc_token" ]; then + _err "You didn't specify MYLOC_token" + return 1 + fi + + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $_myloc_token" + + _myloc_zone="$(_myloc_get_zone "$_myloc_fulldomain")" + if [ $? -ne 0 ]; then + return 1 + fi + + # save token if the previous request was successful + _saveaccountconf_mutable MYLOC_token "$_myloc_token" + + _info "Deleting record for $_myloc_fulldomain" + _myloc_record="{\"type\":\"TXT\",\"name\":\"${_myloc_fulldomain}\",\"content\":\"\\\"${_myloc_txtvalue}\\\"\"}" + _debug "delete record $_myloc_record" + _myloc_response="$(_post "$_myloc_record" "${_myloc_api}/dns/zone/${_myloc_zone}" "" "DELETE")" + _myloc_status=$? + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug "delete response $_code $_myloc_response" + if [ $_myloc_status -ne 0 ] || [ "$_code" != "204" ]; then + _err "Failed to delete record" + return 1 + fi + + return 0 +} + +# Usage: _myloc_get_zone "_acme-challenge.sub1.mydomain.com" +# Subdomains are walked until a zone is found or TLD is reached +_myloc_get_zone() { + _myloc_zone=$1 + + while [ "${_myloc_zone#*.}" != "$_myloc_zone" ]; do + _debug "Get zone trying $_myloc_zone" + _myloc_response="$(_get "${_myloc_api}/dns/zone/${_myloc_zone}")" + _myloc_status=$? + _debug "Get zone response $_myloc_response" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + if [ $_myloc_status -eq 0 ] && [ "$_code" = "200" ]; then + _debug "Get zone success for $_myloc_zone" + echo "${_myloc_zone}" + return 0 + fi + _myloc_zone="${_myloc_zone#*.}" + done + + _err "Get zone failed for all candidates" + return 1 +}