Merge branch 'dev' of https://github.com/Neilpang/acme.sh into dev
						commit
						f90bf756fb
					
				|  | @ -4,6 +4,7 @@ RUN apk update -f \ | |||
|   && apk --no-cache add -f \ | ||||
|   openssl \ | ||||
|   coreutils \ | ||||
|   bind-tools \ | ||||
|   curl \ | ||||
|   socat \ | ||||
|   && rm -rf /var/cache/apk/* | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) | |||
| - [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709) | ||||
| - [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html) | ||||
| - [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://www.archlinux.org/packages/community/any/acme.sh) | ||||
| - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) | ||||
| - [CentOS Web Panel](http://centos-webpanel.com/) | ||||
| - [lnmp.org](https://lnmp.org/) | ||||
|  | @ -327,9 +327,13 @@ You don't have to do anything manually! | |||
| 1. netcup DNS API (https://www.netcup.de) | ||||
| 1. GratisDNS.dk (https://gratisdns.dk) | ||||
| 1. Namecheap API (https://www.namecheap.com/) | ||||
| 1. MyDNS.JP API (https://www.mydns.jp/) | ||||
| 1. hosting.de (https://www.hosting.de) | ||||
| 1. Neodigit.net API (https://www.neodigit.net) | ||||
| 1. Exoscale.com API (https://www.exoscale.com/) | ||||
| 1. Internet.bs API (https://internetbs.net/) | ||||
| 
 | ||||
| And:  | ||||
| And: | ||||
| 
 | ||||
| **lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api | ||||
|    (DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)** | ||||
|  |  | |||
							
								
								
									
										98
									
								
								acme.sh
								
								
								
								
							
							
						
						
									
										98
									
								
								acme.sh
								
								
								
								
							|  | @ -37,6 +37,7 @@ VTYPE_HTTP="http-01" | |||
| VTYPE_DNS="dns-01" | ||||
| VTYPE_TLS="tls-sni-01" | ||||
| VTYPE_TLS2="tls-sni-02" | ||||
| VTYPE_ALPN="tls-alpn-01" | ||||
| 
 | ||||
| LOCAL_ANY_ADDRESS="0.0.0.0" | ||||
| 
 | ||||
|  | @ -48,6 +49,7 @@ NO_VALUE="no" | |||
| 
 | ||||
| W_TLS="tls" | ||||
| W_DNS="dns" | ||||
| W_ALPN="alpn" | ||||
| DNS_ALIAS_PREFIX="=" | ||||
| 
 | ||||
| MODE_STATELESS="stateless" | ||||
|  | @ -124,23 +126,19 @@ if [ -t 1 ]; then | |||
| fi | ||||
| 
 | ||||
| __green() { | ||||
|   if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then | ||||
|     printf '\033[1;31;32m' | ||||
|   if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then | ||||
|     printf '\033[1;31;32m%b\033[0m' "$1" | ||||
|     return | ||||
|   fi | ||||
|   printf -- "%b" "$1" | ||||
|   if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then | ||||
|     printf '\033[0m' | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
| __red() { | ||||
|   if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then | ||||
|     printf '\033[1;31;40m' | ||||
|   if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then | ||||
|     printf '\033[1;31;40m%b\033[0m' "$1" | ||||
|     return | ||||
|   fi | ||||
|   printf -- "%b" "$1" | ||||
|   if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then | ||||
|     printf '\033[0m' | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
| _printargs() { | ||||
|  | @ -1050,7 +1048,7 @@ _idn() { | |||
|   fi | ||||
| } | ||||
| 
 | ||||
| #_createcsr  cn  san_list  keyfile csrfile conf | ||||
| #_createcsr  cn  san_list  keyfile csrfile conf acmeValidationv1 | ||||
| _createcsr() { | ||||
|   _debug _createcsr | ||||
|   domain="$1" | ||||
|  | @ -1058,6 +1056,7 @@ _createcsr() { | |||
|   csrkey="$3" | ||||
|   csr="$4" | ||||
|   csrconf="$5" | ||||
|   acmeValidationv1="$6" | ||||
|   _debug2 domain "$domain" | ||||
|   _debug2 domainlist "$domainlist" | ||||
|   _debug2 csrkey "$csrkey" | ||||
|  | @ -1066,7 +1065,9 @@ _createcsr() { | |||
| 
 | ||||
|   printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf" | ||||
| 
 | ||||
|   if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then | ||||
|   if [ "$acmeValidationv1" ]; then | ||||
|     printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf" | ||||
|   elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then | ||||
|     #single domain | ||||
|     _info "Single domain" "$domain" | ||||
|     printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf" | ||||
|  | @ -1088,6 +1089,10 @@ _createcsr() { | |||
|     printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" | ||||
|   fi | ||||
| 
 | ||||
|   if [ "$acmeValidationv1" ]; then | ||||
|     printf "\n1.3.6.1.5.5.7.1.30.1=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}" | ||||
|   fi | ||||
| 
 | ||||
|   _csr_cn="$(_idn "$domain")" | ||||
|   _debug2 _csr_cn "$_csr_cn" | ||||
|   if _contains "$(uname -a)" "MINGW"; then | ||||
|  | @ -1138,12 +1143,17 @@ _readSubjectAltNamesFromCSR() { | |||
| 
 | ||||
|   if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then | ||||
|     _debug "AltNames contains subject" | ||||
|     _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")" | ||||
|     _excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')" | ||||
|     _debug _excapedAlgnames "$_excapedAlgnames" | ||||
|     _escapedSubject="$(echo "$_csrsubj" | tr '*' '#')" | ||||
|     _debug _escapedSubject "$_escapedSubject" | ||||
|     _dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")" | ||||
|     _debug _dnsAltnames "$_dnsAltnames" | ||||
|   else | ||||
|     _debug "AltNames doesn't contain subject" | ||||
|   fi | ||||
| 
 | ||||
|   printf "%s" "$_dnsAltnames" | sed "s/DNS://g" | ||||
|   echo "$_dnsAltnames" | sed "s/DNS://g" | ||||
| } | ||||
| 
 | ||||
| #_csrfile | ||||
|  | @ -1520,7 +1530,8 @@ _calcjwk() { | |||
|     JWK_HEADERPLACE_PART1='{"nonce": "' | ||||
|     JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"' | ||||
|   else | ||||
|     _err "Only RSA or EC key is supported." | ||||
|     _err "Only RSA or EC key is supported. keyfile=$keyfile" | ||||
|     _debug2 "$(cat "$keyfile")" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|  | @ -2105,7 +2116,7 @@ _sleep() { | |||
|   fi | ||||
| } | ||||
| 
 | ||||
| # _starttlsserver  san_a  san_b port content _ncaddr | ||||
| # _starttlsserver  san_a  san_b port content _ncaddr acmeValidationv1 | ||||
| _starttlsserver() { | ||||
|   _info "Starting tls server." | ||||
|   san_a="$1" | ||||
|  | @ -2113,10 +2124,12 @@ _starttlsserver() { | |||
|   port="$3" | ||||
|   content="$4" | ||||
|   opaddr="$5" | ||||
|   acmeValidationv1="$6" | ||||
| 
 | ||||
|   _debug san_a "$san_a" | ||||
|   _debug san_b "$san_b" | ||||
|   _debug port "$port" | ||||
|   _debug acmeValidationv1 "$acmeValidationv1" | ||||
| 
 | ||||
|   #create key TLS_KEY | ||||
|   if ! _createkey "2048" "$TLS_KEY"; then | ||||
|  | @ -2129,7 +2142,7 @@ _starttlsserver() { | |||
|   if [ "$san_b" ]; then | ||||
|     alt="$alt,$san_b" | ||||
|   fi | ||||
|   if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then | ||||
|   if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then | ||||
|     _err "Create tls validation csr error." | ||||
|     return 1 | ||||
|   fi | ||||
|  | @ -2155,6 +2168,10 @@ _starttlsserver() { | |||
|     __S_OPENSSL="$__S_OPENSSL -6" | ||||
|   fi | ||||
| 
 | ||||
|   if [ "$acmeValidationv1" ]; then | ||||
|     __S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1" | ||||
|   fi | ||||
| 
 | ||||
|   _debug "$__S_OPENSSL" | ||||
|   if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then | ||||
|     $__S_OPENSSL -tlsextdebug & | ||||
|  | @ -2843,7 +2860,7 @@ _isRealNginxConf() { | |||
|         _skip_ssl=1 | ||||
|         for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do | ||||
|           if [ "$_listen_i" ]; then | ||||
|             if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl[ |;]")" ]; then | ||||
|             if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl")" ]; then | ||||
|               _debug2 "$_listen_i is ssl" | ||||
|             else | ||||
|               _debug2 "$_listen_i is plain text" | ||||
|  | @ -2925,6 +2942,7 @@ _clearupdns() { | |||
|     _debug txt "$txt" | ||||
|     if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then | ||||
|       _debug "$d is already verified, skip $vtype." | ||||
|       _alias_index="$(_math "$_alias_index" + 1)" | ||||
|       continue | ||||
|     fi | ||||
| 
 | ||||
|  | @ -3064,8 +3082,8 @@ _on_before_issue() { | |||
|         _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" | ||||
|       fi | ||||
|       _checkport="$Le_HTTPPort" | ||||
|     elif [ "$_currentRoot" = "$W_TLS" ]; then | ||||
|       _info "Standalone tls mode." | ||||
|     elif [ "$_currentRoot" = "$W_TLS" ] || [ "$_currentRoot" = "$W_ALPN" ]; then | ||||
|       _info "Standalone tls/alpn mode." | ||||
|       if [ -z "$Le_TLSPort" ]; then | ||||
|         Le_TLSPort=443 | ||||
|       else | ||||
|  | @ -3691,6 +3709,10 @@ $_authorizations_map" | |||
|         fi | ||||
|       fi | ||||
| 
 | ||||
|       if [ "$_currentRoot" = "$W_ALPN" ]; then | ||||
|         vtype="$VTYPE_ALPN" | ||||
|       fi | ||||
| 
 | ||||
|       if [ "$ACME_VERSION" = "2" ]; then | ||||
|         response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")" | ||||
|         _debug2 "response" "$response" | ||||
|  | @ -3775,6 +3797,7 @@ $_authorizations_map" | |||
|       _debug d "$d" | ||||
|       if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then | ||||
|         _debug "$d is already verified, skip $vtype." | ||||
|         _alias_index="$(_math "$_alias_index" + 1)" | ||||
|         continue | ||||
|       fi | ||||
| 
 | ||||
|  | @ -4003,6 +4026,16 @@ $_authorizations_map" | |||
|         _on_issue_err "$_post_hook" "$vlist" | ||||
|         return 1 | ||||
|       fi | ||||
|     elif [ "$vtype" = "$VTYPE_ALPN" ]; then | ||||
|       acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")" | ||||
|       _debug acmevalidationv1 "$acmevalidationv1" | ||||
|       if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then | ||||
|         _err "Start tls server error." | ||||
|         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | ||||
|         _clearup | ||||
|         _on_issue_err "$_post_hook" "$vlist" | ||||
|         return 1 | ||||
|       fi | ||||
|     fi | ||||
| 
 | ||||
|     if ! __trigger_validation "$uri" "$keyauthorization"; then | ||||
|  | @ -4602,7 +4635,8 @@ deploy() { | |||
| 
 | ||||
|   _initpath "$_d" "$_isEcc" | ||||
|   if [ ! -d "$DOMAIN_PATH" ]; then | ||||
|     _err "Domain is not valid:'$_d'" | ||||
|     _err "The domain '$_d' is not a cert name. You must use the cert name to specify the cert to install." | ||||
|     _err "Can not find path:'$DOMAIN_PATH'" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|  | @ -4629,7 +4663,8 @@ installcert() { | |||
| 
 | ||||
|   _initpath "$_main_domain" "$_isEcc" | ||||
|   if [ ! -d "$DOMAIN_PATH" ]; then | ||||
|     _err "Domain is not valid:'$_main_domain'" | ||||
|     _err "The domain '$_main_domain' is not a cert name. You must use the cert name to specify the cert to install." | ||||
|     _err "Can not find path:'$DOMAIN_PATH'" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|  | @ -5463,6 +5498,7 @@ Parameters: | |||
|   --output-insecure                 Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure. | ||||
|   --webroot, -w  /path/to/webroot   Specifies the web root folder for web root mode. | ||||
|   --standalone                      Use standalone mode. | ||||
|   --alpn                            Use standalone alpn mode. | ||||
|   --stateless                       Use stateless mode, see: $_STATELESS_WIKI | ||||
|   --apache                          Use apache mode. | ||||
|   --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file]   Use dns mode or dns api. | ||||
|  | @ -5474,7 +5510,7 @@ Parameters: | |||
|   --log-level 1|2                   Specifies the log level, default is 1. | ||||
|   --syslog [0|3|6|7]                Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug. | ||||
| 
 | ||||
|   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 any other server after issue/renew a cert: | ||||
| 
 | ||||
|   --cert-file                       After issue/renew, the cert will be copied to this path. | ||||
|   --key-file                        After issue/renew, the key will be copied to this path. | ||||
|  | @ -5485,7 +5521,7 @@ Parameters: | |||
| 
 | ||||
|   --server SERVER                   ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory) | ||||
|   --accountconf                     Specifies a customized account config file. | ||||
|   --home                            Specifies the home dir for $PROJECT_NAME . | ||||
|   --home                            Specifies the home dir for $PROJECT_NAME. | ||||
|   --cert-home                       Specifies the home dir to save all the certs, only valid for '--install' command. | ||||
|   --config-home                     Specifies the home dir to save all the configurations. | ||||
|   --useragent                       Specifies the user agent string. it will be saved for future use too. | ||||
|  | @ -5493,6 +5529,7 @@ Parameters: | |||
|   --accountkey                      Specifies the account key path, only valid for the '--install' command. | ||||
|   --days                            Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days. | ||||
|   --httpport                        Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. | ||||
|   --tlsport                         Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer. | ||||
|   --local-address                   Specifies the standalone/tls server listening address, in case you have multiple ip addresses. | ||||
|   --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. | ||||
|  | @ -5817,6 +5854,14 @@ _process() { | |||
|           _webroot="$_webroot,$wvalue" | ||||
|         fi | ||||
|         ;; | ||||
|       --alpn) | ||||
|         wvalue="$W_ALPN" | ||||
|         if [ -z "$_webroot" ]; then | ||||
|           _webroot="$wvalue" | ||||
|         else | ||||
|           _webroot="$_webroot,$wvalue" | ||||
|         fi | ||||
|         ;; | ||||
|       --stateless) | ||||
|         wvalue="$MODE_STATELESS" | ||||
|         if [ -z "$_webroot" ]; then | ||||
|  | @ -5941,6 +5986,11 @@ _process() { | |||
|         Le_HTTPPort="$_httpport" | ||||
|         shift | ||||
|         ;; | ||||
|       --tlsport) | ||||
|         _tlsport="$2" | ||||
|         Le_TLSPort="$_tlsport" | ||||
|         shift | ||||
|         ;; | ||||
|       --listraw) | ||||
|         _listraw="raw" | ||||
|         ;; | ||||
|  |  | |||
|  | @ -295,4 +295,40 @@ You can then deploy the certificate as follows | |||
| 
 | ||||
| ```sh | ||||
| acme.sh --deploy -d www.mydomain.com --deploy-hook gitlab | ||||
| ``` | ||||
| ``` | ||||
| 
 | ||||
| ## 12. Deploy your cert to Hashicorp Vault | ||||
| 
 | ||||
| ```sh | ||||
| export VAULT_PREFIX="acme" | ||||
| ``` | ||||
| 
 | ||||
| You can then deploy the certificate as follows | ||||
| 
 | ||||
| ```sh | ||||
| acme.sh --deploy -d www.mydomain.com --deploy-hook vault_cli | ||||
| ``` | ||||
| 
 | ||||
| Your certs will be saved in Vault using this structure: | ||||
| 
 | ||||
| ```sh | ||||
| vault write "${VAULT_PREFIX}/${domain}/cert.pem"      value=@"..." | ||||
| vault write "${VAULT_PREFIX}/${domain}/cert.key"      value=@"..." | ||||
| vault write "${VAULT_PREFIX}/${domain}/chain.pem"     value=@"..." | ||||
| vault write "${VAULT_PREFIX}/${domain}/fullchain.pem" value=@"..." | ||||
| ``` | ||||
| 
 | ||||
| You might be using Fabio load balancer (which can get certs from | ||||
| Vault). It needs a bit different structure of your certs in Vault. It | ||||
| gets certs only from keys that were saved in `prefix/domain`, like this: | ||||
| 
 | ||||
| ```bash | ||||
| vault write <PREFIX>/www.domain.com cert=@cert.pem key=@key.pem | ||||
| ``` | ||||
| 
 | ||||
| If you want to save certs in Vault this way just set "FABIO" env | ||||
| variable to anything (ex: "1") before running `acme.sh`: | ||||
| 
 | ||||
| ```sh | ||||
| export FABIO="1" | ||||
| ``` | ||||
|  |  | |||
|  | @ -49,9 +49,13 @@ vault_cli_deploy() { | |||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 | ||||
|   $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 | ||||
|   $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1 | ||||
|   $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 | ||||
|   if [ -n "$FABIO" ]; then | ||||
|     $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1 | ||||
|   else | ||||
|     $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 | ||||
|     $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 | ||||
|     $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1 | ||||
|     $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 | ||||
|   fi | ||||
| 
 | ||||
| } | ||||
|  |  | |||
							
								
								
									
										131
									
								
								dnsapi/README.md
								
								
								
								
							
							
						
						
									
										131
									
								
								dnsapi/README.md
								
								
								
								
							|  | @ -6,7 +6,7 @@ https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode | |||
| 
 | ||||
| ## 1. Use CloudFlare domain API to automatically issue cert | ||||
| 
 | ||||
| First you need to login to your CloudFlare account to get your API key. | ||||
| First you need to login to your CloudFlare account to get your [API key](https://dash.cloudflare.com/profile).  | ||||
| 
 | ||||
| ``` | ||||
| export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||
|  | @ -146,13 +146,17 @@ Finally, make the DNS server and update Key available to `acme.sh` | |||
| export NSUPDATE_SERVER="dns.example.com" | ||||
| export NSUPDATE_KEY="/path/to/your/nsupdate.key" | ||||
| ``` | ||||
| and optionally (depending on DNS server) | ||||
| ``` | ||||
| export NSUPDATE_ZONE="example.com" | ||||
| ``` | ||||
| 
 | ||||
| Ok, let's issue a cert now: | ||||
| ``` | ||||
| acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com | ||||
| ``` | ||||
| 
 | ||||
| The `NSUPDATE_SERVER` and `NSUPDATE_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||
| The `NSUPDATE_SERVER`, `NSUPDATE_KEY`, and `NSUPDATE_ZONE` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||
| 
 | ||||
| 
 | ||||
| ## 8. Use LuaDNS domain API | ||||
|  | @ -263,16 +267,26 @@ when needed. | |||
| 
 | ||||
| ## 14. Use Linode domain API | ||||
| 
 | ||||
| First you need to login to your Linode account to get your API Key. | ||||
| [https://manager.linode.com/profile/api](https://manager.linode.com/profile/api) | ||||
| The tokens created in the classic manager and cloud manager are incompatible | ||||
| with one another. While the classic manager makes an all or nothing API, the | ||||
| newer cloud manager interface promises to produce API keys with a finer | ||||
| permission system. However, either way works just fine. | ||||
| 
 | ||||
| Then add an API key with label *ACME* and copy the new key. | ||||
| ### Classic Manager ### | ||||
| 
 | ||||
| Classic Manager: https://manager.linode.com/profile/api | ||||
| 
 | ||||
| First you need to login to your Linode account to get your API Key. | ||||
| 
 | ||||
| Then add an API key with label *ACME* and copy the new key into the following | ||||
| command. | ||||
| 
 | ||||
| ```sh | ||||
| export LINODE_API_KEY="..." | ||||
| ``` | ||||
| 
 | ||||
| Due to the reload time of any changes in the DNS records, we have to use the `dnssleep` option to wait at least 15 minutes for the changes to take effect. | ||||
| Due to the reload time of any changes in the DNS records, we have to use the | ||||
| `dnssleep` option to wait at least 15 minutes for the changes to take effect. | ||||
| 
 | ||||
| Ok, let's issue a cert now: | ||||
| 
 | ||||
|  | @ -280,7 +294,35 @@ Ok, let's issue a cert now: | |||
| acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com | ||||
| ``` | ||||
| 
 | ||||
| The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||
| The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be | ||||
| reused when needed. | ||||
| 
 | ||||
| ### Cloud Manager ### | ||||
| 
 | ||||
| Cloud Manager: https://cloud.linode.com/profile/tokens | ||||
| 
 | ||||
| First you need to login to your Linode account to get your API Key. | ||||
| 
 | ||||
|    1. Click on "Add a Personal Access Token". | ||||
|    2. Give the new key a "Label" (we recommend *ACME*) | ||||
|    3. Give it Read/Write access to "Domains" | ||||
|    4. "Submit" and copy the new key into the `LINODE_V4_API_KEY` command below. | ||||
| 
 | ||||
| ```sh | ||||
| export LINODE_V4_API_KEY="..." | ||||
| ``` | ||||
| 
 | ||||
| Due to the reload time of any changes in the DNS records, we have to use the | ||||
| `dnssleep` option to wait at least 15 minutes for the changes to take effect. | ||||
| 
 | ||||
| Ok, let's issue a cert now: | ||||
| 
 | ||||
| ```sh | ||||
| acme.sh --issue --dns dns_linode_v4 --dnssleep 900 -d example.com -d www.example.com | ||||
| ``` | ||||
| 
 | ||||
| The `LINODE_V4_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be | ||||
| reused when needed. | ||||
| 
 | ||||
| ## 15. Use FreeDNS | ||||
| 
 | ||||
|  | @ -454,7 +496,7 @@ The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account. | |||
| First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). | ||||
| 
 | ||||
| ``` | ||||
| VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||
| export VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" | ||||
| ``` | ||||
| 
 | ||||
| Ok, let's issue a cert now: | ||||
|  | @ -1014,7 +1056,78 @@ Now you can issue a certificate. | |||
| acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com | ||||
| ``` | ||||
| 
 | ||||
| ## 54. Use Internet.bs | ||||
| ## 54. Use MyDNS.JP API | ||||
| 
 | ||||
| First, register to MyDNS.JP and get MasterID and Password. | ||||
| 
 | ||||
| ``` | ||||
| export MYDNSJP_MasterID=MasterID | ||||
| export MYDNSJP_Password=Password | ||||
| ``` | ||||
| 
 | ||||
| To issue a certificate: | ||||
| 
 | ||||
| ``` | ||||
| acme.sh --issue --dns dns_mydnsjp -d example.com -d www.example.com | ||||
| ``` | ||||
| The `MYDNSJP_MasterID` and `MYDNSJP_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||
| 
 | ||||
| ## 55. Use hosting.de API | ||||
| 
 | ||||
| Create an API key in your hosting.de account here: https://secure.hosting.de | ||||
| 
 | ||||
| The key needs the following rights: | ||||
| - DNS_ZONES_EDIT | ||||
| - DNS_ZONES_LIST | ||||
| 
 | ||||
| Set your API Key and endpoint: | ||||
| 
 | ||||
| ``` | ||||
| export HOSTINGDE_APIKEY='xxx' | ||||
| export HOSTINGDE_ENDPOINT='https://secure.hosting.de' | ||||
| ``` | ||||
| 
 | ||||
| The plugin can also be used for the http.net API. http.net customers have to set endpoint to https://partner.http.net. | ||||
| 
 | ||||
| Ok, let's issue a cert now: | ||||
| ``` | ||||
| acme.sh --issue --dns dns_hostingde -d example.com -d *.example.com | ||||
| ``` | ||||
| 
 | ||||
| The hosting.de API key and endpoint will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||
| 
 | ||||
| ## 56. Use Neodigit.net API | ||||
| 
 | ||||
| ``` | ||||
| export NEODIGIT_API_TOKEN="eXJxTkdUVUZmcHQ3QWJackQ4ZGlMejRDSklRYmo5VG5zcFFKK2thYnE0WnVnNnMy" | ||||
| ``` | ||||
| 
 | ||||
| Ok, let's issue a cert now: | ||||
| ``` | ||||
| acme.sh --issue --dns dns_neodigit -d example.com -d www.example.com | ||||
| ``` | ||||
| 
 | ||||
| Neodigit API Token will be saved in `~/.acme.sh/account.conf` and will be used when needed. | ||||
| 
 | ||||
| ## 57. Use Exoscale API | ||||
| 
 | ||||
| Create an API key and secret key in the Exoscale account section | ||||
| 
 | ||||
| Set your API and secret key: | ||||
| 
 | ||||
| ``` | ||||
| export EXOSCALE_API_KEY='xxx' | ||||
| export EXOSCALE_SECRET_KEY='xxx' | ||||
| ``` | ||||
| 
 | ||||
| Now, let's issue a cert: | ||||
| ``` | ||||
| acme.sh --issue --dns dns_netcup -d example.com -d www.example.com | ||||
| ``` | ||||
| 
 | ||||
| The `EXOSCALE_API_KEY` and `EXOSCALE_SECRET_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. | ||||
| 
 | ||||
| ## 58. Use Internet.bs | ||||
| 
 | ||||
| First you need to create/obtain API credentials on your Internet.bs (https://internetbs.net) account. Go to the "Get my API Key" section in the "My Domains" section. | ||||
| 
 | ||||
|  |  | |||
|  | @ -316,7 +316,7 @@ _get_root() { | |||
|   ## (ZoneListResult with  continuation token for the next page of results) | ||||
|   ## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways | ||||
|   ## | ||||
|   _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?api-version=2017-09-01" "" "$accesstoken" | ||||
|   _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken" | ||||
|   # Find matching domain name is Json response | ||||
|   while true; do | ||||
|     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||
|  |  | |||
|  | @ -34,6 +34,9 @@ dns_cf_add() { | |||
|   _saveaccountconf_mutable CF_Key "$CF_Key" | ||||
|   _saveaccountconf_mutable CF_Email "$CF_Email" | ||||
| 
 | ||||
|   _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')" | ||||
|   _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" | ||||
| 
 | ||||
|   _debug "First detect the root zone" | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _err "invalid domain" | ||||
|  | @ -58,9 +61,12 @@ dns_cf_add() { | |||
|   #  if [ "$count" = "0" ]; then | ||||
|   _info "Adding record" | ||||
|   if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then | ||||
|     if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then | ||||
|     if _contains "$response" "$fulldomain"; then | ||||
|       _info "Added, OK" | ||||
|       return 0 | ||||
|     elif _contains "$response" "The record already exists"; then | ||||
|       _info "Already exists, OK" | ||||
|       return 0 | ||||
|     else | ||||
|       _err "Add txt record error." | ||||
|       return 1 | ||||
|  | @ -99,11 +105,16 @@ dns_cf_rm() { | |||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')" | ||||
| 
 | ||||
|   _debug "First detect the root zone" | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" | ||||
|     _err "invalid domain" | ||||
|     return 1 | ||||
|   fi | ||||
|   _cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" | ||||
| 
 | ||||
|   _debug _domain_id "$_domain_id" | ||||
|   _debug _sub_domain "$_sub_domain" | ||||
|   _debug _domain "$_domain" | ||||
|  | @ -143,6 +154,21 @@ dns_cf_rm() { | |||
| # _domain=domain.com | ||||
| # _domain_id=sdjkglgdfewsdfg | ||||
| _get_root() { | ||||
| 
 | ||||
|   _cf_zones="$(_readdomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_")" | ||||
|   _debug2 "_cf_zones" "$_cf_zones" | ||||
|   if [ -z "$_cf_zones" ]; then | ||||
|     _debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ is none, so get it." | ||||
|     if ! _cf_rest GET "zones"; then | ||||
|       return 1 | ||||
|     fi | ||||
|     _cf_zones="$response" | ||||
|     _savedomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" "$(echo "$_cf_zones" | _base64)" | ||||
|   else | ||||
|     _debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ found" | ||||
|     _cf_zones="$(echo "$_cf_zones" | _dbase64)" | ||||
|   fi | ||||
| 
 | ||||
|   domain=$1 | ||||
|   i=2 | ||||
|   p=1 | ||||
|  | @ -154,12 +180,8 @@ _get_root() { | |||
|       return 1 | ||||
|     fi | ||||
| 
 | ||||
|     if ! _cf_rest GET "zones?name=$h"; then | ||||
|       return 1 | ||||
|     fi | ||||
| 
 | ||||
|     if _contains "$response" "\"name\":\"$h\"" >/dev/null; then | ||||
|       _domain_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") | ||||
|     if _contains "$_cf_zones" "\"name\":\"$h\"" >/dev/null; then | ||||
|       _domain_id=$(echo "$_cf_zones" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "^\"id\":\"[^\"]*\"" | _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 | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| # Cloudxns.com Domain api | ||||
| # CloudXNS Domain api | ||||
| # | ||||
| #CX_Key="1234" | ||||
| # | ||||
|  | @ -19,7 +19,7 @@ dns_cx_add() { | |||
|   if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then | ||||
|     CX_Key="" | ||||
|     CX_Secret="" | ||||
|     _err "You don't specify cloudxns.com  api key or secret yet." | ||||
|     _err "You don't specify cloudxns.net  api key or secret yet." | ||||
|     _err "Please create you key and try again." | ||||
|     return 1 | ||||
|   fi | ||||
|  |  | |||
|  | @ -0,0 +1,168 @@ | |||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| EXOSCALE_API=https://api.exoscale.com/dns/v1 | ||||
| 
 | ||||
| ########  Public functions ##################### | ||||
| 
 | ||||
| # Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||
| # Used to add txt record | ||||
| dns_exoscale_add() { | ||||
|   fulldomain=$1 | ||||
|   txtvalue=$2 | ||||
| 
 | ||||
|   if ! _checkAuth; then | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug "First detect the root zone" | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _err "invalid domain" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug _sub_domain "$_sub_domain" | ||||
|   _debug _domain "$_domain" | ||||
| 
 | ||||
|   _info "Adding record" | ||||
|   if _exoscale_rest POST "domains/$_domain_id/records" "{\"record\":{\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":120}}" "$_domain_token"; then | ||||
|     if _contains "$response" "$txtvalue"; then | ||||
|       _info "Added, OK" | ||||
|       return 0 | ||||
|     fi | ||||
|   fi | ||||
|   _err "Add txt record error." | ||||
|   return 1 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| # Usage: fulldomain txtvalue | ||||
| # Used to remove the txt record after validation | ||||
| dns_exoscale_rm() { | ||||
|   fulldomain=$1 | ||||
|   txtvalue=$2 | ||||
| 
 | ||||
|   if ! _checkAuth; then | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug "First detect the root zone" | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _err "invalid domain" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug _sub_domain "$_sub_domain" | ||||
|   _debug _domain "$_domain" | ||||
| 
 | ||||
|   _debug "Getting txt records" | ||||
|   _exoscale_rest GET "domains/${_domain_id}/records?type=TXT&name=$_sub_domain" "" "$_domain_token" | ||||
|   if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then | ||||
|     _record_id=$(echo "$response" | tr '{' "\n" | grep "\"content\":\"$txtvalue\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") | ||||
|   fi | ||||
| 
 | ||||
|   if [ -z "$_record_id" ]; then | ||||
|     _err "Can not get record id to remove." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug "Deleting record $_record_id" | ||||
| 
 | ||||
|   if ! _exoscale_rest DELETE "domains/$_domain_id/records/$_record_id" "" "$_domain_token"; then | ||||
|     _err "Delete record error." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   return 0 | ||||
| } | ||||
| 
 | ||||
| ####################  Private functions below ################################## | ||||
| 
 | ||||
| _checkAuth() { | ||||
|   EXOSCALE_API_KEY="${EXOSCALE_API_KEY:-$(_readaccountconf_mutable EXOSCALE_API_KEY)}" | ||||
|   EXOSCALE_SECRET_KEY="${EXOSCALE_SECRET_KEY:-$(_readaccountconf_mutable EXOSCALE_SECRET_KEY)}" | ||||
| 
 | ||||
|   if [ -z "$EXOSCALE_API_KEY" ] || [ -z "$EXOSCALE_SECRET_KEY" ]; then | ||||
|     EXOSCALE_API_KEY="" | ||||
|     EXOSCALE_SECRET_KEY="" | ||||
|     _err "You don't specify Exoscale application key and application secret yet." | ||||
|     _err "Please create you key and try again." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _saveaccountconf_mutable EXOSCALE_API_KEY "$EXOSCALE_API_KEY" | ||||
|   _saveaccountconf_mutable EXOSCALE_SECRET_KEY "$EXOSCALE_SECRET_KEY" | ||||
| 
 | ||||
|   return 0 | ||||
| } | ||||
| 
 | ||||
| #_acme-challenge.www.domain.com | ||||
| #returns | ||||
| # _sub_domain=_acme-challenge.www | ||||
| # _domain=domain.com | ||||
| # _domain_id=sdjkglgdfewsdfg | ||||
| # _domain_token=sdjkglgdfewsdfg | ||||
| _get_root() { | ||||
| 
 | ||||
|   if ! _exoscale_rest GET "domains"; then | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   domain=$1 | ||||
|   i=2 | ||||
|   p=1 | ||||
|   while true; do | ||||
|     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||
|     _debug h "$h" | ||||
|     if [ -z "$h" ]; then | ||||
|       #not valid | ||||
|       return 1 | ||||
|     fi | ||||
| 
 | ||||
|     if _contains "$response" "\"name\":\"$h\"" >/dev/null; then | ||||
|       _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") | ||||
|       _domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") | ||||
|       if [ "$_domain_token" ] && [ "$_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 | ||||
|   return 1 | ||||
| } | ||||
| 
 | ||||
| # returns response | ||||
| _exoscale_rest() { | ||||
|   method=$1 | ||||
|   path="$2" | ||||
|   data="$3" | ||||
|   token="$4" | ||||
|   request_url="$EXOSCALE_API/$path" | ||||
|   _debug "$path" | ||||
| 
 | ||||
|   export _H1="Accept: application/json" | ||||
| 
 | ||||
|   if [ "$token" ]; then | ||||
|     export _H2="X-DNS-Domain-Token: $token" | ||||
|   else | ||||
|     export _H2="X-DNS-Token: $EXOSCALE_API_KEY:$EXOSCALE_SECRET_KEY" | ||||
|   fi | ||||
| 
 | ||||
|   if [ "$data" ] || [ "$method" = "DELETE" ]; then | ||||
|     export _H3="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 | ||||
| } | ||||
|  | @ -92,7 +92,9 @@ dns_he_rm() { | |||
|     return 1 | ||||
|   fi | ||||
|   # Remove the record | ||||
|   body="email=${HE_Username}&pass=${HE_Password}" | ||||
|   username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" | ||||
|   password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" | ||||
|   body="email=${username_encoded}&pass=${password_encoded}" | ||||
|   body="$body&menu=edit_zone" | ||||
|   body="$body&hosted_dns_zoneid=$_zone_id" | ||||
|   body="$body&hosted_dns_recordid=$_record_id" | ||||
|  |  | |||
|  | @ -0,0 +1,109 @@ | |||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| # hosting.de API | ||||
| 
 | ||||
| # Values to export: | ||||
| # export HOSTINGDE_ENDPOINT='https://secure.hosting.de' | ||||
| # export HOSTINGDE_APIKEY='xxxxx' | ||||
| 
 | ||||
| ########  Public functions ##################### | ||||
| 
 | ||||
| dns_hostingde_add() { | ||||
|   fulldomain="${1}" | ||||
|   txtvalue="${2}" | ||||
|   _debug "Calling: _hostingde_addRecord() '${fulldomain}' '${txtvalue}'" | ||||
|   _hostingde_apiKey && _hostingde_getZoneConfig && _hostingde_addRecord | ||||
| } | ||||
| 
 | ||||
| dns_hostingde_rm() { | ||||
|   fulldomain="${1}" | ||||
|   txtvalue="${2}" | ||||
|   _debug "Calling: _hostingde_removeRecord() '${fulldomain}' '${txtvalue}'" | ||||
|   _hostingde_apiKey && _hostingde_getZoneConfig && _hostingde_removeRecord | ||||
| } | ||||
| 
 | ||||
| #################### own Private functions below ################################## | ||||
| 
 | ||||
| _hostingde_apiKey() { | ||||
|   HOSTINGDE_APIKEY="${HOSTINGDE_APIKEY:-$(_readaccountconf_mutable HOSTINGDE_APIKEY)}" | ||||
|   if [ -z "$HOSTINGDE_APIKEY" ] || [ -z "$HOSTINGDE_ENDPOINT" ]; then | ||||
|     HOSTINGDE_APIKEY="" | ||||
|     HOSTINGDE_ENDPOINT="" | ||||
|     _err "You haven't specified hosting.de API key or endpoint yet." | ||||
|     _err "Please create your key and try again." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _saveaccountconf_mutable HOSTINGDE_APIKEY "$HOSTINGDE_APIKEY" | ||||
|   _saveaccountconf_mutable HOSTINGDE_ENDPOINT "$HOSTINGDE_ENDPOINT" | ||||
| } | ||||
| 
 | ||||
| _hostingde_getZoneConfig() { | ||||
|   _info "Getting ZoneConfig" | ||||
|   curZone="${fulldomain#*.}" | ||||
|   returnCode=1 | ||||
|   while _contains "${curZone}" "\\."; do | ||||
|     curData="{\"filter\":{\"field\":\"zoneName\",\"value\":\"${curZone}\"},\"limit\":1,\"authToken\":\"${HOSTINGDE_APIKEY}\"}" | ||||
|     curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneConfigsFind")" | ||||
|     _debug "Calling zoneConfigsFind: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneConfigsFind'" | ||||
|     _debug "Result of zoneConfigsFind: '$curResult'" | ||||
|     if _contains "${curResult}" '"status": "error"'; then | ||||
|       if _contains "${curResult}" '"code": 10109'; then | ||||
|         _err "The API-Key is invalid or could not be found" | ||||
|       else | ||||
|         _err "UNKNOWN API ERROR" | ||||
|       fi | ||||
|       returnCode=1 | ||||
|       break | ||||
|     fi | ||||
|     if _contains "${curResult}" '"totalEntries": 1'; then | ||||
|       _info "Retrieved zone data." | ||||
|       _debug "Zone data: '${curResult}'" | ||||
| 
 | ||||
|       # read ZoneConfigId for later update | ||||
|       zoneConfigId=$(echo "${curResult}" | _egrep_o '"id":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) | ||||
|       _debug "zoneConfigId '${zoneConfigId}'" | ||||
|       returnCode=0 | ||||
|       break | ||||
|     fi | ||||
|     curZone="${curZone#*.}" | ||||
|   done | ||||
|   if [ $returnCode -ne 0 ]; then | ||||
|     _info "ZoneEnd reached, Zone ${curZone} not found in hosting.de API" | ||||
|   fi | ||||
|   return $returnCode | ||||
| } | ||||
| 
 | ||||
| _hostingde_addRecord() { | ||||
|   _info "Adding record to zone" | ||||
|   curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}" | ||||
|   curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" | ||||
|   _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" | ||||
|   _debug "Result of zoneUpdate: '$curResult'" | ||||
|   if _contains "${curResult}" '"status": "error"'; then | ||||
|     if _contains "${curResult}" '"code": 10109'; then | ||||
|       _err "The API-Key is invalid or could not be found" | ||||
|     else | ||||
|       _err "UNKNOWN API ERROR" | ||||
|     fi | ||||
|     return 1 | ||||
|   fi | ||||
|   return 0 | ||||
| } | ||||
| 
 | ||||
| _hostingde_removeRecord() { | ||||
|   _info "Removing record from zone" | ||||
|   curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}" | ||||
|   curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")" | ||||
|   _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'" | ||||
|   _debug "Result of zoneUpdate: '$curResult'" | ||||
|   if _contains "${curResult}" '"status": "error"'; then | ||||
|     if _contains "${curResult}" '"code": 10109'; then | ||||
|       _err "The API-Key is invalid or could not be found" | ||||
|     else | ||||
|       _err "UNKNOWN API ERROR" | ||||
|     fi | ||||
|     return 1 | ||||
|   fi | ||||
|   return 0 | ||||
| } | ||||
|  | @ -0,0 +1,185 @@ | |||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| #Original Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net> | ||||
| #v4 Update Author: Aaron W. Swenson <aaron@grandmasfridge.org> | ||||
| 
 | ||||
| LINODE_V4_API_URL="https://api.linode.com/v4/domains" | ||||
| 
 | ||||
| ########  Public functions ##################### | ||||
| 
 | ||||
| #Usage: dns_linode_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||
| dns_linode_add() { | ||||
|   fulldomain="${1}" | ||||
|   txtvalue="${2}" | ||||
| 
 | ||||
|   if ! _Linode_API; then | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _info "Using Linode" | ||||
|   _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" | ||||
| 
 | ||||
|   _debug "First detect the root zone" | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _err "Domain does not exist." | ||||
|     return 1 | ||||
|   fi | ||||
|   _debug _domain_id "$_domain_id" | ||||
|   _debug _sub_domain "$_sub_domain" | ||||
|   _debug _domain "$_domain" | ||||
| 
 | ||||
|   _payload="{ | ||||
|               \"type\": \"TXT\", | ||||
|               \"name\": \"$_sub_domain\", | ||||
|               \"target\": \"$txtvalue\" | ||||
|             }" | ||||
| 
 | ||||
|   if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then | ||||
|     _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) | ||||
|     _debug _resource_id "$_resource_id" | ||||
| 
 | ||||
|     if [ -z "$_resource_id" ]; then | ||||
|       _err "Error adding the domain resource." | ||||
|       return 1 | ||||
|     fi | ||||
| 
 | ||||
|     _info "Domain resource successfully added." | ||||
|     return 0 | ||||
|   fi | ||||
| 
 | ||||
|   return 1 | ||||
| } | ||||
| 
 | ||||
| #Usage: dns_linode_rm   _acme-challenge.www.domain.com | ||||
| dns_linode_rm() { | ||||
|   fulldomain="${1}" | ||||
| 
 | ||||
|   if ! _Linode_API; then | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _info "Using Linode" | ||||
|   _debug "Calling: dns_linode_rm() '${fulldomain}'" | ||||
| 
 | ||||
|   _debug "First detect the root zone" | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _err "Domain does not exist." | ||||
|     return 1 | ||||
|   fi | ||||
|   _debug _domain_id "$_domain_id" | ||||
|   _debug _sub_domain "$_sub_domain" | ||||
|   _debug _domain "$_domain" | ||||
| 
 | ||||
|   if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then | ||||
|     response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" | ||||
| 
 | ||||
|     resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")" | ||||
|     if [ "$resource" ]; then | ||||
|       _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) | ||||
|       if [ "$_resource_id" ]; then | ||||
|         _debug _resource_id "$_resource_id" | ||||
| 
 | ||||
|         if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then | ||||
|           # On 200/OK, empty set is returned. Check for error, if any. | ||||
|           _error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1) | ||||
| 
 | ||||
|           if [ -n "$_error_response" ]; then | ||||
|             _err "Error deleting the domain resource: $_error_response" | ||||
|             return 1 | ||||
|           fi | ||||
| 
 | ||||
|           _info "Domain resource successfully deleted." | ||||
|           return 0 | ||||
|         fi | ||||
|       fi | ||||
| 
 | ||||
|       return 1 | ||||
|     fi | ||||
| 
 | ||||
|     return 0 | ||||
|   fi | ||||
| 
 | ||||
|   return 1 | ||||
| } | ||||
| 
 | ||||
| ####################  Private functions below ################################## | ||||
| 
 | ||||
| _Linode_API() { | ||||
|   if [ -z "$LINODE_V4_API_KEY" ]; then | ||||
|     LINODE_V4_API_KEY="" | ||||
| 
 | ||||
|     _err "You didn't specify the Linode v4 API key yet." | ||||
|     _err "Please create your key and try again." | ||||
| 
 | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _saveaccountconf LINODE_V4_API_KEY "$LINODE_V4_API_KEY" | ||||
| } | ||||
| 
 | ||||
| ####################  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 _rest GET; then | ||||
|     response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" | ||||
|     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 "{.*\"domain\":\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 method action data | ||||
| _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="Authorization: Bearer $LINODE_V4_API_KEY" | ||||
| 
 | ||||
|   if [ "$mtd" != "GET" ]; then | ||||
|     # both POST and DELETE. | ||||
|     _debug data "$data" | ||||
|     response="$(_post "$data" "$LINODE_V4_API_URL$ep" "" "$mtd")" | ||||
|   else | ||||
|     response="$(_get "$LINODE_V4_API_URL$ep$data")" | ||||
|   fi | ||||
| 
 | ||||
|   if [ "$?" != "0" ]; then | ||||
|     _err "error $ep" | ||||
|     return 1 | ||||
|   fi | ||||
|   _debug2 response "$response" | ||||
|   return 0 | ||||
| } | ||||
|  | @ -0,0 +1,210 @@ | |||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| #Here is a api script for MyDNS.JP. | ||||
| #This file name is "dns_mydnsjp.sh" | ||||
| #So, here must be a method   dns_mydnsjp_add() | ||||
| #Which will be called by acme.sh to add the txt record to your api system. | ||||
| #returns 0 means success, otherwise error. | ||||
| # | ||||
| #Author: epgdatacapbon | ||||
| #Report Bugs here: https://github.com/epgdatacapbon/acme.sh | ||||
| # | ||||
| ########  Public functions ##################### | ||||
| 
 | ||||
| # Export MyDNS.JP MasterID and Password in following variables... | ||||
| #  MYDNSJP_MasterID=MasterID | ||||
| #  MYDNSJP_Password=Password | ||||
| 
 | ||||
| MYDNSJP_API="https://www.mydns.jp" | ||||
| 
 | ||||
| #Usage: dns_mydnsjp_add   _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||
| dns_mydnsjp_add() { | ||||
|   fulldomain=$1 | ||||
|   txtvalue=$2 | ||||
| 
 | ||||
|   _info "Using mydnsjp" | ||||
|   _debug fulldomain "$fulldomain" | ||||
|   _debug txtvalue "$txtvalue" | ||||
| 
 | ||||
|   # Load the credentials from the account conf file | ||||
|   MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}" | ||||
|   MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}" | ||||
|   if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then | ||||
|     MYDNSJP_MasterID="" | ||||
|     MYDNSJP_Password="" | ||||
|     _err "You don't specify mydnsjp api MasterID and Password yet." | ||||
|     _err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   # Save the credentials to the account conf file | ||||
|   _saveaccountconf_mutable MYDNSJP_MasterID "$MYDNSJP_MasterID" | ||||
|   _saveaccountconf_mutable MYDNSJP_Password "$MYDNSJP_Password" | ||||
| 
 | ||||
|   _debug "First detect the root zone." | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _err "invalid domain" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug _sub_domain "$_sub_domain" | ||||
|   _debug _domain "$_domain" | ||||
| 
 | ||||
|   if _mydnsjp_api "REGIST" "$_domain" "$txtvalue"; then | ||||
|     if printf -- "%s" "$response" | grep "OK." >/dev/null; then | ||||
|       _info "Added, OK" | ||||
|       return 0 | ||||
|     else | ||||
|       _err "Add txt record error." | ||||
|       return 1 | ||||
|     fi | ||||
|   fi | ||||
|   _err "Add txt record error." | ||||
| 
 | ||||
|   return 1 | ||||
| } | ||||
| 
 | ||||
| #Usage: fulldomain txtvalue | ||||
| #Remove the txt record after validation. | ||||
| dns_mydnsjp_rm() { | ||||
|   fulldomain=$1 | ||||
|   txtvalue=$2 | ||||
| 
 | ||||
|   _info "Removing TXT record" | ||||
|   _debug fulldomain "$fulldomain" | ||||
|   _debug txtvalue "$txtvalue" | ||||
| 
 | ||||
|   # Load the credentials from the account conf file | ||||
|   MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}" | ||||
|   MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}" | ||||
|   if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then | ||||
|     MYDNSJP_MasterID="" | ||||
|     MYDNSJP_Password="" | ||||
|     _err "You don't specify mydnsjp api MasterID and Password yet." | ||||
|     _err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug "First detect the root zone" | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _err "invalid domain" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug _sub_domain "$_sub_domain" | ||||
|   _debug _domain "$_domain" | ||||
| 
 | ||||
|   if _mydnsjp_api "DELETE" "$_domain" "$txtvalue"; then | ||||
|     if printf -- "%s" "$response" | grep "OK." >/dev/null; then | ||||
|       _info "Deleted, OK" | ||||
|       return 0 | ||||
|     else | ||||
|       _err "Delete txt record error." | ||||
|       return 1 | ||||
|     fi | ||||
|   fi | ||||
|   _err "Delete txt record error." | ||||
| 
 | ||||
|   return 1 | ||||
| } | ||||
| 
 | ||||
| ####################  Private functions below ################################## | ||||
| # _acme-challenge.www.domain.com | ||||
| # returns | ||||
| #  _sub_domain=_acme-challenge.www | ||||
| #  _domain=domain.com | ||||
| _get_root() { | ||||
|   fulldomain=$1 | ||||
|   i=2 | ||||
|   p=1 | ||||
| 
 | ||||
|   # Get the root domain | ||||
|   _mydnsjp_retrieve_domain | ||||
|   if [ "$?" != "0" ]; then | ||||
|     # not valid | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   while true; do | ||||
|     _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) | ||||
| 
 | ||||
|     if [ -z "$_domain" ]; then | ||||
|       # not valid | ||||
|       return 1 | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$_domain" = "$_root_domain" ]; then | ||||
|       _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) | ||||
|       return 0 | ||||
|     fi | ||||
| 
 | ||||
|     p=$i | ||||
|     i=$(_math "$i" + 1) | ||||
|   done | ||||
| 
 | ||||
|   return 1 | ||||
| } | ||||
| 
 | ||||
| # Retrieve the root domain | ||||
| # returns 0 success | ||||
| _mydnsjp_retrieve_domain() { | ||||
|   _debug "Login to MyDNS.JP" | ||||
| 
 | ||||
|   response="$(_post "masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/?MENU=100")" | ||||
|   cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)" | ||||
| 
 | ||||
|   # If cookies is not empty then logon successful | ||||
|   if [ -z "$cookie" ]; then | ||||
|     _err "Fail to get a cookie." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug "Retrieve DOMAIN INFO page" | ||||
| 
 | ||||
|   export _H1="Cookie:${cookie}" | ||||
| 
 | ||||
|   response="$(_get "$MYDNSJP_API/?MENU=300")" | ||||
| 
 | ||||
|   if [ "$?" != "0" ]; then | ||||
|     _err "Fail to retrieve DOMAIN INFO." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _root_domain=$(echo "$response" | grep "DNSINFO\[domainname\]" | sed 's/^.*value="\([^"]*\)".*/\1/') | ||||
| 
 | ||||
|   # Logout | ||||
|   response="$(_get "$MYDNSJP_API/?MENU=090")" | ||||
| 
 | ||||
|   _debug _root_domain "$_root_domain" | ||||
| 
 | ||||
|   if [ -z "$_root_domain" ]; then | ||||
|     _err "Fail to get the root domain." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   return 0 | ||||
| } | ||||
| 
 | ||||
| _mydnsjp_api() { | ||||
|   cmd=$1 | ||||
|   domain=$2 | ||||
|   txtvalue=$3 | ||||
| 
 | ||||
|   # Base64 encode the credentials | ||||
|   credentials=$(printf "%s:%s" "$MYDNSJP_MasterID" "$MYDNSJP_Password" | _base64) | ||||
| 
 | ||||
|   # Construct the HTTP Authorization header | ||||
|   export _H1="Content-Type: application/x-www-form-urlencoded" | ||||
|   export _H2="Authorization: Basic ${credentials}" | ||||
| 
 | ||||
|   response="$(_post "CERTBOT_DOMAIN=$domain&CERTBOT_VALIDATION=$txtvalue&EDIT_CMD=$cmd" "$MYDNSJP_API/directedit.html")" | ||||
| 
 | ||||
|   if [ "$?" != "0" ]; then | ||||
|     _err "error $domain" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug2 response "$response" | ||||
| 
 | ||||
|   return 0 | ||||
| } | ||||
|  | @ -0,0 +1,181 @@ | |||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| # | ||||
| # NEODIGIT_API_TOKEN="jasdfhklsjadhflnhsausdfas" | ||||
| 
 | ||||
| # This is Neodigit.net api wrapper for acme.sh | ||||
| # | ||||
| # Author: Adrian Almenar | ||||
| # Report Bugs here: https://github.com/tecnocratica/acme.sh | ||||
| # | ||||
| NEODIGIT_API_URL="https://api.neodigit.net/v1" | ||||
| # | ||||
| ########  Public functions ##################### | ||||
| 
 | ||||
| # Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||||
| dns_neodigit_add() { | ||||
|   fulldomain=$1 | ||||
|   txtvalue=$2 | ||||
| 
 | ||||
|   NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" | ||||
|   if [ -z "$NEODIGIT_API_TOKEN" ]; then | ||||
|     NEODIGIT_API_TOKEN="" | ||||
|     _err "You haven't specified a Token api key." | ||||
|     _err "Please create the key and try again." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   #save the api key and email to the account conf file. | ||||
|   _saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN" | ||||
| 
 | ||||
|   _debug "First detect the root zone" | ||||
|   if ! _get_root "$fulldomain"; then | ||||
|     _err "invalid domain" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug fulldomain "$fulldomain" | ||||
|   _debug txtvalue "$txtvalue" | ||||
|   _debug domain "$_domain" | ||||
|   _debug sub_domain "$_sub_domain" | ||||
| 
 | ||||
|   _debug "Getting txt records" | ||||
|   _neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain" | ||||
| 
 | ||||
|   _debug _code "$_code" | ||||
| 
 | ||||
|   if [ "$_code" != "200" ]; then | ||||
|     _err "error retrieving data!" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   _debug fulldomain "$fulldomain" | ||||
|   _debug txtvalue "$txtvalue" | ||||
|   _debug domain "$_domain" | ||||
|   _debug sub_domain "$_sub_domain" | ||||
| 
 | ||||
|   _info "Adding record" | ||||
|   if _neo_rest POST "dns/zones/$_domain_id/records" "{\"record\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":60}}"; then | ||||
|     if printf -- "%s" "$response" | grep "$_sub_domain" >/dev/null; then | ||||
|       _info "Added, OK" | ||||
|       return 0 | ||||
|     else | ||||
|       _err "Add txt record error." | ||||
|       return 1 | ||||
|     fi | ||||
|   fi | ||||
|   _err "Add txt record error." | ||||
|   return 1 | ||||
| } | ||||
| 
 | ||||
| #fulldomain txtvalue | ||||
| dns_neodigit_rm() { | ||||
|   fulldomain=$1 | ||||
|   txtvalue=$2 | ||||
| 
 | ||||
|   NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" | ||||
|   if [ -z "$NEODIGIT_API_TOKEN" ]; then | ||||
|     NEODIGIT_API_TOKEN="" | ||||
|     _err "You haven't specified a Token api key." | ||||
|     _err "Please create the key and try again." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   #save the api key and email to the account conf file. | ||||
|   _saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN" | ||||
| 
 | ||||
|   _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" | ||||
|   _neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain&content=$txtvalue" | ||||
| 
 | ||||
|   if [ "$_code" != "200" ]; then | ||||
|     _err "error retrieving data!" | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
|   record_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) | ||||
|   _debug "record_id" "$record_id" | ||||
|   if [ -z "$record_id" ]; then | ||||
|     _err "Can not get record id to remove." | ||||
|     return 1 | ||||
|   fi | ||||
|   if ! _neo_rest DELETE "dns/zones/$_domain_id/records/$record_id"; then | ||||
|     _err "Delete record error." | ||||
|     return 1 | ||||
|   fi | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ####################  Private functions below ################################## | ||||
| #_acme-challenge.www.domain.com | ||||
| #returns | ||||
| # _sub_domain=_acme-challenge.www | ||||
| # _domain=domain.com | ||||
| # _domain_id=dasfdsafsadg5ythd | ||||
| _get_root() { | ||||
|   domain=$1 | ||||
|   i=2 | ||||
|   p=1 | ||||
|   while true; do | ||||
|     h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||||
|     _debug h "$h" | ||||
|     if [ -z "$h" ]; then | ||||
|       #not valid | ||||
|       return 1 | ||||
|     fi | ||||
| 
 | ||||
|     if ! _neo_rest GET "dns/zones?name=$h"; then | ||||
|       return 1 | ||||
|     fi | ||||
| 
 | ||||
|     _debug p "$p" | ||||
| 
 | ||||
|     if _contains "$response" "\"name\":\"$h\"" >/dev/null; then | ||||
|       _domain_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) | ||||
|       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 | ||||
|   return 1 | ||||
| } | ||||
| 
 | ||||
| _neo_rest() { | ||||
|   m=$1 | ||||
|   ep="$2" | ||||
|   data="$3" | ||||
|   _debug "$ep" | ||||
| 
 | ||||
|   export _H1="X-TCPanel-Token: $NEODIGIT_API_TOKEN" | ||||
|   export _H2="Content-Type: application/json" | ||||
| 
 | ||||
|   if [ "$m" != "GET" ]; then | ||||
|     _debug data "$data" | ||||
|     response="$(_post "$data" "$NEODIGIT_API_URL/$ep" "" "$m")" | ||||
|   else | ||||
|     response="$(_get "$NEODIGIT_API_URL/$ep")" | ||||
|   fi | ||||
| 
 | ||||
|   _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" | ||||
| 
 | ||||
|   if [ "$?" != "0" ]; then | ||||
|     _err "error $ep" | ||||
|     return 1 | ||||
|   fi | ||||
|   _debug2 response "$response" | ||||
|   return 0 | ||||
| } | ||||
|  | @ -13,12 +13,24 @@ dns_nsupdate_add() { | |||
|   _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" | ||||
|   _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" | ||||
|   _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" | ||||
|   _saveaccountconf NSUPDATE_ZONE "${NSUPDATE_ZONE}" | ||||
|   _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" | ||||
|   nsupdate -k "${NSUPDATE_KEY}" <<EOF | ||||
|   [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" | ||||
|   [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" | ||||
|   if [ -z "${NSUPDATE_ZONE}" ]; then | ||||
|     nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF | ||||
| server ${NSUPDATE_SERVER}  ${NSUPDATE_SERVER_PORT}  | ||||
| update add ${fulldomain}. 60 in txt "${txtvalue}" | ||||
| send | ||||
| EOF | ||||
|   else | ||||
|     nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF | ||||
| server ${NSUPDATE_SERVER}  ${NSUPDATE_SERVER_PORT} | ||||
| zone ${NSUPDATE_ZONE}. | ||||
| update add ${fulldomain}. 60 in txt "${txtvalue}" | ||||
| send | ||||
| EOF | ||||
|   fi | ||||
|   if [ $? -ne 0 ]; then | ||||
|     _err "error updating domain" | ||||
|     return 1 | ||||
|  | @ -34,11 +46,22 @@ dns_nsupdate_rm() { | |||
|   [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" | ||||
|   [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 | ||||
|   _info "removing ${fulldomain}. txt" | ||||
|   nsupdate -k "${NSUPDATE_KEY}" <<EOF | ||||
|   [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" | ||||
|   [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" | ||||
|   if [ -z "${NSUPDATE_ZONE}" ]; then | ||||
|     nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF | ||||
| server ${NSUPDATE_SERVER}  ${NSUPDATE_SERVER_PORT}  | ||||
| update delete ${fulldomain}. txt | ||||
| send | ||||
| EOF | ||||
|   else | ||||
|     nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF | ||||
| server ${NSUPDATE_SERVER}  ${NSUPDATE_SERVER_PORT} | ||||
| zone ${NSUPDATE_ZONE}. | ||||
| update delete ${fulldomain}. txt | ||||
| send | ||||
| EOF | ||||
|   fi | ||||
|   if [ $? -ne 0 ]; then | ||||
|     _err "error updating domain" | ||||
|     return 1 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Ne-Lexa
						Ne-Lexa