2 # Mythic Beasts is a long-standing UK service provider using standards-based OAuth2 authentication
3 # To test: ./acme.sh --dns dns_mythic_beasts --test --debug 1 --output-insecure --issue --domain domain.com
4 # Cannot retest once cert is issued
5 # OAuth2 tokens only valid for 300 seconds so we do not store
6 # NOTE: This will remove all TXT records matching the fulldomain, not just the added ones (_acme-challenge.www.domain.com)
8 # Test OAuth2 credentials
9 #MB_AK="aaaaaaaaaaaaaaaa"
10 #MB_AS="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
13 MB_API
='https://api.mythic-beasts.com/dns/v2/zones'
14 MB_AUTH
='https://auth.mythic-beasts.com/login'
16 ######## Public functions #####################
18 #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
19 dns_mythic_beasts_add
() {
23 _info
"MYTHIC BEASTS Adding record $fulldomain = $txtvalue"
28 if ! _get_root
"$fulldomain"; then
32 # method path body_data
33 if _mb_rest POST
"$_domain/records/$_sub_domain/TXT" "$txtvalue"; then
35 if _contains
"$response" "1 records added"; then
36 _info
"Added, verifying..."
37 # Max 120 seconds to publish
38 for i
in $
(seq 1 6); do
40 if ! _mb_rest GET
"$_domain/records/$_sub_domain/TXT?verify"; then
43 _info
"Record published!"
53 _err
"Add txt record error."
57 #Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
58 dns_mythic_beasts_rm
() {
62 _info
"MYTHIC BEASTS Removing record $fulldomain = $txtvalue"
67 if ! _get_root
"$fulldomain"; then
71 # method path body_data
72 if _mb_rest DELETE
"$_domain/records/$_sub_domain/TXT" "$txtvalue"; then
73 _info
"Record removed"
76 _err
"Remove txt record error."
80 #################### Private functions below ##################################
83 # _acme-challenge.www.example.com
84 # _acme-challenge.example.com
85 # _acme-challenge.example.co.uk
86 # _acme-challenge.www.example.co.uk
87 # _acme-challenge.sub1.sub2.www.example.co.uk
88 # sub1.sub2.example.co.uk
92 # _sub_domain=_acme-challenge.www
99 _debug
"Detect the root zone"
101 h
=$
(printf "%s" "$domain" | cut
-d .
-f $i-100)
103 _err
"Domain exhausted"
107 # Use the status errors to find the domain, continue on 403 Access denied
108 # method path body_data
109 _mb_rest GET
"$h/records"
111 if [ "$ret" -eq 0 ]; then
112 _sub_domain
=$
(printf "%s" "$domain" | cut
-d .
-f 1-$p)
114 _debug _sub_domain
"$_sub_domain"
115 _debug _domain
"$_domain"
117 elif [ "$ret" -eq 1 ]; then
124 if [ "$i" -gt 50 ]; then
128 _err
"Domain too long"
133 MB_AK
="${MB_AK:-$(_readaccountconf_mutable MB_AK)}"
134 MB_AS
="${MB_AS:-$(_readaccountconf_mutable MB_AS)}"
136 if [ -z "$MB_AK" ] ||
[ -z "$MB_AS" ]; then
139 _err
"Please specify an OAuth2 Key & Secret"
143 _saveaccountconf_mutable MB_AK
"$MB_AK"
144 _saveaccountconf_mutable MB_AS
"$MB_AS"
150 _info
"Checking authentication"
151 _secure_debug access_token
"$MB_TK"
154 # GET a list of zones
155 # method path body_data
156 if ! _mb_rest GET
""; then
157 _err
"The token is invalid"
164 # Github appears to use an outbound proxy for requests which means subsequent requests may not have the same
165 # source IP. The standard Mythic Beasts OAuth2 tokens are tied to an IP, meaning github test requests fail
166 # authentication. This is a work around using an undocumented MB API to obtain a token not tied to an
167 # IP just for the github tests.
169 if [ "$GITHUB_ACTIONS" = "true" ]; then
178 # HTTP Basic Authentication
179 _H1
="Authorization: Basic $(echo "$MB_AK:$MB_AS" | _base64)"
180 _H2
="Accepts: application/json"
182 body
="grant_type=client_credentials"
184 _info
"Getting OAuth2 token..."
185 # body url [needbase64] [POST|PUT|DELETE] [ContentType]
186 response
="$(_post "$body" "$MB_AUTH" "" "POST
" "application
/x-www-form-urlencoded
")"
187 if _contains
"$response" "\"token_type\":\"bearer\""; then
188 MB_TK
="$(echo "$response" | _egrep_o "access_token
\":\"[^
\"]*\"" | cut -d : -f 2 | tr -d '"')"
189 if [ -z "$MB_TK" ]; then
190 _err "Unable to get access_token"
195 _err "OAuth2 token_type not Bearer"
199 _debug2 response "$response"
204 _H1="Accepts: application/json"
206 body="{\"login\":{\"handle\":\"$MB_AK\",\"pass\":\"$MB_AS\",\"floating\":1}}"
208 _info "Getting Floating token..."
209 # body url [needbase64] [POST|PUT|DELETE] [ContentType]
210 response="$(_post "$body" "$MB_AUTH" "" "POST" "application/json")"
211 MB_TK="$(echo "$response" | _egrep_o "\"token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')"
212 if [ -z "$MB_TK" ]; then
213 _err
"Unable to get token"
217 _debug2 response
"$response"
221 # method path body_data
223 # URL encoded body for single API operations
228 if [ -z "$ep" ]; then
231 _mb_url
="$MB_API/$ep"
234 _H1
="Authorization: Bearer $MB_TK"
235 _H2
="Accepts: application/json"
237 if [ "$data" ] ||
[ "$m" = "POST" ] ||
[ "$m" = "PUT" ] ||
[ "$m" = "DELETE" ]; then
238 # body url [needbase64] [POST|PUT|DELETE] [ContentType]
239 response
="$(_post "data
=$data" "$_mb_url" "" "$m" "application
/x-www-form-urlencoded
")"
241 response
="$(_get "$_mb_url")"
244 if [ "$?" != "0" ]; then
249 header
="$(cat "$HTTP_HEADER")"
250 status
="$(echo "$header" | _egrep_o "^HTTP
[^
]* .
*$
" | cut -d " " -f 2-100 | tr -d "\f\n")"
251 code
="$(echo "$status" | _egrep_o "^
[0-9]*")"
252 if [ "$code" -ge 400 ] || _contains
"$response" "\"error\"" || _contains
"$response" "invalid_client"; then
259 _debug2 response
"$response"