]> git.proxmox.com Git - proxmox-acme.git/blob - src/proxmox-acme
b4e01d8299eb85e0e93240594eed93ccf1cd28e8
[proxmox-acme.git] / src / proxmox-acme
1 #!/usr/bin/env sh
2
3 HTTP_HEADER="$(mktemp)"
4
5 _base64() {
6 openssl base64 -e | tr -d '\r\n'
7 }
8
9 _dbase64() {
10 openssl base64 -d
11 }
12
13 # Usage: hashalg [outputhex]
14 # Output Base64-encoded digest
15 _digest() {
16 alg="$1"
17
18 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
19 if [ "$2" ]; then
20 openssl dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
21 else
22 openssl dgst -"$alg" -binary | _base64
23 fi
24 fi
25 }
26
27 _upper_case() {
28 # shellcheck disable=SC2018,SC2019
29 tr 'a-z' 'A-Z'
30 }
31
32 _lower_case() {
33 # shellcheck disable=SC2018,SC2019
34 tr 'A-Z' 'a-z'
35 }
36
37 _startswith() {
38 _str="$1"
39 _sub="$2"
40 echo "$_str" | grep "^$_sub" >/dev/null 2>&1
41 }
42
43 _endswith() {
44 _str="$1"
45 _sub="$2"
46 echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1
47 }
48
49 _contains() {
50 _str="$1"
51 _sub="$2"
52 echo "$_str" | grep -- "$_sub" >/dev/null 2>&1
53 }
54
55 # str index [sep]
56 _getfield() {
57 _str="$1"
58 _findex="$2"
59 _sep="$3"
60
61 if [ -z "$_sep" ]; then
62 _sep=","
63 fi
64
65 _ffi="$_findex"
66 while [ "$_ffi" -gt "0" ]; do
67 _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")"
68 if [ "$_fv" ]; then
69 printf -- "%s" "$_fv"
70 return 0
71 fi
72 _ffi="$(_math "$_ffi" - 1)"
73 done
74
75 printf -- "%s" "$_str"
76
77 }
78
79 _exists() {
80 cmd="$1"
81 if eval type type >/dev/null 2>&1; then
82 type "$cmd" >/dev/null 2>&1
83 else command
84 command -v "$cmd" >/dev/null 2>&1
85 fi
86 ret="$?"
87 return $ret
88 }
89
90 # a + b
91 _math() {
92 _m_opts="$@"
93 printf "%s" "$(($_m_opts))"
94 }
95
96 _egrep_o() {
97 if ! egrep -o "$1" 2>/dev/null; then
98 sed -n 's/.*\('"$1"'\).*/\1/p'
99 fi
100 }
101
102 # body url [needbase64] [POST|PUT|DELETE] [ContentType]
103 _post() {
104 body="$1"
105 _post_url="$2"
106 needbase64="$3"
107 httpmethod="$4"
108 _postContentType="$5"
109
110 if [ -z "$httpmethod" ]; then
111 httpmethod="POST"
112 fi
113
114 _CURL="curl -L --silent --dump-header $HTTP_HEADER -g "
115 if [ "$HTTPS_INSECURE" ]; then
116 _CURL="$_CURL --insecure "
117 fi
118 if [ "$httpmethod" = "HEAD" ]; then
119 _CURL="$_CURL -I "
120 fi
121 if [ "$needbase64" ]; then
122 if [ "$body" ]; then
123 if [ "$_postContentType" ]; then
124 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
125 else
126 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
127 fi
128 else
129 if [ "$_postContentType" ]; then
130 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)"
131 else
132 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)"
133 fi
134 fi
135 else
136 if [ "$body" ]; then
137 if [ "$_postContentType" ]; then
138 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
139 else
140 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
141 fi
142 else
143 if [ "$_postContentType" ]; then
144 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")"
145 else
146 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")"
147 fi
148 fi
149 fi
150 _ret="$?"
151 if [ "$_ret" != "0" ]; then
152 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
153 fi
154 printf "%s" "$response"
155 return $_ret
156 }
157
158 # url getheader timeout
159 _get() {
160 url="$1"
161 onlyheader="$2"
162 t="$3"
163
164 _CURL="curl -L --silent --dump-header $HTTP_HEADER -g "
165 if [ "$HTTPS_INSECURE" ]; then
166 _CURL="$_CURL --insecure "
167 fi
168 if [ "$t" ]; then
169 _CURL="$_CURL --connect-timeout $t"
170 fi
171 if [ "$onlyheader" ]; then
172 $_CURL -I --user-agent "USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
173 else
174 $_CURL --user-agent "USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
175 fi
176 ret=$?
177 if [ "$ret" != "0" ]; then
178 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
179 fi
180 return $ret
181 }
182
183 _head_n() {
184 head -n "$1"
185 }
186
187 _tail_n() {
188 tail -n "$1"
189 }
190
191 # stdin output hexstr splited by one space
192 # input:"abc"
193 # output: " 61 62 63"
194 _hex_dump() {
195 od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n"
196 }
197
198 # stdin stdout
199 _url_encode() {
200 _hex_str=$(_hex_dump)
201 for _hex_code in $_hex_str; do
202 #upper case
203 case "${_hex_code}" in
204 "41")
205 printf "%s" "A"
206 ;;
207 "42")
208 printf "%s" "B"
209 ;;
210 "43")
211 printf "%s" "C"
212 ;;
213 "44")
214 printf "%s" "D"
215 ;;
216 "45")
217 printf "%s" "E"
218 ;;
219 "46")
220 printf "%s" "F"
221 ;;
222 "47")
223 printf "%s" "G"
224 ;;
225 "48")
226 printf "%s" "H"
227 ;;
228 "49")
229 printf "%s" "I"
230 ;;
231 "4a")
232 printf "%s" "J"
233 ;;
234 "4b")
235 printf "%s" "K"
236 ;;
237 "4c")
238 printf "%s" "L"
239 ;;
240 "4d")
241 printf "%s" "M"
242 ;;
243 "4e")
244 printf "%s" "N"
245 ;;
246 "4f")
247 printf "%s" "O"
248 ;;
249 "50")
250 printf "%s" "P"
251 ;;
252 "51")
253 printf "%s" "Q"
254 ;;
255 "52")
256 printf "%s" "R"
257 ;;
258 "53")
259 printf "%s" "S"
260 ;;
261 "54")
262 printf "%s" "T"
263 ;;
264 "55")
265 printf "%s" "U"
266 ;;
267 "56")
268 printf "%s" "V"
269 ;;
270 "57")
271 printf "%s" "W"
272 ;;
273 "58")
274 printf "%s" "X"
275 ;;
276 "59")
277 printf "%s" "Y"
278 ;;
279 "5a")
280 printf "%s" "Z"
281 ;;
282
283 #lower case
284 "61")
285 printf "%s" "a"
286 ;;
287 "62")
288 printf "%s" "b"
289 ;;
290 "63")
291 printf "%s" "c"
292 ;;
293 "64")
294 printf "%s" "d"
295 ;;
296 "65")
297 printf "%s" "e"
298 ;;
299 "66")
300 printf "%s" "f"
301 ;;
302 "67")
303 printf "%s" "g"
304 ;;
305 "68")
306 printf "%s" "h"
307 ;;
308 "69")
309 printf "%s" "i"
310 ;;
311 "6a")
312 printf "%s" "j"
313 ;;
314 "6b")
315 printf "%s" "k"
316 ;;
317 "6c")
318 printf "%s" "l"
319 ;;
320 "6d")
321 printf "%s" "m"
322 ;;
323 "6e")
324 printf "%s" "n"
325 ;;
326 "6f")
327 printf "%s" "o"
328 ;;
329 "70")
330 printf "%s" "p"
331 ;;
332 "71")
333 printf "%s" "q"
334 ;;
335 "72")
336 printf "%s" "r"
337 ;;
338 "73")
339 printf "%s" "s"
340 ;;
341 "74")
342 printf "%s" "t"
343 ;;
344 "75")
345 printf "%s" "u"
346 ;;
347 "76")
348 printf "%s" "v"
349 ;;
350 "77")
351 printf "%s" "w"
352 ;;
353 "78")
354 printf "%s" "x"
355 ;;
356 "79")
357 printf "%s" "y"
358 ;;
359 "7a")
360 printf "%s" "z"
361 ;;
362
363 #numbers
364 "30")
365 printf "%s" "0"
366 ;;
367 "31")
368 printf "%s" "1"
369 ;;
370 "32")
371 printf "%s" "2"
372 ;;
373 "33")
374 printf "%s" "3"
375 ;;
376 "34")
377 printf "%s" "4"
378 ;;
379 "35")
380 printf "%s" "5"
381 ;;
382 "36")
383 printf "%s" "6"
384 ;;
385 "37")
386 printf "%s" "7"
387 ;;
388 "38")
389 printf "%s" "8"
390 ;;
391 "39")
392 printf "%s" "9"
393 ;;
394 "2d")
395 printf "%s" "-"
396 ;;
397 "5f")
398 printf "%s" "_"
399 ;;
400 "2e")
401 printf "%s" "."
402 ;;
403 "7e")
404 printf "%s" "~"
405 ;;
406
407 #other hex
408 *)
409 printf '%%%s' "$_hex_code"
410 ;;
411 esac
412 done
413 }
414
415 # Usage: hashalg secret_hex [outputhex]
416 # Output binary hmac
417 _hmac() {
418 alg="$1"
419 secret_hex="$2"
420 outputhex="$3"
421
422 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
423 if [ "$outputhex" ]; then
424 (openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || openssl dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' '
425 else
426 openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || openssl dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary
427 fi
428 fi
429 }
430
431 # domain
432 _is_idn() {
433 _is_idn_d="$1"
434 _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-_')
435 [ "$_idn_temp" ]
436 }
437
438 # aa.com
439 _idn() {
440 __idn_d="$1"
441 if ! _is_idn "$__idn_d"; then
442 printf "%s" "$__idn_d"
443 return 0
444 fi
445
446 if _exists idn; then
447 idn "$__idn_d" | tr -d "\r\n"
448 else
449 _err "Please install idn to process IDN names."
450 fi
451 }
452
453 _normalizeJson() {
454 sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
455 }
456
457 # options file
458 _sed_i() {
459 sed -i "$1" "$2"
460 }
461
462 # sleep sec
463 _sleep() {
464 sleep "$1"
465 }
466
467 _stat() {
468 stat -c '%U:%G' "$1" 2>/dev/null
469 }
470
471 _time() {
472 date -u "+%s"
473 }
474
475 _utc_date() {
476 date -u "+%Y-%m-%d %H:%M:%S"
477 }
478
479 # stubbed/aliased:
480 __green() {
481 printf -- "%b" "$1"
482 }
483
484 __red() {
485 printf -- "%b" "$1"
486 }
487
488 _log() {
489 return
490 }
491
492 _info() {
493 printf -- "%s" "[$(date)] " >&1
494 echo "$1"
495 }
496
497 _err() {
498 printf -- "%s" "[$(date)] " >&2
499 if [ -z "$2" ]; then
500 __red "$1" >&2
501 else
502 __red "$1='$2'" >&2
503 fi
504 printf "\n" >&2
505 return 1
506 }
507
508 # key
509 _readaccountconf() {
510 echo "$1"
511 }
512
513 # key
514 _readaccountconf_mutable() {
515 _readaccountconf "$1"
516 }
517
518 # no-ops:
519 _clearaccountconf() {
520 return
521 }
522
523 _cleardomainconf() {
524 return
525 }
526
527 _debug() {
528 return
529 }
530
531 _debug2() {
532 return
533 }
534
535 _debug3() {
536 return
537 }
538
539 _secure_debug() {
540 return
541 }
542
543 _secure_debug2() {
544 return
545 }
546
547 _secure_debug3() {
548 return
549 }
550
551 _saveaccountconf() {
552 return
553 }
554
555 _saveaccountconf_mutable() {
556 return
557 }
558
559 _save_conf() {
560 return
561 }
562
563 _savedomainconf() {
564 return
565 }
566
567 _source_plugin_config() {
568 return
569 }
570
571 # Proxmox implementation to inject the DNSAPI variables
572 _load_plugin_config() {
573 tmp_str="${plugin_conf_string//[^,]}"
574 index="$(_math ${#tmp_str} + 1)"
575 while [ "$index" -gt "0" ]
576 do
577 field=$(_getfield $plugin_conf_string "$index" ",")
578 ADDR=(${field/=/ })
579 key="${ADDR[0]}"
580 value="${ADDR[1]}"
581
582 # decode base64 encoded values
583 value=$(echo $value | /usr/bin/openssl base64 -d -A)
584
585 # acme.sh uses eval insted of export
586 export "$key"="$value"
587 index="$(_math "$index" - 1)"
588 done
589 }