From c25b4ba0991f083634063a076b51f7d71f004b97 Mon Sep 17 00:00:00 2001 From: Jeremiah Date: Sun, 8 Mar 2020 15:39:18 -0600 Subject: [PATCH 01/12] dns_me id parse using only sed --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index db51cc7..3a01f80 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -114,7 +114,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | cut -c 2- | head -c -2 | sed 's/{.*}//' | sed -r 's/^.*"id":([0-9]+).*$/\1/') + _domain_id=$(printf "%s\n" "$response" | sed 's/^{//; s/}$//; s/{.*}//' | sed -E 's/^.*"id":([0-9]+).*$/\1/') if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" From 5d881a8b0ff8dc5db10a4da1379113e7163ea155 Mon Sep 17 00:00:00 2001 From: Jeremiah Date: Mon, 9 Mar 2020 11:34:50 -0600 Subject: [PATCH 02/12] use more compatible regex flag --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 3a01f80..4900740 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -114,7 +114,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | sed 's/^{//; s/}$//; s/{.*}//' | sed -E 's/^.*"id":([0-9]+).*$/\1/') + _domain_id=$(printf "%s\n" "$response" | sed 's/^{//; s/}$//; s/{.*}//' | sed -r 's/^.*"id":([0-9]+).*$/\1/') if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" From 5530e743827a043f467fc647247c7908432b924f Mon Sep 17 00:00:00 2001 From: aattww <52109748+aattww@users.noreply.github.com> Date: Sun, 5 Apr 2020 21:57:37 +0300 Subject: [PATCH 03/12] Initial release --- dnsapi/dns_joker.sh | 129 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 dnsapi/dns_joker.sh diff --git a/dnsapi/dns_joker.sh b/dnsapi/dns_joker.sh new file mode 100644 index 0000000..14a0e3c --- /dev/null +++ b/dnsapi/dns_joker.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env sh + +# Joker.com API for acme.sh +# +# This script adds the necessary TXT record to a domain in Joker.com. +# +# You must activate Dynamic DNS in Joker.com DNS configuration first. +# Username and password below refer to Dynamic DNS authentication, +# not your Joker.com login credentials. +# See: https://joker.com/faq/content/11/427/en/what-is-dynamic-dns-dyndns.html +# +# NOTE: This script does not support wildcard certificates, because +# Joker.com API does not support adding two TXT records with the same +# subdomain. Adding the second record will overwrite the first one. +# See: https://joker.com/faq/content/6/496/en/let_s-encrypt-support.html +# "... this request will replace all TXT records for the specified +# label by the provided content" +# +# Author: aattww (https://github.com/aattww/) +# +# JOKER_USERNAME="xxxx" +# JOKER_PASSWORD="xxxx" + +JOKER_API="https://svc.joker.com/nic/replace" + +######## Public functions ##################### + +#Usage: dns_joker_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_joker_add() { + fulldomain=$1 + txtvalue=$2 + + JOKER_USERNAME="${JOKER_USERNAME:-$(_readaccountconf_mutable JOKER_USERNAME)}" + JOKER_PASSWORD="${JOKER_PASSWORD:-$(_readaccountconf_mutable JOKER_PASSWORD)}" + + if [ -z "$JOKER_USERNAME" ] || [ -z "$JOKER_PASSWORD" ]; then + _err "No Joker.com username and password specified." + return 1 + fi + + _saveaccountconf_mutable JOKER_USERNAME "$JOKER_USERNAME" + _saveaccountconf_mutable JOKER_PASSWORD "$JOKER_PASSWORD" + + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _info "Adding TXT record" + if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$_domain&label=$_sub_domain&type=TXT&value=$txtvalue"; then + if _startswith "$response" "OK"; then + _info "Added, OK" + return 0 + fi + fi + _err "Error adding TXT record." + return 1 +} + +#fulldomain txtvalue +dns_joker_rm() { + fulldomain=$1 + txtvalue=$2 + + JOKER_USERNAME="${JOKER_USERNAME:-$(_readaccountconf_mutable JOKER_USERNAME)}" + JOKER_PASSWORD="${JOKER_PASSWORD:-$(_readaccountconf_mutable JOKER_PASSWORD)}" + + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _info "Removing TXT record" + # TXT record is removed by setting its value to empty. + if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$_domain&label=$_sub_domain&type=TXT&value="; then + if _startswith "$response" "OK"; then + _info "Removed, OK" + return 0 + fi + fi + _err "Error removing TXT record." + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=1 + while true; do + h=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 + fi + + # Try to remove a test record. With correct root domain, username and password this will return "OK: ..." regardless + # of record in question existing or not. + if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$h&label=jokerTXTUpdateTest&type=TXT&value="; then + if _startswith "$response" "OK"; then + _sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")" + _domain=$h + return 0 + fi + fi + + i=$(_math "$i" + 1) + done + + _debug "Root domain not found" + return 1 +} + +_joker_rest() { + data="$1" + _debug data "$data" + + response="$(_post "$data" "$JOKER_API" "" "POST")" + + if [ "$?" != "0" ]; then + _err "Error POSTing" + return 1 + fi + _debug response "$response" + return 0 +} From 8400d1e60ea75bc0ced48ba43ad649135be31121 Mon Sep 17 00:00:00 2001 From: aattww <52109748+aattww@users.noreply.github.com> Date: Sun, 5 Apr 2020 22:07:20 +0300 Subject: [PATCH 04/12] Add bugs report link --- dnsapi/dns_joker.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/dns_joker.sh b/dnsapi/dns_joker.sh index 14a0e3c..e25530c 100644 --- a/dnsapi/dns_joker.sh +++ b/dnsapi/dns_joker.sh @@ -18,6 +18,8 @@ # # Author: aattww (https://github.com/aattww/) # +# Report bugs to https://github.com/acmesh-official/acme.sh/issues/2840 +# # JOKER_USERNAME="xxxx" # JOKER_PASSWORD="xxxx" From c064b3896a6ab6a24a8d2ff6a9364c42d453850d Mon Sep 17 00:00:00 2001 From: aattww <52109748+aattww@users.noreply.github.com> Date: Mon, 6 Apr 2020 01:13:59 +0300 Subject: [PATCH 05/12] Change command check to fully pass shellcheck --- dnsapi/dns_joker.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dnsapi/dns_joker.sh b/dnsapi/dns_joker.sh index e25530c..5d50953 100644 --- a/dnsapi/dns_joker.sh +++ b/dnsapi/dns_joker.sh @@ -120,9 +120,7 @@ _joker_rest() { data="$1" _debug data "$data" - response="$(_post "$data" "$JOKER_API" "" "POST")" - - if [ "$?" != "0" ]; then + if ! response="$(_post "$data" "$JOKER_API" "" "POST")"; then _err "Error POSTing" return 1 fi From 62378d063e9592837f33a9bf50fdab334569d63a Mon Sep 17 00:00:00 2001 From: Wout Date: Tue, 7 Apr 2020 22:34:05 +0200 Subject: [PATCH 06/12] Fixes getting the correct domain id using Contellix API. --- dnsapi/dns_constellix.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_constellix.sh b/dnsapi/dns_constellix.sh index c47ede4..2eb266b 100644 --- a/dnsapi/dns_constellix.sh +++ b/dnsapi/dns_constellix.sh @@ -86,12 +86,12 @@ _get_root() { return 1 fi - if ! _constellix_rest GET "domains"; then + if ! _constellix_rest GET "domains/search?name=$h"; then return 1 fi if _contains "$response" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | head -n 1 | cut -d ':' -f 2 | tr -d '}') + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+" | cut -d ':' -f 2) if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-$p) _domain="$h" From e158b5ccf65848233dd00c7fbafcf41f87a68a18 Mon Sep 17 00:00:00 2001 From: Wout Date: Thu, 9 Apr 2020 19:15:32 +0200 Subject: [PATCH 07/12] Constellix made changes to their API. They added more search capabilities, but the changes are not backwards compatible. We need to use the `exact` parameter instead of `name` now. --- dnsapi/dns_constellix.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_constellix.sh b/dnsapi/dns_constellix.sh index 2eb266b..42df710 100644 --- a/dnsapi/dns_constellix.sh +++ b/dnsapi/dns_constellix.sh @@ -86,7 +86,7 @@ _get_root() { return 1 fi - if ! _constellix_rest GET "domains/search?name=$h"; then + if ! _constellix_rest GET "domains/search?exact=$h"; then return 1 fi From eef9a60037cc9771a43074f1f6bf855c5850113d Mon Sep 17 00:00:00 2001 From: Adrian Fedoreanu Date: Fri, 10 Apr 2020 23:25:28 +0200 Subject: [PATCH 08/12] add dns_1984hosting dns api --- dnsapi/dns_1984hosting.sh | 254 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100755 dnsapi/dns_1984hosting.sh diff --git a/dnsapi/dns_1984hosting.sh b/dnsapi/dns_1984hosting.sh new file mode 100755 index 0000000..b7cb36d --- /dev/null +++ b/dnsapi/dns_1984hosting.sh @@ -0,0 +1,254 @@ +#!/usr/bin/env sh +#This file name is "dns_1984hosting.sh" +#So, here must be a method dns_1984hosting_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. +# +#Author: Adrian Fedoreanu +#Report Bugs here: https://github.com/acmesh-official/acme.sh +# or here... https://github.com/acmesh-official/acme.sh/issues/2851 +# +######## Public functions ##################### + +# Export 1984HOSTING username and password in following variables +# +# One984HOSTING_Username=username +# One984HOSTING_Password=password +# +# sessionid cookie is saved in ~/.acme.sh/account.conf +# username/password need to be set only when changed. + +#Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_1984hosting_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Add TXT record using 1984Hosting" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + if ! _1984hosting_login; then + _err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" "$fulldomain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _1984hosting_add_txt_record "$_domain" "$_sub_domain" "$txtvalue" + return $? +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_1984hosting_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Delete TXT record using 1984Hosting" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + if ! _1984hosting_login; then + _err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" "$fulldomain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _1984hosting_delete_txt_record "$_domain" "$_sub_domain" + return $? +} + +#################### Private functions below ################################## + +# usage _1984hosting_add_txt_record domain subdomain value +# returns 0 success +_1984hosting_add_txt_record() { + _debug "Add TXT record $1 with value '$3'" + domain="$1" + subdomain="$2" + value="$(printf '%s' "$3" | _url_encode)" + url="https://management.1984hosting.com/domains/entry/" + + postdata="entry=new" + postdata="$postdata&type=TXT" + postdata="$postdata&ttl=3600" + postdata="$postdata&zone=$domain" + postdata="$postdata&host=$subdomain" + postdata="$postdata&rdata=%22$value%22" + _debug2 postdata "$postdata" + + _authpost "$postdata" "$url" + response="$(echo "$_response" | _normalizeJson)" + _debug2 response "$response" + + if _contains "$response" '"haserrors": true'; then + _err "1984Hosting failed to add TXT record for $subdomain bad RC from _post" + return 1 + elif _contains "$response" ""; then + _err "1984Hosting failed to add TXT record for $subdomain. Check $HTTP_HEADER file" + return 1 + elif [ "$response" = '{"auth": false, "ok": false}' ]; then + _err "1984Hosting failed to add TXT record for $subdomain. Invalid or expired cookie" + return 1 + fi + + _info "Added acme challenge TXT record for $fulldomain at 1984Hosting" + return 0 +} + +# usage _1984hosting_delete_txt_record entry_id +# returns 0 success +_1984hosting_delete_txt_record() { + _debug "Delete $fulldomain TXT record" + domain="$1" + subdomain="$2" + url="https://management.1984hosting.com/domains" + + _htmlget "$url" "$domain" + _debug2 _response "$_response" + zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+')" + _debug2 zone_id "$zone_id" + if [ -z "$zone_id" ]; then + _err "Error getting zone_id for $1" + return 1 + fi + + _htmlget "$url/$zone_id" "$subdomain" + _debug2 _response "$_response" + entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')" + _debug2 entry_id "$entry_id" + if [ -z "$entry_id" ]; then + _err "Error getting TXT entry_id for $1" + return 1 + fi + + _authpost "entry=$entry_id" "$url/delentry/" + response="$(echo "$_response" | _normalizeJson)" + _debug2 response "$response" + + if ! _contains "$response" '"ok": true'; then + _err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post" + return 1 + fi + + _info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting" + return 0 +} + +# usage: _1984hosting_login username password +# returns 0 success +_1984hosting_login() { + if ! _check_credentials; then return 1; fi + + if _check_cookie; then + _debug "Already logged in" + return 0 + fi + + _debug "Login to 1984Hosting as user $One984HOSTING_Username" + username=$(printf '%s' "$One984HOSTING_Username" | _url_encode) + password=$(printf '%s' "$One984HOSTING_Password" | _url_encode) + url="https://management.1984hosting.com/accounts/checkuserauth/" + + response="$(_post "username=$username&password=$password&otpkey=" "$url")" + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + + if [ "$response" = '{"loggedin": true, "ok": true}' ]; then + One984HOSTING_COOKIE="$(grep '^Set-Cookie:' "$HTTP_HEADER" | _tail_n 1 | _egrep_o 'sessionid=[^;]*;' | tr -d ';')" + export One984HOSTING_COOKIE + _saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE" + return 0 + fi + return 1 +} + +_check_credentials() { + if [ -z "$One984HOSTING_Username" ] || [ -z "$One984HOSTING_Password" ]; then + One984HOSTING_Username="" + One984HOSTING_Password="" + _err "You haven't specified 1984Hosting username or password yet." + _err "Please export as One984HOSTING_Username / One984HOSTING_Password and try again." + return 1 + fi + return 0 +} + +_check_cookie() { + One984HOSTING_COOKIE="${One984HOSTING_COOKIE:-$(_readaccountconf_mutable One984HOSTING_COOKIE)}" + if [ -z "$One984HOSTING_COOKIE" ]; then + _debug "No cached cookie found" + return 1 + fi + + _authget "https://management.1984hosting.com/accounts/loginstatus/" + response="$(echo "$_response" | _normalizeJson)" + if [ "$_response" = '{"ok": true}' ]; then + _debug "Cached cookie still valid" + return 0 + fi + _debug "Cached cookie no longer valid" + One984HOSTING_COOKIE="" + _saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE" + return 1 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain="$1" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is." + if _contains "$_response" "serial"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +# add extra headers to request +_authget() { + export _H1="Cookie: $One984HOSTING_COOKIE" + _response=$(_get "$1") +} + +# truncate huge HTML response +# echo: Argument list too long +_htmlget() { + export _H1="Cookie: $One984HOSTING_COOKIE" + _response=$(_get "$1" | grep "$2" | _head_n 1) +} + +# add extra headers to request +_authpost() { + export _H1="Cookie: $One984HOSTING_COOKIE" + _response=$(_post "$1" "$2") +} From 52a16c917f3f28d7a83e0ac368c62b28aa99174c Mon Sep 17 00:00:00 2001 From: Scott Wiersdorf Date: Sat, 11 Apr 2020 11:24:30 -0600 Subject: [PATCH 09/12] show response when unable to retrieve DNS records for a zone --- dnsapi/dns_cf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 040934e..43bc142 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -111,7 +111,7 @@ dns_cf_rm() { _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue" if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then - _err "Error" + _err "Error: $response" return 1 fi From a57ba3d81ca3986fd405a38b22c9d7ec23f10dcd Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 12 Apr 2020 10:38:31 +0800 Subject: [PATCH 10/12] update comments --- .github/auto-comment.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/auto-comment.yml b/.github/auto-comment.yml index 75e6ac5..3ef3d9e 100644 --- a/.github/auto-comment.yml +++ b/.github/auto-comment.yml @@ -1,13 +1,17 @@ # Comment to a new issue. issuesOpened: > If this is a bug report, please upgrade to the latest code and try again: - 请先更新到最新版再试: + + 如果有 bug, 请先更新到最新版试试: + ```sh acme.sh --upgrade ``` pullRequestOpened: > + First, never send a PR to `master` branch, it will never be accepted. Please send to the `dev` branch instead. + If this is a PR to support new DNS API or new notification API, please read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide @@ -16,3 +20,5 @@ pullRequestOpened: > Then add your usage here: https://github.com/acmesh-official/acme.sh/wiki/dnsapi + + From 5ace44493a8f6691c39f2143f8fbc2227cff9618 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 12 Apr 2020 10:47:41 +0800 Subject: [PATCH 11/12] fix comments --- .github/auto-comment.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/auto-comment.yml b/.github/auto-comment.yml index 3ef3d9e..1e7b389 100644 --- a/.github/auto-comment.yml +++ b/.github/auto-comment.yml @@ -7,6 +7,10 @@ issuesOpened: > ```sh acme.sh --upgrade ``` + + please also provide the log with `--debug 2`. + + see: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh pullRequestOpened: > From 93de1e4903a975efa45da8fecbc819559e89ded7 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 12 Apr 2020 11:48:24 +0800 Subject: [PATCH 12/12] un-escape json chars fix https://github.com/acmesh-official/acme.sh/issues/2833 --- acme.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 512d57e..f672710 100755 --- a/acme.sh +++ b/acme.sh @@ -846,6 +846,14 @@ _json_encode() { echo "$_j_str" | _hex_dump | _lower_case | sed 's/0a/5c 6e/g' | tr -d ' ' | _h2b | tr -d "\r\n" } +#from: http:\/\/ to http:// +_json_decode() { + _j_str="$(sed 's#\\/#/#g')" + _debug3 "_json_decode" + _debug3 "_j_str" "$_j_str" + echo "$_j_str" +} + #options file _sed_i() { options="$1" @@ -4019,7 +4027,7 @@ issue() { #for dns manual mode _savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize" - _authorizations_seg="$(echo "$response" | _egrep_o '"authorizations" *: *\[[^\[]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _authorizations_seg="$(echo "$response" | _json_decode | _egrep_o '"authorizations" *: *\[[^\[]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" _debug2 _authorizations_seg "$_authorizations_seg" if [ -z "$_authorizations_seg" ]; then _err "_authorizations_seg not found."