You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
4.0 KiB

  1. #!/usr/bin/env sh
  2. # Supports IONOS Cloud DNS API v1.15.4
  3. #
  4. # Usage:
  5. # Export IONOS_TOKEN before calling acme.sh:
  6. # $ export IONOS_TOKEN="..."
  7. #
  8. # $ acme.sh --issue --dns dns_ionos_cloud ...
  9. IONOS_CLOUD_API="https://dns.de-fra.ionos.com"
  10. IONOS_CLOUD_ROUTE_ZONES="/zones"
  11. dns_ionos_cloud_add() {
  12. fulldomain=$1
  13. txtvalue=$2
  14. if ! _ionos_init; then
  15. return 1
  16. fi
  17. _record_name=$(printf "%s" "$fulldomain" | cut -d . -f 1)
  18. _body="{\"properties\":{\"name\":\"$_record_name\", \"type\":\"TXT\", \"content\":\"$txtvalue\"}}"
  19. if _ionos_cloud_rest POST "$IONOS_CLOUD_ROUTE_ZONES/$_zone_id/records" "$_body" && [ "$_code" = "202" ]; then
  20. _info "TXT record has been created successfully."
  21. return 0
  22. fi
  23. return 1
  24. }
  25. dns_ionos_cloud_rm() {
  26. fulldomain=$1
  27. txtvalue=$2
  28. if ! _ionos_init; then
  29. return 1
  30. fi
  31. if ! _ionos_cloud_get_record "$_zone_id" "$txtvalue" "$fulldomain"; then
  32. _err "Could not find _acme-challenge TXT record."
  33. return 1
  34. fi
  35. if _ionos_cloud_rest DELETE "$IONOS_CLOUD_ROUTE_ZONES/$_zone_id/records/$_record_id" && [ "$_code" = "202" ]; then
  36. _info "TXT record has been deleted successfully."
  37. return 0
  38. fi
  39. return 1
  40. }
  41. _ionos_init() {
  42. IONOS_TOKEN="${IONOS_TOKEN:-$(_readaccountconf_mutable IONOS_TOKEN)}"
  43. if [ -z "$IONOS_TOKEN" ]; then
  44. _err "You didn't specify an IONOS token yet."
  45. _err "Read https://api.ionos.com/docs/authentication/v1/#tag/tokens/operation/tokensGenerate to learn how to get a token."
  46. _err "You need to set it before calling acme.sh:"
  47. _err "\$ export IONOS_TOKEN=\"...\""
  48. _err "\$ acme.sh --issue -d ... --dns dns_ionos_cloud"
  49. return 1
  50. fi
  51. _saveaccountconf_mutable IONOS_TOKEN "$IONOS_TOKEN"
  52. if ! _get_cloud_zone "$fulldomain"; then
  53. _err "Cannot find zone $zone in your IONOS account."
  54. return 1
  55. fi
  56. return 0
  57. }
  58. _get_cloud_zone() {
  59. domain=$1
  60. zone=$(printf "%s" "$domain" | cut -d . -f 2-)
  61. if _ionos_cloud_rest GET "$IONOS_CLOUD_ROUTE_ZONES?filter.zoneName=$zone"; then
  62. _response="$(echo "$_response" | tr -d "\n")"
  63. _zone_list_items=$(echo "$_response" | _egrep_o "\"items\":.*")
  64. _zone_id=$(printf "%s\n" "$_zone_list_items" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
  65. if [ "$_zone_id" ]; then
  66. return 0
  67. fi
  68. fi
  69. return 1
  70. }
  71. _ionos_cloud_get_record() {
  72. zone_id=$1
  73. txtrecord=$2
  74. # this is to transform the domain to lower case
  75. fulldomain=$(printf "%s" "$3" | _lower_case)
  76. # this is to transform record name to lower case
  77. # IONOS Cloud API transforms all record names to lower case
  78. _record_name=$(printf "%s" "$fulldomain" | cut -d . -f 1 | _lower_case)
  79. if _ionos_cloud_rest GET "$IONOS_CLOUD_ROUTE_ZONES/$zone_id/records"; then
  80. _response="$(echo "$_response" | tr -d "\n")"
  81. pattern="\{\"id\":\"[a-fA-F0-9\-]*\",\"type\":\"record\",\"href\":\"/zones/$zone_id/records/[a-fA-F0-9\-]*\",\"metadata\":\{\"createdDate\":\"[A-Z0-9\:\.\-]*\",\"lastModifiedDate\":\"[A-Z0-9\:\.\-]*\",\"fqdn\":\"$fulldomain\",\"state\":\"AVAILABLE\",\"zoneId\":\"$zone_id\"\},\"properties\":\{\"content\":\"$txtrecord\",\"enabled\":true,\"name\":\"$_record_name\",\"priority\":[0-9]*,\"ttl\":[0-9]*,\"type\":\"TXT\"\}\}"
  82. _record="$(echo "$_response" | _egrep_o "$pattern")"
  83. if [ "$_record" ]; then
  84. _record_id=$(printf "%s\n" "$_record" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
  85. return 0
  86. fi
  87. fi
  88. return 1
  89. }
  90. _ionos_cloud_rest() {
  91. method="$1"
  92. route="$2"
  93. data="$3"
  94. export _H1="Authorization: Bearer $IONOS_TOKEN"
  95. # clear headers
  96. : >"$HTTP_HEADER"
  97. if [ "$method" != "GET" ]; then
  98. _response="$(_post "$data" "$IONOS_CLOUD_API$route" "" "$method" "application/json")"
  99. else
  100. _response="$(_get "$IONOS_CLOUD_API$route")"
  101. fi
  102. _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
  103. if [ "$?" != "0" ]; then
  104. _err "Error $route: $_response"
  105. return 1
  106. fi
  107. _debug2 "_response" "$_response"
  108. _debug2 "_code" "$_code"
  109. return 0
  110. }