]>
Commit | Line | Data |
---|---|---|
72d800ed MB |
1 | #!/usr/bin/env sh |
2 | ||
3 | #Rcode0 API Integration | |
4 | #https://my.rcodezero.at/api-doc | |
5 | # | |
ac9f6e3a | 6 | # log into https://my.rcodezero.at/enableapi and get your ACME API Token (the ACME API token has limited |
72d800ed MB |
7 | # access to the REST calls needed for acme.sh only) |
8 | # | |
9 | #RCODE0_URL="https://my.rcodezero.at" | |
10 | #RCODE0_API_TOKEN="0123456789ABCDEF" | |
11 | #RCODE0_TTL=60 | |
12 | ||
13 | DEFAULT_RCODE0_URL="https://my.rcodezero.at" | |
14 | DEFAULT_RCODE0_TTL=60 | |
15 | ||
16 | ######## Public functions ##################### | |
17 | #Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" | |
18 | #fulldomain | |
19 | #txtvalue | |
20 | dns_rcode0_add() { | |
21 | fulldomain=$1 | |
22 | txtvalue=$2 | |
23 | ||
24 | RCODE0_API_TOKEN="${RCODE0_API_TOKEN:-$(_readaccountconf_mutable RCODE0_API_TOKEN)}" | |
25 | RCODE0_URL="${RCODE0_URL:-$(_readaccountconf_mutable RCODE0_URL)}" | |
26 | RCODE0_TTL="${RCODE0_TTL:-$(_readaccountconf_mutable RCODE0_TTL)}" | |
27 | ||
28 | if [ -z "$RCODE0_URL" ]; then | |
29 | RCODE0_URL="$DEFAULT_RCODE0_URL" | |
30 | fi | |
31 | ||
32 | if [ -z "$RCODE0_API_TOKEN" ]; then | |
33 | RCODE0_API_TOKEN="" | |
34 | _err "Missing Rcode0 ACME API Token." | |
35 | _err "Please login and create your token at httsp://my.rcodezero.at/enableapi and try again." | |
36 | return 1 | |
37 | fi | |
38 | ||
39 | if [ -z "$RCODE0_TTL" ]; then | |
40 | RCODE0_TTL="$DEFAULT_RCODE0_TTL" | |
41 | fi | |
42 | ||
43 | #save the token to the account conf file. | |
44 | _saveaccountconf_mutable RCODE0_API_TOKEN "$RCODE0_API_TOKEN" | |
45 | ||
46 | if [ "$RCODE0_URL" != "$DEFAULT_RCODE0_URL" ]; then | |
47 | _saveaccountconf_mutable RCODE0_URL "$RCODE0_URL" | |
48 | fi | |
49 | ||
50 | if [ "$RCODE0_TTL" != "$DEFAULT_RCODE0_TTL" ]; then | |
51 | _saveaccountconf_mutable RCODE0_TTL "$RCODE0_TTL" | |
52 | fi | |
53 | ||
54 | _debug "Detect root zone" | |
55 | if ! _get_root "$fulldomain"; then | |
56 | _err "No 'MASTER' zone for $fulldomain found at RcodeZero Anycast." | |
57 | return 1 | |
58 | fi | |
59 | _debug _domain "$_domain" | |
60 | ||
61 | _debug "Adding record" | |
62 | ||
63 | _record_string="" | |
64 | _build_record_string "$txtvalue" | |
65 | _list_existingchallenges | |
66 | for oldchallenge in $_existing_challenges; do | |
67 | _build_record_string "$oldchallenge" | |
68 | done | |
69 | ||
70 | _debug "Challenges: $_existing_challenges" | |
71 | ||
72 | if [ -z "$_existing_challenges" ]; then | |
73 | if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"add\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then | |
74 | _err "Add txt record error." | |
75 | return 1 | |
76 | fi | |
77 | else | |
78 | # try update in case a records exists (need for wildcard certs) | |
79 | if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"update\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then | |
80 | _err "Set txt record error." | |
81 | return 1 | |
82 | fi | |
83 | fi | |
84 | ||
85 | return 0 | |
86 | } | |
87 | ||
88 | #fulldomain txtvalue | |
89 | dns_rcode0_rm() { | |
90 | fulldomain=$1 | |
91 | txtvalue=$2 | |
92 | ||
93 | RCODE0_API_TOKEN="${RCODE0_API_TOKEN:-$(_readaccountconf_mutable RCODE0_API_TOKEN)}" | |
94 | RCODE0_URL="${RCODE0_URL:-$(_readaccountconf_mutable RCODE0_URL)}" | |
95 | RCODE0_TTL="${RCODE0_TTL:-$(_readaccountconf_mutable RCODE0_TTL)}" | |
96 | ||
97 | if [ -z "$RCODE0_URL" ]; then | |
98 | RCODE0_URL="$DEFAULT_RCODE0_URL" | |
99 | fi | |
100 | ||
101 | if [ -z "$RCODE0_API_TOKEN" ]; then | |
102 | RCODE0_API_TOKEN="" | |
103 | _err "Missing Rcode0 API Token." | |
104 | _err "Please login and create your token at httsp://my.rcodezero.at/enableapi and try again." | |
105 | return 1 | |
106 | fi | |
107 | ||
108 | #save the api addr and key to the account conf file. | |
109 | _saveaccountconf_mutable RCODE0_URL "$RCODE0_URL" | |
110 | _saveaccountconf_mutable RCODE0_API_TOKEN "$RCODE0_API_TOKEN" | |
111 | ||
112 | if [ "$RCODE0_TTL" != "$DEFAULT_RCODE0_TTL" ]; then | |
113 | _saveaccountconf_mutable RCODE0_TTL "$RCODE0_TTL" | |
114 | fi | |
115 | ||
116 | if [ -z "$RCODE0_TTL" ]; then | |
117 | RCODE0_TTL="$DEFAULT_RCODE0_TTL" | |
118 | fi | |
119 | ||
120 | _debug "Detect root zone" | |
121 | if ! _get_root "$fulldomain"; then | |
122 | _err "invalid domain" | |
123 | return 1 | |
124 | fi | |
125 | ||
126 | _debug "Remove record" | |
127 | ||
128 | #Enumerate existing acme challenges | |
129 | _list_existingchallenges | |
130 | ||
131 | if _contains "$_existing_challenges" "$txtvalue"; then | |
132 | #Delete all challenges (PowerDNS API does not allow to delete content) | |
133 | if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"delete\", \"name\": \"$fulldomain.\", \"type\": \"TXT\"}]"; then | |
134 | _err "Delete txt record error." | |
135 | return 1 | |
136 | fi | |
137 | _record_string="" | |
138 | #If the only existing challenge was the challenge to delete: nothing to do | |
139 | if ! [ "$_existing_challenges" = "$txtvalue" ]; then | |
140 | for oldchallenge in $_existing_challenges; do | |
141 | #Build up the challenges to re-add, ommitting the one what should be deleted | |
142 | if ! [ "$oldchallenge" = "$txtvalue" ]; then | |
143 | _build_record_string "$oldchallenge" | |
144 | fi | |
145 | done | |
146 | #Recreate the existing challenges | |
147 | if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"update\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then | |
148 | _err "Set txt record error." | |
149 | return 1 | |
150 | fi | |
151 | fi | |
152 | else | |
153 | _info "Record not found, nothing to remove" | |
154 | fi | |
155 | ||
156 | return 0 | |
157 | } | |
158 | ||
159 | #################### Private functions below ################################## | |
160 | #_acme-challenge.www.domain.com | |
161 | #returns | |
162 | # _domain=domain.com | |
163 | _get_root() { | |
164 | domain=$1 | |
165 | i=1 | |
166 | ||
167 | while true; do | |
168 | h=$(printf "%s" "$domain" | cut -d . -f $i-100) | |
169 | ||
170 | _debug "try to find: $h" | |
171 | if _rcode0_rest "GET" "/api/v1/acme/zones/$h"; then | |
172 | if [ "$response" = "[\"found\"]" ]; then | |
173 | _domain="$h" | |
174 | if [ -z "$h" ]; then | |
175 | _domain="=2E" | |
176 | fi | |
177 | return 0 | |
178 | elif [ "$response" = "[\"not a master domain\"]" ]; then | |
179 | return 1 | |
180 | fi | |
181 | fi | |
182 | ||
183 | if [ -z "$h" ]; then | |
184 | return 1 | |
185 | fi | |
186 | i=$(_math $i + 1) | |
187 | done | |
188 | _debug "no matching domain for $domain found" | |
189 | ||
190 | return 1 | |
191 | } | |
192 | ||
193 | _rcode0_rest() { | |
194 | method=$1 | |
195 | ep=$2 | |
196 | data=$3 | |
197 | ||
198 | export _H1="Authorization: Bearer $RCODE0_API_TOKEN" | |
199 | ||
200 | if [ ! "$method" = "GET" ]; then | |
201 | _debug data "$data" | |
202 | response="$(_post "$data" "$RCODE0_URL$ep" "" "$method")" | |
203 | else | |
204 | response="$(_get "$RCODE0_URL$ep")" | |
205 | fi | |
206 | ||
207 | if [ "$?" != "0" ]; then | |
208 | _err "error $ep" | |
209 | return 1 | |
210 | fi | |
211 | _debug2 response "$response" | |
212 | ||
213 | return 0 | |
214 | } | |
215 | ||
216 | _build_record_string() { | |
217 | _record_string="${_record_string:+${_record_string}, }{\"content\": \"\\\"${1}\\\"\", \"disabled\": false}" | |
218 | } | |
219 | ||
220 | _list_existingchallenges() { | |
221 | _rcode0_rest "GET" "/api/v1/acme/zones/$_domain/rrsets" | |
222 | _existing_challenges=$(echo "$response" | _normalizeJson | _egrep_o "\"name\":\"${fulldomain}[^]]*}" | _egrep_o 'content\":\"\\"[^\\]*' | sed -n 's/^content":"\\"//p') | |
223 | _debug2 "$_existing_challenges" | |
224 | } |