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.

391 lines
10 KiB

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