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.

369 lines
10 KiB

  1. #!/usr/bin/env sh
  2. # shellcheck disable=SC2034
  3. dns_myapi_info='omg.lol
  4. Based on the omg.lol API, defined at https://api.omg.lol/
  5. Domains: omg.lol
  6. Site: github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
  7. Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns
  8. Options:
  9. omglolapikey API Key from omg.lol. This is accesible from the bottom of the account page at https://home.omg.lol/account
  10. omgloladdress This is your omg.lol address, without the preceding @ - you can see your list on your dashboard at https://home.omg.lol/dashboard
  11. Issues: github.com/acmesh-official/acme.sh
  12. Author: @Kholin <kholin+omglolapi@omg.lol>
  13. '
  14. #returns 0 means success, otherwise error.
  15. ######## Public functions #####################
  16. # Please Read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
  17. #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  18. dns_omglol_add() {
  19. fulldomain=$1
  20. txtvalue=$2
  21. omglol_apikey="${omglol_apikey:-$(_readaccountconf_mutable omglol_apikey)}"
  22. omglol_address="${omglol_address:-$(_readaccountconf_mutable omglol_address)}"
  23. # As omg.lol includes a leading @ for their addresses, pre-strip this before save
  24. omglol_address="$(echo "$omglol_address" | tr -d '@')"
  25. _saveaccountconf_mutable omglol_apikey "$omglol_apikey"
  26. _saveaccountconf_mutable omglol_address "$omglol_address"
  27. _info "Using omg.lol."
  28. _debug "Function" "dns_omglol_add()"
  29. _debug "Full Domain Name" "$fulldomain"
  30. _debug "txt Record Value" "$txtvalue"
  31. _secure_debug "omg.lol API key" "$omglol_apikey"
  32. _debug "omg.lol Address" "$omglol_address"
  33. omglol_validate "$omglol_apikey" "$omglol_address" "$fulldomain"
  34. if [ ! $? ]; then
  35. return 1
  36. fi
  37. dnsName=$(_getDnsRecordName "$fulldomain" "$omglol_address")
  38. authHeader="$(_createAuthHeader "$omglol_apikey")"
  39. _debug2 " dns_omglol_add(): Address" "$dnsName"
  40. omglol_add "$omglol_address" "$authHeader" "$dnsName" "$txtvalue"
  41. }
  42. #Usage: fulldomain txtvalue
  43. #Remove the txt record after validation.
  44. dns_omglol_rm() {
  45. fulldomain=$1
  46. txtvalue=$2
  47. omglol_apikey="${omglol_apikey:-$(_readaccountconf_mutable omglol_apikey)}"
  48. omglol_address="${omglol_address:-$(_readaccountconf_mutable omglol_address)}"
  49. # As omg.lol includes a leading @ for their addresses, strip this in case provided
  50. omglol_address="$(echo "$omglol_address" | tr -d '@')"
  51. _info "Using omg.lol"
  52. _debug fulldomain "$fulldomain"
  53. _secure_debug ApiKey "$omglol_apikey"
  54. _debug address "$omglol_address"
  55. omglol_validate "$omglol_apikey" "$omglol_address" "$fulldomain"
  56. if [ ! $? ]; then
  57. return 1
  58. fi
  59. dnsName=$(_getDnsRecordName "$fulldomain" "$omglol_address")
  60. authHeader="$(_createAuthHeader "$omglol_apikey")"
  61. omglol_delete "$omglol_address" "$authHeader" "$dnsName" "$txtvalue"
  62. }
  63. #################### Private functions below ##################################
  64. # Check that the minimum requirements are present. Close ungracefully if not
  65. omglol_validate() {
  66. omglol_apikey=$1
  67. omglol_address=$2
  68. fulldomain=$3
  69. if [ "" = "$omglol_address" ]; then
  70. _err "omg.lol base address not provided. Exiting"
  71. return 1
  72. fi
  73. if [ "" = "$omglol_apikey" ]; then
  74. _err "omg.lol API key not provided. Exiting"
  75. return 1
  76. fi
  77. _endswith "$fulldomain" "omg.lol"
  78. if [ ! $? ]; then
  79. _err "Domain name requested is not under omg.lol"
  80. return 1
  81. fi
  82. _endswith "$fulldomain" "$omglol_address.omg.lol"
  83. if [ ! $? ]; then
  84. _err "Domain name is not a subdomain of provided omg.lol address $omglol_address"
  85. return 1
  86. fi
  87. _debug "omglol_validate(): Required environment parameters are all present"
  88. }
  89. # Add (or modify) an entry for a new ACME query
  90. omglol_add() {
  91. address=$1
  92. authHeader=$2
  93. dnsName=$3
  94. txtvalue=$4
  95. _info " Creating DNS entry for $dnsName"
  96. _debug2 " omglol_add()"
  97. _debug2 " omg.lol Address: " "$address"
  98. _secure_debug2 " omg.lol authorization header: " "$authHeader"
  99. _debug2 " Full Domain name:" "$dnsName.$address.omg.lol"
  100. _debug2 " TXT value to set:" "$txtvalue"
  101. export _H1="$authHeader"
  102. endpoint="https://api.omg.lol/address/$address/dns"
  103. _debug2 " Endpoint" "$endpoint"
  104. payload='{"type": "TXT", "name":"'"$dnsName"'", "data":"'"$txtvalue"'", "ttl":30}'
  105. _debug2 " Payload" "$payload"
  106. response=$(_post "$payload" "$endpoint" "" "POST" "application/json")
  107. omglol_validate_add "$response" "$dnsName.$address" "$txtvalue"
  108. }
  109. omglol_validate_add() {
  110. response=$1
  111. name=$2
  112. content=$3
  113. _info " Validating DNS record addition"
  114. _debug2 " omglol_validate_add()"
  115. _debug2 " Response" "$response"
  116. _debug2 " DNS Name" "$name"
  117. _debug2 " DNS value" "$content"
  118. _jsonResponseCheck "$response" "success" "true"
  119. if [ "1" = "$?" ]; then
  120. _err "Response did not report success"
  121. return 1
  122. fi
  123. _jsonResponseCheck "$response" "message" "Your DNS record was created successfully."
  124. if [ "1" = "$?" ]; then
  125. _err "Response message did not indicate DNS record was successfully created"
  126. return 1
  127. fi
  128. _jsonResponseCheck "$response" "name" "$name"
  129. if [ "1" = "$?" ]; then
  130. _err "Response DNS Name did not match the response received"
  131. return 1
  132. fi
  133. _jsonResponseCheck "$response" "content" "$content"
  134. if [ "1" = "$?" ]; then
  135. _err "Response DNS Name did not match the response received"
  136. return 1
  137. fi
  138. _debug " Record Created successfully"
  139. return 0
  140. }
  141. omglol_getRecords() {
  142. address=$1
  143. authHeader=$2
  144. dnsName=$3
  145. txtValue=$4
  146. _debug2 " omglol_getRecords()"
  147. _debug2 " omg.lol Address: " "$address"
  148. _secure_debug2 " omg.lol Auth Header: " "$authHeader"
  149. _debug2 " omg.lol DNS name:" "$dnsName"
  150. _debug2 " txt Value" "$txtValue"
  151. export _H1="$authHeader"
  152. endpoint="https://api.omg.lol/address/$address/dns"
  153. _debug2 " Endpoint" "$endpoint"
  154. payload=$(_get "$endpoint")
  155. _debug2 " Received Payload:" "$payload"
  156. # Reformat the JSON to be more parseable
  157. recordID=$(echo "$payload" | _stripWhitespace)
  158. recordID=$(echo "$recordID" | _exposeJsonArray)
  159. # Now find the one with the right value, and caputre its ID
  160. recordID=$(echo "$recordID" | grep -- "$txtValue" | grep -i -- "$dnsName.$address")
  161. _getJsonElement "$recordID" "id"
  162. }
  163. omglol_delete() {
  164. address=$1
  165. authHeader=$2
  166. dnsName=$3
  167. txtValue=$4
  168. _info " Deleting DNS entry for $dnsName with value $txtValue"
  169. _debug2 " omglol_delete()"
  170. _debug2 " omg.lol Address: " "$address"
  171. _secure_debug2 " omg.lol Auth Header: " "$authHeader"
  172. _debug2 " Full Domain name:" "$dnsName.$address.omg.lol"
  173. _debug2 " txt Value" "$txtValue"
  174. record=$(omglol_getRecords "$address" "$authHeader" "$dnsName" "$txtvalue")
  175. endpoint="https://api.omg.lol/address/$address/dns/$record"
  176. _debug2 " Endpoint" "$endpoint"
  177. export _H1="$authHeader"
  178. output=$(_post "" "$endpoint" "" "DELETE")
  179. _debug2 " Response" "$output"
  180. omglol_validate_delete "$output"
  181. }
  182. # Validate the response on request to delete. Confirm stastus is success and
  183. # Message indicates deletion was successful
  184. # Input: Response - HTTP response received from delete request
  185. omglol_validate_delete() {
  186. response=$1
  187. _info " Validating DNS record deletion"
  188. _debug2 " omglol_validate_delete()"
  189. _debug " Response" "$response"
  190. _jsonResponseCheck "$output" "success" "true"
  191. if [ "1" = "$?" ]; then
  192. _err "Response did not report success"
  193. return 1
  194. fi
  195. _jsonResponseCheck "$output" "message" "OK, your DNS record has been deleted."
  196. if [ "1" = "$?" ]; then
  197. _err "Response message did not indicate DNS record was successfully deleted"
  198. return 1
  199. fi
  200. _info " Record deleted successfully"
  201. return 0
  202. }
  203. ########## Utility Functions #####################################
  204. # All utility functions only log at debug3
  205. _jsonResponseCheck() {
  206. response=$1
  207. field=$2
  208. correct=$3
  209. correct=$(echo "$correct" | _lower_case)
  210. _debug3 " jsonResponseCheck()"
  211. _debug3 " Response to parse" "$response"
  212. _debug3 " Field to get response from" "$field"
  213. _debug3 " What is the correct response" "$correct"
  214. responseValue=$(_jsonGetLastResponse "$response" "$field")
  215. if [ "$responseValue" != "$correct" ]; then
  216. _debug3 " Expected: $correct"
  217. _debug3 " Actual: $responseValue"
  218. return 1
  219. else
  220. _debug3 " Matched: $responseValue"
  221. fi
  222. return 0
  223. }
  224. _jsonGetLastResponse() {
  225. response=$1
  226. field=$2
  227. _debug3 " jsonGetLastResponse()"
  228. _debug3 " Response provided" "$response"
  229. _debug3 " Field to get responses for" "$field"
  230. responseValue=$(echo "$response" | grep -- "\"$field\"" | cut -f2 -d":")
  231. _debug3 " Response lines found:" "$responseValue"
  232. responseValue=$(echo "$responseValue" | sed 's/^ //g' | sed 's/^"//g' | sed 's/\\"//g')
  233. responseValue=$(echo "$responseValue" | sed 's/,$//g' | sed 's/"$//g')
  234. responseValue=$(echo "$responseValue" | _lower_case)
  235. _debug3 " Responses found" "$responseValue"
  236. _debug3 " Response Selected" "$(echo "$responseValue" | tail -1)"
  237. echo "$responseValue" | tail -1
  238. }
  239. _stripWhitespace() {
  240. tr -d '\n' | tr -d '\r' | tr -d '\t' | sed -r 's/ +/ /g' | sed 's/\\"//g'
  241. }
  242. _exposeJsonArray() {
  243. sed -r 's/.*\[//g' | tr '}' '|' | tr '{' '|' | sed 's/|, |/|/g' | tr '|' '\n'
  244. }
  245. _getJsonElement() {
  246. content=$1
  247. field=$2
  248. # With a single JSON entry to parse, convert commas to newlines puts each element on
  249. # its own line - which then allows us to just grep teh name, remove the key, and
  250. # isolate the value
  251. output=$(echo "$content" | tr ',' '\n' | grep -- "\"$field\":" | sed 's/.*: //g')
  252. _debug3 " String before unquoting: $output"
  253. _unquoteString "$output"
  254. }
  255. _createAuthHeader() {
  256. apikey=$1
  257. authheader="Authorization: Bearer $apikey"
  258. _secure_debug2 " Authorization Header" "$authheader"
  259. echo "$authheader"
  260. }
  261. _getDnsRecordName() {
  262. fqdn=$1
  263. address=$2
  264. echo "$fqdn" | sed 's/\.omg\.lol//g' | sed 's/\.'"$address"'$//g'
  265. }
  266. _unquoteString() {
  267. output=$1
  268. quotes=0
  269. _startswith "$output" "\""
  270. if [ $? ]; then
  271. quotes=$((quotes + 1))
  272. fi
  273. _endswith "$output" "\""
  274. if [ $? ]; then
  275. quotes=$((quotes + 1))
  276. fi
  277. _debug3 " Original String: $output"
  278. _debug3 " Quotes found: $quotes"
  279. if [ $((quotes)) -gt 1 ]; then
  280. output=$(echo "$output" | sed 's/^"//g' | sed 's/"$//g')
  281. _debug3 " Quotes removed: $output"
  282. fi
  283. echo "$output"
  284. }