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.

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