Browse Source

Merge pull request #1264 from Neilpang/dev

sync
neil 7 years ago
parent
commit
5c6af92a0d
10 changed files with 157 additions and 127 deletions
  1. 7 0
      README.md
  2. 1 1
      acme.sh
  3. 6 3
      dnsapi/README.md
  4. 35 3
      dnsapi/dns_aws.sh
  5. 16 5
      dnsapi/dns_cloudns.sh
  6. 5 39
      dnsapi/dns_cx.sh
  7. 9 66
      dnsapi/dns_dp.sh
  8. 64 3
      dnsapi/dns_gd.sh
  9. 6 3
      dnsapi/dns_he.sh
  10. 8 4
      dnsapi/dns_ovh.sh

+ 7 - 0
README.md

@@ -315,6 +315,13 @@ You don't have to do anything manually!
 1. Azure DNS
 1. Azure DNS
 1. selectel.com(selectel.ru) DNS API
 1. selectel.com(selectel.ru) DNS API
 1. zonomi.com DNS API
 1. zonomi.com DNS API
+
+
+
+
+
+
+
 And: 
 And: 
 
 
 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api

+ 1 - 1
acme.sh

@@ -4545,7 +4545,7 @@ _installcert() {
       cat "$CERT_KEY_PATH" >"$_real_key"
       cat "$CERT_KEY_PATH" >"$_real_key"
     else
     else
       cat "$CERT_KEY_PATH" >"$_real_key"
       cat "$CERT_KEY_PATH" >"$_real_key"
-      chmod 700 "$_real_key"
+      chmod 600 "$_real_key"
     fi
     fi
   fi
   fi
 
 

+ 6 - 3
dnsapi/README.md

@@ -409,10 +409,13 @@ acme.sh --issue --dns dns_dgon -d example.com -d www.example.com
 
 
 ## 21. Use ClouDNS.net API
 ## 21. Use ClouDNS.net API
 
 
-You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/
+You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/. For security reasons, it's recommended to use a sub user ID that only has access to the necessary zones, as a regular API user has access to your entire account.
 
 
 ```
 ```
-export CLOUDNS_AUTH_ID=XXXXX
+# Use this for a sub auth ID
+export CLOUDNS_SUB_AUTH_ID=XXXXX
+# Use this for a regular auth ID
+#export CLOUDNS_AUTH_ID=XXXXX
 export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
 export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
 ```
 ```
 
 
@@ -585,7 +588,7 @@ For issues, please report to https://github.com/non7top/acme.sh/issues.
 
 
 ## 31. Use Hurricane Electric
 ## 31. Use Hurricane Electric
 
 
-Hurricane Electric doesn't have an API so just set your login credentials like so:
+Hurricane Electric (https://dns.he.net/) doesn't have an API so just set your login credentials like so:
 
 
 ```
 ```
 export HE_Username="yourusername"
 export HE_Username="yourusername"

+ 35 - 3
dnsapi/dns_aws.sh

@@ -42,7 +42,26 @@ dns_aws_add() {
   _debug _sub_domain "$_sub_domain"
   _debug _sub_domain "$_sub_domain"
   _debug _domain "$_domain"
   _debug _domain "$_domain"
 
 
-  _aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>UPSERT</Action><ResourceRecordSet><Name>$fulldomain</Name><Type>TXT</Type><TTL>300</TTL><ResourceRecords><ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
+  _info "Geting existing records for $fulldomain"
+  if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then
+    return 1
+  fi
+
+  if _contains "$response" "<Name>$fulldomain.</Name>"; then
+    _resource_record="$(echo "$response" | sed 's/<ResourceRecordSet>/"/g' | tr '"' "\n" | grep "<Name>$fulldomain.</Name>" | _egrep_o "<ResourceRecords.*</ResourceRecords>" | sed "s/<ResourceRecords>//" | sed "s#</ResourceRecords>##")"
+    _debug "_resource_record" "$_resource_record"
+  else
+    _debug "single new add"
+  fi
+
+  if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then
+    _info "The txt record already exists, skip"
+    return 0
+  fi
+
+  _debug "Adding records"
+
+  _aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>UPSERT</Action><ResourceRecordSet><Name>$fulldomain</Name><Type>TXT</Type><TTL>300</TTL><ResourceRecords>$_resource_record<ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
 
 
   if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
   if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
     _info "txt record updated success."
     _info "txt record updated success."
@@ -68,7 +87,20 @@ dns_aws_rm() {
   _debug _sub_domain "$_sub_domain"
   _debug _sub_domain "$_sub_domain"
   _debug _domain "$_domain"
   _debug _domain "$_domain"
 
 
-  _aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>DELETE</Action><ResourceRecordSet><ResourceRecords><ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords><Name>$fulldomain.</Name><Type>TXT</Type><TTL>300</TTL></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
+  _info "Geting existing records for $fulldomain"
+  if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then
+    return 1
+  fi
+
+  if _contains "$response" "<Name>$fulldomain.</Name>"; then
+    _resource_record="$(echo "$response" | sed 's/<ResourceRecordSet>/"/g' | tr '"' "\n" | grep "<Name>$fulldomain.</Name>" | _egrep_o "<ResourceRecords.*</ResourceRecords>" | sed "s/<ResourceRecords>//" | sed "s#</ResourceRecords>##")"
+    _debug "_resource_record" "$_resource_record"
+  else
+    _debug "no records exists, skip"
+    return 0
+  fi
+
+  _aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>DELETE</Action><ResourceRecordSet><ResourceRecords>$_resource_record</ResourceRecords><Name>$fulldomain.</Name><Type>TXT</Type><TTL>300</TTL></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
 
 
   if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
   if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
     _info "txt record deleted success."
     _info "txt record deleted success."
@@ -87,7 +119,6 @@ _get_root() {
   p=1
   p=1
 
 
   if aws_rest GET "2013-04-01/hostedzone"; then
   if aws_rest GET "2013-04-01/hostedzone"; then
-    _debug "response" "$response"
     while true; do
     while true; do
       h=$(printf "%s" "$domain" | cut -d . -f $i-100)
       h=$(printf "%s" "$domain" | cut -d . -f $i-100)
       _debug2 "Checking domain: $h"
       _debug2 "Checking domain: $h"
@@ -236,6 +267,7 @@ aws_rest() {
   fi
   fi
 
 
   _ret="$?"
   _ret="$?"
+  _debug2 response "$response"
   if [ "$_ret" = "0" ]; then
   if [ "$_ret" = "0" ]; then
     if _contains "$response" "<ErrorResponse"; then
     if _contains "$response" "<ErrorResponse"; then
       _err "Response error:$response"
       _err "Response error:$response"

+ 16 - 5
dnsapi/dns_cloudns.sh

@@ -4,6 +4,7 @@
 # Repository: https://github.com/ClouDNS/acme.sh/
 # Repository: https://github.com/ClouDNS/acme.sh/
 
 
 #CLOUDNS_AUTH_ID=XXXXX
 #CLOUDNS_AUTH_ID=XXXXX
+#CLOUDNS_SUB_AUTH_ID=XXXXX
 #CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
 #CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
 CLOUDNS_API="https://api.cloudns.net"
 CLOUDNS_API="https://api.cloudns.net"
 
 
@@ -97,17 +98,19 @@ _dns_cloudns_init_check() {
   fi
   fi
 
 
   CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}"
   CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}"
+  CLOUDNS_SUB_AUTH_ID="${CLOUDNS_SUB_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_SUB_AUTH_ID)}"
   CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}"
   CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}"
-  if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then
+  if [ -z "$CLOUDNS_AUTH_ID$CLOUDNS_SUB_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then
     CLOUDNS_AUTH_ID=""
     CLOUDNS_AUTH_ID=""
+    CLOUDNS_SUB_AUTH_ID=""
     CLOUDNS_AUTH_PASSWORD=""
     CLOUDNS_AUTH_PASSWORD=""
     _err "You don't specify cloudns api id and password yet."
     _err "You don't specify cloudns api id and password yet."
     _err "Please create you id and password and try again."
     _err "Please create you id and password and try again."
     return 1
     return 1
   fi
   fi
 
 
-  if [ -z "$CLOUDNS_AUTH_ID" ]; then
-    _err "CLOUDNS_AUTH_ID is not configured"
+  if [ -z "$CLOUDNS_AUTH_ID" ] && [ -z "$CLOUDNS_SUB_AUTH_ID" ]; then
+    _err "CLOUDNS_AUTH_ID or CLOUDNS_SUB_AUTH_ID is not configured"
     return 1
     return 1
   fi
   fi
 
 
@@ -125,6 +128,7 @@ _dns_cloudns_init_check() {
 
 
   #save the api id and password to the account conf file.
   #save the api id and password to the account conf file.
   _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
   _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
+  _saveaccountconf_mutable CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID"
   _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
   _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
 
 
   CLOUDNS_INIT_CHECK_COMPLETED=1
   CLOUDNS_INIT_CHECK_COMPLETED=1
@@ -168,12 +172,19 @@ _dns_cloudns_http_api_call() {
   method=$1
   method=$1
 
 
   _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
   _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
+  _debug CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID"
   _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
   _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
 
 
+  if [ ! -z "$CLOUDNS_SUB_AUTH_ID" ]; then
+    auth_user="sub-auth-id=$CLOUDNS_SUB_AUTH_ID"
+  else
+    auth_user="auth-id=$CLOUDNS_AUTH_ID"
+  fi
+
   if [ -z "$2" ]; then
   if [ -z "$2" ]; then
-    data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD"
+    data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD"
   else
   else
-    data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2"
+    data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD&$2"
   fi
   fi
 
 
   response="$(_get "$CLOUDNS_API/$method?$data")"
   response="$(_get "$CLOUDNS_API/$method?$data")"

+ 5 - 39
dnsapi/dns_cx.sh

@@ -36,33 +36,18 @@ dns_cx_add() {
     return 1
     return 1
   fi
   fi
 
 
-  existing_records "$_domain" "$_sub_domain"
-  _debug count "$count"
-  if [ "$?" != "0" ]; then
-    _err "Error get existing records."
-    return 1
-  fi
-
-  if [ "$count" = "0" ]; then
-    add_record "$_domain" "$_sub_domain" "$txtvalue"
-  else
-    update_record "$_domain" "$_sub_domain" "$txtvalue"
-  fi
-
-  if [ "$?" = "0" ]; then
-    return 0
-  fi
-  return 1
+  add_record "$_domain" "$_sub_domain" "$txtvalue"
 }
 }
 
 
-#fulldomain
+#fulldomain txtvalue
 dns_cx_rm() {
 dns_cx_rm() {
   fulldomain=$1
   fulldomain=$1
+  txtvalue=$2
   REST_API="$CX_Api"
   REST_API="$CX_Api"
   if _get_root "$fulldomain"; then
   if _get_root "$fulldomain"; then
     record_id=""
     record_id=""
-    existing_records "$_domain" "$_sub_domain"
-    if ! [ "$record_id" = "" ]; then
+    existing_records "$_domain" "$_sub_domain" "$txtvalue"
+    if [ "$record_id" ]; then
       _rest DELETE "record/$record_id/$_domain_id" "{}"
       _rest DELETE "record/$record_id/$_domain_id" "{}"
       _info "Deleted record ${fulldomain}"
       _info "Deleted record ${fulldomain}"
     fi
     fi
@@ -77,7 +62,6 @@ existing_records() {
   _debug "Getting txt records"
   _debug "Getting txt records"
   root=$1
   root=$1
   sub=$2
   sub=$2
-  count=0
   if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
   if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
     return 1
     return 1
   fi
   fi
@@ -89,7 +73,6 @@ existing_records() {
   fi
   fi
 
 
   if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
   if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
-    count=1
     record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
     record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
     _debug record_id "$record_id"
     _debug record_id "$record_id"
     return 0
     return 0
@@ -114,23 +97,6 @@ add_record() {
   return 0
   return 0
 }
 }
 
 
-#update the txt record
-#Usage: root sub txtvalue
-update_record() {
-  root=$1
-  sub=$2
-  txtvalue=$3
-  fulldomain="$sub.$root"
-
-  _info "Updating record"
-
-  if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
-    return 0
-  fi
-
-  return 1
-}
-
 ####################  Private functions below ##################################
 ####################  Private functions below ##################################
 #_acme-challenge.www.domain.com
 #_acme-challenge.www.domain.com
 #returns
 #returns

+ 9 - 66
dnsapi/dns_dp.sh

@@ -15,6 +15,8 @@ dns_dp_add() {
   fulldomain=$1
   fulldomain=$1
   txtvalue=$2
   txtvalue=$2
 
 
+  DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}"
+  DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}"
   if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then
   if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then
     DP_Id=""
     DP_Id=""
     DP_Key=""
     DP_Key=""
@@ -24,8 +26,8 @@ dns_dp_add() {
   fi
   fi
 
 
   #save the api key and email to the account conf file.
   #save the api key and email to the account conf file.
-  _saveaccountconf DP_Id "$DP_Id"
-  _saveaccountconf DP_Key "$DP_Key"
+  _saveaccountconf_mutable DP_Id "$DP_Id"
+  _saveaccountconf_mutable DP_Key "$DP_Key"
 
 
   _debug "First detect the root zone"
   _debug "First detect the root zone"
   if ! _get_root "$fulldomain"; then
   if ! _get_root "$fulldomain"; then
@@ -33,24 +35,18 @@ dns_dp_add() {
     return 1
     return 1
   fi
   fi
 
 
-  existing_records "$_domain" "$_sub_domain"
-  _debug count "$count"
-  if [ "$?" != "0" ]; then
-    _err "Error get existing records."
-    return 1
-  fi
+  add_record "$_domain" "$_sub_domain" "$txtvalue"
 
 
-  if [ "$count" = "0" ]; then
-    add_record "$_domain" "$_sub_domain" "$txtvalue"
-  else
-    update_record "$_domain" "$_sub_domain" "$txtvalue"
-  fi
 }
 }
 
 
 #fulldomain txtvalue
 #fulldomain txtvalue
 dns_dp_rm() {
 dns_dp_rm() {
   fulldomain=$1
   fulldomain=$1
   txtvalue=$2
   txtvalue=$2
+
+  DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}"
+  DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}"
+
   _debug "First detect the root zone"
   _debug "First detect the root zone"
   if ! _get_root "$fulldomain"; then
   if ! _get_root "$fulldomain"; then
     _err "invalid domain"
     _err "invalid domain"
@@ -83,37 +79,6 @@ dns_dp_rm() {
 
 
 }
 }
 
 
-#usage:  root  sub
-#return if the sub record already exists.
-#echos the existing records count.
-# '0' means doesn't exist
-existing_records() {
-  _debug "Getting txt records"
-  root=$1
-  sub=$2
-
-  if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&domain_id=$_domain_id&sub_domain=$_sub_domain"; then
-    return 1
-  fi
-
-  if _contains "$response" 'No records'; then
-    count=0
-    return 0
-  fi
-
-  if _contains "$response" "Action completed successful"; then
-    count=$(printf "%s" "$response" | grep -c '<type>TXT</type>' | tr -d ' ')
-    record_id=$(printf "%s" "$response" | grep '^<id>' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1)
-    _debug record_id "$record_id"
-    return 0
-  else
-    _err "get existing records error."
-    return 1
-  fi
-
-  count=0
-}
-
 #add the txt record.
 #add the txt record.
 #usage: root  sub  txtvalue
 #usage: root  sub  txtvalue
 add_record() {
 add_record() {
@@ -136,28 +101,6 @@ add_record() {
   return 1 #error
   return 1 #error
 }
 }
 
 
-#update the txt record
-#Usage: root sub txtvalue
-update_record() {
-  root=$1
-  sub=$2
-  txtvalue=$3
-  fulldomain="$sub.$root"
-
-  _info "Updating record"
-
-  if ! _rest POST "Record.Modify" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认&record_id=$record_id"; then
-    return 1
-  fi
-
-  if _contains "$response" "Action completed successful"; then
-
-    return 0
-  fi
-
-  return 1 #error
-}
-
 ####################  Private functions below ##################################
 ####################  Private functions below ##################################
 #_acme-challenge.www.domain.com
 #_acme-challenge.www.domain.com
 #returns
 #returns

+ 64 - 3
dnsapi/dns_gd.sh

@@ -15,6 +15,8 @@ dns_gd_add() {
   fulldomain=$1
   fulldomain=$1
   txtvalue=$2
   txtvalue=$2
 
 
+  GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}"
+  GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}"
   if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
   if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
     GD_Key=""
     GD_Key=""
     GD_Secret=""
     GD_Secret=""
@@ -24,8 +26,8 @@ dns_gd_add() {
   fi
   fi
 
 
   #save the api key and email to the account conf file.
   #save the api key and email to the account conf file.
-  _saveaccountconf GD_Key "$GD_Key"
-  _saveaccountconf GD_Secret "$GD_Secret"
+  _saveaccountconf_mutable GD_Key "$GD_Key"
+  _saveaccountconf_mutable GD_Secret "$GD_Secret"
 
 
   _debug "First detect the root zone"
   _debug "First detect the root zone"
   if ! _get_root "$fulldomain"; then
   if ! _get_root "$fulldomain"; then
@@ -36,8 +38,27 @@ dns_gd_add() {
   _debug _sub_domain "$_sub_domain"
   _debug _sub_domain "$_sub_domain"
   _debug _domain "$_domain"
   _debug _domain "$_domain"
 
 
+  _debug "Getting existing records"
+  if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
+    return 1
+  fi
+
+  if _contains "$response" "$txtvalue"; then
+    _info "The record is existing, skip"
+    return 0
+  fi
+
+  _add_data="{\"data\":\"$txtvalue\"}"
+  for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
+    _debug2 t "$t"
+    if [ "$t" ]; then
+      _add_data="$_add_data,{\"data\":$t}"
+    fi
+  done
+  _debug2 _add_data "$_add_data"
+
   _info "Adding record"
   _info "Adding record"
-  if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then
+  if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
     if [ "$response" = "{}" ]; then
     if [ "$response" = "{}" ]; then
       _info "Added, sleeping 10 seconds"
       _info "Added, sleeping 10 seconds"
       _sleep 10
       _sleep 10
@@ -56,7 +77,47 @@ dns_gd_add() {
 #fulldomain
 #fulldomain
 dns_gd_rm() {
 dns_gd_rm() {
   fulldomain=$1
   fulldomain=$1
+  txtvalue=$2
+
+  GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}"
+  GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}"
+
+  _debug "First detect the root zone"
+  if ! _get_root "$fulldomain"; then
+    _err "invalid domain"
+    return 1
+  fi
+
+  _debug _sub_domain "$_sub_domain"
+  _debug _domain "$_domain"
+
+  _debug "Getting existing records"
+  if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
+    return 1
+  fi
+
+  if ! _contains "$response" "$txtvalue"; then
+    _info "The record is not existing, skip"
+    return 0
+  fi
+
+  _add_data=""
+  for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
+    _debug2 t "$t"
+    if [ "$t" ] && [ "$t" != "\"$txtvalue\"" ]; then
+      if [ "$_add_data" ]; then
+        _add_data="$_add_data,{\"data\":$t}"
+      else
+        _add_data="{\"data\":$t}"
+      fi
+    fi
+  done
+  if [ -z "$_add_data" ]; then
+    _add_data="{\"data\":\"\"}"
+  fi
+  _debug2 _add_data "$_add_data"
 
 
+  _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"
 }
 }
 
 
 ####################  Private functions below ##################################
 ####################  Private functions below ##################################

+ 6 - 3
dnsapi/dns_he.sh

@@ -19,14 +19,16 @@ dns_he_add() {
   _txt_value=$2
   _txt_value=$2
   _info "Using DNS-01 Hurricane Electric hook"
   _info "Using DNS-01 Hurricane Electric hook"
 
 
+  HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}"
+  HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}"
   if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then
   if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then
     HE_Username=
     HE_Username=
     HE_Password=
     HE_Password=
     _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
     _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
     return 1
     return 1
   fi
   fi
-  _saveaccountconf HE_Username "$HE_Username"
-  _saveaccountconf HE_Password "$HE_Password"
+  _saveaccountconf_mutable HE_Username "$HE_Username"
+  _saveaccountconf_mutable HE_Password "$HE_Password"
 
 
   # Fills in the $_zone_id
   # Fills in the $_zone_id
   _find_zone "$_full_domain" || return 1
   _find_zone "$_full_domain" || return 1
@@ -62,7 +64,8 @@ dns_he_rm() {
   _full_domain=$1
   _full_domain=$1
   _txt_value=$2
   _txt_value=$2
   _info "Cleaning up after DNS-01 Hurricane Electric hook"
   _info "Cleaning up after DNS-01 Hurricane Electric hook"
-
+  HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}"
+  HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}"
   # fills in the $_zone_id
   # fills in the $_zone_id
   _find_zone "$_full_domain" || return 1
   _find_zone "$_full_domain" || return 1
   _debug "Zone id \"$_zone_id\" will be used."
   _debug "Zone id \"$_zone_id\" will be used."

+ 8 - 4
dnsapi/dns_ovh.sh

@@ -79,6 +79,9 @@ _ovh_get_api() {
 }
 }
 
 
 _initAuth() {
 _initAuth() {
+  OVH_AK="${OVH_AK:-$(_readaccountconf_mutable OVH_AK)}"
+  OVH_AS="${OVH_AS:-$(_readaccountconf_mutable OVH_AS)}"
+
   if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then
   if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then
     OVH_AK=""
     OVH_AK=""
     OVH_AS=""
     OVH_AS=""
@@ -87,21 +90,22 @@ _initAuth() {
     return 1
     return 1
   fi
   fi
 
 
-  #save the api key and email to the account conf file.
-  _saveaccountconf OVH_AK "$OVH_AK"
-  _saveaccountconf OVH_AS "$OVH_AS"
+  _saveaccountconf_mutable OVH_AK "$OVH_AK"
+  _saveaccountconf_mutable OVH_AS "$OVH_AS"
 
 
+  OVH_END_POINT="${OVH_END_POINT:-$(_readaccountconf_mutable OVH_END_POINT)}"
   if [ -z "$OVH_END_POINT" ]; then
   if [ -z "$OVH_END_POINT" ]; then
     OVH_END_POINT="ovh-eu"
     OVH_END_POINT="ovh-eu"
   fi
   fi
   _info "Using OVH endpoint: $OVH_END_POINT"
   _info "Using OVH endpoint: $OVH_END_POINT"
   if [ "$OVH_END_POINT" != "ovh-eu" ]; then
   if [ "$OVH_END_POINT" != "ovh-eu" ]; then
-    _saveaccountconf OVH_END_POINT "$OVH_END_POINT"
+    _saveaccountconf_mutable OVH_END_POINT "$OVH_END_POINT"
   fi
   fi
 
 
   OVH_API="$(_ovh_get_api $OVH_END_POINT)"
   OVH_API="$(_ovh_get_api $OVH_END_POINT)"
   _debug OVH_API "$OVH_API"
   _debug OVH_API "$OVH_API"
 
 
+  OVH_CK="${OVH_CK:-$(_readaccountconf_mutable OVH_CK)}"
   if [ -z "$OVH_CK" ]; then
   if [ -z "$OVH_CK" ]; then
     _info "OVH consumer key is empty, Let's get one:"
     _info "OVH consumer key is empty, Let's get one:"
     if ! _ovh_authentication; then
     if ! _ovh_authentication; then