Browse Source

Merge branch 'acmesh-official:master' into master

pull/4477/head
OrpheeGT 2 years ago
committed by GitHub
parent
commit
4698b483cb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      .github/workflows/dockerhub.yml
  2. 2
      Dockerfile
  3. 39
      acme.sh
  4. 78
      dnsapi/dns_huaweicloud.sh
  5. 157
      dnsapi/dns_ipv64.sh
  6. 59
      dnsapi/dns_nanelo.sh
  7. 4
      dnsapi/dns_vultr.sh
  8. 4
      notify/smtp.sh

8
.github/workflows/dockerhub.yml

@ -28,9 +28,9 @@ jobs:
id: step_one
run: |
if [ "$DOCKER_PASSWORD" ] ; then
echo "::set-output name=hasToken::true"
echo "hasToken=true" >>$GITHUB_OUTPUT
else
echo "::set-output name=hasToken::false"
echo "hasToken=false" >>$GITHUB_OUTPUT
fi
- name: Check the value
run: echo ${{ steps.step_one.outputs.hasToken }}
@ -43,9 +43,9 @@ jobs:
- name: checkout code
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: login to docker hub
run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin

2
Dockerfile

@ -26,7 +26,7 @@ COPY ./ /install_acme.sh/
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab -
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null#> /proc/1/fd/1 2>/proc/1/fd/2#' | crontab -
RUN for verb in help \
version \

39
acme.sh

@ -1852,9 +1852,15 @@ _inithttp() {
_ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE "
fi
if _contains "$(curl --help 2>&1)" "--globoff"; then
if _contains "$(curl --help 2>&1)" "--globoff" || _contains "$(curl --help curl 2>&1)" "--globoff"; then
_ACME_CURL="$_ACME_CURL -g "
fi
#don't use --fail-with-body
##from curl 7.76: return fail on HTTP errors but keep the body
#if _contains "$(curl --help http 2>&1)" "--fail-with-body"; then
# _ACME_CURL="$_ACME_CURL --fail-with-body "
#fi
fi
if [ -z "$_ACME_WGET" ] && _exists "wget"; then
@ -1872,11 +1878,11 @@ _inithttp() {
elif [ "$CA_BUNDLE" ]; then
_ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE "
fi
fi
#from wget 1.14: do not skip body on 404 error
if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then
_ACME_WGET="$_ACME_WGET --content-on-error "
#from wget 1.14: do not skip body on 404 error
if _contains "$(wget --help 2>&1)" "--content-on-error"; then
_ACME_WGET="$_ACME_WGET --content-on-error "
fi
fi
__HTTP_INITIALIZED=1
@ -2223,6 +2229,16 @@ _send_signed_request() {
_debug3 _body "$_body"
fi
_retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *:" | cut -d : -f 2 | tr -d ' ' | tr -d '\r')
if [ "$code" = '503' ] || [ "$_retryafter" ]; then
_sleep_overload_retry_sec=$_retryafter
if [ -z "$_sleep_overload_retry_sec" ]; then
_sleep_overload_retry_sec=5
fi
_info "It seems the CA server is currently overloaded, let's wait and retry. Sleeping $_sleep_overload_retry_sec seconds."
_sleep $_sleep_overload_retry_sec
continue
fi
if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then
_info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds."
_CACHED_NONCE=""
@ -2857,7 +2873,7 @@ _initpath() {
if _isEccKey "$_ilength"; then
DOMAIN_PATH="$domainhomeecc"
else
elif [ -z "$__SELECTED_RSA_KEY" ]; then
if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then
_info "The domain '$domain' seems to have a ECC cert already, lets use ecc cert."
DOMAIN_PATH="$domainhomeecc"
@ -4018,7 +4034,7 @@ _ns_purge_cf() {
#checks if cf server is available
_ns_is_available_cf() {
if _get "https://cloudflare-dns.com" "" 1 >/dev/null 2>&1; then
if _get "https://cloudflare-dns.com" "" 10 >/dev/null; then
return 0
else
return 1
@ -4026,7 +4042,7 @@ _ns_is_available_cf() {
}
_ns_is_available_google() {
if _get "https://dns.google" "" 1 >/dev/null 2>&1; then
if _get "https://dns.google" "" 10 >/dev/null; then
return 0
else
return 1
@ -4042,7 +4058,7 @@ _ns_lookup_google() {
}
_ns_is_available_ali() {
if _get "https://dns.alidns.com" "" 1 >/dev/null 2>&1; then
if _get "https://dns.alidns.com" "" 10 >/dev/null; then
return 0
else
return 1
@ -4058,7 +4074,7 @@ _ns_lookup_ali() {
}
_ns_is_available_dp() {
if _get "https://doh.pub" "" 1 >/dev/null 2>&1; then
if _get "https://doh.pub" "" 10 >/dev/null; then
return 0
else
return 1
@ -7502,6 +7518,9 @@ _process() {
--keylength | -k)
_keylength="$2"
shift
if [ "$_keylength" ] && ! _isEccKey "$_keylength"; then
export __SELECTED_RSA_KEY=1
fi
;;
-ak | --accountkeylength)
_accountkeylength="$2"

78
dnsapi/dns_huaweicloud.sh

@ -23,7 +23,7 @@ dns_huaweicloud_add() {
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
# Check information
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
@ -74,7 +74,7 @@ dns_huaweicloud_rm() {
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
# Check information
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
@ -98,19 +98,59 @@ dns_huaweicloud_rm() {
fi
_debug "Zone ID is:" "${zoneid}"
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
_recursive_rm_record "${token}" "${fulldomain}" "${zoneid}" "${record_id}"
ret="$?"
if [ "${ret}" != "0" ]; then
_err "dns_api(dns_huaweicloud): Error removing record."
return 1
fi
return 0
}
################### Private functions below ##################################
# _recursive_rm_record
# remove all records from the record set
#
# _token=$1
# _domain=$2
# _zoneid=$3
# _record_id=$4
#
# Returns 0 on success
_recursive_rm_record() {
_token=$1
_domain=$2
_zoneid=$3
_record_id=$4
# Most likely to have problems will huaweicloud side if more than 50 attempts but still cannot fully remove the record set
# Maybe can be removed manually in the dashboard
_retry_cnt=50
# Remove all records
# Therotically HuaweiCloud does not allow more than one record set
# But remove them recurringly to increase robusty
while [ "${record_id}" != "0" ]; do
while [ "${_record_id}" != "0" ] && [ "${_retry_cnt}" != "0" ]; do
_debug "Removing Record"
_rm_record "${token}" "${zoneid}" "${record_id}"
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
_retry_cnt=$((_retry_cnt - 1))
_rm_record "${_token}" "${_zoneid}" "${_record_id}"
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${_zoneid}")"
_debug2 "Checking record exists: record_id=${_record_id}"
done
# Check if retry count is reached
if [ "${_retry_cnt}" = "0" ]; then
_debug "Failed to remove record after 50 attempts, please try removing it manually in the dashboard"
return 1
fi
return 0
}
################### Private functions below ##################################
# _get_zoneid
#
# _token=$1
@ -124,7 +164,7 @@ _get_zoneid() {
i=1
while true; do
h=$(printf "%s" "${_domain_string}" | cut -d . -f $i-100)
h=$(printf "%s" "${_domain_string}" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then
#not valid
return 1
@ -135,11 +175,11 @@ _get_zoneid() {
if _contains "${response}" '"id"'; then
zoneidlist=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
zonenamelist=$(echo "${response}" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
_debug2 "Return Zone ID(s):" "${zoneidlist}"
_debug2 "Return Zone Name(s):" "${zonenamelist}"
_debug2 "Returned Zone ID(s):" "${zoneidlist}"
_debug2 "Returned Zone Name(s):" "${zonenamelist}"
zoneidnum=0
zoneidcount=$(echo "${zoneidlist}" | grep -c '^')
_debug "Retund Zone ID(s) Count:" "${zoneidcount}"
_debug "Returned Zone ID(s) Count:" "${zoneidcount}"
while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do
zoneidnum=$(_math "$zoneidnum" + 1)
_zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p")
@ -206,8 +246,7 @@ _add_record() {
\"type\": \"TXT\",
\"ttl\": 1,
\"records\": [
${_exist_record},
\"\\\"${_txtvalue}\\\"\"
${_exist_record},\"\\\"${_txtvalue}\\\"\"
]
}"
fi
@ -215,19 +254,16 @@ _add_record() {
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
_debug "Record Set ID is:" "${_record_id}"
# Remove all records
while [ "${_record_id}" != "0" ]; do
_debug "Removing Record"
_rm_record "${_token}" "${zoneid}" "${_record_id}"
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
done
# Add brand new records with all old and new records
export _H2="Content-Type: application/json"
export _H1="X-Auth-Token: ${_token}"
_debug2 "${_post_body}"
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
if [ -z "${_exist_record}" ]; then
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
else
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets/${_record_id}" false "PUT" >/dev/null
fi
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
if [ "$_code" != "202" ]; then
_err "dns_huaweicloud: http code ${_code}"

157
dnsapi/dns_ipv64.sh

@ -0,0 +1,157 @@
#!/usr/bin/env sh
#Created by Roman Lumetsberger, to use ipv64.net's API to add/remove text records
#2022/11/29
# Pass credentials before "acme.sh --issue --dns dns_ipv64 ..."
# --
# export IPv64_Token="aaaaaaaaaaaaaaaaaaaaaaaaaa"
# --
#
IPv64_API="https://ipv64.net/api"
######## Public functions ######################
#Usage: dns_ipv64_add _acme-challenge.domain.ipv64.net "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_ipv64_add() {
fulldomain=$1
txtvalue=$2
IPv64_Token="${IPv64_Token:-$(_readaccountconf_mutable IPv64_Token)}"
if [ -z "$IPv64_Token" ]; then
_err "You must export variable: IPv64_Token"
_err "The API Key for your IPv64 account is necessary."
_err "You can look it up in your IPv64 account."
return 1
fi
# Now save the credentials.
_saveaccountconf_mutable IPv64_Token "$IPv64_Token"
if ! _get_root "$fulldomain"; then
_err "invalid domain" "$fulldomain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
# convert to lower case
_domain="$(echo "$_domain" | _lower_case)"
_sub_domain="$(echo "$_sub_domain" | _lower_case)"
# Now add the TXT record
_info "Trying to add TXT record"
if _ipv64_rest "POST" "add_record=$_domain&praefix=$_sub_domain&type=TXT&content=$txtvalue"; then
_info "TXT record has been successfully added."
return 0
else
_err "Errors happened during adding the TXT record, response=$_response"
return 1
fi
}
#Usage: fulldomain txtvalue
#Usage: dns_ipv64_rm _acme-challenge.domain.ipv64.net "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
#Remove the txt record after validation.
dns_ipv64_rm() {
fulldomain=$1
txtvalue=$2
IPv64_Token="${IPv64_Token:-$(_readaccountconf_mutable IPv64_Token)}"
if [ -z "$IPv64_Token" ]; then
_err "You must export variable: IPv64_Token"
_err "The API Key for your IPv64 account is necessary."
_err "You can look it up in your IPv64 account."
return 1
fi
if ! _get_root "$fulldomain"; then
_err "invalid domain" "$fulldomain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
# convert to lower case
_domain="$(echo "$_domain" | _lower_case)"
_sub_domain="$(echo "$_sub_domain" | _lower_case)"
# Now delete the TXT record
_info "Trying to delete TXT record"
if _ipv64_rest "DELETE" "del_record=$_domain&praefix=$_sub_domain&type=TXT&content=$txtvalue"; then
_info "TXT record has been successfully deleted."
return 0
else
_err "Errors happened during deleting the TXT record, response=$_response"
return 1
fi
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_get_root() {
domain="$1"
i=1
p=1
_ipv64_get "get_domains"
domain_data=$_response
while true; do
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
if [ -z "$h" ]; then
#not valid
return 1
fi
#if _contains "$domain_data" "\""$h"\"\:"; then
if _contains "$domain_data" "\"""$h""\"\:"; 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
}
#send get request to api
# $1 has to set the api-function
_ipv64_get() {
url="$IPv64_API?$1"
export _H1="Authorization: Bearer $IPv64_Token"
_response=$(_get "$url")
_response="$(echo "$_response" | _normalizeJson)"
if _contains "$_response" "429 Too Many Requests"; then
_info "API throttled, sleeping to reset the limit"
_sleep 10
_response=$(_get "$url")
_response="$(echo "$_response" | _normalizeJson)"
fi
}
_ipv64_rest() {
url="$IPv64_API"
export _H1="Authorization: Bearer $IPv64_Token"
export _H2="Content-Type: application/x-www-form-urlencoded"
_response=$(_post "$2" "$url" "" "$1")
if _contains "$_response" "429 Too Many Requests"; then
_info "API throttled, sleeping to reset the limit"
_sleep 10
_response=$(_post "$2" "$url" "" "$1")
fi
if ! _contains "$_response" "\"info\":\"success\""; then
return 1
fi
_debug2 response "$_response"
return 0
}

59
dnsapi/dns_nanelo.sh

@ -0,0 +1,59 @@
#!/usr/bin/env sh
# Official DNS API for Nanelo.com
# Provide the required API Key like this:
# NANELO_TOKEN="FmD408PdqT1E269gUK57"
NANELO_API="https://api.nanelo.com/v1/"
######## Public functions #####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_nanelo_add() {
fulldomain=$1
txtvalue=$2
NANELO_TOKEN="${NANELO_TOKEN:-$(_readaccountconf_mutable NANELO_TOKEN)}"
if [ -z "$NANELO_TOKEN" ]; then
NANELO_TOKEN=""
_err "You didn't configure a Nanelo API Key yet."
_err "Please set NANELO_TOKEN and try again."
_err "Login to Nanelo.com and go to Settings > API Keys to get a Key"
return 1
fi
_saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN"
_info "Adding TXT record to ${fulldomain}"
response="$(_get "$NANELO_API$NANELO_TOKEN/dns/addrecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")"
if _contains "${response}" 'success'; then
return 0
fi
_err "Could not create resource record, please check the logs"
_err "${response}"
return 1
}
dns_nanelo_rm() {
fulldomain=$1
txtvalue=$2
NANELO_TOKEN="${NANELO_TOKEN:-$(_readaccountconf_mutable NANELO_TOKEN)}"
if [ -z "$NANELO_TOKEN" ]; then
NANELO_TOKEN=""
_err "You didn't configure a Nanelo API Key yet."
_err "Please set NANELO_TOKEN and try again."
_err "Login to Nanelo.com and go to Settings > API Keys to get a Key"
return 1
fi
_saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN"
_info "Deleting resource record $fulldomain"
response="$(_get "$NANELO_API$NANELO_TOKEN/dns/deleterecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")"
if _contains "${response}" 'success'; then
return 0
fi
_err "Could not delete resource record, please check the logs"
_err "${response}"
return 1
}

4
dnsapi/dns_vultr.sh

@ -78,7 +78,7 @@ dns_vultr_rm() {
return 1
fi
_record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep -- "$txtvalue" | tr ',' '\n' | grep -i 'id' | cut -d : -f 2)"
_record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep -- "$txtvalue" | tr ',' '\n' | grep -i 'id' | cut -d : -f 2 | tr -d '"')"
_debug _record_id "$_record_id"
if [ "$_record_id" ]; then
_info "Successfully retrieved the record id for ACME challenge."
@ -116,7 +116,7 @@ _get_root() {
return 1
fi
if printf "%s\n" "$response" | grep '^\{.*\}' >/dev/null; then
if printf "%s\n" "$response" | grep -E '^\{.*\}' >/dev/null; then
if _contains "$response" "\"domain\":\"$_domain\""; then
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
return 0

4
notify/smtp.sh

@ -169,7 +169,7 @@ _clean_email_header() {
# email
_email_has_display_name() {
_email="$1"
expr "$_email" : '^.*[<>"]' >/dev/null
echo "$_email" | grep -q -E '^.*[<>"]'
}
##
@ -249,7 +249,7 @@ _mime_encoded_word() {
_text="$1"
# (regex character ranges like [a-z] can be locale-dependent; enumerate ASCII chars to avoid that)
_ascii='] $`"'"[!#%&'()*+,./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ~^_abcdefghijklmnopqrstuvwxyz{|}~-"
if expr "$_text" : "^.*[^$_ascii]" >/dev/null; then
if echo "$_text" | grep -q -E "^.*[^$_ascii]"; then
# At least one non-ASCII char; convert entire thing to encoded word
printf "%s" "=?UTF-8?B?$(printf "%s" "$_text" | _base64)?="
else

Loading…
Cancel
Save