282 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			282 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
#!/usr/bin/env sh
 | 
						|
# shellcheck disable=SC2034
 | 
						|
dns_beget_info='Beget.com
 | 
						|
Site: Beget.com
 | 
						|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_beget
 | 
						|
Options:
 | 
						|
 BEGET_User API user
 | 
						|
 BEGET_Password API password
 | 
						|
Issues: github.com/acmesh-official/acme.sh/issues/6200
 | 
						|
Author: ARNik <arnik@arnik.ru>
 | 
						|
'
 | 
						|
 | 
						|
Beget_Api="https://api.beget.com/api"
 | 
						|
 | 
						|
####################  Public functions ####################
 | 
						|
 | 
						|
# Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
						|
# Used to add txt record
 | 
						|
dns_beget_add() {
 | 
						|
  fulldomain=$1
 | 
						|
  txtvalue=$2
 | 
						|
  _debug "dns_beget_add() $fulldomain $txtvalue"
 | 
						|
  fulldomain=$(echo "$fulldomain" | _lower_case)
 | 
						|
 | 
						|
  Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
 | 
						|
  Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
 | 
						|
 | 
						|
  if [ -z "$Beget_Username" ] || [ -z "$Beget_Password" ]; then
 | 
						|
    Beget_Username=""
 | 
						|
    Beget_Password=""
 | 
						|
    _err "You must export variables: Beget_Username, and Beget_Password"
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  #save the credentials to the account conf file.
 | 
						|
  _saveaccountconf_mutable Beget_Username "$Beget_Username"
 | 
						|
  _saveaccountconf_mutable Beget_Password "$Beget_Password"
 | 
						|
 | 
						|
  _info "Prepare subdomain."
 | 
						|
  if ! _prepare_subdomain "$fulldomain"; then
 | 
						|
    _err "Can't prepare subdomain."
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  _info "Get domain records"
 | 
						|
  data="{\"fqdn\":\"$fulldomain\"}"
 | 
						|
  res=$(_api_call "$Beget_Api/dns/getData" "$data")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _err "Can't get domain records."
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  _info "Add new TXT record"
 | 
						|
  data="{\"fqdn\":\"$fulldomain\",\"records\":{"
 | 
						|
  data=${data}$(_parce_records "$res" "A")
 | 
						|
  data=${data}$(_parce_records "$res" "AAAA")
 | 
						|
  data=${data}$(_parce_records "$res" "CAA")
 | 
						|
  data=${data}$(_parce_records "$res" "MX")
 | 
						|
  data=${data}$(_parce_records "$res" "SRV")
 | 
						|
  data=${data}$(_parce_records "$res" "TXT")
 | 
						|
  data=$(echo "$data" | sed 's/,$//')
 | 
						|
  data=${data}'}}'
 | 
						|
 | 
						|
  str=$(_txt_to_dns_json "$txtvalue")
 | 
						|
  data=$(_add_record "$data" "TXT" "$str")
 | 
						|
 | 
						|
  res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _err "Can't change domain records."
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  return 0
 | 
						|
}
 | 
						|
 | 
						|
# Usage: fulldomain txtvalue
 | 
						|
# Used to remove the txt record after validation
 | 
						|
dns_beget_rm() {
 | 
						|
  fulldomain=$1
 | 
						|
  txtvalue=$2
 | 
						|
  _debug "dns_beget_rm() $fulldomain $txtvalue"
 | 
						|
  fulldomain=$(echo "$fulldomain" | _lower_case)
 | 
						|
 | 
						|
  Beget_Username="${Beget_Username:-$(_readaccountconf_mutable Beget_Username)}"
 | 
						|
  Beget_Password="${Beget_Password:-$(_readaccountconf_mutable Beget_Password)}"
 | 
						|
 | 
						|
  _info "Get current domain records"
 | 
						|
  data="{\"fqdn\":\"$fulldomain\"}"
 | 
						|
  res=$(_api_call "$Beget_Api/dns/getData" "$data")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _err "Can't get domain records."
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  _info "Remove TXT record"
 | 
						|
  data="{\"fqdn\":\"$fulldomain\",\"records\":{"
 | 
						|
  data=${data}$(_parce_records "$res" "A")
 | 
						|
  data=${data}$(_parce_records "$res" "AAAA")
 | 
						|
  data=${data}$(_parce_records "$res" "CAA")
 | 
						|
  data=${data}$(_parce_records "$res" "MX")
 | 
						|
  data=${data}$(_parce_records "$res" "SRV")
 | 
						|
  data=${data}$(_parce_records "$res" "TXT")
 | 
						|
  data=$(echo "$data" | sed 's/,$//')
 | 
						|
  data=${data}'}}'
 | 
						|
 | 
						|
  str=$(_txt_to_dns_json "$txtvalue")
 | 
						|
  data=$(_rm_record "$data" "$str")
 | 
						|
 | 
						|
  res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _err "Can't change domain records."
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  return 0
 | 
						|
}
 | 
						|
 | 
						|
####################  Private functions below ####################
 | 
						|
 | 
						|
# Create subdomain if needed
 | 
						|
# Usage: _prepare_subdomain [fulldomain]
 | 
						|
_prepare_subdomain() {
 | 
						|
  fulldomain=$1
 | 
						|
 | 
						|
  _info "Detect the root zone"
 | 
						|
  if ! _get_root "$fulldomain"; then
 | 
						|
    _err "invalid domain"
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
  _debug _domain_id "$_domain_id"
 | 
						|
  _debug _sub_domain "$_sub_domain"
 | 
						|
  _debug _domain "$_domain"
 | 
						|
 | 
						|
  if [ -z "$_sub_domain" ]; then
 | 
						|
    _debug "$fulldomain is a root domain."
 | 
						|
    return 0
 | 
						|
  fi
 | 
						|
 | 
						|
  _info "Get subdomain list"
 | 
						|
  res=$(_api_call "$Beget_Api/domain/getSubdomainList")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _err "Can't get subdomain list."
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  if _contains "$res" "\"fqdn\":\"$fulldomain\""; then
 | 
						|
    _debug "Subdomain $fulldomain already exist."
 | 
						|
    return 0
 | 
						|
  fi
 | 
						|
 | 
						|
  _info "Subdomain $fulldomain does not exist. Let's create one."
 | 
						|
  data="{\"subdomain\":\"$_sub_domain\",\"domain_id\":$_domain_id}"
 | 
						|
  res=$(_api_call "$Beget_Api/domain/addSubdomainVirtual" "$data")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _err "Can't create subdomain."
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  _debug "Cleanup subdomen records"
 | 
						|
  data="{\"fqdn\":\"$fulldomain\",\"records\":{}}"
 | 
						|
  res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _debug "Can't cleanup $fulldomain records."
 | 
						|
  fi
 | 
						|
 | 
						|
  data="{\"fqdn\":\"www.$fulldomain\",\"records\":{}}"
 | 
						|
  res=$(_api_call "$Beget_Api/dns/changeRecords" "$data")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _debug "Can't cleanup www.$fulldomain records."
 | 
						|
  fi
 | 
						|
 | 
						|
  return 0
 | 
						|
}
 | 
						|
 | 
						|
# Usage: _get_root _acme-challenge.www.domain.com
 | 
						|
#returns
 | 
						|
# _sub_domain=_acme-challenge.www
 | 
						|
# _domain=domain.com
 | 
						|
# _domain_id=32436365
 | 
						|
_get_root() {
 | 
						|
  fulldomain=$1
 | 
						|
  i=1
 | 
						|
  p=1
 | 
						|
 | 
						|
  _debug "Get domain list"
 | 
						|
  res=$(_api_call "$Beget_Api/domain/getList")
 | 
						|
  if ! _is_api_reply_ok "$res"; then
 | 
						|
    _err "Can't get domain list."
 | 
						|
    return 1
 | 
						|
  fi
 | 
						|
 | 
						|
  while true; do
 | 
						|
    h=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-100)
 | 
						|
    _debug h "$h"
 | 
						|
 | 
						|
    if [ -z "$h" ]; then
 | 
						|
      return 1
 | 
						|
    fi
 | 
						|
 | 
						|
    if _contains "$res" "$h"; then
 | 
						|
      _domain_id=$(echo "$res" | _egrep_o "\"id\":[0-9]*,\"fqdn\":\"$h\"" | cut -d , -f1 | cut -d : -f2)
 | 
						|
      if [ "$_domain_id" ]; then
 | 
						|
        if [ "$h" != "$fulldomain" ]; then
 | 
						|
          _sub_domain=$(echo "$fulldomain" | cut -d . -f 1-"$p")
 | 
						|
        else
 | 
						|
          _sub_domain=""
 | 
						|
        fi
 | 
						|
        _domain=$h
 | 
						|
        return 0
 | 
						|
      fi
 | 
						|
      return 1
 | 
						|
    fi
 | 
						|
    p="$i"
 | 
						|
    i=$(_math "$i" + 1)
 | 
						|
  done
 | 
						|
  return 1
 | 
						|
}
 | 
						|
 | 
						|
# Parce DNS records from json string
 | 
						|
# Usage: _parce_records [j_str] [record_name]
 | 
						|
_parce_records() {
 | 
						|
  j_str=$1
 | 
						|
  record_name=$2
 | 
						|
  res="\"$record_name\":["
 | 
						|
  res=${res}$(echo "$j_str" | _egrep_o "\"$record_name\":\[.*" | cut -d '[' -f2 | cut -d ']' -f1)
 | 
						|
  res=${res}"],"
 | 
						|
  echo "$res"
 | 
						|
}
 | 
						|
 | 
						|
# Usage: _add_record [data] [record_name] [record_data]
 | 
						|
_add_record() {
 | 
						|
  data=$1
 | 
						|
  record_name=$2
 | 
						|
  record_data=$3
 | 
						|
  echo "$data" | sed "s/\"$record_name\":\[/\"$record_name\":\[$record_data,/" | sed "s/,\]/\]/"
 | 
						|
}
 | 
						|
 | 
						|
# Usage: _rm_record [data] [record_data]
 | 
						|
_rm_record() {
 | 
						|
  data=$1
 | 
						|
  record_data=$2
 | 
						|
  echo "$data" | sed "s/$record_data//g" | sed "s/,\+/,/g" |
 | 
						|
    sed "s/{,/{/g" | sed "s/,}/}/g" |
 | 
						|
    sed "s/\[,/\[/g" | sed "s/,\]/\]/g"
 | 
						|
}
 | 
						|
 | 
						|
_txt_to_dns_json() {
 | 
						|
  echo "{\"ttl\":600,\"txtdata\":\"$1\"}"
 | 
						|
}
 | 
						|
 | 
						|
# Usage: _api_call [api_url] [input_data]
 | 
						|
_api_call() {
 | 
						|
  api_url="$1"
 | 
						|
  input_data="$2"
 | 
						|
 | 
						|
  _debug "_api_call $api_url"
 | 
						|
  _debug "Request: $input_data"
 | 
						|
 | 
						|
  # res=$(curl -s -L -D ./http.header \
 | 
						|
  # "$api_url" \
 | 
						|
  # --data-urlencode login=$Beget_Username \
 | 
						|
  # --data-urlencode passwd=$Beget_Password \
 | 
						|
  # --data-urlencode input_format=json \
 | 
						|
  # --data-urlencode output_format=json \
 | 
						|
  # --data-urlencode "input_data=$input_data")
 | 
						|
 | 
						|
  url="$api_url?login=$Beget_Username&passwd=$Beget_Password&input_format=json&output_format=json"
 | 
						|
  if [ -n "$input_data" ]; then
 | 
						|
    url=${url}"&input_data="
 | 
						|
    url=${url}$(echo "$input_data" | _url_encode)
 | 
						|
  fi
 | 
						|
  res=$(_get "$url")
 | 
						|
 | 
						|
  _debug "Reply: $res"
 | 
						|
  echo "$res"
 | 
						|
}
 | 
						|
 | 
						|
# Usage: _is_api_reply_ok [api_reply]
 | 
						|
_is_api_reply_ok() {
 | 
						|
  _contains "$1" '^{"status":"success","answer":{"status":"success","result":.*}}$'
 | 
						|
}
 |