mirror of
				https://github.com/hiskang/acme.sh
				synced 2025-10-31 02:17:18 +00:00 
			
		
		
		
	
						commit
						726c7a4d32
					
				| @ -3,6 +3,8 @@ | |||||||
| [](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | [](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||||||
| - An ACME protocol client written purely in Shell (Unix shell) language. | - An ACME protocol client written purely in Shell (Unix shell) language. | ||||||
| - Full ACME protocol implementation. | - Full ACME protocol implementation. | ||||||
|  | - Support ACME v1 and ACME v2 | ||||||
|  | - Support ACME v2 wildcard certs | ||||||
| - Simple, powerful and very easy to use. You only need 3 minutes to learn it. | - Simple, powerful and very easy to use. You only need 3 minutes to learn it. | ||||||
| - Bash, dash and sh compatible. | - Bash, dash and sh compatible. | ||||||
| - Simplest shell script for Let's Encrypt free certificate client. | - Simplest shell script for Let's Encrypt free certificate client. | ||||||
|  | |||||||
							
								
								
									
										474
									
								
								acme.sh
									
									
									
									
									
								
							
							
						
						
									
										474
									
								
								acme.sh
									
									
									
									
									
								
							| @ -13,8 +13,14 @@ _SCRIPT_="$0" | |||||||
| 
 | 
 | ||||||
| _SUB_FOLDERS="dnsapi deploy" | _SUB_FOLDERS="dnsapi deploy" | ||||||
| 
 | 
 | ||||||
| _OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" | LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory" | ||||||
| DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" | LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" | ||||||
|  | 
 | ||||||
|  | LETSENCRYPT_CA_V2="https://acme-v02.api.letsencrypt.org/directory" | ||||||
|  | LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/directory" | ||||||
|  | 
 | ||||||
|  | DEFAULT_CA=$LETSENCRYPT_CA_V1 | ||||||
|  | DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1 | ||||||
| 
 | 
 | ||||||
| DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" | DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" | ||||||
| DEFAULT_ACCOUNT_EMAIL="" | DEFAULT_ACCOUNT_EMAIL="" | ||||||
| @ -24,13 +30,13 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 | |||||||
| 
 | 
 | ||||||
| DEFAULT_OPENSSL_BIN="openssl" | DEFAULT_OPENSSL_BIN="openssl" | ||||||
| 
 | 
 | ||||||
| STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" | _OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" | ||||||
| _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" | _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" | ||||||
| 
 | 
 | ||||||
| VTYPE_HTTP="http-01" | VTYPE_HTTP="http-01" | ||||||
| VTYPE_DNS="dns-01" | VTYPE_DNS="dns-01" | ||||||
| VTYPE_TLS="tls-sni-01" | VTYPE_TLS="tls-sni-01" | ||||||
| #VTYPE_TLS2="tls-sni-02" | VTYPE_TLS2="tls-sni-02" | ||||||
| 
 | 
 | ||||||
| LOCAL_ANY_ADDRESS="0.0.0.0" | LOCAL_ANY_ADDRESS="0.0.0.0" | ||||||
| 
 | 
 | ||||||
| @ -991,7 +997,7 @@ _createkey() { | |||||||
| _is_idn() { | _is_idn() { | ||||||
|   _is_idn_d="$1" |   _is_idn_d="$1" | ||||||
|   _debug2 _is_idn_d "$_is_idn_d" |   _debug2 _is_idn_d "$_is_idn_d" | ||||||
|   _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-') |   _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-') | ||||||
|   _debug2 _idn_temp "$_idn_temp" |   _debug2 _idn_temp "$_idn_temp" | ||||||
|   [ "$_idn_temp" ] |   [ "$_idn_temp" ] | ||||||
| } | } | ||||||
| @ -1044,13 +1050,14 @@ _createcsr() { | |||||||
|   if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then |   if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then | ||||||
|     #single domain |     #single domain | ||||||
|     _info "Single domain" "$domain" |     _info "Single domain" "$domain" | ||||||
|  |     printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf" | ||||||
|   else |   else | ||||||
|     domainlist="$(_idn "$domainlist")" |     domainlist="$(_idn "$domainlist")" | ||||||
|     _debug2 domainlist "$domainlist" |     _debug2 domainlist "$domainlist" | ||||||
|     if _contains "$domainlist" ","; then |     if _contains "$domainlist" ","; then | ||||||
|       alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" |       alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" | ||||||
|     else |     else | ||||||
|       alt="DNS:$domainlist" |       alt="DNS:$domain,DNS:$domainlist" | ||||||
|     fi |     fi | ||||||
|     #multi |     #multi | ||||||
|     _info "Multi domain" "$alt" |     _info "Multi domain" "$alt" | ||||||
| @ -1421,7 +1428,7 @@ _calcjwk() { | |||||||
| 
 | 
 | ||||||
|     JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' |     JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' | ||||||
|     JWK_HEADERPLACE_PART1='{"nonce": "' |     JWK_HEADERPLACE_PART1='{"nonce": "' | ||||||
|     JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' |     JWK_HEADERPLACE_PART2='", "alg": "RS256"' | ||||||
|   elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then |   elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then | ||||||
|     _debug "EC key" |     _debug "EC key" | ||||||
|     crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" |     crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" | ||||||
| @ -1490,7 +1497,7 @@ _calcjwk() { | |||||||
| 
 | 
 | ||||||
|     JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' |     JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' | ||||||
|     JWK_HEADERPLACE_PART1='{"nonce": "' |     JWK_HEADERPLACE_PART1='{"nonce": "' | ||||||
|     JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' |     JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"' | ||||||
|   else |   else | ||||||
|     _err "Only RSA or EC key is supported." |     _err "Only RSA or EC key is supported." | ||||||
|     return 1 |     return 1 | ||||||
| @ -1580,7 +1587,7 @@ _inithttp() { | |||||||
| # body  url [needbase64] [POST|PUT] | # body  url [needbase64] [POST|PUT] | ||||||
| _post() { | _post() { | ||||||
|   body="$1" |   body="$1" | ||||||
|   url="$2" |   _post_url="$2" | ||||||
|   needbase64="$3" |   needbase64="$3" | ||||||
|   httpmethod="$4" |   httpmethod="$4" | ||||||
| 
 | 
 | ||||||
| @ -1588,7 +1595,7 @@ _post() { | |||||||
|     httpmethod="POST" |     httpmethod="POST" | ||||||
|   fi |   fi | ||||||
|   _debug $httpmethod |   _debug $httpmethod | ||||||
|   _debug "url" "$url" |   _debug "_post_url" "$_post_url" | ||||||
|   _debug2 "body" "$body" |   _debug2 "body" "$body" | ||||||
| 
 | 
 | ||||||
|   _inithttp |   _inithttp | ||||||
| @ -1600,9 +1607,9 @@ _post() { | |||||||
|     fi |     fi | ||||||
|     _debug "_CURL" "$_CURL" |     _debug "_CURL" "$_CURL" | ||||||
|     if [ "$needbase64" ]; then |     if [ "$needbase64" ]; then | ||||||
|       response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" |       response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" | ||||||
|     else |     else | ||||||
|       response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")" |       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="$?" |     _ret="$?" | ||||||
|     if [ "$_ret" != "0" ]; then |     if [ "$_ret" != "0" ]; then | ||||||
| @ -1620,15 +1627,15 @@ _post() { | |||||||
|     _debug "_WGET" "$_WGET" |     _debug "_WGET" "$_WGET" | ||||||
|     if [ "$needbase64" ]; then |     if [ "$needbase64" ]; then | ||||||
|       if [ "$httpmethod" = "POST" ]; then |       if [ "$httpmethod" = "POST" ]; then | ||||||
|         response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" |         response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" | ||||||
|       else |       else | ||||||
|         response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" |         response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" | ||||||
|       fi |       fi | ||||||
|     else |     else | ||||||
|       if [ "$httpmethod" = "POST" ]; then |       if [ "$httpmethod" = "POST" ]; then | ||||||
|         response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" |         response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" | ||||||
|       else |       else | ||||||
|         response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" |         response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" | ||||||
|       fi |       fi | ||||||
|     fi |     fi | ||||||
|     _ret="$?" |     _ret="$?" | ||||||
| @ -1656,7 +1663,7 @@ _get() { | |||||||
|   onlyheader="$2" |   onlyheader="$2" | ||||||
|   t="$3" |   t="$3" | ||||||
|   _debug url "$url" |   _debug url "$url" | ||||||
|   _debug "timeout" "$t" |   _debug "timeout=$t" | ||||||
| 
 | 
 | ||||||
|   _inithttp |   _inithttp | ||||||
| 
 | 
 | ||||||
| @ -1776,7 +1783,15 @@ _send_signed_request() { | |||||||
|     nonce="$_CACHED_NONCE" |     nonce="$_CACHED_NONCE" | ||||||
|     _debug2 nonce "$nonce" |     _debug2 nonce "$nonce" | ||||||
| 
 | 
 | ||||||
|     protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2" |     if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |       if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then | ||||||
|  |         protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' | ||||||
|  |       else | ||||||
|  |         protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"$ACCOUNT_URL\""'}' | ||||||
|  |       fi | ||||||
|  |     else | ||||||
|  |       protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' | ||||||
|  |     fi | ||||||
|     _debug3 protected "$protected" |     _debug3 protected "$protected" | ||||||
| 
 | 
 | ||||||
|     protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" |     protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" | ||||||
| @ -1791,7 +1806,11 @@ _send_signed_request() { | |||||||
|     sig="$(printf "%s" "$_sig_t" | _url_replace)" |     sig="$(printf "%s" "$_sig_t" | _url_replace)" | ||||||
|     _debug3 sig "$sig" |     _debug3 sig "$sig" | ||||||
| 
 | 
 | ||||||
|     body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" |     if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |       body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" | ||||||
|  |     else | ||||||
|  |       body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" | ||||||
|  |     fi | ||||||
|     _debug3 body "$body" |     _debug3 body "$body" | ||||||
| 
 | 
 | ||||||
|     response="$(_post "$body" "$url" "$needbase64")" |     response="$(_post "$body" "$url" "$needbase64")" | ||||||
| @ -2170,9 +2189,15 @@ _initAPI() { | |||||||
|     _debug2 "response" "$response" |     _debug2 "response" "$response" | ||||||
| 
 | 
 | ||||||
|     ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) |     ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     if [ -z "$ACME_KEY_CHANGE" ]; then | ||||||
|  |       ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'keyChange" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     fi | ||||||
|     export ACME_KEY_CHANGE |     export ACME_KEY_CHANGE | ||||||
| 
 | 
 | ||||||
|     ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) |     ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     if [ -z "$ACME_NEW_AUTHZ" ]; then | ||||||
|  |       ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'newAuthz" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     fi | ||||||
|     export ACME_NEW_AUTHZ |     export ACME_NEW_AUTHZ | ||||||
| 
 | 
 | ||||||
|     ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) |     ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
| @ -2180,6 +2205,9 @@ _initAPI() { | |||||||
|     if [ -z "$ACME_NEW_ORDER" ]; then |     if [ -z "$ACME_NEW_ORDER" ]; then | ||||||
|       ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) |       ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|       ACME_NEW_ORDER_RES="new-order" |       ACME_NEW_ORDER_RES="new-order" | ||||||
|  |       if [ -z "$ACME_NEW_ORDER" ]; then | ||||||
|  |         ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'newOrder" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |       fi | ||||||
|     fi |     fi | ||||||
|     export ACME_NEW_ORDER |     export ACME_NEW_ORDER | ||||||
|     export ACME_NEW_ORDER_RES |     export ACME_NEW_ORDER_RES | ||||||
| @ -2189,17 +2217,32 @@ _initAPI() { | |||||||
|     if [ -z "$ACME_NEW_ACCOUNT" ]; then |     if [ -z "$ACME_NEW_ACCOUNT" ]; then | ||||||
|       ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) |       ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|       ACME_NEW_ACCOUNT_RES="new-account" |       ACME_NEW_ACCOUNT_RES="new-account" | ||||||
|  |       if [ -z "$ACME_NEW_ACCOUNT" ]; then | ||||||
|  |         ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'newAccount" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |         if [ "$ACME_NEW_ACCOUNT" ]; then | ||||||
|  |           export ACME_VERSION=2 | ||||||
|  |         fi | ||||||
|  |       fi | ||||||
|     fi |     fi | ||||||
|     export ACME_NEW_ACCOUNT |     export ACME_NEW_ACCOUNT | ||||||
|     export ACME_NEW_ACCOUNT_RES |     export ACME_NEW_ACCOUNT_RES | ||||||
| 
 | 
 | ||||||
|     ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) |     ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     if [ -z "$ACME_REVOKE_CERT" ]; then | ||||||
|  |       ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revokeCert" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     fi | ||||||
|     export ACME_REVOKE_CERT |     export ACME_REVOKE_CERT | ||||||
| 
 | 
 | ||||||
|     ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) |     ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     if [ -z "$ACME_NEW_NONCE" ]; then | ||||||
|  |       ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'newNonce" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     fi | ||||||
|     export ACME_NEW_NONCE |     export ACME_NEW_NONCE | ||||||
| 
 | 
 | ||||||
|     ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) |     ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     if [ -z "$ACME_AGREEMENT" ]; then | ||||||
|  |       ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3) | ||||||
|  |     fi | ||||||
|     export ACME_AGREEMENT |     export ACME_AGREEMENT | ||||||
| 
 | 
 | ||||||
|     _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" |     _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" | ||||||
| @ -2208,12 +2251,16 @@ _initAPI() { | |||||||
|     _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" |     _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" | ||||||
|     _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" |     _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" | ||||||
|     _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" |     _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" | ||||||
|  |     _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE" | ||||||
|  |     _debug "ACME_VERSION" "$ACME_VERSION" | ||||||
| 
 | 
 | ||||||
|   fi |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[domain]  [keylength or isEcc flag] | #[domain]  [keylength or isEcc flag] | ||||||
| _initpath() { | _initpath() { | ||||||
|  |   domain="$1" | ||||||
|  |   _ilength="$2" | ||||||
| 
 | 
 | ||||||
|   __initHome |   __initHome | ||||||
| 
 | 
 | ||||||
| @ -2232,11 +2279,16 @@ _initpath() { | |||||||
|     CA_HOME="$DEFAULT_CA_HOME" |     CA_HOME="$DEFAULT_CA_HOME" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|  |   if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |     DEFAULT_CA="$LETSENCRYPT_CA_V2" | ||||||
|  |     DEFAULT_STAGING_CA="$LETSENCRYPT_STAGING_CA_V2" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|   if [ -z "$ACME_DIRECTORY" ]; then |   if [ -z "$ACME_DIRECTORY" ]; then | ||||||
|     if [ -z "$STAGE" ]; then |     if [ -z "$STAGE" ]; then | ||||||
|       ACME_DIRECTORY="$DEFAULT_CA" |       ACME_DIRECTORY="$DEFAULT_CA" | ||||||
|     else |     else | ||||||
|       ACME_DIRECTORY="$STAGE_CA" |       ACME_DIRECTORY="$DEFAULT_STAGING_CA" | ||||||
|       _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" |       _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" | ||||||
|     fi |     fi | ||||||
|   fi |   fi | ||||||
| @ -2296,13 +2348,10 @@ _initpath() { | |||||||
|     ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" |     ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if [ -z "$1" ]; then |   if [ -z "$domain" ]; then | ||||||
|     return 0 |     return 0 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   domain="$1" |  | ||||||
|   _ilength="$2" |  | ||||||
| 
 |  | ||||||
|   if [ -z "$DOMAIN_PATH" ]; then |   if [ -z "$DOMAIN_PATH" ]; then | ||||||
|     domainhome="$CERT_HOME/$domain" |     domainhome="$CERT_HOME/$domain" | ||||||
|     domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" |     domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" | ||||||
| @ -2835,7 +2884,11 @@ _clearupdns() { | |||||||
|         return 1 |         return 1 | ||||||
|       fi |       fi | ||||||
| 
 | 
 | ||||||
|       txtdomain="_acme-challenge.$d" |       _dns_root_d="$d" | ||||||
|  |       if _startswith "$_dns_root_d" "*."; then | ||||||
|  |         _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" | ||||||
|  |       fi | ||||||
|  |       txtdomain="_acme-challenge.$_dns_root_d" | ||||||
| 
 | 
 | ||||||
|       if ! $rmcommand "$txtdomain" "$txt"; then |       if ! $rmcommand "$txtdomain" "$txt"; then | ||||||
|         _err "Error removing txt for domain:$txtdomain" |         _err "Error removing txt for domain:$txtdomain" | ||||||
| @ -2968,6 +3021,7 @@ _on_issue_err() { | |||||||
|   _chk_post_hook="$1" |   _chk_post_hook="$1" | ||||||
|   _chk_vlist="$2" |   _chk_vlist="$2" | ||||||
|   _debug _on_issue_err |   _debug _on_issue_err | ||||||
|  | 
 | ||||||
|   if [ "$LOG_FILE" ]; then |   if [ "$LOG_FILE" ]; then | ||||||
|     _err "Please check log file for more details: $LOG_FILE" |     _err "Please check log file for more details: $LOG_FILE" | ||||||
|   else |   else | ||||||
| @ -3069,6 +3123,8 @@ _regAccount() { | |||||||
|   _initpath |   _initpath | ||||||
|   _reg_length="$1" |   _reg_length="$1" | ||||||
|   _debug3 _regAccount "$_regAccount" |   _debug3 _regAccount "$_regAccount" | ||||||
|  |   _initAPI | ||||||
|  | 
 | ||||||
|   mkdir -p "$CA_DIR" |   mkdir -p "$CA_DIR" | ||||||
|   if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then |   if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then | ||||||
|     _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" |     _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" | ||||||
| @ -3090,11 +3146,18 @@ _regAccount() { | |||||||
|   if ! _calcjwk "$ACCOUNT_KEY_PATH"; then |   if ! _calcjwk "$ACCOUNT_KEY_PATH"; then | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|   _initAPI | 
 | ||||||
|   _reg_res="$ACME_NEW_ACCOUNT_RES" |   if [ "$ACME_VERSION" = "2" ]; then | ||||||
|   regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' |     regjson='{"termsOfServiceAgreed": true}' | ||||||
|   if [ "$ACCOUNT_EMAIL" ]; then |     if [ "$ACCOUNT_EMAIL" ]; then | ||||||
|     regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' |       regjson='{"contact": ["mailto: '$ACCOUNT_EMAIL'"], "termsOfServiceAgreed": true}' | ||||||
|  |     fi | ||||||
|  |   else | ||||||
|  |     _reg_res="$ACME_NEW_ACCOUNT_RES" | ||||||
|  |     regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' | ||||||
|  |     if [ "$ACCOUNT_EMAIL" ]; then | ||||||
|  |       regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' | ||||||
|  |     fi | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   _info "Registering account" |   _info "Registering account" | ||||||
| @ -3117,8 +3180,8 @@ _regAccount() { | |||||||
|   _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" |   _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" | ||||||
|   _debug "_accUri" "$_accUri" |   _debug "_accUri" "$_accUri" | ||||||
|   _savecaconf "ACCOUNT_URL" "$_accUri" |   _savecaconf "ACCOUNT_URL" "$_accUri" | ||||||
|  |   export ACCOUNT_URL="$ACCOUNT_URL" | ||||||
| 
 | 
 | ||||||
|   echo "$response" >"$ACCOUNT_JSON_PATH" |  | ||||||
|   CA_KEY_HASH="$(__calcAccountKeyHash)" |   CA_KEY_HASH="$(__calcAccountKeyHash)" | ||||||
|   _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" |   _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" | ||||||
|   _savecaconf CA_KEY_HASH "$CA_KEY_HASH" |   _savecaconf CA_KEY_HASH "$CA_KEY_HASH" | ||||||
| @ -3130,7 +3193,6 @@ _regAccount() { | |||||||
| 
 | 
 | ||||||
|   ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" |   ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" | ||||||
|   _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" |   _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #Implement deactivate account | #Implement deactivate account | ||||||
| @ -3166,7 +3228,12 @@ deactivateaccount() { | |||||||
|   fi |   fi | ||||||
|   _initAPI |   _initAPI | ||||||
| 
 | 
 | ||||||
|   if _send_signed_request "$_accUri" "{\"resource\": \"reg\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then |   if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |     _djson="{\"status\":\"deactivated\"}" | ||||||
|  |   else | ||||||
|  |     _djson="{\"resource\": \"reg\", \"status\":\"deactivated\"}" | ||||||
|  |   fi | ||||||
|  |   if _send_signed_request "$_accUri" "$_djson" && _contains "$response" '"deactivated"'; then | ||||||
|     _info "Deactivate account success for $_accUri." |     _info "Deactivate account success for $_accUri." | ||||||
|     _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,') |     _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,') | ||||||
|   elif [ "$code" = "403" ]; then |   elif [ "$code" = "403" ]; then | ||||||
| @ -3268,7 +3335,11 @@ __trigger_validation() { | |||||||
|   _debug2 _t_url "$_t_url" |   _debug2 _t_url "$_t_url" | ||||||
|   _t_key_authz="$2" |   _t_key_authz="$2" | ||||||
|   _debug2 _t_key_authz "$_t_key_authz" |   _debug2 _t_key_authz "$_t_key_authz" | ||||||
|   _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" |   if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |     _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}" | ||||||
|  |   else | ||||||
|  |     _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" | ||||||
|  |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #webroot, domain domainlist  keylength | #webroot, domain domainlist  keylength | ||||||
| @ -3284,6 +3355,7 @@ issue() { | |||||||
|   _web_roots="$1" |   _web_roots="$1" | ||||||
|   _main_domain="$2" |   _main_domain="$2" | ||||||
|   _alt_domains="$3" |   _alt_domains="$3" | ||||||
|  | 
 | ||||||
|   if _contains "$_main_domain" ","; then |   if _contains "$_main_domain" ","; then | ||||||
|     _main_domain=$(echo "$2,$3" | cut -d , -f 1) |     _main_domain=$(echo "$2,$3" | cut -d , -f 1) | ||||||
|     _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") |     _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") | ||||||
| @ -3410,32 +3482,109 @@ issue() { | |||||||
|   sep='#' |   sep='#' | ||||||
|   dvsep=',' |   dvsep=',' | ||||||
|   if [ -z "$vlist" ]; then |   if [ -z "$vlist" ]; then | ||||||
|  |     if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |       #make new order request | ||||||
|  |       _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" | ||||||
|  |       for d in $(echo "$_alt_domains" | tr ',' ' '); do | ||||||
|  |         if [ "$d" ]; then | ||||||
|  |           _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" | ||||||
|  |         fi | ||||||
|  |       done | ||||||
|  |       _debug2 _identifiers "$_identifiers" | ||||||
|  |       if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then | ||||||
|  |         _err "Create new order error." | ||||||
|  |         _clearup | ||||||
|  |         _on_issue_err "$_post_hook" | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  | 
 | ||||||
|  |       Le_OrderFinalize="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" | ||||||
|  |       _debug Le_OrderFinalize "$Le_OrderFinalize" | ||||||
|  |       if [ -z "$Le_OrderFinalize" ]; then | ||||||
|  |         _err "Le_OrderFinalize not found." | ||||||
|  |         _clearup | ||||||
|  |         _on_issue_err "$_post_hook" | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  | 
 | ||||||
|  |       #for dns manual mode | ||||||
|  |       _savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize" | ||||||
|  | 
 | ||||||
|  |       _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _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." | ||||||
|  |         _clearup | ||||||
|  |         _on_issue_err "$_post_hook" | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  | 
 | ||||||
|  |       #domain and authz map | ||||||
|  |       _authorizations_map="" | ||||||
|  |       for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do | ||||||
|  |         _debug2 "_authz_url" "$_authz_url" | ||||||
|  |         if ! response="$(_get "$_authz_url")"; then | ||||||
|  |           _err "get to authz error." | ||||||
|  |           _clearup | ||||||
|  |           _on_issue_err "$_post_hook" | ||||||
|  |           return 1 | ||||||
|  |         fi | ||||||
|  | 
 | ||||||
|  |         response="$(echo "$response" | _normalizeJson)" | ||||||
|  |         _debug2 response "$response" | ||||||
|  |         _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')" | ||||||
|  |         if _contains "$response" "\"wildcard\" *: *true"; then | ||||||
|  |           _d="*.$_d" | ||||||
|  |         fi | ||||||
|  |         _debug2 _d "$_d" | ||||||
|  |         _authorizations_map="$_d,$response | ||||||
|  | $_authorizations_map" | ||||||
|  |       done | ||||||
|  |       _debug2 _authorizations_map "$_authorizations_map" | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|     alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ') |     alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ') | ||||||
|     _index=1 |     _index=0 | ||||||
|     _currentRoot="" |     _currentRoot="" | ||||||
|     for d in $alldomains; do |     for d in $alldomains; do | ||||||
|       _info "Getting webroot for domain" "$d" |       _info "Getting webroot for domain" "$d" | ||||||
|  |       _index=$(_math $_index + 1) | ||||||
|       _w="$(echo $_web_roots | cut -d , -f $_index)" |       _w="$(echo $_web_roots | cut -d , -f $_index)" | ||||||
|       _debug _w "$_w" |       _debug _w "$_w" | ||||||
|       if [ "$_w" ]; then |       if [ "$_w" ]; then | ||||||
|         _currentRoot="$_w" |         _currentRoot="$_w" | ||||||
|       fi |       fi | ||||||
|       _debug "_currentRoot" "$_currentRoot" |       _debug "_currentRoot" "$_currentRoot" | ||||||
|       _index=$(_math $_index + 1) |  | ||||||
| 
 | 
 | ||||||
|       vtype="$VTYPE_HTTP" |       vtype="$VTYPE_HTTP" | ||||||
|  |       #todo, v2 wildcard force to use dns | ||||||
|       if _startswith "$_currentRoot" "dns"; then |       if _startswith "$_currentRoot" "dns"; then | ||||||
|         vtype="$VTYPE_DNS" |         vtype="$VTYPE_DNS" | ||||||
|       fi |       fi | ||||||
| 
 | 
 | ||||||
|       if [ "$_currentRoot" = "$W_TLS" ]; then |       if [ "$_currentRoot" = "$W_TLS" ]; then | ||||||
|         vtype="$VTYPE_TLS" |         if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |           vtype="$VTYPE_TLS2" | ||||||
|  |         else | ||||||
|  |           vtype="$VTYPE_TLS" | ||||||
|  |         fi | ||||||
|       fi |       fi | ||||||
| 
 | 
 | ||||||
|       if ! __get_domain_new_authz "$d"; then |       if [ "$ACME_VERSION" = "2" ]; then | ||||||
|         _clearup |         response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")" | ||||||
|         _on_issue_err "$_post_hook" |         _debug2 "response" "$response" | ||||||
|         return 1 |         if [ -z "$response" ]; then | ||||||
|  |           _err "get to authz error." | ||||||
|  |           _clearup | ||||||
|  |           _on_issue_err "$_post_hook" | ||||||
|  |           return 1 | ||||||
|  |         fi | ||||||
|  |       else | ||||||
|  |         if ! __get_domain_new_authz "$d"; then | ||||||
|  |           _clearup | ||||||
|  |           _on_issue_err "$_post_hook" | ||||||
|  |           return 1 | ||||||
|  |         fi | ||||||
|       fi |       fi | ||||||
| 
 | 
 | ||||||
|       if [ -z "$thumbprint" ]; then |       if [ -z "$thumbprint" ]; then | ||||||
| @ -3453,14 +3602,18 @@ issue() { | |||||||
|       token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" |       token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" | ||||||
|       _debug token "$token" |       _debug token "$token" | ||||||
| 
 | 
 | ||||||
|       uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" |       if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |         uri="$(printf "%s\n" "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)" | ||||||
|  |       else | ||||||
|  |         uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" | ||||||
|  |       fi | ||||||
|       _debug uri "$uri" |       _debug uri "$uri" | ||||||
| 
 | 
 | ||||||
|       keyauthorization="$token.$thumbprint" |       keyauthorization="$token.$thumbprint" | ||||||
|       _debug keyauthorization "$keyauthorization" |       _debug keyauthorization "$keyauthorization" | ||||||
| 
 | 
 | ||||||
|       if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then |       if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then | ||||||
|         _debug "$d is already verified, skip." |         _debug "$d is already verified." | ||||||
|         keyauthorization="$STATE_VERIFIED" |         keyauthorization="$STATE_VERIFIED" | ||||||
|         _debug keyauthorization "$keyauthorization" |         _debug keyauthorization "$keyauthorization" | ||||||
|       fi |       fi | ||||||
| @ -3480,7 +3633,7 @@ issue() { | |||||||
|       keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) |       keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) | ||||||
|       vtype=$(echo "$ventry" | cut -d "$sep" -f 4) |       vtype=$(echo "$ventry" | cut -d "$sep" -f 4) | ||||||
|       _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) |       _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) | ||||||
| 
 |       _debug d "$d" | ||||||
|       if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then |       if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then | ||||||
|         _debug "$d is already verified, skip $vtype." |         _debug "$d is already verified, skip $vtype." | ||||||
|         continue |         continue | ||||||
| @ -3488,12 +3641,16 @@ issue() { | |||||||
| 
 | 
 | ||||||
|       if [ "$vtype" = "$VTYPE_DNS" ]; then |       if [ "$vtype" = "$VTYPE_DNS" ]; then | ||||||
|         dnsadded='0' |         dnsadded='0' | ||||||
|         txtdomain="_acme-challenge.$d" |         _dns_root_d="$d" | ||||||
|  |         if _startswith "$_dns_root_d" "*."; then | ||||||
|  |           _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" | ||||||
|  |         fi | ||||||
|  |         txtdomain="_acme-challenge.$_dns_root_d" | ||||||
|         _debug txtdomain "$txtdomain" |         _debug txtdomain "$txtdomain" | ||||||
|         txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" |         txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" | ||||||
|         _debug txt "$txt" |         _debug txt "$txt" | ||||||
| 
 | 
 | ||||||
|         d_api="$(_findHook "$d" dnsapi "$_currentRoot")" |         d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")" | ||||||
| 
 | 
 | ||||||
|         _debug d_api "$d_api" |         _debug d_api "$d_api" | ||||||
| 
 | 
 | ||||||
| @ -3702,12 +3859,16 @@ issue() { | |||||||
|       return 1 |       return 1 | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then |     if [ "$code" ] && [ "$code" != '202' ]; then | ||||||
|       _err "$d:Challenge error: $response" |       if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then | ||||||
|       _clearupwebbroot "$_currentRoot" "$removelevel" "$token" |         _debug "trigger validation code: $code" | ||||||
|       _clearup |       else | ||||||
|       _on_issue_err "$_post_hook" "$vlist" |         _err "$d:Challenge error: $response" | ||||||
|       return 1 |         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | ||||||
|  |         _clearup | ||||||
|  |         _on_issue_err "$_post_hook" "$vlist" | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     waittimes=0 |     waittimes=0 | ||||||
| @ -3790,18 +3951,42 @@ issue() { | |||||||
|   _info "Verify finished, start to sign." |   _info "Verify finished, start to sign." | ||||||
|   der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" |   der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" | ||||||
| 
 | 
 | ||||||
|   if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then |   if [ "$ACME_VERSION" = "2" ]; then | ||||||
|     _err "Sign failed." |     if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then | ||||||
|     _on_issue_err "$_post_hook" |       _err "Sign failed." | ||||||
|     return 1 |       _on_issue_err "$_post_hook" | ||||||
|   fi |       return 1 | ||||||
|  |     fi | ||||||
|  |     if [ "$code" != "200" ]; then | ||||||
|  |       _err "Sign failed, code is not 200." | ||||||
|  |       _on_issue_err "$_post_hook" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" | ||||||
| 
 | 
 | ||||||
|   _rcert="$response" |     if ! _get "$Le_LinkCert" >"$CERT_PATH"; then | ||||||
|   Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" |       _err "Sign failed, code is not 200." | ||||||
|   _debug "Le_LinkCert" "$Le_LinkCert" |       _on_issue_err "$_post_hook" | ||||||
|   _savedomainconf "Le_LinkCert" "$Le_LinkCert" |       return 1 | ||||||
|  |     fi | ||||||
| 
 | 
 | ||||||
|   if [ "$Le_LinkCert" ]; then |     if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then | ||||||
|  |       _debug "Found cert chain" | ||||||
|  |       cat "$CERT_PATH" >"$CERT_FULLCHAIN_PATH" | ||||||
|  |       _end_n="$(grep -n -- "$END_CERT" "$CERT_FULLCHAIN_PATH" | _head_n 1 | cut -d : -f 1)" | ||||||
|  |       _debug _end_n "$_end_n" | ||||||
|  |       sed -n "1,${_end_n}p" "$CERT_FULLCHAIN_PATH" >"$CERT_PATH" | ||||||
|  |       _end_n="$(_math $_end_n + 1)" | ||||||
|  |       sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" >"$CA_CERT_PATH" | ||||||
|  |     fi | ||||||
|  |   else | ||||||
|  |     if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then | ||||||
|  |       _err "Sign failed." | ||||||
|  |       _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)" | ||||||
|     echo "$BEGIN_CERT" >"$CERT_PATH" |     echo "$BEGIN_CERT" >"$CERT_PATH" | ||||||
| 
 | 
 | ||||||
|     #if ! _get "$Le_LinkCert" | _base64 "multiline"  >> "$CERT_PATH" ; then |     #if ! _get "$Le_LinkCert" | _base64 "multiline"  >> "$CERT_PATH" ; then | ||||||
| @ -3815,6 +4000,12 @@ issue() { | |||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     echo "$END_CERT" >>"$CERT_PATH" |     echo "$END_CERT" >>"$CERT_PATH" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug "Le_LinkCert" "$Le_LinkCert" | ||||||
|  |   _savedomainconf "Le_LinkCert" "$Le_LinkCert" | ||||||
|  | 
 | ||||||
|  |   if [ "$Le_LinkCert" ]; then | ||||||
|     _info "$(__green "Cert success.")" |     _info "$(__green "Cert success.")" | ||||||
|     cat "$CERT_PATH" |     cat "$CERT_PATH" | ||||||
| 
 | 
 | ||||||
| @ -3841,40 +4032,49 @@ issue() { | |||||||
| 
 | 
 | ||||||
|   _cleardomainconf "Le_Vlist" |   _cleardomainconf "Le_Vlist" | ||||||
| 
 | 
 | ||||||
|   Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') |   if [ "$ACME_VERSION" = "2" ]; then | ||||||
|   if ! _contains "$Le_LinkIssuer" ":"; then |     _debug "v2 chain." | ||||||
|     _info "$(__red "Relative issuer link found.")" |  | ||||||
|     Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" |  | ||||||
|   fi |  | ||||||
|   _debug Le_LinkIssuer "$Le_LinkIssuer" |  | ||||||
|   _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" |  | ||||||
| 
 |  | ||||||
|   if [ "$Le_LinkIssuer" ]; then |  | ||||||
|     _link_issuer_retry=0 |  | ||||||
|     _MAX_ISSUER_RETRY=5 |  | ||||||
|     while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do |  | ||||||
|       _debug _link_issuer_retry "$_link_issuer_retry" |  | ||||||
|       if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then |  | ||||||
|         echo "$BEGIN_CERT" >"$CA_CERT_PATH" |  | ||||||
|         _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" |  | ||||||
|         echo "$END_CERT" >>"$CA_CERT_PATH" |  | ||||||
| 
 |  | ||||||
|         _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" |  | ||||||
|         cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" |  | ||||||
|         _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" |  | ||||||
| 
 |  | ||||||
|         rm -f "$CA_CERT_PATH.der" |  | ||||||
|         break |  | ||||||
|       fi |  | ||||||
|       _link_issuer_retry=$(_math $_link_issuer_retry + 1) |  | ||||||
|       _sleep "$_link_issuer_retry" |  | ||||||
|     done |  | ||||||
|     if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then |  | ||||||
|       _err "Max retry for issuer ca cert is reached." |  | ||||||
|     fi |  | ||||||
|   else |   else | ||||||
|     _debug "No Le_LinkIssuer header found." |     Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') | ||||||
|  | 
 | ||||||
|  |     if [ "$Le_LinkIssuer" ]; then | ||||||
|  |       if ! _contains "$Le_LinkIssuer" ":"; then | ||||||
|  |         _info "$(__red "Relative issuer link found.")" | ||||||
|  |         Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" | ||||||
|  |       fi | ||||||
|  |       _debug Le_LinkIssuer "$Le_LinkIssuer" | ||||||
|  |       _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" | ||||||
|  | 
 | ||||||
|  |       _link_issuer_retry=0 | ||||||
|  |       _MAX_ISSUER_RETRY=5 | ||||||
|  |       while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do | ||||||
|  |         _debug _link_issuer_retry "$_link_issuer_retry" | ||||||
|  |         if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |           if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then | ||||||
|  |             break | ||||||
|  |           fi | ||||||
|  |         else | ||||||
|  |           if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then | ||||||
|  |             echo "$BEGIN_CERT" >"$CA_CERT_PATH" | ||||||
|  |             _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" | ||||||
|  |             echo "$END_CERT" >>"$CA_CERT_PATH" | ||||||
|  |             cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" | ||||||
|  |             rm -f "$CA_CERT_PATH.der" | ||||||
|  |             break | ||||||
|  |           fi | ||||||
|  |         fi | ||||||
|  |         _link_issuer_retry=$(_math $_link_issuer_retry + 1) | ||||||
|  |         _sleep "$_link_issuer_retry" | ||||||
|  |       done | ||||||
|  |       if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then | ||||||
|  |         _err "Max retry for issuer ca cert is reached." | ||||||
|  |       fi | ||||||
|  |     else | ||||||
|  |       _debug "No Le_LinkIssuer header found." | ||||||
|  |     fi | ||||||
|   fi |   fi | ||||||
|  |   [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" | ||||||
|  |   [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" | ||||||
| 
 | 
 | ||||||
|   Le_CertCreateTime=$(_time) |   Le_CertCreateTime=$(_time) | ||||||
|   _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" |   _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" | ||||||
| @ -3974,7 +4174,7 @@ renew() { | |||||||
|       _savedomainconf Le_API "$Le_API" |       _savedomainconf Le_API "$Le_API" | ||||||
|     fi |     fi | ||||||
|     if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then |     if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then | ||||||
|       export Le_API="$STAGE_CA" |       export Le_API="$DEFAULT_STAGING_CA" | ||||||
|       _savedomainconf Le_API "$Le_API" |       _savedomainconf Le_API "$Le_API" | ||||||
|     fi |     fi | ||||||
|     export ACME_DIRECTORY="$Le_API" |     export ACME_DIRECTORY="$Le_API" | ||||||
| @ -4062,8 +4262,6 @@ signcsr() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   _initpath |  | ||||||
| 
 |  | ||||||
|   _csrsubj=$(_readSubjectFromCSR "$_csrfile") |   _csrsubj=$(_readSubjectFromCSR "$_csrfile") | ||||||
|   if [ "$?" != "0" ]; then |   if [ "$?" != "0" ]; then | ||||||
|     _err "Can not read subject from csr: $_csrfile" |     _err "Can not read subject from csr: $_csrfile" | ||||||
| @ -4100,6 +4298,9 @@ signcsr() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|  |   if [ -z "$ACME_VERSION" ] && _contains "$_csrsubj,$_csrdomainlist" "*."; then | ||||||
|  |     export ACME_VERSION=2 | ||||||
|  |   fi | ||||||
|   _initpath "$_csrsubj" "$_csrkeylength" |   _initpath "$_csrsubj" "$_csrkeylength" | ||||||
|   mkdir -p "$DOMAIN_PATH" |   mkdir -p "$DOMAIN_PATH" | ||||||
| 
 | 
 | ||||||
| @ -4465,7 +4666,11 @@ revoke() { | |||||||
| 
 | 
 | ||||||
|   _initAPI |   _initAPI | ||||||
| 
 | 
 | ||||||
|   data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" |   if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |     data="{\"certificate\": \"$cert\"}" | ||||||
|  |   else | ||||||
|  |     data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" | ||||||
|  |   fi | ||||||
|   uri="${ACME_REVOKE_CERT}" |   uri="${ACME_REVOKE_CERT}" | ||||||
| 
 | 
 | ||||||
|   if [ -f "$CERT_KEY_PATH" ]; then |   if [ -f "$CERT_KEY_PATH" ]; then | ||||||
| @ -4536,27 +4741,56 @@ _deactivate() { | |||||||
|   _d_type="$2" |   _d_type="$2" | ||||||
|   _initpath |   _initpath | ||||||
| 
 | 
 | ||||||
|   if ! __get_domain_new_authz "$_d_domain"; then |   if [ "$ACME_VERSION" = "2" ]; then | ||||||
|     _err "Can not get domain new authz token." |     _identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}" | ||||||
|     return 1 |     if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then | ||||||
|  |       _err "Can not get domain new order." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _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." | ||||||
|  |       _clearup | ||||||
|  |       _on_issue_err "$_post_hook" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     authzUri="$_authorizations_seg" | ||||||
|  |     _debug2 "authzUri" "$authzUri" | ||||||
|  |     if ! response="$(_get "$authzUri")"; then | ||||||
|  |       _err "get to authz error." | ||||||
|  |       _clearup | ||||||
|  |       _on_issue_err "$_post_hook" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     response="$(echo "$response" | _normalizeJson)" | ||||||
|  |     _debug2 response "$response" | ||||||
|  |     _URL_NAME="url" | ||||||
|  |   else | ||||||
|  |     if ! __get_domain_new_authz "$_d_domain"; then | ||||||
|  |       _err "Can not get domain new authz token." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" | ||||||
|  |     _debug "authzUri" "$authzUri" | ||||||
|  |     if [ "$code" ] && [ ! "$code" = '201' ]; then | ||||||
|  |       _err "new-authz error: $response" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _URL_NAME="uri" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" |   entries="$(echo "$response" | _egrep_o "{ *\"type\":\"[^\"]*\", *\"status\": *\"valid\", *\"$_URL_NAME\"[^}]*")" | ||||||
|   _debug "authzUri" "$authzUri" |  | ||||||
| 
 |  | ||||||
|   if [ "$code" ] && [ ! "$code" = '201' ]; then |  | ||||||
|     _err "new-authz error: $response" |  | ||||||
|     return 1 |  | ||||||
|   fi |  | ||||||
| 
 |  | ||||||
|   entries="$(echo "$response" | _egrep_o '{ *"type":"[^"]*", *"status": *"valid", *"uri"[^}]*')" |  | ||||||
|   if [ -z "$entries" ]; then |   if [ -z "$entries" ]; then | ||||||
|     _info "No valid entries found." |     _info "No valid entries found." | ||||||
|     if [ -z "$thumbprint" ]; then |     if [ -z "$thumbprint" ]; then | ||||||
|       thumbprint="$(__calc_account_thumbprint)" |       thumbprint="$(__calc_account_thumbprint)" | ||||||
|     fi |     fi | ||||||
|     _debug "Trigger validation." |     _debug "Trigger validation." | ||||||
|     vtype="$VTYPE_HTTP" |     vtype="$VTYPE_DNS" | ||||||
|     entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" |     entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" | ||||||
|     _debug entry "$entry" |     _debug entry "$entry" | ||||||
|     if [ -z "$entry" ]; then |     if [ -z "$entry" ]; then | ||||||
| @ -4566,7 +4800,7 @@ _deactivate() { | |||||||
|     token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" |     token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" | ||||||
|     _debug token "$token" |     _debug token "$token" | ||||||
| 
 | 
 | ||||||
|     uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" |     uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" | ||||||
|     _debug uri "$uri" |     _debug uri "$uri" | ||||||
| 
 | 
 | ||||||
|     keyauthorization="$token.$thumbprint" |     keyauthorization="$token.$thumbprint" | ||||||
| @ -4592,7 +4826,7 @@ _deactivate() { | |||||||
|     _debug _vtype "$_vtype" |     _debug _vtype "$_vtype" | ||||||
|     _info "Found $_vtype" |     _info "Found $_vtype" | ||||||
| 
 | 
 | ||||||
|     uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" |     uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" | ||||||
|     _debug uri "$uri" |     _debug uri "$uri" | ||||||
| 
 | 
 | ||||||
|     if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then |     if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then | ||||||
| @ -4602,7 +4836,13 @@ _deactivate() { | |||||||
| 
 | 
 | ||||||
|     _info "Deactivate: $_vtype" |     _info "Deactivate: $_vtype" | ||||||
| 
 | 
 | ||||||
|     if _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then |     if [ "$ACME_VERSION" = "2" ]; then | ||||||
|  |       _djson="{\"status\":\"deactivated\"}" | ||||||
|  |     else | ||||||
|  |       _djson="{\"resource\": \"authz\", \"status\":\"deactivated\"}" | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if _send_signed_request "$authzUri" "$_djson" && _contains "$response" '"deactivated"'; then | ||||||
|       _info "Deactivate: $_vtype success." |       _info "Deactivate: $_vtype success." | ||||||
|     else |     else | ||||||
|       _err "Can not deactivate $_vtype." |       _err "Can not deactivate $_vtype." | ||||||
| @ -5324,6 +5564,10 @@ _process() { | |||||||
|             return 1 |             return 1 | ||||||
|           fi |           fi | ||||||
| 
 | 
 | ||||||
|  |           if _startswith "$_dvalue" "*."; then | ||||||
|  |             _debug "Wildcard domain" | ||||||
|  |             export ACME_VERSION=2 | ||||||
|  |           fi | ||||||
|           if [ -z "$_domain" ]; then |           if [ -z "$_domain" ]; then | ||||||
|             _domain="$_dvalue" |             _domain="$_dvalue" | ||||||
|           else |           else | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ dns_aws_add() { | |||||||
|     AWS_ACCESS_KEY_ID="" |     AWS_ACCESS_KEY_ID="" | ||||||
|     AWS_SECRET_ACCESS_KEY="" |     AWS_SECRET_ACCESS_KEY="" | ||||||
|     _err "You don't specify aws route53 api key id and and api key secret yet." |     _err "You don't specify aws route53 api key id and and api key secret yet." | ||||||
|     _err "Please create you key and try again. see $(__green $AWS_WIKI)" |     _err "Please create your key and try again. see $(__green $AWS_WIKI)" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -51,33 +51,36 @@ dns_cf_add() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) |   # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so | ||||||
|   _debug count "$count" |   # we can not use updating anymore. | ||||||
|   if [ "$count" = "0" ]; then |   #  count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) | ||||||
|     _info "Adding record" |   #  _debug count "$count" | ||||||
|     if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then |   #  if [ "$count" = "0" ]; then | ||||||
|       if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then |   _info "Adding record" | ||||||
|         _info "Added, OK" |   if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then | ||||||
|         return 0 |     if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then | ||||||
|       else |       _info "Added, OK" | ||||||
|         _err "Add txt record error." |  | ||||||
|         return 1 |  | ||||||
|       fi |  | ||||||
|     fi |  | ||||||
|     _err "Add txt record error." |  | ||||||
|   else |  | ||||||
|     _info "Updating record" |  | ||||||
|     record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) |  | ||||||
|     _debug "record_id" "$record_id" |  | ||||||
| 
 |  | ||||||
|     _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" |  | ||||||
|     if [ "$?" = "0" ]; then |  | ||||||
|       _info "Updated, OK" |  | ||||||
|       return 0 |       return 0 | ||||||
|  |     else | ||||||
|  |       _err "Add txt record error." | ||||||
|  |       return 1 | ||||||
|     fi |     fi | ||||||
|     _err "Update error" |  | ||||||
|     return 1 |  | ||||||
|   fi |   fi | ||||||
|  |   _err "Add txt record error." | ||||||
|  |   return 1 | ||||||
|  |   #  else | ||||||
|  |   #    _info "Updating record" | ||||||
|  |   #    record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) | ||||||
|  |   #    _debug "record_id" "$record_id" | ||||||
|  |   # | ||||||
|  |   #    _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" | ||||||
|  |   #    if [ "$?" = "0" ]; then | ||||||
|  |   #      _info "Updated, OK" | ||||||
|  |   #      return 0 | ||||||
|  |   #    fi | ||||||
|  |   #    _err "Update error" | ||||||
|  |   #    return 1 | ||||||
|  |   #  fi | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -78,13 +78,7 @@ _ovh_get_api() { | |||||||
|   esac |   esac | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ########  Public functions ##################### | _initAuth() { | ||||||
| 
 |  | ||||||
| #Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |  | ||||||
| dns_ovh_add() { |  | ||||||
|   fulldomain=$1 |  | ||||||
|   txtvalue=$2 |  | ||||||
| 
 |  | ||||||
|   if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then |   if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then | ||||||
|     OVH_AK="" |     OVH_AK="" | ||||||
|     OVH_AS="" |     OVH_AS="" | ||||||
| @ -119,14 +113,26 @@ dns_ovh_add() { | |||||||
| 
 | 
 | ||||||
|   _info "Checking authentication" |   _info "Checking authentication" | ||||||
| 
 | 
 | ||||||
|   response="$(_ovh_rest GET "domain")" |   if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL"; then | ||||||
|   if _contains "$response" "INVALID_CREDENTIAL"; then |  | ||||||
|     _err "The consumer key is invalid: $OVH_CK" |     _err "The consumer key is invalid: $OVH_CK" | ||||||
|     _err "Please retry to create a new one." |     _err "Please retry to create a new one." | ||||||
|     _clearaccountconf OVH_CK |     _clearaccountconf OVH_CK | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|   _info "Consumer key is ok." |   _info "Consumer key is ok." | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_ovh_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if ! _initAuth; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
| 
 | 
 | ||||||
|   _debug "First detect the root zone" |   _debug "First detect the root zone" | ||||||
|   if ! _get_root "$fulldomain"; then |   if ! _get_root "$fulldomain"; then | ||||||
| @ -137,49 +143,58 @@ dns_ovh_add() { | |||||||
|   _debug _sub_domain "$_sub_domain" |   _debug _sub_domain "$_sub_domain" | ||||||
|   _debug _domain "$_domain" |   _debug _domain "$_domain" | ||||||
| 
 | 
 | ||||||
|   _debug "Getting txt records" |   _info "Adding record" | ||||||
|   _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" |   if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then | ||||||
| 
 |     if _contains "$response" "$txtvalue"; then | ||||||
|   if _contains "$response" '\[\]' || _contains "$response" "This service does not exist"; then |       _ovh_rest POST "domain/zone/$_domain/refresh" | ||||||
|     _info "Adding record" |       _debug "Refresh:$response" | ||||||
|     if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then |       _info "Added, sleep 10 seconds." | ||||||
|       if _contains "$response" "$txtvalue"; then |       _sleep 10 | ||||||
|         _ovh_rest POST "domain/zone/$_domain/refresh" |       return 0 | ||||||
|         _debug "Refresh:$response" |  | ||||||
|         _info "Added, sleeping 10 seconds" |  | ||||||
|         sleep 10 |  | ||||||
|         return 0 |  | ||||||
|       fi |  | ||||||
|     fi |     fi | ||||||
|     _err "Add txt record error." |  | ||||||
|   else |  | ||||||
|     _info "Updating record" |  | ||||||
|     record_id=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 1) |  | ||||||
|     if [ -z "$record_id" ]; then |  | ||||||
|       _err "Can not get record id." |  | ||||||
|       return 1 |  | ||||||
|     fi |  | ||||||
|     _debug "record_id" "$record_id" |  | ||||||
| 
 |  | ||||||
|     if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}"; then |  | ||||||
|       if _contains "$response" "null"; then |  | ||||||
|         _ovh_rest POST "domain/zone/$_domain/refresh" |  | ||||||
|         _debug "Refresh:$response" |  | ||||||
|         _info "Updated, sleeping 10 seconds" |  | ||||||
|         sleep 10 |  | ||||||
|         return 0 |  | ||||||
|       fi |  | ||||||
|     fi |  | ||||||
|     _err "Update error" |  | ||||||
|     return 1 |  | ||||||
|   fi |   fi | ||||||
|  |   _err "Add txt record error." | ||||||
|  |   return 1 | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #fulldomain | #fulldomain | ||||||
| dns_ovh_rm() { | dns_ovh_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
| 
 | 
 | ||||||
|  |   if ! _initAuth; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug "First detect the root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  |   _debug "Getting txt records" | ||||||
|  |   if ! _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   for rid in $(echo "$response" | tr '][,' '   '); do | ||||||
|  |     _debug rid "$rid" | ||||||
|  |     if ! _ovh_rest GET "domain/zone/$_domain/record/$rid"; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     if _contains "$response" "\"target\":\"$txtvalue\""; then | ||||||
|  |       _debug "Found txt id:$rid" | ||||||
|  |       if ! _ovh_rest DELETE "domain/zone/$_domain/record/$rid"; then | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ####################  Private functions below ################################## | ####################  Private functions below ################################## | ||||||
| @ -191,7 +206,7 @@ _ovh_authentication() { | |||||||
|   _H3="" |   _H3="" | ||||||
|   _H4="" |   _H4="" | ||||||
| 
 | 
 | ||||||
|   _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' |   _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"},{"method": "DELETE","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' | ||||||
| 
 | 
 | ||||||
|   response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" |   response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" | ||||||
|   _debug3 response "$response" |   _debug3 response "$response" | ||||||
| @ -279,15 +294,15 @@ _ovh_rest() { | |||||||
|   export _H3="X-Ovh-Timestamp: $_ovh_t" |   export _H3="X-Ovh-Timestamp: $_ovh_t" | ||||||
|   export _H4="X-Ovh-Consumer: $OVH_CK" |   export _H4="X-Ovh-Consumer: $OVH_CK" | ||||||
|   export _H5="Content-Type: application/json;charset=utf-8" |   export _H5="Content-Type: application/json;charset=utf-8" | ||||||
|   if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then |   if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then | ||||||
|     _debug data "$data" |     _debug data "$data" | ||||||
|     response="$(_post "$data" "$_ovh_url" "" "$m")" |     response="$(_post "$data" "$_ovh_url" "" "$m")" | ||||||
|   else |   else | ||||||
|     response="$(_get "$_ovh_url")" |     response="$(_get "$_ovh_url")" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if [ "$?" != "0" ]; then |   if [ "$?" != "0" ] || _contains "$response" "INVALID_CREDENTIAL"; then | ||||||
|     _err "error $ep" |     _err "error $response" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|   _debug2 response "$response" |   _debug2 response "$response" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user