Skip to content

Commit bdd1058

Browse files
committed
Add support for Google Domains DNS API.
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.
1 parent 799e402 commit bdd1058

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

dnsapi/dns_googledomains.sh

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#!/usr/bin/env sh
2+
3+
# Author: Alex Leigh <leigh at alexleigh dot me>
4+
# Created: 2023-03-02
5+
6+
#GOOGLEDOMAINS_ACCESS_TOKEN="xxxx"
7+
#GOOGLEDOMAINS_ZONE="xxxx"
8+
GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets"
9+
10+
######## Public functions ########
11+
12+
#Usage: dns_googledomains_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
13+
dns_googledomains_add() {
14+
fulldomain=$1
15+
txtvalue=$2
16+
17+
_info "Invoking Google Domains ACME DNS API."
18+
19+
if ! _dns_googledomains_setup; then
20+
return 1
21+
fi
22+
23+
zone="$(_dns_googledomains_get_zone "$fulldomain")"
24+
if [ -z "$zone" ]; then
25+
_err "Could not find a Google Domains-managed domain based on request."
26+
return 1
27+
fi
28+
29+
_debug zone "$zone"
30+
_debug txtvalue "$txtvalue"
31+
32+
_info "Adding TXT record for $fulldomain."
33+
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToAdd\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
34+
if _contains "$response" "$txtvalue"; then
35+
_info "TXT record added."
36+
return 0
37+
else
38+
_err "Error adding TXT record."
39+
return 1
40+
fi
41+
fi
42+
43+
_err "Error adding TXT record."
44+
return 1
45+
}
46+
47+
#Usage: dns_googledomains_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
48+
dns_googledomains_rm() {
49+
fulldomain=$1
50+
txtvalue=$2
51+
52+
_info "Invoking Google Domains ACME DNS API."
53+
54+
if ! _dns_googledomains_setup; then
55+
return 1
56+
fi
57+
58+
zone="$(_dns_googledomains_get_zone "$fulldomain")"
59+
if [ -z "$zone" ]; then
60+
_err "Could not find a Google Domains-managed domain based on request."
61+
return 1
62+
fi
63+
64+
_debug zone "$zone"
65+
_debug txtvalue "$txtvalue"
66+
67+
_info "Removing TXT record for $fulldomain."
68+
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToRemove\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
69+
if _contains "$response" "$txtvalue"; then
70+
_err "Error removing TXT record."
71+
return 1
72+
else
73+
_info "TXT record removed."
74+
return 0
75+
fi
76+
fi
77+
78+
_err "Error removing TXT record."
79+
return 1
80+
}
81+
82+
######## Private functions ########
83+
84+
_dns_googledomains_setup() {
85+
if [ -n "$GOOGLEDOMAINS_SETUP_COMPLETED" ]; then
86+
return 0
87+
fi
88+
89+
GOOGLEDOMAINS_ACCESS_TOKEN="${GOOGLEDOMAINS_ACCESS_TOKEN:-$(_readaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN)}"
90+
GOOGLEDOMAINS_ZONE="${GOOGLEDOMAINS_ZONE:-$(_readaccountconf_mutable GOOGLEDOMAINS_ZONE)}"
91+
92+
if [ -z "$GOOGLEDOMAINS_ACCESS_TOKEN" ]; then
93+
GOOGLEDOMAINS_ACCESS_TOKEN=""
94+
_err "Google Domains access token was not specified."
95+
_err "Please visit Google Domains Security settings to provision an ACME DNS API access token."
96+
return 1
97+
fi
98+
99+
# Save the access token to the domain conf file. Google Domains API requires
100+
# different access tokens per zone, so we can't save to account conf.
101+
_savedomainconf GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
102+
103+
if [ "$GOOGLEDOMAINS_ZONE" ]; then
104+
_savedomainconf GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
105+
fi
106+
107+
_debug GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
108+
_debug GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
109+
110+
GOOGLEDOMAINS_SETUP_COMPLETED=1
111+
return 0
112+
}
113+
114+
_dns_googledomains_get_zone() {
115+
domain=$1
116+
117+
# Use zone directly if provided
118+
if [ "$GOOGLEDOMAINS_ZONE" ]; then
119+
if ! _dns_googledomains_api "$GOOGLEDOMAINS_ZONE"; then
120+
return 1
121+
fi
122+
123+
echo "$GOOGLEDOMAINS_ZONE"
124+
return 0
125+
fi
126+
127+
i=2
128+
while true; do
129+
curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
130+
_debug curr "$curr"
131+
132+
if [ -z "$curr" ]; then
133+
return 1
134+
fi
135+
136+
if _dns_googledomains_api "$curr"; then
137+
echo "$curr"
138+
return 0
139+
fi
140+
141+
i=$(_math "$i" + 1)
142+
done
143+
144+
return 1
145+
}
146+
147+
_dns_googledomains_api() {
148+
zone=$1
149+
apimethod=$2
150+
data="$3"
151+
152+
if [ -z "$data" ]; then
153+
response="$(_get "$GOOGLEDOMAINS_API/$zone$apimethod")"
154+
else
155+
_debug data "$data"
156+
export _H1="Content-Type: application/json"
157+
response="$(_post "$data" "$GOOGLEDOMAINS_API/$zone$apimethod")"
158+
fi
159+
160+
_debug response "$response"
161+
162+
if [ "$?" != "0" ]; then
163+
_err "Error"
164+
return 1
165+
fi
166+
167+
if _contains "$response" "\"error\": {"; then
168+
return 1
169+
fi
170+
171+
return 0
172+
}

0 commit comments

Comments
 (0)