]> git.proxmox.com Git - mirror_acme.sh.git/blob - dnsapi/dns_cf.sh
fix https://github.com/acmesh-official/acme.sh/issues/2888
[mirror_acme.sh.git] / dnsapi / dns_cf.sh
1 #!/usr/bin/env sh
2
3 #
4 #CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
5 #
6 #CF_Email="xxxx@sss.com"
7
8 #CF_Token="xxxx"
9 #CF_Account_ID="xxxx"
10 #CF_Zone_ID="xxxx"
11
12 CF_Api="https://api.cloudflare.com/client/v4"
13
14 ######## Public functions #####################
15
16 #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
17 dns_cf_add() {
18 fulldomain=$1
19 txtvalue=$2
20
21 CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}"
22 CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}"
23 CF_Zone_ID="${CF_Zone_ID:-$(_readaccountconf_mutable CF_Zone_ID)}"
24 CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}"
25 CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
26
27 if [ "$CF_Token" ]; then
28 _saveaccountconf_mutable CF_Token "$CF_Token"
29 _saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
30 _saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
31 else
32 if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
33 CF_Key=""
34 CF_Email=""
35 _err "You didn't specify a Cloudflare api key and email yet."
36 _err "You can get yours from here https://dash.cloudflare.com/profile."
37 return 1
38 fi
39
40 if ! _contains "$CF_Email" "@"; then
41 _err "It seems that the CF_Email=$CF_Email is not a valid email address."
42 _err "Please check and retry."
43 return 1
44 fi
45 #save the api key and email to the account conf file.
46 _saveaccountconf_mutable CF_Key "$CF_Key"
47 _saveaccountconf_mutable CF_Email "$CF_Email"
48 fi
49
50 _debug "First detect the root zone"
51 if ! _get_root "$fulldomain"; then
52 _err "invalid domain"
53 return 1
54 fi
55 _debug _domain_id "$_domain_id"
56 _debug _sub_domain "$_sub_domain"
57 _debug _domain "$_domain"
58
59 _debug "Getting txt records"
60 _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain"
61
62 if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then
63 _err "Error"
64 return 1
65 fi
66
67 # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
68 # we can not use updating anymore.
69 # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
70 # _debug count "$count"
71 # if [ "$count" = "0" ]; then
72 _info "Adding record"
73 if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
74 if _contains "$response" "$txtvalue"; then
75 _info "Added, OK"
76 return 0
77 elif _contains "$response" "The record already exists"; then
78 _info "Already exists, OK"
79 return 0
80 else
81 _err "Add txt record error."
82 return 1
83 fi
84 fi
85 _err "Add txt record error."
86 return 1
87
88 }
89
90 #fulldomain txtvalue
91 dns_cf_rm() {
92 fulldomain=$1
93 txtvalue=$2
94
95 CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}"
96 CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}"
97 CF_Zone_ID="${CF_Zone_ID:-$(_readaccountconf_mutable CF_Zone_ID)}"
98 CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}"
99 CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
100
101 _debug "First detect the root zone"
102 if ! _get_root "$fulldomain"; then
103 _err "invalid domain"
104 return 1
105 fi
106 _debug _domain_id "$_domain_id"
107 _debug _sub_domain "$_sub_domain"
108 _debug _domain "$_domain"
109
110 _debug "Getting txt records"
111 _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue"
112
113 if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then
114 _err "Error: $response"
115 return 1
116 fi
117
118 count=$(echo "$response" | _egrep_o "\"count\": *[^,]*" | cut -d : -f 2 | tr -d " ")
119 _debug count "$count"
120 if [ "$count" = "0" ]; then
121 _info "Don't need to remove."
122 else
123 record_id=$(echo "$response" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ")
124 _debug "record_id" "$record_id"
125 if [ -z "$record_id" ]; then
126 _err "Can not get record id to remove."
127 return 1
128 fi
129 if ! _cf_rest DELETE "zones/$_domain_id/dns_records/$record_id"; then
130 _err "Delete record error."
131 return 1
132 fi
133 _contains "$response" '"success":true'
134 fi
135
136 }
137
138 #################### Private functions below ##################################
139 #_acme-challenge.www.domain.com
140 #returns
141 # _sub_domain=_acme-challenge.www
142 # _domain=domain.com
143 # _domain_id=sdjkglgdfewsdfg
144 _get_root() {
145 domain=$1
146 i=1
147 p=1
148
149 # Use Zone ID directly if provided
150 if [ "$CF_Zone_ID" ]; then
151 if ! _cf_rest GET "zones/$CF_Zone_ID"; then
152 return 1
153 else
154 if _contains "$response" '"success":true'; then
155 _domain=$(echo "$response" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ")
156 if [ "$_domain" ]; then
157 _cutlength=$((${#domain} - ${#_domain} - 1))
158 _sub_domain=$(printf "%s" "$domain" | cut -c "1-$_cutlength")
159 _domain_id=$CF_Zone_ID
160 return 0
161 else
162 return 1
163 fi
164 else
165 return 1
166 fi
167 fi
168 fi
169
170 while true; do
171 h=$(printf "%s" "$domain" | cut -d . -f $i-100)
172 _debug h "$h"
173 if [ -z "$h" ]; then
174 #not valid
175 return 1
176 fi
177
178 if [ "$CF_Account_ID" ]; then
179 if ! _cf_rest GET "zones?name=$h&account.id=$CF_Account_ID"; then
180 return 1
181 fi
182 else
183 if ! _cf_rest GET "zones?name=$h"; then
184 return 1
185 fi
186 fi
187
188 if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; then
189 _domain_id=$(echo "$response" | _egrep_o "\[.\"id\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ")
190 if [ "$_domain_id" ]; then
191 _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
192 _domain=$h
193 return 0
194 fi
195 return 1
196 fi
197 p=$i
198 i=$(_math "$i" + 1)
199 done
200 return 1
201 }
202
203 _cf_rest() {
204 m=$1
205 ep="$2"
206 data="$3"
207 _debug "$ep"
208
209 email_trimmed=$(echo "$CF_Email" | tr -d '"')
210 key_trimmed=$(echo "$CF_Key" | tr -d '"')
211 token_trimmed=$(echo "$CF_Token" | tr -d '"')
212
213 export _H1="Content-Type: application/json"
214 if [ "$token_trimmed" ]; then
215 export _H2="Authorization: Bearer $token_trimmed"
216 else
217 export _H2="X-Auth-Email: $email_trimmed"
218 export _H3="X-Auth-Key: $key_trimmed"
219 fi
220
221 if [ "$m" != "GET" ]; then
222 _debug data "$data"
223 response="$(_post "$data" "$CF_Api/$ep" "" "$m")"
224 else
225 response="$(_get "$CF_Api/$ep")"
226 fi
227
228 if [ "$?" != "0" ]; then
229 _err "error $ep"
230 return 1
231 fi
232 _debug2 response "$response"
233 return 0
234 }