mirror of
				https://github.com/hiskang/acme.sh
				synced 2025-10-31 10:27:22 +00:00 
			
		
		
		
	Merge branch 'dev' into master
This commit is contained in:
		
						commit
						9201e0a5b9
					
				
							
								
								
									
										59
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | FROM alpine | ||||||
|  | 
 | ||||||
|  | RUN apk update -f \ | ||||||
|  |   && apk --no-cache add -f \ | ||||||
|  |   openssl \ | ||||||
|  |   curl \ | ||||||
|  |   netcat-openbsd | ||||||
|  | 
 | ||||||
|  | ENV LE_CONFIG_HOME /acme.sh | ||||||
|  | 
 | ||||||
|  | ENV AUTO_UPGRADE 1 | ||||||
|  | 
 | ||||||
|  | #Install | ||||||
|  | RUN mkdir -p /install_acme.sh/ | ||||||
|  | ADD ./ /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) | ||||||
|  | RUN rm -rf /install_acme.sh/ | ||||||
|  | 
 | ||||||
|  | RUN ln -s  /root/.acme.sh/acme.sh  /usr/local/bin/acme.sh | ||||||
|  | 
 | ||||||
|  | RUN for verb in help \  | ||||||
|  |   version \ | ||||||
|  |   install \ | ||||||
|  |   uninstall \ | ||||||
|  |   upgrade \ | ||||||
|  |   issue \ | ||||||
|  |   signcsr \ | ||||||
|  |   deploy \ | ||||||
|  |   install-cert \ | ||||||
|  |   renew \ | ||||||
|  |   renew-all \ | ||||||
|  |   revoke \ | ||||||
|  |   remove \ | ||||||
|  |   list \ | ||||||
|  |   showcsr \ | ||||||
|  |   install-cronjob \ | ||||||
|  |   uninstall-cronjob \ | ||||||
|  |   cron \ | ||||||
|  |   toPkcs \ | ||||||
|  |   toPkcs8 \ | ||||||
|  |   update-account \ | ||||||
|  |   register-account \ | ||||||
|  |   create-account-key \ | ||||||
|  |   create-domain-key \ | ||||||
|  |   createCSR \ | ||||||
|  |   deactivate \ | ||||||
|  |   ; do \ | ||||||
|  |     printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \ | ||||||
|  |   ; done | ||||||
|  | 
 | ||||||
|  | RUN printf "%b" '#!'"/usr/bin/env sh\n \ | ||||||
|  | if [ \"\$1\" = \"daemon\" ];  then \n \ | ||||||
|  |  crond; tail -f /dev/null;\n \ | ||||||
|  | else \n \ | ||||||
|  |  /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ | ||||||
|  | fi" >/entry.sh && chmod +x /entry.sh | ||||||
|  | 
 | ||||||
|  | ENTRYPOINT ["/entry.sh"] | ||||||
|  | CMD ["--help"] | ||||||
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
								
							| @ -7,11 +7,13 @@ | |||||||
| - Purely written in Shell with no dependencies on python or the official Let's Encrypt client. | - Purely written in Shell with no dependencies on python or the official Let's Encrypt client. | ||||||
| - Just one script to issue, renew and install your certificates automatically. | - Just one script to issue, renew and install your certificates automatically. | ||||||
| - DOES NOT require `root/sudoer` access. | - DOES NOT require `root/sudoer` access. | ||||||
|  | - Docker friendly | ||||||
| 
 | 
 | ||||||
| It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. | It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. | ||||||
| 
 | 
 | ||||||
| Wiki: https://github.com/Neilpang/acme.sh/wiki | Wiki: https://github.com/Neilpang/acme.sh/wiki | ||||||
| 
 | 
 | ||||||
|  | For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/Neilpang/acme.sh/wiki/Run-acme.sh-in-docker) | ||||||
| 
 | 
 | ||||||
| Twitter: [@neilpangxa](https://twitter.com/neilpangxa) | Twitter: [@neilpangxa](https://twitter.com/neilpangxa) | ||||||
| 
 | 
 | ||||||
| @ -29,6 +31,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) | |||||||
| - [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) | - [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) | ||||||
| - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) | - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) | ||||||
| - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) | - [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) | ||||||
| - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) | - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) | ||||||
| 
 | 
 | ||||||
| # Tested OS | # Tested OS | ||||||
| @ -133,13 +136,25 @@ root@v1:~# acme.sh -h | |||||||
| acme.sh --issue -d example.com -w /home/wwwroot/example.com | acme.sh --issue -d example.com -w /home/wwwroot/example.com | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | or: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | acme.sh --issue -d example.com -w /home/username/public_html | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | or: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | acme.sh --issue -d example.com -w /var/www/html | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| **Example 2:** Multiple domains in the same cert. | **Example 2:** Multiple domains in the same cert. | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com | acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| The parameter `/home/wwwroot/example.com` is the web root folder. You **MUST** have `write access` to this folder. | The parameter `/home/wwwroot/example.com` or `/home/username/public_html` or `/var/www/html` is the web root folder where you host your website files. You **MUST** have `write access` to this folder. | ||||||
| 
 | 
 | ||||||
| Second argument **"example.com"** is the main domain you want to issue the cert for. | Second argument **"example.com"** is the main domain you want to issue the cert for. | ||||||
| You must have at least one domain there. | You must have at least one domain there. | ||||||
| @ -161,17 +176,17 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT** | |||||||
| **Apache** example: | **Apache** example: | ||||||
| ```bash | ```bash | ||||||
| acme.sh --install-cert -d example.com \ | acme.sh --install-cert -d example.com \ | ||||||
| --certpath      /path/to/certfile/in/apache/cert.pem  \ | --cert-file      /path/to/certfile/in/apache/cert.pem  \ | ||||||
| --keypath       /path/to/keyfile/in/apache/key.pem  \ | --key-file       /path/to/keyfile/in/apache/key.pem  \ | ||||||
| --fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ | --fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \ | ||||||
| --reloadcmd     "service apache2 force-reload" | --reloadcmd     "service apache2 force-reload" | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| **Nginx** example: | **Nginx** example: | ||||||
| ```bash | ```bash | ||||||
| acme.sh --install-cert -d example.com \ | acme.sh --install-cert -d example.com \ | ||||||
| --keypath       /path/to/keyfile/in/nginx/key.pem  \ | --key-file       /path/to/keyfile/in/nginx/key.pem  \ | ||||||
| --fullchainpath /path/to/fullchain/nginx/cert.pem \ | --fullchain-file /path/to/fullchain/nginx/cert.pem \ | ||||||
| --reloadcmd     "service nginx force-reload" | --reloadcmd     "service nginx force-reload" | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| @ -289,6 +304,7 @@ You don't have to do anything manually! | |||||||
| 
 | 
 | ||||||
| 1. CloudFlare.com API | 1. CloudFlare.com API | ||||||
| 1. DNSPod.cn API | 1. DNSPod.cn API | ||||||
|  | 1. DNSimple API | ||||||
| 1. CloudXNS.com API | 1. CloudXNS.com API | ||||||
| 1. GoDaddy.com API | 1. GoDaddy.com API | ||||||
| 1. OVH, kimsufi, soyoustart and runabove API | 1. OVH, kimsufi, soyoustart and runabove API | ||||||
| @ -308,7 +324,13 @@ You don't have to do anything manually! | |||||||
| 1. Domain-Offensive/Resellerinterface/Domainrobot API | 1. Domain-Offensive/Resellerinterface/Domainrobot API | ||||||
| 1. Gandi LiveDNS API | 1. Gandi LiveDNS API | ||||||
| 1. Knot DNS API | 1. Knot DNS API | ||||||
| 1. NS1. API | 1. NS1.com API | ||||||
|  | 1. DigitalOcean API (native) | ||||||
|  | 1. ClouDNS.net API | ||||||
|  | 1. Infoblox NIOS API (https://www.infoblox.com/) | ||||||
|  | 1. VSCALE (https://vscale.io/) | ||||||
|  | 1. Dynu API (https://www.dynu.com) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| **More APIs coming soon...** | **More APIs coming soon...** | ||||||
| 
 | 
 | ||||||
| @ -327,7 +349,7 @@ Just set the `length` parameter with a prefix `ec-`. | |||||||
| 
 | 
 | ||||||
| For example: | For example: | ||||||
| 
 | 
 | ||||||
| ### Single domain ECC cerfiticate | ### Single domain ECC certificate | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256 | acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256 | ||||||
|  | |||||||
							
								
								
									
										264
									
								
								acme.sh
									
									
									
									
									
								
							
							
						
						
									
										264
									
								
								acme.sh
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| #!/usr/bin/env sh | #!/usr/bin/env sh | ||||||
| 
 | 
 | ||||||
| VER=2.6.7 | VER=2.6.9 | ||||||
| 
 | 
 | ||||||
| PROJECT_NAME="acme.sh" | PROJECT_NAME="acme.sh" | ||||||
| 
 | 
 | ||||||
| @ -107,7 +107,7 @@ __green() { | |||||||
|   if [ "$__INTERACTIVE" ]; then |   if [ "$__INTERACTIVE" ]; then | ||||||
|     printf '\033[1;31;32m' |     printf '\033[1;31;32m' | ||||||
|   fi |   fi | ||||||
|   printf -- "$1" |   printf -- "%b" "$1" | ||||||
|   if [ "$__INTERACTIVE" ]; then |   if [ "$__INTERACTIVE" ]; then | ||||||
|     printf '\033[0m' |     printf '\033[0m' | ||||||
|   fi |   fi | ||||||
| @ -117,7 +117,7 @@ __red() { | |||||||
|   if [ "$__INTERACTIVE" ]; then |   if [ "$__INTERACTIVE" ]; then | ||||||
|     printf '\033[1;31;40m' |     printf '\033[1;31;40m' | ||||||
|   fi |   fi | ||||||
|   printf -- "$1" |   printf -- "%b" "$1" | ||||||
|   if [ "$__INTERACTIVE" ]; then |   if [ "$__INTERACTIVE" ]; then | ||||||
|     printf '\033[0m' |     printf '\033[0m' | ||||||
|   fi |   fi | ||||||
| @ -138,8 +138,8 @@ _printargs() { | |||||||
| _dlg_versions() { | _dlg_versions() { | ||||||
|   echo "Diagnosis versions: " |   echo "Diagnosis versions: " | ||||||
|   echo "openssl:$ACME_OPENSSL_BIN" |   echo "openssl:$ACME_OPENSSL_BIN" | ||||||
|   if _exists "$ACME_OPENSSL_BIN"; then |   if _exists "${ACME_OPENSSL_BIN:-openssl}"; then | ||||||
|     $ACME_OPENSSL_BIN version 2>&1 |     ${ACME_OPENSSL_BIN:-openssl} version 2>&1 | ||||||
|   else |   else | ||||||
|     echo "$ACME_OPENSSL_BIN doesn't exists." |     echo "$ACME_OPENSSL_BIN doesn't exists." | ||||||
|   fi |   fi | ||||||
| @ -166,7 +166,14 @@ _syslog() { | |||||||
|   fi |   fi | ||||||
|   _logclass="$1" |   _logclass="$1" | ||||||
|   shift |   shift | ||||||
|   logger -i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 |   if [ -z "$__logger_i" ]; then | ||||||
|  |     if _contains "$(logger --help 2>&1)" "-i"; then | ||||||
|  |       __logger_i="logger -i" | ||||||
|  |     else | ||||||
|  |       __logger_i="logger" | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  |   $__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| _log() { | _log() { | ||||||
| @ -299,6 +306,16 @@ _secure_debug3() { | |||||||
|   fi |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | _upper_case() { | ||||||
|  |   # shellcheck disable=SC2018,SC2019 | ||||||
|  |   tr 'a-z' 'A-Z' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _lower_case() { | ||||||
|  |   # shellcheck disable=SC2018,SC2019 | ||||||
|  |   tr 'A-Z' 'a-z' | ||||||
|  | } | ||||||
|  | 
 | ||||||
| _startswith() { | _startswith() { | ||||||
|   _str="$1" |   _str="$1" | ||||||
|   _sub="$2" |   _sub="$2" | ||||||
| @ -330,7 +347,7 @@ _hasfield() { | |||||||
|     _sep="," |     _sep="," | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   for f in $(echo "$_str" | tr ',' ' '); do |   for f in $(echo "$_str" | tr "$_sep" ' '); do | ||||||
|     if [ "$f" = "$_field" ]; then |     if [ "$f" = "$_field" ]; then | ||||||
|       _debug2 "'$_str' contains '$_field'" |       _debug2 "'$_str' contains '$_field'" | ||||||
|       return 0 #contains ok |       return 0 #contains ok | ||||||
| @ -780,19 +797,19 @@ _base64() { | |||||||
|   [ "" ] #urgly |   [ "" ] #urgly | ||||||
|   if [ "$1" ]; then |   if [ "$1" ]; then | ||||||
|     _debug3 "base64 multiline:'$1'" |     _debug3 "base64 multiline:'$1'" | ||||||
|     $ACME_OPENSSL_BIN base64 -e |     ${ACME_OPENSSL_BIN:-openssl} base64 -e | ||||||
|   else |   else | ||||||
|     _debug3 "base64 single line." |     _debug3 "base64 single line." | ||||||
|     $ACME_OPENSSL_BIN base64 -e | tr -d '\r\n' |     ${ACME_OPENSSL_BIN:-openssl} base64 -e | tr -d '\r\n' | ||||||
|   fi |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #Usage: multiline | #Usage: multiline | ||||||
| _dbase64() { | _dbase64() { | ||||||
|   if [ "$1" ]; then |   if [ "$1" ]; then | ||||||
|     $ACME_OPENSSL_BIN base64 -d -A |     ${ACME_OPENSSL_BIN:-openssl} base64 -d -A | ||||||
|   else |   else | ||||||
|     $ACME_OPENSSL_BIN base64 -d |     ${ACME_OPENSSL_BIN:-openssl} base64 -d | ||||||
|   fi |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -809,9 +826,9 @@ _digest() { | |||||||
| 
 | 
 | ||||||
|   if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then |   if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then | ||||||
|     if [ "$outputhex" ]; then |     if [ "$outputhex" ]; then | ||||||
|       $ACME_OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' |       ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' | ||||||
|     else |     else | ||||||
|       $ACME_OPENSSL_BIN dgst -"$alg" -binary | _base64 |       ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -binary | _base64 | ||||||
|     fi |     fi | ||||||
|   else |   else | ||||||
|     _err "$alg is not supported yet" |     _err "$alg is not supported yet" | ||||||
| @ -834,9 +851,9 @@ _hmac() { | |||||||
| 
 | 
 | ||||||
|   if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then |   if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then | ||||||
|     if [ "$outputhex" ]; then |     if [ "$outputhex" ]; then | ||||||
|       ($ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' |       (${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' | ||||||
|     else |     else | ||||||
|       $ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary |       ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary | ||||||
|     fi |     fi | ||||||
|   else |   else | ||||||
|     _err "$alg is not supported yet" |     _err "$alg is not supported yet" | ||||||
| @ -855,7 +872,7 @@ _sign() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   _sign_openssl="$ACME_OPENSSL_BIN   dgst -sign $keyfile " |   _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " | ||||||
|   if [ "$alg" = "sha256" ]; then |   if [ "$alg" = "sha256" ]; then | ||||||
|     _sign_openssl="$_sign_openssl -$alg" |     _sign_openssl="$_sign_openssl -$alg" | ||||||
|   else |   else | ||||||
| @ -866,10 +883,10 @@ _sign() { | |||||||
|   if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then |   if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then | ||||||
|     $_sign_openssl | _base64 |     $_sign_openssl | _base64 | ||||||
|   elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then |   elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then | ||||||
|     if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then |     if ! _signedECText="$($_sign_openssl | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then | ||||||
|       _err "Sign failed: $_sign_openssl" |       _err "Sign failed: $_sign_openssl" | ||||||
|       _err "Key file: $keyfile" |       _err "Key file: $keyfile" | ||||||
|       _err "Key content:$(wc -l <"$keyfile") lises" |       _err "Key content:$(wc -l <"$keyfile") lines" | ||||||
|       return 1 |       return 1 | ||||||
|     fi |     fi | ||||||
|     _debug3 "_signedECText" "$_signedECText" |     _debug3 "_signedECText" "$_signedECText" | ||||||
| @ -938,10 +955,10 @@ _createkey() { | |||||||
| 
 | 
 | ||||||
|   if _isEccKey "$length"; then |   if _isEccKey "$length"; then | ||||||
|     _debug "Using ec name: $eccname" |     _debug "Using ec name: $eccname" | ||||||
|     $ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" |     ${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null >"$f" | ||||||
|   else |   else | ||||||
|     _debug "Using RSA: $length" |     _debug "Using RSA: $length" | ||||||
|     $ACME_OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" |     ${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null >"$f" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if [ "$?" != "0" ]; then |   if [ "$?" != "0" ]; then | ||||||
| @ -1028,9 +1045,9 @@ _createcsr() { | |||||||
|   _csr_cn="$(_idn "$domain")" |   _csr_cn="$(_idn "$domain")" | ||||||
|   _debug2 _csr_cn "$_csr_cn" |   _debug2 _csr_cn "$_csr_cn" | ||||||
|   if _contains "$(uname -a)" "MINGW"; then |   if _contains "$(uname -a)" "MINGW"; then | ||||||
|     $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" |     ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" | ||||||
|   else |   else | ||||||
|     $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" |     ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" | ||||||
|   fi |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -1042,7 +1059,7 @@ _signcsr() { | |||||||
|   cert="$4" |   cert="$4" | ||||||
|   _debug "_signcsr" |   _debug "_signcsr" | ||||||
| 
 | 
 | ||||||
|   _msg="$($ACME_OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" |   _msg="$(${ACME_OPENSSL_BIN:-openssl} x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" | ||||||
|   _ret="$?" |   _ret="$?" | ||||||
|   _debug "$_msg" |   _debug "$_msg" | ||||||
|   return $_ret |   return $_ret | ||||||
| @ -1055,7 +1072,7 @@ _readSubjectFromCSR() { | |||||||
|     _usage "_readSubjectFromCSR mycsr.csr" |     _usage "_readSubjectFromCSR mycsr.csr" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|   $ACME_OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' |   ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #_csrfile | #_csrfile | ||||||
| @ -1070,7 +1087,7 @@ _readSubjectAltNamesFromCSR() { | |||||||
|   _csrsubj="$(_readSubjectFromCSR "$_csrfile")" |   _csrsubj="$(_readSubjectFromCSR "$_csrfile")" | ||||||
|   _debug _csrsubj "$_csrsubj" |   _debug _csrsubj "$_csrsubj" | ||||||
| 
 | 
 | ||||||
|   _dnsAltnames="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" |   _dnsAltnames="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" | ||||||
|   _debug _dnsAltnames "$_dnsAltnames" |   _debug _dnsAltnames "$_dnsAltnames" | ||||||
| 
 | 
 | ||||||
|   if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then |   if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then | ||||||
| @ -1091,13 +1108,14 @@ _readKeyLengthFromCSR() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   _outcsr="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile")" |   _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" | ||||||
|  |   _debug2 _outcsr "$_outcsr" | ||||||
|   if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then |   if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then | ||||||
|     _debug "ECC CSR" |     _debug "ECC CSR" | ||||||
|     echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' |     echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' | ||||||
|   else |   else | ||||||
|     _debug "RSA CSR" |     _debug "RSA CSR" | ||||||
|     echo "$_outcsr" | _egrep_o "(^ *|^RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 |     echo "$_outcsr" | tr "\t" " " | _egrep_o "(^ *|RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 | ||||||
|   fi |   fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -1121,8 +1139,12 @@ _ss() { | |||||||
|       elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then |       elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then | ||||||
|         #for solaris |         #for solaris | ||||||
|         netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" |         netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" | ||||||
|       else |       elif netstat -help 2>&1 | grep "\-p" >/dev/null; then | ||||||
|  |         #for full linux | ||||||
|         netstat -ntpl | grep ":$_port " |         netstat -ntpl | grep ":$_port " | ||||||
|  |       else | ||||||
|  |         #for busybox (embedded linux; no pid support) | ||||||
|  |         netstat -ntl 2>/dev/null | grep ":$_port " | ||||||
|       fi |       fi | ||||||
|     fi |     fi | ||||||
|     return 0 |     return 0 | ||||||
| @ -1145,9 +1167,9 @@ toPkcs() { | |||||||
|   _initpath "$domain" "$_isEcc" |   _initpath "$domain" "$_isEcc" | ||||||
| 
 | 
 | ||||||
|   if [ "$pfxPassword" ]; then |   if [ "$pfxPassword" ]; then | ||||||
|     $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" |     ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" | ||||||
|   else |   else | ||||||
|     $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" |     ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if [ "$?" = "0" ]; then |   if [ "$?" = "0" ]; then | ||||||
| @ -1169,7 +1191,7 @@ toPkcs8() { | |||||||
| 
 | 
 | ||||||
|   _initpath "$domain" "$_isEcc" |   _initpath "$domain" "$_isEcc" | ||||||
| 
 | 
 | ||||||
|   $ACME_OPENSSL_BIN pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" |   ${ACME_OPENSSL_BIN:-openssl} pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" | ||||||
| 
 | 
 | ||||||
|   if [ "$?" = "0" ]; then |   if [ "$?" = "0" ]; then | ||||||
|     _info "Success, $CERT_PKCS8_PATH" |     _info "Success, $CERT_PKCS8_PATH" | ||||||
| @ -1330,7 +1352,7 @@ _calcjwk() { | |||||||
| 
 | 
 | ||||||
|   if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then |   if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then | ||||||
|     _debug "RSA key" |     _debug "RSA key" | ||||||
|     pub_exp=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) |     pub_exp=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) | ||||||
|     if [ "${#pub_exp}" = "5" ]; then |     if [ "${#pub_exp}" = "5" ]; then | ||||||
|       pub_exp=0$pub_exp |       pub_exp=0$pub_exp | ||||||
|     fi |     fi | ||||||
| @ -1339,7 +1361,7 @@ _calcjwk() { | |||||||
|     e=$(echo "$pub_exp" | _h2b | _base64) |     e=$(echo "$pub_exp" | _h2b | _base64) | ||||||
|     _debug3 e "$e" |     _debug3 e "$e" | ||||||
| 
 | 
 | ||||||
|     modulus=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) |     modulus=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) | ||||||
|     _debug3 modulus "$modulus" |     _debug3 modulus "$modulus" | ||||||
|     n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" |     n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" | ||||||
|     _debug3 n "$n" |     _debug3 n "$n" | ||||||
| @ -1352,12 +1374,12 @@ _calcjwk() { | |||||||
|     JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' |     JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' | ||||||
|   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 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")" | ||||||
|     _debug3 crv "$crv" |     _debug3 crv "$crv" | ||||||
| 
 | 
 | ||||||
|     if [ -z "$crv" ]; then |     if [ -z "$crv" ]; then | ||||||
|       _debug "Let's try ASN1 OID" |       _debug "Let's try ASN1 OID" | ||||||
|       crv_oid="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" |       crv_oid="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" | ||||||
|       _debug3 crv_oid "$crv_oid" |       _debug3 crv_oid "$crv_oid" | ||||||
|       case "${crv_oid}" in |       case "${crv_oid}" in | ||||||
|         "prime256v1") |         "prime256v1") | ||||||
| @ -1377,15 +1399,15 @@ _calcjwk() { | |||||||
|       _debug3 crv "$crv" |       _debug3 crv "$crv" | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     pubi="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" |     pubi="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" | ||||||
|     pubi=$(_math "$pubi" + 1) |     pubi=$(_math "$pubi" + 1) | ||||||
|     _debug3 pubi "$pubi" |     _debug3 pubi "$pubi" | ||||||
| 
 | 
 | ||||||
|     pubj="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" |     pubj="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" | ||||||
|     pubj=$(_math "$pubj" - 1) |     pubj=$(_math "$pubj" - 1) | ||||||
|     _debug3 pubj "$pubj" |     _debug3 pubj "$pubj" | ||||||
| 
 | 
 | ||||||
|     pubtext="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" |     pubtext="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" | ||||||
|     _debug3 pubtext "$pubtext" |     _debug3 pubtext "$pubtext" | ||||||
| 
 | 
 | ||||||
|     xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" |     xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" | ||||||
| @ -1469,7 +1491,9 @@ _inithttp() { | |||||||
|       _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " |       _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if [ "$CA_BUNDLE" ]; then |     if [ "$CA_PATH" ]; then | ||||||
|  |       _ACME_CURL="$_ACME_CURL --capath $CA_PATH " | ||||||
|  |     elif [ "$CA_BUNDLE" ]; then | ||||||
|       _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " |       _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
| @ -1480,8 +1504,10 @@ _inithttp() { | |||||||
|     if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then |     if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then | ||||||
|       _ACME_WGET="$_ACME_WGET -d " |       _ACME_WGET="$_ACME_WGET -d " | ||||||
|     fi |     fi | ||||||
|     if [ "$CA_BUNDLE" ]; then |     if [ "$CA_PATH" ]; then | ||||||
|       _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " |       _ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH " | ||||||
|  |     elif [ "$CA_BUNDLE" ]; then | ||||||
|  |       _ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE " | ||||||
|     fi |     fi | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
| @ -1828,6 +1854,24 @@ _saveaccountconf() { | |||||||
|   _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2" |   _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2" | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #key  value | ||||||
|  | _saveaccountconf_mutable() { | ||||||
|  |   _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" | ||||||
|  |   #remove later | ||||||
|  |   _clearaccountconf "$1" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #key | ||||||
|  | _readaccountconf() { | ||||||
|  |   _read_conf "$ACCOUNT_CONF_PATH" "$1" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #key | ||||||
|  | _readaccountconf_mutable() { | ||||||
|  |   _rac_key="$1" | ||||||
|  |   _readaccountconf "SAVED_$_rac_key" | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #_clearaccountconf   key | #_clearaccountconf   key | ||||||
| _clearaccountconf() { | _clearaccountconf() { | ||||||
|   _clear_conf "$ACCOUNT_CONF_PATH" "$1" |   _clear_conf "$ACCOUNT_CONF_PATH" "$1" | ||||||
| @ -1999,7 +2043,7 @@ _starttlsserver() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   __S_OPENSSL="$ACME_OPENSSL_BIN s_server -cert $TLS_CERT  -key $TLS_KEY " |   __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -cert $TLS_CERT  -key $TLS_KEY " | ||||||
|   if [ "$opaddr" ]; then |   if [ "$opaddr" ]; then | ||||||
|     __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" |     __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" | ||||||
|   else |   else | ||||||
| @ -2240,16 +2284,16 @@ _initpath() { | |||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if [ -z "$TLS_CONF" ]; then |   if [ -z "$TLS_CONF" ]; then | ||||||
|     TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" |     TLS_CONF="$DOMAIN_PATH/tls.validation.conf" | ||||||
|   fi |   fi | ||||||
|   if [ -z "$TLS_CERT" ]; then |   if [ -z "$TLS_CERT" ]; then | ||||||
|     TLS_CERT="$DOMAIN_PATH/tls.valdation.cert" |     TLS_CERT="$DOMAIN_PATH/tls.validation.cert" | ||||||
|   fi |   fi | ||||||
|   if [ -z "$TLS_KEY" ]; then |   if [ -z "$TLS_KEY" ]; then | ||||||
|     TLS_KEY="$DOMAIN_PATH/tls.valdation.key" |     TLS_KEY="$DOMAIN_PATH/tls.validation.key" | ||||||
|   fi |   fi | ||||||
|   if [ -z "$TLS_CSR" ]; then |   if [ -z "$TLS_CSR" ]; then | ||||||
|     TLS_CSR="$DOMAIN_PATH/tls.valdation.csr" |     TLS_CSR="$DOMAIN_PATH/tls.validation.csr" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| @ -2367,7 +2411,7 @@ _setApache() { | |||||||
|   _debug "Backup apache config file" "$httpdconf" |   _debug "Backup apache config file" "$httpdconf" | ||||||
|   if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then |   if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then | ||||||
|     _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed." |     _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed." | ||||||
|     _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT" |     _err "This might be a bug of $PROJECT_NAME , please report issue: $PROJECT" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|   _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" |   _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" | ||||||
| @ -2546,7 +2590,7 @@ _checkConf() { | |||||||
|   if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then |   if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then | ||||||
|     _debug "wildcard" |     _debug "wildcard" | ||||||
|     for _w_f in $2; do |     for _w_f in $2; do | ||||||
|       if [ -f "$_w_f"] && _checkConf "$1" "$_w_f"; then |       if [ -f "$_w_f" ] && _checkConf "$1" "$_w_f"; then | ||||||
|         return 0 |         return 0 | ||||||
|       fi |       fi | ||||||
|     done |     done | ||||||
| @ -2580,10 +2624,10 @@ _checkConf() { | |||||||
| _isRealNginxConf() { | _isRealNginxConf() { | ||||||
|   _debug "_isRealNginxConf $1 $2" |   _debug "_isRealNginxConf $1 $2" | ||||||
|   if [ -f "$2" ]; then |   if [ -f "$2" ]; then | ||||||
|     for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do |     for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do | ||||||
|       _debug _fln "$_fln" |       _debug _fln "$_fln" | ||||||
|       if [ "$_fln" ]; then |       if [ "$_fln" ]; then | ||||||
|         _start=$(cat "$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) |         _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) | ||||||
|         _debug "_start" "$_start" |         _debug "_start" "$_start" | ||||||
|         _start_n=$(echo "$_start" | cut -d : -f 1) |         _start_n=$(echo "$_start" | cut -d : -f 1) | ||||||
|         _start_nn=$(_math $_start_n + 1) |         _start_nn=$(_math $_start_n + 1) | ||||||
| @ -2592,8 +2636,8 @@ _isRealNginxConf() { | |||||||
| 
 | 
 | ||||||
|         _left="$(sed -n "${_start_nn},99999p" "$2")" |         _left="$(sed -n "${_start_nn},99999p" "$2")" | ||||||
|         _debug2 _left "$_left" |         _debug2 _left "$_left" | ||||||
|         if echo "$_left" | grep -n "^ *server *{" >/dev/null; then |         if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" >/dev/null; then | ||||||
|           _end=$(echo "$_left" | grep -n "^ *server *{" | _head_n 1) |           _end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" | _head_n 1) | ||||||
|           _debug "_end" "$_end" |           _debug "_end" "$_end" | ||||||
|           _end_n=$(echo "$_end" | cut -d : -f 1) |           _end_n=$(echo "$_end" | cut -d : -f 1) | ||||||
|           _debug "_end_n" "$_end_n" |           _debug "_end_n" "$_end_n" | ||||||
| @ -2865,7 +2909,7 @@ _on_issue_err() { | |||||||
|         uri=$(echo "$ventry" | cut -d "$sep" -f 3) |         uri=$(echo "$ventry" | cut -d "$sep" -f 3) | ||||||
|         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) | ||||||
|         __trigger_validaton "$uri" "$keyauthorization" |         __trigger_validation "$uri" "$keyauthorization" | ||||||
|       done |       done | ||||||
|     ) |     ) | ||||||
|   fi |   fi | ||||||
| @ -3087,7 +3131,7 @@ __get_domain_new_authz() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #uri keyAuthorization | #uri keyAuthorization | ||||||
| __trigger_validaton() { | __trigger_validation() { | ||||||
|   _debug2 "tigger domain validation." |   _debug2 "tigger domain validation." | ||||||
|   _t_url="$1" |   _t_url="$1" | ||||||
|   _debug2 _t_url "$_t_url" |   _debug2 _t_url "$_t_url" | ||||||
| @ -3102,6 +3146,10 @@ issue() { | |||||||
|     _usage "Usage: $PROJECT_ENTRY --issue  -d  a.com  -w /path/to/webroot/a.com/ " |     _usage "Usage: $PROJECT_ENTRY --issue  -d  a.com  -w /path/to/webroot/a.com/ " | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|  |   if [ -z "$1" ]; then | ||||||
|  |     _usage "Please specify at least one validation method: '--webroot', '--standalone', '--apache', '--nginx' or '--dns' etc." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|   _web_roots="$1" |   _web_roots="$1" | ||||||
|   _main_domain="$2" |   _main_domain="$2" | ||||||
|   _alt_domains="$3" |   _alt_domains="$3" | ||||||
| @ -3467,9 +3515,12 @@ issue() { | |||||||
|         if [ ! "$usingApache" ]; then |         if [ ! "$usingApache" ]; then | ||||||
|           if webroot_owner=$(_stat "$_currentRoot"); then |           if webroot_owner=$(_stat "$_currentRoot"); then | ||||||
|             _debug "Changing owner/group of .well-known to $webroot_owner" |             _debug "Changing owner/group of .well-known to $webroot_owner" | ||||||
|             chown -R "$webroot_owner" "$_currentRoot/.well-known" |             if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then | ||||||
|  |               _debug "$(cat "$_EXEC_TEMP_ERR")" | ||||||
|  |               _exec_err >/dev/null 2>&1 | ||||||
|  |             fi | ||||||
|           else |           else | ||||||
|             _debug "not chaning owner/group of webroot" |             _debug "not changing owner/group of webroot" | ||||||
|           fi |           fi | ||||||
|         fi |         fi | ||||||
| 
 | 
 | ||||||
| @ -3510,7 +3561,7 @@ issue() { | |||||||
|       fi |       fi | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if ! __trigger_validaton "$uri" "$keyauthorization"; then |     if ! __trigger_validation "$uri" "$keyauthorization"; then | ||||||
|       _err "$d:Can not get challenge: $response" |       _err "$d:Can not get challenge: $response" | ||||||
|       _clearupwebbroot "$_currentRoot" "$removelevel" "$token" |       _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | ||||||
|       _clearup |       _clearup | ||||||
| @ -3614,6 +3665,7 @@ issue() { | |||||||
| 
 | 
 | ||||||
|   _rcert="$response" |   _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" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" | ||||||
|  |   _debug "Le_LinkCert" "$Le_LinkCert" | ||||||
|   _savedomainconf "Le_LinkCert" "$Le_LinkCert" |   _savedomainconf "Le_LinkCert" "$Le_LinkCert" | ||||||
| 
 | 
 | ||||||
|   if [ "$Le_LinkCert" ]; then |   if [ "$Le_LinkCert" ]; then | ||||||
| @ -3660,16 +3712,34 @@ issue() { | |||||||
|   if ! _contains "$Le_LinkIssuer" ":"; then |   if ! _contains "$Le_LinkIssuer" ":"; then | ||||||
|     Le_LinkIssuer="$API$Le_LinkIssuer" |     Le_LinkIssuer="$API$Le_LinkIssuer" | ||||||
|   fi |   fi | ||||||
| 
 |   _debug Le_LinkIssuer "$Le_LinkIssuer" | ||||||
|   _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" |   _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" | ||||||
| 
 | 
 | ||||||
|   if [ "$Le_LinkIssuer" ]; then |   if [ "$Le_LinkIssuer" ]; then | ||||||
|     echo "$BEGIN_CERT" >"$CA_CERT_PATH" |     _link_issuer_retry=0 | ||||||
|     _get "$Le_LinkIssuer" | _base64 "multiline" >>"$CA_CERT_PATH" |     _MAX_ISSUER_RETRY=5 | ||||||
|     echo "$END_CERT" >>"$CA_CERT_PATH" |     while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do | ||||||
|     _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" |       _debug _link_issuer_retry "$_link_issuer_retry" | ||||||
|     cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" |       if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then | ||||||
|     _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" |         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 | ||||||
|  |     _debug "No Le_LinkIssuer header found." | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   Le_CertCreateTime=$(_time) |   Le_CertCreateTime=$(_time) | ||||||
| @ -3690,6 +3760,12 @@ issue() { | |||||||
|     _clearaccountconf "CA_BUNDLE" |     _clearaccountconf "CA_BUNDLE" | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|  |   if [ "$CA_PATH" ]; then | ||||||
|  |     _saveaccountconf CA_PATH "$CA_PATH" | ||||||
|  |   else | ||||||
|  |     _clearaccountconf "CA_PATH" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|   if [ "$HTTPS_INSECURE" ]; then |   if [ "$HTTPS_INSECURE" ]; then | ||||||
|     _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" |     _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" | ||||||
|   else |   else | ||||||
| @ -3814,7 +3890,7 @@ renewAll() { | |||||||
|         return "$rc" |         return "$rc" | ||||||
|       else |       else | ||||||
|         _ret="$rc" |         _ret="$rc" | ||||||
|         _err "Error renew $d, Go ahead to next one." |         _err "Error renew $d." | ||||||
|       fi |       fi | ||||||
|     fi |     fi | ||||||
|   done |   done | ||||||
| @ -4008,7 +4084,7 @@ deploy() { | |||||||
| installcert() { | installcert() { | ||||||
|   _main_domain="$1" |   _main_domain="$1" | ||||||
|   if [ -z "$_main_domain" ]; then |   if [ -z "$_main_domain" ]; then | ||||||
|     _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com  [--ecc] [--certpath cert-file-path]  [--keypath key-file-path]  [--capath ca-cert-file-path]   [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" |     _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com  [--ecc] [--cert-file cert-file-path]  [--key-file key-file-path]  [--ca-file ca-cert-file-path]   [ --reloadCmd reloadCmd] [--fullchain-file fullchain-path]" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
| @ -4107,6 +4183,7 @@ _installcert() { | |||||||
|       export CERT_KEY_PATH |       export CERT_KEY_PATH | ||||||
|       export CA_CERT_PATH |       export CA_CERT_PATH | ||||||
|       export CERT_FULLCHAIN_PATH |       export CERT_FULLCHAIN_PATH | ||||||
|  |       export Le_Domain | ||||||
|       cd "$DOMAIN_PATH" && eval "$_reload_cmd" |       cd "$DOMAIN_PATH" && eval "$_reload_cmd" | ||||||
|     ); then |     ); then | ||||||
|       _info "$(__green "Reload success")" |       _info "$(__green "Reload success")" | ||||||
| @ -4435,7 +4512,7 @@ _precheck() { | |||||||
|     fi |     fi | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if ! _exists "$ACME_OPENSSL_BIN"; then |   if ! _exists "${ACME_OPENSSL_BIN:-openssl}"; then | ||||||
|     _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" |     _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" | ||||||
|     _err "We need openssl to generate keys." |     _err "We need openssl to generate keys." | ||||||
|     return 1 |     return 1 | ||||||
| @ -4618,7 +4695,7 @@ install() { | |||||||
|     #Modify shebang |     #Modify shebang | ||||||
|     if _exists bash; then |     if _exists bash; then | ||||||
|       _info "Good, bash is found, so change the shebang to use bash as preferred." |       _info "Good, bash is found, so change the shebang to use bash as preferred." | ||||||
|       _shebang='#!/usr/bin/env bash' |       _shebang='#!'"$(env bash -c "command -v bash")" | ||||||
|       _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" |       _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" | ||||||
|       for subf in $_SUB_FOLDERS; do |       for subf in $_SUB_FOLDERS; do | ||||||
|         if [ -d "$LE_WORKING_DIR/$subf" ]; then |         if [ -d "$LE_WORKING_DIR/$subf" ]; then | ||||||
| @ -4677,6 +4754,7 @@ _uninstallalias() { | |||||||
| cron() { | cron() { | ||||||
|   IN_CRON=1 |   IN_CRON=1 | ||||||
|   _initpath |   _initpath | ||||||
|  |   _info "$(__green "===Starting cron===")" | ||||||
|   if [ "$AUTO_UPGRADE" = "1" ]; then |   if [ "$AUTO_UPGRADE" = "1" ]; then | ||||||
|     export LE_WORKING_DIR |     export LE_WORKING_DIR | ||||||
|     ( |     ( | ||||||
| @ -4696,6 +4774,7 @@ cron() { | |||||||
|   renewAll |   renewAll | ||||||
|   _ret="$?" |   _ret="$?" | ||||||
|   IN_CRON="" |   IN_CRON="" | ||||||
|  |   _info "$(__green "===End cron===")" | ||||||
|   exit $_ret |   exit $_ret | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -4758,10 +4837,10 @@ Parameters: | |||||||
| 
 | 
 | ||||||
|   These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: |   These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: | ||||||
| 
 | 
 | ||||||
|   --certpath /path/to/real/cert/file  After issue/renew, the cert will be copied to this path. |   --cert-file                       After issue/renew, the cert will be copied to this path. | ||||||
|   --keypath /path/to/real/key/file  After issue/renew, the key will be copied to this path. |   --key-file                        After issue/renew, the key will be copied to this path. | ||||||
|   --capath /path/to/real/ca/file    After issue/renew, the intermediate cert will be copied to this path. |   --ca-file                         After issue/renew, the intermediate cert will be copied to this path. | ||||||
|   --fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. |   --fullchain-file                  After issue/renew, the fullchain cert will be copied to this path. | ||||||
| 
 | 
 | ||||||
|   --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. |   --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. | ||||||
| 
 | 
 | ||||||
| @ -4779,12 +4858,13 @@ Parameters: | |||||||
|   --listraw                         Only used for '--list' command, list the certs in raw format. |   --listraw                         Only used for '--list' command, list the certs in raw format. | ||||||
|   --stopRenewOnError, -se           Only valid for '--renew-all' command. Stop if one cert has error in renewal. |   --stopRenewOnError, -se           Only valid for '--renew-all' command. Stop if one cert has error in renewal. | ||||||
|   --insecure                        Do not check the server certificate, in some devices, the api server's certificate may not be trusted. |   --insecure                        Do not check the server certificate, in some devices, the api server's certificate may not be trusted. | ||||||
|   --ca-bundle                       Specifices the path to the CA certificate bundle to verify api server's certificate. |   --ca-bundle                       Specifies the path to the CA certificate bundle to verify api server's certificate. | ||||||
|  |   --ca-path                         Specifies directory containing CA certificates in PEM format, used by wget or curl. | ||||||
|   --nocron                          Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically. |   --nocron                          Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically. | ||||||
|   --ecc                             Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' |   --ecc                             Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' | ||||||
|   --csr                             Specifies the input csr. |   --csr                             Specifies the input csr. | ||||||
|   --pre-hook                        Command to be run before obtaining any certificates. |   --pre-hook                        Command to be run before obtaining any certificates. | ||||||
|   --post-hook                       Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed. |   --post-hook                       Command to be run after attempting to obtain/renew certificates. No matter the obtain/renew is success or failed. | ||||||
|   --renew-hook                      Command to be run once for each successfully renewed certificate. |   --renew-hook                      Command to be run once for each successfully renewed certificate. | ||||||
|   --deploy-hook                     The hook file to deploy cert |   --deploy-hook                     The hook file to deploy cert | ||||||
|   --ocsp-must-staple, --ocsp        Generate ocsp must Staple extension. |   --ocsp-must-staple, --ocsp        Generate ocsp must Staple extension. | ||||||
| @ -4886,10 +4966,10 @@ _process() { | |||||||
|   _webroot="" |   _webroot="" | ||||||
|   _keylength="" |   _keylength="" | ||||||
|   _accountkeylength="" |   _accountkeylength="" | ||||||
|   _certpath="" |   _cert_file="" | ||||||
|   _keypath="" |   _key_file="" | ||||||
|   _capath="" |   _ca_file="" | ||||||
|   _fullchainpath="" |   _fullchain_file="" | ||||||
|   _reloadcmd="" |   _reloadcmd="" | ||||||
|   _password="" |   _password="" | ||||||
|   _accountconf="" |   _accountconf="" | ||||||
| @ -4905,6 +4985,7 @@ _process() { | |||||||
|   _stopRenewOnError="" |   _stopRenewOnError="" | ||||||
|   #_insecure="" |   #_insecure="" | ||||||
|   _ca_bundle="" |   _ca_bundle="" | ||||||
|  |   _ca_path="" | ||||||
|   _nocron="" |   _nocron="" | ||||||
|   _ecc="" |   _ecc="" | ||||||
|   _csr="" |   _csr="" | ||||||
| @ -5130,20 +5211,20 @@ _process() { | |||||||
|         shift |         shift | ||||||
|         ;; |         ;; | ||||||
| 
 | 
 | ||||||
|       --certpath) |       --cert-file | --certpath) | ||||||
|         _certpath="$2" |         _cert_file="$2" | ||||||
|         shift |         shift | ||||||
|         ;; |         ;; | ||||||
|       --keypath) |       --key-file | --keypath) | ||||||
|         _keypath="$2" |         _key_file="$2" | ||||||
|         shift |         shift | ||||||
|         ;; |         ;; | ||||||
|       --capath) |       --ca-file | --capath) | ||||||
|         _capath="$2" |         _ca_file="$2" | ||||||
|         shift |         shift | ||||||
|         ;; |         ;; | ||||||
|       --fullchainpath) |       --fullchain-file | --fullchainpath) | ||||||
|         _fullchainpath="$2" |         _fullchain_file="$2" | ||||||
|         shift |         shift | ||||||
|         ;; |         ;; | ||||||
|       --reloadcmd | --reloadCmd) |       --reloadcmd | --reloadCmd) | ||||||
| @ -5219,6 +5300,11 @@ _process() { | |||||||
|         CA_BUNDLE="$_ca_bundle" |         CA_BUNDLE="$_ca_bundle" | ||||||
|         shift |         shift | ||||||
|         ;; |         ;; | ||||||
|  |       --ca-path) | ||||||
|  |         _ca_path="$2" | ||||||
|  |         CA_PATH="$_ca_path" | ||||||
|  |         shift | ||||||
|  |         ;; | ||||||
|       --nocron) |       --nocron) | ||||||
|         _nocron="1" |         _nocron="1" | ||||||
|         ;; |         ;; | ||||||
| @ -5360,7 +5446,7 @@ _process() { | |||||||
|     uninstall) uninstall "$_nocron" ;; |     uninstall) uninstall "$_nocron" ;; | ||||||
|     upgrade) upgrade ;; |     upgrade) upgrade ;; | ||||||
|     issue) |     issue) | ||||||
|       issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" |       issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" | ||||||
|       ;; |       ;; | ||||||
|     deploy) |     deploy) | ||||||
|       deploy "$_domain" "$_deploy_hook" "$_ecc" |       deploy "$_domain" "$_deploy_hook" "$_ecc" | ||||||
| @ -5372,7 +5458,7 @@ _process() { | |||||||
|       showcsr "$_csr" "$_domain" |       showcsr "$_csr" "$_domain" | ||||||
|       ;; |       ;; | ||||||
|     installcert) |     installcert) | ||||||
|       installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc" |       installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc" | ||||||
|       ;; |       ;; | ||||||
|     renew) |     renew) | ||||||
|       renew "$_domain" "$_ecc" |       renew "$_domain" "$_ecc" | ||||||
|  | |||||||
| @ -21,8 +21,11 @@ acme.sh --deploy -d example.com --deploy-hook cpanel | |||||||
| ## 2. Deploy ssl cert on kong proxy engine based on api. | ## 2. Deploy ssl cert on kong proxy engine based on api. | ||||||
| 
 | 
 | ||||||
| Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). | Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). | ||||||
|  | Currently supports Kong-v0.10.x. | ||||||
| 
 | 
 | ||||||
| (TODO) | ```sh | ||||||
|  | acme.sh --deploy -d ftp.example.com --deploy-hook kong | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| ## 3. Deploy the cert to remote server through SSH access. | ## 3. Deploy the cert to remote server through SSH access. | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -79,7 +79,7 @@ exim4_deploy() { | |||||||
|         _info "Restore conf success" |         _info "Restore conf success" | ||||||
|         eval "$_reload" |         eval "$_reload" | ||||||
|       else |       else | ||||||
|         _err "Opps, error restore exim4 conf, please report bug to us." |         _err "Oops, error restore exim4 conf, please report bug to us." | ||||||
|       fi |       fi | ||||||
|       return 1 |       return 1 | ||||||
|     fi |     fi | ||||||
| @ -105,7 +105,7 @@ exim4_deploy() { | |||||||
|       _info "Restore conf success" |       _info "Restore conf success" | ||||||
|       eval "$_reload" |       eval "$_reload" | ||||||
|     else |     else | ||||||
|       _err "Opps, error restore exim4 conf, please report bug to us." |       _err "Oops, error restore exim4 conf, please report bug to us." | ||||||
|     fi |     fi | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|  | |||||||
| @ -1,13 +1,7 @@ | |||||||
| #!/usr/bin/env sh | #!/usr/bin/env sh | ||||||
| 
 | # If certificate already exist it will update only cert and key not touching other parameter | ||||||
| # This deploy hook will deploy ssl cert on kong proxy engine based on api request_host parameter. | # If certificate  doesn't exist it will only upload cert and key and not set other parameter | ||||||
| # Note that ssl plugin should be available on Kong instance | # Note that we deploy full chain | ||||||
| # The hook will match cdomain to request_host, in case of multiple domain it will always take the first |  | ||||||
| # one (acme.sh behaviour). |  | ||||||
| # If ssl config already exist it will update only cert and key not touching other parameter |  | ||||||
| # If ssl config doesn't exist it will only upload cert and key and not set other parameter |  | ||||||
| # Not that we deploy full chain |  | ||||||
| # See https://getkong.org/plugins/dynamic-ssl/ for other options |  | ||||||
| # Written by Geoffroi Genot <ggenot@voxbone.com> | # Written by Geoffroi Genot <ggenot@voxbone.com> | ||||||
| 
 | 
 | ||||||
| ########  Public functions ##################### | ########  Public functions ##################### | ||||||
| @ -31,29 +25,32 @@ kong_deploy() { | |||||||
|   _debug _cca "$_cca" |   _debug _cca "$_cca" | ||||||
|   _debug _cfullchain "$_cfullchain" |   _debug _cfullchain "$_cfullchain" | ||||||
| 
 | 
 | ||||||
|   #Get uuid linked to the domain |   #Get ssl_uuid linked to the domain | ||||||
|   uuid=$(_get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') |   ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') | ||||||
|   if [ -z "$uuid" ]; then |   if [ -z "$ssl_uuid" ]; then | ||||||
|     _err "Unable to get Kong uuid for domain $_cdomain" |     _debug "Unable to get Kong ssl_uuid for domain $_cdomain" | ||||||
|     _err "Make sure that KONG_URL is correctly configured" |     _debug "Make sure that KONG_URL is correctly configured" | ||||||
|     _err "Make sure that a Kong api request_host match the domain" |     _debug "Make sure that a Kong certificate match the sni" | ||||||
|     _err "Kong url: $KONG_URL" |     _debug "Kong url: $KONG_URL" | ||||||
|     return 1 |     _info "No existing certificate, creating..." | ||||||
|  |     #return 1 | ||||||
|   fi |   fi | ||||||
|   #Save kong url if it's succesful (First run case) |   #Save kong url if it's succesful (First run case) | ||||||
|   _saveaccountconf KONG_URL "$KONG_URL" |   _saveaccountconf KONG_URL "$KONG_URL" | ||||||
|   #Generate DEIM |   #Generate DEIM | ||||||
|   delim="-----MultipartDelimeter$(date "+%s%N")" |   delim="-----MultipartDelimiter$(date "+%s%N")" | ||||||
|   nl="\015\012" |   nl="\015\012" | ||||||
|   #Set Header |   #Set Header | ||||||
|   _H1="Content-Type: multipart/form-data; boundary=$delim" |   _H1="Content-Type: multipart/form-data; boundary=$delim" | ||||||
|   #Generate data for request (Multipart/form-data with mixed content) |   #Generate data for request (Multipart/form-data with mixed content) | ||||||
|   #set name to ssl |   if [ -z "$ssl_uuid" ]; then | ||||||
|   content="--$delim${nl}Content-Disposition: form-data; name=\"name\"${nl}${nl}ssl" |     #set sni to domain | ||||||
|  |     content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" | ||||||
|  |   fi | ||||||
|   #add key |   #add key | ||||||
|   content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" |   content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" | ||||||
|   #Add cert |   #Add cert | ||||||
|   content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" |   content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" | ||||||
|   #Close multipart |   #Close multipart | ||||||
|   content="$content${nl}--$delim--${nl}" |   content="$content${nl}--$delim--${nl}" | ||||||
|   #Convert CRLF |   #Convert CRLF | ||||||
| @ -61,18 +58,17 @@ kong_deploy() { | |||||||
|   #DEBUG |   #DEBUG | ||||||
|   _debug header "$_H1" |   _debug header "$_H1" | ||||||
|   _debug content "$content" |   _debug content "$content" | ||||||
|   #Check if ssl plugins is aready enabled (if not => POST else => PATCH) |   #Check if sslcreated (if not => POST else => PATCH) | ||||||
|   ssl_uuid=$(_get "$KONG_URL/apis/$uuid/plugins" | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') | 
 | ||||||
|   _debug ssl_uuid "$ssl_uuid" |  | ||||||
|   if [ -z "$ssl_uuid" ]; then |   if [ -z "$ssl_uuid" ]; then | ||||||
|     #Post certificate to Kong |     #Post certificate to Kong | ||||||
|     response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") |     response=$(_post "$content" "$KONG_URL/certificates" "" "POST") | ||||||
|   else |   else | ||||||
|     #patch |     #patch | ||||||
|     response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") |     response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH") | ||||||
|   fi |   fi | ||||||
|   if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then |   if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then | ||||||
|     _err "An error occured with cert upload. Check response:" |     _err "An error occurred with cert upload. Check response:" | ||||||
|     _err "$response" |     _err "$response" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|  | |||||||
| @ -76,7 +76,7 @@ vsftpd_deploy() { | |||||||
|         _info "Restore conf success" |         _info "Restore conf success" | ||||||
|         eval "$_reload" |         eval "$_reload" | ||||||
|       else |       else | ||||||
|         _err "Opps, error restore vsftpd conf, please report bug to us." |         _err "Oops, error restore vsftpd conf, please report bug to us." | ||||||
|       fi |       fi | ||||||
|       return 1 |       return 1 | ||||||
|     fi |     fi | ||||||
| @ -102,7 +102,7 @@ vsftpd_deploy() { | |||||||
|       _info "Restore conf success" |       _info "Restore conf success" | ||||||
|       eval "$_reload" |       eval "$_reload" | ||||||
|     else |     else | ||||||
|       _err "Opps, error restore vsftpd conf, please report bug to us." |       _err "Oops, error restore vsftpd conf, please report bug to us." | ||||||
|     fi |     fi | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|  | |||||||
							
								
								
									
										106
									
								
								dnsapi/README.md
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								dnsapi/README.md
									
									
									
									
									
								
							| @ -302,7 +302,7 @@ acme.sh --issue --dns dns_freedns -d example.com -d www.example.com | |||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Note that you cannot use acme.sh automatic DNS validation for FreeDNS public domains or for a subdomain that | Note that you cannot use acme.sh automatic DNS validation for FreeDNS public domains or for a subdomain that | ||||||
| you create under a FreeDNS public domain.  You must own the top level domain in order to automaitcally | you create under a FreeDNS public domain.  You must own the top level domain in order to automatically | ||||||
| validate with acme.sh at FreeDNS. | validate with acme.sh at FreeDNS. | ||||||
| 
 | 
 | ||||||
| ## 16. Use cyon.ch | ## 16. Use cyon.ch | ||||||
| @ -394,7 +394,8 @@ acme.sh --issue --dns dns_knot -d example.com -d www.example.com | |||||||
| 
 | 
 | ||||||
| The `KNOT_SERVER` and `KNOT_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | The `KNOT_SERVER` and `KNOT_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
| 
 | 
 | ||||||
| ## 20. Use NS1. API | 
 | ||||||
|  | ## 20. Use NS1.com API | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| export NS1_Key="fdmlfsdklmfdkmqsdfk" | export NS1_Key="fdmlfsdklmfdkmqsdfk" | ||||||
| @ -405,6 +406,107 @@ Ok, let's issue a cert now: | |||||||
| acme.sh --issue --dns dns_nsone -d example.com -d www.example.com | acme.sh --issue --dns dns_nsone -d example.com -d www.example.com | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ## 20. Use DigitalOcean API (native) | ||||||
|  | 
 | ||||||
|  | You need to obtain a read and write capable API key from your DigitalOcean account. See: https://www.digitalocean.com/help/api/ | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_dgon -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 21. Use ClouDNS.net API | ||||||
|  | 
 | ||||||
|  | You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/ | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export CLOUDNS_AUTH_ID=XXXXX | ||||||
|  | export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## 22. Use Infoblox API | ||||||
|  | 
 | ||||||
|  | First you need to create/obtain API credentials on your Infoblox appliance. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export Infoblox_Creds="username:password" | ||||||
|  | export Infoblox_Server="ip or fqdn of infoblox appliance" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Note: This script will automatically create and delete the ephemeral txt record. | ||||||
|  | The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## 23. Use VSCALE API | ||||||
|  | 
 | ||||||
|  | First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_vscale -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ##  24. Use Dynu API | ||||||
|  | 
 | ||||||
|  | First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export Dynu_ClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | ||||||
|  | export Dynu_Secret="yyyyyyyyyyyyyyyyyyyyyyyyy" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Ok, let's issue a cert now: | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_dynu -d example.com -d www.example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `Dynu_ClientId` and `Dynu_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||||
|  | 
 | ||||||
|  | ## 25. Use DNSimple API | ||||||
|  | 
 | ||||||
|  | First you need to login to your DNSimple account and generate a new oauth token. | ||||||
|  | 
 | ||||||
|  | https://dnsimple.com/a/{your account id}/account/access_tokens | ||||||
|  | 
 | ||||||
|  | Note that this is an _account_ token and not a user token. The account token is | ||||||
|  | needed to infer the `account_id` used in requests. A user token will not be able | ||||||
|  | to determine the correct account to use. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | export DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | To issue the cert just specify the `dns_dnsimple` API. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | acme.sh --issue --dns dns_dnsimple -d example.com | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `DNSimple_OAUTH_TOKEN` will be saved in `~/.acme.sh/account.conf` and will | ||||||
|  | be reused when needed. | ||||||
|  | 
 | ||||||
|  | If you have any issues with this integration please report them to | ||||||
|  | https://github.com/pho3nixf1re/acme.sh/issues. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| # Use custom API | # Use custom API | ||||||
| 
 | 
 | ||||||
| If your API is not supported yet, you can write your own DNS API. | If your API is not supported yet, you can write your own DNS API. | ||||||
|  | |||||||
| @ -88,12 +88,25 @@ _get_root() { | |||||||
|     while true; do |     while true; do | ||||||
|       h=$(printf "%s" "$domain" | cut -d . -f $i-100) |       h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|       if [ -z "$h" ]; then |       if [ -z "$h" ]; then | ||||||
|  |         if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then | ||||||
|  |           _debug "IsTruncated" | ||||||
|  |           _nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)" | ||||||
|  |           _debug "NextMarker" "$_nextMarker" | ||||||
|  |           if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then | ||||||
|  |             _debug "Truncated request OK" | ||||||
|  |             i=2 | ||||||
|  |             p=1 | ||||||
|  |             continue | ||||||
|  |           else | ||||||
|  |             _err "Truncated request error." | ||||||
|  |           fi | ||||||
|  |         fi | ||||||
|         #not valid |         #not valid | ||||||
|         return 1 |         return 1 | ||||||
|       fi |       fi | ||||||
| 
 | 
 | ||||||
|       if _contains "$response" "<Name>$h.</Name>"; then |       if _contains "$response" "<Name>$h.</Name>"; then | ||||||
|         hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<.HostedZone>")" |         hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")" | ||||||
|         _debug hostedzone "$hostedzone" |         _debug hostedzone "$hostedzone" | ||||||
|         if [ -z "$hostedzone" ]; then |         if [ -z "$hostedzone" ]; then | ||||||
|           _err "Error, can not get hostedzone." |           _err "Error, can not get hostedzone." | ||||||
| @ -143,7 +156,7 @@ aws_rest() { | |||||||
|   CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" |   CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" | ||||||
|   SignedHeaders="host;x-amz-date" |   SignedHeaders="host;x-amz-date" | ||||||
|   if [ -n "$AWS_SESSION_TOKEN" ]; then |   if [ -n "$AWS_SESSION_TOKEN" ]; then | ||||||
|     export _H2="x-amz-security-token: $AWS_SESSION_TOKEN" |     export _H3="x-amz-security-token: $AWS_SESSION_TOKEN" | ||||||
|     CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" |     CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" | ||||||
|     SignedHeaders="${SignedHeaders};x-amz-security-token" |     SignedHeaders="${SignedHeaders};x-amz-security-token" | ||||||
|   fi |   fi | ||||||
| @ -204,10 +217,13 @@ aws_rest() { | |||||||
|   Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" |   Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" | ||||||
|   _debug2 Authorization "$Authorization" |   _debug2 Authorization "$Authorization" | ||||||
| 
 | 
 | ||||||
|   _H3="Authorization: $Authorization" |   _H2="Authorization: $Authorization" | ||||||
|   _debug _H3 "$_H3" |   _debug _H2 "$_H2" | ||||||
| 
 | 
 | ||||||
|   url="$AWS_URL/$ep" |   url="$AWS_URL/$ep" | ||||||
|  |   if [ "$qsr" ]; then | ||||||
|  |     url="$AWS_URL/$ep?$qsr" | ||||||
|  |   fi | ||||||
| 
 | 
 | ||||||
|   if [ "$mtd" = "GET" ]; then |   if [ "$mtd" = "GET" ]; then | ||||||
|     response="$(_get "$url")" |     response="$(_get "$url")" | ||||||
|  | |||||||
| @ -14,6 +14,8 @@ dns_cf_add() { | |||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|   txtvalue=$2 |   txtvalue=$2 | ||||||
| 
 | 
 | ||||||
|  |   CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" | ||||||
|  |   CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" | ||||||
|   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then |   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then | ||||||
|     CF_Key="" |     CF_Key="" | ||||||
|     CF_Email="" |     CF_Email="" | ||||||
| @ -29,8 +31,8 @@ dns_cf_add() { | |||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   #save the api key and email to the account conf file. |   #save the api key and email to the account conf file. | ||||||
|   _saveaccountconf CF_Key "$CF_Key" |   _saveaccountconf_mutable CF_Key "$CF_Key" | ||||||
|   _saveaccountconf CF_Email "$CF_Email" |   _saveaccountconf_mutable CF_Email "$CF_Email" | ||||||
| 
 | 
 | ||||||
|   _debug "First detect the root zone" |   _debug "First detect the root zone" | ||||||
|   if ! _get_root "$fulldomain"; then |   if ! _get_root "$fulldomain"; then | ||||||
| @ -83,6 +85,17 @@ dns_cf_add() { | |||||||
| dns_cf_rm() { | dns_cf_rm() { | ||||||
|   fulldomain=$1 |   fulldomain=$1 | ||||||
|   txtvalue=$2 |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" | ||||||
|  |   CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" | ||||||
|  |   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." | ||||||
|  |     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 | ||||||
|     _err "invalid domain" |     _err "invalid domain" | ||||||
|  | |||||||
							
								
								
									
										170
									
								
								dnsapi/dns_cloudns.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										170
									
								
								dnsapi/dns_cloudns.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,170 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | # Author: Boyan Peychev <boyan at cloudns dot net> | ||||||
|  | # Repository: https://github.com/ClouDNS/acme.sh/ | ||||||
|  | 
 | ||||||
|  | #CLOUDNS_AUTH_ID=XXXXX | ||||||
|  | #CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" | ||||||
|  | CLOUDNS_API="https://api.cloudns.net" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_cloudns_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_cloudns_add() { | ||||||
|  |   _info "Using cloudns" | ||||||
|  | 
 | ||||||
|  |   if ! _dns_cloudns_init_check; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   zone="$(_dns_cloudns_get_zone_name "$1")" | ||||||
|  |   if [ -z "$zone" ]; then | ||||||
|  |     _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   host="$(echo "$1" | sed "s/\.$zone\$//")" | ||||||
|  |   record=$2 | ||||||
|  |   record_id=$(_dns_cloudns_get_record_id "$zone" "$host") | ||||||
|  | 
 | ||||||
|  |   _debug zone "$zone" | ||||||
|  |   _debug host "$host" | ||||||
|  |   _debug record "$record" | ||||||
|  |   _debug record_id "$record_id" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$record_id" ]; then | ||||||
|  |     _info "Adding the TXT record for $1" | ||||||
|  |     _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" | ||||||
|  |     if ! _contains "$response" "\"status\":\"Success\""; then | ||||||
|  |       _err "Record cannot be added." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _info "Added." | ||||||
|  |   else | ||||||
|  |     _info "Updating the TXT record for $1" | ||||||
|  |     _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" | ||||||
|  |     if ! _contains "$response" "\"status\":\"Success\""; then | ||||||
|  |       _err "The TXT record for $1 cannot be updated." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _info "Updated." | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: dns_cloudns_rm   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_cloudns_rm() { | ||||||
|  |   _info "Using cloudns" | ||||||
|  | 
 | ||||||
|  |   if ! _dns_cloudns_init_check; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$zone" ]; then | ||||||
|  |     zone="$(_dns_cloudns_get_zone_name "$1")" | ||||||
|  |     if [ -z "$zone" ]; then | ||||||
|  |       _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   host="$(echo "$1" | sed "s/\.$zone\$//")" | ||||||
|  |   record=$2 | ||||||
|  |   record_id=$(_dns_cloudns_get_record_id "$zone" "$host") | ||||||
|  | 
 | ||||||
|  |   _debug zone "$zone" | ||||||
|  |   _debug host "$host" | ||||||
|  |   _debug record "$record" | ||||||
|  |   _debug record_id "$record_id" | ||||||
|  | 
 | ||||||
|  |   if [ ! -z "$record_id" ]; then | ||||||
|  |     _info "Deleting the TXT record for $1" | ||||||
|  |     _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" | ||||||
|  |     if ! _contains "$response" "\"status\":\"Success\""; then | ||||||
|  |       _err "The TXT record for $1 cannot be deleted." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     _info "Deleted." | ||||||
|  |   fi | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | _dns_cloudns_init_check() { | ||||||
|  |   if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$CLOUDNS_AUTH_ID" ]; then | ||||||
|  |     _err "CLOUDNS_AUTH_ID is not configured" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then | ||||||
|  |     _err "CLOUDNS_AUTH_PASSWORD is not configured" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _dns_cloudns_http_api_call "dns/login.json" "" | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "\"status\":\"Success\""; then | ||||||
|  |     _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   CLOUDNS_INIT_CHECK_COMPLETED=1 | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dns_cloudns_get_zone_name() { | ||||||
|  |   i=2 | ||||||
|  |   while true; do | ||||||
|  |     zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) | ||||||
|  | 
 | ||||||
|  |     if [ -z "$zoneForCheck" ]; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     _debug zoneForCheck "$zoneForCheck" | ||||||
|  | 
 | ||||||
|  |     _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" | ||||||
|  | 
 | ||||||
|  |     if ! _contains "$response" "\"status\":\"Failed\""; then | ||||||
|  |       echo "$zoneForCheck" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     i=$(_math "$i" + 1) | ||||||
|  |   done | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dns_cloudns_get_record_id() { | ||||||
|  |   _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" | ||||||
|  |   if _contains "$response" "\"id\":"; then | ||||||
|  |     echo "$response" | cut -d '"' -f 2 | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dns_cloudns_http_api_call() { | ||||||
|  |   method=$1 | ||||||
|  | 
 | ||||||
|  |   _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" | ||||||
|  |   _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$2" ]; then | ||||||
|  |     data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" | ||||||
|  |   else | ||||||
|  |     data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   response="$(_get "$CLOUDNS_API/$method?$data")" | ||||||
|  | 
 | ||||||
|  |   _debug2 response "$response" | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
| @ -209,8 +209,7 @@ _rest() { | |||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|   _debug2 response "$response" |   _debug2 response "$response" | ||||||
|   if ! _contains "$response" '"message":"success"'; then | 
 | ||||||
|     return 1 |   _contains "$response" '"code":1' | ||||||
|   fi | 
 | ||||||
|   return 0 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -50,7 +50,7 @@ _cyon_load_credentials() { | |||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then |   if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then | ||||||
|     # Dummy entries to satify script checker. |     # Dummy entries to satisfy script checker. | ||||||
|     CY_Username="" |     CY_Username="" | ||||||
|     CY_Password="" |     CY_Password="" | ||||||
|     CY_OTP_Secret="" |     CY_OTP_Secret="" | ||||||
|  | |||||||
							
								
								
									
										205
									
								
								dnsapi/dns_dgon.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										205
									
								
								dnsapi/dns_dgon.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,205 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | ## Will be called by acme.sh to add the txt record to your api system. | ||||||
|  | ## returns 0 means success, otherwise error. | ||||||
|  | 
 | ||||||
|  | ## Author: thewer <github at thewer.com> | ||||||
|  | ## GitHub: https://github.com/gitwer/acme.sh | ||||||
|  | 
 | ||||||
|  | ## | ||||||
|  | ## Environment Variables Required: | ||||||
|  | ## | ||||||
|  | ## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" | ||||||
|  | ## | ||||||
|  | 
 | ||||||
|  | #####################  Public functions  ##################### | ||||||
|  | 
 | ||||||
|  | ## Create the text record for validation. | ||||||
|  | ## Usage: fulldomain txtvalue | ||||||
|  | ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" | ||||||
|  | dns_dgon_add() { | ||||||
|  |   fulldomain="$(echo "$1" | _lower_case)" | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _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" | ||||||
|  | 
 | ||||||
|  |   ## split the domain for DO API | ||||||
|  |   if ! _get_base_domain "$fulldomain"; then | ||||||
|  |     _err "domain not found in your account for addition" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  | 
 | ||||||
|  |   ## Set the header with our post type and key auth key | ||||||
|  |   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'"}' | ||||||
|  | 
 | ||||||
|  |   _debug PURL "$PURL" | ||||||
|  |   _debug PBODY "$PBODY" | ||||||
|  | 
 | ||||||
|  |   ## the create request - post | ||||||
|  |   ## args: BODY, URL, [need64, httpmethod] | ||||||
|  |   response="$(_post "$PBODY" "$PURL")" | ||||||
|  | 
 | ||||||
|  |   ## check response | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error in response: $response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  | 
 | ||||||
|  |   ## finished correctly | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ## Remove the txt record after validation. | ||||||
|  | ## Usage: fulldomain txtvalue | ||||||
|  | ## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" | ||||||
|  | dns_dgon_rm() { | ||||||
|  |   fulldomain="$(echo "$1" | _lower_case)" | ||||||
|  |   txtvalue=$2 | ||||||
|  |   _info "Using digitalocean dns validation - remove record" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|  | 
 | ||||||
|  |   ## split the domain for DO API | ||||||
|  |   if ! _get_base_domain "$fulldomain"; then | ||||||
|  |     _err "domain not found in your account for removal" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  | 
 | ||||||
|  |   ## Set the header with our post type and key auth key | ||||||
|  |   export _H1="Content-Type: application/json" | ||||||
|  |   export _H2="Authorization: Bearer $DO_API_KEY" | ||||||
|  |   ## get URL for the list of domains | ||||||
|  |   ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} | ||||||
|  |   GURL="https://api.digitalocean.com/v2/domains/$_domain/records" | ||||||
|  | 
 | ||||||
|  |   ## while we dont have a record ID we keep going | ||||||
|  |   while [ -z "$record" ]; do | ||||||
|  |     ## 1) get the URL | ||||||
|  |     ## the create request - get | ||||||
|  |     ## args: URL, [onlyheader, timeout] | ||||||
|  |     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\"")" | ||||||
|  |     ## 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+")" | ||||||
|  |       if [ -z "$nextpage" ]; then | ||||||
|  |         _err "no record and no nextpage in digital ocean DNS removal" | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |       _debug2 nextpage "$nextpage" | ||||||
|  |       GURL="$nextpage" | ||||||
|  |     fi | ||||||
|  |     ## we break out of the loop when we have a record | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   ## we found the record | ||||||
|  |   rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")" | ||||||
|  |   _debug rec_id "$rec_id" | ||||||
|  | 
 | ||||||
|  |   ## delete the record | ||||||
|  |   ## delete URL for removing the one we dont want | ||||||
|  |   DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" | ||||||
|  | 
 | ||||||
|  |   ## the create request - delete | ||||||
|  |   ## args: BODY, URL, [need64, httpmethod] | ||||||
|  |   response="$(_post "" "$DURL" "" "DELETE")" | ||||||
|  | 
 | ||||||
|  |   ## check response (sort of) | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error in remove response: $response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  | 
 | ||||||
|  |   ## finished correctly | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #####################  Private functions below  ##################### | ||||||
|  | 
 | ||||||
|  | ## Split the domain provided into the "bade domain" and the "start prefix". | ||||||
|  | ## This function searches for the longest subdomain in your account | ||||||
|  | ## for the full domain given and splits it into the base domain (zone) | ||||||
|  | ## and the prefix/record to be added/removed | ||||||
|  | ## USAGE: fulldomain | ||||||
|  | ## EG: "_acme-challenge.two.three.four.domain.com" | ||||||
|  | ## returns | ||||||
|  | ## _sub_domain="_acme-challenge.two" | ||||||
|  | ## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists | ||||||
|  | ## if only "domain.com" exists it will return | ||||||
|  | ## _sub_domain="_acme-challenge.two.three.four" | ||||||
|  | ## _domain="domain.com" | ||||||
|  | _get_base_domain() { | ||||||
|  |   # args | ||||||
|  |   fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  | 
 | ||||||
|  |   # domain max legal length = 253 | ||||||
|  |   MAX_DOM=255 | ||||||
|  | 
 | ||||||
|  |   ## get a list of domains for the account to check thru | ||||||
|  |   ## Set the headers | ||||||
|  |   export _H1="Content-Type: application/json" | ||||||
|  |   export _H2="Authorization: Bearer $DO_API_KEY" | ||||||
|  |   _debug DO_API_KEY "$DO_API_KEY" | ||||||
|  |   ## get URL for the list of domains | ||||||
|  |   ## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO) | ||||||
|  |   DOMURL="https://api.digitalocean.com/v2/domains" | ||||||
|  | 
 | ||||||
|  |   ## get the domain list (DO gives basically a full XFER!) | ||||||
|  |   domain_list="$(_get "$DOMURL")" | ||||||
|  | 
 | ||||||
|  |   ## check response | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error in domain_list response: $domain_list" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 domain_list "$domain_list" | ||||||
|  | 
 | ||||||
|  |   ## for each shortening of our $fulldomain, check if it exists in the $domain_list | ||||||
|  |   ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge" | ||||||
|  |   i=2 | ||||||
|  |   while [ $i -gt 0 ]; do | ||||||
|  |     ## get next longest domain | ||||||
|  |     _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") | ||||||
|  |     ## check we got something back from our cut (or are we at the end) | ||||||
|  |     if [ -z "$_domain" ]; then | ||||||
|  |       ## we got to the end of the domain - invalid domain | ||||||
|  |       _err "domain not found in DigitalOcean account" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     ## we got part of a domain back - grep it out | ||||||
|  |     found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")" | ||||||
|  |     ## check if it exists | ||||||
|  |     if [ ! -z "$found" ]; then | ||||||
|  |       ## exists - exit loop returning the parts | ||||||
|  |       sub_point=$(_math $i - 1) | ||||||
|  |       _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") | ||||||
|  |       _debug _domain "$_domain" | ||||||
|  |       _debug _sub_domain "$_sub_domain" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     ## increment cut point $i | ||||||
|  |     i=$(_math $i + 1) | ||||||
|  |   done | ||||||
|  | 
 | ||||||
|  |   ## we went through the entire domain zone list and dint find one that matched | ||||||
|  |   ## doesnt look like we can add in the record | ||||||
|  |   _err "domain not found in DigitalOcean account, but we should never get here" | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
							
								
								
									
										215
									
								
								dnsapi/dns_dnsimple.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								dnsapi/dns_dnsimple.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,215 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | # DNSimple domain api | ||||||
|  | # https://github.com/pho3nixf1re/acme.sh/issues | ||||||
|  | # | ||||||
|  | # This is your oauth token which can be acquired on the account page. Please | ||||||
|  | # note that this must be an _account_ token and not a _user_ token. | ||||||
|  | # https://dnsimple.com/a/<your account id>/account/access_tokens | ||||||
|  | # DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | 
 | ||||||
|  | DNSimple_API="https://api.dnsimple.com/v2" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | # Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_dnsimple_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$DNSimple_OAUTH_TOKEN" ]; then | ||||||
|  |     DNSimple_OAUTH_TOKEN="" | ||||||
|  |     _err "You have not set the dnsimple oauth token yet." | ||||||
|  |     _err "Please visit https://dnsimple.com/user to generate it." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   # save the oauth token for later | ||||||
|  |   _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN" | ||||||
|  | 
 | ||||||
|  |   if ! _get_account_id; then | ||||||
|  |     _err "failed to retrive account id" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _get_records "$_account_id" "$_domain" "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |   if [ "$_records_count" = "0" ]; then | ||||||
|  |     _info "Adding record" | ||||||
|  |     if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then | ||||||
|  |       if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then | ||||||
|  |         _info "Added" | ||||||
|  |         return 0 | ||||||
|  |       else | ||||||
|  |         _err "Unexpected response while adding text record." | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |     fi | ||||||
|  |     _err "Add txt record error." | ||||||
|  |   else | ||||||
|  |     _info "Updating record" | ||||||
|  |     _extract_record_id "$_records" "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |     if _dnsimple_rest \ | ||||||
|  |       PATCH \ | ||||||
|  |       "$_account_id/zones/$_domain/records/$_record_id" \ | ||||||
|  |       "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then | ||||||
|  | 
 | ||||||
|  |       _info "Updated!" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     _err "Update error" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # fulldomain | ||||||
|  | dns_dnsimple_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  | 
 | ||||||
|  |   if ! _get_account_id; then | ||||||
|  |     _err "failed to retrive account id" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _get_records "$_account_id" "$_domain" "$_sub_domain" | ||||||
|  |   _extract_record_id "$_records" "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |   if [ "$_record_id" ]; then | ||||||
|  | 
 | ||||||
|  |     if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then | ||||||
|  |       _info "removed record" "$_record_id" | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _err "failed to remove record" "$_record_id" | ||||||
|  |   return 1 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions bellow ################################## | ||||||
|  | # _acme-challenge.www.domain.com | ||||||
|  | # returns | ||||||
|  | #   _sub_domain=_acme-challenge.www | ||||||
|  | #   _domain=domain.com | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   previous=1 | ||||||
|  |   while true; do | ||||||
|  |     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |     if [ -z "$h" ]; then | ||||||
|  |       # not valid | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if ! _dnsimple_rest GET "$_account_id/zones/$h"; then | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if _contains "$response" 'not found'; then | ||||||
|  |       _debug "$h not found" | ||||||
|  |     else | ||||||
|  |       _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous) | ||||||
|  |       _domain="$h" | ||||||
|  | 
 | ||||||
|  |       _debug _domain "$_domain" | ||||||
|  |       _debug _sub_domain "$_sub_domain" | ||||||
|  | 
 | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     previous="$i" | ||||||
|  |     i=$(_math "$i" + 1) | ||||||
|  |   done | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # returns _account_id | ||||||
|  | _get_account_id() { | ||||||
|  |   _debug "retrive account id" | ||||||
|  |   if ! _dnsimple_rest GET "whoami"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if _contains "$response" "\"account\":null"; then | ||||||
|  |     _err "no account associated with this token" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if _contains "$response" "timeout"; then | ||||||
|  |     _err "timeout retrieving account id" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1) | ||||||
|  |   _debug _account_id "$_account_id" | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # returns | ||||||
|  | #   _records | ||||||
|  | #   _records_count | ||||||
|  | _get_records() { | ||||||
|  |   account_id=$1 | ||||||
|  |   domain=$2 | ||||||
|  |   sub_domain=$3 | ||||||
|  | 
 | ||||||
|  |   _debug "fetching txt records" | ||||||
|  |   _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100" | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "\"id\":"; then | ||||||
|  |     _err "failed to retrieve records" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _records_count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$sub_domain\"" | wc -l | _egrep_o "[0-9]+") | ||||||
|  |   _records=$response | ||||||
|  |   _debug _records_count "$_records_count" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # returns _record_id | ||||||
|  | _extract_record_id() { | ||||||
|  |   _record_id=$(printf "%s" "$_records" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) | ||||||
|  |   _debug "_record_id" "$_record_id" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # returns response | ||||||
|  | _dnsimple_rest() { | ||||||
|  |   method=$1 | ||||||
|  |   path="$2" | ||||||
|  |   data="$3" | ||||||
|  |   request_url="$DNSimple_API/$path" | ||||||
|  |   _debug "$path" | ||||||
|  | 
 | ||||||
|  |   export _H1="Accept: application/json" | ||||||
|  |   export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" | ||||||
|  | 
 | ||||||
|  |   if [ "$data" ] || [ "$method" = "DELETE" ]; then | ||||||
|  |     _H1="Content-Type: application/json" | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$request_url" "" "$method")" | ||||||
|  |   else | ||||||
|  |     response="$(_get "$request_url" "" "" "$method")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $request_url" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
							
								
								
									
										216
									
								
								dnsapi/dns_dynu.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								dnsapi/dns_dynu.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,216 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #Client ID | ||||||
|  | #Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" | ||||||
|  | # | ||||||
|  | #Secret | ||||||
|  | #Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" | ||||||
|  | # | ||||||
|  | #Token | ||||||
|  | Dynu_Token="" | ||||||
|  | # | ||||||
|  | #Endpoint | ||||||
|  | Dynu_EndPoint="https://api.dynu.com/v1" | ||||||
|  | # | ||||||
|  | #Author: Dynu Systems, Inc. | ||||||
|  | #Report Bugs here: https://github.com/shar0119/acme.sh | ||||||
|  | # | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_dynu_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then | ||||||
|  |     Dynu_ClientId="" | ||||||
|  |     Dynu_Secret="" | ||||||
|  |     _err "Dynu client id and secret is not specified." | ||||||
|  |     _err "Please create you API client id and secret and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   #save the client id and secret to the account conf file. | ||||||
|  |   _saveaccountconf Dynu_ClientId "$Dynu_ClientId" | ||||||
|  |   _saveaccountconf Dynu_Secret "$Dynu_Secret" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Dynu_Token" ]; then | ||||||
|  |     _info "Getting Dynu token." | ||||||
|  |     if ! _dynu_authentication; then | ||||||
|  |       _err "Can not get token." | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug "Detect root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "Invalid domain." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug _node "$_node" | ||||||
|  |   _debug _domain_name "$_domain_name" | ||||||
|  | 
 | ||||||
|  |   _info "Creating TXT record." | ||||||
|  |   if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "text_data"; then | ||||||
|  |     _err "Could not add TXT record." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_dynu_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then | ||||||
|  |     Dynu_ClientId="" | ||||||
|  |     Dynu_Secret="" | ||||||
|  |     _err "Dynu client id and secret is not specified." | ||||||
|  |     _err "Please create you API client id and secret and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   #save the client id and secret to the account conf file. | ||||||
|  |   _saveaccountconf Dynu_ClientId "$Dynu_ClientId" | ||||||
|  |   _saveaccountconf Dynu_Secret "$Dynu_Secret" | ||||||
|  | 
 | ||||||
|  |   if [ -z "$Dynu_Token" ]; then | ||||||
|  |     _info "Getting Dynu token." | ||||||
|  |     if ! _dynu_authentication; then | ||||||
|  |       _err "Can not get token." | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug "Detect root zone." | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "Invalid domain." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug _node "$_node" | ||||||
|  |   _debug _domain_name "$_domain_name" | ||||||
|  | 
 | ||||||
|  |   _info "Checking for TXT record." | ||||||
|  |   if ! _get_recordid "$fulldomain" "$txtvalue"; then | ||||||
|  |     _err "Could not get TXT record id." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$_dns_record_id" = "" ]; then | ||||||
|  |     _err "TXT record not found." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _info "Removing TXT record." | ||||||
|  |   if ! _delete_txt_record "$_dns_record_id"; then | ||||||
|  |     _err "Could not remove TXT record $_dns_record_id." | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ########  Private functions below ################################## | ||||||
|  | #_acme-challenge.www.domain.com | ||||||
|  | #returns | ||||||
|  | # _node=_acme-challenge.www | ||||||
|  | # _domain_name=domain.com | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   if ! _dynu_rest GET "dns/getroot/$domain"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "domain_name"; then | ||||||
|  |     _debug "Domain name not found." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _domain_name=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2) | ||||||
|  |   _node=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 3 | cut -d : -f 2 | cut -d '"' -f 2) | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _get_recordid() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "$txtvalue"; then | ||||||
|  |     _dns_record_id=0 | ||||||
|  |     return 0 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _delete_txt_record() { | ||||||
|  |   _dns_record_id=$1 | ||||||
|  | 
 | ||||||
|  |   if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if ! _contains "$response" "true"; then | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dynu_rest() { | ||||||
|  |   m=$1 | ||||||
|  |   ep="$2" | ||||||
|  |   data="$3" | ||||||
|  |   _debug "$ep" | ||||||
|  | 
 | ||||||
|  |   export _H1="Authorization: Bearer $Dynu_Token" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   if [ "$data" ]; then | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" | ||||||
|  |   else | ||||||
|  |     _info "Getting $Dynu_EndPoint/$ep" | ||||||
|  |     response="$(_get "$Dynu_EndPoint/$ep")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $ep" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | _dynu_authentication() { | ||||||
|  |   realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" | ||||||
|  | 
 | ||||||
|  |   export _H1="Authorization: Basic $realm" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  | 
 | ||||||
|  |   response="$(_get "$Dynu_EndPoint/oauth2/token")" | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "Authentication failed." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   if _contains "$response" "accessToken"; then | ||||||
|  |     Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2) | ||||||
|  |   fi | ||||||
|  |   if _contains "$Dynu_Token" "null"; then | ||||||
|  |     Dynu_Token="" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
| @ -10,7 +10,7 @@ | |||||||
| # | # | ||||||
| ########  Public functions ##################### | ########  Public functions ##################### | ||||||
| 
 | 
 | ||||||
| # Export FreeDNS userid and password in folowing variables... | # Export FreeDNS userid and password in following variables... | ||||||
| #  FREEDNS_User=username | #  FREEDNS_User=username | ||||||
| #  FREEDNS_Password=password | #  FREEDNS_Password=password | ||||||
| # login cookie is saved in acme account config file so userid / pw | # login cookie is saved in acme account config file so userid / pw | ||||||
| @ -53,7 +53,7 @@ dns_freedns_add() { | |||||||
|   i="$(_math "$i" - 1)" |   i="$(_math "$i" - 1)" | ||||||
|   sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" |   sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" | ||||||
| 
 | 
 | ||||||
|   # Sometimes FreeDNS does not reurn the subdomain page but rather  |   # Sometimes FreeDNS does not return the subdomain page but rather | ||||||
|   # returns a page regarding becoming a premium member.  This usually |   # returns a page regarding becoming a premium member.  This usually | ||||||
|   # happens after a period of inactivity.  Immediately trying again |   # happens after a period of inactivity.  Immediately trying again | ||||||
|   # returns the correct subdomain page.  So, we will try twice to |   # returns the correct subdomain page.  So, we will try twice to | ||||||
| @ -65,7 +65,7 @@ dns_freedns_add() { | |||||||
|     htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" |     htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" | ||||||
|     if [ "$?" != "0" ]; then |     if [ "$?" != "0" ]; then | ||||||
|       if [ "$using_cached_cookies" = "true" ]; then |       if [ "$using_cached_cookies" = "true" ]; then | ||||||
|         _err "Has your FreeDNS username and password channged?  If so..." |         _err "Has your FreeDNS username and password changed?  If so..." | ||||||
|         _err "Please export as FREEDNS_User / FREEDNS_Password and try again." |         _err "Please export as FREEDNS_User / FREEDNS_Password and try again." | ||||||
|       fi |       fi | ||||||
|       return 1 |       return 1 | ||||||
| @ -112,7 +112,7 @@ dns_freedns_add() { | |||||||
|           # not produce accurate results as the value field is truncated |           # not produce accurate results as the value field is truncated | ||||||
|           # on this webpage. To get full value we would need to load |           # on this webpage. To get full value we would need to load | ||||||
|           # another page. However we don't really need this so long as |           # another page. However we don't really need this so long as | ||||||
|           # there is only one TXT record for the acme chalenge subdomain. |           # there is only one TXT record for the acme challenge subdomain. | ||||||
|           DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" |           DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" | ||||||
|           if [ $found != 0 ]; then |           if [ $found != 0 ]; then | ||||||
|             break |             break | ||||||
| @ -192,11 +192,11 @@ dns_freedns_rm() { | |||||||
| 
 | 
 | ||||||
|   # Need to read cookie from conf file again in case new value set |   # Need to read cookie from conf file again in case new value set | ||||||
|   # during login to FreeDNS when TXT record was created. |   # during login to FreeDNS when TXT record was created. | ||||||
|   # acme.sh does not have a _readaccountconf() fuction |   # acme.sh does not have a _readaccountconf() function | ||||||
|   FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" |   FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" | ||||||
|   _debug "FreeDNS login cookies: $FREEDNS_COOKIE" |   _debug "FreeDNS login cookies: $FREEDNS_COOKIE" | ||||||
| 
 | 
 | ||||||
|   # Sometimes FreeDNS does not reurn the subdomain page but rather  |   # Sometimes FreeDNS does not return the subdomain page but rather | ||||||
|   # returns a page regarding becoming a premium member.  This usually |   # returns a page regarding becoming a premium member.  This usually | ||||||
|   # happens after a period of inactivity.  Immediately trying again |   # happens after a period of inactivity.  Immediately trying again | ||||||
|   # returns the correct subdomain page.  So, we will try twice to |   # returns the correct subdomain page.  So, we will try twice to | ||||||
| @ -302,12 +302,12 @@ _freedns_retrieve_subdomain_page() { | |||||||
|   export _H2="Accept-Language:en-US" |   export _H2="Accept-Language:en-US" | ||||||
|   url="https://freedns.afraid.org/subdomain/" |   url="https://freedns.afraid.org/subdomain/" | ||||||
| 
 | 
 | ||||||
|   _debug "Retrieve subdmoain page from FreeDNS" |   _debug "Retrieve subdomain page from FreeDNS" | ||||||
| 
 | 
 | ||||||
|   htmlpage="$(_get "$url")" |   htmlpage="$(_get "$url")" | ||||||
| 
 | 
 | ||||||
|   if [ "$?" != "0" ]; then |   if [ "$?" != "0" ]; then | ||||||
|     _err "FreeDNS retrieve subdomins failed bad RC from _get" |     _err "FreeDNS retrieve subdomains failed bad RC from _get" | ||||||
|     return 1 |     return 1 | ||||||
|   elif [ -z "$htmlpage" ]; then |   elif [ -z "$htmlpage" ]; then | ||||||
|     _err "FreeDNS returned empty subdomain page" |     _err "FreeDNS returned empty subdomain page" | ||||||
| @ -341,7 +341,7 @@ _freedns_add_txt_record() { | |||||||
|     return 1 |     return 1 | ||||||
|   elif _contains "$htmlpage" "security code was incorrect"; then |   elif _contains "$htmlpage" "security code was incorrect"; then | ||||||
|     _debug "$htmlpage" |     _debug "$htmlpage" | ||||||
|     _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested seurity code" |     _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code" | ||||||
|     _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" |     _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ dns_gandi_livedns_add() { | |||||||
|   txtvalue=$2 |   txtvalue=$2 | ||||||
| 
 | 
 | ||||||
|   if [ -z "$GANDI_LIVEDNS_KEY" ]; then |   if [ -z "$GANDI_LIVEDNS_KEY" ]; then | ||||||
|     _err "No API key specifed for Gandi LiveDNS." |     _err "No API key specified for Gandi LiveDNS." | ||||||
|     _err "Create your key and export it as GANDI_LIVEDNS_KEY" |     _err "Create your key and export it as GANDI_LIVEDNS_KEY" | ||||||
|     return 1 |     return 1 | ||||||
|   fi |   fi | ||||||
|  | |||||||
							
								
								
									
										97
									
								
								dnsapi/dns_infoblox.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								dnsapi/dns_infoblox.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,97 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | ## Infoblox API integration by Jason Keller and Elijah Tenai | ||||||
|  | ## | ||||||
|  | ## Report any bugs via https://github.com/jasonkeller/acme.sh | ||||||
|  | 
 | ||||||
|  | dns_infoblox_add() { | ||||||
|  | 
 | ||||||
|  |   ## Nothing to see here, just some housekeeping | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  |   baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue" | ||||||
|  | 
 | ||||||
|  |   _info "Using Infoblox API" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|  | 
 | ||||||
|  |   ## Check for the credentials | ||||||
|  |   if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then | ||||||
|  |     Infoblox_Creds="" | ||||||
|  |     Infoblox_Server="" | ||||||
|  |     _err "You didn't specify the credentials or server yet (Infoblox_Creds and Infoblox_Server)." | ||||||
|  |     _err "Please set them via EXPORT ([username:password] and [ip or hostname]) and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   ## Save the credentials to the account file | ||||||
|  |   _saveaccountconf Infoblox_Creds "$Infoblox_Creds" | ||||||
|  |   _saveaccountconf Infoblox_Server "$Infoblox_Server" | ||||||
|  | 
 | ||||||
|  |   ## Base64 encode the credentials | ||||||
|  |   Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) | ||||||
|  | 
 | ||||||
|  |   ## Construct the HTTP Authorization header | ||||||
|  |   export _H1="Accept-Language:en-US" | ||||||
|  |   export _H2="Authorization: Basic $Infoblox_CredsEncoded" | ||||||
|  | 
 | ||||||
|  |   ## Add the challenge record to the Infoblox grid member | ||||||
|  |   result=$(_post "" "$baseurlnObject" "" "POST") | ||||||
|  | 
 | ||||||
|  |   ## Let's see if we get something intelligible back from the unit | ||||||
|  |   if echo "$result" | egrep 'record:txt/.*:.*/default'; then | ||||||
|  |     _info "Successfully created the txt record" | ||||||
|  |     return 0 | ||||||
|  |   else | ||||||
|  |     _err "Error encountered during record addition" | ||||||
|  |     _err "$result" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | dns_infoblox_rm() { | ||||||
|  | 
 | ||||||
|  |   ## Nothing to see here, just some housekeeping | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   _info "Using Infoblox API" | ||||||
|  |   _debug fulldomain "$fulldomain" | ||||||
|  |   _debug txtvalue "$txtvalue" | ||||||
|  | 
 | ||||||
|  |   ## Base64 encode the credentials | ||||||
|  |   Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) | ||||||
|  | 
 | ||||||
|  |   ## Construct the HTTP Authorization header | ||||||
|  |   export _H1="Accept-Language:en-US" | ||||||
|  |   export _H2="Authorization: Basic $Infoblox_CredsEncoded" | ||||||
|  | 
 | ||||||
|  |   ## Does the record exist?  Let's check. | ||||||
|  |   baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&_return_type=xml-pretty" | ||||||
|  |   result=$(_get "$baseurlnObject") | ||||||
|  | 
 | ||||||
|  |   ## Let's see if we get something intelligible back from the grid | ||||||
|  |   if echo "$result" | egrep 'record:txt/.*:.*/default'; then | ||||||
|  |     ## Extract the object reference | ||||||
|  |     objRef=$(printf "%b" "$result" | _egrep_o 'record:txt/.*:.*/default') | ||||||
|  |     objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" | ||||||
|  |     ## Delete them! All the stale records! | ||||||
|  |     rmResult=$(_post "" "$objRmUrl" "" "DELETE") | ||||||
|  |     ## Let's see if that worked | ||||||
|  |     if echo "$rmResult" | egrep 'record:txt/.*:.*/default'; then | ||||||
|  |       _info "Successfully deleted $objRef" | ||||||
|  |       return 0 | ||||||
|  |     else | ||||||
|  |       _err "Error occurred during txt record delete" | ||||||
|  |       _err "$rmResult" | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |   else | ||||||
|  |     _err "Record to delete didn't match an existing record" | ||||||
|  |     _err "$result" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
| @ -1,6 +1,6 @@ | |||||||
| #!/usr/bin/env sh | #!/usr/bin/env sh | ||||||
| 
 | 
 | ||||||
| #Applcation Key | #Application Key | ||||||
| #OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" | #OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
| # | # | ||||||
| #Application Secret | #Application Secret | ||||||
| @ -119,7 +119,7 @@ dns_ovh_add() { | |||||||
| 
 | 
 | ||||||
|   _info "Checking authentication" |   _info "Checking authentication" | ||||||
| 
 | 
 | ||||||
|   response="$(_ovh_rest GET "domain/")" |   response="$(_ovh_rest GET "domain")" | ||||||
|   if _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." | ||||||
| @ -191,7 +191,7 @@ _ovh_authentication() { | |||||||
|   _H3="" |   _H3="" | ||||||
|   _H4="" |   _H4="" | ||||||
| 
 | 
 | ||||||
|   _ovhdata='{"accessRules": [{"method": "GET","path": "/*"},{"method": "POST","path": "/*"},{"method": "PUT","path": "/*"},{"method": "DELETE","path": "/*"}],"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/*"}],"redirection":"'$ovh_success'"}' | ||||||
| 
 | 
 | ||||||
|   response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" |   response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" | ||||||
|   _debug3 response "$response" |   _debug3 response "$response" | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #!/usr/bin/env sh | #!/usr/bin/env sh | ||||||
| 
 | 
 | ||||||
| #PowerDNS Emdedded API | #PowerDNS Embedded API | ||||||
| #https://doc.powerdns.com/md/httpapi/api_spec/ | #https://doc.powerdns.com/md/httpapi/api_spec/ | ||||||
| # | # | ||||||
| #PDNS_Url="http://ns.example.com:8081" | #PDNS_Url="http://ns.example.com:8081" | ||||||
|  | |||||||
							
								
								
									
										149
									
								
								dnsapi/dns_vscale.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										149
									
								
								dnsapi/dns_vscale.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,149 @@ | |||||||
|  | #!/usr/bin/env sh | ||||||
|  | 
 | ||||||
|  | #This is the vscale.io api wrapper for acme.sh | ||||||
|  | # | ||||||
|  | #Author: Alex Loban | ||||||
|  | #Report Bugs here: https://github.com/LAV45/acme.sh | ||||||
|  | 
 | ||||||
|  | #VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||||
|  | VSCALE_API_URL="https://api.vscale.io/v1" | ||||||
|  | 
 | ||||||
|  | ########  Public functions ##################### | ||||||
|  | 
 | ||||||
|  | #Usage: dns_myapi_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||||
|  | dns_vscale_add() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   if [ -z "$VSCALE_API_KEY" ]; then | ||||||
|  |     VSCALE_API_KEY="" | ||||||
|  |     _err "You didn't specify the VSCALE api key yet." | ||||||
|  |     _err "Please create you key and try again." | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   _saveaccountconf VSCALE_API_KEY "$VSCALE_API_KEY" | ||||||
|  | 
 | ||||||
|  |   _debug "First detect the root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug _domain_id "$_domain_id" | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  | 
 | ||||||
|  |   _vscale_tmpl_json="{\"type\":\"TXT\",\"name\":\"$_sub_domain.$_domain\",\"content\":\"$txtvalue\"}" | ||||||
|  | 
 | ||||||
|  |   if _vscale_rest POST "domains/$_domain_id/records/" "$_vscale_tmpl_json"; then | ||||||
|  |     response=$(printf "%s\n" "$response" | _egrep_o "{\"error\": \".+\"" | cut -d : -f 2) | ||||||
|  |     if [ -z "$response" ]; then | ||||||
|  |       _info "txt record updated success." | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #fulldomain txtvalue | ||||||
|  | dns_vscale_rm() { | ||||||
|  |   fulldomain=$1 | ||||||
|  |   txtvalue=$2 | ||||||
|  | 
 | ||||||
|  |   _debug "First detect the root zone" | ||||||
|  |   if ! _get_root "$fulldomain"; then | ||||||
|  |     _err "invalid domain" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug _domain_id "$_domain_id" | ||||||
|  |   _debug _sub_domain "$_sub_domain" | ||||||
|  |   _debug _domain "$_domain" | ||||||
|  | 
 | ||||||
|  |   _debug "Getting txt records" | ||||||
|  |   _vscale_rest GET "domains/$_domain_id/records/" | ||||||
|  | 
 | ||||||
|  |   if [ -n "$response" ]; then | ||||||
|  |     record_id=$(printf "%s\n" "$response" | _egrep_o "\"TXT\", \"id\": [0-9]+, \"name\": \"$_sub_domain.$_domain\"" | cut -d : -f 2 | tr -d ", \"name\"") | ||||||
|  |     _debug record_id "$record_id" | ||||||
|  |     if [ -z "$record_id" ]; then | ||||||
|  |       _err "Can not get record id to remove." | ||||||
|  |       return 1 | ||||||
|  |     fi | ||||||
|  |     if _vscale_rest DELETE "domains/$_domain_id/records/$record_id" && [ -z "$response" ]; then | ||||||
|  |       _info "txt record deleted success." | ||||||
|  |       return 0 | ||||||
|  |     fi | ||||||
|  |     _debug response "$response" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ####################  Private functions below ################################## | ||||||
|  | #_acme-challenge.www.domain.com | ||||||
|  | #returns | ||||||
|  | # _sub_domain=_acme-challenge.www | ||||||
|  | # _domain=domain.com | ||||||
|  | # _domain_id=12345 | ||||||
|  | _get_root() { | ||||||
|  |   domain=$1 | ||||||
|  |   i=2 | ||||||
|  |   p=1 | ||||||
|  | 
 | ||||||
|  |   if _vscale_rest GET "domains/"; then | ||||||
|  |     response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" | ||||||
|  |     while true; do | ||||||
|  |       h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||||
|  |       _debug h "$h" | ||||||
|  |       if [ -z "$h" ]; then | ||||||
|  |         #not valid | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  | 
 | ||||||
|  |       hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" | ||||||
|  |       if [ "$hostedzone" ]; then | ||||||
|  |         _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) | ||||||
|  |         if [ "$_domain_id" ]; then | ||||||
|  |           _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) | ||||||
|  |           _domain=$h | ||||||
|  |           return 0 | ||||||
|  |         fi | ||||||
|  |         return 1 | ||||||
|  |       fi | ||||||
|  |       p=$i | ||||||
|  |       i=$(_math "$i" + 1) | ||||||
|  |     done | ||||||
|  |   fi | ||||||
|  |   return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #method uri qstr data | ||||||
|  | _vscale_rest() { | ||||||
|  |   mtd="$1" | ||||||
|  |   ep="$2" | ||||||
|  |   data="$3" | ||||||
|  | 
 | ||||||
|  |   _debug mtd "$mtd" | ||||||
|  |   _debug ep "$ep" | ||||||
|  | 
 | ||||||
|  |   export _H1="Accept: application/json" | ||||||
|  |   export _H2="Content-Type: application/json" | ||||||
|  |   export _H3="X-Token: ${VSCALE_API_KEY}" | ||||||
|  | 
 | ||||||
|  |   if [ "$mtd" != "GET" ]; then | ||||||
|  |     # both POST and DELETE. | ||||||
|  |     _debug data "$data" | ||||||
|  |     response="$(_post "$data" "$VSCALE_API_URL/$ep" "" "$mtd")" | ||||||
|  |   else | ||||||
|  |     response="$(_get "$VSCALE_API_URL/$ep")" | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if [ "$?" != "0" ]; then | ||||||
|  |     _err "error $ep" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |   _debug2 response "$response" | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user