mirror of
				https://github.com/acmesh-official/acme.sh
				synced 2025-11-04 13:55:56 +08:00 
			
		
		
		
	
							
								
								
									
										22
									
								
								acme.sh
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								acme.sh
									
									
									
									
									
								
							@@ -2118,12 +2118,7 @@ _tail_n() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_tail_c() {
 | 
			
		||||
  if _is_solaris; then
 | 
			
		||||
    #fix for solaris
 | 
			
		||||
    tail -"$1"c
 | 
			
		||||
  else
 | 
			
		||||
    tail -c "$1"
 | 
			
		||||
  fi
 | 
			
		||||
  tail -c "$1" 2>/dev/null || tail -"$1"c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# url  payload needbase64  keyfile
 | 
			
		||||
@@ -5993,6 +5988,7 @@ installcronjob() {
 | 
			
		||||
  fi
 | 
			
		||||
  _t=$(_time)
 | 
			
		||||
  random_minute=$(_math $_t % 60)
 | 
			
		||||
  random_hour=$(_math $_t / 60 % 24)
 | 
			
		||||
 | 
			
		||||
  if ! _exists "$_CRONTAB" && _exists "fcrontab"; then
 | 
			
		||||
    _CRONTAB="fcrontab"
 | 
			
		||||
@@ -6017,16 +6013,14 @@ installcronjob() {
 | 
			
		||||
  _info "Installing cron job"
 | 
			
		||||
  if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then
 | 
			
		||||
    if _exists uname && uname -a | grep SunOS >/dev/null; then
 | 
			
		||||
      $_CRONTAB -l | {
 | 
			
		||||
        cat
 | 
			
		||||
        echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
 | 
			
		||||
      } | $_CRONTAB --
 | 
			
		||||
      _CRONTAB_STDIN="$_CRONTAB --"
 | 
			
		||||
    else
 | 
			
		||||
      $_CRONTAB -l | {
 | 
			
		||||
        cat
 | 
			
		||||
        echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
 | 
			
		||||
      } | $_CRONTAB -
 | 
			
		||||
      _CRONTAB_STDIN="$_CRONTAB -"
 | 
			
		||||
    fi
 | 
			
		||||
    $_CRONTAB -l | {
 | 
			
		||||
      cat
 | 
			
		||||
      echo "$random_minute $random_hour * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
 | 
			
		||||
    } | $_CRONTAB_STDIN
 | 
			
		||||
  fi
 | 
			
		||||
  if [ "$?" != "0" ]; then
 | 
			
		||||
    _err "Install cron job failed. You need to manually renew your certs."
 | 
			
		||||
 
 | 
			
		||||
@@ -91,8 +91,10 @@ synology_dsm_deploy() {
 | 
			
		||||
 | 
			
		||||
  _debug "Getting API version"
 | 
			
		||||
  response=$(_get "$_base_url/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth")
 | 
			
		||||
  api_path=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"path" *: *"\([0-9]*\)".*/\1/p')
 | 
			
		||||
  api_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p')
 | 
			
		||||
  _debug3 response "$response"
 | 
			
		||||
  _debug3 api_path "$api_path"
 | 
			
		||||
  _debug3 api_version "$api_version"
 | 
			
		||||
 | 
			
		||||
  # Login, get the session ID & SynoToken from JSON
 | 
			
		||||
@@ -133,12 +135,15 @@ synology_dsm_deploy() {
 | 
			
		||||
      [ -n "${SYNO_Device_Name}" ] || SYNO_Device_Name="CertRenewal"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&otp_code=$otp_code&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_Device_Name")
 | 
			
		||||
    _debug3 response "$response"
 | 
			
		||||
    SYNO_Device_ID=$(echo "$response" | grep "device_id" | sed -n 's/.*"device_id" *: *"\([^"]*\).*/\1/p')
 | 
			
		||||
    response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&otp_code=$otp_code&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_Device_Name")
 | 
			
		||||
    _secure_debug3 response "$response"
 | 
			
		||||
 | 
			
		||||
    id_property='device_id'
 | 
			
		||||
    [ "${api_version}" -gt '6' ] || id_property='did'
 | 
			
		||||
    SYNO_Device_ID=$(echo "$response" | grep "$id_property" | sed -n 's/.*"'$id_property'" *: *"\([^"]*\).*/\1/p')
 | 
			
		||||
    _secure_debug2 SYNO_Device_ID "$SYNO_Device_ID"
 | 
			
		||||
  else
 | 
			
		||||
    response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_Device_Name&device_id=$SYNO_Device_ID")
 | 
			
		||||
    response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_Device_Name&device_id=$SYNO_Device_ID")
 | 
			
		||||
    _debug3 response "$response"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -117,7 +117,7 @@ _ali_urlencode() {
 | 
			
		||||
_ali_nonce() {
 | 
			
		||||
  #_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
 | 
			
		||||
  #Not so good...
 | 
			
		||||
  date +"%s%N"
 | 
			
		||||
  date +"%s%N" | sed 's/%N//g'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_check_exist_query() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										180
									
								
								dnsapi/dns_artfiles.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								dnsapi/dns_artfiles.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,180 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
# ACME.sh 3rd party DNS API plugin for ArtFiles.de
 | 
			
		||||
################################################################################
 | 
			
		||||
# Author:   Martin Arndt, https://troublezone.net/
 | 
			
		||||
# Released: 2022-02-27
 | 
			
		||||
# Issues:   https://github.com/acmesh-official/acme.sh/issues/4718
 | 
			
		||||
################################################################################
 | 
			
		||||
# Usage:
 | 
			
		||||
# 1. export AF_API_USERNAME='api12345678'
 | 
			
		||||
# 2. export AF_API_PASSWORD='apiPassword'
 | 
			
		||||
# 3. acme.sh --issue -d example.com --dns dns_artfiles
 | 
			
		||||
################################################################################
 | 
			
		||||
 | 
			
		||||
########## API configuration ###################################################
 | 
			
		||||
 | 
			
		||||
AF_API_SUCCESS='status":"OK'
 | 
			
		||||
AF_URL_DCP='https://dcp.c.artfiles.de/api/'
 | 
			
		||||
AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain='
 | 
			
		||||
AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html'
 | 
			
		||||
 | 
			
		||||
########## Public functions ####################################################
 | 
			
		||||
 | 
			
		||||
# Adds a new TXT record for given ACME challenge value & domain.
 | 
			
		||||
# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value"
 | 
			
		||||
dns_artfiles_add() {
 | 
			
		||||
  domain="$1"
 | 
			
		||||
  txtValue="$2"
 | 
			
		||||
  _info 'Using ArtFiles.de DNS addition API…'
 | 
			
		||||
  _debug 'Domain' "$domain"
 | 
			
		||||
  _debug 'txtValue' "$txtValue"
 | 
			
		||||
 | 
			
		||||
  _set_credentials
 | 
			
		||||
  _saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME"
 | 
			
		||||
  _saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD"
 | 
			
		||||
 | 
			
		||||
  _set_headers
 | 
			
		||||
  _get_zone "$domain"
 | 
			
		||||
  _dns 'GET'
 | 
			
		||||
  if ! _contains "$response" 'TXT'; then
 | 
			
		||||
    _err 'Retrieving TXT records failed.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _clean_records
 | 
			
		||||
  _dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")"
 | 
			
		||||
  if ! _contains "$response" "$AF_API_SUCCESS"; then
 | 
			
		||||
    _err 'Adding ACME challenge value failed.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Removes the existing TXT record for given ACME challenge value & domain.
 | 
			
		||||
# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value"
 | 
			
		||||
dns_artfiles_rm() {
 | 
			
		||||
  domain="$1"
 | 
			
		||||
  txtValue="$2"
 | 
			
		||||
  _info 'Using ArtFiles.de DNS removal API…'
 | 
			
		||||
  _debug 'Domain' "$domain"
 | 
			
		||||
  _debug 'txtValue' "$txtValue"
 | 
			
		||||
 | 
			
		||||
  _set_credentials
 | 
			
		||||
  _set_headers
 | 
			
		||||
  _get_zone "$domain"
 | 
			
		||||
  if ! _dns 'GET'; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "$txtValue"; then
 | 
			
		||||
    _err 'Retrieved TXT records are missing given ACME challenge value.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _clean_records
 | 
			
		||||
  response="$(printf -- '%s' "$response" | sed '/_acme-challenge "'"$txtValue"'"/d')"
 | 
			
		||||
  _dns 'SET' "$response"
 | 
			
		||||
  if ! _contains "$response" "$AF_API_SUCCESS"; then
 | 
			
		||||
    _err 'Removing ACME challenge value failed.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
########## Private functions ###################################################
 | 
			
		||||
 | 
			
		||||
# Cleans awful TXT records response of ArtFiles's API & pretty prints it.
 | 
			
		||||
# Usage: _clean_records
 | 
			
		||||
_clean_records() {
 | 
			
		||||
  _info 'Cleaning TXT records…'
 | 
			
		||||
  # Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid
 | 
			
		||||
  # usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\'
 | 
			
		||||
  # from '\"' & turn '\n' into real LF characters.
 | 
			
		||||
  # Yup, awful API to use - but that's all we got to get this working, so… ;)
 | 
			
		||||
  _debug2 'Raw  ' "$response"
 | 
			
		||||
  response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')"
 | 
			
		||||
  _debug2 'Clean' "$response"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Executes an HTTP GET or POST request for getting or setting DNS records,
 | 
			
		||||
# containing given payload upon POST.
 | 
			
		||||
# Usage: _dns [GET | SET] [payload]
 | 
			
		||||
_dns() {
 | 
			
		||||
  _info 'Executing HTTP request…'
 | 
			
		||||
  action="$1"
 | 
			
		||||
  payload="$(printf -- '%s' "$2" | _url_encode)"
 | 
			
		||||
  url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')"
 | 
			
		||||
 | 
			
		||||
  if [ "$action" = 'SET' ]; then
 | 
			
		||||
    _debug2 'Payload' "$payload"
 | 
			
		||||
    response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')"
 | 
			
		||||
  else
 | 
			
		||||
    response="$(_get "$url" '' 10)"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! _contains "$response" "$AF_API_SUCCESS"; then
 | 
			
		||||
    _err "DNS API error: $response"
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug 'Response' "$response"
 | 
			
		||||
 | 
			
		||||
  return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Gets the root domain zone for given domain.
 | 
			
		||||
# Usage: _get_zone _acme-challenge.www.example.com
 | 
			
		||||
_get_zone() {
 | 
			
		||||
  fqdn="$1"
 | 
			
		||||
  domains="$(_get "$AF_URL_DOMAINS" '' 10)"
 | 
			
		||||
  _info 'Getting domain zone…'
 | 
			
		||||
  _debug2 'FQDN' "$fqdn"
 | 
			
		||||
  _debug2 'Domains' "$domains"
 | 
			
		||||
 | 
			
		||||
  while _contains "$fqdn" "."; do
 | 
			
		||||
    if _contains "$domains" "$fqdn"; then
 | 
			
		||||
      domain="$fqdn"
 | 
			
		||||
      _info "Found root domain zone: $domain"
 | 
			
		||||
      break
 | 
			
		||||
    else
 | 
			
		||||
      fqdn="${fqdn#*.}"
 | 
			
		||||
      _debug2 'FQDN' "$fqdn"
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  if [ "$domain" = "$fqdn" ]; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _err 'Couldn'\''t find root domain zone.'
 | 
			
		||||
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Sets the credentials for accessing ArtFiles's API
 | 
			
		||||
# Usage: _set_credentials
 | 
			
		||||
_set_credentials() {
 | 
			
		||||
  _info 'Setting credentials…'
 | 
			
		||||
  AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}"
 | 
			
		||||
  AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}"
 | 
			
		||||
  if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then
 | 
			
		||||
    _err 'Missing ArtFiles.de username and/or password.'
 | 
			
		||||
    _err 'Please ensure both are set via export command & try again.'
 | 
			
		||||
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Adds the HTTP Authorization & Content-Type headers to a follow-up request.
 | 
			
		||||
# Usage: _set_headers
 | 
			
		||||
_set_headers() {
 | 
			
		||||
  _info 'Setting headers…'
 | 
			
		||||
  encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)"
 | 
			
		||||
  export _H1="Authorization: Basic $encoded"
 | 
			
		||||
  export _H2='Content-Type: application/json'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
# Gandi LiveDNS v5 API
 | 
			
		||||
# https://doc.livedns.gandi.net/
 | 
			
		||||
# https://api.gandi.net/docs/livedns/
 | 
			
		||||
# https://api.gandi.net/docs/authentication/ for token + apikey (deprecated) authentication
 | 
			
		||||
# currently under beta
 | 
			
		||||
#
 | 
			
		||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
 | 
			
		||||
@@ -19,13 +20,20 @@ dns_gandi_livedns_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  if [ -z "$GANDI_LIVEDNS_KEY" ]; then
 | 
			
		||||
    _err "No API key specified for Gandi LiveDNS."
 | 
			
		||||
    _err "Create your key and export it as GANDI_LIVEDNS_KEY"
 | 
			
		||||
  if [ -z "$GANDI_LIVEDNS_KEY" ] && [ -z "$GANDI_LIVEDNS_TOKEN" ]; then
 | 
			
		||||
    _err "No Token or API key (deprecated) specified for Gandi LiveDNS."
 | 
			
		||||
    _err "Create your token or key and export it as GANDI_LIVEDNS_KEY or GANDI_LIVEDNS_TOKEN respectively"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
 | 
			
		||||
  # Keep only one secret in configuration
 | 
			
		||||
  if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
 | 
			
		||||
    _saveaccountconf GANDI_LIVEDNS_TOKEN "$GANDI_LIVEDNS_TOKEN"
 | 
			
		||||
    _clearaccountconf GANDI_LIVEDNS_KEY
 | 
			
		||||
  elif [ -n "$GANDI_LIVEDNS_KEY" ]; then
 | 
			
		||||
    _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
 | 
			
		||||
    _clearaccountconf GANDI_LIVEDNS_TOKEN
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
@@ -157,7 +165,12 @@ _gandi_livedns_rest() {
 | 
			
		||||
  _debug "$ep"
 | 
			
		||||
 | 
			
		||||
  export _H1="Content-Type: application/json"
 | 
			
		||||
  export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY"
 | 
			
		||||
 | 
			
		||||
  if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
 | 
			
		||||
    export _H2="Authorization: Bearer $GANDI_LIVEDNS_TOKEN"
 | 
			
		||||
  else
 | 
			
		||||
    export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "$m" = "GET" ]; then
 | 
			
		||||
    response="$(_get "$GANDI_LIVEDNS_API/$ep")"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										211
									
								
								dnsapi/dns_tencent.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								dnsapi/dns_tencent.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,211 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
Tencent_API="https://dnspod.tencentcloudapi.com"
 | 
			
		||||
 | 
			
		||||
#Tencent_SecretId="AKIDz81d2cd22cdcdc2dcd1cc1d1A"
 | 
			
		||||
#Tencent_SecretKey="Gu5t9abcabcaabcbabcbbbcbcbbccbbcb"
 | 
			
		||||
 | 
			
		||||
#Usage: dns_tencent_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
 | 
			
		||||
dns_tencent_add() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
 | 
			
		||||
  Tencent_SecretId="${Tencent_SecretId:-$(_readaccountconf_mutable Tencent_SecretId)}"
 | 
			
		||||
  Tencent_SecretKey="${Tencent_SecretKey:-$(_readaccountconf_mutable Tencent_SecretKey)}"
 | 
			
		||||
  if [ -z "$Tencent_SecretId" ] || [ -z "$Tencent_SecretKey" ]; then
 | 
			
		||||
    Tencent_SecretId=""
 | 
			
		||||
    Tencent_SecretKey=""
 | 
			
		||||
    _err "You don't specify tencent api SecretId and SecretKey yet."
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  #save the api SecretId and SecretKey to the account conf file.
 | 
			
		||||
  _saveaccountconf_mutable Tencent_SecretId "$Tencent_SecretId"
 | 
			
		||||
  _saveaccountconf_mutable Tencent_SecretKey "$Tencent_SecretKey"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "Add record"
 | 
			
		||||
  _add_record_query "$_domain" "$_sub_domain" "$txtvalue" && _tencent_rest "CreateRecord"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dns_tencent_rm() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  txtvalue=$2
 | 
			
		||||
  Tencent_SecretId="${Tencent_SecretId:-$(_readaccountconf_mutable Tencent_SecretId)}"
 | 
			
		||||
  Tencent_SecretKey="${Tencent_SecretKey:-$(_readaccountconf_mutable Tencent_SecretKey)}"
 | 
			
		||||
 | 
			
		||||
  _debug "First detect the root zone"
 | 
			
		||||
  if ! _get_root "$fulldomain"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "Get record list"
 | 
			
		||||
  attempt=1
 | 
			
		||||
  max_attempts=5
 | 
			
		||||
  while [ -z "$record_id" ] && [ "$attempt" -le $max_attempts ]; do
 | 
			
		||||
    _check_exist_query "$_domain" "$_sub_domain" "$txtvalue" && _tencent_rest "DescribeRecordFilterList"
 | 
			
		||||
    record_id="$(echo "$response" | _egrep_o "\"RecordId\":\s*[0-9]+" | _egrep_o "[0-9]+")"
 | 
			
		||||
    _debug2 record_id "$record_id"
 | 
			
		||||
    if [ -z "$record_id" ]; then
 | 
			
		||||
      _debug "Due to TencentCloud API synchronization delay, record not found, waiting 10 seconds and retrying"
 | 
			
		||||
      _sleep 10
 | 
			
		||||
      attempt=$(_math "$attempt + 1")
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  record_id="$(echo "$response" | _egrep_o "\"RecordId\":\s*[0-9]+" | _egrep_o "[0-9]+")"
 | 
			
		||||
  _debug2 record_id "$record_id"
 | 
			
		||||
 | 
			
		||||
  if [ -z "$record_id" ]; then
 | 
			
		||||
    _debug "record not found after $max_attempts attempts, skip"
 | 
			
		||||
  else
 | 
			
		||||
    _debug "Delete record"
 | 
			
		||||
    _delete_record_query "$record_id" && _tencent_rest "DeleteRecord"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
####################  Private functions below ##################################
 | 
			
		||||
 | 
			
		||||
_get_root() {
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=1
 | 
			
		||||
  p=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      #not valid
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    _describe_records_query "$h" "@"
 | 
			
		||||
    if ! _tencent_rest "DescribeRecordList" "ignore"; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _contains "$response" "\"TotalCount\":"; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
 | 
			
		||||
      _debug _sub_domain "$_sub_domain"
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      _debug _domain "$_domain"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p="$i"
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_tencent_rest() {
 | 
			
		||||
  action=$1
 | 
			
		||||
  service="dnspod"
 | 
			
		||||
  payload="${query}"
 | 
			
		||||
  timestamp=$(date -u +%s)
 | 
			
		||||
 | 
			
		||||
  token=$(tencent_signature_v3 $service "$action" "$payload" "$timestamp")
 | 
			
		||||
  version="2021-03-23"
 | 
			
		||||
 | 
			
		||||
  if ! response="$(tencent_api_request $service $version "$action" "$payload" "$timestamp")"; then
 | 
			
		||||
    _err "Error <$1>"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug2 response "$response"
 | 
			
		||||
  if [ -z "$2" ]; then
 | 
			
		||||
    message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")"
 | 
			
		||||
    if [ "$message" ]; then
 | 
			
		||||
      _err "$message"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_add_record_query() {
 | 
			
		||||
  query="{\"Domain\":\"$1\",\"SubDomain\":\"$2\",\"RecordType\":\"TXT\",\"RecordLineId\":\"0\",\"RecordLine\":\"0\",\"Value\":\"$3\",\"TTL\":600}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_describe_records_query() {
 | 
			
		||||
  query="{\"Domain\":\"$1\",\"Limit\":3000}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_delete_record_query() {
 | 
			
		||||
  query="{\"Domain\":\"$_domain\",\"RecordId\":$1}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_check_exist_query() {
 | 
			
		||||
  _domain="$1"
 | 
			
		||||
  _subdomain="$2"
 | 
			
		||||
  _value="$3"
 | 
			
		||||
  query="{\"Domain\":\"$_domain\",\"SubDomain\":\"$_subdomain\",\"RecordValue\":\"$_value\"}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# shell client for tencent cloud api v3 | @author: rehiy
 | 
			
		||||
 | 
			
		||||
tencent_sha256() {
 | 
			
		||||
  printf %b "$@" | _digest sha256 hex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tencent_hmac_sha256() {
 | 
			
		||||
  k=$1
 | 
			
		||||
  shift
 | 
			
		||||
  hex_key=$(printf %b "$k" | _hex_dump | tr -d ' ')
 | 
			
		||||
  printf %b "$@" | _hmac sha256 "$hex_key" hex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tencent_hmac_sha256_hexkey() {
 | 
			
		||||
  k=$1
 | 
			
		||||
  shift
 | 
			
		||||
  printf %b "$@" | _hmac sha256 "$k" hex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tencent_signature_v3() {
 | 
			
		||||
  service=$1
 | 
			
		||||
  action=$(echo "$2" | _lower_case)
 | 
			
		||||
  payload=${3:-'{}'}
 | 
			
		||||
  timestamp=${4:-$(date +%s)}
 | 
			
		||||
 | 
			
		||||
  domain="$service.tencentcloudapi.com"
 | 
			
		||||
  secretId=${Tencent_SecretId:-'tencent-cloud-secret-id'}
 | 
			
		||||
  secretKey=${Tencent_SecretKey:-'tencent-cloud-secret-key'}
 | 
			
		||||
 | 
			
		||||
  algorithm='TC3-HMAC-SHA256'
 | 
			
		||||
  date=$(date -u -d "@$timestamp" +%Y-%m-%d 2>/dev/null)
 | 
			
		||||
  [ -z "$date" ] && date=$(date -u -r "$timestamp" +%Y-%m-%d)
 | 
			
		||||
 | 
			
		||||
  canonicalUri='/'
 | 
			
		||||
  canonicalQuery=''
 | 
			
		||||
  canonicalHeaders="content-type:application/json\nhost:$domain\nx-tc-action:$action\n"
 | 
			
		||||
 | 
			
		||||
  signedHeaders='content-type;host;x-tc-action'
 | 
			
		||||
  canonicalRequest="POST\n$canonicalUri\n$canonicalQuery\n$canonicalHeaders\n$signedHeaders\n$(tencent_sha256 "$payload")"
 | 
			
		||||
 | 
			
		||||
  credentialScope="$date/$service/tc3_request"
 | 
			
		||||
  stringToSign="$algorithm\n$timestamp\n$credentialScope\n$(tencent_sha256 "$canonicalRequest")"
 | 
			
		||||
 | 
			
		||||
  secretDate=$(tencent_hmac_sha256 "TC3$secretKey" "$date")
 | 
			
		||||
  secretService=$(tencent_hmac_sha256_hexkey "$secretDate" "$service")
 | 
			
		||||
  secretSigning=$(tencent_hmac_sha256_hexkey "$secretService" 'tc3_request')
 | 
			
		||||
  signature=$(tencent_hmac_sha256_hexkey "$secretSigning" "$stringToSign")
 | 
			
		||||
 | 
			
		||||
  echo "$algorithm Credential=$secretId/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tencent_api_request() {
 | 
			
		||||
  service=$1
 | 
			
		||||
  version=$2
 | 
			
		||||
  action=$3
 | 
			
		||||
  payload=${4:-'{}'}
 | 
			
		||||
  timestamp=${5:-$(date +%s)}
 | 
			
		||||
 | 
			
		||||
  token=$(tencent_signature_v3 "$service" "$action" "$payload" "$timestamp")
 | 
			
		||||
 | 
			
		||||
  _H1="Content-Type: application/json"
 | 
			
		||||
  _H2="Authorization: $token"
 | 
			
		||||
  _H3="X-TC-Version: $version"
 | 
			
		||||
  _H4="X-TC-Timestamp: $timestamp"
 | 
			
		||||
  _H5="X-TC-Action: $action"
 | 
			
		||||
 | 
			
		||||
  _post "$payload" "$Tencent_API" "" "POST" "application/json"
 | 
			
		||||
}
 | 
			
		||||
@@ -69,7 +69,7 @@ dns_variomedia_rm() {
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _record_id="$(echo "$response" | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep "$_sub_domain" | grep "$txtvalue" | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')"
 | 
			
		||||
  _record_id="$(echo "$response" | sed -E 's/,"tags":\[[^]]*\]//g' | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep "$_sub_domain" | grep -- "$txtvalue" | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')"
 | 
			
		||||
  _debug _record_id "$_record_id"
 | 
			
		||||
  if [ "$_record_id" ]; then
 | 
			
		||||
    _info "Successfully retrieved the record id for ACME challenge."
 | 
			
		||||
@@ -93,11 +93,11 @@ dns_variomedia_rm() {
 | 
			
		||||
# _sub_domain=_acme-challenge.www
 | 
			
		||||
# _domain=domain.com
 | 
			
		||||
_get_root() {
 | 
			
		||||
  fulldomain=$1
 | 
			
		||||
  domain=$1
 | 
			
		||||
  i=1
 | 
			
		||||
  p=1
 | 
			
		||||
  while true; do
 | 
			
		||||
    h=$(printf "%s" "$fulldomain" | cut -d . -f $i-100)
 | 
			
		||||
    _debug h "$h"
 | 
			
		||||
    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
 | 
			
		||||
    if [ -z "$h" ]; then
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
@@ -106,17 +106,14 @@ _get_root() {
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if _startswith "$response" "\{\"data\":"; then
 | 
			
		||||
      if _contains "$response" "\"id\":\"$h\""; then
 | 
			
		||||
        _sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")"
 | 
			
		||||
        _domain=$h
 | 
			
		||||
        return 0
 | 
			
		||||
      fi
 | 
			
		||||
    if _contains "$response" "\"id\":\"$h\""; then
 | 
			
		||||
      _sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-$p)
 | 
			
		||||
      _domain="$h"
 | 
			
		||||
      return 0
 | 
			
		||||
    fi
 | 
			
		||||
    p=$i
 | 
			
		||||
    i=$(_math "$i" + 1)
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  _debug "root domain not found"
 | 
			
		||||
  return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user