Skip to content

Commit

Permalink
Add support for Google Domains DNS API.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
alexleigh committed Mar 8, 2023
1 parent 799e402 commit 8aecfa4
Showing 1 changed file with 173 additions and 0 deletions.
173 changes: 173 additions & 0 deletions dnsapi/dns_googledomains.sh
Original file line number Diff line number Diff line change
@@ -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 domain based on request."
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
}

0 comments on commit 8aecfa4

Please sign in to comment.