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.

431 lines
9.5 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. #!/usr/bin/env sh
  2. #
  3. #INWX_User="username"
  4. #
  5. #INWX_Password="password"
  6. #
  7. # Dependencies:
  8. # -------------
  9. # - oathtool (When using 2 Factor Authentication)
  10. INWX_Api="https://api.domrobot.com/xmlrpc/"
  11. ######## Public functions #####################
  12. #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  13. dns_inwx_add() {
  14. fulldomain=$1
  15. txtvalue=$2
  16. INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
  17. INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
  18. INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}"
  19. if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
  20. INWX_User=""
  21. INWX_Password=""
  22. _err "You don't specify inwx user and password yet."
  23. _err "Please create you key and try again."
  24. return 1
  25. fi
  26. #save the api key and email to the account conf file.
  27. _saveaccountconf_mutable INWX_User "$INWX_User"
  28. _saveaccountconf_mutable INWX_Password "$INWX_Password"
  29. _saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret"
  30. if ! _inwx_login; then
  31. return 1
  32. fi
  33. _debug "First detect the root zone"
  34. if ! _get_root "$fulldomain"; then
  35. _err "invalid domain"
  36. return 1
  37. fi
  38. _debug _sub_domain "$_sub_domain"
  39. _debug _domain "$_domain"
  40. _info "Adding record"
  41. _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue"
  42. }
  43. #fulldomain txtvalue
  44. dns_inwx_rm() {
  45. fulldomain=$1
  46. txtvalue=$2
  47. INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
  48. INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
  49. INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}"
  50. if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
  51. INWX_User=""
  52. INWX_Password=""
  53. _err "You don't specify inwx user and password yet."
  54. _err "Please create you key and try again."
  55. return 1
  56. fi
  57. if ! _inwx_login; then
  58. return 1
  59. fi
  60. _debug "First detect the root zone"
  61. if ! _get_root "$fulldomain"; then
  62. _err "invalid domain"
  63. return 1
  64. fi
  65. _debug _sub_domain "$_sub_domain"
  66. _debug _domain "$_domain"
  67. _debug "Getting txt records"
  68. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  69. <methodCall>
  70. <methodName>nameserver.info</methodName>
  71. <params>
  72. <param>
  73. <value>
  74. <struct>
  75. <member>
  76. <name>domain</name>
  77. <value>
  78. <string>%s</string>
  79. </value>
  80. </member>
  81. <member>
  82. <name>type</name>
  83. <value>
  84. <string>TXT</string>
  85. </value>
  86. </member>
  87. <member>
  88. <name>name</name>
  89. <value>
  90. <string>%s</string>
  91. </value>
  92. </member>
  93. </struct>
  94. </value>
  95. </param>
  96. </params>
  97. </methodCall>' "$_domain" "$_sub_domain")
  98. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  99. if ! _contains "$response" "Command completed successfully"; then
  100. _err "Error could not get txt records"
  101. return 1
  102. fi
  103. if ! printf "%s" "$response" | grep "count" >/dev/null; then
  104. _info "Do not need to delete record"
  105. else
  106. _record_id=$(printf '%s' "$response" | _egrep_o '.*(<member><name>record){1}(.*)([0-9]+){1}' | _egrep_o '<name>id<\/name><value><int>[0-9]+' | _egrep_o '[0-9]+')
  107. _info "Deleting record"
  108. _inwx_delete_record "$_record_id"
  109. fi
  110. }
  111. #################### Private functions below ##################################
  112. _inwx_check_cookie() {
  113. INWX_Cookie="${INWX_Cookie:-$(_readaccountconf_mutable INWX_Cookie)}"
  114. if [ -z "$INWX_Cookie" ]; then
  115. _debug "No cached cookie found"
  116. return 1
  117. fi
  118. _H1="$INWX_Cookie"
  119. export _H1
  120. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  121. <methodCall>
  122. <methodName>account.info</methodName>
  123. </methodCall>')
  124. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  125. if _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>"; then
  126. _debug "Cached cookie still valid"
  127. return 0
  128. fi
  129. _debug "Cached cookie no longer valid"
  130. _H1=""
  131. export _H1
  132. INWX_Cookie=""
  133. _saveaccountconf_mutable INWX_Cookie "$INWX_Cookie"
  134. return 1
  135. }
  136. _htmlEscape() {
  137. local s
  138. s=${1//&/&amp;}
  139. s=${s//</&lt;}
  140. s=${s//>/&gt;}
  141. s=${s//'"'/&quot;}
  142. printf -- %s "$s"
  143. }
  144. _inwx_login() {
  145. if _inwx_check_cookie; then
  146. _debug "Already logged in"
  147. return 0
  148. fi
  149. XML_PASS=$(_htmlEscape "$INWX_Password")
  150. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  151. <methodCall>
  152. <methodName>account.login</methodName>
  153. <params>
  154. <param>
  155. <value>
  156. <struct>
  157. <member>
  158. <name>user</name>
  159. <value>
  160. <string>%s</string>
  161. </value>
  162. </member>
  163. <member>
  164. <name>pass</name>
  165. <value>
  166. <string>%s</string>
  167. </value>
  168. </member>
  169. </struct>
  170. </value>
  171. </param>
  172. </params>
  173. </methodCall>' "$INWX_User" "$XML_PASS")
  174. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  175. INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep -i "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')")
  176. _H1=$INWX_Cookie
  177. export _H1
  178. export INWX_Cookie
  179. _saveaccountconf_mutable INWX_Cookie "$INWX_Cookie"
  180. if ! _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>"; then
  181. _err "INWX API: Authentication error (username/password correct?)"
  182. return 1
  183. fi
  184. #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71
  185. if _contains "$response" "<member><name>tfa</name><value><string>GOOGLE-AUTH</string></value></member>"; then
  186. if [ -z "$INWX_Shared_Secret" ]; then
  187. _err "INWX API: Mobile TAN detected."
  188. _err "Please define a shared secret."
  189. return 1
  190. fi
  191. if ! _exists oathtool; then
  192. _err "Please install oathtool to use 2 Factor Authentication."
  193. _err ""
  194. return 1
  195. fi
  196. tan="$(oathtool --base32 --totp "${INWX_Shared_Secret}" 2>/dev/null)"
  197. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  198. <methodCall>
  199. <methodName>account.unlock</methodName>
  200. <params>
  201. <param>
  202. <value>
  203. <struct>
  204. <member>
  205. <name>tan</name>
  206. <value>
  207. <string>%s</string>
  208. </value>
  209. </member>
  210. </struct>
  211. </value>
  212. </param>
  213. </params>
  214. </methodCall>' "$tan")
  215. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  216. if ! _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>"; then
  217. _err "INWX API: Mobile TAN not correct."
  218. return 1
  219. fi
  220. fi
  221. }
  222. _get_root() {
  223. domain=$1
  224. _debug "get root"
  225. domain=$1
  226. i=2
  227. p=1
  228. xml_content='<?xml version="1.0" encoding="UTF-8"?>
  229. <methodCall>
  230. <methodName>nameserver.list</methodName>
  231. <params>
  232. <param>
  233. <value>
  234. <struct>
  235. <member>
  236. <name>pagelimit</name>
  237. <value>
  238. <int>9999</int>
  239. </value>
  240. </member>
  241. </struct>
  242. </value>
  243. </param>
  244. </params>
  245. </methodCall>'
  246. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  247. while true; do
  248. h=$(printf "%s" "$domain" | cut -d . -f $i-100)
  249. _debug h "$h"
  250. if [ -z "$h" ]; then
  251. #not valid
  252. return 1
  253. fi
  254. if _contains "$response" "$h"; then
  255. _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
  256. _domain="$h"
  257. return 0
  258. fi
  259. p=$i
  260. i=$(_math "$i" + 1)
  261. done
  262. return 1
  263. }
  264. _inwx_delete_record() {
  265. record_id=$1
  266. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  267. <methodCall>
  268. <methodName>nameserver.deleteRecord</methodName>
  269. <params>
  270. <param>
  271. <value>
  272. <struct>
  273. <member>
  274. <name>id</name>
  275. <value>
  276. <int>%s</int>
  277. </value>
  278. </member>
  279. </struct>
  280. </value>
  281. </param>
  282. </params>
  283. </methodCall>' "$record_id")
  284. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  285. if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
  286. _err "Error"
  287. return 1
  288. fi
  289. return 0
  290. }
  291. _inwx_update_record() {
  292. record_id=$1
  293. txtval=$2
  294. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  295. <methodCall>
  296. <methodName>nameserver.updateRecord</methodName>
  297. <params>
  298. <param>
  299. <value>
  300. <struct>
  301. <member>
  302. <name>content</name>
  303. <value>
  304. <string>%s</string>
  305. </value>
  306. </member>
  307. <member>
  308. <name>id</name>
  309. <value>
  310. <int>%s</int>
  311. </value>
  312. </member>
  313. </struct>
  314. </value>
  315. </param>
  316. </params>
  317. </methodCall>' "$txtval" "$record_id")
  318. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  319. if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
  320. _err "Error"
  321. return 1
  322. fi
  323. return 0
  324. }
  325. _inwx_add_record() {
  326. domain=$1
  327. sub_domain=$2
  328. txtval=$3
  329. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  330. <methodCall>
  331. <methodName>nameserver.createRecord</methodName>
  332. <params>
  333. <param>
  334. <value>
  335. <struct>
  336. <member>
  337. <name>domain</name>
  338. <value>
  339. <string>%s</string>
  340. </value>
  341. </member>
  342. <member>
  343. <name>type</name>
  344. <value>
  345. <string>TXT</string>
  346. </value>
  347. </member>
  348. <member>
  349. <name>content</name>
  350. <value>
  351. <string>%s</string>
  352. </value>
  353. </member>
  354. <member>
  355. <name>name</name>
  356. <value>
  357. <string>%s</string>
  358. </value>
  359. </member>
  360. </struct>
  361. </value>
  362. </param>
  363. </params>
  364. </methodCall>' "$domain" "$txtval" "$sub_domain")
  365. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  366. if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
  367. _err "Error"
  368. return 1
  369. fi
  370. return 0
  371. }