diff --git a/README.md b/README.md
index d6b2c555..9e3ec1a5 100644
--- a/README.md
+++ b/README.md
@@ -315,6 +315,13 @@ You don't have to do anything manually!
1. Azure DNS
1. selectel.com(selectel.ru) DNS API
1. zonomi.com DNS API
+
+
+
+
+
+
+
And:
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
diff --git a/acme.sh b/acme.sh
index a4224fc9..b9e57a7b 100755
--- a/acme.sh
+++ b/acme.sh
@@ -4545,7 +4545,7 @@ _installcert() {
cat "$CERT_KEY_PATH" >"$_real_key"
else
cat "$CERT_KEY_PATH" >"$_real_key"
- chmod 700 "$_real_key"
+ chmod 600 "$_real_key"
fi
fi
diff --git a/dnsapi/README.md b/dnsapi/README.md
index 5ded260c..b5b73f47 100644
--- a/dnsapi/README.md
+++ b/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
-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"
```
@@ -585,7 +588,7 @@ For issues, please report to https://github.com/non7top/acme.sh/issues.
## 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"
diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh
index ed317460..71f969f0 100755
--- a/dnsapi/dns_aws.sh
+++ b/dnsapi/dns_aws.sh
@@ -42,7 +42,26 @@ dns_aws_add() {
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
- _aws_tmpl_xml="UPSERT$fulldomainTXT300\"$txtvalue\""
+ _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" "$fulldomain."; then
+ _resource_record="$(echo "$response" | sed 's//"/g' | tr '"' "\n" | grep "$fulldomain." | _egrep_o "" | sed "s///" | sed "s###")"
+ _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="UPSERT$fulldomainTXT300$_resource_record\"$txtvalue\""
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
_info "txt record updated success."
@@ -68,7 +87,20 @@ dns_aws_rm() {
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
- _aws_tmpl_xml="DELETE\"$txtvalue\"$fulldomain.TXT300"
+ _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" "$fulldomain."; then
+ _resource_record="$(echo "$response" | sed 's//"/g' | tr '"' "\n" | grep "$fulldomain." | _egrep_o "" | sed "s///" | sed "s###")"
+ _debug "_resource_record" "$_resource_record"
+ else
+ _debug "no records exists, skip"
+ return 0
+ fi
+
+ _aws_tmpl_xml="DELETE$_resource_record$fulldomain.TXT300"
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
_info "txt record deleted success."
@@ -87,7 +119,6 @@ _get_root() {
p=1
if aws_rest GET "2013-04-01/hostedzone"; then
- _debug "response" "$response"
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug2 "Checking domain: $h"
@@ -236,6 +267,7 @@ aws_rest() {
fi
_ret="$?"
+ _debug2 response "$response"
if [ "$_ret" = "0" ]; then
if _contains "$response" "/dev/null; then
- count=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"
return 0
@@ -114,23 +97,6 @@ add_record() {
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 ##################################
#_acme-challenge.www.domain.com
#returns
diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh
index 301a1f6c..bf623e26 100755
--- a/dnsapi/dns_dp.sh
+++ b/dnsapi/dns_dp.sh
@@ -15,6 +15,8 @@ dns_dp_add() {
fulldomain=$1
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
DP_Id=""
DP_Key=""
@@ -24,8 +26,8 @@ dns_dp_add() {
fi
#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"
if ! _get_root "$fulldomain"; then
@@ -33,24 +35,18 @@ dns_dp_add() {
return 1
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
dns_dp_rm() {
fulldomain=$1
txtvalue=$2
+
+ DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}"
+ DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}"
+
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_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 'TXT' | tr -d ' ')
- record_id=$(printf "%s" "$response" | grep '^' | 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.
#usage: root sub txtvalue
add_record() {
@@ -136,28 +101,6 @@ add_record() {
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 ##################################
#_acme-challenge.www.domain.com
#returns
diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh
index f2dd1fd5..5fb1b174 100755
--- a/dnsapi/dns_gd.sh
+++ b/dnsapi/dns_gd.sh
@@ -15,6 +15,8 @@ dns_gd_add() {
fulldomain=$1
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
GD_Key=""
GD_Secret=""
@@ -24,8 +26,8 @@ dns_gd_add() {
fi
#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"
if ! _get_root "$fulldomain"; then
@@ -36,8 +38,27 @@ dns_gd_add() {
_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 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"
- 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
_info "Added, sleeping 10 seconds"
_sleep 10
@@ -56,7 +77,47 @@ dns_gd_add() {
#fulldomain
dns_gd_rm() {
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 ##################################
diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh
index 4d1973ad..7b854ead 100755
--- a/dnsapi/dns_he.sh
+++ b/dnsapi/dns_he.sh
@@ -19,14 +19,16 @@ dns_he_add() {
_txt_value=$2
_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
HE_Username=
HE_Password=
_err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables."
return 1
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
_find_zone "$_full_domain" || return 1
@@ -62,7 +64,8 @@ dns_he_rm() {
_full_domain=$1
_txt_value=$2
_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
_find_zone "$_full_domain" || return 1
_debug "Zone id \"$_zone_id\" will be used."
diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh
index 60094739..296a2698 100755
--- a/dnsapi/dns_ovh.sh
+++ b/dnsapi/dns_ovh.sh
@@ -79,6 +79,9 @@ _ovh_get_api() {
}
_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
OVH_AK=""
OVH_AS=""
@@ -87,21 +90,22 @@ _initAuth() {
return 1
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
OVH_END_POINT="ovh-eu"
fi
_info "Using OVH endpoint: $OVH_END_POINT"
if [ "$OVH_END_POINT" != "ovh-eu" ]; then
- _saveaccountconf OVH_END_POINT "$OVH_END_POINT"
+ _saveaccountconf_mutable OVH_END_POINT "$OVH_END_POINT"
fi
OVH_API="$(_ovh_get_api $OVH_END_POINT)"
_debug OVH_API "$OVH_API"
+ OVH_CK="${OVH_CK:-$(_readaccountconf_mutable OVH_CK)}"
if [ -z "$OVH_CK" ]; then
_info "OVH consumer key is empty, Let's get one:"
if ! _ovh_authentication; then