]> git.proxmox.com Git - mirror_acme.sh.git/commitdiff
Add support for Google Domains DNS API.
authorAlex Leigh <leigh@alexleigh.me>
Tue, 7 Mar 2023 10:31:27 +0000 (02:31 -0800)
committerAlex Leigh <leigh@alexleigh.me>
Wed, 8 Mar 2023 19:13:25 +0000 (11:13 -0800)
https://domains.google/learn/gts-acme/

This is an ACME API for Google Domains customers, which is
different from the Google Cloud Domains API for Google Cloud
customers.

dnsapi/dns_googledomains.sh [new file with mode: 0755]

diff --git a/dnsapi/dns_googledomains.sh b/dnsapi/dns_googledomains.sh
new file mode 100755 (executable)
index 0000000..63e3073
--- /dev/null
@@ -0,0 +1,173 @@
+#!/usr/bin/env sh
+
+# Author: Alex Leigh <leigh at alexleigh dot me>
+# Created: 2023-03-02
+
+#GOOGLEDOMAINS_ACCESS_TOKEN="xxxx"
+#GOOGLEDOMAINS_ZONE="xxxx"
+GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets"
+
+######## Public functions ########
+
+#Usage: dns_googledomains_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_googledomains_add() {
+  fulldomain=$1
+  txtvalue=$2
+
+  _info "Invoking Google Domains ACME DNS API."
+
+  if ! _dns_googledomains_setup; then
+    return 1
+  fi
+
+  zone="$(_dns_googledomains_get_zone "$fulldomain")"
+  if [ -z "$zone" ]; then
+    _err "Could not find a Google Domains-managed zone containing the requested domain."
+    return 1
+  fi
+
+  _debug zone "$zone"
+  _debug txtvalue "$txtvalue"
+
+  _info "Adding TXT record for $fulldomain."
+  if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToAdd\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
+    if _contains "$response" "$txtvalue"; then
+      _info "TXT record added."
+      return 0
+    else
+      _err "Error adding TXT record."
+      return 1
+    fi
+  fi
+
+  _err "Error adding TXT record."
+  return 1
+}
+
+#Usage: dns_googledomains_rm   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_googledomains_rm() {
+  fulldomain=$1
+  txtvalue=$2
+
+  _info "Invoking Google Domains ACME DNS API."
+
+  if ! _dns_googledomains_setup; then
+    return 1
+  fi
+
+  zone="$(_dns_googledomains_get_zone "$fulldomain")"
+  if [ -z "$zone" ]; then
+    _err "Could not find a Google Domains-managed domain based on request."
+    return 1
+  fi
+
+  _debug zone "$zone"
+  _debug txtvalue "$txtvalue"
+
+  _info "Removing TXT record for $fulldomain."
+  if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToRemove\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
+    if _contains "$response" "$txtvalue"; then
+      _err "Error removing TXT record."
+      return 1
+    else
+      _info "TXT record removed."
+      return 0
+    fi
+  fi
+
+  _err "Error removing TXT record."
+  return 1
+}
+
+######## Private functions ########
+
+_dns_googledomains_setup() {
+  if [ -n "$GOOGLEDOMAINS_SETUP_COMPLETED" ]; then
+    return 0
+  fi
+
+  GOOGLEDOMAINS_ACCESS_TOKEN="${GOOGLEDOMAINS_ACCESS_TOKEN:-$(_readaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN)}"
+  GOOGLEDOMAINS_ZONE="${GOOGLEDOMAINS_ZONE:-$(_readaccountconf_mutable GOOGLEDOMAINS_ZONE)}"
+
+  if [ -z "$GOOGLEDOMAINS_ACCESS_TOKEN" ]; then
+    GOOGLEDOMAINS_ACCESS_TOKEN=""
+    _err "Google Domains access token was not specified."
+    _err "Please visit Google Domains Security settings to provision an ACME DNS API access token."
+    return 1
+  fi
+
+  if [ "$GOOGLEDOMAINS_ZONE" ]; then
+    _savedomainconf GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
+    _savedomainconf GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
+  else
+    _saveaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
+    _clearaccountconf_mutable GOOGLEDOMAINS_ZONE
+    _clearaccountconf GOOGLEDOMAINS_ZONE
+  fi
+
+  _debug GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
+  _debug GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
+
+  GOOGLEDOMAINS_SETUP_COMPLETED=1
+  return 0
+}
+
+_dns_googledomains_get_zone() {
+  domain=$1
+
+  # Use zone directly if provided
+  if [ "$GOOGLEDOMAINS_ZONE" ]; then
+    if ! _dns_googledomains_api "$GOOGLEDOMAINS_ZONE"; then
+      return 1
+    fi
+
+    echo "$GOOGLEDOMAINS_ZONE"
+    return 0
+  fi
+
+  i=2
+  while true; do
+    curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
+    _debug curr "$curr"
+
+    if [ -z "$curr" ]; then
+      return 1
+    fi
+
+    if _dns_googledomains_api "$curr"; then
+      echo "$curr"
+      return 0
+    fi
+
+    i=$(_math "$i" + 1)
+  done
+
+  return 1
+}
+
+_dns_googledomains_api() {
+  zone=$1
+  apimethod=$2
+  data="$3"
+
+  if [ -z "$data" ]; then
+    response="$(_get "$GOOGLEDOMAINS_API/$zone$apimethod")"
+  else
+    _debug data "$data"
+    export _H1="Content-Type: application/json"
+    response="$(_post "$data" "$GOOGLEDOMAINS_API/$zone$apimethod")"
+  fi
+
+  _debug response "$response"
+
+  if [ "$?" != "0" ]; then
+    _err "Error"
+    return 1
+  fi
+
+  if _contains "$response" "\"error\": {"; then
+    return 1
+  fi
+
+  return 0
+}