commit
43e9553ebc
@ -37,6 +37,8 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
|
||||
- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/)
|
||||
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
|
||||
- [CentOS Web Panel](http://centos-webpanel.com/)
|
||||
- [lnmp.org](https://lnmp.org/)
|
||||
- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials)
|
||||
|
||||
# Tested OS
|
||||
@ -398,7 +400,7 @@ Valid values are:
|
||||
It's simple, just give a wildcard domain as the `-d` parameter.
|
||||
|
||||
```sh
|
||||
acme.sh --issue -d example.com -d *.example.com --dns dns_cf
|
||||
acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf
|
||||
```
|
||||
|
||||
|
||||
|
41
acme.sh
41
acme.sh
@ -1617,6 +1617,7 @@ _post() {
|
||||
_debug $httpmethod
|
||||
_debug "_post_url" "$_post_url"
|
||||
_debug2 "body" "$body"
|
||||
_debug2 "_postContentType" "$_postContentType"
|
||||
|
||||
_inithttp
|
||||
|
||||
@ -1625,15 +1626,20 @@ _post() {
|
||||
if [ "$HTTPS_INSECURE" ]; then
|
||||
_CURL="$_CURL --insecure "
|
||||
fi
|
||||
if [ "$_postContentType" ]; then
|
||||
_CURL="$_CURL -H \"Content-Type: $_postContentType\" "
|
||||
fi
|
||||
_debug "_CURL" "$_CURL"
|
||||
if [ "$needbase64" ]; then
|
||||
if [ "$_postContentType" ]; then
|
||||
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
|
||||
else
|
||||
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
|
||||
fi
|
||||
else
|
||||
if [ "$_postContentType" ]; then
|
||||
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
|
||||
else
|
||||
response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
|
||||
fi
|
||||
fi
|
||||
_ret="$?"
|
||||
if [ "$_ret" != "0" ]; then
|
||||
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
|
||||
@ -1785,6 +1791,11 @@ _send_signed_request() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$ACME_VERSION" = "2" ]; then
|
||||
__request_conent_type="$CONTENT_TYPE_JSON"
|
||||
else
|
||||
__request_conent_type=""
|
||||
fi
|
||||
payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
|
||||
_debug3 payload64 "$payload64"
|
||||
|
||||
@ -1797,7 +1808,7 @@ _send_signed_request() {
|
||||
if [ "$ACME_NEW_NONCE" ]; then
|
||||
_debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
|
||||
nonceurl="$ACME_NEW_NONCE"
|
||||
if _post "" "$nonceurl" "" "HEAD" "$CONTENT_TYPE_JSON"; then
|
||||
if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then
|
||||
_headers="$(cat "$HTTP_HEADER")"
|
||||
fi
|
||||
fi
|
||||
@ -1852,7 +1863,7 @@ _send_signed_request() {
|
||||
fi
|
||||
_debug3 body "$body"
|
||||
|
||||
response="$(_post "$body" "$url" "$needbase64" "POST" "$CONTENT_TYPE_JSON")"
|
||||
response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
|
||||
_CACHED_NONCE=""
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
@ -3247,10 +3258,16 @@ _regAccount() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 responseHeaders "$responseHeaders"
|
||||
_accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
|
||||
_debug "_accUri" "$_accUri"
|
||||
if [ -z "$_accUri" ]; then
|
||||
_err "Can not find account id url."
|
||||
_err "$responseHeaders"
|
||||
return 1
|
||||
fi
|
||||
_savecaconf "ACCOUNT_URL" "$_accUri"
|
||||
export ACCOUNT_URL="$ACCOUNT_URL"
|
||||
export ACCOUNT_URL="$_accUri"
|
||||
|
||||
CA_KEY_HASH="$(__calcAccountKeyHash)"
|
||||
_debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
|
||||
@ -3521,7 +3538,7 @@ issue() {
|
||||
_saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")"
|
||||
_debug2 _saved_account_key_hash "$_saved_account_key_hash"
|
||||
|
||||
if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
|
||||
if [ -z "$ACCOUNT_URL" ] || [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
|
||||
if ! _regAccount "$_accountkeylength"; then
|
||||
_on_issue_err "$_post_hook"
|
||||
return 1
|
||||
@ -3819,7 +3836,7 @@ $_authorizations_map"
|
||||
if [ "$dnsadded" = '0' ]; then
|
||||
_savedomainconf "Le_Vlist" "$vlist"
|
||||
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
|
||||
_err "Please add the TXT records to the domains, and retry again."
|
||||
_err "Please add the TXT records to the domains, and re-run with --renew."
|
||||
_clearup
|
||||
_on_issue_err "$_post_hook"
|
||||
return 1
|
||||
@ -4105,12 +4122,12 @@ $_authorizations_map"
|
||||
fi
|
||||
else
|
||||
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
|
||||
_err "Sign failed."
|
||||
_err "Sign failed. $response"
|
||||
_on_issue_err "$_post_hook"
|
||||
return 1
|
||||
fi
|
||||
_rcert="$response"
|
||||
Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
|
||||
Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
|
||||
echo "$BEGIN_CERT" >"$CERT_PATH"
|
||||
|
||||
#if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then
|
||||
@ -5456,8 +5473,8 @@ Parameters:
|
||||
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
|
||||
--config-home Specifies the home dir to save all the configurations.
|
||||
--useragent Specifies the user agent string. it will be saved for future use too.
|
||||
--accountemail Specifies the account email for registering, Only valid for the '--install' command.
|
||||
--accountkey Specifies the account key path, Only valid for the '--install' command.
|
||||
--accountemail Specifies the account email, only valid for the '--install' and '--update-account' command.
|
||||
--accountkey Specifies the account key path, only valid for the '--install' command.
|
||||
--days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
|
||||
--httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
|
||||
--local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
|
||||
|
@ -99,6 +99,7 @@ dns_azure_add() {
|
||||
_azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
|
||||
if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
|
||||
_info "validation value added"
|
||||
return 0
|
||||
else
|
||||
_err "error adding validation value ($_code)"
|
||||
return 1
|
||||
@ -194,6 +195,7 @@ dns_azure_rm() {
|
||||
_azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
|
||||
if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
|
||||
_info "validation value removed"
|
||||
return 0
|
||||
else
|
||||
_err "error removing validation value ($_code)"
|
||||
return 1
|
||||
@ -226,6 +228,7 @@ _azure_rest() {
|
||||
else
|
||||
response="$(_get "$ep")"
|
||||
fi
|
||||
_ret="$?"
|
||||
_secure_debug2 "response $response"
|
||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
|
||||
_debug "http response code $_code"
|
||||
@ -236,7 +239,7 @@ _azure_rest() {
|
||||
return 1
|
||||
fi
|
||||
# See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes
|
||||
if [ "$?" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then
|
||||
if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then
|
||||
_request_retry_times="$(_math "$_request_retry_times" + 1)"
|
||||
_info "REST call error $_code retrying $ep in $_request_retry_times s"
|
||||
_sleep "$_request_retry_times"
|
||||
@ -281,6 +284,7 @@ _azure_getaccess_token() {
|
||||
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
|
||||
_secure_debug2 "data $body"
|
||||
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
|
||||
_ret="$?"
|
||||
_secure_debug2 "response $response"
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
@ -290,7 +294,7 @@ _azure_getaccess_token() {
|
||||
_err "no acccess token received. Check your Azure settings see $WIKI"
|
||||
return 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
if [ "$_ret" != "0" ]; then
|
||||
_err "error $response"
|
||||
return 1
|
||||
fi
|
||||
|
@ -19,8 +19,8 @@ dns_cf_add() {
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||
CF_Key=""
|
||||
CF_Email=""
|
||||
_err "You don't specify cloudflare api key and email yet."
|
||||
_err "Please create you key and try again."
|
||||
_err "You didn't specify a cloudflare api key and email yet."
|
||||
_err "Please create the key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
@ -94,8 +94,8 @@ dns_cf_rm() {
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||
CF_Key=""
|
||||
CF_Email=""
|
||||
_err "You don't specify cloudflare api key and email yet."
|
||||
_err "Please create you key and try again."
|
||||
_err "You didn't specify a cloudflare api key and email yet."
|
||||
_err "Please create the key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
@ -20,12 +20,22 @@
|
||||
dns_dgon_add() {
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
txtvalue=$2
|
||||
|
||||
DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
|
||||
# Check if API Key Exist
|
||||
if [ -z "$DO_API_KEY" ]; then
|
||||
DO_API_KEY=""
|
||||
_err "You did not specify DigitalOcean API key."
|
||||
_err "Please export DO_API_KEY and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using digitalocean dns validation - add record"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
## save the env vars (key and domain split location) for later automated use
|
||||
_saveaccountconf DO_API_KEY "$DO_API_KEY"
|
||||
_saveaccountconf_mutable DO_API_KEY "$DO_API_KEY"
|
||||
|
||||
## split the domain for DO API
|
||||
if ! _get_base_domain "$fulldomain"; then
|
||||
@ -39,7 +49,7 @@ dns_dgon_add() {
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: Bearer $DO_API_KEY"
|
||||
PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records'
|
||||
PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}'
|
||||
PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'","ttl":120}'
|
||||
|
||||
_debug PURL "$PURL"
|
||||
_debug PBODY "$PBODY"
|
||||
@ -65,6 +75,16 @@ dns_dgon_add() {
|
||||
dns_dgon_rm() {
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
txtvalue=$2
|
||||
|
||||
DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
|
||||
# Check if API Key Exist
|
||||
if [ -z "$DO_API_KEY" ]; then
|
||||
DO_API_KEY=""
|
||||
_err "You did not specify DigitalOcean API key."
|
||||
_err "Please export DO_API_KEY and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using digitalocean dns validation - remove record"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
@ -92,11 +112,11 @@ dns_dgon_rm() {
|
||||
domain_list="$(_get "$GURL")"
|
||||
## 2) find record
|
||||
## check for what we are looing for: "type":"A","name":"$_sub_domain"
|
||||
record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*\d+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
|
||||
record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
|
||||
## 3) check record and get next page
|
||||
if [ -z "$record" ]; then
|
||||
## find the next page if we dont have a match
|
||||
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=\d+")"
|
||||
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
|
||||
if [ -z "$nextpage" ]; then
|
||||
_err "no record and no nextpage in digital ocean DNS removal"
|
||||
return 1
|
||||
@ -108,7 +128,7 @@ dns_dgon_rm() {
|
||||
done
|
||||
|
||||
## we found the record
|
||||
rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")"
|
||||
rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||
_debug rec_id "$rec_id"
|
||||
|
||||
## delete the record
|
||||
|
@ -90,7 +90,7 @@ set_record() {
|
||||
full=$2
|
||||
txtvalue=$3
|
||||
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then
|
||||
_err "Set txt record error."
|
||||
return 1
|
||||
fi
|
||||
@ -107,7 +107,7 @@ rm_record() {
|
||||
root=$1
|
||||
full=$2
|
||||
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then
|
||||
if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then
|
||||
_err "Delete txt record error."
|
||||
return 1
|
||||
fi
|
||||
@ -122,7 +122,7 @@ rm_record() {
|
||||
notify_slaves() {
|
||||
root=$1
|
||||
|
||||
if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify"; then
|
||||
if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root/notify"; then
|
||||
_err "Notify slaves error."
|
||||
return 1
|
||||
fi
|
||||
@ -144,15 +144,18 @@ _get_root() {
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$_zones_response" "\"name\": \"$h.\""; then
|
||||
_domain="$h"
|
||||
_domain="$h."
|
||||
if [ -z "$h" ]; then
|
||||
_domain="=2E"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
i=$(_math $i + 1)
|
||||
done
|
||||
_debug "$domain not found"
|
||||
|
@ -50,9 +50,9 @@ _PDD_get_domain() {
|
||||
__last=0
|
||||
while [ $__last -eq 0 ]; do
|
||||
uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20"
|
||||
res1=$(_get "$uri1" | _normalizeJson)
|
||||
#_debug "$res1"
|
||||
__found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')
|
||||
res1="$(_get "$uri1" | _normalizeJson)"
|
||||
_debug2 "res1" "$res1"
|
||||
__found="$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')"
|
||||
_debug "found: $__found results on page"
|
||||
if [ "$__found" -lt 20 ]; then
|
||||
_debug "last page: $__page"
|
||||
|
Loading…
Reference in New Issue
Block a user