From 7bd6d32b914d1e85754484fa87b9dc227183d11b Mon Sep 17 00:00:00 2001 From: hexim Date: Fri, 13 Mar 2026 14:41:33 +0100 Subject: [PATCH] Add BEST-HOSTING DNS API --- dnsapi/dns_bh.sh | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100755 dnsapi/dns_bh.sh diff --git a/dnsapi/dns_bh.sh b/dnsapi/dns_bh.sh new file mode 100755 index 00000000..563564bd --- /dev/null +++ b/dnsapi/dns_bh.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_bh_info='Best-Hosting.cz +Site: best-hosting.cz +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bh +Options: + BH_API_USER API User identifier. + BH_API_KEY API Secret key. +Issues: github.com/acmesh-official/acme.sh/issues/6854 +Author: @heximcz +' + +BH_Api="https://best-hosting.cz/api/v1" + +######## Public functions ##################### + +# Usage: dns_bh_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_bh_add() { + fulldomain=$1 + txtvalue=$2 + + # --- 1. Credentials --- + BH_API_USER="${BH_API_USER:-$(_readaccountconf_mutable BH_API_USER)}" + BH_API_KEY="${BH_API_KEY:-$(_readaccountconf_mutable BH_API_KEY)}" + + if [ -z "$BH_API_USER" ] || [ -z "$BH_API_KEY" ]; then + BH_API_USER="" + BH_API_KEY="" + _err "You must specify BH_API_USER and BH_API_KEY." + return 1 + fi + + _saveaccountconf_mutable BH_API_USER "$BH_API_USER" + _saveaccountconf_mutable BH_API_KEY "$BH_API_KEY" + + # --- 2. Add TXT record --- + _info "Adding TXT record for $fulldomain" + + if ! _bh_rest POST "dns" "{\"fulldomain\":\"$fulldomain\",\"txtvalue\":\"$txtvalue\"}"; then + _err "Failed to add DNS record." + return 1 + fi + + record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[0-9]+" | cut -d':' -f2) + _debug record_id "$record_id" + + if [ -z "$record_id" ]; then + _err "Could not parse record ID from response." + return 1 + fi + + # Sanitize key — replace dots and hyphens with underscores + _conf_key=$(printf "%s" "BH_record_ids_${fulldomain}" | tr '.-' '_') + + # Wildcard support: store space-separated list of IDs + # First call stores "111", second call stores "111 222" + _existing_ids=$(_readdomainconf "$_conf_key") + if [ -z "$_existing_ids" ]; then + _savedomainconf "$_conf_key" "$record_id" + else + _savedomainconf "$_conf_key" "$_existing_ids $record_id" + fi + + _info "DNS TXT record added successfully." + return 0 +} + +# Usage: dns_bh_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_bh_rm() { + fulldomain=$1 + txtvalue=$2 + + # --- 1. Credentials --- + BH_API_USER="${BH_API_USER:-$(_readaccountconf_mutable BH_API_USER)}" + BH_API_KEY="${BH_API_KEY:-$(_readaccountconf_mutable BH_API_KEY)}" + + if [ -z "$BH_API_USER" ] || [ -z "$BH_API_KEY" ]; then + BH_API_USER="" + BH_API_KEY="" + _err "You must specify BH_API_USER and BH_API_KEY." + return 1 + fi + + # Sanitize key — same as in add + _conf_key=$(printf "%s" "BH_record_ids_${fulldomain}" | tr '.-' '_') + + # --- 2. Load stored record ID --- + _existing_ids=$(_readdomainconf "$_conf_key") + _debug _existing_ids "$_existing_ids" + + if [ -z "$_existing_ids" ]; then + _err "Could not find record ID for $fulldomain." + return 1 + fi + + # Take the first ID from the list + record_id=$(printf "%s" "$_existing_ids" | cut -d' ' -f1) + # Remaining IDs for wildcard support + _remaining_ids=$(printf "%s" "$_existing_ids" | cut -d' ' -f2-) + _debug record_id "$record_id" + + # --- 3. Delete record --- + _info "Removing TXT record for $fulldomain" + + if ! _bh_rest DELETE "dns/$record_id"; then + _err "Failed to remove DNS record." + return 1 + fi + + # Update stored list — remove used ID + if [ -z "$_remaining_ids" ] || [ "$_remaining_ids" = "$record_id" ]; then + _savedomainconf "$_conf_key" "" + else + _savedomainconf "$_conf_key" "$_remaining_ids" + fi + + _info "DNS TXT record removed successfully." + return 0 +} + +#################### Private functions ##################### + +_bh_rest() { + m=$1 + ep=$2 + data=$3 + _debug "$ep" + + _credentials="$(printf "%s:%s" "$BH_API_USER" "$BH_API_KEY" | _base64)" + + export _H1="Authorization: Basic $_credentials" + export _H2="Content-Type: application/json" + export _H3="Accept: application/json" + + if [ "$m" = "GET" ]; then + response="$(_get "$BH_Api/$ep")" + else + response="$(_post "$data" "$BH_Api/$ep" "" "$m")" + fi + + if [ "$?" != "0" ]; then + _err "Error calling $m $BH_Api/$ep" + return 1 + fi + + _debug2 response "$response" + return 0 +}