From b5ec3615d055801ebef8e96bc9c3e8f0af1c7a2d Mon Sep 17 00:00:00 2001 From: kaklakariada Date: Sun, 6 Mar 2016 18:12:36 +0100 Subject: [PATCH 0001/1348] Fix typo: Geting -> Getting --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index bb99dfd6..7329fbb5 100755 --- a/le.sh +++ b/le.sh @@ -660,7 +660,7 @@ issue() { alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) for d in $alldomains do - _info "Geting token for domain" $d + _info "Getting token for domain" $d _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" if [ ! -z "$code" ] && [ ! "$code" == '201' ] ; then _err "new-authz error: $response" From 2400e41fbc3b771d76b8128aea4ea9e1994c7ba8 Mon Sep 17 00:00:00 2001 From: Neil Date: Mon, 7 Mar 2016 09:52:54 +0800 Subject: [PATCH 0002/1348] example --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index d9447fea..c7c5b842 100644 --- a/README.md +++ b/README.md @@ -92,9 +92,19 @@ In all the cases, the issued cert will be placed in "~/.le/domain.com/" # Just issue a cert: +Example 1: +Only one domain: +``` +le issue /home/wwwroot/aa.com aa.com +``` + +Example 2: +Multiple domains in the same cert: + ``` le issue /home/wwwroot/aa.com aa.com www.aa.com,cp.aa.com ``` + First argument `/home/wwwroot/aa.com` is the web root folder, You must have `write` access to this folder. Second argument "aa.com" is the main domain you want to issue cert for. From d6863a09a6a3d3b69dedc55b6045efb835ad9d69 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 7 Mar 2016 21:14:05 +0800 Subject: [PATCH 0003/1348] minor, uncomment the conf values --- le.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 7329fbb5..136d0a32 100755 --- a/le.sh +++ b/le.sh @@ -272,12 +272,13 @@ _setopt() { __val="$4" __end="$5" if [ -z "$__opt" ] ; then - echo usage: $0 '"file" "opt" "=" "value" [";"]' + echo usage: _setopt '"file" "opt" "=" "value" [";"]' return fi if [ ! -f "$__conf" ] ; then touch "$__conf" fi + if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then _debug OK if [[ "$__val" == *"&"* ]] ; then @@ -285,6 +286,14 @@ _setopt() { fi text="$(cat $__conf)" printf "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + + elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then + if [[ "$__val" == *"&"* ]] ; then + __val="$(echo $__val | sed 's/&/\\&/g')" + fi + text="$(cat $__conf)" + printf "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + else _debug APP echo "$__opt$__sep$__val$__end" >> "$__conf" From ea455f73528b8c9481ca31f3ec557527797bc03a Mon Sep 17 00:00:00 2001 From: theit8514 Date: Mon, 7 Mar 2016 17:09:02 -0500 Subject: [PATCH 0004/1348] Add post-renew hook for executing commands when certificate was renewed successfully. --- le.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/le.sh b/le.sh index 136d0a32..eec523a4 100755 --- a/le.sh +++ b/le.sh @@ -389,6 +389,9 @@ _initpath() { domainhome="$LE_WORKING_DIR/$domain" mkdir -p "$domainhome" + if [ -z "$DOMAIN_PATH" ] ; then + DOMAIN_PATH="$domainhome" + fi if [ -z "$DOMAIN_CONF" ] ; then DOMAIN_CONF="$domainhome/$Le_Domain.conf" fi @@ -409,6 +412,9 @@ _initpath() { if [ -z "$CA_CERT_PATH" ] ; then CA_CERT_PATH="$domainhome/ca.cer" fi + if [ -z "$POST_RENEW_PATH" ] ; then + POST_RENEW_PATH="$domainhome/post-renew.sh" + fi } @@ -956,6 +962,9 @@ renew() { local res=$? IS_RENEW="" + if [ -x "$POST_RENEW_PATH" -a "$res" -eq "0" ] ; then + (cd $DOMAIN_PATH && exec $POST_RENEW_PATH) + fi return $res } @@ -988,12 +997,14 @@ renewAll() { Le_ReloadCmd="" DOMAIN_CONF="" + DOMAIN_PATH="" DOMAIN_SSL_CONF="" CSR_PATH="" CERT_KEY_PATH="" CERT_PATH="" CA_CERT_PATH="" ACCOUNT_KEY_PATH="" + POST_RENEW_PATH="" wellknown_path="" From eef38fccfe9b60ee52474e5f298ca9d10f288215 Mon Sep 17 00:00:00 2001 From: theit8514 Date: Mon, 7 Mar 2016 22:27:08 -0500 Subject: [PATCH 0005/1348] Modified code for Le_ReloadCmd --- le.sh | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/le.sh b/le.sh index eec523a4..36092ec4 100755 --- a/le.sh +++ b/le.sh @@ -412,9 +412,6 @@ _initpath() { if [ -z "$CA_CERT_PATH" ] ; then CA_CERT_PATH="$domainhome/ca.cer" fi - if [ -z "$POST_RENEW_PATH" ] ; then - POST_RENEW_PATH="$domainhome/post-renew.sh" - fi } @@ -962,9 +959,6 @@ renew() { local res=$? IS_RENEW="" - if [ -x "$POST_RENEW_PATH" -a "$res" -eq "0" ] ; then - (cd $DOMAIN_PATH && exec $POST_RENEW_PATH) - fi return $res } @@ -996,15 +990,14 @@ renewAll() { Le_ReloadCmd="" - DOMAIN_CONF="" DOMAIN_PATH="" + DOMAIN_CONF="" DOMAIN_SSL_CONF="" CSR_PATH="" CERT_KEY_PATH="" CERT_PATH="" CA_CERT_PATH="" ACCOUNT_KEY_PATH="" - POST_RENEW_PATH="" wellknown_path="" @@ -1061,7 +1054,7 @@ installcert() { if [ "$Le_ReloadCmd" ] ; then _info "Run Le_ReloadCmd: $Le_ReloadCmd" - eval $Le_ReloadCmd + (cd $DOMAIN_PATH && eval $Le_ReloadCmd) fi } From f8029e2e75408caec7ac6c15f7a81a45547f7abc Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 8 Mar 2016 20:18:24 +0800 Subject: [PATCH 0006/1348] minor --- le.sh | 2602 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 1301 insertions(+), 1301 deletions(-) diff --git a/le.sh b/le.sh index 36092ec4..1b3768d1 100755 --- a/le.sh +++ b/le.sh @@ -1,1301 +1,1301 @@ -#!/usr/bin/env bash -VER=1.1.8 -PROJECT="https://github.com/Neilpang/le" - -DEFAULT_CA="https://acme-v01.api.letsencrypt.org" -DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" - -STAGE_CA="https://acme-staging.api.letsencrypt.org" - -VTYPE_HTTP="http-01" -VTYPE_DNS="dns-01" - -if [ -z "$AGREEMENT" ] ; then - AGREEMENT="$DEFAULT_AGREEMENT" -fi - -_debug() { - - if [ -z "$DEBUG" ] ; then - return - fi - - if [ -z "$2" ] ; then - echo $1 - else - echo "$1"="$2" - fi -} - -_info() { - if [ -z "$2" ] ; then - echo "$1" - else - echo "$1"="$2" - fi -} - -_err() { - if [ -z "$2" ] ; then - echo "$1" >&2 - else - echo "$1"="$2" >&2 - fi - return 1 -} - -_h2b() { - hex=$(cat) - i=1 - j=2 - while [ '1' ] ; do - h=$(printf $hex | cut -c $i-$j) - if [ -z "$h" ] ; then - break; - fi - printf "\x$h" - let "i+=2" - let "j+=2" - done -} - -_base64() { - openssl base64 -e | tr -d '\n' -} - -#domain [2048] -createAccountKey() { - _info "Creating account key" - if [ -z "$1" ] ; then - echo Usage: createAccountKey account-domain [2048] - return - fi - - account=$1 - length=$2 - - if [[ "$length" == "ec-"* ]] ; then - length=2048 - fi - - if [ -z "$2" ] ; then - _info "Use default length 2048" - length=2048 - fi - _initpath - - if [ -f "$ACCOUNT_KEY_PATH" ] ; then - _info "Account key exists, skip" - return - else - #generate account key - openssl genrsa $length > "$ACCOUNT_KEY_PATH" - fi - -} - -#domain length -createDomainKey() { - _info "Creating domain key" - if [ -z "$1" ] ; then - echo Usage: createDomainKey domain [2048] - return - fi - - domain=$1 - length=$2 - isec="" - if [[ "$length" == "ec-"* ]] ; then - isec="1" - length=$(printf $length | cut -d '-' -f 2-100) - eccname="$length" - fi - - if [ -z "$length" ] ; then - if [ "$isec" ] ; then - length=256 - else - length=2048 - fi - fi - _info "Use length $length" - - if [ "$isec" ] ; then - if [ "$length" == "256" ] ; then - eccname="prime256v1" - fi - if [ "$length" == "384" ] ; then - eccname="secp384r1" - fi - if [ "$length" == "521" ] ; then - eccname="secp521r1" - fi - _info "Using ec name: $eccname" - fi - - _initpath $domain - - if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then - #generate account key - if [ "$isec" ] ; then - openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH" - else - openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH" - fi - else - if [ "$IS_RENEW" ] ; then - _info "Domain key exists, skip" - return 0 - else - _err "Domain key exists, do you want to overwrite the key?" - _err "Set FORCE=1, and try again." - return 1 - fi - fi - -} - -# domain domainlist -createCSR() { - _info "Creating csr" - if [ -z "$1" ] ; then - echo Usage: $0 domain [domainlist] - return - fi - domain=$1 - _initpath $domain - - domainlist=$2 - - if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && ! [ "$FORCE" ]; then - _info "CSR exists, skip" - return - fi - - if [ -z "$domainlist" ] ; then - #single domain - _info "Single domain" $domain - openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" > "$CSR_PATH" - else - alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" - #multi - _info "Multi domain" "$alt" - printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n[SAN]\nsubjectAltName=$alt" > "$DOMAIN_SSL_CONF" - openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -reqexts SAN -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" - fi - -} - -_b64() { - __n=$(cat) - echo $__n | tr '/+' '_-' | tr -d '= ' -} - -_time2str() { - #BSD - if date -u -d@$1 2>/dev/null ; then - return - fi - - #Linux - if date -u -r $1 2>/dev/null ; then - return - fi - -} - -_send_signed_request() { - url=$1 - payload=$2 - needbase64=$3 - - _debug url $url - _debug payload "$payload" - - CURL_HEADER="$LE_WORKING_DIR/curl.header" - dp="$LE_WORKING_DIR/curl.dump" - CURL="curl --silent --dump-header $CURL_HEADER " - if [ "$DEBUG" ] ; then - CURL="$CURL --trace-ascii $dp " - fi - payload64=$(echo -n $payload | _base64 | _b64) - _debug payload64 $payload64 - - nonceurl="$API/directory" - nonce="$($CURL -I $nonceurl | grep -o "^Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)" - - _debug nonce "$nonce" - - protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" - _debug protected "$protected" - - protected64="$(printf "$protected" | _base64 | _b64)" - _debug protected64 "$protected64" - - sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY_PATH | _base64 | _b64) - _debug sig "$sig" - - body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - _debug body "$body" - - if [ "$needbase64" ] ; then - response="$($CURL -X POST --data "$body" $url | _base64)" - else - response="$($CURL -X POST --data "$body" $url)" - fi - - responseHeaders="$(cat $CURL_HEADER)" - - _debug responseHeaders "$responseHeaders" - _debug response "$response" - code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )" - _debug code $code - -} - -_get() { - url="$1" - _debug url $url - response="$(curl --silent $url)" - ret=$? - _debug response "$response" - code="$(echo $response | grep -o '"status":[0-9]\+' | cut -d : -f 2)" - _debug code $code - return $ret -} - -#setopt "file" "opt" "=" "value" [";"] -_setopt() { - __conf="$1" - __opt="$2" - __sep="$3" - __val="$4" - __end="$5" - if [ -z "$__opt" ] ; then - echo usage: _setopt '"file" "opt" "=" "value" [";"]' - return - fi - if [ ! -f "$__conf" ] ; then - touch "$__conf" - fi - - if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then - _debug OK - if [[ "$__val" == *"&"* ]] ; then - __val="$(echo $__val | sed 's/&/\\&/g')" - fi - text="$(cat $__conf)" - printf "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" - - elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then - if [[ "$__val" == *"&"* ]] ; then - __val="$(echo $__val | sed 's/&/\\&/g')" - fi - text="$(cat $__conf)" - printf "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" - - else - _debug APP - echo "$__opt$__sep$__val$__end" >> "$__conf" - fi - _debug "$(grep -H -n "^$__opt$__sep" $__conf)" -} - -#_savedomainconf key value -#save to domain.conf -_savedomainconf() { - key="$1" - value="$2" - if [ "$DOMAIN_CONF" ] ; then - _setopt $DOMAIN_CONF "$key" "=" "$value" - else - _err "DOMAIN_CONF is empty, can not save $key=$value" - fi -} - -#_saveaccountconf key value -_saveaccountconf() { - key="$1" - value="$2" - if [ "$ACCOUNT_CONF_PATH" ] ; then - _setopt $ACCOUNT_CONF_PATH "$key" "=" "$value" - else - _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" - fi -} - -_startserver() { - content="$1" - _NC="nc -q 1" - if nc -h 2>&1 | grep "nmap.org/ncat" >/dev/null ; then - _NC="nc" - fi -# while true ; do - if [ "$DEBUG" ] ; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort -vv - else - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort > /dev/null - fi -# done -} - -_stopserver() { - pid="$1" - -} - -_initpath() { - - if [ -z "$LE_WORKING_DIR" ]; then - LE_WORKING_DIR=$HOME/.le - fi - - if [ -z "$ACCOUNT_CONF_PATH" ] ; then - ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" - fi - - if [ -f "$ACCOUNT_CONF_PATH" ] ; then - source "$ACCOUNT_CONF_PATH" - fi - - if [ -z "$API" ] ; then - if [ -z "$STAGE" ] ; then - API="$DEFAULT_CA" - else - API="$STAGE_CA" - _info "Using stage api:$API" - fi - fi - - if [ -z "$ACME_DIR" ] ; then - ACME_DIR="/home/.acme" - fi - - if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then - APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/" - fi - - domain="$1" - mkdir -p "$LE_WORKING_DIR" - - if [ -z "$ACCOUNT_KEY_PATH" ] ; then - ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" - fi - - if [ -z "$domain" ] ; then - return 0 - fi - - domainhome="$LE_WORKING_DIR/$domain" - mkdir -p "$domainhome" - - if [ -z "$DOMAIN_PATH" ] ; then - DOMAIN_PATH="$domainhome" - fi - if [ -z "$DOMAIN_CONF" ] ; then - DOMAIN_CONF="$domainhome/$Le_Domain.conf" - fi - - if [ -z "$DOMAIN_SSL_CONF" ] ; then - DOMAIN_SSL_CONF="$domainhome/$Le_Domain.ssl.conf" - fi - - if [ -z "$CSR_PATH" ] ; then - CSR_PATH="$domainhome/$domain.csr" - fi - if [ -z "$CERT_KEY_PATH" ] ; then - CERT_KEY_PATH="$domainhome/$domain.key" - fi - if [ -z "$CERT_PATH" ] ; then - CERT_PATH="$domainhome/$domain.cer" - fi - if [ -z "$CA_CERT_PATH" ] ; then - CA_CERT_PATH="$domainhome/ca.cer" - fi - -} - - -_apachePath() { - httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" - httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" - httpdconf="$httpdroot/$httpdconfname" - if [ ! -f $httpdconf ] ; then - _err "Apache Config file not found" $httpdconf - return 1 - fi - return 0 -} - -_restoreApache() { - if [ -z "$usingApache" ] ; then - return 0 - fi - _initpath - if ! _apachePath ; then - return 1 - fi - - if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then - _debug "No config file to restore." - return 0 - fi - - cp -p "$APACHE_CONF_BACKUP_DIR/$httpdconfname" "$httpdconf" - if ! apachectl -t ; then - _err "Sorry, restore apache config error, please contact me." - return 1; - fi - rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" - return 0 -} - -_setApache() { - _initpath - if ! _apachePath ; then - return 1 - fi - - #backup the conf - _debug "Backup apache config file" $httpdconf - cp -p $httpdconf $APACHE_CONF_BACKUP_DIR/ - _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" - _info "In case there is an error that can not be restored automatically, you may try restore it yourself." - _info "The backup file will be deleted on sucess, just forget it." - - #add alias - echo " -Alias /.well-known/acme-challenge $ACME_DIR - - -Require all granted - - " >> $httpdconf - - if ! apachectl -t ; then - _err "Sorry, apache config error, please contact me." - _restoreApache - return 1; - fi - - if [ ! -d "$ACME_DIR" ] ; then - mkdir -p "$ACME_DIR" - chmod 755 "$ACME_DIR" - fi - - if ! apachectl graceful ; then - _err "Sorry, apachectl graceful error, please contact me." - _restoreApache - return 1; - fi - usingApache="1" - return 0 -} - -_clearup () { - _stopserver $serverproc - serverproc="" - _restoreApache -} - -# webroot removelevel tokenfile -_clearupwebbroot() { - __webroot="$1" - if [ -z "$__webroot" ] ; then - _debug "no webroot specified, skip" - return 0 - fi - - if [ "$2" == '1' ] ; then - _debug "remove $__webroot/.well-known" - rm -rf "$__webroot/.well-known" - elif [ "$2" == '2' ] ; then - _debug "remove $__webroot/.well-known/acme-challenge" - rm -rf "$__webroot/.well-known/acme-challenge" - elif [ "$2" == '3' ] ; then - _debug "remove $__webroot/.well-known/acme-challenge/$3" - rm -rf "$__webroot/.well-known/acme-challenge/$3" - else - _info "Skip for removelevel:$2" - fi - - return 0 - -} - -issue() { - if [ -z "$2" ] ; then - _err "Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no" - return 1 - fi - Le_Webroot="$1" - Le_Domain="$2" - Le_Alt="$3" - Le_Keylength="$4" - Le_RealCertPath="$5" - Le_RealKeyPath="$6" - Le_RealCACertPath="$7" - Le_ReloadCmd="$8" - - - _initpath $Le_Domain - - if [ -f "$DOMAIN_CONF" ] ; then - Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2) - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then - _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" - return 2 - fi - fi - - if [ "$Le_Alt" == "no" ] ; then - Le_Alt="" - fi - if [ "$Le_Keylength" == "no" ] ; then - Le_Keylength="" - fi - if [ "$Le_RealCertPath" == "no" ] ; then - Le_RealCertPath="" - fi - if [ "$Le_RealKeyPath" == "no" ] ; then - Le_RealKeyPath="" - fi - if [ "$Le_RealCACertPath" == "no" ] ; then - Le_RealCACertPath="" - fi - if [ "$Le_ReloadCmd" == "no" ] ; then - Le_ReloadCmd="" - fi - - _setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain" - _setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt" - _setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot" - _setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength" - _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" - _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" - - if [ "$Le_Webroot" == "no" ] ; then - _info "Standalone mode." - if ! command -v "nc" > /dev/null ; then - _err "Please install netcat(nc) tools first." - return 1 - fi - - if [ -z "$Le_HTTPPort" ] ; then - Le_HTTPPort=80 - fi - _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" - - netprc="$(ss -ntpl | grep :$Le_HTTPPort" ")" - if [ "$netprc" ] ; then - _err "$netprc" - _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" - _err "Please stop it first" - return 1 - fi - fi - - if [ "$Le_Webroot" == "apache" ] ; then - if ! _setApache ; then - _err "set up apache error. Report error to me." - return 1 - fi - wellknown_path="$ACME_DIR" - else - usingApache="" - fi - - createAccountKey $Le_Domain $Le_Keylength - - if ! createDomainKey $Le_Domain $Le_Keylength ; then - _err "Create domain key error." - return 1 - fi - - if ! createCSR $Le_Domain $Le_Alt ; then - _err "Create CSR error." - return 1 - fi - - pub_exp=$(openssl rsa -in $ACCOUNT_KEY_PATH -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) - if [ "${#pub_exp}" == "5" ] ; then - pub_exp=0$pub_exp - fi - _debug pub_exp "$pub_exp" - - e=$(echo $pub_exp | _h2b | _base64) - _debug e "$e" - - modulus=$(openssl rsa -in $ACCOUNT_KEY_PATH -modulus -noout | cut -d '=' -f 2 ) - n=$(echo $modulus| _h2b | _base64 | _b64 ) - - jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' - - HEADER='{"alg": "RS256", "jwk": '$jwk'}' - HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' - _debug HEADER "$HEADER" - - accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) - thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _b64) - - - _info "Registering account" - regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ] ; then - regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' - fi - _send_signed_request "$API/acme/new-reg" "$regjson" - - if [ "$code" == "" ] || [ "$code" == '201' ] ; then - _info "Registered" - echo $response > $LE_WORKING_DIR/account.json - elif [ "$code" == '409' ] ; then - _info "Already registered" - else - _err "Register account Error." - _clearup - return 1 - fi - - vtype="$VTYPE_HTTP" - if [[ "$Le_Webroot" == "dns"* ]] ; then - vtype="$VTYPE_DNS" - fi - - vlist="$Le_Vlist" - # verify each domain - _info "Verify each domain" - sep='#' - if [ -z "$vlist" ] ; then - alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) - for d in $alldomains - do - _info "Getting token for domain" $d - _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" - if [ ! -z "$code" ] && [ ! "$code" == '201' ] ; then - _err "new-authz error: $response" - _clearup - return 1 - fi - - entry="$(printf $response | egrep -o '{[^{]*"type":"'$vtype'"[^}]*')" - _debug entry "$entry" - - token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" - _debug token $token - - uri="$(printf "$entry" | egrep -o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" - _debug uri $uri - - keyauthorization="$token.$thumbprint" - _debug keyauthorization "$keyauthorization" - - dvlist="$d$sep$keyauthorization$sep$uri" - _debug dvlist "$dvlist" - - vlist="$vlist$dvlist," - - done - - #add entry - dnsadded="" - ventries=$(echo "$vlist" | tr ',' ' ' ) - for ventry in $ventries - do - d=$(echo $ventry | cut -d $sep -f 1) - keyauthorization=$(echo $ventry | cut -d $sep -f 2) - - if [ "$vtype" == "$VTYPE_DNS" ] ; then - dnsadded='0' - txtdomain="_acme-challenge.$d" - _debug txtdomain "$txtdomain" - txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _b64)" - _debug txt "$txt" - #dns - #1. check use api - d_api="" - if [ -f "$LE_WORKING_DIR/$d/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/$d/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/$d/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/$d/$Le_Webroot.sh" - elif [ -f "$LE_WORKING_DIR/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/$Le_Webroot.sh" - elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" - fi - _debug d_api "$d_api" - - if [ "$d_api" ]; then - _info "Found domain api file: $d_api" - else - _err "Add the following TXT record:" - _err "Domain: $txtdomain" - _err "TXT value: $txt" - _err "Please be aware that you prepend _acme-challenge. before your domain" - _err "so the resulting subdomain will be: $txtdomain" - continue - fi - - if ! source $d_api ; then - _err "Load file $d_api error. Please check your api file and try again." - return 1 - fi - - addcommand="$Le_Webroot-add" - if ! command -v $addcommand ; then - _err "It seems that your api file is not correct, it must have a function named: $Le_Webroot" - return 1 - fi - - if ! $addcommand $txtdomain $txt ; then - _err "Error add txt for domain:$txtdomain" - return 1 - fi - dnsadded='1' - fi - done - - if [ "$dnsadded" == '0' ] ; then - _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\"" - _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." - _err "Please add the TXT records to the domains, and retry again." - return 1 - fi - - fi - - if [ "$dnsadded" == '1' ] ; then - _info "Sleep 60 seconds for the txt records to take effect" - sleep 60 - fi - - _debug "ok, let's start to verify" - ventries=$(echo "$vlist" | tr ',' ' ' ) - for ventry in $ventries - do - d=$(echo $ventry | cut -d $sep -f 1) - keyauthorization=$(echo $ventry | cut -d $sep -f 2) - uri=$(echo $ventry | cut -d $sep -f 3) - _info "Verifying:$d" - _debug "d" "$d" - _debug "keyauthorization" "$keyauthorization" - _debug "uri" "$uri" - removelevel="" - token="" - if [ "$vtype" == "$VTYPE_HTTP" ] ; then - if [ "$Le_Webroot" == "no" ] ; then - _info "Standalone mode server" - _startserver "$keyauthorization" & - serverproc="$!" - sleep 2 - _debug serverproc $serverproc - else - if [ -z "$wellknown_path" ] ; then - wellknown_path="$Le_Webroot/.well-known/acme-challenge" - fi - _debug wellknown_path "$wellknown_path" - - if [ ! -d "$Le_Webroot/.well-known" ] ; then - removelevel='1' - elif [ ! -d "$Le_Webroot/.well-known/acme-challenge" ] ; then - removelevel='2' - else - removelevel='3' - fi - - token="$(echo -e -n "$keyauthorization" | cut -d '.' -f 1)" - _debug "writing token:$token to $wellknown_path/$token" - - mkdir -p "$wellknown_path" - echo -n "$keyauthorization" > "$wellknown_path/$token" - - webroot_owner=$(stat -c '%U:%G' $Le_Webroot) - _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R $webroot_owner "$Le_Webroot/.well-known" - - fi - fi - - _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" - - if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then - _err "$d:Challenge error: $resource" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - _clearup - return 1 - fi - - while [ "1" ] ; do - _debug "sleep 5 secs to verify" - sleep 5 - _debug "checking" - - if ! _get $uri ; then - _err "$d:Verify error:$resource" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - _clearup - return 1 - fi - - status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | tr -d '"') - if [ "$status" == "valid" ] ; then - _info "Success" - _stopserver $serverproc - serverproc="" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - break; - fi - - if [ "$status" == "invalid" ] ; then - error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4) - _err "$d:Verify error:$error" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - _clearup - return 1; - fi - - if [ "$status" == "pending" ] ; then - _info "Pending" - else - _err "$d:Verify error:$response" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - _clearup - return 1 - fi - - done - - done - - _clearup - _info "Verify finished, start to sign." - der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _b64)" - _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" - - - Le_LinkCert="$(grep -i -o '^Location.*$' $CURL_HEADER | tr -d "\r\n" | cut -d " " -f 2)" - _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" - - if [ "$Le_LinkCert" ] ; then - echo -----BEGIN CERTIFICATE----- > "$CERT_PATH" - curl --silent "$Le_LinkCert" | openssl base64 -e >> "$CERT_PATH" - echo -----END CERTIFICATE----- >> "$CERT_PATH" - _info "Cert success." - cat "$CERT_PATH" - - _info "Your cert is in $CERT_PATH" - fi - - - if [ -z "$Le_LinkCert" ] ; then - response="$(echo $response | openssl base64 -d -A)" - _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" - return 1 - fi - - _setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\"" - - Le_LinkIssuer=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) - _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" - - if [ "$Le_LinkIssuer" ] ; then - echo -----BEGIN CERTIFICATE----- > "$CA_CERT_PATH" - curl --silent "$Le_LinkIssuer" | openssl base64 -e >> "$CA_CERT_PATH" - echo -----END CERTIFICATE----- >> "$CA_CERT_PATH" - _info "The intermediate CA cert is in $CA_CERT_PATH" - fi - - Le_CertCreateTime=$(date -u "+%s") - _setopt "$DOMAIN_CONF" "Le_CertCreateTime" "=" "$Le_CertCreateTime" - - Le_CertCreateTimeStr=$(date -u ) - _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\"" - - if [ ! "$Le_RenewalDays" ] ; then - Le_RenewalDays=80 - fi - - _setopt "$DOMAIN_CONF" "Le_RenewalDays" "=" "$Le_RenewalDays" - - let "Le_NextRenewTime=Le_CertCreateTime+Le_RenewalDays*24*60*60" - _setopt "$DOMAIN_CONF" "Le_NextRenewTime" "=" "$Le_NextRenewTime" - - Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) - _setopt "$DOMAIN_CONF" "Le_NextRenewTimeStr" "=" "\"$Le_NextRenewTimeStr\"" - - - installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" - -} - -renew() { - Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then - _err "Usage: $0 domain.com" - return 1 - fi - - _initpath $Le_Domain - - if [ ! -f "$DOMAIN_CONF" ] ; then - _info "$Le_Domain is not a issued domain, skip." - return 0; - fi - - source "$DOMAIN_CONF" - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then - _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" - return 2 - fi - - IS_RENEW="1" - issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" - local res=$? - IS_RENEW="" - - return $res -} - -renewAll() { - _initpath - _info "renewAll" - - for d in $(ls -F $LE_WORKING_DIR | grep [^.].*[.].*/$ ) ; do - d=$(echo $d | cut -d '/' -f 1) - _info "renew $d" - - Le_LinkCert="" - Le_Domain="" - Le_Alt="" - Le_Webroot="" - Le_Keylength="" - Le_LinkIssuer="" - - Le_CertCreateTime="" - Le_CertCreateTimeStr="" - Le_RenewalDays="" - Le_NextRenewTime="" - Le_NextRenewTimeStr="" - - Le_RealCertPath="" - Le_RealKeyPath="" - - Le_RealCACertPath="" - - Le_ReloadCmd="" - - DOMAIN_PATH="" - DOMAIN_CONF="" - DOMAIN_SSL_CONF="" - CSR_PATH="" - CERT_KEY_PATH="" - CERT_PATH="" - CA_CERT_PATH="" - ACCOUNT_KEY_PATH="" - - wellknown_path="" - - renew "$d" - done - -} - -installcert() { - Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then - _err "Usage: $0 domain.com [cert-file-path]|no [key-file-path]|no [ca-cert-file-path]|no [reloadCmd]|no" - return 1 - fi - - Le_RealCertPath="$2" - Le_RealKeyPath="$3" - Le_RealCACertPath="$4" - Le_ReloadCmd="$5" - - _initpath $Le_Domain - - _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" - _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" - - if [ "$Le_RealCertPath" ] ; then - if [ -f "$Le_RealCertPath" ] ; then - cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak - fi - cat "$CERT_PATH" > "$Le_RealCertPath" - fi - - if [ "$Le_RealCACertPath" ] ; then - if [ -f "$Le_RealCACertPath" ] ; then - cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak - fi - if [ "$Le_RealCACertPath" == "$Le_RealCertPath" ] ; then - echo "" >> "$Le_RealCACertPath" - cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" - else - cat "$CA_CERT_PATH" > "$Le_RealCACertPath" - fi - fi - - - if [ "$Le_RealKeyPath" ] ; then - if [ -f "$Le_RealKeyPath" ] ; then - cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak - fi - cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" - fi - - if [ "$Le_ReloadCmd" ] ; then - _info "Run Le_ReloadCmd: $Le_ReloadCmd" - (cd $DOMAIN_PATH && eval $Le_ReloadCmd) - fi - -} - -installcronjob() { - _initpath - _info "Installing cron job" - if ! crontab -l | grep 'le.sh cron' ; then - if [ -f "$LE_WORKING_DIR/le.sh" ] ; then - lesh="\"$LE_WORKING_DIR\"/le.sh" - else - _err "Can not install cronjob, le.sh not found." - return 1 - fi - crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab - - fi - return 0 -} - -uninstallcronjob() { - _info "Removing cron job" - cr="$(crontab -l | grep 'le.sh cron')" - if [ "$cr" ] ; then - crontab -l | sed "/le.sh cron/d" | crontab - - LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 6 | cut -d '=' -f 2 | tr -d '"')" - _info LE_WORKING_DIR "$LE_WORKING_DIR" - fi - _initpath - -} - - -# Detect profile file if not specified as environment variable -_detect_profile() { - if [ -n "$PROFILE" -a -f "$PROFILE" ]; then - echo "$PROFILE" - return - fi - - local DETECTED_PROFILE - DETECTED_PROFILE='' - local SHELLTYPE - SHELLTYPE="$(basename "/$SHELL")" - - if [ "$SHELLTYPE" = "bash" ]; then - if [ -f "$HOME/.bashrc" ]; then - DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then - DETECTED_PROFILE="$HOME/.bash_profile" - fi - elif [ "$SHELLTYPE" = "zsh" ]; then - DETECTED_PROFILE="$HOME/.zshrc" - fi - - if [ -z "$DETECTED_PROFILE" ]; then - if [ -f "$HOME/.profile" ]; then - DETECTED_PROFILE="$HOME/.profile" - elif [ -f "$HOME/.bashrc" ]; then - DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then - DETECTED_PROFILE="$HOME/.bash_profile" - elif [ -f "$HOME/.zshrc" ]; then - DETECTED_PROFILE="$HOME/.zshrc" - fi - fi - - if [ ! -z "$DETECTED_PROFILE" ]; then - echo "$DETECTED_PROFILE" - fi -} - -_initconf() { - _initpath - if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then - echo "#Account configurations: -#Here are the supported macros, uncomment them to make them take effect. -#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. - -#STAGE=1 # Use the staging api -#FORCE=1 # Force to issue cert -#DEBUG=1 # Debug mode - -#dns api -####################### -#Cloudflare: -#api key -#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" -#account email -#CF_Email="xxxx@sss.com" - -####################### -#Dnspod.cn: -#api key id -#DP_Id="1234" -#api key -#DP_Key="sADDsdasdgdsf" - -####################### -#Cloudxns.com: -#CX_Key="1234" -# -#CX_Secret="sADDsdasdgdsf" - - " > $ACCOUNT_CONF_PATH - fi -} - -install() { - _initpath - - #check if there is sudo installed, AND if the current user is a sudoer. - if command -v sudo > /dev/null ; then - if [ "$(sudo -n uptime 2>&1|grep "load"|wc -l)" != "0" ] ; then - SUDO=sudo - fi - fi - - if command -v yum > /dev/null ; then - YUM="1" - INSTALL="$SUDO yum install -y " - elif command -v apt-get > /dev/null ; then - INSTALL="$SUDO apt-get install -y " - fi - - if ! command -v "curl" > /dev/null ; then - _err "Please install curl first." - _err "$INSTALL curl" - return 1 - fi - - if ! command -v "crontab" > /dev/null ; then - _err "Please install crontab first." - if [ "$YUM" ] ; then - _err "$INSTALL crontabs" - else - _err "$INSTALL crontab" - fi - return 1 - fi - - if ! command -v "openssl" > /dev/null ; then - _err "Please install openssl first." - _err "$INSTALL openssl" - return 1 - fi - - _info "Installing to $LE_WORKING_DIR" - - _info "Installed to $LE_WORKING_DIR/le.sh" - cp le.sh $LE_WORKING_DIR/ - chmod +x $LE_WORKING_DIR/le.sh - - _profile="$(_detect_profile)" - if [ "$_profile" ] ; then - _debug "Found profile: $_profile" - - echo "LE_WORKING_DIR=$LE_WORKING_DIR -alias le=\"$LE_WORKING_DIR/le.sh\" -alias le.sh=\"$LE_WORKING_DIR/le.sh\" - " > "$LE_WORKING_DIR/le.env" - - _setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\"" - _info "OK, Close and reopen your terminal to start using le" - else - _info "No profile is found, you will need to go into $LE_WORKING_DIR to use le.sh" - fi - - mkdir -p $LE_WORKING_DIR/dnsapi - cp dnsapi/* $LE_WORKING_DIR/dnsapi/ - - #to keep compatible mv the .acc file to .key file - if [ -f "$LE_WORKING_DIR/account.acc" ] ; then - mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key" - fi - - installcronjob - - if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then - _initconf - fi - _info OK -} - -uninstall() { - uninstallcronjob - _initpath - - _profile="$(_detect_profile)" - if [ "$_profile" ] ; then - sed -i /le.env/d "$_profile" - fi - - rm -f $LE_WORKING_DIR/le.sh - _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." - -} - -cron() { - renewAll -} - -version() { - _info "$PROJECT" - _info "v$VER" -} - -showhelp() { - version - echo "Usage: le.sh [command] ...[args].... -Avalible commands: - -install: - Install le.sh to your system. -issue: - Issue a cert. -installcert: - Install the issued cert to apache/nginx or any other server. -renew: - Renew a cert. -renewAll: - Renew all the certs. -uninstall: - Uninstall le.sh, and uninstall the cron job. -version: - Show version info. -installcronjob: - Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. -uninstallcronjob: - Uninstall the cron job. The 'uninstall' command can do this automatically. -createAccountKey: - Create an account private key, professional use. -createDomainKey: - Create an domain private key, professional use. -createCSR: - Create CSR , professional use. - " -} - - -if [ -z "$1" ] ; then - showhelp -else - "$@" -fi +#!/usr/bin/env bash +VER=1.1.8 +PROJECT="https://github.com/Neilpang/le" + +DEFAULT_CA="https://acme-v01.api.letsencrypt.org" +DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" + +STAGE_CA="https://acme-staging.api.letsencrypt.org" + +VTYPE_HTTP="http-01" +VTYPE_DNS="dns-01" + +if [ -z "$AGREEMENT" ] ; then + AGREEMENT="$DEFAULT_AGREEMENT" +fi + +_debug() { + + if [ -z "$DEBUG" ] ; then + return + fi + + if [ -z "$2" ] ; then + echo $1 + else + echo "$1"="$2" + fi +} + +_info() { + if [ -z "$2" ] ; then + echo "$1" + else + echo "$1"="$2" + fi +} + +_err() { + if [ -z "$2" ] ; then + echo "$1" >&2 + else + echo "$1"="$2" >&2 + fi + return 1 +} + +_h2b() { + hex=$(cat) + i=1 + j=2 + while [ '1' ] ; do + h=$(printf $hex | cut -c $i-$j) + if [ -z "$h" ] ; then + break; + fi + printf "\x$h" + let "i+=2" + let "j+=2" + done +} + +_base64() { + openssl base64 -e | tr -d '\n' +} + +#domain [2048] +createAccountKey() { + _info "Creating account key" + if [ -z "$1" ] ; then + echo Usage: createAccountKey account-domain [2048] + return + fi + + account=$1 + length=$2 + + if [[ "$length" == "ec-"* ]] ; then + length=2048 + fi + + if [ -z "$2" ] ; then + _info "Use default length 2048" + length=2048 + fi + _initpath + + if [ -f "$ACCOUNT_KEY_PATH" ] ; then + _info "Account key exists, skip" + return + else + #generate account key + openssl genrsa $length > "$ACCOUNT_KEY_PATH" + fi + +} + +#domain length +createDomainKey() { + _info "Creating domain key" + if [ -z "$1" ] ; then + echo Usage: createDomainKey domain [2048] + return + fi + + domain=$1 + length=$2 + isec="" + if [[ "$length" == "ec-"* ]] ; then + isec="1" + length=$(printf $length | cut -d '-' -f 2-100) + eccname="$length" + fi + + if [ -z "$length" ] ; then + if [ "$isec" ] ; then + length=256 + else + length=2048 + fi + fi + _info "Use length $length" + + if [ "$isec" ] ; then + if [ "$length" == "256" ] ; then + eccname="prime256v1" + fi + if [ "$length" == "384" ] ; then + eccname="secp384r1" + fi + if [ "$length" == "521" ] ; then + eccname="secp521r1" + fi + _info "Using ec name: $eccname" + fi + + _initpath $domain + + if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then + #generate account key + if [ "$isec" ] ; then + openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH" + else + openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH" + fi + else + if [ "$IS_RENEW" ] ; then + _info "Domain key exists, skip" + return 0 + else + _err "Domain key exists, do you want to overwrite the key?" + _err "Set FORCE=1, and try again." + return 1 + fi + fi + +} + +# domain domainlist +createCSR() { + _info "Creating csr" + if [ -z "$1" ] ; then + echo Usage: $0 domain [domainlist] + return + fi + domain=$1 + _initpath $domain + + domainlist=$2 + + if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && ! [ "$FORCE" ]; then + _info "CSR exists, skip" + return + fi + + if [ -z "$domainlist" ] ; then + #single domain + _info "Single domain" $domain + openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" > "$CSR_PATH" + else + alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" + #multi + _info "Multi domain" "$alt" + printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n[SAN]\nsubjectAltName=$alt" > "$DOMAIN_SSL_CONF" + openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -reqexts SAN -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" + fi + +} + +_b64() { + __n=$(cat) + echo $__n | tr '/+' '_-' | tr -d '= ' +} + +_time2str() { + #BSD + if date -u -d@$1 2>/dev/null ; then + return + fi + + #Linux + if date -u -r $1 2>/dev/null ; then + return + fi + +} + +_send_signed_request() { + url=$1 + payload=$2 + needbase64=$3 + + _debug url $url + _debug payload "$payload" + + CURL_HEADER="$LE_WORKING_DIR/curl.header" + dp="$LE_WORKING_DIR/curl.dump" + CURL="curl --silent --dump-header $CURL_HEADER " + if [ "$DEBUG" ] ; then + CURL="$CURL --trace-ascii $dp " + fi + payload64=$(echo -n $payload | _base64 | _b64) + _debug payload64 $payload64 + + nonceurl="$API/directory" + nonce="$($CURL -I $nonceurl | grep -o "^Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)" + + _debug nonce "$nonce" + + protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" + _debug protected "$protected" + + protected64="$(printf "$protected" | _base64 | _b64)" + _debug protected64 "$protected64" + + sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY_PATH | _base64 | _b64) + _debug sig "$sig" + + body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + _debug body "$body" + + if [ "$needbase64" ] ; then + response="$($CURL -X POST --data "$body" $url | _base64)" + else + response="$($CURL -X POST --data "$body" $url)" + fi + + responseHeaders="$(cat $CURL_HEADER)" + + _debug responseHeaders "$responseHeaders" + _debug response "$response" + code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )" + _debug code $code + +} + +_get() { + url="$1" + _debug url $url + response="$(curl --silent $url)" + ret=$? + _debug response "$response" + code="$(echo $response | grep -o '"status":[0-9]\+' | cut -d : -f 2)" + _debug code $code + return $ret +} + +#setopt "file" "opt" "=" "value" [";"] +_setopt() { + __conf="$1" + __opt="$2" + __sep="$3" + __val="$4" + __end="$5" + if [ -z "$__opt" ] ; then + echo usage: _setopt '"file" "opt" "=" "value" [";"]' + return + fi + if [ ! -f "$__conf" ] ; then + touch "$__conf" + fi + + if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then + _debug OK + if [[ "$__val" == *"&"* ]] ; then + __val="$(echo $__val | sed 's/&/\\&/g')" + fi + text="$(cat $__conf)" + printf "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + + elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then + if [[ "$__val" == *"&"* ]] ; then + __val="$(echo $__val | sed 's/&/\\&/g')" + fi + text="$(cat $__conf)" + printf "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + + else + _debug APP + echo "$__opt$__sep$__val$__end" >> "$__conf" + fi + _debug "$(grep -H -n "^$__opt$__sep" $__conf)" +} + +#_savedomainconf key value +#save to domain.conf +_savedomainconf() { + key="$1" + value="$2" + if [ "$DOMAIN_CONF" ] ; then + _setopt $DOMAIN_CONF "$key" "=" "$value" + else + _err "DOMAIN_CONF is empty, can not save $key=$value" + fi +} + +#_saveaccountconf key value +_saveaccountconf() { + key="$1" + value="$2" + if [ "$ACCOUNT_CONF_PATH" ] ; then + _setopt $ACCOUNT_CONF_PATH "$key" "=" "$value" + else + _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" + fi +} + +_startserver() { + content="$1" + _NC="nc -q 1" + if nc -h 2>&1 | grep "nmap.org/ncat" >/dev/null ; then + _NC="nc" + fi +# while true ; do + if [ "$DEBUG" ] ; then + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort -vv + else + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort > /dev/null + fi +# done +} + +_stopserver() { + pid="$1" + +} + +_initpath() { + + if [ -z "$LE_WORKING_DIR" ]; then + LE_WORKING_DIR=$HOME/.le + fi + + if [ -z "$ACCOUNT_CONF_PATH" ] ; then + ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" + fi + + if [ -f "$ACCOUNT_CONF_PATH" ] ; then + source "$ACCOUNT_CONF_PATH" + fi + + if [ -z "$API" ] ; then + if [ -z "$STAGE" ] ; then + API="$DEFAULT_CA" + else + API="$STAGE_CA" + _info "Using stage api:$API" + fi + fi + + if [ -z "$ACME_DIR" ] ; then + ACME_DIR="/home/.acme" + fi + + if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then + APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/" + fi + + domain="$1" + mkdir -p "$LE_WORKING_DIR" + + if [ -z "$ACCOUNT_KEY_PATH" ] ; then + ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" + fi + + if [ -z "$domain" ] ; then + return 0 + fi + + domainhome="$LE_WORKING_DIR/$domain" + mkdir -p "$domainhome" + + if [ -z "$DOMAIN_PATH" ] ; then + DOMAIN_PATH="$domainhome" + fi + if [ -z "$DOMAIN_CONF" ] ; then + DOMAIN_CONF="$domainhome/$Le_Domain.conf" + fi + + if [ -z "$DOMAIN_SSL_CONF" ] ; then + DOMAIN_SSL_CONF="$domainhome/$Le_Domain.ssl.conf" + fi + + if [ -z "$CSR_PATH" ] ; then + CSR_PATH="$domainhome/$domain.csr" + fi + if [ -z "$CERT_KEY_PATH" ] ; then + CERT_KEY_PATH="$domainhome/$domain.key" + fi + if [ -z "$CERT_PATH" ] ; then + CERT_PATH="$domainhome/$domain.cer" + fi + if [ -z "$CA_CERT_PATH" ] ; then + CA_CERT_PATH="$domainhome/ca.cer" + fi + +} + + +_apachePath() { + httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" + httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" + httpdconf="$httpdroot/$httpdconfname" + if [ ! -f $httpdconf ] ; then + _err "Apache Config file not found" $httpdconf + return 1 + fi + return 0 +} + +_restoreApache() { + if [ -z "$usingApache" ] ; then + return 0 + fi + _initpath + if ! _apachePath ; then + return 1 + fi + + if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then + _debug "No config file to restore." + return 0 + fi + + cp -p "$APACHE_CONF_BACKUP_DIR/$httpdconfname" "$httpdconf" + if ! apachectl -t ; then + _err "Sorry, restore apache config error, please contact me." + return 1; + fi + rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" + return 0 +} + +_setApache() { + _initpath + if ! _apachePath ; then + return 1 + fi + + #backup the conf + _debug "Backup apache config file" $httpdconf + cp -p $httpdconf $APACHE_CONF_BACKUP_DIR/ + _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" + _info "In case there is an error that can not be restored automatically, you may try restore it yourself." + _info "The backup file will be deleted on sucess, just forget it." + + #add alias + echo " +Alias /.well-known/acme-challenge $ACME_DIR + + +Require all granted + + " >> $httpdconf + + if ! apachectl -t ; then + _err "Sorry, apache config error, please contact me." + _restoreApache + return 1; + fi + + if [ ! -d "$ACME_DIR" ] ; then + mkdir -p "$ACME_DIR" + chmod 755 "$ACME_DIR" + fi + + if ! apachectl graceful ; then + _err "Sorry, apachectl graceful error, please contact me." + _restoreApache + return 1; + fi + usingApache="1" + return 0 +} + +_clearup () { + _stopserver $serverproc + serverproc="" + _restoreApache +} + +# webroot removelevel tokenfile +_clearupwebbroot() { + __webroot="$1" + if [ -z "$__webroot" ] ; then + _debug "no webroot specified, skip" + return 0 + fi + + if [ "$2" == '1' ] ; then + _debug "remove $__webroot/.well-known" + rm -rf "$__webroot/.well-known" + elif [ "$2" == '2' ] ; then + _debug "remove $__webroot/.well-known/acme-challenge" + rm -rf "$__webroot/.well-known/acme-challenge" + elif [ "$2" == '3' ] ; then + _debug "remove $__webroot/.well-known/acme-challenge/$3" + rm -rf "$__webroot/.well-known/acme-challenge/$3" + else + _info "Skip for removelevel:$2" + fi + + return 0 + +} + +issue() { + if [ -z "$2" ] ; then + _err "Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no" + return 1 + fi + Le_Webroot="$1" + Le_Domain="$2" + Le_Alt="$3" + Le_Keylength="$4" + Le_RealCertPath="$5" + Le_RealKeyPath="$6" + Le_RealCACertPath="$7" + Le_ReloadCmd="$8" + + + _initpath $Le_Domain + + if [ -f "$DOMAIN_CONF" ] ; then + Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2) + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then + _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" + return 2 + fi + fi + + if [ "$Le_Alt" == "no" ] ; then + Le_Alt="" + fi + if [ "$Le_Keylength" == "no" ] ; then + Le_Keylength="" + fi + if [ "$Le_RealCertPath" == "no" ] ; then + Le_RealCertPath="" + fi + if [ "$Le_RealKeyPath" == "no" ] ; then + Le_RealKeyPath="" + fi + if [ "$Le_RealCACertPath" == "no" ] ; then + Le_RealCACertPath="" + fi + if [ "$Le_ReloadCmd" == "no" ] ; then + Le_ReloadCmd="" + fi + + _setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain" + _setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt" + _setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot" + _setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength" + _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" + _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" + + if [ "$Le_Webroot" == "no" ] ; then + _info "Standalone mode." + if ! command -v "nc" > /dev/null ; then + _err "Please install netcat(nc) tools first." + return 1 + fi + + if [ -z "$Le_HTTPPort" ] ; then + Le_HTTPPort=80 + fi + _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" + + netprc="$(ss -ntpl | grep :$Le_HTTPPort" ")" + if [ "$netprc" ] ; then + _err "$netprc" + _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" + _err "Please stop it first" + return 1 + fi + fi + + if [ "$Le_Webroot" == "apache" ] ; then + if ! _setApache ; then + _err "set up apache error. Report error to me." + return 1 + fi + wellknown_path="$ACME_DIR" + else + usingApache="" + fi + + createAccountKey $Le_Domain $Le_Keylength + + if ! createDomainKey $Le_Domain $Le_Keylength ; then + _err "Create domain key error." + return 1 + fi + + if ! createCSR $Le_Domain $Le_Alt ; then + _err "Create CSR error." + return 1 + fi + + pub_exp=$(openssl rsa -in $ACCOUNT_KEY_PATH -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) + if [ "${#pub_exp}" == "5" ] ; then + pub_exp=0$pub_exp + fi + _debug pub_exp "$pub_exp" + + e=$(echo $pub_exp | _h2b | _base64) + _debug e "$e" + + modulus=$(openssl rsa -in $ACCOUNT_KEY_PATH -modulus -noout | cut -d '=' -f 2 ) + n=$(echo $modulus| _h2b | _base64 | _b64 ) + + jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' + + HEADER='{"alg": "RS256", "jwk": '$jwk'}' + HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' + _debug HEADER "$HEADER" + + accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) + thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _b64) + + + _info "Registering account" + regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' + if [ "$ACCOUNT_EMAIL" ] ; then + regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' + fi + _send_signed_request "$API/acme/new-reg" "$regjson" + + if [ "$code" == "" ] || [ "$code" == '201' ] ; then + _info "Registered" + echo $response > $LE_WORKING_DIR/account.json + elif [ "$code" == '409' ] ; then + _info "Already registered" + else + _err "Register account Error." + _clearup + return 1 + fi + + vtype="$VTYPE_HTTP" + if [[ "$Le_Webroot" == "dns"* ]] ; then + vtype="$VTYPE_DNS" + fi + + vlist="$Le_Vlist" + # verify each domain + _info "Verify each domain" + sep='#' + if [ -z "$vlist" ] ; then + alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) + for d in $alldomains + do + _info "Getting token for domain" $d + _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" + if [ ! -z "$code" ] && [ ! "$code" == '201' ] ; then + _err "new-authz error: $response" + _clearup + return 1 + fi + + entry="$(printf $response | egrep -o '{[^{]*"type":"'$vtype'"[^}]*')" + _debug entry "$entry" + + token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" + _debug token $token + + uri="$(printf "$entry" | egrep -o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" + _debug uri $uri + + keyauthorization="$token.$thumbprint" + _debug keyauthorization "$keyauthorization" + + dvlist="$d$sep$keyauthorization$sep$uri" + _debug dvlist "$dvlist" + + vlist="$vlist$dvlist," + + done + + #add entry + dnsadded="" + ventries=$(echo "$vlist" | tr ',' ' ' ) + for ventry in $ventries + do + d=$(echo $ventry | cut -d $sep -f 1) + keyauthorization=$(echo $ventry | cut -d $sep -f 2) + + if [ "$vtype" == "$VTYPE_DNS" ] ; then + dnsadded='0' + txtdomain="_acme-challenge.$d" + _debug txtdomain "$txtdomain" + txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _b64)" + _debug txt "$txt" + #dns + #1. check use api + d_api="" + if [ -f "$LE_WORKING_DIR/$d/$Le_Webroot" ] ; then + d_api="$LE_WORKING_DIR/$d/$Le_Webroot" + elif [ -f "$LE_WORKING_DIR/$d/$Le_Webroot.sh" ] ; then + d_api="$LE_WORKING_DIR/$d/$Le_Webroot.sh" + elif [ -f "$LE_WORKING_DIR/$Le_Webroot" ] ; then + d_api="$LE_WORKING_DIR/$Le_Webroot" + elif [ -f "$LE_WORKING_DIR/$Le_Webroot.sh" ] ; then + d_api="$LE_WORKING_DIR/$Le_Webroot.sh" + elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot" ] ; then + d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot" + elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" ] ; then + d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" + fi + _debug d_api "$d_api" + + if [ "$d_api" ]; then + _info "Found domain api file: $d_api" + else + _err "Add the following TXT record:" + _err "Domain: $txtdomain" + _err "TXT value: $txt" + _err "Please be aware that you prepend _acme-challenge. before your domain" + _err "so the resulting subdomain will be: $txtdomain" + continue + fi + + if ! source $d_api ; then + _err "Load file $d_api error. Please check your api file and try again." + return 1 + fi + + addcommand="$Le_Webroot-add" + if ! command -v $addcommand ; then + _err "It seems that your api file is not correct, it must have a function named: $Le_Webroot" + return 1 + fi + + if ! $addcommand $txtdomain $txt ; then + _err "Error add txt for domain:$txtdomain" + return 1 + fi + dnsadded='1' + fi + done + + if [ "$dnsadded" == '0' ] ; then + _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\"" + _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." + _err "Please add the TXT records to the domains, and retry again." + return 1 + fi + + fi + + if [ "$dnsadded" == '1' ] ; then + _info "Sleep 60 seconds for the txt records to take effect" + sleep 60 + fi + + _debug "ok, let's start to verify" + ventries=$(echo "$vlist" | tr ',' ' ' ) + for ventry in $ventries + do + d=$(echo $ventry | cut -d $sep -f 1) + keyauthorization=$(echo $ventry | cut -d $sep -f 2) + uri=$(echo $ventry | cut -d $sep -f 3) + _info "Verifying:$d" + _debug "d" "$d" + _debug "keyauthorization" "$keyauthorization" + _debug "uri" "$uri" + removelevel="" + token="" + if [ "$vtype" == "$VTYPE_HTTP" ] ; then + if [ "$Le_Webroot" == "no" ] ; then + _info "Standalone mode server" + _startserver "$keyauthorization" & + serverproc="$!" + sleep 2 + _debug serverproc $serverproc + else + if [ -z "$wellknown_path" ] ; then + wellknown_path="$Le_Webroot/.well-known/acme-challenge" + fi + _debug wellknown_path "$wellknown_path" + + if [ ! -d "$Le_Webroot/.well-known" ] ; then + removelevel='1' + elif [ ! -d "$Le_Webroot/.well-known/acme-challenge" ] ; then + removelevel='2' + else + removelevel='3' + fi + + token="$(echo -e -n "$keyauthorization" | cut -d '.' -f 1)" + _debug "writing token:$token to $wellknown_path/$token" + + mkdir -p "$wellknown_path" + echo -n "$keyauthorization" > "$wellknown_path/$token" + + webroot_owner=$(stat -c '%U:%G' $Le_Webroot) + _debug "Changing owner/group of .well-known to $webroot_owner" + chown -R $webroot_owner "$Le_Webroot/.well-known" + + fi + fi + + _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" + + if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then + _err "$d:Challenge error: $resource" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearup + return 1 + fi + + while [ "1" ] ; do + _debug "sleep 5 secs to verify" + sleep 5 + _debug "checking" + + if ! _get $uri ; then + _err "$d:Verify error:$resource" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearup + return 1 + fi + + status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | tr -d '"') + if [ "$status" == "valid" ] ; then + _info "Success" + _stopserver $serverproc + serverproc="" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + break; + fi + + if [ "$status" == "invalid" ] ; then + error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4) + _err "$d:Verify error:$error" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearup + return 1; + fi + + if [ "$status" == "pending" ] ; then + _info "Pending" + else + _err "$d:Verify error:$response" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearup + return 1 + fi + + done + + done + + _clearup + _info "Verify finished, start to sign." + der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _b64)" + _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" + + + Le_LinkCert="$(grep -i -o '^Location.*$' $CURL_HEADER | tr -d "\r\n" | cut -d " " -f 2)" + _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" + + if [ "$Le_LinkCert" ] ; then + echo -----BEGIN CERTIFICATE----- > "$CERT_PATH" + curl --silent "$Le_LinkCert" | openssl base64 -e >> "$CERT_PATH" + echo -----END CERTIFICATE----- >> "$CERT_PATH" + _info "Cert success." + cat "$CERT_PATH" + + _info "Your cert is in $CERT_PATH" + fi + + + if [ -z "$Le_LinkCert" ] ; then + response="$(echo $response | openssl base64 -d -A)" + _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" + return 1 + fi + + _setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\"" + + Le_LinkIssuer=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) + _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" + + if [ "$Le_LinkIssuer" ] ; then + echo -----BEGIN CERTIFICATE----- > "$CA_CERT_PATH" + curl --silent "$Le_LinkIssuer" | openssl base64 -e >> "$CA_CERT_PATH" + echo -----END CERTIFICATE----- >> "$CA_CERT_PATH" + _info "The intermediate CA cert is in $CA_CERT_PATH" + fi + + Le_CertCreateTime=$(date -u "+%s") + _setopt "$DOMAIN_CONF" "Le_CertCreateTime" "=" "$Le_CertCreateTime" + + Le_CertCreateTimeStr=$(date -u ) + _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\"" + + if [ ! "$Le_RenewalDays" ] ; then + Le_RenewalDays=80 + fi + + _setopt "$DOMAIN_CONF" "Le_RenewalDays" "=" "$Le_RenewalDays" + + let "Le_NextRenewTime=Le_CertCreateTime+Le_RenewalDays*24*60*60" + _setopt "$DOMAIN_CONF" "Le_NextRenewTime" "=" "$Le_NextRenewTime" + + Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) + _setopt "$DOMAIN_CONF" "Le_NextRenewTimeStr" "=" "\"$Le_NextRenewTimeStr\"" + + + installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" + +} + +renew() { + Le_Domain="$1" + if [ -z "$Le_Domain" ] ; then + _err "Usage: $0 domain.com" + return 1 + fi + + _initpath $Le_Domain + + if [ ! -f "$DOMAIN_CONF" ] ; then + _info "$Le_Domain is not a issued domain, skip." + return 0; + fi + + source "$DOMAIN_CONF" + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then + _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" + return 2 + fi + + IS_RENEW="1" + issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" + local res=$? + IS_RENEW="" + + return $res +} + +renewAll() { + _initpath + _info "renewAll" + + for d in $(ls -F $LE_WORKING_DIR | grep [^.].*[.].*/$ ) ; do + d=$(echo $d | cut -d '/' -f 1) + _info "renew $d" + + Le_LinkCert="" + Le_Domain="" + Le_Alt="" + Le_Webroot="" + Le_Keylength="" + Le_LinkIssuer="" + + Le_CertCreateTime="" + Le_CertCreateTimeStr="" + Le_RenewalDays="" + Le_NextRenewTime="" + Le_NextRenewTimeStr="" + + Le_RealCertPath="" + Le_RealKeyPath="" + + Le_RealCACertPath="" + + Le_ReloadCmd="" + + DOMAIN_PATH="" + DOMAIN_CONF="" + DOMAIN_SSL_CONF="" + CSR_PATH="" + CERT_KEY_PATH="" + CERT_PATH="" + CA_CERT_PATH="" + ACCOUNT_KEY_PATH="" + + wellknown_path="" + + renew "$d" + done + +} + +installcert() { + Le_Domain="$1" + if [ -z "$Le_Domain" ] ; then + _err "Usage: $0 domain.com [cert-file-path]|no [key-file-path]|no [ca-cert-file-path]|no [reloadCmd]|no" + return 1 + fi + + Le_RealCertPath="$2" + Le_RealKeyPath="$3" + Le_RealCACertPath="$4" + Le_ReloadCmd="$5" + + _initpath $Le_Domain + + _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" + _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" + + if [ "$Le_RealCertPath" ] ; then + if [ -f "$Le_RealCertPath" ] ; then + cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak + fi + cat "$CERT_PATH" > "$Le_RealCertPath" + fi + + if [ "$Le_RealCACertPath" ] ; then + if [ -f "$Le_RealCACertPath" ] ; then + cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak + fi + if [ "$Le_RealCACertPath" == "$Le_RealCertPath" ] ; then + echo "" >> "$Le_RealCACertPath" + cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" + else + cat "$CA_CERT_PATH" > "$Le_RealCACertPath" + fi + fi + + + if [ "$Le_RealKeyPath" ] ; then + if [ -f "$Le_RealKeyPath" ] ; then + cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak + fi + cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" + fi + + if [ "$Le_ReloadCmd" ] ; then + _info "Run Le_ReloadCmd: $Le_ReloadCmd" + (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") + fi + +} + +installcronjob() { + _initpath + _info "Installing cron job" + if ! crontab -l | grep 'le.sh cron' ; then + if [ -f "$LE_WORKING_DIR/le.sh" ] ; then + lesh="\"$LE_WORKING_DIR\"/le.sh" + else + _err "Can not install cronjob, le.sh not found." + return 1 + fi + crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab - + fi + return 0 +} + +uninstallcronjob() { + _info "Removing cron job" + cr="$(crontab -l | grep 'le.sh cron')" + if [ "$cr" ] ; then + crontab -l | sed "/le.sh cron/d" | crontab - + LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 6 | cut -d '=' -f 2 | tr -d '"')" + _info LE_WORKING_DIR "$LE_WORKING_DIR" + fi + _initpath + +} + + +# Detect profile file if not specified as environment variable +_detect_profile() { + if [ -n "$PROFILE" -a -f "$PROFILE" ]; then + echo "$PROFILE" + return + fi + + local DETECTED_PROFILE + DETECTED_PROFILE='' + local SHELLTYPE + SHELLTYPE="$(basename "/$SHELL")" + + if [ "$SHELLTYPE" = "bash" ]; then + if [ -f "$HOME/.bashrc" ]; then + DETECTED_PROFILE="$HOME/.bashrc" + elif [ -f "$HOME/.bash_profile" ]; then + DETECTED_PROFILE="$HOME/.bash_profile" + fi + elif [ "$SHELLTYPE" = "zsh" ]; then + DETECTED_PROFILE="$HOME/.zshrc" + fi + + if [ -z "$DETECTED_PROFILE" ]; then + if [ -f "$HOME/.profile" ]; then + DETECTED_PROFILE="$HOME/.profile" + elif [ -f "$HOME/.bashrc" ]; then + DETECTED_PROFILE="$HOME/.bashrc" + elif [ -f "$HOME/.bash_profile" ]; then + DETECTED_PROFILE="$HOME/.bash_profile" + elif [ -f "$HOME/.zshrc" ]; then + DETECTED_PROFILE="$HOME/.zshrc" + fi + fi + + if [ ! -z "$DETECTED_PROFILE" ]; then + echo "$DETECTED_PROFILE" + fi +} + +_initconf() { + _initpath + if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then + echo "#Account configurations: +#Here are the supported macros, uncomment them to make them take effect. +#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. + +#STAGE=1 # Use the staging api +#FORCE=1 # Force to issue cert +#DEBUG=1 # Debug mode + +#dns api +####################### +#Cloudflare: +#api key +#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +#account email +#CF_Email="xxxx@sss.com" + +####################### +#Dnspod.cn: +#api key id +#DP_Id="1234" +#api key +#DP_Key="sADDsdasdgdsf" + +####################### +#Cloudxns.com: +#CX_Key="1234" +# +#CX_Secret="sADDsdasdgdsf" + + " > $ACCOUNT_CONF_PATH + fi +} + +install() { + _initpath + + #check if there is sudo installed, AND if the current user is a sudoer. + if command -v sudo > /dev/null ; then + if [ "$(sudo -n uptime 2>&1|grep "load"|wc -l)" != "0" ] ; then + SUDO=sudo + fi + fi + + if command -v yum > /dev/null ; then + YUM="1" + INSTALL="$SUDO yum install -y " + elif command -v apt-get > /dev/null ; then + INSTALL="$SUDO apt-get install -y " + fi + + if ! command -v "curl" > /dev/null ; then + _err "Please install curl first." + _err "$INSTALL curl" + return 1 + fi + + if ! command -v "crontab" > /dev/null ; then + _err "Please install crontab first." + if [ "$YUM" ] ; then + _err "$INSTALL crontabs" + else + _err "$INSTALL crontab" + fi + return 1 + fi + + if ! command -v "openssl" > /dev/null ; then + _err "Please install openssl first." + _err "$INSTALL openssl" + return 1 + fi + + _info "Installing to $LE_WORKING_DIR" + + _info "Installed to $LE_WORKING_DIR/le.sh" + cp le.sh $LE_WORKING_DIR/ + chmod +x $LE_WORKING_DIR/le.sh + + _profile="$(_detect_profile)" + if [ "$_profile" ] ; then + _debug "Found profile: $_profile" + + echo "LE_WORKING_DIR=$LE_WORKING_DIR +alias le=\"$LE_WORKING_DIR/le.sh\" +alias le.sh=\"$LE_WORKING_DIR/le.sh\" + " > "$LE_WORKING_DIR/le.env" + + _setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\"" + _info "OK, Close and reopen your terminal to start using le" + else + _info "No profile is found, you will need to go into $LE_WORKING_DIR to use le.sh" + fi + + mkdir -p $LE_WORKING_DIR/dnsapi + cp dnsapi/* $LE_WORKING_DIR/dnsapi/ + + #to keep compatible mv the .acc file to .key file + if [ -f "$LE_WORKING_DIR/account.acc" ] ; then + mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key" + fi + + installcronjob + + if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then + _initconf + fi + _info OK +} + +uninstall() { + uninstallcronjob + _initpath + + _profile="$(_detect_profile)" + if [ "$_profile" ] ; then + sed -i /le.env/d "$_profile" + fi + + rm -f $LE_WORKING_DIR/le.sh + _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." + +} + +cron() { + renewAll +} + +version() { + _info "$PROJECT" + _info "v$VER" +} + +showhelp() { + version + echo "Usage: le.sh [command] ...[args].... +Avalible commands: + +install: + Install le.sh to your system. +issue: + Issue a cert. +installcert: + Install the issued cert to apache/nginx or any other server. +renew: + Renew a cert. +renewAll: + Renew all the certs. +uninstall: + Uninstall le.sh, and uninstall the cron job. +version: + Show version info. +installcronjob: + Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. +uninstallcronjob: + Uninstall the cron job. The 'uninstall' command can do this automatically. +createAccountKey: + Create an account private key, professional use. +createDomainKey: + Create an domain private key, professional use. +createCSR: + Create CSR , professional use. + " +} + + +if [ -z "$1" ] ; then + showhelp +else + "$@" +fi From 48a8e6e64b077be004dc693823cd21cfcc12edc2 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 8 Mar 2016 20:40:52 +0800 Subject: [PATCH 0007/1348] minor, just more checks --- le.sh | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/le.sh b/le.sh index 1b3768d1..12defd60 100755 --- a/le.sh +++ b/le.sh @@ -296,6 +296,7 @@ _setopt() { else _debug APP + echo "" >> "$__conf" echo "$__opt$__sep$__val$__end" >> "$__conf" fi _debug "$(grep -H -n "^$__opt$__sep" $__conf)" @@ -376,7 +377,10 @@ _initpath() { fi domain="$1" - mkdir -p "$LE_WORKING_DIR" + if ! mkdir -p "$LE_WORKING_DIR" ; then + _err "Can not craete working dir: $LE_WORKING_DIR" + return 1 + fi if [ -z "$ACCOUNT_KEY_PATH" ] ; then ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" @@ -1071,7 +1075,12 @@ installcronjob() { fi crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab - fi - return 0 + if [ "$?" != "0" ] ; then + _err "Install cron job failed. You need to manually renew your certs." + _err "Or you can add cronjob by yourself:" + _err "LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null" + return 1 + fi } uninstallcronjob() { @@ -1163,7 +1172,10 @@ _initconf() { } install() { - _initpath + if ! _initpath ; then + _err "Install failed." + return 1 + fi #check if there is sudo installed, AND if the current user is a sudoer. if command -v sudo > /dev/null ; then @@ -1203,9 +1215,14 @@ install() { _info "Installing to $LE_WORKING_DIR" - _info "Installed to $LE_WORKING_DIR/le.sh" - cp le.sh $LE_WORKING_DIR/ - chmod +x $LE_WORKING_DIR/le.sh + cp le.sh "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/le.sh" + + if [ "$?" != "0" ] ; then + _err "Install failed, can not copy le.sh" + return 1 + fi + + _info "Installed to $LE_WORKING_DIR/le.sh" _profile="$(_detect_profile)" if [ "$_profile" ] ; then From 4c3b360886844440bde27e6b25e6aa27ac581ba6 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 8 Mar 2016 20:44:12 +0800 Subject: [PATCH 0008/1348] minor --- le.sh | 2636 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 1318 insertions(+), 1318 deletions(-) diff --git a/le.sh b/le.sh index 12defd60..5dca6265 100755 --- a/le.sh +++ b/le.sh @@ -1,1318 +1,1318 @@ -#!/usr/bin/env bash -VER=1.1.8 -PROJECT="https://github.com/Neilpang/le" - -DEFAULT_CA="https://acme-v01.api.letsencrypt.org" -DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" - -STAGE_CA="https://acme-staging.api.letsencrypt.org" - -VTYPE_HTTP="http-01" -VTYPE_DNS="dns-01" - -if [ -z "$AGREEMENT" ] ; then - AGREEMENT="$DEFAULT_AGREEMENT" -fi - -_debug() { - - if [ -z "$DEBUG" ] ; then - return - fi - - if [ -z "$2" ] ; then - echo $1 - else - echo "$1"="$2" - fi -} - -_info() { - if [ -z "$2" ] ; then - echo "$1" - else - echo "$1"="$2" - fi -} - -_err() { - if [ -z "$2" ] ; then - echo "$1" >&2 - else - echo "$1"="$2" >&2 - fi - return 1 -} - -_h2b() { - hex=$(cat) - i=1 - j=2 - while [ '1' ] ; do - h=$(printf $hex | cut -c $i-$j) - if [ -z "$h" ] ; then - break; - fi - printf "\x$h" - let "i+=2" - let "j+=2" - done -} - -_base64() { - openssl base64 -e | tr -d '\n' -} - -#domain [2048] -createAccountKey() { - _info "Creating account key" - if [ -z "$1" ] ; then - echo Usage: createAccountKey account-domain [2048] - return - fi - - account=$1 - length=$2 - - if [[ "$length" == "ec-"* ]] ; then - length=2048 - fi - - if [ -z "$2" ] ; then - _info "Use default length 2048" - length=2048 - fi - _initpath - - if [ -f "$ACCOUNT_KEY_PATH" ] ; then - _info "Account key exists, skip" - return - else - #generate account key - openssl genrsa $length > "$ACCOUNT_KEY_PATH" - fi - -} - -#domain length -createDomainKey() { - _info "Creating domain key" - if [ -z "$1" ] ; then - echo Usage: createDomainKey domain [2048] - return - fi - - domain=$1 - length=$2 - isec="" - if [[ "$length" == "ec-"* ]] ; then - isec="1" - length=$(printf $length | cut -d '-' -f 2-100) - eccname="$length" - fi - - if [ -z "$length" ] ; then - if [ "$isec" ] ; then - length=256 - else - length=2048 - fi - fi - _info "Use length $length" - - if [ "$isec" ] ; then - if [ "$length" == "256" ] ; then - eccname="prime256v1" - fi - if [ "$length" == "384" ] ; then - eccname="secp384r1" - fi - if [ "$length" == "521" ] ; then - eccname="secp521r1" - fi - _info "Using ec name: $eccname" - fi - - _initpath $domain - - if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then - #generate account key - if [ "$isec" ] ; then - openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH" - else - openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH" - fi - else - if [ "$IS_RENEW" ] ; then - _info "Domain key exists, skip" - return 0 - else - _err "Domain key exists, do you want to overwrite the key?" - _err "Set FORCE=1, and try again." - return 1 - fi - fi - -} - -# domain domainlist -createCSR() { - _info "Creating csr" - if [ -z "$1" ] ; then - echo Usage: $0 domain [domainlist] - return - fi - domain=$1 - _initpath $domain - - domainlist=$2 - - if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && ! [ "$FORCE" ]; then - _info "CSR exists, skip" - return - fi - - if [ -z "$domainlist" ] ; then - #single domain - _info "Single domain" $domain - openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" > "$CSR_PATH" - else - alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" - #multi - _info "Multi domain" "$alt" - printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n[SAN]\nsubjectAltName=$alt" > "$DOMAIN_SSL_CONF" - openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -reqexts SAN -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" - fi - -} - -_b64() { - __n=$(cat) - echo $__n | tr '/+' '_-' | tr -d '= ' -} - -_time2str() { - #BSD - if date -u -d@$1 2>/dev/null ; then - return - fi - - #Linux - if date -u -r $1 2>/dev/null ; then - return - fi - -} - -_send_signed_request() { - url=$1 - payload=$2 - needbase64=$3 - - _debug url $url - _debug payload "$payload" - - CURL_HEADER="$LE_WORKING_DIR/curl.header" - dp="$LE_WORKING_DIR/curl.dump" - CURL="curl --silent --dump-header $CURL_HEADER " - if [ "$DEBUG" ] ; then - CURL="$CURL --trace-ascii $dp " - fi - payload64=$(echo -n $payload | _base64 | _b64) - _debug payload64 $payload64 - - nonceurl="$API/directory" - nonce="$($CURL -I $nonceurl | grep -o "^Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)" - - _debug nonce "$nonce" - - protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" - _debug protected "$protected" - - protected64="$(printf "$protected" | _base64 | _b64)" - _debug protected64 "$protected64" - - sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY_PATH | _base64 | _b64) - _debug sig "$sig" - - body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - _debug body "$body" - - if [ "$needbase64" ] ; then - response="$($CURL -X POST --data "$body" $url | _base64)" - else - response="$($CURL -X POST --data "$body" $url)" - fi - - responseHeaders="$(cat $CURL_HEADER)" - - _debug responseHeaders "$responseHeaders" - _debug response "$response" - code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )" - _debug code $code - -} - -_get() { - url="$1" - _debug url $url - response="$(curl --silent $url)" - ret=$? - _debug response "$response" - code="$(echo $response | grep -o '"status":[0-9]\+' | cut -d : -f 2)" - _debug code $code - return $ret -} - -#setopt "file" "opt" "=" "value" [";"] -_setopt() { - __conf="$1" - __opt="$2" - __sep="$3" - __val="$4" - __end="$5" - if [ -z "$__opt" ] ; then - echo usage: _setopt '"file" "opt" "=" "value" [";"]' - return - fi - if [ ! -f "$__conf" ] ; then - touch "$__conf" - fi - - if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then - _debug OK - if [[ "$__val" == *"&"* ]] ; then - __val="$(echo $__val | sed 's/&/\\&/g')" - fi - text="$(cat $__conf)" - printf "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" - - elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then - if [[ "$__val" == *"&"* ]] ; then - __val="$(echo $__val | sed 's/&/\\&/g')" - fi - text="$(cat $__conf)" - printf "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" - - else - _debug APP - echo "" >> "$__conf" - echo "$__opt$__sep$__val$__end" >> "$__conf" - fi - _debug "$(grep -H -n "^$__opt$__sep" $__conf)" -} - -#_savedomainconf key value -#save to domain.conf -_savedomainconf() { - key="$1" - value="$2" - if [ "$DOMAIN_CONF" ] ; then - _setopt $DOMAIN_CONF "$key" "=" "$value" - else - _err "DOMAIN_CONF is empty, can not save $key=$value" - fi -} - -#_saveaccountconf key value -_saveaccountconf() { - key="$1" - value="$2" - if [ "$ACCOUNT_CONF_PATH" ] ; then - _setopt $ACCOUNT_CONF_PATH "$key" "=" "$value" - else - _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" - fi -} - -_startserver() { - content="$1" - _NC="nc -q 1" - if nc -h 2>&1 | grep "nmap.org/ncat" >/dev/null ; then - _NC="nc" - fi -# while true ; do - if [ "$DEBUG" ] ; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort -vv - else - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort > /dev/null - fi -# done -} - -_stopserver() { - pid="$1" - -} - -_initpath() { - - if [ -z "$LE_WORKING_DIR" ]; then - LE_WORKING_DIR=$HOME/.le - fi - - if [ -z "$ACCOUNT_CONF_PATH" ] ; then - ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" - fi - - if [ -f "$ACCOUNT_CONF_PATH" ] ; then - source "$ACCOUNT_CONF_PATH" - fi - - if [ -z "$API" ] ; then - if [ -z "$STAGE" ] ; then - API="$DEFAULT_CA" - else - API="$STAGE_CA" - _info "Using stage api:$API" - fi - fi - - if [ -z "$ACME_DIR" ] ; then - ACME_DIR="/home/.acme" - fi - - if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then - APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/" - fi - - domain="$1" - if ! mkdir -p "$LE_WORKING_DIR" ; then - _err "Can not craete working dir: $LE_WORKING_DIR" - return 1 - fi - - if [ -z "$ACCOUNT_KEY_PATH" ] ; then - ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" - fi - - if [ -z "$domain" ] ; then - return 0 - fi - - domainhome="$LE_WORKING_DIR/$domain" - mkdir -p "$domainhome" - - if [ -z "$DOMAIN_PATH" ] ; then - DOMAIN_PATH="$domainhome" - fi - if [ -z "$DOMAIN_CONF" ] ; then - DOMAIN_CONF="$domainhome/$Le_Domain.conf" - fi - - if [ -z "$DOMAIN_SSL_CONF" ] ; then - DOMAIN_SSL_CONF="$domainhome/$Le_Domain.ssl.conf" - fi - - if [ -z "$CSR_PATH" ] ; then - CSR_PATH="$domainhome/$domain.csr" - fi - if [ -z "$CERT_KEY_PATH" ] ; then - CERT_KEY_PATH="$domainhome/$domain.key" - fi - if [ -z "$CERT_PATH" ] ; then - CERT_PATH="$domainhome/$domain.cer" - fi - if [ -z "$CA_CERT_PATH" ] ; then - CA_CERT_PATH="$domainhome/ca.cer" - fi - -} - - -_apachePath() { - httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" - httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" - httpdconf="$httpdroot/$httpdconfname" - if [ ! -f $httpdconf ] ; then - _err "Apache Config file not found" $httpdconf - return 1 - fi - return 0 -} - -_restoreApache() { - if [ -z "$usingApache" ] ; then - return 0 - fi - _initpath - if ! _apachePath ; then - return 1 - fi - - if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then - _debug "No config file to restore." - return 0 - fi - - cp -p "$APACHE_CONF_BACKUP_DIR/$httpdconfname" "$httpdconf" - if ! apachectl -t ; then - _err "Sorry, restore apache config error, please contact me." - return 1; - fi - rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" - return 0 -} - -_setApache() { - _initpath - if ! _apachePath ; then - return 1 - fi - - #backup the conf - _debug "Backup apache config file" $httpdconf - cp -p $httpdconf $APACHE_CONF_BACKUP_DIR/ - _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" - _info "In case there is an error that can not be restored automatically, you may try restore it yourself." - _info "The backup file will be deleted on sucess, just forget it." - - #add alias - echo " -Alias /.well-known/acme-challenge $ACME_DIR - - -Require all granted - - " >> $httpdconf - - if ! apachectl -t ; then - _err "Sorry, apache config error, please contact me." - _restoreApache - return 1; - fi - - if [ ! -d "$ACME_DIR" ] ; then - mkdir -p "$ACME_DIR" - chmod 755 "$ACME_DIR" - fi - - if ! apachectl graceful ; then - _err "Sorry, apachectl graceful error, please contact me." - _restoreApache - return 1; - fi - usingApache="1" - return 0 -} - -_clearup () { - _stopserver $serverproc - serverproc="" - _restoreApache -} - -# webroot removelevel tokenfile -_clearupwebbroot() { - __webroot="$1" - if [ -z "$__webroot" ] ; then - _debug "no webroot specified, skip" - return 0 - fi - - if [ "$2" == '1' ] ; then - _debug "remove $__webroot/.well-known" - rm -rf "$__webroot/.well-known" - elif [ "$2" == '2' ] ; then - _debug "remove $__webroot/.well-known/acme-challenge" - rm -rf "$__webroot/.well-known/acme-challenge" - elif [ "$2" == '3' ] ; then - _debug "remove $__webroot/.well-known/acme-challenge/$3" - rm -rf "$__webroot/.well-known/acme-challenge/$3" - else - _info "Skip for removelevel:$2" - fi - - return 0 - -} - -issue() { - if [ -z "$2" ] ; then - _err "Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no" - return 1 - fi - Le_Webroot="$1" - Le_Domain="$2" - Le_Alt="$3" - Le_Keylength="$4" - Le_RealCertPath="$5" - Le_RealKeyPath="$6" - Le_RealCACertPath="$7" - Le_ReloadCmd="$8" - - - _initpath $Le_Domain - - if [ -f "$DOMAIN_CONF" ] ; then - Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2) - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then - _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" - return 2 - fi - fi - - if [ "$Le_Alt" == "no" ] ; then - Le_Alt="" - fi - if [ "$Le_Keylength" == "no" ] ; then - Le_Keylength="" - fi - if [ "$Le_RealCertPath" == "no" ] ; then - Le_RealCertPath="" - fi - if [ "$Le_RealKeyPath" == "no" ] ; then - Le_RealKeyPath="" - fi - if [ "$Le_RealCACertPath" == "no" ] ; then - Le_RealCACertPath="" - fi - if [ "$Le_ReloadCmd" == "no" ] ; then - Le_ReloadCmd="" - fi - - _setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain" - _setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt" - _setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot" - _setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength" - _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" - _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" - - if [ "$Le_Webroot" == "no" ] ; then - _info "Standalone mode." - if ! command -v "nc" > /dev/null ; then - _err "Please install netcat(nc) tools first." - return 1 - fi - - if [ -z "$Le_HTTPPort" ] ; then - Le_HTTPPort=80 - fi - _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" - - netprc="$(ss -ntpl | grep :$Le_HTTPPort" ")" - if [ "$netprc" ] ; then - _err "$netprc" - _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" - _err "Please stop it first" - return 1 - fi - fi - - if [ "$Le_Webroot" == "apache" ] ; then - if ! _setApache ; then - _err "set up apache error. Report error to me." - return 1 - fi - wellknown_path="$ACME_DIR" - else - usingApache="" - fi - - createAccountKey $Le_Domain $Le_Keylength - - if ! createDomainKey $Le_Domain $Le_Keylength ; then - _err "Create domain key error." - return 1 - fi - - if ! createCSR $Le_Domain $Le_Alt ; then - _err "Create CSR error." - return 1 - fi - - pub_exp=$(openssl rsa -in $ACCOUNT_KEY_PATH -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) - if [ "${#pub_exp}" == "5" ] ; then - pub_exp=0$pub_exp - fi - _debug pub_exp "$pub_exp" - - e=$(echo $pub_exp | _h2b | _base64) - _debug e "$e" - - modulus=$(openssl rsa -in $ACCOUNT_KEY_PATH -modulus -noout | cut -d '=' -f 2 ) - n=$(echo $modulus| _h2b | _base64 | _b64 ) - - jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' - - HEADER='{"alg": "RS256", "jwk": '$jwk'}' - HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' - _debug HEADER "$HEADER" - - accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) - thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _b64) - - - _info "Registering account" - regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ] ; then - regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' - fi - _send_signed_request "$API/acme/new-reg" "$regjson" - - if [ "$code" == "" ] || [ "$code" == '201' ] ; then - _info "Registered" - echo $response > $LE_WORKING_DIR/account.json - elif [ "$code" == '409' ] ; then - _info "Already registered" - else - _err "Register account Error." - _clearup - return 1 - fi - - vtype="$VTYPE_HTTP" - if [[ "$Le_Webroot" == "dns"* ]] ; then - vtype="$VTYPE_DNS" - fi - - vlist="$Le_Vlist" - # verify each domain - _info "Verify each domain" - sep='#' - if [ -z "$vlist" ] ; then - alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) - for d in $alldomains - do - _info "Getting token for domain" $d - _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" - if [ ! -z "$code" ] && [ ! "$code" == '201' ] ; then - _err "new-authz error: $response" - _clearup - return 1 - fi - - entry="$(printf $response | egrep -o '{[^{]*"type":"'$vtype'"[^}]*')" - _debug entry "$entry" - - token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" - _debug token $token - - uri="$(printf "$entry" | egrep -o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" - _debug uri $uri - - keyauthorization="$token.$thumbprint" - _debug keyauthorization "$keyauthorization" - - dvlist="$d$sep$keyauthorization$sep$uri" - _debug dvlist "$dvlist" - - vlist="$vlist$dvlist," - - done - - #add entry - dnsadded="" - ventries=$(echo "$vlist" | tr ',' ' ' ) - for ventry in $ventries - do - d=$(echo $ventry | cut -d $sep -f 1) - keyauthorization=$(echo $ventry | cut -d $sep -f 2) - - if [ "$vtype" == "$VTYPE_DNS" ] ; then - dnsadded='0' - txtdomain="_acme-challenge.$d" - _debug txtdomain "$txtdomain" - txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _b64)" - _debug txt "$txt" - #dns - #1. check use api - d_api="" - if [ -f "$LE_WORKING_DIR/$d/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/$d/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/$d/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/$d/$Le_Webroot.sh" - elif [ -f "$LE_WORKING_DIR/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/$Le_Webroot.sh" - elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" - fi - _debug d_api "$d_api" - - if [ "$d_api" ]; then - _info "Found domain api file: $d_api" - else - _err "Add the following TXT record:" - _err "Domain: $txtdomain" - _err "TXT value: $txt" - _err "Please be aware that you prepend _acme-challenge. before your domain" - _err "so the resulting subdomain will be: $txtdomain" - continue - fi - - if ! source $d_api ; then - _err "Load file $d_api error. Please check your api file and try again." - return 1 - fi - - addcommand="$Le_Webroot-add" - if ! command -v $addcommand ; then - _err "It seems that your api file is not correct, it must have a function named: $Le_Webroot" - return 1 - fi - - if ! $addcommand $txtdomain $txt ; then - _err "Error add txt for domain:$txtdomain" - return 1 - fi - dnsadded='1' - fi - done - - if [ "$dnsadded" == '0' ] ; then - _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\"" - _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." - _err "Please add the TXT records to the domains, and retry again." - return 1 - fi - - fi - - if [ "$dnsadded" == '1' ] ; then - _info "Sleep 60 seconds for the txt records to take effect" - sleep 60 - fi - - _debug "ok, let's start to verify" - ventries=$(echo "$vlist" | tr ',' ' ' ) - for ventry in $ventries - do - d=$(echo $ventry | cut -d $sep -f 1) - keyauthorization=$(echo $ventry | cut -d $sep -f 2) - uri=$(echo $ventry | cut -d $sep -f 3) - _info "Verifying:$d" - _debug "d" "$d" - _debug "keyauthorization" "$keyauthorization" - _debug "uri" "$uri" - removelevel="" - token="" - if [ "$vtype" == "$VTYPE_HTTP" ] ; then - if [ "$Le_Webroot" == "no" ] ; then - _info "Standalone mode server" - _startserver "$keyauthorization" & - serverproc="$!" - sleep 2 - _debug serverproc $serverproc - else - if [ -z "$wellknown_path" ] ; then - wellknown_path="$Le_Webroot/.well-known/acme-challenge" - fi - _debug wellknown_path "$wellknown_path" - - if [ ! -d "$Le_Webroot/.well-known" ] ; then - removelevel='1' - elif [ ! -d "$Le_Webroot/.well-known/acme-challenge" ] ; then - removelevel='2' - else - removelevel='3' - fi - - token="$(echo -e -n "$keyauthorization" | cut -d '.' -f 1)" - _debug "writing token:$token to $wellknown_path/$token" - - mkdir -p "$wellknown_path" - echo -n "$keyauthorization" > "$wellknown_path/$token" - - webroot_owner=$(stat -c '%U:%G' $Le_Webroot) - _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R $webroot_owner "$Le_Webroot/.well-known" - - fi - fi - - _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" - - if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then - _err "$d:Challenge error: $resource" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - _clearup - return 1 - fi - - while [ "1" ] ; do - _debug "sleep 5 secs to verify" - sleep 5 - _debug "checking" - - if ! _get $uri ; then - _err "$d:Verify error:$resource" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - _clearup - return 1 - fi - - status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | tr -d '"') - if [ "$status" == "valid" ] ; then - _info "Success" - _stopserver $serverproc - serverproc="" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - break; - fi - - if [ "$status" == "invalid" ] ; then - error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4) - _err "$d:Verify error:$error" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - _clearup - return 1; - fi - - if [ "$status" == "pending" ] ; then - _info "Pending" - else - _err "$d:Verify error:$response" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" - _clearup - return 1 - fi - - done - - done - - _clearup - _info "Verify finished, start to sign." - der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _b64)" - _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" - - - Le_LinkCert="$(grep -i -o '^Location.*$' $CURL_HEADER | tr -d "\r\n" | cut -d " " -f 2)" - _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" - - if [ "$Le_LinkCert" ] ; then - echo -----BEGIN CERTIFICATE----- > "$CERT_PATH" - curl --silent "$Le_LinkCert" | openssl base64 -e >> "$CERT_PATH" - echo -----END CERTIFICATE----- >> "$CERT_PATH" - _info "Cert success." - cat "$CERT_PATH" - - _info "Your cert is in $CERT_PATH" - fi - - - if [ -z "$Le_LinkCert" ] ; then - response="$(echo $response | openssl base64 -d -A)" - _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" - return 1 - fi - - _setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\"" - - Le_LinkIssuer=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) - _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" - - if [ "$Le_LinkIssuer" ] ; then - echo -----BEGIN CERTIFICATE----- > "$CA_CERT_PATH" - curl --silent "$Le_LinkIssuer" | openssl base64 -e >> "$CA_CERT_PATH" - echo -----END CERTIFICATE----- >> "$CA_CERT_PATH" - _info "The intermediate CA cert is in $CA_CERT_PATH" - fi - - Le_CertCreateTime=$(date -u "+%s") - _setopt "$DOMAIN_CONF" "Le_CertCreateTime" "=" "$Le_CertCreateTime" - - Le_CertCreateTimeStr=$(date -u ) - _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\"" - - if [ ! "$Le_RenewalDays" ] ; then - Le_RenewalDays=80 - fi - - _setopt "$DOMAIN_CONF" "Le_RenewalDays" "=" "$Le_RenewalDays" - - let "Le_NextRenewTime=Le_CertCreateTime+Le_RenewalDays*24*60*60" - _setopt "$DOMAIN_CONF" "Le_NextRenewTime" "=" "$Le_NextRenewTime" - - Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) - _setopt "$DOMAIN_CONF" "Le_NextRenewTimeStr" "=" "\"$Le_NextRenewTimeStr\"" - - - installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" - -} - -renew() { - Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then - _err "Usage: $0 domain.com" - return 1 - fi - - _initpath $Le_Domain - - if [ ! -f "$DOMAIN_CONF" ] ; then - _info "$Le_Domain is not a issued domain, skip." - return 0; - fi - - source "$DOMAIN_CONF" - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then - _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" - return 2 - fi - - IS_RENEW="1" - issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" - local res=$? - IS_RENEW="" - - return $res -} - -renewAll() { - _initpath - _info "renewAll" - - for d in $(ls -F $LE_WORKING_DIR | grep [^.].*[.].*/$ ) ; do - d=$(echo $d | cut -d '/' -f 1) - _info "renew $d" - - Le_LinkCert="" - Le_Domain="" - Le_Alt="" - Le_Webroot="" - Le_Keylength="" - Le_LinkIssuer="" - - Le_CertCreateTime="" - Le_CertCreateTimeStr="" - Le_RenewalDays="" - Le_NextRenewTime="" - Le_NextRenewTimeStr="" - - Le_RealCertPath="" - Le_RealKeyPath="" - - Le_RealCACertPath="" - - Le_ReloadCmd="" - - DOMAIN_PATH="" - DOMAIN_CONF="" - DOMAIN_SSL_CONF="" - CSR_PATH="" - CERT_KEY_PATH="" - CERT_PATH="" - CA_CERT_PATH="" - ACCOUNT_KEY_PATH="" - - wellknown_path="" - - renew "$d" - done - -} - -installcert() { - Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then - _err "Usage: $0 domain.com [cert-file-path]|no [key-file-path]|no [ca-cert-file-path]|no [reloadCmd]|no" - return 1 - fi - - Le_RealCertPath="$2" - Le_RealKeyPath="$3" - Le_RealCACertPath="$4" - Le_ReloadCmd="$5" - - _initpath $Le_Domain - - _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" - _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" - - if [ "$Le_RealCertPath" ] ; then - if [ -f "$Le_RealCertPath" ] ; then - cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak - fi - cat "$CERT_PATH" > "$Le_RealCertPath" - fi - - if [ "$Le_RealCACertPath" ] ; then - if [ -f "$Le_RealCACertPath" ] ; then - cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak - fi - if [ "$Le_RealCACertPath" == "$Le_RealCertPath" ] ; then - echo "" >> "$Le_RealCACertPath" - cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" - else - cat "$CA_CERT_PATH" > "$Le_RealCACertPath" - fi - fi - - - if [ "$Le_RealKeyPath" ] ; then - if [ -f "$Le_RealKeyPath" ] ; then - cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak - fi - cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" - fi - - if [ "$Le_ReloadCmd" ] ; then - _info "Run Le_ReloadCmd: $Le_ReloadCmd" - (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") - fi - -} - -installcronjob() { - _initpath - _info "Installing cron job" - if ! crontab -l | grep 'le.sh cron' ; then - if [ -f "$LE_WORKING_DIR/le.sh" ] ; then - lesh="\"$LE_WORKING_DIR\"/le.sh" - else - _err "Can not install cronjob, le.sh not found." - return 1 - fi - crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab - - fi - if [ "$?" != "0" ] ; then - _err "Install cron job failed. You need to manually renew your certs." - _err "Or you can add cronjob by yourself:" - _err "LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null" - return 1 - fi -} - -uninstallcronjob() { - _info "Removing cron job" - cr="$(crontab -l | grep 'le.sh cron')" - if [ "$cr" ] ; then - crontab -l | sed "/le.sh cron/d" | crontab - - LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 6 | cut -d '=' -f 2 | tr -d '"')" - _info LE_WORKING_DIR "$LE_WORKING_DIR" - fi - _initpath - -} - - -# Detect profile file if not specified as environment variable -_detect_profile() { - if [ -n "$PROFILE" -a -f "$PROFILE" ]; then - echo "$PROFILE" - return - fi - - local DETECTED_PROFILE - DETECTED_PROFILE='' - local SHELLTYPE - SHELLTYPE="$(basename "/$SHELL")" - - if [ "$SHELLTYPE" = "bash" ]; then - if [ -f "$HOME/.bashrc" ]; then - DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then - DETECTED_PROFILE="$HOME/.bash_profile" - fi - elif [ "$SHELLTYPE" = "zsh" ]; then - DETECTED_PROFILE="$HOME/.zshrc" - fi - - if [ -z "$DETECTED_PROFILE" ]; then - if [ -f "$HOME/.profile" ]; then - DETECTED_PROFILE="$HOME/.profile" - elif [ -f "$HOME/.bashrc" ]; then - DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then - DETECTED_PROFILE="$HOME/.bash_profile" - elif [ -f "$HOME/.zshrc" ]; then - DETECTED_PROFILE="$HOME/.zshrc" - fi - fi - - if [ ! -z "$DETECTED_PROFILE" ]; then - echo "$DETECTED_PROFILE" - fi -} - -_initconf() { - _initpath - if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then - echo "#Account configurations: -#Here are the supported macros, uncomment them to make them take effect. -#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. - -#STAGE=1 # Use the staging api -#FORCE=1 # Force to issue cert -#DEBUG=1 # Debug mode - -#dns api -####################### -#Cloudflare: -#api key -#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" -#account email -#CF_Email="xxxx@sss.com" - -####################### -#Dnspod.cn: -#api key id -#DP_Id="1234" -#api key -#DP_Key="sADDsdasdgdsf" - -####################### -#Cloudxns.com: -#CX_Key="1234" -# -#CX_Secret="sADDsdasdgdsf" - - " > $ACCOUNT_CONF_PATH - fi -} - -install() { - if ! _initpath ; then - _err "Install failed." - return 1 - fi - - #check if there is sudo installed, AND if the current user is a sudoer. - if command -v sudo > /dev/null ; then - if [ "$(sudo -n uptime 2>&1|grep "load"|wc -l)" != "0" ] ; then - SUDO=sudo - fi - fi - - if command -v yum > /dev/null ; then - YUM="1" - INSTALL="$SUDO yum install -y " - elif command -v apt-get > /dev/null ; then - INSTALL="$SUDO apt-get install -y " - fi - - if ! command -v "curl" > /dev/null ; then - _err "Please install curl first." - _err "$INSTALL curl" - return 1 - fi - - if ! command -v "crontab" > /dev/null ; then - _err "Please install crontab first." - if [ "$YUM" ] ; then - _err "$INSTALL crontabs" - else - _err "$INSTALL crontab" - fi - return 1 - fi - - if ! command -v "openssl" > /dev/null ; then - _err "Please install openssl first." - _err "$INSTALL openssl" - return 1 - fi - - _info "Installing to $LE_WORKING_DIR" - - cp le.sh "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/le.sh" - - if [ "$?" != "0" ] ; then - _err "Install failed, can not copy le.sh" - return 1 - fi - - _info "Installed to $LE_WORKING_DIR/le.sh" - - _profile="$(_detect_profile)" - if [ "$_profile" ] ; then - _debug "Found profile: $_profile" - - echo "LE_WORKING_DIR=$LE_WORKING_DIR -alias le=\"$LE_WORKING_DIR/le.sh\" -alias le.sh=\"$LE_WORKING_DIR/le.sh\" - " > "$LE_WORKING_DIR/le.env" - - _setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\"" - _info "OK, Close and reopen your terminal to start using le" - else - _info "No profile is found, you will need to go into $LE_WORKING_DIR to use le.sh" - fi - - mkdir -p $LE_WORKING_DIR/dnsapi - cp dnsapi/* $LE_WORKING_DIR/dnsapi/ - - #to keep compatible mv the .acc file to .key file - if [ -f "$LE_WORKING_DIR/account.acc" ] ; then - mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key" - fi - - installcronjob - - if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then - _initconf - fi - _info OK -} - -uninstall() { - uninstallcronjob - _initpath - - _profile="$(_detect_profile)" - if [ "$_profile" ] ; then - sed -i /le.env/d "$_profile" - fi - - rm -f $LE_WORKING_DIR/le.sh - _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." - -} - -cron() { - renewAll -} - -version() { - _info "$PROJECT" - _info "v$VER" -} - -showhelp() { - version - echo "Usage: le.sh [command] ...[args].... -Avalible commands: - -install: - Install le.sh to your system. -issue: - Issue a cert. -installcert: - Install the issued cert to apache/nginx or any other server. -renew: - Renew a cert. -renewAll: - Renew all the certs. -uninstall: - Uninstall le.sh, and uninstall the cron job. -version: - Show version info. -installcronjob: - Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. -uninstallcronjob: - Uninstall the cron job. The 'uninstall' command can do this automatically. -createAccountKey: - Create an account private key, professional use. -createDomainKey: - Create an domain private key, professional use. -createCSR: - Create CSR , professional use. - " -} - - -if [ -z "$1" ] ; then - showhelp -else - "$@" -fi +#!/usr/bin/env bash +VER=1.1.8 +PROJECT="https://github.com/Neilpang/le" + +DEFAULT_CA="https://acme-v01.api.letsencrypt.org" +DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" + +STAGE_CA="https://acme-staging.api.letsencrypt.org" + +VTYPE_HTTP="http-01" +VTYPE_DNS="dns-01" + +if [ -z "$AGREEMENT" ] ; then + AGREEMENT="$DEFAULT_AGREEMENT" +fi + +_debug() { + + if [ -z "$DEBUG" ] ; then + return + fi + + if [ -z "$2" ] ; then + echo $1 + else + echo "$1"="$2" + fi +} + +_info() { + if [ -z "$2" ] ; then + echo "$1" + else + echo "$1"="$2" + fi +} + +_err() { + if [ -z "$2" ] ; then + echo "$1" >&2 + else + echo "$1"="$2" >&2 + fi + return 1 +} + +_h2b() { + hex=$(cat) + i=1 + j=2 + while [ '1' ] ; do + h=$(printf $hex | cut -c $i-$j) + if [ -z "$h" ] ; then + break; + fi + printf "\x$h" + let "i+=2" + let "j+=2" + done +} + +_base64() { + openssl base64 -e | tr -d '\n' +} + +#domain [2048] +createAccountKey() { + _info "Creating account key" + if [ -z "$1" ] ; then + echo Usage: createAccountKey account-domain [2048] + return + fi + + account=$1 + length=$2 + + if [[ "$length" == "ec-"* ]] ; then + length=2048 + fi + + if [ -z "$2" ] ; then + _info "Use default length 2048" + length=2048 + fi + _initpath + + if [ -f "$ACCOUNT_KEY_PATH" ] ; then + _info "Account key exists, skip" + return + else + #generate account key + openssl genrsa $length > "$ACCOUNT_KEY_PATH" + fi + +} + +#domain length +createDomainKey() { + _info "Creating domain key" + if [ -z "$1" ] ; then + echo Usage: createDomainKey domain [2048] + return + fi + + domain=$1 + length=$2 + isec="" + if [[ "$length" == "ec-"* ]] ; then + isec="1" + length=$(printf $length | cut -d '-' -f 2-100) + eccname="$length" + fi + + if [ -z "$length" ] ; then + if [ "$isec" ] ; then + length=256 + else + length=2048 + fi + fi + _info "Use length $length" + + if [ "$isec" ] ; then + if [ "$length" == "256" ] ; then + eccname="prime256v1" + fi + if [ "$length" == "384" ] ; then + eccname="secp384r1" + fi + if [ "$length" == "521" ] ; then + eccname="secp521r1" + fi + _info "Using ec name: $eccname" + fi + + _initpath $domain + + if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then + #generate account key + if [ "$isec" ] ; then + openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH" + else + openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH" + fi + else + if [ "$IS_RENEW" ] ; then + _info "Domain key exists, skip" + return 0 + else + _err "Domain key exists, do you want to overwrite the key?" + _err "Set FORCE=1, and try again." + return 1 + fi + fi + +} + +# domain domainlist +createCSR() { + _info "Creating csr" + if [ -z "$1" ] ; then + echo Usage: $0 domain [domainlist] + return + fi + domain=$1 + _initpath $domain + + domainlist=$2 + + if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && ! [ "$FORCE" ]; then + _info "CSR exists, skip" + return + fi + + if [ -z "$domainlist" ] ; then + #single domain + _info "Single domain" $domain + openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" > "$CSR_PATH" + else + alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" + #multi + _info "Multi domain" "$alt" + printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n[SAN]\nsubjectAltName=$alt" > "$DOMAIN_SSL_CONF" + openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -reqexts SAN -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" + fi + +} + +_b64() { + __n=$(cat) + echo $__n | tr '/+' '_-' | tr -d '= ' +} + +_time2str() { + #BSD + if date -u -d@$1 2>/dev/null ; then + return + fi + + #Linux + if date -u -r $1 2>/dev/null ; then + return + fi + +} + +_send_signed_request() { + url=$1 + payload=$2 + needbase64=$3 + + _debug url $url + _debug payload "$payload" + + CURL_HEADER="$LE_WORKING_DIR/curl.header" + dp="$LE_WORKING_DIR/curl.dump" + CURL="curl --silent --dump-header $CURL_HEADER " + if [ "$DEBUG" ] ; then + CURL="$CURL --trace-ascii $dp " + fi + payload64=$(echo -n $payload | _base64 | _b64) + _debug payload64 $payload64 + + nonceurl="$API/directory" + nonce="$($CURL -I $nonceurl | grep -o "^Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)" + + _debug nonce "$nonce" + + protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" + _debug protected "$protected" + + protected64="$(printf "$protected" | _base64 | _b64)" + _debug protected64 "$protected64" + + sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY_PATH | _base64 | _b64) + _debug sig "$sig" + + body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + _debug body "$body" + + if [ "$needbase64" ] ; then + response="$($CURL -X POST --data "$body" $url | _base64)" + else + response="$($CURL -X POST --data "$body" $url)" + fi + + responseHeaders="$(cat $CURL_HEADER)" + + _debug responseHeaders "$responseHeaders" + _debug response "$response" + code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )" + _debug code $code + +} + +_get() { + url="$1" + _debug url $url + response="$(curl --silent $url)" + ret=$? + _debug response "$response" + code="$(echo $response | grep -o '"status":[0-9]\+' | cut -d : -f 2)" + _debug code $code + return $ret +} + +#setopt "file" "opt" "=" "value" [";"] +_setopt() { + __conf="$1" + __opt="$2" + __sep="$3" + __val="$4" + __end="$5" + if [ -z "$__opt" ] ; then + echo usage: _setopt '"file" "opt" "=" "value" [";"]' + return + fi + if [ ! -f "$__conf" ] ; then + touch "$__conf" + fi + + if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then + _debug OK + if [[ "$__val" == *"&"* ]] ; then + __val="$(echo $__val | sed 's/&/\\&/g')" + fi + text="$(cat $__conf)" + printf "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + + elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then + if [[ "$__val" == *"&"* ]] ; then + __val="$(echo $__val | sed 's/&/\\&/g')" + fi + text="$(cat $__conf)" + printf "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + + else + _debug APP + echo "" >> "$__conf" + echo "$__opt$__sep$__val$__end" >> "$__conf" + fi + _debug "$(grep -H -n "^$__opt$__sep" $__conf)" +} + +#_savedomainconf key value +#save to domain.conf +_savedomainconf() { + key="$1" + value="$2" + if [ "$DOMAIN_CONF" ] ; then + _setopt $DOMAIN_CONF "$key" "=" "$value" + else + _err "DOMAIN_CONF is empty, can not save $key=$value" + fi +} + +#_saveaccountconf key value +_saveaccountconf() { + key="$1" + value="$2" + if [ "$ACCOUNT_CONF_PATH" ] ; then + _setopt $ACCOUNT_CONF_PATH "$key" "=" "$value" + else + _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" + fi +} + +_startserver() { + content="$1" + _NC="nc -q 1" + if nc -h 2>&1 | grep "nmap.org/ncat" >/dev/null ; then + _NC="nc" + fi +# while true ; do + if [ "$DEBUG" ] ; then + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort -vv + else + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort > /dev/null + fi +# done +} + +_stopserver() { + pid="$1" + +} + +_initpath() { + + if [ -z "$LE_WORKING_DIR" ]; then + LE_WORKING_DIR=$HOME/.le + fi + + if [ -z "$ACCOUNT_CONF_PATH" ] ; then + ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" + fi + + if [ -f "$ACCOUNT_CONF_PATH" ] ; then + source "$ACCOUNT_CONF_PATH" + fi + + if [ -z "$API" ] ; then + if [ -z "$STAGE" ] ; then + API="$DEFAULT_CA" + else + API="$STAGE_CA" + _info "Using stage api:$API" + fi + fi + + if [ -z "$ACME_DIR" ] ; then + ACME_DIR="/home/.acme" + fi + + if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then + APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/" + fi + + domain="$1" + if ! mkdir -p "$LE_WORKING_DIR" ; then + _err "Can not craete working dir: $LE_WORKING_DIR" + return 1 + fi + + if [ -z "$ACCOUNT_KEY_PATH" ] ; then + ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" + fi + + if [ -z "$domain" ] ; then + return 0 + fi + + domainhome="$LE_WORKING_DIR/$domain" + mkdir -p "$domainhome" + + if [ -z "$DOMAIN_PATH" ] ; then + DOMAIN_PATH="$domainhome" + fi + if [ -z "$DOMAIN_CONF" ] ; then + DOMAIN_CONF="$domainhome/$Le_Domain.conf" + fi + + if [ -z "$DOMAIN_SSL_CONF" ] ; then + DOMAIN_SSL_CONF="$domainhome/$Le_Domain.ssl.conf" + fi + + if [ -z "$CSR_PATH" ] ; then + CSR_PATH="$domainhome/$domain.csr" + fi + if [ -z "$CERT_KEY_PATH" ] ; then + CERT_KEY_PATH="$domainhome/$domain.key" + fi + if [ -z "$CERT_PATH" ] ; then + CERT_PATH="$domainhome/$domain.cer" + fi + if [ -z "$CA_CERT_PATH" ] ; then + CA_CERT_PATH="$domainhome/ca.cer" + fi + +} + + +_apachePath() { + httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" + httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" + httpdconf="$httpdroot/$httpdconfname" + if [ ! -f $httpdconf ] ; then + _err "Apache Config file not found" $httpdconf + return 1 + fi + return 0 +} + +_restoreApache() { + if [ -z "$usingApache" ] ; then + return 0 + fi + _initpath + if ! _apachePath ; then + return 1 + fi + + if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then + _debug "No config file to restore." + return 0 + fi + + cp -p "$APACHE_CONF_BACKUP_DIR/$httpdconfname" "$httpdconf" + if ! apachectl -t ; then + _err "Sorry, restore apache config error, please contact me." + return 1; + fi + rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" + return 0 +} + +_setApache() { + _initpath + if ! _apachePath ; then + return 1 + fi + + #backup the conf + _debug "Backup apache config file" $httpdconf + cp -p $httpdconf $APACHE_CONF_BACKUP_DIR/ + _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" + _info "In case there is an error that can not be restored automatically, you may try restore it yourself." + _info "The backup file will be deleted on sucess, just forget it." + + #add alias + echo " +Alias /.well-known/acme-challenge $ACME_DIR + + +Require all granted + + " >> $httpdconf + + if ! apachectl -t ; then + _err "Sorry, apache config error, please contact me." + _restoreApache + return 1; + fi + + if [ ! -d "$ACME_DIR" ] ; then + mkdir -p "$ACME_DIR" + chmod 755 "$ACME_DIR" + fi + + if ! apachectl graceful ; then + _err "Sorry, apachectl graceful error, please contact me." + _restoreApache + return 1; + fi + usingApache="1" + return 0 +} + +_clearup () { + _stopserver $serverproc + serverproc="" + _restoreApache +} + +# webroot removelevel tokenfile +_clearupwebbroot() { + __webroot="$1" + if [ -z "$__webroot" ] ; then + _debug "no webroot specified, skip" + return 0 + fi + + if [ "$2" == '1' ] ; then + _debug "remove $__webroot/.well-known" + rm -rf "$__webroot/.well-known" + elif [ "$2" == '2' ] ; then + _debug "remove $__webroot/.well-known/acme-challenge" + rm -rf "$__webroot/.well-known/acme-challenge" + elif [ "$2" == '3' ] ; then + _debug "remove $__webroot/.well-known/acme-challenge/$3" + rm -rf "$__webroot/.well-known/acme-challenge/$3" + else + _info "Skip for removelevel:$2" + fi + + return 0 + +} + +issue() { + if [ -z "$2" ] ; then + _err "Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no" + return 1 + fi + Le_Webroot="$1" + Le_Domain="$2" + Le_Alt="$3" + Le_Keylength="$4" + Le_RealCertPath="$5" + Le_RealKeyPath="$6" + Le_RealCACertPath="$7" + Le_ReloadCmd="$8" + + + _initpath $Le_Domain + + if [ -f "$DOMAIN_CONF" ] ; then + Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2) + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then + _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" + return 2 + fi + fi + + if [ "$Le_Alt" == "no" ] ; then + Le_Alt="" + fi + if [ "$Le_Keylength" == "no" ] ; then + Le_Keylength="" + fi + if [ "$Le_RealCertPath" == "no" ] ; then + Le_RealCertPath="" + fi + if [ "$Le_RealKeyPath" == "no" ] ; then + Le_RealKeyPath="" + fi + if [ "$Le_RealCACertPath" == "no" ] ; then + Le_RealCACertPath="" + fi + if [ "$Le_ReloadCmd" == "no" ] ; then + Le_ReloadCmd="" + fi + + _setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain" + _setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt" + _setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot" + _setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength" + _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" + _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" + + if [ "$Le_Webroot" == "no" ] ; then + _info "Standalone mode." + if ! command -v "nc" > /dev/null ; then + _err "Please install netcat(nc) tools first." + return 1 + fi + + if [ -z "$Le_HTTPPort" ] ; then + Le_HTTPPort=80 + fi + _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" + + netprc="$(ss -ntpl | grep :$Le_HTTPPort" ")" + if [ "$netprc" ] ; then + _err "$netprc" + _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" + _err "Please stop it first" + return 1 + fi + fi + + if [ "$Le_Webroot" == "apache" ] ; then + if ! _setApache ; then + _err "set up apache error. Report error to me." + return 1 + fi + wellknown_path="$ACME_DIR" + else + usingApache="" + fi + + createAccountKey $Le_Domain $Le_Keylength + + if ! createDomainKey $Le_Domain $Le_Keylength ; then + _err "Create domain key error." + return 1 + fi + + if ! createCSR $Le_Domain $Le_Alt ; then + _err "Create CSR error." + return 1 + fi + + pub_exp=$(openssl rsa -in $ACCOUNT_KEY_PATH -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) + if [ "${#pub_exp}" == "5" ] ; then + pub_exp=0$pub_exp + fi + _debug pub_exp "$pub_exp" + + e=$(echo $pub_exp | _h2b | _base64) + _debug e "$e" + + modulus=$(openssl rsa -in $ACCOUNT_KEY_PATH -modulus -noout | cut -d '=' -f 2 ) + n=$(echo $modulus| _h2b | _base64 | _b64 ) + + jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' + + HEADER='{"alg": "RS256", "jwk": '$jwk'}' + HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' + _debug HEADER "$HEADER" + + accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) + thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _b64) + + + _info "Registering account" + regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' + if [ "$ACCOUNT_EMAIL" ] ; then + regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' + fi + _send_signed_request "$API/acme/new-reg" "$regjson" + + if [ "$code" == "" ] || [ "$code" == '201' ] ; then + _info "Registered" + echo $response > $LE_WORKING_DIR/account.json + elif [ "$code" == '409' ] ; then + _info "Already registered" + else + _err "Register account Error." + _clearup + return 1 + fi + + vtype="$VTYPE_HTTP" + if [[ "$Le_Webroot" == "dns"* ]] ; then + vtype="$VTYPE_DNS" + fi + + vlist="$Le_Vlist" + # verify each domain + _info "Verify each domain" + sep='#' + if [ -z "$vlist" ] ; then + alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) + for d in $alldomains + do + _info "Getting token for domain" $d + _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" + if [ ! -z "$code" ] && [ ! "$code" == '201' ] ; then + _err "new-authz error: $response" + _clearup + return 1 + fi + + entry="$(printf $response | egrep -o '{[^{]*"type":"'$vtype'"[^}]*')" + _debug entry "$entry" + + token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" + _debug token $token + + uri="$(printf "$entry" | egrep -o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" + _debug uri $uri + + keyauthorization="$token.$thumbprint" + _debug keyauthorization "$keyauthorization" + + dvlist="$d$sep$keyauthorization$sep$uri" + _debug dvlist "$dvlist" + + vlist="$vlist$dvlist," + + done + + #add entry + dnsadded="" + ventries=$(echo "$vlist" | tr ',' ' ' ) + for ventry in $ventries + do + d=$(echo $ventry | cut -d $sep -f 1) + keyauthorization=$(echo $ventry | cut -d $sep -f 2) + + if [ "$vtype" == "$VTYPE_DNS" ] ; then + dnsadded='0' + txtdomain="_acme-challenge.$d" + _debug txtdomain "$txtdomain" + txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _b64)" + _debug txt "$txt" + #dns + #1. check use api + d_api="" + if [ -f "$LE_WORKING_DIR/$d/$Le_Webroot" ] ; then + d_api="$LE_WORKING_DIR/$d/$Le_Webroot" + elif [ -f "$LE_WORKING_DIR/$d/$Le_Webroot.sh" ] ; then + d_api="$LE_WORKING_DIR/$d/$Le_Webroot.sh" + elif [ -f "$LE_WORKING_DIR/$Le_Webroot" ] ; then + d_api="$LE_WORKING_DIR/$Le_Webroot" + elif [ -f "$LE_WORKING_DIR/$Le_Webroot.sh" ] ; then + d_api="$LE_WORKING_DIR/$Le_Webroot.sh" + elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot" ] ; then + d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot" + elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" ] ; then + d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" + fi + _debug d_api "$d_api" + + if [ "$d_api" ]; then + _info "Found domain api file: $d_api" + else + _err "Add the following TXT record:" + _err "Domain: $txtdomain" + _err "TXT value: $txt" + _err "Please be aware that you prepend _acme-challenge. before your domain" + _err "so the resulting subdomain will be: $txtdomain" + continue + fi + + if ! source $d_api ; then + _err "Load file $d_api error. Please check your api file and try again." + return 1 + fi + + addcommand="$Le_Webroot-add" + if ! command -v $addcommand ; then + _err "It seems that your api file is not correct, it must have a function named: $Le_Webroot" + return 1 + fi + + if ! $addcommand $txtdomain $txt ; then + _err "Error add txt for domain:$txtdomain" + return 1 + fi + dnsadded='1' + fi + done + + if [ "$dnsadded" == '0' ] ; then + _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\"" + _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." + _err "Please add the TXT records to the domains, and retry again." + return 1 + fi + + fi + + if [ "$dnsadded" == '1' ] ; then + _info "Sleep 60 seconds for the txt records to take effect" + sleep 60 + fi + + _debug "ok, let's start to verify" + ventries=$(echo "$vlist" | tr ',' ' ' ) + for ventry in $ventries + do + d=$(echo $ventry | cut -d $sep -f 1) + keyauthorization=$(echo $ventry | cut -d $sep -f 2) + uri=$(echo $ventry | cut -d $sep -f 3) + _info "Verifying:$d" + _debug "d" "$d" + _debug "keyauthorization" "$keyauthorization" + _debug "uri" "$uri" + removelevel="" + token="" + if [ "$vtype" == "$VTYPE_HTTP" ] ; then + if [ "$Le_Webroot" == "no" ] ; then + _info "Standalone mode server" + _startserver "$keyauthorization" & + serverproc="$!" + sleep 2 + _debug serverproc $serverproc + else + if [ -z "$wellknown_path" ] ; then + wellknown_path="$Le_Webroot/.well-known/acme-challenge" + fi + _debug wellknown_path "$wellknown_path" + + if [ ! -d "$Le_Webroot/.well-known" ] ; then + removelevel='1' + elif [ ! -d "$Le_Webroot/.well-known/acme-challenge" ] ; then + removelevel='2' + else + removelevel='3' + fi + + token="$(echo -e -n "$keyauthorization" | cut -d '.' -f 1)" + _debug "writing token:$token to $wellknown_path/$token" + + mkdir -p "$wellknown_path" + echo -n "$keyauthorization" > "$wellknown_path/$token" + + webroot_owner=$(stat -c '%U:%G' $Le_Webroot) + _debug "Changing owner/group of .well-known to $webroot_owner" + chown -R $webroot_owner "$Le_Webroot/.well-known" + + fi + fi + + _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" + + if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then + _err "$d:Challenge error: $resource" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearup + return 1 + fi + + while [ "1" ] ; do + _debug "sleep 5 secs to verify" + sleep 5 + _debug "checking" + + if ! _get $uri ; then + _err "$d:Verify error:$resource" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearup + return 1 + fi + + status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | tr -d '"') + if [ "$status" == "valid" ] ; then + _info "Success" + _stopserver $serverproc + serverproc="" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + break; + fi + + if [ "$status" == "invalid" ] ; then + error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4) + _err "$d:Verify error:$error" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearup + return 1; + fi + + if [ "$status" == "pending" ] ; then + _info "Pending" + else + _err "$d:Verify error:$response" + _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearup + return 1 + fi + + done + + done + + _clearup + _info "Verify finished, start to sign." + der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _b64)" + _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" + + + Le_LinkCert="$(grep -i -o '^Location.*$' $CURL_HEADER | tr -d "\r\n" | cut -d " " -f 2)" + _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" + + if [ "$Le_LinkCert" ] ; then + echo -----BEGIN CERTIFICATE----- > "$CERT_PATH" + curl --silent "$Le_LinkCert" | openssl base64 -e >> "$CERT_PATH" + echo -----END CERTIFICATE----- >> "$CERT_PATH" + _info "Cert success." + cat "$CERT_PATH" + + _info "Your cert is in $CERT_PATH" + fi + + + if [ -z "$Le_LinkCert" ] ; then + response="$(echo $response | openssl base64 -d -A)" + _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" + return 1 + fi + + _setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\"" + + Le_LinkIssuer=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) + _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" + + if [ "$Le_LinkIssuer" ] ; then + echo -----BEGIN CERTIFICATE----- > "$CA_CERT_PATH" + curl --silent "$Le_LinkIssuer" | openssl base64 -e >> "$CA_CERT_PATH" + echo -----END CERTIFICATE----- >> "$CA_CERT_PATH" + _info "The intermediate CA cert is in $CA_CERT_PATH" + fi + + Le_CertCreateTime=$(date -u "+%s") + _setopt "$DOMAIN_CONF" "Le_CertCreateTime" "=" "$Le_CertCreateTime" + + Le_CertCreateTimeStr=$(date -u ) + _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\"" + + if [ ! "$Le_RenewalDays" ] ; then + Le_RenewalDays=80 + fi + + _setopt "$DOMAIN_CONF" "Le_RenewalDays" "=" "$Le_RenewalDays" + + let "Le_NextRenewTime=Le_CertCreateTime+Le_RenewalDays*24*60*60" + _setopt "$DOMAIN_CONF" "Le_NextRenewTime" "=" "$Le_NextRenewTime" + + Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) + _setopt "$DOMAIN_CONF" "Le_NextRenewTimeStr" "=" "\"$Le_NextRenewTimeStr\"" + + + installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" + +} + +renew() { + Le_Domain="$1" + if [ -z "$Le_Domain" ] ; then + _err "Usage: $0 domain.com" + return 1 + fi + + _initpath $Le_Domain + + if [ ! -f "$DOMAIN_CONF" ] ; then + _info "$Le_Domain is not a issued domain, skip." + return 0; + fi + + source "$DOMAIN_CONF" + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then + _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" + return 2 + fi + + IS_RENEW="1" + issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" + local res=$? + IS_RENEW="" + + return $res +} + +renewAll() { + _initpath + _info "renewAll" + + for d in $(ls -F $LE_WORKING_DIR | grep [^.].*[.].*/$ ) ; do + d=$(echo $d | cut -d '/' -f 1) + _info "renew $d" + + Le_LinkCert="" + Le_Domain="" + Le_Alt="" + Le_Webroot="" + Le_Keylength="" + Le_LinkIssuer="" + + Le_CertCreateTime="" + Le_CertCreateTimeStr="" + Le_RenewalDays="" + Le_NextRenewTime="" + Le_NextRenewTimeStr="" + + Le_RealCertPath="" + Le_RealKeyPath="" + + Le_RealCACertPath="" + + Le_ReloadCmd="" + + DOMAIN_PATH="" + DOMAIN_CONF="" + DOMAIN_SSL_CONF="" + CSR_PATH="" + CERT_KEY_PATH="" + CERT_PATH="" + CA_CERT_PATH="" + ACCOUNT_KEY_PATH="" + + wellknown_path="" + + renew "$d" + done + +} + +installcert() { + Le_Domain="$1" + if [ -z "$Le_Domain" ] ; then + _err "Usage: $0 domain.com [cert-file-path]|no [key-file-path]|no [ca-cert-file-path]|no [reloadCmd]|no" + return 1 + fi + + Le_RealCertPath="$2" + Le_RealKeyPath="$3" + Le_RealCACertPath="$4" + Le_ReloadCmd="$5" + + _initpath $Le_Domain + + _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" + _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" + + if [ "$Le_RealCertPath" ] ; then + if [ -f "$Le_RealCertPath" ] ; then + cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak + fi + cat "$CERT_PATH" > "$Le_RealCertPath" + fi + + if [ "$Le_RealCACertPath" ] ; then + if [ -f "$Le_RealCACertPath" ] ; then + cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak + fi + if [ "$Le_RealCACertPath" == "$Le_RealCertPath" ] ; then + echo "" >> "$Le_RealCACertPath" + cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" + else + cat "$CA_CERT_PATH" > "$Le_RealCACertPath" + fi + fi + + + if [ "$Le_RealKeyPath" ] ; then + if [ -f "$Le_RealKeyPath" ] ; then + cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak + fi + cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" + fi + + if [ "$Le_ReloadCmd" ] ; then + _info "Run Le_ReloadCmd: $Le_ReloadCmd" + (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") + fi + +} + +installcronjob() { + _initpath + _info "Installing cron job" + if ! crontab -l | grep 'le.sh cron' ; then + if [ -f "$LE_WORKING_DIR/le.sh" ] ; then + lesh="\"$LE_WORKING_DIR\"/le.sh" + else + _err "Can not install cronjob, le.sh not found." + return 1 + fi + crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab - + fi + if [ "$?" != "0" ] ; then + _err "Install cron job failed. You need to manually renew your certs." + _err "Or you can add cronjob by yourself:" + _err "LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null" + return 1 + fi +} + +uninstallcronjob() { + _info "Removing cron job" + cr="$(crontab -l | grep 'le.sh cron')" + if [ "$cr" ] ; then + crontab -l | sed "/le.sh cron/d" | crontab - + LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 6 | cut -d '=' -f 2 | tr -d '"')" + _info LE_WORKING_DIR "$LE_WORKING_DIR" + fi + _initpath + +} + + +# Detect profile file if not specified as environment variable +_detect_profile() { + if [ -n "$PROFILE" -a -f "$PROFILE" ]; then + echo "$PROFILE" + return + fi + + local DETECTED_PROFILE + DETECTED_PROFILE='' + local SHELLTYPE + SHELLTYPE="$(basename "/$SHELL")" + + if [ "$SHELLTYPE" = "bash" ]; then + if [ -f "$HOME/.bashrc" ]; then + DETECTED_PROFILE="$HOME/.bashrc" + elif [ -f "$HOME/.bash_profile" ]; then + DETECTED_PROFILE="$HOME/.bash_profile" + fi + elif [ "$SHELLTYPE" = "zsh" ]; then + DETECTED_PROFILE="$HOME/.zshrc" + fi + + if [ -z "$DETECTED_PROFILE" ]; then + if [ -f "$HOME/.profile" ]; then + DETECTED_PROFILE="$HOME/.profile" + elif [ -f "$HOME/.bashrc" ]; then + DETECTED_PROFILE="$HOME/.bashrc" + elif [ -f "$HOME/.bash_profile" ]; then + DETECTED_PROFILE="$HOME/.bash_profile" + elif [ -f "$HOME/.zshrc" ]; then + DETECTED_PROFILE="$HOME/.zshrc" + fi + fi + + if [ ! -z "$DETECTED_PROFILE" ]; then + echo "$DETECTED_PROFILE" + fi +} + +_initconf() { + _initpath + if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then + echo "#Account configurations: +#Here are the supported macros, uncomment them to make them take effect. +#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. + +#STAGE=1 # Use the staging api +#FORCE=1 # Force to issue cert +#DEBUG=1 # Debug mode + +#dns api +####################### +#Cloudflare: +#api key +#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +#account email +#CF_Email="xxxx@sss.com" + +####################### +#Dnspod.cn: +#api key id +#DP_Id="1234" +#api key +#DP_Key="sADDsdasdgdsf" + +####################### +#Cloudxns.com: +#CX_Key="1234" +# +#CX_Secret="sADDsdasdgdsf" + + " > $ACCOUNT_CONF_PATH + fi +} + +install() { + if ! _initpath ; then + _err "Install failed." + return 1 + fi + + #check if there is sudo installed, AND if the current user is a sudoer. + if command -v sudo > /dev/null ; then + if [ "$(sudo -n uptime 2>&1|grep "load"|wc -l)" != "0" ] ; then + SUDO=sudo + fi + fi + + if command -v yum > /dev/null ; then + YUM="1" + INSTALL="$SUDO yum install -y " + elif command -v apt-get > /dev/null ; then + INSTALL="$SUDO apt-get install -y " + fi + + if ! command -v "curl" > /dev/null ; then + _err "Please install curl first." + _err "$INSTALL curl" + return 1 + fi + + if ! command -v "crontab" > /dev/null ; then + _err "Please install crontab first." + if [ "$YUM" ] ; then + _err "$INSTALL crontabs" + else + _err "$INSTALL crontab" + fi + return 1 + fi + + if ! command -v "openssl" > /dev/null ; then + _err "Please install openssl first." + _err "$INSTALL openssl" + return 1 + fi + + _info "Installing to $LE_WORKING_DIR" + + cp le.sh "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/le.sh" + + if [ "$?" != "0" ] ; then + _err "Install failed, can not copy le.sh" + return 1 + fi + + _info "Installed to $LE_WORKING_DIR/le.sh" + + _profile="$(_detect_profile)" + if [ "$_profile" ] ; then + _debug "Found profile: $_profile" + + echo "LE_WORKING_DIR=$LE_WORKING_DIR +alias le=\"$LE_WORKING_DIR/le.sh\" +alias le.sh=\"$LE_WORKING_DIR/le.sh\" + " > "$LE_WORKING_DIR/le.env" + + _setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\"" + _info "OK, Close and reopen your terminal to start using le" + else + _info "No profile is found, you will need to go into $LE_WORKING_DIR to use le.sh" + fi + + mkdir -p $LE_WORKING_DIR/dnsapi + cp dnsapi/* $LE_WORKING_DIR/dnsapi/ + + #to keep compatible mv the .acc file to .key file + if [ -f "$LE_WORKING_DIR/account.acc" ] ; then + mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key" + fi + + installcronjob + + if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then + _initconf + fi + _info OK +} + +uninstall() { + uninstallcronjob + _initpath + + _profile="$(_detect_profile)" + if [ "$_profile" ] ; then + sed -i /le.env/d "$_profile" + fi + + rm -f $LE_WORKING_DIR/le.sh + _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." + +} + +cron() { + renewAll +} + +version() { + _info "$PROJECT" + _info "v$VER" +} + +showhelp() { + version + echo "Usage: le.sh [command] ...[args].... +Avalible commands: + +install: + Install le.sh to your system. +issue: + Issue a cert. +installcert: + Install the issued cert to apache/nginx or any other server. +renew: + Renew a cert. +renewAll: + Renew all the certs. +uninstall: + Uninstall le.sh, and uninstall the cron job. +version: + Show version info. +installcronjob: + Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. +uninstallcronjob: + Uninstall the cron job. The 'uninstall' command can do this automatically. +createAccountKey: + Create an account private key, professional use. +createDomainKey: + Create an domain private key, professional use. +createCSR: + Create CSR , professional use. + " +} + + +if [ -z "$1" ] ; then + showhelp +else + "$@" +fi From 6dfaaa702cf1a37219e2e22b3fa302a5364eca55 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 8 Mar 2016 20:55:54 +0800 Subject: [PATCH 0009/1348] minor, use "echo" for more compatible --- le.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index 5dca6265..e2c19592 100755 --- a/le.sh +++ b/le.sh @@ -285,14 +285,14 @@ _setopt() { __val="$(echo $__val | sed 's/&/\\&/g')" fi text="$(cat $__conf)" - printf "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then if [[ "$__val" == *"&"* ]] ; then __val="$(echo $__val | sed 's/&/\\&/g')" fi text="$(cat $__conf)" - printf "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" else _debug APP From b86869a0a4909cd9b98b718009e218b88cfd6d4e Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 8 Mar 2016 23:18:48 +0800 Subject: [PATCH 0010/1348] minor, fix blank line --- le.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/le.sh b/le.sh index e2c19592..7c93e5c3 100755 --- a/le.sh +++ b/le.sh @@ -296,7 +296,6 @@ _setopt() { else _debug APP - echo "" >> "$__conf" echo "$__opt$__sep$__val$__end" >> "$__conf" fi _debug "$(grep -H -n "^$__opt$__sep" $__conf)" @@ -1232,7 +1231,7 @@ install() { alias le=\"$LE_WORKING_DIR/le.sh\" alias le.sh=\"$LE_WORKING_DIR/le.sh\" " > "$LE_WORKING_DIR/le.env" - + echo "" >> "$_profile" _setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\"" _info "OK, Close and reopen your terminal to start using le" else From 5fd3f21b1f7c39f9b5100f74933b4b21f0dd9ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= Date: Wed, 9 Mar 2016 11:32:50 +0100 Subject: [PATCH 0011/1348] update _initconf with ACCOUNT_KEY_PATH --- le.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/le.sh b/le.sh index 7c93e5c3..06172479 100755 --- a/le.sh +++ b/le.sh @@ -1140,6 +1140,7 @@ _initconf() { echo "#Account configurations: #Here are the supported macros, uncomment them to make them take effect. #ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. +#ACCOUNT_KEY_PATH=\"/path/to/account.key\" #STAGE=1 # Use the staging api #FORCE=1 # Force to issue cert From 3d49985af886a0de520c27711538b9c250fd3884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= Date: Wed, 9 Mar 2016 11:33:24 +0100 Subject: [PATCH 0012/1348] update _initconf proper " escaping --- le.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/le.sh b/le.sh index 06172479..cfc927a4 100755 --- a/le.sh +++ b/le.sh @@ -1150,22 +1150,22 @@ _initconf() { ####################### #Cloudflare: #api key -#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +#CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\" #account email -#CF_Email="xxxx@sss.com" +#CF_Email=\"xxxx@sss.com\" ####################### #Dnspod.cn: #api key id -#DP_Id="1234" +#DP_Id=\"1234\" #api key -#DP_Key="sADDsdasdgdsf" +#DP_Key=\"sADDsdasdgdsf\" ####################### #Cloudxns.com: -#CX_Key="1234" +#CX_Key=\"1234\" # -#CX_Secret="sADDsdasdgdsf" +#CX_Secret=\"sADDsdasdgdsf\" " > $ACCOUNT_CONF_PATH fi From 1ad65f7d78e3897da776ba7ef79fb06e26ea1e0b Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 9 Mar 2016 22:45:05 +0800 Subject: [PATCH 0013/1348] fix compatible to pfsense. use "-config" for single domain to override the default openssl config file. --- le.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/le.sh b/le.sh index cfc927a4..f91fc1de 100755 --- a/le.sh +++ b/le.sh @@ -175,7 +175,8 @@ createCSR() { if [ -z "$domainlist" ] ; then #single domain _info "Single domain" $domain - openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" > "$CSR_PATH" + printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$DOMAIN_SSL_CONF" + openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" else alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" #multi @@ -396,11 +397,11 @@ _initpath() { DOMAIN_PATH="$domainhome" fi if [ -z "$DOMAIN_CONF" ] ; then - DOMAIN_CONF="$domainhome/$Le_Domain.conf" + DOMAIN_CONF="$domainhome/$domain.conf" fi if [ -z "$DOMAIN_SSL_CONF" ] ; then - DOMAIN_SSL_CONF="$domainhome/$Le_Domain.ssl.conf" + DOMAIN_SSL_CONF="$domainhome/$domain.ssl.conf" fi if [ -z "$CSR_PATH" ] ; then From 44df29670786fd093b190b46ba5b64c42aaac8bd Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 9 Mar 2016 23:16:46 +0800 Subject: [PATCH 0014/1348] fix compatible for pfsense. --- le.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/le.sh b/le.sh index f91fc1de..ac975308 100755 --- a/le.sh +++ b/le.sh @@ -205,6 +205,18 @@ _time2str() { } +_stat() { + #Linux + if stat -c '%U:%G' "$1" 2>/dev/null ; then + return + fi + + #BSD + if stat -f '%Su:%Sg' "$1" 2>/dev/null ; then + return + fi +} + _send_signed_request() { url=$1 payload=$2 @@ -819,7 +831,7 @@ issue() { mkdir -p "$wellknown_path" echo -n "$keyauthorization" > "$wellknown_path/$token" - webroot_owner=$(stat -c '%U:%G' $Le_Webroot) + webroot_owner=$(_stat $Le_Webroot) _debug "Changing owner/group of .well-known to $webroot_owner" chown -R $webroot_owner "$Le_Webroot/.well-known" From 7203a1c1a090ac707565a8253560009c9b04c097 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 9 Mar 2016 23:34:41 +0800 Subject: [PATCH 0015/1348] fix compatible, 'sed -i' is not supported be freeBSD --- le.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/le.sh b/le.sh index ac975308..95bb541a 100755 --- a/le.sh +++ b/le.sh @@ -1274,7 +1274,8 @@ uninstall() { _profile="$(_detect_profile)" if [ "$_profile" ] ; then - sed -i /le.env/d "$_profile" + text="$(cat $_profile)" + echo "$text" | sed "s|^source.*le.env.*$||" > "$_profile" fi rm -f $LE_WORKING_DIR/le.sh From 54f473d8268efa3520aa6f7664da6db6e03ffe23 Mon Sep 17 00:00:00 2001 From: Neil Date: Wed, 9 Mar 2016 23:42:49 +0800 Subject: [PATCH 0016/1348] support pfsense --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c7c5b842..0be7453a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Do NOT require to be `root/sudoer`. 2. CentOS 3. Windows (cygwin with curl, openssl and crontab included) 4. FreeBSD with bash +5. pfsense with bash and curl #Supported Mode From 2dd02b8d1eb7842ab642baab827a3ece9fbaa4a5 Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 10 Mar 2016 12:21:32 +0800 Subject: [PATCH 0017/1348] AWS Route 53 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0be7453a..ab57e1bd 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ You don't have do anything manually. 1. Cloudflare.com api 2. Dnspod.cn api 3. Cloudxns.com api +4. AWS Route 53, see: https://github.com/Neilpang/le/issues/65 More apis are comming soon.... From 7bd9a3b17a72425ce2ce03d4e1a4807b38aaabe3 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 10 Mar 2016 13:42:46 +0800 Subject: [PATCH 0018/1348] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ab57e1bd..29ca454d 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ You don't have do anything manually. 3. Cloudxns.com api 4. AWS Route 53, see: https://github.com/Neilpang/le/issues/65 -More apis are comming soon.... +More apis are coming soon.... If your dns provider is not in the supported list above, you can write your own script api easily. From cbb5f7ec5c2556d87c376132569176e32d322d4f Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 10 Mar 2016 13:47:35 +0800 Subject: [PATCH 0019/1348] minor, remove space --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 29ca454d..dcfbd1ea 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # le: means simp`Le` Simplest shell script for LetsEncrypt free Certificate client -Simple and Powerful, you only need 3 minutes to learn. +Simple and Powerful, you only need 3 minutes to learn. -Pure written in bash, no dependencies to python , acme-tiny or LetsEncrypt official client. +Pure written in bash, no dependencies to python, acme-tiny or LetsEncrypt official client. Just one script, to issue, renew your certificates automatically. -Probably it's the smallest&easiest&smartest shell script to automatically issue&renew the free certificates from LetsEncrypt. +Probably it's the smallest&easiest&smartest shell script to automatically issue & renew the free certificates from LetsEncrypt. Do NOT require to be `root/sudoer`. @@ -42,7 +42,7 @@ All the certs will be placed in this folder. After install, you must close current terminal and reopen again to make the alias take effect. -Ok, you are ready to issue cert now. +Ok, you are ready to issue cert now. Show help message: ``` root@v1:~# le.sh @@ -110,7 +110,7 @@ First argument `/home/wwwroot/aa.com` is the web root folder, You must have `wri Second argument "aa.com" is the main domain you want to issue cert for. -Third argument is the additional domain list you want to use. Comma separated list, which is Optional. +Third argument is the additional domain list you want to use. Comma separated list, which is Optional. You must point and bind all the domains to the same webroot dir:`/home/wwwroot/aa.com` @@ -125,10 +125,10 @@ le installcert aa.com /path/to/certfile/in/apache/nginx /path/to/keyfile/in/ap Install the issued cert/key to the production apache or nginx path. -The cert will be renewed every 80 days by default (which is configurable), Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: ` service apache2 reload` or `service nginx reload` +The cert will be renewed every 80 days by default (which is configurable), Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload` -# Use Standalone server to issue cert( requires you be root/sudoer, or you have permission to listen tcp 80 port): +# Use Standalone server to issue cert (requires you be root/sudoer, or you have permission to listen tcp 80 port): Same usage as all above, just give `no` as the webroot. The tcp `80` port must be free to listen, otherwise you will be prompted to free the `80` port and try again. @@ -136,7 +136,7 @@ The tcp `80` port must be free to listen, otherwise you will be prompted to free le issue no aa.com www.aa.com,cp.aa.com ``` -# Use Apache mode(requires you be root/sudoer, since it is required to interact with apache server): +# Use Apache mode (requires you be root/sudoer, since it is required to interact with apache server): If you are running a web server, apache or nginx, it is recommended to use the Webroot mode. Particularly, if you are running an apache server, you can use apache mode instead. Which doesn't write any file to your web root folder. @@ -179,15 +179,15 @@ Ok, it's finished. #Automatic dns api integeration -If your dns provider supports api access, we can use api to automatically issue certs. +If your dns provider supports api access, we can use api to automatically issue certs. You don't have do anything manually. ###Currently we support: -1. Cloudflare.com api -2. Dnspod.cn api -3. Cloudxns.com api -4. AWS Route 53, see: https://github.com/Neilpang/le/issues/65 +1. Cloudflare.com api +2. Dnspod.cn api +3. Cloudxns.com api +4. AWS Route 53, see: https://github.com/Neilpang/le/issues/65 More apis are coming soon.... From 9e6c420872e6e843a6a86ee31f2472574eeda3f6 Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 10 Mar 2016 14:17:47 +0800 Subject: [PATCH 0020/1348] add example for ecc certificate --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dcfbd1ea..3b8d012e 100644 --- a/README.md +++ b/README.md @@ -202,9 +202,17 @@ And we also support it. Just set the `length` parameter with a prefix `ec-`. For example: + +Single domain: +``` +le issue /home/wwwroot/aa.com aa.com no ec-256 ``` -le issue /home/wwwroot/aa.com aa.com www.aa.com ec-256 + +SAN multiple domains: ``` +le issue /home/wwwroot/aa.com aa.com www.aa.com,cp.aa.com ec-256 +``` + Please look at the last parameter above. Valid values are: From 6389e87fd36821fdf4a7fb1e1f85c1473fc959e2 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 10 Mar 2016 21:54:07 +0800 Subject: [PATCH 0021/1348] fix compatible for centos5 nc-1.84-10. `-p` is not necessary for all the tested platforms. so, remove it. --- le.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index 95bb541a..71ed1677 100755 --- a/le.sh +++ b/le.sh @@ -345,9 +345,9 @@ _startserver() { fi # while true ; do if [ "$DEBUG" ] ; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort -vv + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l $Le_HTTPPort -vv else - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l -p $Le_HTTPPort > /dev/null + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l $Le_HTTPPort > /dev/null fi # done } From 5434c15ec564e948e1be890dd0f699a0b9e5bc90 Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 10 Mar 2016 21:59:41 +0800 Subject: [PATCH 0022/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b8d012e..a0b60c14 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Do NOT require to be `root/sudoer`. #Tested OS 1. Ubuntu/Debian. -2. CentOS +2. CentOS 5, 6, 7 3. Windows (cygwin with curl, openssl and crontab included) 4. FreeBSD with bash 5. pfsense with bash and curl From 7559e804b292eeb6466dedc33e811cfc2f5149c2 Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 10 Mar 2016 22:55:33 +0800 Subject: [PATCH 0023/1348] test openSUSE --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a0b60c14..ecde5e5d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Do NOT require to be `root/sudoer`. 3. Windows (cygwin with curl, openssl and crontab included) 4. FreeBSD with bash 5. pfsense with bash and curl +6. openSUSE 13 #Supported Mode From 348cddd7628c7433f3255c30dbb8f0a246f0a138 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 10 Mar 2016 23:43:03 +0800 Subject: [PATCH 0024/1348] fix compatible to alpine linux --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 71ed1677..619f658f 100755 --- a/le.sh +++ b/le.sh @@ -696,7 +696,7 @@ issue() { return 1 fi - entry="$(printf $response | egrep -o '{[^{]*"type":"'$vtype'"[^}]*')" + entry="$(printf $response | egrep -o '\{[^{]*"type":"'$vtype'"[^}]*')" _debug entry "$entry" token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" From 0eaada6f233118655e5d7a41ee76f847249948ea Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 10 Mar 2016 23:51:52 +0800 Subject: [PATCH 0025/1348] support Alpine Linux --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ecde5e5d..e69bf480 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Do NOT require to be `root/sudoer`. 4. FreeBSD with bash 5. pfsense with bash and curl 6. openSUSE 13 +7. Alpine Linux (with bash, curl. https://github.com/Neilpang/le/issues/94) #Supported Mode From 07f4ec4f73d4130a15ecec1fb9de00ef634334c9 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 11 Mar 2016 21:57:05 +0800 Subject: [PATCH 0026/1348] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e69bf480..7c8f955b 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,11 @@ Do NOT require to be `root/sudoer`. 5. pfsense with bash and curl 6. openSUSE 13 7. Alpine Linux (with bash, curl. https://github.com/Neilpang/le/issues/94) +8. Archlinux +If anyone want to test le on your system, you can simply run our test project: https://github.com/Neilpang/letest + #Supported Mode 1. Webroot mode 2. Standalone mode From 1b2e940d6a53364e87a38cbb39b8185d37c3df79 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 11 Mar 2016 22:08:54 +0800 Subject: [PATCH 0027/1348] fix issue '-p' is needed by Debian nc tool --- le.sh | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/le.sh b/le.sh index 619f658f..d4315155 100755 --- a/le.sh +++ b/le.sh @@ -339,15 +339,26 @@ _saveaccountconf() { _startserver() { content="$1" - _NC="nc -q 1" - if nc -h 2>&1 | grep "nmap.org/ncat" >/dev/null ; then - _NC="nc" + _NC="nc -q 1 -l" + + nchelp="$(nc -h 2>&1)" + if echo "$nchelp" | grep "nmap.org/ncat" >/dev/null ; then + _NC="nc -l" fi + + if echo "$nchelp" | grep "--version" >/dev/null ; then + ncver="$(nc --version)" + if echo "$ncver" | grep "http://www.deepspace6.net" > /dev/null ; then + _NC="$_NC -p" + fi + fi + + _debug nc "$_NC" # while true ; do if [ "$DEBUG" ] ; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l $Le_HTTPPort -vv + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv else - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -l $Le_HTTPPort > /dev/null + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null fi # done } From bce55f429b7b297cae1e706e3f6fce654de155c0 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 11 Mar 2016 22:17:35 +0800 Subject: [PATCH 0028/1348] graceful --- le.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/le.sh b/le.sh index d4315155..5853cff6 100755 --- a/le.sh +++ b/le.sh @@ -342,15 +342,15 @@ _startserver() { _NC="nc -q 1 -l" nchelp="$(nc -h 2>&1)" + #centos if echo "$nchelp" | grep "nmap.org/ncat" >/dev/null ; then _NC="nc -l" fi - if echo "$nchelp" | grep "--version" >/dev/null ; then - ncver="$(nc --version)" - if echo "$ncver" | grep "http://www.deepspace6.net" > /dev/null ; then - _NC="$_NC -p" - fi + #debian + ncver="$(nc --version 2>&1)" + if echo "$ncver" | grep "http://www.deepspace6.net" > /dev/null ; then + _NC="$_NC -p" fi _debug nc "$_NC" From f89d991d0f615fd8e7a6d7bbda409ddc59444d6c Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 11 Mar 2016 22:37:04 +0800 Subject: [PATCH 0029/1348] minor --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 5853cff6..7e4a532d 100755 --- a/le.sh +++ b/le.sh @@ -89,7 +89,7 @@ createAccountKey() { return else #generate account key - openssl genrsa $length > "$ACCOUNT_KEY_PATH" + openssl genrsa $length 2>/dev/null > "$ACCOUNT_KEY_PATH" fi } From 0705f65336e9e0b6d44df4bb02b0e881d2b167c0 Mon Sep 17 00:00:00 2001 From: kaklakariada Date: Fri, 11 Mar 2016 18:00:52 +0100 Subject: [PATCH 0030/1348] Fix error message for missing dos api function --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 7e4a532d..ac76c049 100755 --- a/le.sh +++ b/le.sh @@ -776,7 +776,7 @@ issue() { addcommand="$Le_Webroot-add" if ! command -v $addcommand ; then - _err "It seems that your api file is not correct, it must have a function named: $Le_Webroot" + _err "It seems that your api file is not correct, it must have a function named: $Le_Webroot-add" return 1 fi From f8ad8f34b1d9b8d1aea7b0eab674a669a9dbe4a9 Mon Sep 17 00:00:00 2001 From: kaklakariada Date: Sat, 12 Mar 2016 07:42:18 +0100 Subject: [PATCH 0031/1348] Use variable in error message instead of constructing it again --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index ac76c049..7ffed9bd 100755 --- a/le.sh +++ b/le.sh @@ -776,7 +776,7 @@ issue() { addcommand="$Le_Webroot-add" if ! command -v $addcommand ; then - _err "It seems that your api file is not correct, it must have a function named: $Le_Webroot-add" + _err "It seems that your api file is not correct, it must have a function named: $addcommand" return 1 fi From caf1fc10ff5ce40eafa4a969958abf277511d0f8 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 11:37:14 +0800 Subject: [PATCH 0032/1348] add fullchain.pem --- le.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/le.sh b/le.sh index 7ffed9bd..e0464afd 100755 --- a/le.sh +++ b/le.sh @@ -439,6 +439,9 @@ _initpath() { if [ -z "$CA_CERT_PATH" ] ; then CA_CERT_PATH="$domainhome/ca.cer" fi + if [ -z "$CERT_FULLCHAIN_PATH" ] ; then + CERT_FULLCHAIN_PATH="$domainhome/fullchain.pem" + fi } @@ -917,6 +920,7 @@ issue() { cat "$CERT_PATH" _info "Your cert is in $CERT_PATH" + cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" fi @@ -936,6 +940,8 @@ issue() { curl --silent "$Le_LinkIssuer" | openssl base64 -e >> "$CA_CERT_PATH" echo -----END CERTIFICATE----- >> "$CA_CERT_PATH" _info "The intermediate CA cert is in $CA_CERT_PATH" + cat "$CA_CERT_PATH" >> "$CERT_FULLCHAIN_PATH" + _info "And the full chain certs is there: $CERT_FULLCHAIN_PATH" fi Le_CertCreateTime=$(date -u "+%s") @@ -1024,6 +1030,7 @@ renewAll() { CERT_KEY_PATH="" CERT_PATH="" CA_CERT_PATH="" + CERT_FULLCHAIN_PATH="" ACCOUNT_KEY_PATH="" wellknown_path="" From 850db6d4d946a833e941084fb93a43ca01ceb42d Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 12:34:53 +0800 Subject: [PATCH 0033/1348] rename fullchain.pem to fullchain.cer --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index e0464afd..47dc7923 100755 --- a/le.sh +++ b/le.sh @@ -440,7 +440,7 @@ _initpath() { CA_CERT_PATH="$domainhome/ca.cer" fi if [ -z "$CERT_FULLCHAIN_PATH" ] ; then - CERT_FULLCHAIN_PATH="$domainhome/fullchain.pem" + CERT_FULLCHAIN_PATH="$domainhome/fullchain.cer" fi } From 051c706d787c90589510c598598f48f2561852ca Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 15:57:12 +0800 Subject: [PATCH 0034/1348] fix nc info --- le.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 47dc7923..2f1f63d1 100755 --- a/le.sh +++ b/le.sh @@ -353,13 +353,17 @@ _startserver() { _NC="$_NC -p" fi - _debug nc "$_NC" + _debug "$_NC $Le_HTTPPort" # while true ; do if [ "$DEBUG" ] ; then echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv else echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null fi + if [ "$?" != "0" ] ; then + _err "nc listen error." + return 1 + fi # done } From 3aff11f6296093d5bd034be814bc2eaf6c890a1c Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 16:14:15 +0800 Subject: [PATCH 0035/1348] fix nc compatible. try '-p' first --- le.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/le.sh b/le.sh index 2f1f63d1..16925283 100755 --- a/le.sh +++ b/le.sh @@ -346,19 +346,17 @@ _startserver() { if echo "$nchelp" | grep "nmap.org/ncat" >/dev/null ; then _NC="nc -l" fi - - #debian - ncver="$(nc --version 2>&1)" - if echo "$ncver" | grep "http://www.deepspace6.net" > /dev/null ; then - _NC="$_NC -p" - fi _debug "$_NC $Le_HTTPPort" # while true ; do if [ "$DEBUG" ] ; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv + if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; + fi else - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null + if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null ; then + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null + fi fi if [ "$?" != "0" ] ; then _err "nc listen error." From 34c27e0995eb49791bdbe24ad6c91fc905fc090c Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 18:17:13 +0800 Subject: [PATCH 0036/1348] fix portable. detect 'ss' or 'netstat' --- le.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 16925283..a5e06ab9 100755 --- a/le.sh +++ b/le.sh @@ -63,6 +63,21 @@ _base64() { openssl base64 -e | tr -d '\n' } +_ss() { + _port="$1" + if command -v "netstat" >/dev/null 2>&1 ; then + _err "Using: netstat" + netstat -ntpl | grep :$_port" " + return 0 + fi + if command -v "ss" >/dev/null 2>&1 ; then + _err "Using: ss" + ss -ntpl | grep :$_port" " + return 0 + fi + return 1 +} + #domain [2048] createAccountKey() { _info "Creating account key" @@ -620,7 +635,7 @@ issue() { fi _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" - netprc="$(ss -ntpl | grep :$Le_HTTPPort" ")" + netprc="$(_ss "$Le_HTTPPort")" if [ "$netprc" ] ; then _err "$netprc" _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" From 251fc37c3daaa0b5423246a014301230bd9d4837 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 18:24:03 +0800 Subject: [PATCH 0037/1348] minor, change debug info --- le.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/le.sh b/le.sh index a5e06ab9..49618e64 100755 --- a/le.sh +++ b/le.sh @@ -66,12 +66,12 @@ _base64() { _ss() { _port="$1" if command -v "netstat" >/dev/null 2>&1 ; then - _err "Using: netstat" + _debug "Using: netstat" netstat -ntpl | grep :$_port" " return 0 fi if command -v "ss" >/dev/null 2>&1 ; then - _err "Using: ss" + _debug "Using: ss" ss -ntpl | grep :$_port" " return 0 fi @@ -635,7 +635,7 @@ issue() { fi _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" - netprc="$(_ss "$Le_HTTPPort")" + netprc="$(_ss "$Le_HTTPPort" | grep "$Le_HTTPPort")" if [ "$netprc" ] ; then _err "$netprc" _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" From 22514bee34541e5bb6d1944171c79bf597413106 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 19:30:47 +0800 Subject: [PATCH 0038/1348] add fedora --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7c8f955b..b910e235 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Do NOT require to be `root/sudoer`. 6. openSUSE 13 7. Alpine Linux (with bash, curl. https://github.com/Neilpang/le/issues/94) 8. Archlinux +9. fedora 21, 22, 23 If anyone want to test le on your system, you can simply run our test project: https://github.com/Neilpang/letest From 850c1128dfb52786b546354619a8037b8d817617 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 21:46:58 +0800 Subject: [PATCH 0039/1348] fix nc -q param for centos5 --- le.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/le.sh b/le.sh index 49618e64..ea693a40 100755 --- a/le.sh +++ b/le.sh @@ -354,11 +354,12 @@ _saveaccountconf() { _startserver() { content="$1" - _NC="nc -q 1 -l" - + nchelp="$(nc -h 2>&1)" - #centos - if echo "$nchelp" | grep "nmap.org/ncat" >/dev/null ; then + + if echo "$nchelp" | grep " \-q " >/dev/null ; then + _NC="nc -q 1 -l" + else _NC="nc -l" fi @@ -701,7 +702,7 @@ issue() { elif [ "$code" == '409' ] ; then _info "Already registered" else - _err "Register account Error." + _err "Register account Error: $response" _clearup return 1 fi From 0f4e8b0e69f26716e9f5e69dba5a3fc40bffc072 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 13 Mar 2016 22:08:28 +0800 Subject: [PATCH 0040/1348] minor --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index ea693a40..f6dc475a 100755 --- a/le.sh +++ b/le.sh @@ -357,7 +357,7 @@ _startserver() { nchelp="$(nc -h 2>&1)" - if echo "$nchelp" | grep " \-q " >/dev/null ; then + if echo "$nchelp" | grep "\-q " >/dev/null ; then _NC="nc -q 1 -l" else _NC="nc -l" From bac3b6b08d2a48f8956ddce59883a4cc033edda3 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 14 Mar 2016 22:36:11 +0800 Subject: [PATCH 0041/1348] minor --- le.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index f6dc475a..64918890 100755 --- a/le.sh +++ b/le.sh @@ -370,8 +370,8 @@ _startserver() { echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; fi else - if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null ; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null + if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 fi fi if [ "$?" != "0" ] ; then From 166096dc12009ec31ca821657abf471a34cf5068 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 15 Mar 2016 21:27:47 +0800 Subject: [PATCH 0042/1348] 1.1.9, do not register account key each time. compare the account key hash. --- le.sh | 176 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 127 insertions(+), 49 deletions(-) diff --git a/le.sh b/le.sh index 64918890..677236cb 100755 --- a/le.sh +++ b/le.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -VER=1.1.8 +VER=1.1.9 PROJECT="https://github.com/Neilpang/le" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" @@ -202,7 +202,7 @@ createCSR() { } -_b64() { +_urlencode() { __n=$(cat) echo $__n | tr '/+' '_-' | tr -d '= ' } @@ -232,21 +232,104 @@ _stat() { fi } +#keyfile +_calcjwk() { + keyfile="$1" + if [ -z "$keyfile" ] ; then + _err "Usage: _calcjwk keyfile" + return 1 + fi + EC_SIGN="" + if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then + _debug "RSA key" + pub_exp=$(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 + pub_exp=0$pub_exp + fi + _debug pub_exp "$pub_exp" + + e=$(echo $pub_exp | _h2b | _base64) + _debug e "$e" + + modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2 ) + n=$(echo $modulus| _h2b | _base64 | _urlencode ) + jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' + _debug jwk "$jwk" + + HEADER='{"alg": "RS256", "jwk": '$jwk'}' + HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' + elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then + _debug "EC key" + EC_SIGN="1" + crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" + _debug crv $crv + + pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + _debug pubi $pubi + let "pubi=pubi+1" + + pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + _debug pubj $pubj + let "pubj=pubj-1" + + pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + _debug pubtext "$pubtext" + + xlen="$(printf "$pubtext" | tr -d ':' | wc -c)" + let "xlen=xlen/4" + _debug xlen $xlen + + let "xend=xlen+1" + x="$(printf $pubtext | cut -d : -f 2-$xend)" + _debug x $x + + x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)" + _debug x64 $x64 + + let "xend+=1" + y="$(printf $pubtext | cut -d : -f $xend-10000)" + _debug y $y + + y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)" + _debug y64 $y64 + + jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}' + _debug jwk "$jwk" + + HEADER='{"alg": "ES256", "jwk": '$jwk'}' + HEADERPLACE='{"nonce": "NONCE", "alg": "ES256", "jwk": '$jwk'}' + + else + _err "Only RSA or EC key is supported." + return 1 + fi + + _debug HEADER "$HEADER" +} + +# url payload needbase64 keyfile _send_signed_request() { url=$1 payload=$2 needbase64=$3 - + keyfile=$4 + if [ -z "$keyfile" ] ; then + keyfile="$ACCOUNT_KEY_PATH" + fi _debug url $url _debug payload "$payload" + if ! _calcjwk "$keyfile" ; then + return 1 + fi + CURL_HEADER="$LE_WORKING_DIR/curl.header" dp="$LE_WORKING_DIR/curl.dump" CURL="curl --silent --dump-header $CURL_HEADER " if [ "$DEBUG" ] ; then CURL="$CURL --trace-ascii $dp " fi - payload64=$(echo -n $payload | _base64 | _b64) + payload64=$(echo -n $payload | _base64 | _urlencode) _debug payload64 $payload64 nonceurl="$API/directory" @@ -257,10 +340,10 @@ _send_signed_request() { protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" _debug protected "$protected" - protected64="$(printf "$protected" | _base64 | _b64)" + protected64="$(printf "$protected" | _base64 | _urlencode)" _debug protected64 "$protected64" - - sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY_PATH | _base64 | _b64) + + sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign "$keyfile" | _base64 | _urlencode) _debug sig "$sig" body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" @@ -656,7 +739,40 @@ issue() { fi createAccountKey $Le_Domain $Le_Keylength + + if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then + return 1 + fi + + accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) + thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _urlencode) + accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | openssl dgst -sha256 -binary | _base64)" + + if [ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ] ; then + _info "Registering account" + regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' + if [ "$ACCOUNT_EMAIL" ] ; then + regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' + fi + _send_signed_request "$API/acme/new-reg" "$regjson" + + if [ "$code" == "" ] || [ "$code" == '201' ] ; then + _info "Registered" + echo $response > $LE_WORKING_DIR/account.json + elif [ "$code" == '409' ] ; then + _info "Already registered" + else + _err "Register account Error: $response" + _clearup + return 1 + fi + ACCOUNT_KEY_HASH="$accountkeyhash" + _saveaccountconf "ACCOUNT_KEY_HASH" "$ACCOUNT_KEY_HASH" + else + _info "Skip register account key" + fi + if ! createDomainKey $Le_Domain $Le_Keylength ; then _err "Create domain key error." return 1 @@ -666,46 +782,6 @@ issue() { _err "Create CSR error." return 1 fi - - pub_exp=$(openssl rsa -in $ACCOUNT_KEY_PATH -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) - if [ "${#pub_exp}" == "5" ] ; then - pub_exp=0$pub_exp - fi - _debug pub_exp "$pub_exp" - - e=$(echo $pub_exp | _h2b | _base64) - _debug e "$e" - - modulus=$(openssl rsa -in $ACCOUNT_KEY_PATH -modulus -noout | cut -d '=' -f 2 ) - n=$(echo $modulus| _h2b | _base64 | _b64 ) - - jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' - - HEADER='{"alg": "RS256", "jwk": '$jwk'}' - HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' - _debug HEADER "$HEADER" - - accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) - thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _b64) - - - _info "Registering account" - regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ] ; then - regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' - fi - _send_signed_request "$API/acme/new-reg" "$regjson" - - if [ "$code" == "" ] || [ "$code" == '201' ] ; then - _info "Registered" - echo $response > $LE_WORKING_DIR/account.json - elif [ "$code" == '409' ] ; then - _info "Already registered" - else - _err "Register account Error: $response" - _clearup - return 1 - fi vtype="$VTYPE_HTTP" if [[ "$Le_Webroot" == "dns"* ]] ; then @@ -759,7 +835,7 @@ issue() { dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" - txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _b64)" + txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _urlencode)" _debug txt "$txt" #dns #1. check use api @@ -923,7 +999,7 @@ issue() { _clearup _info "Verify finished, start to sign." - der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _b64)" + der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _urlencode)" _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" @@ -1195,6 +1271,8 @@ _initconf() { #FORCE=1 # Force to issue cert #DEBUG=1 # Debug mode +#ACCOUNT_KEY_HASH=account key hash + #dns api ####################### #Cloudflare: From 387c2eab57bfeb93220960c34218a1203d1ba51f Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 16 Mar 2016 00:39:37 +0800 Subject: [PATCH 0043/1348] add CI status --- README.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b910e235..51895db0 100644 --- a/README.md +++ b/README.md @@ -11,18 +11,20 @@ Probably it's the smallest&easiest&smartest shell script to automatically issue Do NOT require to be `root/sudoer`. #Tested OS -1. Ubuntu/Debian. -2. CentOS 5, 6, 7 -3. Windows (cygwin with curl, openssl and crontab included) -4. FreeBSD with bash -5. pfsense with bash and curl -6. openSUSE 13 -7. Alpine Linux (with bash, curl. https://github.com/Neilpang/le/issues/94) -8. Archlinux -9. fedora 21, 22, 23 - - -If anyone want to test le on your system, you can simply run our test project: https://github.com/Neilpang/letest +1. Ubuntu ![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg) +2. Debian ![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg) +3. CentOS ![](https://cdn.rawgit.com/Neilpang/letest/master/status/centos-latest.svg) +4. Windows (cygwin with curl, openssl and crontab included) +5. FreeBSD with bash +6. pfsense with bash and curl +7. openSUSE 13 +8. Alpine Linux ![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg) (with bash, curl. https://github.com/Neilpang/le/issues/94) +9. Archlinux +10. fedora ![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg) + +For all the build status, check our daily build project: + +https://github.com/Neilpang/letest.git #Supported Mode 1. Webroot mode From 04eb75a1f79c777a00d4c42bd4e78a76d7ac1f7c Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 16 Mar 2016 19:24:48 +0800 Subject: [PATCH 0044/1348] add openSUSE CI status --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 51895db0..5f134aff 100644 --- a/README.md +++ b/README.md @@ -11,16 +11,16 @@ Probably it's the smallest&easiest&smartest shell script to automatically issue Do NOT require to be `root/sudoer`. #Tested OS -1. Ubuntu ![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg) -2. Debian ![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg) -3. CentOS ![](https://cdn.rawgit.com/Neilpang/letest/master/status/centos-latest.svg) +1. Ubuntu [![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) +2. Debian [![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) +3. CentOS [![](https://cdn.rawgit.com/Neilpang/letest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 4. Windows (cygwin with curl, openssl and crontab included) 5. FreeBSD with bash 6. pfsense with bash and curl -7. openSUSE 13 -8. Alpine Linux ![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg) (with bash, curl. https://github.com/Neilpang/le/issues/94) +7. openSUSE [![](https://cdn.rawgit.com/Neilpang/letest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) +8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with bash, curl. https://github.com/Neilpang/le/issues/94) 9. Archlinux -10. fedora ![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg) +10. fedora [![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) For all the build status, check our daily build project: From f76eb45217abeda0ffdbcd71b771b82afaa3079d Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 16 Mar 2016 22:20:47 +0800 Subject: [PATCH 0045/1348] compatible to GNU netcat --- le.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index 677236cb..c028e75f 100755 --- a/le.sh +++ b/le.sh @@ -443,10 +443,14 @@ _startserver() { if echo "$nchelp" | grep "\-q " >/dev/null ; then _NC="nc -q 1 -l" else - _NC="nc -l" + if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then + _NC="nc -c -l" + else + _NC="nc -l" + fi fi - _debug "$_NC $Le_HTTPPort" + _debug "_NC" "$_NC" # while true ; do if [ "$DEBUG" ] ; then if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then From bb4db3e9743d6945a2f4d51e1ae1ffeb215c7a75 Mon Sep 17 00:00:00 2001 From: colegatron Date: Wed, 16 Mar 2016 16:06:48 +0100 Subject: [PATCH 0046/1348] In case /home/ivan/.le points to a symlink, it does not displays the contents with a simple 'ls'. Added a slash to force list the folder content. --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index c028e75f..474f28f9 100755 --- a/le.sh +++ b/le.sh @@ -1097,7 +1097,7 @@ renewAll() { _initpath _info "renewAll" - for d in $(ls -F $LE_WORKING_DIR | grep [^.].*[.].*/$ ) ; do + for d in $(ls -F ${LE_WORKING_DIR}/ | grep [^.].*[.].*/$ ) ; do d=$(echo $d | cut -d '/' -f 1) _info "renew $d" From 2f06c8507bc34f2b04f66ffa50ce662c7d44d857 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 16 Mar 2016 23:10:20 +0800 Subject: [PATCH 0047/1348] add Archlinux CI status --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f134aff..d5305c19 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Do NOT require to be `root/sudoer`. 6. pfsense with bash and curl 7. openSUSE [![](https://cdn.rawgit.com/Neilpang/letest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with bash, curl. https://github.com/Neilpang/le/issues/94) -9. Archlinux +9. Archlinux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 10. fedora [![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) For all the build status, check our daily build project: From 88fab7d68e45a96924cb4f8d00461a31278a4183 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 17 Mar 2016 21:18:09 +0800 Subject: [PATCH 0048/1348] refactor openssl code --- le.sh | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 13 deletions(-) diff --git a/le.sh b/le.sh index 474f28f9..2f9585a1 100755 --- a/le.sh +++ b/le.sh @@ -10,6 +10,12 @@ STAGE_CA="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" +BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" +END_CSR="-----END CERTIFICATE REQUEST-----" + +BEGIN_CERT="-----BEGIN CERTIFICATE-----" +END_CERT="-----END CERTIFICATE-----" + if [ -z "$AGREEMENT" ] ; then AGREEMENT="$DEFAULT_AGREEMENT" fi @@ -59,8 +65,89 @@ _h2b() { done } +#Usage: file startline endline +_getfile() { + filename="$1" + startline="$2" + endline="$3" + if [ -z "$endline" ] ; then + _err "Usage: file startline endline" + return 1 + fi + + i="$(grep -n -- "$startline" $filename | cut -d : -f 1)" + if [ -z "$i" ] ; then + _err "Can not find start line: $startline" + return 1 + fi + let "i+=1" + _debug i $i + + j="$(grep -n -- "$endline" $filename | cut -d : -f 1)" + if [ -z "$j" ] ; then + _err "Can not find end line: $endline" + return 1 + fi + let "j-=1" + _debug j $j + + sed -n $i,${j}p "$filename" + +} + +#Usage: multiline _base64() { - openssl base64 -e | tr -d '\n' + if [ "$1" ] ; then + openssl base64 -e + else + openssl base64 -e | tr -d '\r\n' + fi +} + +#Usage: multiline +_dbase64() { + if [ "$1" ] ; then + openssl base64 -d -A + else + openssl base64 -d + fi +} + +#Usage: hashalg +#Output Base64-encoded digest +_digest() { + alg="$1" + if [ -z "$alg" ] ; then + _err "Usage: _digest hashalg" + return 1 + fi + + if [ "$alg" == "sha256" ] ; then + openssl dgst -sha256 -binary | _base64 + else + _err "$alg is not supported yet" + return 1 + fi + +} + +#Usage: keyfile hashalg +#Output: Base64-encoded signature value +_sign() { + keyfile="$1" + alg="$2" + if [ -z "$alg" ] ; then + _err "Usage: _sign keyfile hashalg" + return 1 + fi + + if [ "$alg" == "sha256" ] ; then + openssl dgst -sha256 -sign "$keyfile" | _base64 + else + _err "$alg is not supported yet" + return 1 + fi + } _ss() { @@ -343,7 +430,7 @@ _send_signed_request() { protected64="$(printf "$protected" | _base64 | _urlencode)" _debug protected64 "$protected64" - sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign "$keyfile" | _base64 | _urlencode) + sig=$(echo -n "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode) _debug sig "$sig" body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" @@ -749,9 +836,9 @@ issue() { fi accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) - thumbprint=$(echo -n "$accountkey_json" | openssl dgst -sha256 -binary | _base64 | _urlencode) + thumbprint=$(echo -n "$accountkey_json" | _digest "sha256" | _urlencode) - accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | openssl dgst -sha256 -binary | _base64)" + accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | _digest "sha256" )" if [ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ] ; then _info "Registering account" @@ -839,7 +926,7 @@ issue() { dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" - txt="$(echo -e -n $keyauthorization | openssl dgst -sha256 -binary | _base64 | _urlencode)" + txt="$(echo -e -n $keyauthorization | _digest "sha256" | _urlencode)" _debug txt "$txt" #dns #1. check use api @@ -1003,7 +1090,7 @@ issue() { _clearup _info "Verify finished, start to sign." - der="$(openssl req -in $CSR_PATH -outform DER | _base64 | _urlencode)" + der="$(_getfile "$CSR_PATH" "$BEGIN_CSR" "$END_CSR" | tr -d "\r\n" | _urlencode)" _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" @@ -1011,9 +1098,9 @@ issue() { _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" if [ "$Le_LinkCert" ] ; then - echo -----BEGIN CERTIFICATE----- > "$CERT_PATH" - curl --silent "$Le_LinkCert" | openssl base64 -e >> "$CERT_PATH" - echo -----END CERTIFICATE----- >> "$CERT_PATH" + echo "$BEGIN_CERT" > "$CERT_PATH" + curl --silent "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" + echo "$END_CERT" >> "$CERT_PATH" _info "Cert success." cat "$CERT_PATH" @@ -1023,7 +1110,7 @@ issue() { if [ -z "$Le_LinkCert" ] ; then - response="$(echo $response | openssl base64 -d -A)" + response="$(echo $response | _dbase64 "multiline" )" _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" return 1 fi @@ -1034,9 +1121,9 @@ issue() { _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ] ; then - echo -----BEGIN CERTIFICATE----- > "$CA_CERT_PATH" - curl --silent "$Le_LinkIssuer" | openssl base64 -e >> "$CA_CERT_PATH" - echo -----END CERTIFICATE----- >> "$CA_CERT_PATH" + echo "$BEGIN_CERT" > "$CA_CERT_PATH" + curl --silent "$Le_LinkIssuer" | _base64 "multiline" >> "$CA_CERT_PATH" + echo "$END_CERT" >> "$CA_CERT_PATH" _info "The intermediate CA cert is in $CA_CERT_PATH" cat "$CA_CERT_PATH" >> "$CERT_FULLCHAIN_PATH" _info "And the full chain certs is there: $CERT_FULLCHAIN_PATH" From c60883ef927a785286ca856550784bed5f11007d Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 19 Mar 2016 18:18:34 +0800 Subject: [PATCH 0049/1348] Use 'wget' instead, if 'curl' is not installed. --- le.sh | 205 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 130 insertions(+), 75 deletions(-) diff --git a/le.sh b/le.sh index 2f9585a1..79bc2740 100755 --- a/le.sh +++ b/le.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -VER=1.1.9 +VER=1.2.0 PROJECT="https://github.com/Neilpang/le" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" @@ -20,18 +20,6 @@ if [ -z "$AGREEMENT" ] ; then AGREEMENT="$DEFAULT_AGREEMENT" fi -_debug() { - - if [ -z "$DEBUG" ] ; then - return - fi - - if [ -z "$2" ] ; then - echo $1 - else - echo "$1"="$2" - fi -} _info() { if [ -z "$2" ] ; then @@ -50,6 +38,26 @@ _err() { return 1 } +_debug() { + if [ -z "$DEBUG" ] ; then + return + fi + _err "$1" "$2" + return 0 +} + +_exists() { + cmd="$1" + if [ -z "$cmd" ] ; then + _err "Usage: _exists cmd" + return 1 + fi + command -v $cmd >/dev/null 2>&1 + ret="$?" + _debug "$cmd exists=$ret" + return $ret +} + _h2b() { hex=$(cat) i=1 @@ -65,6 +73,25 @@ _h2b() { done } +#options file +_sed_i() { + options="$1" + filename="$2" + if [ -z "$filename" ] ; then + _err "Usage:_sed_i options filename" + return 1 + fi + + if sed -h 2>&1 | grep "\-i[SUFFIX]" ; then + _debug "Using sed -i" + sed -i "" + else + _debug "No -i support in sed" + text="$(cat $filename)" + echo "$text" | sed "$options" > "$filename" + fi +} + #Usage: file startline endline _getfile() { filename="$1" @@ -393,6 +420,57 @@ _calcjwk() { _debug HEADER "$HEADER" } +# body url [needbase64] +_post() { + body="$1" + url="$2" + needbase64="$3" + + if _exists "curl" ; then + dp="$LE_WORKING_DIR/curl.dump" + CURL="curl --silent --dump-header $HTTP_HEADER " + if [ "$DEBUG" ] ; then + CURL="$CURL --trace-ascii $dp " + fi + + if [ "$needbase64" ] ; then + response="$($CURL -X POST --data "$body" $url | _base64)" + else + response="$($CURL -X POST --data "$body" $url)" + fi + else + if [ "$needbase64" ] ; then + response="$(wget -q -S -O - --post-data="$body" $url 2>"$HTTP_HEADER" | _base64)" + else + response="$(wget -q -S -O - --post-data="$body" $url 2>"$HTTP_HEADER")" + fi + _sed_i "s/^ *//g" "$HTTP_HEADER" + fi + echo -n "$response" + +} + +# url getheader +_get() { + url="$1" + onlyheader="$2" + _debug url $url + if _exists "curl" ; then + if [ "$onlyheader" ] ; then + curl -I --silent $url + else + curl --silent $url + fi + else + if [ "$onlyheader" ] ; then + wget -S -q -O /dev/null $url 2>&1 | sed "s/^[ ]*//g" + else + wget -q -O - $url + fi + fi + ret=$? + return $ret +} # url payload needbase64 keyfile _send_signed_request() { @@ -409,18 +487,12 @@ _send_signed_request() { if ! _calcjwk "$keyfile" ; then return 1 fi - - CURL_HEADER="$LE_WORKING_DIR/curl.header" - dp="$LE_WORKING_DIR/curl.dump" - CURL="curl --silent --dump-header $CURL_HEADER " - if [ "$DEBUG" ] ; then - CURL="$CURL --trace-ascii $dp " - fi + payload64=$(echo -n $payload | _base64 | _urlencode) _debug payload64 $payload64 nonceurl="$API/directory" - nonce="$($CURL -I $nonceurl | grep -o "^Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)" + nonce="$(_get $nonceurl "onlyheader" | grep -o "Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)" _debug nonce "$nonce" @@ -436,31 +508,18 @@ _send_signed_request() { body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" _debug body "$body" - if [ "$needbase64" ] ; then - response="$($CURL -X POST --data "$body" $url | _base64)" - else - response="$($CURL -X POST --data "$body" $url)" - fi + HTTP_HEADER="$LE_WORKING_DIR/http.header" + response="$(_post "$body" $url "$needbase64" )" - responseHeaders="$(cat $CURL_HEADER)" + responseHeaders="$(cat $HTTP_HEADER)" _debug responseHeaders "$responseHeaders" _debug response "$response" - code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )" + code="$(grep "^HTTP" $HTTP_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )" _debug code $code } -_get() { - url="$1" - _debug url $url - response="$(curl --silent $url)" - ret=$? - _debug response "$response" - code="$(echo $response | grep -o '"status":[0-9]\+' | cut -d : -f 2)" - _debug code $code - return $ret -} #setopt "file" "opt" "=" "value" [";"] _setopt() { @@ -1040,7 +1099,7 @@ issue() { _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then - _err "$d:Challenge error: $resource" + _err "$d:Challenge error: $response" _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" _clearup return 1 @@ -1050,9 +1109,9 @@ issue() { _debug "sleep 5 secs to verify" sleep 5 _debug "checking" - - if ! _get $uri ; then - _err "$d:Verify error:$resource" + response="$(_get $uri)" + if [ "$?" != "0" ] ; then + _err "$d:Verify error:$response" _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" _clearup return 1 @@ -1094,12 +1153,12 @@ issue() { _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" - Le_LinkCert="$(grep -i -o '^Location.*$' $CURL_HEADER | tr -d "\r\n" | cut -d " " -f 2)" + Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | tr -d "\r\n" | cut -d " " -f 2)" _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" if [ "$Le_LinkCert" ] ; then echo "$BEGIN_CERT" > "$CERT_PATH" - curl --silent "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" + _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" echo "$END_CERT" >> "$CERT_PATH" _info "Cert success." cat "$CERT_PATH" @@ -1117,12 +1176,12 @@ issue() { _setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\"" - Le_LinkIssuer=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) + Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ] ; then echo "$BEGIN_CERT" > "$CA_CERT_PATH" - curl --silent "$Le_LinkIssuer" | _base64 "multiline" >> "$CA_CERT_PATH" + _get "$Le_LinkIssuer" | _base64 "multiline" >> "$CA_CERT_PATH" echo "$END_CERT" >> "$CA_CERT_PATH" _info "The intermediate CA cert is in $CA_CERT_PATH" cat "$CA_CERT_PATH" >> "$CERT_FULLCHAIN_PATH" @@ -1389,48 +1448,44 @@ _initconf() { fi } -install() { - if ! _initpath ; then - _err "Install failed." +_precheck() { + if ! _exists "curl" && ! _exists "wget"; then + _err "Please install curl or wget first, we need to access http resources." return 1 fi - #check if there is sudo installed, AND if the current user is a sudoer. - if command -v sudo > /dev/null ; then - if [ "$(sudo -n uptime 2>&1|grep "load"|wc -l)" != "0" ] ; then - SUDO=sudo - fi + if ! _exists "crontab" ; then + _err "Please install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." + _err "We need to set cron job to renew the certs automatically." + return 1 fi - if command -v yum > /dev/null ; then - YUM="1" - INSTALL="$SUDO yum install -y " - elif command -v apt-get > /dev/null ; then - INSTALL="$SUDO apt-get install -y " - fi - - if ! command -v "curl" > /dev/null ; then - _err "Please install curl first." - _err "$INSTALL curl" + if ! _exists "openssl" ; then + _err "Please install openssl first." + _err "We need openssl to generate keys." return 1 fi - if ! command -v "crontab" > /dev/null ; then - _err "Please install crontab first." - if [ "$YUM" ] ; then - _err "$INSTALL crontabs" - else - _err "$INSTALL crontab" - fi + if ! _exists "nc" ; then + _err "It is recommended to install nc first, try to install 'nc' or 'netcat'." + _err "We use nc for standalone server if you use standalone mode." + _err "If you don't use standalone mode, just ignore this warning." + fi + + return 0 +} + +install() { + if ! _initpath ; then + _err "Install failed." return 1 fi - if ! command -v "openssl" > /dev/null ; then - _err "Please install openssl first." - _err "$INSTALL openssl" + if ! _precheck ; then + _err "Pre-check failed, can not install." return 1 fi - + _info "Installing to $LE_WORKING_DIR" cp le.sh "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/le.sh" From bbbdcb091adcf018891a60fe48a7e0a2e81d10f6 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 19 Mar 2016 22:04:03 +0800 Subject: [PATCH 0050/1348] minor --- le.sh | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/le.sh b/le.sh index 79bc2740..bd1bb8d6 100755 --- a/le.sh +++ b/le.sh @@ -5,6 +5,8 @@ PROJECT="https://github.com/Neilpang/le" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" +DEFAULT_USER_AGENT="le.sh client: $PROJECT" + STAGE_CA="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" @@ -33,7 +35,7 @@ _err() { if [ -z "$2" ] ; then echo "$1" >&2 else - echo "$1"="$2" >&2 + echo "$1"="'$2'" >&2 fi return 1 } @@ -427,22 +429,17 @@ _post() { needbase64="$3" if _exists "curl" ; then - dp="$LE_WORKING_DIR/curl.dump" - CURL="curl --silent --dump-header $HTTP_HEADER " - if [ "$DEBUG" ] ; then - CURL="$CURL --trace-ascii $dp " - fi - + CURL="$CURL --dump-header $HTTP_HEADER " if [ "$needbase64" ] ; then - response="$($CURL -X POST --data "$body" $url | _base64)" + response="$($CURL -A "User-Agent: $USER_AGENT" -X POST --data "$body" $url | _base64)" else - response="$($CURL -X POST --data "$body" $url)" + response="$($CURL -A "User-Agent: $USER_AGENT" -X POST --data "$body" $url)" fi else if [ "$needbase64" ] ; then - response="$(wget -q -S -O - --post-data="$body" $url 2>"$HTTP_HEADER" | _base64)" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --post-data="$body" $url 2>"$HTTP_HEADER" | _base64)" else - response="$(wget -q -S -O - --post-data="$body" $url 2>"$HTTP_HEADER")" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --post-data="$body" $url 2>"$HTTP_HEADER")" fi _sed_i "s/^ *//g" "$HTTP_HEADER" fi @@ -457,15 +454,16 @@ _get() { _debug url $url if _exists "curl" ; then if [ "$onlyheader" ] ; then - curl -I --silent $url + $CURL -I -A "User-Agent: $USER_AGENT" $url else - curl --silent $url + $CURL -A "User-Agent: $USER_AGENT" $url fi else + _debug "WGET" "$WGET" if [ "$onlyheader" ] ; then - wget -S -q -O /dev/null $url 2>&1 | sed "s/^[ ]*//g" + eval $WGET --user-agent=\"$USER_AGENT\" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else - wget -q -O - $url + eval $WGET --user-agent=\"$USER_AGENT\" -O - $url fi fi ret=$? @@ -492,7 +490,7 @@ _send_signed_request() { _debug payload64 $payload64 nonceurl="$API/directory" - nonce="$(_get $nonceurl "onlyheader" | grep -o "Replay-Nonce:.*$" | tr -d "\r\n" | cut -d ' ' -f 2)" + nonce="$(_get $nonceurl "onlyheader" | grep -o "Replay-Nonce:.*$" | head -1 | tr -d "\r\n" | cut -d ' ' -f 2)" _debug nonce "$nonce" @@ -508,7 +506,7 @@ _send_signed_request() { body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" _debug body "$body" - HTTP_HEADER="$LE_WORKING_DIR/http.header" + response="$(_post "$body" $url "$needbase64" )" responseHeaders="$(cat $HTTP_HEADER)" @@ -650,6 +648,23 @@ _initpath() { APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/" fi + if [ -z "$USER_AGENT" ] ; then + USER_AGENT="$DEFAULT_USER_AGENT" + fi + + HTTP_HEADER="$LE_WORKING_DIR/http.header" + + WGET="wget -q" + if [ "$DEBUG" ] ; then + WGET="$WGET -d " + fi + + dp="$LE_WORKING_DIR/curl.dump" + CURL="curl --silent" + if [ "$DEBUG" ] ; then + CURL="$CURL --trace-ascii $dp " + fi + domain="$1" if ! mkdir -p "$LE_WORKING_DIR" ; then _err "Can not craete working dir: $LE_WORKING_DIR" @@ -1153,7 +1168,7 @@ issue() { _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" - Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | tr -d "\r\n" | cut -d " " -f 2)" + Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)" _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" if [ "$Le_LinkCert" ] ; then @@ -1176,7 +1191,7 @@ issue() { _setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\"" - Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) + Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ] ; then @@ -1423,6 +1438,7 @@ _initconf() { #ACCOUNT_KEY_HASH=account key hash +USER_AGENT=\"le.sh client: $PROJECT\" #dns api ####################### #Cloudflare: From d3d884c16f52301689955f4a4f38fc7ee1682daa Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 21 Mar 2016 20:35:19 +0800 Subject: [PATCH 0051/1348] Test on KaLi Linux --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d5305c19..e5afd09f 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Do NOT require to be `root/sudoer`. 8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with bash, curl. https://github.com/Neilpang/le/issues/94) 9. Archlinux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 10. fedora [![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) +11. Kali Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) For all the build status, check our daily build project: From ccb965359c40f2ebc6fa1377329813a4c5c97ac4 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Mar 2016 20:23:56 +0800 Subject: [PATCH 0052/1348] compatible for windows netstat tool --- le.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/le.sh b/le.sh index bd1bb8d6..6feac9be 100755 --- a/le.sh +++ b/le.sh @@ -183,7 +183,12 @@ _ss() { _port="$1" if command -v "netstat" >/dev/null 2>&1 ; then _debug "Using: netstat" - netstat -ntpl | grep :$_port" " + if netstat -h 2>&1 | grep "\-p proto" >/dev/null ; then + #for windows version netstat tool + netstat -nb -p tcp | grep :$_port" " + else + netstat -ntpl | grep :$_port" " + fi return 0 fi if command -v "ss" >/dev/null 2>&1 ; then From 50a4ef9cca02354f9f90d174be9123358d338207 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Mar 2016 20:39:20 +0800 Subject: [PATCH 0053/1348] minor fix --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 6feac9be..9c5936c4 100755 --- a/le.sh +++ b/le.sh @@ -185,7 +185,7 @@ _ss() { _debug "Using: netstat" if netstat -h 2>&1 | grep "\-p proto" >/dev/null ; then #for windows version netstat tool - netstat -nb -p tcp | grep :$_port" " + netstat -anb -p tcp | grep "LISTENING" | grep :$_port" " else netstat -ntpl | grep :$_port" " fi From edf08da6f38699675ac0271638558bce4cba5ecf Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Mar 2016 22:23:24 +0800 Subject: [PATCH 0054/1348] compatible for netstat on FreeBSD --- le.sh | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/le.sh b/le.sh index 9c5936c4..46f52ffa 100755 --- a/le.sh +++ b/le.sh @@ -181,21 +181,28 @@ _sign() { _ss() { _port="$1" - if command -v "netstat" >/dev/null 2>&1 ; then + + if _exists "ss" ; then + _debug "Using: ss" + ss -ntpl | grep :$_port" " + return 0 + fi + + if _exists "netstat" ; then _debug "Using: netstat" if netstat -h 2>&1 | grep "\-p proto" >/dev/null ; then #for windows version netstat tool netstat -anb -p tcp | grep "LISTENING" | grep :$_port" " else - netstat -ntpl | grep :$_port" " + if netstat -help 2>&1 | grep "-p protocol" >/dev/null ; then + netstat -an -p tcp | grep LISTEN | grep :$_port" " + else + netstat -ntpl | grep :$_port" " + fi fi return 0 fi - if command -v "ss" >/dev/null 2>&1 ; then - _debug "Using: ss" - ss -ntpl | grep :$_port" " - return 0 - fi + return 1 } From 14165e5a9b589787d2c431e5a52ced1b420008e8 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Mar 2016 22:41:24 +0800 Subject: [PATCH 0055/1348] minor --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 46f52ffa..06d8d2c0 100755 --- a/le.sh +++ b/le.sh @@ -194,7 +194,7 @@ _ss() { #for windows version netstat tool netstat -anb -p tcp | grep "LISTENING" | grep :$_port" " else - if netstat -help 2>&1 | grep "-p protocol" >/dev/null ; then + if netstat -help 2>&1 | grep "\-p protocol" >/dev/null ; then netstat -an -p tcp | grep LISTEN | grep :$_port" " else netstat -ntpl | grep :$_port" " From 6d60f2885203674efef5f05ad3d97a9b8ceb40fa Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Mar 2016 23:02:59 +0800 Subject: [PATCH 0056/1348] fix nc issue for freebsd --- le.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/le.sh b/le.sh index 06d8d2c0..184611c1 100755 --- a/le.sh +++ b/le.sh @@ -601,6 +601,8 @@ _startserver() { else if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then _NC="nc -c -l" + elif echo "$nchelp" | grep "\-N" |grep "Shutdown the network socket after EOF on stdin" >/dev/null ; then + _NC="nc -N -l" else _NC="nc -l" fi From 779e7ea0c8dc51d0eecc8447399ae786e3505a2f Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Mar 2016 23:26:26 +0800 Subject: [PATCH 0057/1348] Add CI status for Windows and FreeBSD --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e5afd09f..7ef33fca 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Do NOT require to be `root/sudoer`. 1. Ubuntu [![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 2. Debian [![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 3. CentOS [![](https://cdn.rawgit.com/Neilpang/letest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -4. Windows (cygwin with curl, openssl and crontab included) -5. FreeBSD with bash +4. Windows (cygwin with curl, openssl and crontab included) [![](https://cdn.rawgit.com/Neilpang/letest/master/status/windows.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) +5. FreeBSD with bash [![](https://cdn.rawgit.com/Neilpang/letest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 6. pfsense with bash and curl 7. openSUSE [![](https://cdn.rawgit.com/Neilpang/letest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with bash, curl. https://github.com/Neilpang/le/issues/94) From a34bd89f95aefc910f381e23ebcf717c86dd8b55 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 24 Mar 2016 22:32:43 +0800 Subject: [PATCH 0058/1348] Support Oracle Linux --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7ef33fca..a9ed443d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Do NOT require to be `root/sudoer`. 9. Archlinux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 10. fedora [![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 11. Kali Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) +12. Oracle Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) For all the build status, check our daily build project: From 4a0f23e2ad81e6573407c89a841a850426c4f738 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 27 Mar 2016 20:31:22 +0800 Subject: [PATCH 0059/1348] Install online, git is not need. --- le.sh | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/le.sh b/le.sh index 184611c1..2baf813e 100755 --- a/le.sh +++ b/le.sh @@ -674,16 +674,12 @@ _initpath() { fi dp="$LE_WORKING_DIR/curl.dump" - CURL="curl --silent" + CURL="curl -L --silent" if [ "$DEBUG" ] ; then - CURL="$CURL --trace-ascii $dp " + CURL="$CURL -L --trace-ascii $dp " fi domain="$1" - if ! mkdir -p "$LE_WORKING_DIR" ; then - _err "Can not craete working dir: $LE_WORKING_DIR" - return 1 - fi if [ -z "$ACCOUNT_KEY_PATH" ] ; then ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" @@ -1517,7 +1513,12 @@ install() { fi _info "Installing to $LE_WORKING_DIR" - + + if ! mkdir -p "$LE_WORKING_DIR" ; then + _err "Can not craete working dir: $LE_WORKING_DIR" + return 1 + fi + cp le.sh "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/le.sh" if [ "$?" != "0" ] ; then @@ -1614,6 +1615,36 @@ createCSR: " } +_installOnline() { + _info "Installing from online archive." + if [ ! "$BRANCH" ] ; then + BRANCH="master" + fi + _initpath + target="$PROJECT/archive/$BRANCH.tar.gz" + _info "Downloading $target" + localname="$BRANCH.tar.gz" + if ! _get "$target" > $localname ; then + _debug "Download error." + return 1 + fi + _info "Extracting $localname" + tar xzf $localname + cd "le-$BRANCH" + chmod +x le.sh + if ./le.sh install ; then + _info "Install success!" + fi + + cd .. + rm -rf "le-$BRANCH" + rm -f "$localname" +} + +if [ "$INSTALLONLINE" ] ; then + _installOnline $BRANCH + exit +fi if [ -z "$1" ] ; then showhelp From d1f97fc85f7b4707eb7b682ecd14110702c91982 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 27 Mar 2016 20:37:26 +0800 Subject: [PATCH 0060/1348] minor fix --- le.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/le.sh b/le.sh index 2baf813e..3d41864d 100755 --- a/le.sh +++ b/le.sh @@ -1642,6 +1642,7 @@ _installOnline() { } if [ "$INSTALLONLINE" ] ; then + INSTALLONLINE="" _installOnline $BRANCH exit fi From 90dda23f3345a6191faa2c99c1ddf5ccd10758b5 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 27 Mar 2016 20:43:32 +0800 Subject: [PATCH 0061/1348] Install online. --- README.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a9ed443d..c44b0ea8 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Just one script, to issue, renew your certificates automatically. Probably it's the smallest&easiest&smartest shell script to automatically issue & renew the free certificates from LetsEncrypt. -Do NOT require to be `root/sudoer`. +NOT require to be `root/sudoer`. #Tested OS 1. Ubuntu [![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) @@ -34,14 +34,30 @@ https://github.com/Neilpang/letest.git 3. Apache mode 4. Dns mode -#How to use +#How to install -1. Clone this project: https://github.com/Neilpang/le.git +1. Install online: -2. Install le: ``` +curl https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLONLINE=1 bash + +``` + +Or: +``` +wget -O - https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLONLINE=1 bash + +``` + + +2. Or, Install from git: +Clone this project: +``` +git clone https://github.com/Neilpang/le.git +cd le ./le.sh install ``` + You don't have to be root then, although it is recommended. Which does 3 jobs: From 7d91e35f5fa9120f4a426370314b0785899f2953 Mon Sep 17 00:00:00 2001 From: Aaron Bartell Date: Mon, 28 Mar 2016 13:06:43 -0500 Subject: [PATCH 0062/1348] Fix for parsing status in response The JSON `status` attribute wasn't being parsed and that caused the rest of the process to fail. I changed it to be like the other JSON parsing (i.e. `entry` and `token`) and it now works. --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 3d41864d..09097b3a 100755 --- a/le.sh +++ b/le.sh @@ -1142,7 +1142,7 @@ issue() { return 1 fi - status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | tr -d '"') + status=$(echo $response | egrep -o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') if [ "$status" == "valid" ] ; then _info "Success" _stopserver $serverproc From 77546ea5be778beb1a06a723ef8efc23670e340f Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 29 Mar 2016 21:49:18 +0800 Subject: [PATCH 0063/1348] Force to Install without crontab. --- le.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index 09097b3a..2971b219 100755 --- a/le.sh +++ b/le.sh @@ -1364,6 +1364,13 @@ installcert() { installcronjob() { _initpath + if ! _exists "crontab" ; then + _err "crontab doesn't exist, so, we can not install cron jobs." + _err "All your certs will not be renewed automatically." + _err "You must add your own cron job to call 'le.sh cron' everyday." + return 1 + fi + _info "Installing cron job" if ! crontab -l | grep 'le.sh cron' ; then if [ -f "$LE_WORKING_DIR/le.sh" ] ; then @@ -1481,9 +1488,14 @@ _precheck() { fi if ! _exists "crontab" ; then - _err "Please install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." + _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." _err "We need to set cron job to renew the certs automatically." - return 1 + _err "Otherwise, your certs will not be able to be renewed automatically." + if [ -z "$FORCE" ] ; then + _err "Please define 'FORCE=1' and try install again to go without crontab." + _err "FORCE=1 ./le.sh install" + return 1 + fi fi if ! _exists "openssl" ; then From 37db5b813156203a5003a3c02734f7f09041f786 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 29 Mar 2016 21:57:56 +0800 Subject: [PATCH 0064/1348] uninstall without crontab. --- le.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/le.sh b/le.sh index 2971b219..2ef8cf0d 100755 --- a/le.sh +++ b/le.sh @@ -1390,6 +1390,9 @@ installcronjob() { } uninstallcronjob() { + if ! _exists "crontab" ; then + return + fi _info "Removing cron job" cr="$(crontab -l | grep 'le.sh cron')" if [ "$cr" ] ; then From c09dc68b27951848d3a1f8125d37dd954cd4e3af Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 30 Mar 2016 19:10:58 +0800 Subject: [PATCH 0065/1348] minor, just upgrade to a new version number 1.2.1 --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 2ef8cf0d..4af0616a 100755 --- a/le.sh +++ b/le.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -VER=1.2.0 +VER=1.2.1 PROJECT="https://github.com/Neilpang/le" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" From fa8311dc6ed0cc7029291e9d638f50e47760c607 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 31 Mar 2016 20:42:17 +0800 Subject: [PATCH 0066/1348] minor --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 2ef8cf0d..0f7a1b8d 100755 --- a/le.sh +++ b/le.sh @@ -1174,7 +1174,7 @@ issue() { _clearup _info "Verify finished, start to sign." - der="$(_getfile "$CSR_PATH" "$BEGIN_CSR" "$END_CSR" | tr -d "\r\n" | _urlencode)" + der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)" _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" From 73b8b1201601ec6a9e7f9866c7249d22f5793d76 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 31 Mar 2016 21:28:54 +0800 Subject: [PATCH 0067/1348] use domain api in sub shell. --- le.sh | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/le.sh b/le.sh index 15b223e5..223c27ed 100755 --- a/le.sh +++ b/le.sh @@ -1040,20 +1040,26 @@ issue() { _err "so the resulting subdomain will be: $txtdomain" continue fi - - if ! source $d_api ; then - _err "Load file $d_api error. Please check your api file and try again." - return 1 - fi - addcommand="$Le_Webroot-add" - if ! command -v $addcommand ; then - _err "It seems that your api file is not correct, it must have a function named: $addcommand" - return 1 - fi + ( + if ! source $d_api ; then + _err "Load file $d_api error. Please check your api file and try again." + return 1 + fi + + addcommand="$Le_Webroot-add" + if ! command -v $addcommand ; then + _err "It seems that your api file is not correct, it must have a function named: $addcommand" + return 1 + fi + + if ! $addcommand $txtdomain $txt ; then + _err "Error add txt for domain:$txtdomain" + return 1 + fi + ) - if ! $addcommand $txtdomain $txt ; then - _err "Error add txt for domain:$txtdomain" + if [[ "$?" != "0" ]] ; then return 1 fi dnsadded='1' From ddc04a754902c59ddacf30f51481eaf69b5f0609 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 31 Mar 2016 21:40:52 +0800 Subject: [PATCH 0068/1348] CloudLinux passed. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c44b0ea8..57fb3160 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ NOT require to be `root/sudoer`. 10. fedora [![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 11. Kali Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 12. Oracle Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) +13. Cloud Linux https://github.com/Neilpang/le/issues/111 For all the build status, check our daily build project: From b7604c0647fe7ebdf2a0ffdaebc48fbd0b8d3ef5 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 31 Mar 2016 23:26:31 +0800 Subject: [PATCH 0069/1348] add Proxmox --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 57fb3160..99aa885f 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ NOT require to be `root/sudoer`. 11. Kali Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 12. Oracle Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 13. Cloud Linux https://github.com/Neilpang/le/issues/111 +14. Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_le.sh + For all the build status, check our daily build project: From 399306a1640c9a121a48f79751b84523337cbb63 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 1 Apr 2016 23:48:42 +0800 Subject: [PATCH 0070/1348] fix for Proxmox --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 223c27ed..86a05a37 100755 --- a/le.sh +++ b/le.sh @@ -596,7 +596,7 @@ _startserver() { nchelp="$(nc -h 2>&1)" - if echo "$nchelp" | grep "\-q " >/dev/null ; then + if echo "$nchelp" | grep "\-q[ ,]" >/dev/null ; then _NC="nc -q 1 -l" else if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then From 96a46cfcd5a35f2a647e714ab5c42cde9f253920 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Apr 2016 10:10:05 +0800 Subject: [PATCH 0071/1348] fix bug save the real params for renewing. --- le.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/le.sh b/le.sh index 86a05a37..1c110277 100755 --- a/le.sh +++ b/le.sh @@ -853,6 +853,15 @@ issue() { return 2 fi fi + + _setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain" + _setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt" + _setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot" + _setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength" + _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" + _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" + _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" if [ "$Le_Alt" == "no" ] ; then Le_Alt="" @@ -873,14 +882,7 @@ issue() { Le_ReloadCmd="" fi - _setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain" - _setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt" - _setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot" - _setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength" - _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" - _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" + if [ "$Le_Webroot" == "no" ] ; then _info "Standalone mode." From ed373617006bf9d9255025f86d406ea6369210ab Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Apr 2016 11:03:15 +0800 Subject: [PATCH 0072/1348] fix compatible --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 1c110277..4bad707d 100755 --- a/le.sh +++ b/le.sh @@ -1282,7 +1282,7 @@ renewAll() { Le_LinkCert="" Le_Domain="" - Le_Alt="" + Le_Alt="no" Le_Webroot="" Le_Keylength="" Le_LinkIssuer="" From d62ee94019cb16af6abca1187271f310fdbea215 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 4 Apr 2016 22:37:58 +0800 Subject: [PATCH 0073/1348] fix issue for apache mode: fix case when the httpdconf is absolute path. --- le.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index 4bad707d..b3ed7cab 100755 --- a/le.sh +++ b/le.sh @@ -723,9 +723,14 @@ _initpath() { _apachePath() { - httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" - httpdconf="$httpdroot/$httpdconfname" + if [[ "$httpdconfname" == '/'* ]] ; then + httpdconf="$httpdconfname" + else + httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" + httpdconf="$httpdroot/$httpdconfname" + fi + if [ ! -f $httpdconf ] ; then _err "Apache Config file not found" $httpdconf return 1 From 78552b183bfbb5fd4b40457f80bbba80f5fde426 Mon Sep 17 00:00:00 2001 From: BlueAnanas Date: Thu, 3 Mar 2016 14:51:07 +0100 Subject: [PATCH 0074/1348] Removed redundant backup in installcert when RealCACertPath == RealCertPath --- le.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/le.sh b/le.sh index b3ed7cab..cdefac4c 100755 --- a/le.sh +++ b/le.sh @@ -1349,13 +1349,13 @@ installcert() { fi if [ "$Le_RealCACertPath" ] ; then - if [ -f "$Le_RealCACertPath" ] ; then - cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak - fi if [ "$Le_RealCACertPath" == "$Le_RealCertPath" ] ; then echo "" >> "$Le_RealCACertPath" cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" else + if [ -f "$Le_RealCACertPath" ] ; then + cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak + fi cat "$CA_CERT_PATH" > "$Le_RealCACertPath" fi fi From c456d9543f31487531a8a1fa1f69b721dddad9b4 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 5 Apr 2016 19:10:56 +0800 Subject: [PATCH 0075/1348] fix httpdconfname to be the basename --- le.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/le.sh b/le.sh index b3ed7cab..7544f7f3 100755 --- a/le.sh +++ b/le.sh @@ -726,6 +726,7 @@ _apachePath() { httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" if [[ "$httpdconfname" == '/'* ]] ; then httpdconf="$httpdconfname" + httpdconfname="$(basename $httpdconfname)" else httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" httpdconf="$httpdroot/$httpdconfname" From df886ffa25ca2f4e97293ee94f60c51fa82c4513 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 5 Apr 2016 19:18:19 +0800 Subject: [PATCH 0076/1348] fix apache mode: It's not necessary to chown for apache mode. --- le.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/le.sh b/le.sh index 7544f7f3..f0626fc0 100755 --- a/le.sh +++ b/le.sh @@ -1127,10 +1127,11 @@ issue() { mkdir -p "$wellknown_path" echo -n "$keyauthorization" > "$wellknown_path/$token" - - webroot_owner=$(_stat $Le_Webroot) - _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R $webroot_owner "$Le_Webroot/.well-known" + if [[ ! "$usingApache" ]] ; then + webroot_owner=$(_stat $Le_Webroot) + _debug "Changing owner/group of .well-known to $webroot_owner" + chown -R $webroot_owner "$Le_Webroot/.well-known" + fi fi fi From 281aa3497ffa411da718878ad64b4273bb88aea0 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 5 Apr 2016 21:08:19 +0800 Subject: [PATCH 0077/1348] Save user's PATH for cron job. --- le.sh | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index f0626fc0..d6de4b7e 100755 --- a/le.sh +++ b/le.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -VER=1.2.1 +VER=1.2.2 PROJECT="https://github.com/Neilpang/le" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" @@ -585,7 +585,7 @@ _saveaccountconf() { key="$1" value="$2" if [ "$ACCOUNT_CONF_PATH" ] ; then - _setopt $ACCOUNT_CONF_PATH "$key" "=" "$value" + _setopt $ACCOUNT_CONF_PATH "$key" "=" "\"$value\"" else _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" fi @@ -645,6 +645,13 @@ _initpath() { source "$ACCOUNT_CONF_PATH" fi + if [[ "$IN_CRON" ]] ; then + if [[ ! "$_USER_PATH_EXPORTED" ]] ; then + _USER_PATH_EXPORTED=1 + export PATH="$USER_PATH:$PATH" + fi + fi + if [ -z "$API" ] ; then if [ -z "$STAGE" ] ; then API="$DEFAULT_CA" @@ -1205,6 +1212,11 @@ issue() { _info "Your cert is in $CERT_PATH" cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" + + if [[ ! "$USER_PATH" ]] || [[ ! "$IN_CRON" ]] ; then + USER_PATH="$PATH" + _saveaccountconf "USER_PATH" "$USER_PATH" + fi fi @@ -1474,6 +1486,9 @@ _initconf() { #ACCOUNT_KEY_HASH=account key hash USER_AGENT=\"le.sh client: $PROJECT\" + +#USER_PATH="" + #dns api ####################### #Cloudflare: @@ -1605,7 +1620,9 @@ uninstall() { } cron() { + IN_CRON=1 renewAll + IN_CRON="" } version() { From 8a144f4d972a28fbc69b0c2d19ba0e43e17f96a6 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 5 Apr 2016 21:17:04 +0800 Subject: [PATCH 0078/1348] minor, remove unnecessary '/' --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index d6de4b7e..8e5c0a72 100755 --- a/le.sh +++ b/le.sh @@ -666,7 +666,7 @@ _initpath() { fi if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then - APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR/" + APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR" fi if [ -z "$USER_AGENT" ] ; then From b09d597c845cd77b8ed1c21832805fb44e68b84c Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 5 Apr 2016 21:40:48 +0800 Subject: [PATCH 0079/1348] fix compatible: apache before 2.4 and after 2.4 --- le.sh | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/le.sh b/le.sh index a85c1329..cd814c84 100755 --- a/le.sh +++ b/le.sh @@ -783,13 +783,31 @@ _setApache() { _info "The backup file will be deleted on sucess, just forget it." #add alias - echo " + + apacheVer="$(apachectl -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2 )" + _debug "apacheVer" "$apacheVer" + apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)" + apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" + + if [[ "$apacheVer" ]] && [[ "$apacheMajer" -ge "2" ]] && [[ "$apacheMinor" -ge "4" ]] ; then + echo " Alias /.well-known/acme-challenge $ACME_DIR Require all granted + + " >> $httpdconf + else + echo " +Alias /.well-known/acme-challenge $ACME_DIR + + +Order allow,deny +Allow from all " >> $httpdconf + fi + if ! apachectl -t ; then _err "Sorry, apache config error, please contact me." From ac2d512327a970fbc96c52243b679ce1133715b2 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 5 Apr 2016 22:39:34 +0800 Subject: [PATCH 0080/1348] add command "toPkcs" to convert cert file to pfx file. --- le.sh | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index cd814c84..05097b2b 100755 --- a/le.sh +++ b/le.sh @@ -206,6 +206,28 @@ _ss() { return 1 } +toPkcs() { + domain="$1" + pfxPassword="$2" + if [[ -z "$domain" ]] ; then + _err "Usage: toPkcs domain [pfx-password]" + return 1 + fi + + _initpath "$domain" + + if [[ "$pfxPassword" ]] ; then + openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" + else + openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" + fi + + if [[ "$?" == "0" ]] ; then + _info "Success, Pfx is exported to: $CERT_PFX_PATH" + fi + +} + #domain [2048] createAccountKey() { _info "Creating account key" @@ -725,7 +747,9 @@ _initpath() { if [ -z "$CERT_FULLCHAIN_PATH" ] ; then CERT_FULLCHAIN_PATH="$domainhome/fullchain.cer" fi - + if [ -z "$CERT_PFX_PATH" ] ; then + CERT_PFX_PATH="$domainhome/$domain.pfx" + fi } @@ -1344,6 +1368,7 @@ renewAll() { CERT_KEY_PATH="" CERT_PATH="" CA_CERT_PATH="" + CERT_PFX_PATH="" CERT_FULLCHAIN_PATH="" ACCOUNT_KEY_PATH="" @@ -1651,7 +1676,7 @@ version() { showhelp() { version echo "Usage: le.sh [command] ...[args].... -Avalible commands: +Available commands: install: Install le.sh to your system. @@ -1671,6 +1696,8 @@ installcronjob: Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. uninstallcronjob: Uninstall the cron job. The 'uninstall' command can do this automatically. +toPkcs: + Export the certificate and key to a pfx file. createAccountKey: Create an account private key, professional use. createDomainKey: From 9dfd5a9c3127f1c46f9f6ebb47cc93dc09e536f6 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 5 Apr 2016 22:46:55 +0800 Subject: [PATCH 0081/1348] Add `toPkcs` doc --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 99aa885f..aa3004aa 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Show help message: ``` root@v1:~# le.sh https://github.com/Neilpang/le -v1.1.1 +v1.2.2 Usage: le.sh [command] ...[args].... Available commands: @@ -98,6 +98,8 @@ installcronjob: Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. uninstallcronjob: Uninstall the cron job. The 'uninstall' command can do this automatically. +toPkcs: + Export the certificate and key to a pfx file. createAccountKey: Create an account private key, professional use. createDomainKey: @@ -106,6 +108,7 @@ createCSR: Create CSR , professional use. + root@v1:~/le# le issue Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no From de9fd54e7638e95f26ab775ce45926c903bb4ba4 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 5 Apr 2016 22:48:33 +0800 Subject: [PATCH 0082/1348] add wiki link --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index aa3004aa..fdbf9fd9 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ Probably it's the smallest&easiest&smartest shell script to automatically issue NOT require to be `root/sudoer`. +Wiki: https://github.com/Neilpang/le/wiki + #Tested OS 1. Ubuntu [![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 2. Debian [![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) From 6cb415f57e9afd0b06b6ea236f5ab86278179127 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 6 Apr 2016 22:16:09 +0800 Subject: [PATCH 0083/1348] Support revoke cert --- README.md | 5 ++++- le.sh | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fdbf9fd9..a9f5966a 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Show help message: ``` root@v1:~# le.sh https://github.com/Neilpang/le -v1.2.2 +v1.2.3 Usage: le.sh [command] ...[args].... Available commands: @@ -94,6 +94,8 @@ renewAll: Renew all the certs. uninstall: Uninstall le.sh, and uninstall the cron job. +revoke: + Revoke a cert. version: Show version info. installcronjob: @@ -111,6 +113,7 @@ createCSR: + root@v1:~/le# le issue Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no diff --git a/le.sh b/le.sh index 05097b2b..c1fa62f2 100755 --- a/le.sh +++ b/le.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -VER=1.2.2 +VER=1.2.3 PROJECT="https://github.com/Neilpang/le" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" @@ -1474,6 +1474,60 @@ uninstallcronjob() { } +revoke() { + Le_Domain="$1" + if [ -z "$Le_Domain" ] ; then + _err "Usage: revoke domain.com" + return 1 + fi + + _initpath $Le_Domain + if [ ! -f "$DOMAIN_CONF" ] ; then + _err "$Le_Domain is not a issued domain, skip." + return 1; + fi + + if [ ! -f "$CERT_PATH" ] ; then + _err "Cert for $Le_Domain $CERT_PATH is not found, skip." + return 1 + fi + + cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}"| tr -d "\r\n" | _urlencode)" + + if [ -z "$cert" ] ; then + _err "Cert for $Le_Domain is empty found, skip." + return 1 + fi + + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" + uri="$API/acme/revoke-cert" + + _info "Try domain key first." + if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then + if [ -z "$response" ] ; then + _info "Revoke success." + rm -f $CERT_PATH + return 0 + else + _err "Revoke error by domain key." + _err "$resource" + fi + fi + + _info "Then try account key." + + if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH" ; then + if [ -z "$response" ] ; then + _info "Revoke success." + rm -f $CERT_PATH + return 0 + else + _err "Revoke error." + _debug "$resource" + fi + fi + return 1 +} # Detect profile file if not specified as environment variable _detect_profile() { @@ -1690,6 +1744,8 @@ renewAll: Renew all the certs. uninstall: Uninstall le.sh, and uninstall the cron job. +revoke: + Revoke a cert. version: Show version info. installcronjob: From a63b05a9e761eb7d89811be4b714d818dd7c76c0 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 9 Apr 2016 23:40:59 +0800 Subject: [PATCH 0084/1348] le.sh v2.0.0 1. Unix-like command api 2. 100% compatible with le.sh 1.x command api. 3. Support different webroot for each domain in the same cert. ``` le.sh --issue -d a.com -w /wwwroot/a.com -d b.com -w /wwwroot/b.com ``` 4. Support different authentication methods for each domain in the same cert. Hybrid usage: ``` le.sh --issue -d a.com -w /wwwroot/a.com -d b.com -dns dns-cf ``` 5. Two different debug levels to provide useful debug info. `--debug` or `--debug 2` 6. Support to install `fullchain.cer` after renewal. 7. Better performance. --- README.md | 144 ++++---- dnsapi/dns-cf.sh | 32 +- dnsapi/dns-cx.sh | 32 +- dnsapi/dns-dp.sh | 34 +- dnsapi/dns-myapi.sh | 43 +-- le.sh | 816 ++++++++++++++++++++++++++++++-------------- 6 files changed, 659 insertions(+), 442 deletions(-) diff --git a/README.md b/README.md index a9f5966a..e8d18386 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Clone this project: ``` git clone https://github.com/Neilpang/le.git cd le -./le.sh install +./le.sh --install ``` You don't have to be root then, although it is recommended. @@ -78,76 +78,73 @@ Show help message: ``` root@v1:~# le.sh https://github.com/Neilpang/le -v1.2.3 -Usage: le.sh [command] ...[args].... -Available commands: - -install: - Install le.sh to your system. -issue: - Issue a cert. -installcert: - Install the issued cert to apache/nginx or any other server. -renew: - Renew a cert. -renewAll: - Renew all the certs. -uninstall: - Uninstall le.sh, and uninstall the cron job. -revoke: - Revoke a cert. -version: - Show version info. -installcronjob: - Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. -uninstallcronjob: - Uninstall the cron job. The 'uninstall' command can do this automatically. -toPkcs: - Export the certificate and key to a pfx file. -createAccountKey: - Create an account private key, professional use. -createDomainKey: - Create an domain private key, professional use. -createCSR: - Create CSR , professional use. - - - - -root@v1:~/le# le issue -Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no +v2.0.0 +Usage: le.sh command ...[parameters].... +Commands: + --help, -h Show this help message. + --version, -v Show version info. + --install Install le.sh to your system. + --uninstall Uninstall le.sh, and uninstall the cron job. + --issue Issue a cert. + --installcert Install the issued cert to apache/nginx or any other server. + --renew, -r Renew a cert. + --renewAll Renew all the certs + --revoke Revoke a cert. + --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. + --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically. + --cron Run cron job to renew all the certs. + --toPkcs Export the certificate and key to a pfx file. + --createAccountKey, -cak Create an account private key, professional use. + --createDomainKey, -cdk Create an domain private key, professional use. + --createCSR, -ccsr Create CSR , professional use. + +Parameters: + --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. + --force, -f Used to force to install or force to renew a cert immediately. + --staging, --test Use staging server, just for test. + --debug Output debug info. + + --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. + --standalone Use standalone mode. + --apache Use apache mode. + --dns [dns-cf|dns-dp|dns-cx|/path/to/api/file] Use dns mode or dns api. + + --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. + --accountkeylength, -ak [2048] Specifies the account key length. + + 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. + --keypath /path/to/real/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. + --fullchainpath /path/to/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. + + --accountconf Specifies a customized account config file. + --leworkingdir Specifies the home dir for le.sh ``` - -Set the param value to "no" means you want to ignore it. - -For example, if you give "no" to "key-length", it will use default length 2048. - -And if you give 'no' to 'cert-file-path', it will not copy the issued cert to the "cert-file-path". - -In all the cases, the issued cert will be placed in "~/.le/domain.com/" - # Just issue a cert: Example 1: Only one domain: ``` -le issue /home/wwwroot/aa.com aa.com +le --issue -d aa.com -w /home/wwwroot/aa.com ``` Example 2: Multiple domains in the same cert: ``` -le issue /home/wwwroot/aa.com aa.com www.aa.com,cp.aa.com +le --issue -d aa.com -d www.aa.com -d cp.aa.com -w /home/wwwroot/aa.com ``` -First argument `/home/wwwroot/aa.com` is the web root folder, You must have `write` access to this folder. +The parameter `/home/wwwroot/aa.com` is the web root folder, You must have `write` access to this folder. Second argument "aa.com" is the main domain you want to issue cert for. - -Third argument is the additional domain list you want to use. Comma separated list, which is Optional. +You must have at least domain there. You must point and bind all the domains to the same webroot dir:`/home/wwwroot/aa.com` @@ -155,41 +152,60 @@ The cert will be placed in `~/.le/aa.com/` The issued cert will be renewed every 80 days automatically. + +More examples: https://github.com/Neilpang/le/wiki/How-to-issue-a-cert + + # Install issued cert to apache/nginx etc. +After you issue a cert, you probably want to install the cert to you nginx/apache or other servers to use. + ``` -le installcert aa.com /path/to/certfile/in/apache/nginx /path/to/keyfile/in/apache/nginx /path/to/ca/certfile/apache/nginx "service apache2|nginx reload" +le --installcert -d aa.com \ +--certpath /path/to/certfile/in/apache/nginx \ +--keypath /path/to/keyfile/in/apache/nginx \ +--capath /path/to/ca/certfile/apache/nginx \ +--fullchainpath path/to/fullchain/certfile/apache/nginx \ +--reloadcmd "service apache2|nginx reload" ``` +Only the domain is required, all the other parameters are optional. + Install the issued cert/key to the production apache or nginx path. The cert will be renewed every 80 days by default (which is configurable), Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload` -# Use Standalone server to issue cert (requires you be root/sudoer, or you have permission to listen tcp 80 port): +# Use Standalone server to issue cert +(requires you be root/sudoer, or you have permission to listen tcp 80 port): Same usage as all above, just give `no` as the webroot. The tcp `80` port must be free to listen, otherwise you will be prompted to free the `80` port and try again. ``` -le issue no aa.com www.aa.com,cp.aa.com +le --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com ``` -# Use Apache mode (requires you be root/sudoer, since it is required to interact with apache server): +More examples: https://github.com/Neilpang/le/wiki/How-to-issue-a-cert + + +# Use Apache mode +(requires you be root/sudoer, since it is required to interact with apache server): If you are running a web server, apache or nginx, it is recommended to use the Webroot mode. Particularly, if you are running an apache server, you can use apache mode instead. Which doesn't write any file to your web root folder. Just set string "apache" to the first argument, it will use apache plugin automatically. ``` -le issue apache aa.com www.aa.com,user.aa.com +le --issue --apache -d aa.com -d www.aa.com -d user.aa.com ``` -All the other arguments are the same with previous. + +More examples: https://github.com/Neilpang/le/wiki/How-to-issue-a-cert # Use DNS mode: -Support the latest dns-01 challenge. +Support the dns-01 challenge. ``` -le issue dns aa.com www.aa.com,user.aa.com +le --issue --dns -d aa.com -d www.aa.com -d user.aa.com ``` You will get the output like bellow: @@ -208,7 +224,7 @@ Please add those txt records to the domains. Waiting for the dns to take effect. Then just retry with 'renew' command: ``` -le renew aa.com +le --renew -d aa.com ``` Ok, it's finished. @@ -242,12 +258,12 @@ For example: Single domain: ``` -le issue /home/wwwroot/aa.com aa.com no ec-256 +le --issue -w /home/wwwroot/aa.com -d aa.com --keylength ec-256 ``` SAN multiple domains: ``` -le issue /home/wwwroot/aa.com aa.com www.aa.com,cp.aa.com ec-256 +le --issue -w /home/wwwroot/aa.com -d aa.com -d www.aa.com --keylength ec-256 ``` Please look at the last parameter above. diff --git a/dnsapi/dns-cf.sh b/dnsapi/dns-cf.sh index 159969d2..dc56bf13 100755 --- a/dnsapi/dns-cf.sh +++ b/dnsapi/dns-cf.sh @@ -134,38 +134,8 @@ _cf_rest() { _err "error $ep" return 1 fi - _debug response "$response" + _debug2 response "$response" return 0 } -_debug() { - - if [ -z "$DEBUG" ] ; then - return - fi - - if [ -z "$2" ] ; then - echo $1 - else - echo "$1"="$2" - fi -} - -_info() { - if [ -z "$2" ] ; then - echo "$1" - else - echo "$1"="$2" - fi -} - -_err() { - if [ -z "$2" ] ; then - echo "$1" >&2 - else - echo "$1"="$2" >&2 - fi -} - - diff --git a/dnsapi/dns-cx.sh b/dnsapi/dns-cx.sh index 07c9cf08..2a455a32 100644 --- a/dnsapi/dns-cx.sh +++ b/dnsapi/dns-cx.sh @@ -194,7 +194,7 @@ _rest() { _err "error $ep" return 1 fi - _debug response "$response" + _debug2 response "$response" if ! printf "$response" | grep '"message":"success"' > /dev/null ; then return 1 fi @@ -202,33 +202,3 @@ _rest() { } -_debug() { - - if [ -z "$DEBUG" ] ; then - return - fi - - if [ -z "$2" ] ; then - echo $1 - else - echo "$1"="$2" - fi -} - -_info() { - if [ -z "$2" ] ; then - echo "$1" - else - echo "$1"="$2" - fi -} - -_err() { - if [ -z "$2" ] ; then - echo "$1" >&2 - else - echo "$1"="$2" >&2 - fi -} - - diff --git a/dnsapi/dns-dp.sh b/dnsapi/dns-dp.sh index b39e3c40..f58b9d3a 100644 --- a/dnsapi/dns-dp.sh +++ b/dnsapi/dns-dp.sh @@ -182,7 +182,7 @@ _rest() { if [ "$3" ] ; then data="$3" - _debug data "$data" + _debug2 data "$data" response="$(curl --silent -X $m "$url" -d $data)" else response="$(curl --silent -X $m "$url" )" @@ -192,38 +192,8 @@ _rest() { _err "error $ep" return 1 fi - _debug response "$response" + _debug2 response "$response" return 0 } -_debug() { - - if [ -z "$DEBUG" ] ; then - return - fi - - if [ -z "$2" ] ; then - echo $1 - else - echo "$1"="$2" - fi -} - -_info() { - if [ -z "$2" ] ; then - echo "$1" - else - echo "$1"="$2" - fi -} - -_err() { - if [ -z "$2" ] ; then - echo "$1" >&2 - else - echo "$1"="$2" >&2 - fi -} - - diff --git a/dnsapi/dns-myapi.sh b/dnsapi/dns-myapi.sh index af7dda7a..9d53c7f7 100644 --- a/dnsapi/dns-myapi.sh +++ b/dnsapi/dns-myapi.sh @@ -25,37 +25,38 @@ dns-myapi-add() { - #################### Private functions bellow ################################## - -_debug() { - - if [ -z "$DEBUG" ] ; then - return - fi - - if [ -z "$2" ] ; then - echo $1 +_info() { + if [[ -z "$2" ]] ; then + echo "[$(date)] $1" else - echo "$1"="$2" + echo "[$(date)] $1"="'$2'" fi } -_info() { - if [ -z "$2" ] ; then - echo "$1" - else - echo "$1"="$2" +_err() { + _info "$@" >&2 + return 1 +} + +_debug() { + if [[ -z "$DEBUG" ]] ; then + return fi + _err "$@" + return 0 } -_err() { - if [ -z "$2" ] ; then - echo "$1" >&2 - else - echo "$1"="$2" >&2 +_debug2() { + if [[ "$DEBUG" -ge "2" ]] ; then + _debug "$@" fi + return } + + +#################### Private functions bellow ################################## + diff --git a/le.sh b/le.sh index c1fa62f2..afd7a110 100755 --- a/le.sh +++ b/le.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -VER=1.2.3 +VER=2.0.0 PROJECT="https://github.com/Neilpang/le" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" @@ -18,45 +18,48 @@ END_CSR="-----END CERTIFICATE REQUEST-----" BEGIN_CERT="-----BEGIN CERTIFICATE-----" END_CERT="-----END CERTIFICATE-----" -if [ -z "$AGREEMENT" ] ; then +if [[ -z "$AGREEMENT" ]] ; then AGREEMENT="$DEFAULT_AGREEMENT" fi _info() { - if [ -z "$2" ] ; then - echo "$1" + if [[ -z "$2" ]] ; then + echo "[$(date)] $1" else - echo "$1"="$2" + echo "[$(date)] $1"="'$2'" fi } _err() { - if [ -z "$2" ] ; then - echo "$1" >&2 - else - echo "$1"="'$2'" >&2 - fi + _info "$@" >&2 return 1 } _debug() { - if [ -z "$DEBUG" ] ; then + if [[ -z "$DEBUG" ]] ; then return fi - _err "$1" "$2" + _err "$@" return 0 } +_debug2() { + if [[ "$DEBUG" -ge "2" ]] ; then + _debug "$@" + fi + return +} + _exists() { cmd="$1" - if [ -z "$cmd" ] ; then + if [[ -z "$cmd" ]] ; then _err "Usage: _exists cmd" return 1 fi command -v $cmd >/dev/null 2>&1 ret="$?" - _debug "$cmd exists=$ret" + _debug2 "$cmd exists=$ret" return $ret } @@ -66,7 +69,7 @@ _h2b() { j=2 while [ '1' ] ; do h=$(printf $hex | cut -c $i-$j) - if [ -z "$h" ] ; then + if [[ -z "$h" ]] ; then break; fi printf "\x$h" @@ -79,7 +82,7 @@ _h2b() { _sed_i() { options="$1" filename="$2" - if [ -z "$filename" ] ; then + if [[ -z "$filename" ]] ; then _err "Usage:_sed_i options filename" return 1 fi @@ -99,13 +102,13 @@ _getfile() { filename="$1" startline="$2" endline="$3" - if [ -z "$endline" ] ; then + if [[ -z "$endline" ]] ; then _err "Usage: file startline endline" return 1 fi i="$(grep -n -- "$startline" $filename | cut -d : -f 1)" - if [ -z "$i" ] ; then + if [[ -z "$i" ]] ; then _err "Can not find start line: $startline" return 1 fi @@ -113,7 +116,7 @@ _getfile() { _debug i $i j="$(grep -n -- "$endline" $filename | cut -d : -f 1)" - if [ -z "$j" ] ; then + if [[ -z "$j" ]] ; then _err "Can not find end line: $endline" return 1 fi @@ -126,7 +129,7 @@ _getfile() { #Usage: multiline _base64() { - if [ "$1" ] ; then + if [[ "$1" ]] ; then openssl base64 -e else openssl base64 -e | tr -d '\r\n' @@ -135,7 +138,7 @@ _base64() { #Usage: multiline _dbase64() { - if [ "$1" ] ; then + if [[ "$1" ]] ; then openssl base64 -d -A else openssl base64 -d @@ -146,12 +149,12 @@ _dbase64() { #Output Base64-encoded digest _digest() { alg="$1" - if [ -z "$alg" ] ; then + if [[ -z "$alg" ]] ; then _err "Usage: _digest hashalg" return 1 fi - if [ "$alg" == "sha256" ] ; then + if [[ "$alg" == "sha256" ]] ; then openssl dgst -sha256 -binary | _base64 else _err "$alg is not supported yet" @@ -165,12 +168,12 @@ _digest() { _sign() { keyfile="$1" alg="$2" - if [ -z "$alg" ] ; then + if [[ -z "$alg" ]] ; then _err "Usage: _sign keyfile hashalg" return 1 fi - if [ "$alg" == "sha256" ] ; then + if [[ "$alg" == "sha256" ]] ; then openssl dgst -sha256 -sign "$keyfile" | _base64 else _err "$alg is not supported yet" @@ -210,7 +213,7 @@ toPkcs() { domain="$1" pfxPassword="$2" if [[ -z "$domain" ]] ; then - _err "Usage: toPkcs domain [pfx-password]" + echo "Usage: le.sh --toPkcs -d domain [--password pfx-password]" return 1 fi @@ -231,8 +234,8 @@ toPkcs() { #domain [2048] createAccountKey() { _info "Creating account key" - if [ -z "$1" ] ; then - echo Usage: createAccountKey account-domain [2048] + if [[ -z "$1" ]] ; then + echo Usage: le.sh --createAccountKey -d domain.com [--accountkeylength 2048] return fi @@ -243,13 +246,13 @@ createAccountKey() { length=2048 fi - if [ -z "$2" ] ; then + if [[ -z "$2" ]] ; then _info "Use default length 2048" length=2048 fi _initpath - if [ -f "$ACCOUNT_KEY_PATH" ] ; then + if [[ -f "$ACCOUNT_KEY_PATH" ]] ; then _info "Account key exists, skip" return else @@ -262,8 +265,8 @@ createAccountKey() { #domain length createDomainKey() { _info "Creating domain key" - if [ -z "$1" ] ; then - echo Usage: createDomainKey domain [2048] + if [[ -z "$1" ]] ; then + echo Usage: le.sh --createDomainKey -d domain.com [ --keylength 2048 ] return fi @@ -276,8 +279,8 @@ createDomainKey() { eccname="$length" fi - if [ -z "$length" ] ; then - if [ "$isec" ] ; then + if [[ -z "$length" ]] ; then + if [[ "$isec" ]] ; then length=256 else length=2048 @@ -285,14 +288,14 @@ createDomainKey() { fi _info "Use length $length" - if [ "$isec" ] ; then - if [ "$length" == "256" ] ; then + if [[ "$isec" ]] ; then + if [[ "$length" == "256" ]] ; then eccname="prime256v1" fi - if [ "$length" == "384" ] ; then + if [[ "$length" == "384" ]] ; then eccname="secp384r1" fi - if [ "$length" == "521" ] ; then + if [[ "$length" == "521" ]] ; then eccname="secp521r1" fi _info "Using ec name: $eccname" @@ -300,15 +303,15 @@ createDomainKey() { _initpath $domain - if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then + if [[ ! -f "$CERT_KEY_PATH" ]] || ( [[ "$FORCE" ]] && ! [[ "$IS_RENEW" ]] ); then #generate account key - if [ "$isec" ] ; then + if [[ "$isec" ]] ; then openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH" else openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH" fi else - if [ "$IS_RENEW" ] ; then + if [[ "$IS_RENEW" ]] ; then _info "Domain key exists, skip" return 0 else @@ -323,8 +326,8 @@ createDomainKey() { # domain domainlist createCSR() { _info "Creating csr" - if [ -z "$1" ] ; then - echo Usage: $0 domain [domainlist] + if [[ -z "$1" ]] ; then + echo Usage: le.sh --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ] return fi domain=$1 @@ -332,12 +335,12 @@ createCSR() { domainlist=$2 - if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && ! [ "$FORCE" ]; then + if [[ -f "$CSR_PATH" ]] && [[ "$IS_RENEW" ]] && [[ -z "$FORCE" ]]; then _info "CSR exists, skip" return fi - if [ -z "$domainlist" ] ; then + if [[ -z "$domainlist" ]] || [[ "$domainlist" == "no" ]]; then #single domain _info "Single domain" $domain printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$DOMAIN_SSL_CONF" @@ -385,7 +388,7 @@ _stat() { #keyfile _calcjwk() { keyfile="$1" - if [ -z "$keyfile" ] ; then + if [[ -z "$keyfile" ]] ; then _err "Usage: _calcjwk keyfile" return 1 fi @@ -393,18 +396,18 @@ _calcjwk() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "RSA key" pub_exp=$(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 fi - _debug pub_exp "$pub_exp" + _debug2 pub_exp "$pub_exp" e=$(echo $pub_exp | _h2b | _base64) - _debug e "$e" + _debug2 e "$e" modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2 ) n=$(echo $modulus| _h2b | _base64 | _urlencode ) jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' - _debug jwk "$jwk" + _debug2 jwk "$jwk" HEADER='{"alg": "RS256", "jwk": '$jwk'}' HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' @@ -412,39 +415,39 @@ _calcjwk() { _debug "EC key" EC_SIGN="1" crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" - _debug crv $crv + _debug2 crv $crv pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" - _debug pubi $pubi + _debug2 pubi $pubi let "pubi=pubi+1" pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" - _debug pubj $pubj + _debug2 pubj $pubj let "pubj=pubj-1" pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" - _debug pubtext "$pubtext" + _debug2 pubtext "$pubtext" xlen="$(printf "$pubtext" | tr -d ':' | wc -c)" let "xlen=xlen/4" - _debug xlen $xlen + _debug2 xlen $xlen let "xend=xlen+1" x="$(printf $pubtext | cut -d : -f 2-$xend)" - _debug x $x + _debug2 x $x x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)" - _debug x64 $x64 + _debug2 x64 $x64 let "xend+=1" y="$(printf $pubtext | cut -d : -f $xend-10000)" - _debug y $y + _debug2 y $y y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)" - _debug y64 $y64 + _debug2 y64 $y64 jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}' - _debug jwk "$jwk" + _debug2 jwk "$jwk" HEADER='{"alg": "ES256", "jwk": '$jwk'}' HEADERPLACE='{"nonce": "NONCE", "alg": "ES256", "jwk": '$jwk'}' @@ -454,7 +457,7 @@ _calcjwk() { return 1 fi - _debug HEADER "$HEADER" + _debug2 HEADER "$HEADER" } # body url [needbase64] _post() { @@ -464,13 +467,13 @@ _post() { if _exists "curl" ; then CURL="$CURL --dump-header $HTTP_HEADER " - if [ "$needbase64" ] ; then + if [[ "$needbase64" ]] ; then response="$($CURL -A "User-Agent: $USER_AGENT" -X POST --data "$body" $url | _base64)" else response="$($CURL -A "User-Agent: $USER_AGENT" -X POST --data "$body" $url)" fi else - if [ "$needbase64" ] ; then + if [[ "$needbase64" ]] ; then response="$($WGET -S -O - --user-agent="$USER_AGENT" --post-data="$body" $url 2>"$HTTP_HEADER" | _base64)" else response="$($WGET -S -O - --user-agent="$USER_AGENT" --post-data="$body" $url 2>"$HTTP_HEADER")" @@ -487,14 +490,14 @@ _get() { onlyheader="$2" _debug url $url if _exists "curl" ; then - if [ "$onlyheader" ] ; then + if [[ "$onlyheader" ]] ; then $CURL -I -A "User-Agent: $USER_AGENT" $url else $CURL -A "User-Agent: $USER_AGENT" $url fi else _debug "WGET" "$WGET" - if [ "$onlyheader" ] ; then + if [[ "$onlyheader" ]] ; then eval $WGET --user-agent=\"$USER_AGENT\" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else eval $WGET --user-agent=\"$USER_AGENT\" -O - $url @@ -510,7 +513,7 @@ _send_signed_request() { payload=$2 needbase64=$3 keyfile=$4 - if [ -z "$keyfile" ] ; then + if [[ -z "$keyfile" ]] ; then keyfile="$ACCOUNT_KEY_PATH" fi _debug url $url @@ -521,7 +524,7 @@ _send_signed_request() { fi payload64=$(echo -n $payload | _base64 | _urlencode) - _debug payload64 $payload64 + _debug2 payload64 $payload64 nonceurl="$API/directory" nonce="$(_get $nonceurl "onlyheader" | grep -o "Replay-Nonce:.*$" | head -1 | tr -d "\r\n" | cut -d ' ' -f 2)" @@ -529,24 +532,24 @@ _send_signed_request() { _debug nonce "$nonce" protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" - _debug protected "$protected" + _debug2 protected "$protected" protected64="$(printf "$protected" | _base64 | _urlencode)" - _debug protected64 "$protected64" + _debug2 protected64 "$protected64" sig=$(echo -n "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode) - _debug sig "$sig" + _debug2 sig "$sig" body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - _debug body "$body" + _debug2 body "$body" response="$(_post "$body" $url "$needbase64" )" responseHeaders="$(cat $HTTP_HEADER)" - _debug responseHeaders "$responseHeaders" - _debug response "$response" + _debug2 responseHeaders "$responseHeaders" + _debug2 response "$response" code="$(grep "^HTTP" $HTTP_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )" _debug code $code @@ -560,16 +563,16 @@ _setopt() { __sep="$3" __val="$4" __end="$5" - if [ -z "$__opt" ] ; then + if [[ -z "$__opt" ]] ; then echo usage: _setopt '"file" "opt" "=" "value" [";"]' return fi - if [ ! -f "$__conf" ] ; then + if [[ ! -f "$__conf" ]] ; then touch "$__conf" fi if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then - _debug OK + _debug2 OK if [[ "$__val" == *"&"* ]] ; then __val="$(echo $__val | sed 's/&/\\&/g')" fi @@ -584,7 +587,7 @@ _setopt() { echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" else - _debug APP + _debug2 APP echo "$__opt$__sep$__val$__end" >> "$__conf" fi _debug "$(grep -H -n "^$__opt$__sep" $__conf)" @@ -595,7 +598,7 @@ _setopt() { _savedomainconf() { key="$1" value="$2" - if [ "$DOMAIN_CONF" ] ; then + if [[ "$DOMAIN_CONF" ]] ; then _setopt $DOMAIN_CONF "$key" "=" "$value" else _err "DOMAIN_CONF is empty, can not save $key=$value" @@ -606,7 +609,7 @@ _savedomainconf() { _saveaccountconf() { key="$1" value="$2" - if [ "$ACCOUNT_CONF_PATH" ] ; then + if [[ "$ACCOUNT_CONF_PATH" ]] ; then _setopt $ACCOUNT_CONF_PATH "$key" "=" "\"$value\"" else _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" @@ -632,7 +635,7 @@ _startserver() { _debug "_NC" "$_NC" # while true ; do - if [ "$DEBUG" ] ; then + if [[ "$DEBUG" ]] ; then if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; fi @@ -641,7 +644,7 @@ _startserver() { echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 fi fi - if [ "$?" != "0" ] ; then + if [[ "$?" != "0" ]] ; then _err "nc listen error." return 1 fi @@ -655,15 +658,15 @@ _stopserver() { _initpath() { - if [ -z "$LE_WORKING_DIR" ]; then + if [[ -z "$LE_WORKING_DIR" ]] ; then LE_WORKING_DIR=$HOME/.le fi - if [ -z "$ACCOUNT_CONF_PATH" ] ; then + if [[ -z "$ACCOUNT_CONF_PATH" ]] ; then ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" fi - if [ -f "$ACCOUNT_CONF_PATH" ] ; then + if [[ -f "$ACCOUNT_CONF_PATH" ]] ; then source "$ACCOUNT_CONF_PATH" fi @@ -674,8 +677,8 @@ _initpath() { fi fi - if [ -z "$API" ] ; then - if [ -z "$STAGE" ] ; then + if [[ -z "$API" ]] ; then + if [[ -z "$STAGE" ]] ; then API="$DEFAULT_CA" else API="$STAGE_CA" @@ -683,71 +686,71 @@ _initpath() { fi fi - if [ -z "$ACME_DIR" ] ; then + if [[ -z "$ACME_DIR" ]] ; then ACME_DIR="/home/.acme" fi - if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then + if [[ -z "$APACHE_CONF_BACKUP_DIR" ]] ; then APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR" fi - if [ -z "$USER_AGENT" ] ; then + if [[ -z "$USER_AGENT" ]] ; then USER_AGENT="$DEFAULT_USER_AGENT" fi HTTP_HEADER="$LE_WORKING_DIR/http.header" WGET="wget -q" - if [ "$DEBUG" ] ; then + if [[ "$DEBUG" -ge "2" ]] ; then WGET="$WGET -d " fi dp="$LE_WORKING_DIR/curl.dump" CURL="curl -L --silent" - if [ "$DEBUG" ] ; then + if [[ "$DEBUG" -ge "2" ]] ; then CURL="$CURL -L --trace-ascii $dp " fi domain="$1" - if [ -z "$ACCOUNT_KEY_PATH" ] ; then + if [[ -z "$ACCOUNT_KEY_PATH" ]] ; then ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" fi - if [ -z "$domain" ] ; then + if [[ -z "$domain" ]] ; then return 0 fi domainhome="$LE_WORKING_DIR/$domain" mkdir -p "$domainhome" - if [ -z "$DOMAIN_PATH" ] ; then + if [[ -z "$DOMAIN_PATH" ]] ; then DOMAIN_PATH="$domainhome" fi - if [ -z "$DOMAIN_CONF" ] ; then + if [[ -z "$DOMAIN_CONF" ]] ; then DOMAIN_CONF="$domainhome/$domain.conf" fi - if [ -z "$DOMAIN_SSL_CONF" ] ; then + if [[ -z "$DOMAIN_SSL_CONF" ]] ; then DOMAIN_SSL_CONF="$domainhome/$domain.ssl.conf" fi - if [ -z "$CSR_PATH" ] ; then + if [[ -z "$CSR_PATH" ]] ; then CSR_PATH="$domainhome/$domain.csr" fi - if [ -z "$CERT_KEY_PATH" ] ; then + if [[ -z "$CERT_KEY_PATH" ]] ; then CERT_KEY_PATH="$domainhome/$domain.key" fi - if [ -z "$CERT_PATH" ] ; then + if [[ -z "$CERT_PATH" ]] ; then CERT_PATH="$domainhome/$domain.cer" fi - if [ -z "$CA_CERT_PATH" ] ; then + if [[ -z "$CA_CERT_PATH" ]] ; then CA_CERT_PATH="$domainhome/ca.cer" fi - if [ -z "$CERT_FULLCHAIN_PATH" ] ; then + if [[ -z "$CERT_FULLCHAIN_PATH" ]] ; then CERT_FULLCHAIN_PATH="$domainhome/fullchain.cer" fi - if [ -z "$CERT_PFX_PATH" ] ; then + if [[ -z "$CERT_PFX_PATH" ]] ; then CERT_PFX_PATH="$domainhome/$domain.pfx" fi } @@ -763,7 +766,7 @@ _apachePath() { httpdconf="$httpdroot/$httpdconfname" fi - if [ ! -f $httpdconf ] ; then + if [[ ! -f $httpdconf ]] ; then _err "Apache Config file not found" $httpdconf return 1 fi @@ -771,7 +774,7 @@ _apachePath() { } _restoreApache() { - if [ -z "$usingApache" ] ; then + if [[ -z "$usingApache" ]] ; then return 0 fi _initpath @@ -779,7 +782,7 @@ _restoreApache() { return 1 fi - if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then + if [[ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]] ; then _debug "No config file to restore." return 0 fi @@ -839,7 +842,7 @@ Allow from all return 1; fi - if [ ! -d "$ACME_DIR" ] ; then + if [[ ! -d "$ACME_DIR" ]] ; then mkdir -p "$ACME_DIR" chmod 755 "$ACME_DIR" fi @@ -862,18 +865,18 @@ _clearup () { # webroot removelevel tokenfile _clearupwebbroot() { __webroot="$1" - if [ -z "$__webroot" ] ; then + if [[ -z "$__webroot" ]] ; then _debug "no webroot specified, skip" return 0 fi - if [ "$2" == '1' ] ; then + if [[ "$2" == '1' ]] ; then _debug "remove $__webroot/.well-known" rm -rf "$__webroot/.well-known" - elif [ "$2" == '2' ] ; then + elif [[ "$2" == '2' ]] ; then _debug "remove $__webroot/.well-known/acme-challenge" rm -rf "$__webroot/.well-known/acme-challenge" - elif [ "$2" == '3' ] ; then + elif [[ "$2" == '3' ]] ; then _debug "remove $__webroot/.well-known/acme-challenge/$3" rm -rf "$__webroot/.well-known/acme-challenge/$3" else @@ -885,8 +888,8 @@ _clearupwebbroot() { } issue() { - if [ -z "$2" ] ; then - _err "Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no" + if [[ -z "$2" ]] ; then + echo "Usage: le --issue -d a.com -w /path/to/webroot/a.com/ " return 1 fi Le_Webroot="$1" @@ -897,13 +900,13 @@ issue() { Le_RealKeyPath="$6" Le_RealCACertPath="$7" Le_ReloadCmd="$8" - + Le_RealFullChainPath="$9" _initpath $Le_Domain - if [ -f "$DOMAIN_CONF" ] ; then + if [[ -f "$DOMAIN_CONF" ]] ; then Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2) - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then + if [[ -z "$FORCE" ]] && [[ "$Le_NextRenewTime" ]] && [[ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ]] ; then _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" return 2 fi @@ -917,42 +920,45 @@ issue() { _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" + _setopt "$DOMAIN_CONF" "Le_RealFullChainPath" "=" "\"$Le_RealFullChainPath\"" - if [ "$Le_Alt" == "no" ] ; then + if [[ "$Le_Alt" == "no" ]] ; then Le_Alt="" fi - if [ "$Le_Keylength" == "no" ] ; then + if [[ "$Le_Keylength" == "no" ]] ; then Le_Keylength="" fi - if [ "$Le_RealCertPath" == "no" ] ; then + if [[ "$Le_RealCertPath" == "no" ]] ; then Le_RealCertPath="" fi - if [ "$Le_RealKeyPath" == "no" ] ; then + if [[ "$Le_RealKeyPath" == "no" ]] ; then Le_RealKeyPath="" fi - if [ "$Le_RealCACertPath" == "no" ] ; then + if [[ "$Le_RealCACertPath" == "no" ]] ; then Le_RealCACertPath="" fi - if [ "$Le_ReloadCmd" == "no" ] ; then + if [[ "$Le_ReloadCmd" == "no" ]] ; then Le_ReloadCmd="" fi - + if [[ "$Le_RealFullChainPath" == "no" ]] ; then + Le_RealFullChainPath="" + fi - if [ "$Le_Webroot" == "no" ] ; then + if [[ "$Le_Webroot" == *"no"* ]] ; then _info "Standalone mode." if ! command -v "nc" > /dev/null ; then _err "Please install netcat(nc) tools first." return 1 fi - if [ -z "$Le_HTTPPort" ] ; then + if [[ -z "$Le_HTTPPort" ]] ; then Le_HTTPPort=80 fi _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" netprc="$(_ss "$Le_HTTPPort" | grep "$Le_HTTPPort")" - if [ "$netprc" ] ; then + if [[ "$netprc" ]] ; then _err "$netprc" _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" _err "Please stop it first" @@ -960,7 +966,7 @@ issue() { fi fi - if [ "$Le_Webroot" == "apache" ] ; then + if [[ "$Le_Webroot" == *"apache"* ]] ; then if ! _setApache ; then _err "set up apache error. Report error to me." return 1 @@ -980,19 +986,19 @@ issue() { thumbprint=$(echo -n "$accountkey_json" | _digest "sha256" | _urlencode) accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | _digest "sha256" )" - - if [ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ] ; then + accountkeyhash="$(echo $accountkeyhash$API | _digest "sha256" )" + if [[ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ]] ; then _info "Registering account" regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ] ; then + if [[ "$ACCOUNT_EMAIL" ]] ; then regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' fi _send_signed_request "$API/acme/new-reg" "$regjson" - if [ "$code" == "" ] || [ "$code" == '201' ] ; then + if [[ "$code" == "" ]] || [[ "$code" == '201' ]] ; then _info "Registered" echo $response > $LE_WORKING_DIR/account.json - elif [ "$code" == '409' ] ; then + elif [[ "$code" == '409' ]] ; then _info "Already registered" else _err "Register account Error: $response" @@ -1014,23 +1020,33 @@ issue() { _err "Create CSR error." return 1 fi - - vtype="$VTYPE_HTTP" - if [[ "$Le_Webroot" == "dns"* ]] ; then - vtype="$VTYPE_DNS" - fi - + vlist="$Le_Vlist" # verify each domain _info "Verify each domain" sep='#' - if [ -z "$vlist" ] ; then + if [[ -z "$vlist" ]] ; then alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) + _index=1 + _currentRoot="" for d in $alldomains - do + do + _info "Getting webroot for domain" $d + _w="$(echo $Le_Webroot | cut -d , -f $_index)" + _debug _w "$_w" + if [[ "$_w" ]] ; then + _currentRoot="$_w" + fi + _debug "_currentRoot" "$_currentRoot" + let "_index+=1" + + vtype="$VTYPE_HTTP" + if [[ "$_currentRoot" == "dns"* ]] ; then + vtype="$VTYPE_DNS" + fi _info "Getting token for domain" $d _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" - if [ ! -z "$code" ] && [ ! "$code" == '201' ] ; then + if [[ ! -z "$code" ]] && [[ ! "$code" == '201' ]] ; then _err "new-authz error: $response" _clearup return 1 @@ -1048,7 +1064,7 @@ issue() { keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" - dvlist="$d$sep$keyauthorization$sep$uri" + dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" _debug dvlist "$dvlist" vlist="$vlist$dvlist," @@ -1062,8 +1078,9 @@ issue() { do d=$(echo $ventry | cut -d $sep -f 1) keyauthorization=$(echo $ventry | cut -d $sep -f 2) - - if [ "$vtype" == "$VTYPE_DNS" ] ; then + vtype=$(echo $ventry | cut -d $sep -f 4) + _currentRoot=$(echo $ventry | cut -d $sep -f 5) + if [[ "$vtype" == "$VTYPE_DNS" ]] ; then dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" @@ -1072,22 +1089,22 @@ issue() { #dns #1. check use api d_api="" - if [ -f "$LE_WORKING_DIR/$d/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/$d/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/$d/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/$d/$Le_Webroot.sh" - elif [ -f "$LE_WORKING_DIR/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/$Le_Webroot.sh" - elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot" ] ; then - d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot" - elif [ -f "$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" ] ; then - d_api="$LE_WORKING_DIR/dnsapi/$Le_Webroot.sh" + if [[ -f "$LE_WORKING_DIR/$d/$_currentRoot" ]] ; then + d_api="$LE_WORKING_DIR/$d/$_currentRoot" + elif [[ -f "$LE_WORKING_DIR/$d/$_currentRoot.sh" ]] ; then + d_api="$LE_WORKING_DIR/$d/$_currentRoot.sh" + elif [[ -f "$LE_WORKING_DIR/$_currentRoot" ]] ; then + d_api="$LE_WORKING_DIR/$_currentRoot" + elif [[ -f "$LE_WORKING_DIR/$_currentRoot.sh" ]] ; then + d_api="$LE_WORKING_DIR/$_currentRoot.sh" + elif [[ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot" ]] ; then + d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot" + elif [[ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" ]] ; then + d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" fi _debug d_api "$d_api" - if [ "$d_api" ]; then + if [[ "$d_api" ]] ; then _info "Found domain api file: $d_api" else _err "Add the following TXT record:" @@ -1104,7 +1121,7 @@ issue() { return 1 fi - addcommand="$Le_Webroot-add" + addcommand="$_currentRoot-add" if ! command -v $addcommand ; then _err "It seems that your api file is not correct, it must have a function named: $addcommand" return 1 @@ -1123,7 +1140,7 @@ issue() { fi done - if [ "$dnsadded" == '0' ] ; then + if [[ "$dnsadded" == '0' ]] ; then _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\"" _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." @@ -1132,40 +1149,47 @@ issue() { fi - if [ "$dnsadded" == '1' ] ; then + if [[ "$dnsadded" == '1' ]] ; then _info "Sleep 60 seconds for the txt records to take effect" sleep 60 fi _debug "ok, let's start to verify" + ventries=$(echo "$vlist" | tr ',' ' ' ) for ventry in $ventries do d=$(echo $ventry | cut -d $sep -f 1) keyauthorization=$(echo $ventry | cut -d $sep -f 2) uri=$(echo $ventry | cut -d $sep -f 3) + vtype=$(echo $ventry | cut -d $sep -f 4) + _currentRoot=$(echo $ventry | cut -d $sep -f 5) _info "Verifying:$d" _debug "d" "$d" _debug "keyauthorization" "$keyauthorization" _debug "uri" "$uri" removelevel="" token="" - if [ "$vtype" == "$VTYPE_HTTP" ] ; then - if [ "$Le_Webroot" == "no" ] ; then + + _debug "_currentRoot" "$_currentRoot" + + + if [[ "$vtype" == "$VTYPE_HTTP" ]] ; then + if [[ "$_currentRoot" == "no" ]] ; then _info "Standalone mode server" _startserver "$keyauthorization" & serverproc="$!" sleep 2 _debug serverproc $serverproc else - if [ -z "$wellknown_path" ] ; then - wellknown_path="$Le_Webroot/.well-known/acme-challenge" + if [[ -z "$wellknown_path" ]] ; then + wellknown_path="$_currentRoot/.well-known/acme-challenge" fi _debug wellknown_path "$wellknown_path" - if [ ! -d "$Le_Webroot/.well-known" ] ; then + if [[ ! -d "$_currentRoot/.well-known" ]] ; then removelevel='1' - elif [ ! -d "$Le_Webroot/.well-known/acme-challenge" ] ; then + elif [[ ! -d "$_currentRoot/.well-known/acme-challenge" ]] ; then removelevel='2' else removelevel='3' @@ -1177,9 +1201,9 @@ issue() { mkdir -p "$wellknown_path" echo -n "$keyauthorization" > "$wellknown_path/$token" if [[ ! "$usingApache" ]] ; then - webroot_owner=$(_stat $Le_Webroot) + webroot_owner=$(_stat $_currentRoot) _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R $webroot_owner "$Le_Webroot/.well-known" + chown -R $webroot_owner "$_currentRoot/.well-known" fi fi @@ -1187,47 +1211,47 @@ issue() { _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" - if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then + if [[ ! -z "$code" ]] && [[ ! "$code" == '202' ]] ; then _err "$d:Challenge error: $response" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup return 1 fi - while [ "1" ] ; do + while [[ "1" ]] ; do _debug "sleep 5 secs to verify" sleep 5 _debug "checking" response="$(_get $uri)" - if [ "$?" != "0" ] ; then + if [[ "$?" != "0" ]] ; then _err "$d:Verify error:$response" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup return 1 fi status=$(echo $response | egrep -o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') - if [ "$status" == "valid" ] ; then + if [[ "$status" == "valid" ]] ; then _info "Success" _stopserver $serverproc serverproc="" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" break; fi - if [ "$status" == "invalid" ] ; then + if [[ "$status" == "invalid" ]] ; then error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4) _err "$d:Verify error:$error" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup return 1; fi - if [ "$status" == "pending" ] ; then + if [[ "$status" == "pending" ]] ; then _info "Pending" else _err "$d:Verify error:$response" - _clearupwebbroot "$Le_Webroot" "$removelevel" "$token" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup return 1 fi @@ -1245,7 +1269,7 @@ issue() { Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)" _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" - if [ "$Le_LinkCert" ] ; then + if [[ "$Le_LinkCert" ]] ; then echo "$BEGIN_CERT" > "$CERT_PATH" _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" echo "$END_CERT" >> "$CERT_PATH" @@ -1262,7 +1286,7 @@ issue() { fi - if [ -z "$Le_LinkCert" ] ; then + if [[ -z "$Le_LinkCert" ]] ; then response="$(echo $response | _dbase64 "multiline" )" _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" return 1 @@ -1273,7 +1297,7 @@ issue() { Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" - if [ "$Le_LinkIssuer" ] ; then + if [[ "$Le_LinkIssuer" ]] ; then echo "$BEGIN_CERT" > "$CA_CERT_PATH" _get "$Le_LinkIssuer" | _base64 "multiline" >> "$CA_CERT_PATH" echo "$END_CERT" >> "$CA_CERT_PATH" @@ -1288,7 +1312,7 @@ issue() { Le_CertCreateTimeStr=$(date -u ) _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\"" - if [ ! "$Le_RenewalDays" ] ; then + if [[ ! "$Le_RenewalDays" ]] ; then Le_RenewalDays=80 fi @@ -1301,32 +1325,32 @@ issue() { _setopt "$DOMAIN_CONF" "Le_NextRenewTimeStr" "=" "\"$Le_NextRenewTimeStr\"" - installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" + installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" } renew() { Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then - _err "Usage: $0 domain.com" + if [[ -z "$Le_Domain" ]] ; then + _err "Usage: le.sh --renew -d domain.com" return 1 fi _initpath $Le_Domain - if [ ! -f "$DOMAIN_CONF" ] ; then + if [[ ! -f "$DOMAIN_CONF" ]] ; then _info "$Le_Domain is not a issued domain, skip." return 0; fi source "$DOMAIN_CONF" - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then + if [[ -z "$FORCE" ]] && [[ "$Le_NextRenewTime" ]] && [[ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ]] ; then _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" return 2 fi IS_RENEW="1" - issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" + issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" local res=$? IS_RENEW="" @@ -1360,6 +1384,7 @@ renewAll() { Le_RealCACertPath="" Le_ReloadCmd="" + Le_RealFullChainPath="" DOMAIN_PATH="" DOMAIN_CONF="" @@ -1381,8 +1406,8 @@ renewAll() { installcert() { Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then - _err "Usage: $0 domain.com [cert-file-path]|no [key-file-path]|no [ca-cert-file-path]|no [reloadCmd]|no" + if [[ -z "$Le_Domain" ]] ; then + echo "Usage: le.sh --installcert -d domain.com [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" return 1 fi @@ -1390,6 +1415,7 @@ installcert() { Le_RealKeyPath="$3" Le_RealCACertPath="$4" Le_ReloadCmd="$5" + Le_RealFullChainPath="$6" _initpath $Le_Domain @@ -1397,20 +1423,21 @@ installcert() { _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" + _setopt "$DOMAIN_CONF" "Le_RealFullChainPath" "=" "\"$Le_RealFullChainPath\"" - if [ "$Le_RealCertPath" ] ; then - if [ -f "$Le_RealCertPath" ] ; then + if [[ "$Le_RealCertPath" ]] ; then + if [[ -f "$Le_RealCertPath" ]] ; then cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak fi cat "$CERT_PATH" > "$Le_RealCertPath" fi - if [ "$Le_RealCACertPath" ] ; then - if [ "$Le_RealCACertPath" == "$Le_RealCertPath" ] ; then + if [[ "$Le_RealCACertPath" ]] ; then + if [[ "$Le_RealCACertPath" == "$Le_RealCertPath" ]] ; then echo "" >> "$Le_RealCACertPath" cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" else - if [ -f "$Le_RealCACertPath" ] ; then + if [[ -f "$Le_RealCACertPath" ]] ; then cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak fi cat "$CA_CERT_PATH" > "$Le_RealCACertPath" @@ -1418,14 +1445,21 @@ installcert() { fi - if [ "$Le_RealKeyPath" ] ; then - if [ -f "$Le_RealKeyPath" ] ; then + if [[ "$Le_RealKeyPath" ]] ; then + if [[ -f "$Le_RealKeyPath" ]] ; then cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak fi cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" fi + + if [[ "$Le_RealFullChainPath" ]] ; then + if [[ -f "$Le_RealFullChainPath" ]] ; then + cp -p "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak + fi + cat "$CERT_FULLCHAIN_PATH" > "$Le_RealFullChainPath" + fi - if [ "$Le_ReloadCmd" ] ; then + if [[ "$Le_ReloadCmd" ]] ; then _info "Run Le_ReloadCmd: $Le_ReloadCmd" (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") fi @@ -1443,7 +1477,7 @@ installcronjob() { _info "Installing cron job" if ! crontab -l | grep 'le.sh cron' ; then - if [ -f "$LE_WORKING_DIR/le.sh" ] ; then + if [[ -f "$LE_WORKING_DIR/le.sh" ]] ; then lesh="\"$LE_WORKING_DIR\"/le.sh" else _err "Can not install cronjob, le.sh not found." @@ -1451,7 +1485,7 @@ installcronjob() { fi crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab - fi - if [ "$?" != "0" ] ; then + if [[ "$?" != "0" ]] ; then _err "Install cron job failed. You need to manually renew your certs." _err "Or you can add cronjob by yourself:" _err "LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null" @@ -1465,7 +1499,7 @@ uninstallcronjob() { fi _info "Removing cron job" cr="$(crontab -l | grep 'le.sh cron')" - if [ "$cr" ] ; then + if [[ "$cr" ]] ; then crontab -l | sed "/le.sh cron/d" | crontab - LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 6 | cut -d '=' -f 2 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" @@ -1476,25 +1510,25 @@ uninstallcronjob() { revoke() { Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then - _err "Usage: revoke domain.com" + if [[ -z "$Le_Domain" ]] ; then + echo "Usage: le.sh --revoke -d domain.com" return 1 fi _initpath $Le_Domain - if [ ! -f "$DOMAIN_CONF" ] ; then + if [[ ! -f "$DOMAIN_CONF" ]] ; then _err "$Le_Domain is not a issued domain, skip." return 1; fi - if [ ! -f "$CERT_PATH" ] ; then + if [[ ! -f "$CERT_PATH" ]] ; then _err "Cert for $Le_Domain $CERT_PATH is not found, skip." return 1 fi cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}"| tr -d "\r\n" | _urlencode)" - if [ -z "$cert" ] ; then + if [[ -z "$cert" ]] ; then _err "Cert for $Le_Domain is empty found, skip." return 1 fi @@ -1504,7 +1538,7 @@ revoke() { _info "Try domain key first." if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then - if [ -z "$response" ] ; then + if [[ -z "$response" ]] ; then _info "Revoke success." rm -f $CERT_PATH return 0 @@ -1517,7 +1551,7 @@ revoke() { _info "Then try account key." if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH" ; then - if [ -z "$response" ] ; then + if [[ -z "$response" ]] ; then _info "Revoke success." rm -f $CERT_PATH return 0 @@ -1531,7 +1565,7 @@ revoke() { # Detect profile file if not specified as environment variable _detect_profile() { - if [ -n "$PROFILE" -a -f "$PROFILE" ]; then + if [ -n "$PROFILE" -a -f "$PROFILE" ] ; then echo "$PROFILE" return fi @@ -1541,36 +1575,36 @@ _detect_profile() { local SHELLTYPE SHELLTYPE="$(basename "/$SHELL")" - if [ "$SHELLTYPE" = "bash" ]; then - if [ -f "$HOME/.bashrc" ]; then + if [[ "$SHELLTYPE" = "bash" ]] ; then + if [[ -f "$HOME/.bashrc" ]] ; then DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then + elif [[ -f "$HOME/.bash_profile" ]] ; then DETECTED_PROFILE="$HOME/.bash_profile" fi - elif [ "$SHELLTYPE" = "zsh" ]; then + elif [[ "$SHELLTYPE" = "zsh" ]] ; then DETECTED_PROFILE="$HOME/.zshrc" fi - if [ -z "$DETECTED_PROFILE" ]; then - if [ -f "$HOME/.profile" ]; then + if [[ -z "$DETECTED_PROFILE" ]] ; then + if [[ -f "$HOME/.profile" ]] ; then DETECTED_PROFILE="$HOME/.profile" - elif [ -f "$HOME/.bashrc" ]; then + elif [[ -f "$HOME/.bashrc" ]] ; then DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then + elif [[ -f "$HOME/.bash_profile" ]] ; then DETECTED_PROFILE="$HOME/.bash_profile" - elif [ -f "$HOME/.zshrc" ]; then + elif [[ -f "$HOME/.zshrc" ]] ; then DETECTED_PROFILE="$HOME/.zshrc" fi fi - if [ ! -z "$DETECTED_PROFILE" ]; then + if [[ ! -z "$DETECTED_PROFILE" ]] ; then echo "$DETECTED_PROFILE" fi } _initconf() { _initpath - if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then + if [[ ! -f "$ACCOUNT_CONF_PATH" ]] ; then echo "#Account configurations: #Here are the supported macros, uncomment them to make them take effect. #ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. @@ -1621,7 +1655,7 @@ _precheck() { _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." _err "We need to set cron job to renew the certs automatically." _err "Otherwise, your certs will not be able to be renewed automatically." - if [ -z "$FORCE" ] ; then + if [[ -z "$FORCE" ]] ; then _err "Please define 'FORCE=1' and try install again to go without crontab." _err "FORCE=1 ./le.sh install" return 1 @@ -1663,7 +1697,7 @@ install() { cp le.sh "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/le.sh" - if [ "$?" != "0" ] ; then + if [[ "$?" != "0" ]] ; then _err "Install failed, can not copy le.sh" return 1 fi @@ -1671,7 +1705,7 @@ install() { _info "Installed to $LE_WORKING_DIR/le.sh" _profile="$(_detect_profile)" - if [ "$_profile" ] ; then + if [[ "$_profile" ]] ; then _debug "Found profile: $_profile" echo "LE_WORKING_DIR=$LE_WORKING_DIR @@ -1689,13 +1723,13 @@ alias le.sh=\"$LE_WORKING_DIR/le.sh\" cp dnsapi/* $LE_WORKING_DIR/dnsapi/ #to keep compatible mv the .acc file to .key file - if [ -f "$LE_WORKING_DIR/account.acc" ] ; then + if [[ -f "$LE_WORKING_DIR/account.acc" ]] ; then mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key" fi installcronjob - if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then + if [[ ! -f "$ACCOUNT_CONF_PATH" ]] ; then _initconf fi _info OK @@ -1706,7 +1740,7 @@ uninstall() { _initpath _profile="$(_detect_profile)" - if [ "$_profile" ] ; then + if [[ "$_profile" ]] ; then text="$(cat $_profile)" echo "$text" | sed "s|^source.*le.env.*$||" > "$_profile" fi @@ -1723,49 +1757,63 @@ cron() { } version() { - _info "$PROJECT" - _info "v$VER" + echo "$PROJECT" + echo "v$VER" } showhelp() { version - echo "Usage: le.sh [command] ...[args].... -Available commands: - -install: - Install le.sh to your system. -issue: - Issue a cert. -installcert: - Install the issued cert to apache/nginx or any other server. -renew: - Renew a cert. -renewAll: - Renew all the certs. -uninstall: - Uninstall le.sh, and uninstall the cron job. -revoke: - Revoke a cert. -version: - Show version info. -installcronjob: - Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. -uninstallcronjob: - Uninstall the cron job. The 'uninstall' command can do this automatically. -toPkcs: - Export the certificate and key to a pfx file. -createAccountKey: - Create an account private key, professional use. -createDomainKey: - Create an domain private key, professional use. -createCSR: - Create CSR , professional use. + echo "Usage: le.sh command ...[parameters].... +Commands: + --help, -h Show this help message. + --version, -v Show version info. + --install Install le.sh to your system. + --uninstall Uninstall le.sh, and uninstall the cron job. + --issue Issue a cert. + --installcert Install the issued cert to apache/nginx or any other server. + --renew, -r Renew a cert. + --renewAll Renew all the certs + --revoke Revoke a cert. + --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. + --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically. + --cron Run cron job to renew all the certs. + --toPkcs Export the certificate and key to a pfx file. + --createAccountKey, -cak Create an account private key, professional use. + --createDomainKey, -cdk Create an domain private key, professional use. + --createCSR, -ccsr Create CSR , professional use. + +Parameters: + --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. + --force, -f Used to force to install or force to renew a cert immediately. + --staging, --test Use staging server, just for test. + --debug Output debug info. + + --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. + --standalone Use standalone mode. + --apache Use apache mode. + --dns [dns-cf|dns-dp|dns-cx|/path/to/api/file] Use dns mode or dns api. + + --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. + --accountkeylength, -ak [2048] Specifies the account key length. + + 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. + --keypath /path/to/real/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. + --fullchainpath /path/to/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. + + --accountconf Specifies a customized account config file. + --leworkingdir Specifies the home dir for le.sh + " } _installOnline() { _info "Installing from online archive." - if [ ! "$BRANCH" ] ; then + if [[ ! "$BRANCH" ]] ; then BRANCH="master" fi _initpath @@ -1789,14 +1837,256 @@ _installOnline() { rm -f "$localname" } -if [ "$INSTALLONLINE" ] ; then + +_process() { + _CMD="" + _domain="" + _altdomains="no" + _webroot="" + _keylength="no" + _accountkeylength="no" + _certpath="no" + _keypath="no" + _capath="no" + _fullchainpath="no" + _reloadcmd="no" + _password="" + while (( ${#} )); do + case "${1}" in + + --help|-h) + showhelp + return + ;; + --version|-v) + version + return + ;; + --install) + _CMD="install" + ;; + --uninstall) + _CMD="uninstall" + ;; + --issue) + _CMD="issue" + ;; + --installcert|-i) + _CMD="installcert" + ;; + --renew|-r) + _CMD="renew" + ;; + --renewAll|-renewall) + _CMD="renewAll" + ;; + --revoke) + _CMD="revoke" + ;; + --installcronjob) + _CMD="installcronjob" + ;; + --uninstallcronjob) + _CMD="uninstallcronjob" + ;; + --cron) + _CMD="cron" + ;; + --toPkcs) + _CMD="toPkcs" + ;; + --createAccountKey|--createaccountkey|-cak) + _CMD="createAccountKey" + ;; + --createDomainKey|--createdomainkey|-cdk) + _CMD="createDomainKey" + ;; + --createCSR|--createcsr|-ccr) + _CMD="createCSR" + ;; + + + --domain|-d) + _dvalue="$2" + + if [[ -z "$_dvalue" ]] || [[ "$_dvalue" == "-"* ]] ; then + _err "'$_dvalue' is not a valid domain for parameter '$1'" + return 1 + fi + + if [[ -z "$_domain" ]] ; then + _domain="$_dvalue" + else + if [[ "$_altdomains" == "no" ]] ; then + _altdomains="$_dvalue" + else + _altdomains="$_altdomains,$_dvalue" + fi + fi + shift + ;; + + --force|-f) + FORCE="1" + ;; + --staging|--test) + STAGE="1" + ;; + --debug) + if [[ "$2" == "-"* ]] ; then + DEBUG="1" + else + DEBUG="$2" + shift + fi + ;; + + --webroot|-w) + wvalue="$2" + if [[ -z "$_webroot" ]] ; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + shift + ;; + --standalone) + wvalue="no" + if [[ -z "$_webroot" ]] ; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --apache) + wvalue="apache" + if [[ -z "$_webroot" ]] ; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --dns) + wvalue="dns" + if [[ "$2" != "-"* ]] ; then + wvalue="$2" + shift + fi + if [[ -z "$_webroot" ]] ; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --keylength|-k) + _keylength="$2" + accountkeylength="$2" + shift + ;; + --accountkeylength|-ak) + accountkeylength="$2" + shift + ;; + + --certpath) + _certpath="$2" + shift + ;; + --keypath) + _keypath="$2" + shift + ;; + --capath) + _capath="$2" + shift + ;; + --fullchainpath) + _fullchainpath="$2" + shift + ;; + --reloadcmd) + _reloadcmd="$2" + shift + ;; + --password) + _password="$2" + shift + ;; + --accountconf) + ACCOUNT_CONF_PATH="$2" + ;; + --leworkingdir) + LE_WORKING_DIR="$2" + ;; + + *) + _err "Unknown parameter : $1" + return 1 + ;; + esac + + shift 1 + done + + + case "${_CMD}" in + install) install ;; + uninstall) uninstall ;; + issue) + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keylength" "$_capath" "$_reloadcmd" "$_fullchainpath" + ;; + installcert) + installcert "$_domain" "$_certpath" "$_keylength" "$_capath" "$_reloadcmd" "$_fullchainpath" + ;; + renew) + renew "$_domain" + ;; + renewAll) + renewAll + ;; + revoke) + revoke "$_domain" + ;; + installcronjob) installcronjob ;; + uninstallcronjob) uninstallcronjob ;; + cron) cron ;; + toPkcs) + toPkcs "$_domain" "$_password" + ;; + createAccountKey) + createAccountKey "$_domain" "$_accountkeylength" + ;; + createDomainKey) + createDomainKey "$_domain" "$_keylength" + ;; + createCSR) + createCSR "$_domain" "$_altdomains" + ;; + + *) + _err "Invalid command: $_CMD" + showhelp; + return 1 + ;; + esac + +} + + +if [[ "$INSTALLONLINE" ]] ; then INSTALLONLINE="" _installOnline $BRANCH exit fi -if [ -z "$1" ] ; then +if [[ -z "$1" ]] ; then showhelp else - "$@" + if [[ "$1" == "-"* ]] ; then + _process "$@" + else + "$@" + fi fi + + From 5c917113e8ae30a506c3f5aefddc62a58c3cad96 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 9 Apr 2016 23:57:29 +0800 Subject: [PATCH 0085/1348] V2 help --- dnsapi/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 3588dd44..b397e556 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -15,7 +15,7 @@ export CF_Email="xxxx@sss.com" Ok, let's issue cert now: ``` -le.sh issue dns-cf aa.com www.aa.com +le.sh --issue --dns dns-cf -d aa.com -d www.aa.com ``` The `CF_Key` and `CF_Email` will be saved in `~/.le/account.conf`, when next time you use cloudflare api, it will reuse this key. @@ -37,7 +37,7 @@ export DP_Key="sADDsdasdgdsf" Ok, let's issue cert now: ``` -le.sh issue dns-dp aa.com www.aa.com +le.sh --issue --dns dns-dp -d aa.com -d www.aa.com ``` The `DP_Id` and `DP_Key` will be saved in `~/.le/account.conf`, when next time you use dnspod.cn api, it will reuse this key. @@ -58,7 +58,7 @@ export CX_Secret="sADDsdasdgdsf" Ok, let's issue cert now: ``` -le.sh issue dns-cx aa.com www.aa.com +le.sh --issue --dns dns-cx -d aa.com -d www.aa.com ``` The `CX_Key` and `CX_Secret` will be saved in `~/.le/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. @@ -76,7 +76,7 @@ Let's assume you want to name it 'myapi', 3. Then you can use your api to issue cert like: ``` -le.sh issue dns-myapi aa.com www.aa.com +le.sh --issue --dns dns-myapi -d aa.com -d www.aa.com ``` For more details, please check our sample script: [dns-myapi.sh](dns-myapi.sh) From e8cce73a17ddd69a696e7f4730443b552a5c4727 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 10 Apr 2016 12:54:01 +0800 Subject: [PATCH 0086/1348] 100% compatible from 1.x to 2.x --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e8d18386..1c98b295 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ https://github.com/Neilpang/letest.git 3. Apache mode 4. Dns mode +#Upgrade from 1.x to 2.x +You can simply uninstall 1.x and re-install 2.x. +2.x is 100% compatible to 1.x. You will feel nothing changed. + #How to install 1. Install online: @@ -157,7 +161,7 @@ More examples: https://github.com/Neilpang/le/wiki/How-to-issue-a-cert # Install issued cert to apache/nginx etc. -After you issue a cert, you probably want to install the cert to you nginx/apache or other servers to use. +After you issue a cert, you probably want to install the cert to your nginx/apache or other servers to use. ``` le --installcert -d aa.com \ From d53289d707d72ceec0282c265f345228ef333f90 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 11 Apr 2016 22:33:57 +0800 Subject: [PATCH 0087/1348] Save customized account.conf. --- le.sh | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/le.sh b/le.sh index afd7a110..40772907 100755 --- a/le.sh +++ b/le.sh @@ -662,8 +662,14 @@ _initpath() { LE_WORKING_DIR=$HOME/.le fi + _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" + + if [[ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]] ; then + source "$_DEFAULT_ACCOUNT_CONF_PATH" + fi + if [[ -z "$ACCOUNT_CONF_PATH" ]] ; then - ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" + ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi if [[ -f "$ACCOUNT_CONF_PATH" ]] ; then @@ -1122,7 +1128,7 @@ issue() { fi addcommand="$_currentRoot-add" - if ! command -v $addcommand ; then + if ! _exists $addcommand ; then _err "It seems that your api file is not correct, it must have a function named: $addcommand" return 1 fi @@ -1605,8 +1611,11 @@ _detect_profile() { _initconf() { _initpath if [[ ! -f "$ACCOUNT_CONF_PATH" ]] ; then - echo "#Account configurations: + echo "#ACCOUNT_CONF_PATH=xxxx + +#Account configurations: #Here are the supported macros, uncomment them to make them take effect. + #ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. #ACCOUNT_KEY_PATH=\"/path/to/account.key\" @@ -1726,12 +1735,16 @@ alias le.sh=\"$LE_WORKING_DIR/le.sh\" if [[ -f "$LE_WORKING_DIR/account.acc" ]] ; then mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key" fi - - installcronjob - + if [[ ! -f "$ACCOUNT_CONF_PATH" ]] ; then _initconf fi + + _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" + _setopt "$ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" + + installcronjob + _info OK } From 3ed4102a3c3006cb80b99255f0901598c432a0fb Mon Sep 17 00:00:00 2001 From: roozbehk Date: Mon, 11 Apr 2016 21:32:49 -0400 Subject: [PATCH 0088/1348] incorrect parameter for keypath --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 40772907..4306fabb 100755 --- a/le.sh +++ b/le.sh @@ -2049,7 +2049,7 @@ _process() { issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keylength" "$_capath" "$_reloadcmd" "$_fullchainpath" ;; installcert) - installcert "$_domain" "$_certpath" "$_keylength" "$_capath" "$_reloadcmd" "$_fullchainpath" + installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" ;; renew) renew "$_domain" From 6fc1447fa652fd2a52935c9c5742733c51671a09 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 12 Apr 2016 23:18:22 +0800 Subject: [PATCH 0089/1348] add timeout for nc. --- le.sh | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/le.sh b/le.sh index 40772907..fd386226 100755 --- a/le.sh +++ b/le.sh @@ -618,7 +618,7 @@ _saveaccountconf() { _startserver() { content="$1" - + _debug "startserver: $$" nchelp="$(nc -h 2>&1)" if echo "$nchelp" | grep "\-q[ ,]" >/dev/null ; then @@ -646,13 +646,24 @@ _startserver() { fi if [[ "$?" != "0" ]] ; then _err "nc listen error." - return 1 + exit 1 fi # done } -_stopserver() { +_stopserver(){ pid="$1" + _debug "pid" "$pid" + if [[ -z "$pid" ]] ; then + return + fi + + if [[ "$(ps | grep "$pid" | grep "nc")" ]] ; then + _debug "Found nc process, kill it." + kill -s 9 $pid > /dev/null 2>&1 + fi + + _get "http://localhost:$Le_HTTPPort" >/dev/null 2>$1 } @@ -1184,9 +1195,13 @@ issue() { if [[ "$_currentRoot" == "no" ]] ; then _info "Standalone mode server" _startserver "$keyauthorization" & + if [[ "$?" != "0" ]] ; then + return 1 + fi serverproc="$!" sleep 2 _debug serverproc $serverproc + else if [[ -z "$wellknown_path" ]] ; then wellknown_path="$_currentRoot/.well-known/acme-challenge" @@ -1224,7 +1239,20 @@ issue() { return 1 fi + waittimes=0 + if [[ -z "$MAX_RETRY_TIMES" ]] ; then + MAX_RETRY_TIMES=30 + fi + while [[ "1" ]] ; do + let "waittimes+=1" + if [[ "$waittimes" -ge "$MAX_RETRY_TIMES" ]] ; then + _err "$d:Timeout" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + return 1 + fi + _debug "sleep 5 secs to verify" sleep 5 _debug "checking" @@ -1946,14 +1974,13 @@ _process() { STAGE="1" ;; --debug) - if [[ "$2" == "-"* ]] ; then + if [[ "$2" == "-"* ]] || [[ -z "$2" ]]; then DEBUG="1" else DEBUG="$2" shift - fi + fi ;; - --webroot|-w) wvalue="$2" if [[ -z "$_webroot" ]] ; then From dca09dedace304c083fc2e343ebdebdb967f3f79 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 12 Apr 2016 23:43:24 +0800 Subject: [PATCH 0090/1348] kill nc process --- le.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index fd386226..d27735c0 100755 --- a/le.sh +++ b/le.sh @@ -658,11 +658,16 @@ _stopserver(){ return fi - if [[ "$(ps | grep "$pid" | grep "nc")" ]] ; then - _debug "Found nc process, kill it." + if [[ "$(ps | grep "$pid")" ]] ; then + _debug "Found proc process, kill it." kill -s 9 $pid > /dev/null 2>&1 fi + for ncid in $(ps | grep nc | cut -d " " -f 1) ; do + _debug "kill $ncid" + kill -s 9 $ncid > /dev/null 2>&1 + done + _get "http://localhost:$Le_HTTPPort" >/dev/null 2>$1 } From 770dc4b23023aa8bb35a21d24aef0609005a48d2 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 12 Apr 2016 23:47:09 +0800 Subject: [PATCH 0091/1348] expose the error --- le.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index d27735c0..0881c3a8 100755 --- a/le.sh +++ b/le.sh @@ -660,12 +660,12 @@ _stopserver(){ if [[ "$(ps | grep "$pid")" ]] ; then _debug "Found proc process, kill it." - kill -s 9 $pid > /dev/null 2>&1 + kill -s 9 $pid > /dev/null fi for ncid in $(ps | grep nc | cut -d " " -f 1) ; do _debug "kill $ncid" - kill -s 9 $ncid > /dev/null 2>&1 + kill -s 9 $ncid > /dev/null done _get "http://localhost:$Le_HTTPPort" >/dev/null 2>$1 From 233e8a20853d3877e97fc4ae6e8ae703893bfc4e Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 13 Apr 2016 00:24:55 +0800 Subject: [PATCH 0092/1348] kill nc --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 0881c3a8..8c461fb8 100755 --- a/le.sh +++ b/le.sh @@ -663,7 +663,7 @@ _stopserver(){ kill -s 9 $pid > /dev/null fi - for ncid in $(ps | grep nc | cut -d " " -f 1) ; do + for ncid in $(echo $(ps | grep nc) | cut -d " " -f 1) ; do _debug "kill $ncid" kill -s 9 $ncid > /dev/null done From a7b7355dcf1f1b75fb581bf5d15cf26086d58c06 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 13 Apr 2016 20:37:18 +0800 Subject: [PATCH 0093/1348] v2.0.1. Use '--home' install of env --- le.sh | 90 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/le.sh b/le.sh index d24c290c..746740d7 100755 --- a/le.sh +++ b/le.sh @@ -1,11 +1,15 @@ #!/usr/bin/env bash -VER=2.0.0 +VER=2.0.1 + +PROJECT_NAME="le.sh" +PROJECT_ENTRY="le.sh" + PROJECT="https://github.com/Neilpang/le" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" -DEFAULT_USER_AGENT="le.sh client: $PROJECT" +DEFAULT_USER_AGENT="$PROJECT_ENTRY client: $PROJECT" STAGE_CA="https://acme-staging.api.letsencrypt.org" @@ -213,7 +217,7 @@ toPkcs() { domain="$1" pfxPassword="$2" if [[ -z "$domain" ]] ; then - echo "Usage: le.sh --toPkcs -d domain [--password pfx-password]" + echo "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]" return 1 fi @@ -235,7 +239,7 @@ toPkcs() { createAccountKey() { _info "Creating account key" if [[ -z "$1" ]] ; then - echo Usage: le.sh --createAccountKey -d domain.com [--accountkeylength 2048] + echo Usage: $PROJECT_ENTRY --createAccountKey -d domain.com [--accountkeylength 2048] return fi @@ -266,7 +270,7 @@ createAccountKey() { createDomainKey() { _info "Creating domain key" if [[ -z "$1" ]] ; then - echo Usage: le.sh --createDomainKey -d domain.com [ --keylength 2048 ] + echo Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ] return fi @@ -327,7 +331,7 @@ createDomainKey() { createCSR() { _info "Creating csr" if [[ -z "$1" ]] ; then - echo Usage: le.sh --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ] + echo Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ] return fi domain=$1 @@ -911,7 +915,7 @@ _clearupwebbroot() { issue() { if [[ -z "$2" ]] ; then - echo "Usage: le --issue -d a.com -w /path/to/webroot/a.com/ " + echo "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " return 1 fi Le_Webroot="$1" @@ -1371,7 +1375,7 @@ issue() { renew() { Le_Domain="$1" if [[ -z "$Le_Domain" ]] ; then - _err "Usage: le.sh --renew -d domain.com" + _err "Usage: $PROJECT_ENTRY --renew -d domain.com" return 1 fi @@ -1446,7 +1450,7 @@ renewAll() { installcert() { Le_Domain="$1" if [[ -z "$Le_Domain" ]] ; then - echo "Usage: le.sh --installcert -d domain.com [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" + echo "Usage: $PROJECT_ENTRY --installcert -d domain.com [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" return 1 fi @@ -1510,24 +1514,24 @@ installcronjob() { if ! _exists "crontab" ; then _err "crontab doesn't exist, so, we can not install cron jobs." _err "All your certs will not be renewed automatically." - _err "You must add your own cron job to call 'le.sh cron' everyday." + _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday." return 1 fi _info "Installing cron job" - if ! crontab -l | grep 'le.sh cron' ; then - if [[ -f "$LE_WORKING_DIR/le.sh" ]] ; then - lesh="\"$LE_WORKING_DIR\"/le.sh" + if ! crontab -l | grep "$PROJECT_ENTRY --cron" ; then + if [[ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]] ; then + lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" else - _err "Can not install cronjob, le.sh not found." + _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi - crontab -l | { cat; echo "0 0 * * * LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null"; } | crontab - + crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab - fi if [[ "$?" != "0" ]] ; then _err "Install cron job failed. You need to manually renew your certs." _err "Or you can add cronjob by yourself:" - _err "LE_WORKING_DIR=\"$LE_WORKING_DIR\" $lesh cron > /dev/null" + _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" return 1 fi } @@ -1537,20 +1541,20 @@ uninstallcronjob() { return fi _info "Removing cron job" - cr="$(crontab -l | grep 'le.sh cron')" + cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")" if [[ "$cr" ]] ; then - crontab -l | sed "/le.sh cron/d" | crontab - - LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 6 | cut -d '=' -f 2 | tr -d '"')" + crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab - + LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" fi _initpath - + } revoke() { Le_Domain="$1" if [[ -z "$Le_Domain" ]] ; then - echo "Usage: le.sh --revoke -d domain.com" + echo "Usage: $PROJECT_ENTRY --revoke -d domain.com" return 1 fi @@ -1658,7 +1662,7 @@ _initconf() { #ACCOUNT_KEY_HASH=account key hash -USER_AGENT=\"le.sh client: $PROJECT\" +USER_AGENT=\"$DEFAULT_USER_AGENT\" #USER_PATH="" @@ -1698,8 +1702,8 @@ _precheck() { _err "We need to set cron job to renew the certs automatically." _err "Otherwise, your certs will not be able to be renewed automatically." if [[ -z "$FORCE" ]] ; then - _err "Please define 'FORCE=1' and try install again to go without crontab." - _err "FORCE=1 ./le.sh install" + _err "Please add '--force' and try install again to go without crontab." + _err "./$PROJECT_ENTRY --install --force" return 1 fi fi @@ -1737,28 +1741,28 @@ install() { return 1 fi - cp le.sh "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/le.sh" + cp $PROJECT_ENTRY "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" if [[ "$?" != "0" ]] ; then - _err "Install failed, can not copy le.sh" + _err "Install failed, can not copy $PROJECT_ENTRY" return 1 fi - _info "Installed to $LE_WORKING_DIR/le.sh" + _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" _profile="$(_detect_profile)" if [[ "$_profile" ]] ; then _debug "Found profile: $_profile" echo "LE_WORKING_DIR=$LE_WORKING_DIR -alias le=\"$LE_WORKING_DIR/le.sh\" -alias le.sh=\"$LE_WORKING_DIR/le.sh\" - " > "$LE_WORKING_DIR/le.env" +alias le=\"$LE_WORKING_DIR/$PROJECT_ENTRY\" +alias $PROJECT_ENTRY=\"$LE_WORKING_DIR/$PROJECT_ENTRY\" + " > "$LE_WORKING_DIR/$PROJECT_ENTRY.env" echo "" >> "$_profile" - _setopt "$_profile" "source \"$LE_WORKING_DIR/le.env\"" - _info "OK, Close and reopen your terminal to start using le" + _setopt "$_profile" "source \"$LE_WORKING_DIR/$PROJECT_NAME.env\"" + _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" else - _info "No profile is found, you will need to go into $LE_WORKING_DIR to use le.sh" + _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" fi mkdir -p $LE_WORKING_DIR/dnsapi @@ -1788,10 +1792,10 @@ uninstall() { _profile="$(_detect_profile)" if [[ "$_profile" ]] ; then text="$(cat $_profile)" - echo "$text" | sed "s|^source.*le.env.*$||" > "$_profile" + echo "$text" | sed "s|^source.*$PROJECT_NAME.env.*$||" > "$_profile" fi - rm -f $LE_WORKING_DIR/le.sh + rm -f $LE_WORKING_DIR/$PROJECT_ENTRY _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." } @@ -1809,12 +1813,12 @@ version() { showhelp() { version - echo "Usage: le.sh command ...[parameters].... + echo "Usage: $PROJECT_ENTRY command ...[parameters].... Commands: --help, -h Show this help message. --version, -v Show version info. - --install Install le.sh to your system. - --uninstall Uninstall le.sh, and uninstall the cron job. + --install Install $PROJECT_NAME to your system. + --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job. --issue Issue a cert. --installcert Install the issued cert to apache/nginx or any other server. --renew, -r Renew a cert. @@ -1852,7 +1856,7 @@ Parameters: --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. --accountconf Specifies a customized account config file. - --leworkingdir Specifies the home dir for le.sh + --home Specifies the home dir for $PROJECT_NAME " } @@ -1873,8 +1877,8 @@ _installOnline() { _info "Extracting $localname" tar xzf $localname cd "le-$BRANCH" - chmod +x le.sh - if ./le.sh install ; then + chmod +x $PROJECT_ENTRY + if ./$PROJECT_ENTRY install ; then _info "Install success!" fi @@ -2059,9 +2063,11 @@ _process() { ;; --accountconf) ACCOUNT_CONF_PATH="$2" + shift ;; - --leworkingdir) + --home) LE_WORKING_DIR="$2" + shift ;; *) From 3d434e43ad1e8dac5b9fdb993ee10c68702dadec Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 13 Apr 2016 21:38:13 +0800 Subject: [PATCH 0094/1348] minor --- le.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/le.sh b/le.sh index 746740d7..58247b81 100755 --- a/le.sh +++ b/le.sh @@ -672,7 +672,7 @@ _stopserver(){ kill -s 9 $ncid > /dev/null done - _get "http://localhost:$Le_HTTPPort" >/dev/null 2>$1 + _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 } From 70a5587513bed00d51fb34014ebbfda001b350b5 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 13 Apr 2016 22:58:03 +0800 Subject: [PATCH 0095/1348] typo --- le.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/le.sh b/le.sh index 58247b81..ef400ccf 100755 --- a/le.sh +++ b/le.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -VER=2.0.1 +VER=2.0.2 PROJECT_NAME="le.sh" PROJECT_ENTRY="le.sh" @@ -2084,7 +2084,7 @@ _process() { install) install ;; uninstall) uninstall ;; issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keylength" "$_capath" "$_reloadcmd" "$_fullchainpath" + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" ;; installcert) installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" From 65938b73e1174b600132d20972f18693dbe068d0 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 13 Apr 2016 23:36:32 +0800 Subject: [PATCH 0096/1348] update doc for --home --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1c98b295..abe8a1ee 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ You can simply uninstall 1.x and re-install 2.x. #How to install -1. Install online: +### 1. Install online: ``` curl https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLONLINE=1 bash @@ -59,7 +59,7 @@ wget -O - https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLO ``` -2. Or, Install from git: +### 2. Or, Install from git: Clone this project: ``` git clone https://github.com/Neilpang/le.git @@ -82,7 +82,7 @@ Show help message: ``` root@v1:~# le.sh https://github.com/Neilpang/le -v2.0.0 +v2.0.2 Usage: le.sh command ...[parameters].... Commands: --help, -h Show this help message. @@ -126,7 +126,8 @@ Parameters: --reloadcmd "service nginx reload" After issue/renew, it's used to reload the server. --accountconf Specifies a customized account config file. - --leworkingdir Specifies the home dir for le.sh + --home Specifies the home dir for le.sh + ``` From 6cc11ffb7ddfa0f505d9a3822de2486c892fecde Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 14 Apr 2016 21:44:26 +0800 Subject: [PATCH 0097/1348] rename to acme.sh --- README.md | 77 ++++++++++++++++++++++++++---------------------- le.sh => acme.sh | 53 +++++++++++++++++++++++++-------- 2 files changed, 81 insertions(+), 49 deletions(-) rename le.sh => acme.sh (97%) diff --git a/README.md b/README.md index abe8a1ee..4c6e2b55 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,17 @@ -# le: means simp`Le` -Simplest shell script for LetsEncrypt free Certificate client - -Simple and Powerful, you only need 3 minutes to learn. +# A acme Shell script: acme.sh +A acme protocol client in pure bash language. +Fully ACME protocol implementation. +Simple, Powerful and very easy to use, you only need 3 minutes to learn. -Pure written in bash, no dependencies to python, acme-tiny or LetsEncrypt official client. +Simplest shell script for LetsEncrypt free Certificate client +Pure written in bash, no dependencies to python or LetsEncrypt official client. Just one script, to issue, renew your certificates automatically. Probably it's the smallest&easiest&smartest shell script to automatically issue & renew the free certificates from LetsEncrypt. NOT require to be `root/sudoer`. -Wiki: https://github.com/Neilpang/le/wiki +Wiki: https://github.com/Neilpang/acme.sh/wiki #Tested OS 1. Ubuntu [![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) @@ -31,7 +32,7 @@ Wiki: https://github.com/Neilpang/le/wiki For all the build status, check our daily build project: -https://github.com/Neilpang/letest.git +https://github.com/Neilpang/acmetest #Supported Mode 1. Webroot mode @@ -39,22 +40,26 @@ https://github.com/Neilpang/letest.git 3. Apache mode 4. Dns mode -#Upgrade from 1.x to 2.x +# Upgrade from 1.x to 2.x You can simply uninstall 1.x and re-install 2.x. 2.x is 100% compatible to 1.x. You will feel nothing changed. +# le.sh renamed to acme.sh NOW! +All configurations are 100% compatible. You just need to uninstall `le.sh` and re-install `acme.sh` again. +Nothing broken. + #How to install ### 1. Install online: ``` -curl https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLONLINE=1 bash +curl https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh | INSTALLONLINE=1 bash ``` Or: ``` -wget -O - https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLONLINE=1 bash +wget -O - https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh | INSTALLONLINE=1 bash ``` @@ -62,17 +67,17 @@ wget -O - https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLO ### 2. Or, Install from git: Clone this project: ``` -git clone https://github.com/Neilpang/le.git -cd le -./le.sh --install +git clone https://github.com/Neilpang/acme.sh.git +cd acme.sh +./acme.sh --install ``` You don't have to be root then, although it is recommended. Which does 3 jobs: -* create and copy `le.sh` to your home dir: `~/.le` +* create and copy `acme.sh` to your home dir: `~/.acme.sh/` All the certs will be placed in this folder. -* create alias : `le.sh=~/.le/le.sh` and `le=~/.le/le.sh`. +* create alias : `acme.sh=~/.acme.sh/acme.sh`. * create everyday cron job to check and renew the cert if needed. After install, you must close current terminal and reopen again to make the alias take effect. @@ -80,15 +85,15 @@ After install, you must close current terminal and reopen again to make the alia Ok, you are ready to issue cert now. Show help message: ``` -root@v1:~# le.sh -https://github.com/Neilpang/le -v2.0.2 -Usage: le.sh command ...[parameters].... +root@v1:~# acme.sh +https://github.com/Neilpang/acme.sh +v2.1.0 +Usage: acme.sh command ...[parameters].... Commands: --help, -h Show this help message. --version, -v Show version info. - --install Install le.sh to your system. - --uninstall Uninstall le.sh, and uninstall the cron job. + --install Install acme.sh to your system. + --uninstall Uninstall acme.sh, and uninstall the cron job. --issue Issue a cert. --installcert Install the issued cert to apache/nginx or any other server. --renew, -r Renew a cert. @@ -126,7 +131,7 @@ Parameters: --reloadcmd "service nginx reload" After issue/renew, it's used to reload the server. --accountconf Specifies a customized account config file. - --home Specifies the home dir for le.sh + --home Specifies the home dir for acme.sh @@ -136,14 +141,14 @@ Parameters: Example 1: Only one domain: ``` -le --issue -d aa.com -w /home/wwwroot/aa.com +acme.sh --issue -d aa.com -w /home/wwwroot/aa.com ``` Example 2: Multiple domains in the same cert: ``` -le --issue -d aa.com -d www.aa.com -d cp.aa.com -w /home/wwwroot/aa.com +acme.sh --issue -d aa.com -d www.aa.com -d cp.aa.com -w /home/wwwroot/aa.com ``` The parameter `/home/wwwroot/aa.com` is the web root folder, You must have `write` access to this folder. @@ -153,19 +158,19 @@ You must have at least domain there. You must point and bind all the domains to the same webroot dir:`/home/wwwroot/aa.com` -The cert will be placed in `~/.le/aa.com/` +The cert will be placed in `~/.acme.sh/aa.com/` The issued cert will be renewed every 80 days automatically. -More examples: https://github.com/Neilpang/le/wiki/How-to-issue-a-cert +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert # Install issued cert to apache/nginx etc. After you issue a cert, you probably want to install the cert to your nginx/apache or other servers to use. ``` -le --installcert -d aa.com \ +acme.sh --installcert -d aa.com \ --certpath /path/to/certfile/in/apache/nginx \ --keypath /path/to/keyfile/in/apache/nginx \ --capath /path/to/ca/certfile/apache/nginx \ @@ -186,10 +191,10 @@ Same usage as all above, just give `no` as the webroot. The tcp `80` port must be free to listen, otherwise you will be prompted to free the `80` port and try again. ``` -le --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com +acme.sh --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com ``` -More examples: https://github.com/Neilpang/le/wiki/How-to-issue-a-cert +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert # Use Apache mode @@ -200,17 +205,17 @@ Particularly, if you are running an apache server, you can use apache mode inst Just set string "apache" to the first argument, it will use apache plugin automatically. ``` -le --issue --apache -d aa.com -d www.aa.com -d user.aa.com +acme.sh --issue --apache -d aa.com -d www.aa.com -d user.aa.com ``` -More examples: https://github.com/Neilpang/le/wiki/How-to-issue-a-cert +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert # Use DNS mode: Support the dns-01 challenge. ``` -le --issue --dns -d aa.com -d www.aa.com -d user.aa.com +acme.sh --issue --dns -d aa.com -d www.aa.com -d user.aa.com ``` You will get the output like bellow: @@ -229,7 +234,7 @@ Please add those txt records to the domains. Waiting for the dns to take effect. Then just retry with 'renew' command: ``` -le --renew -d aa.com +acme.sh --renew -d aa.com ``` Ok, it's finished. @@ -245,7 +250,7 @@ You don't have do anything manually. 1. Cloudflare.com api 2. Dnspod.cn api 3. Cloudxns.com api -4. AWS Route 53, see: https://github.com/Neilpang/le/issues/65 +4. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 More apis are coming soon.... @@ -263,12 +268,12 @@ For example: Single domain: ``` -le --issue -w /home/wwwroot/aa.com -d aa.com --keylength ec-256 +acme.sh --issue -w /home/wwwroot/aa.com -d aa.com --keylength ec-256 ``` SAN multiple domains: ``` -le --issue -w /home/wwwroot/aa.com -d aa.com -d www.aa.com --keylength ec-256 +acme.sh --issue -w /home/wwwroot/aa.com -d aa.com -d www.aa.com --keylength ec-256 ``` Please look at the last parameter above. diff --git a/le.sh b/acme.sh similarity index 97% rename from le.sh rename to acme.sh index ef400ccf..12628c5b 100755 --- a/le.sh +++ b/acme.sh @@ -1,10 +1,11 @@ #!/usr/bin/env bash -VER=2.0.2 +VER=2.1.0 -PROJECT_NAME="le.sh" -PROJECT_ENTRY="le.sh" +PROJECT_NAME="acme.sh" -PROJECT="https://github.com/Neilpang/le" +PROJECT_ENTRY="acme.sh" + +PROJECT="https://github.com/Neilpang/$PROJECT_NAME" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" @@ -679,7 +680,7 @@ _stopserver(){ _initpath() { if [[ -z "$LE_WORKING_DIR" ]] ; then - LE_WORKING_DIR=$HOME/.le + LE_WORKING_DIR=$HOME/.$PROJECT_NAME fi _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" @@ -1734,6 +1735,23 @@ install() { return 1 fi + #convert from le + if [[ -d "$HOME/.le" ]] ; then + for envfile in "le.env" "le.sh.env" + do + if [[ -f "$HOME/.le/$envfile" ]] ; then + if grep "le.sh" "$HOME/.le/$envfile" >/dev/null ; then + _upgrading="1" + _info "You are upgrading from le.sh" + _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR" + mv "$HOME/.le" "$LE_WORKING_DIR" + mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env" + break; + fi + fi + done + fi + _info "Installing to $LE_WORKING_DIR" if ! mkdir -p "$LE_WORKING_DIR" ; then @@ -1754,10 +1772,16 @@ install() { if [[ "$_profile" ]] ; then _debug "Found profile: $_profile" - echo "LE_WORKING_DIR=$LE_WORKING_DIR -alias le=\"$LE_WORKING_DIR/$PROJECT_ENTRY\" -alias $PROJECT_ENTRY=\"$LE_WORKING_DIR/$PROJECT_ENTRY\" - " > "$LE_WORKING_DIR/$PROJECT_ENTRY.env" + _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" + if [[ "$_upgrading" == "1" ]] ; then + echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile" + echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile" + echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile" + fi + + _setopt "$_envfile" "LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" + _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + echo "" >> "$_profile" _setopt "$_profile" "source \"$LE_WORKING_DIR/$PROJECT_NAME.env\"" _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" @@ -1778,8 +1802,11 @@ alias $PROJECT_ENTRY=\"$LE_WORKING_DIR/$PROJECT_ENTRY\" fi _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" - _setopt "$ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" - + + if [[ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]] ; then + _setopt "$ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" + fi + installcronjob _info OK @@ -1876,14 +1903,14 @@ _installOnline() { fi _info "Extracting $localname" tar xzf $localname - cd "le-$BRANCH" + cd "$PROJECT_NAME-$BRANCH" chmod +x $PROJECT_ENTRY if ./$PROJECT_ENTRY install ; then _info "Install success!" fi cd .. - rm -rf "le-$BRANCH" + rm -rf "$PROJECT_NAME-$BRANCH" rm -f "$localname" } From b0515cf8c0109548498e965b9b9fbcac1893b350 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 14 Apr 2016 22:27:51 +0800 Subject: [PATCH 0098/1348] Install from get.acme.sh --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4c6e2b55..e9c08865 100644 --- a/README.md +++ b/README.md @@ -52,14 +52,16 @@ Nothing broken. ### 1. Install online: +Check this project:https://github.com/Neilpang/get.acme.sh + ``` -curl https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh | INSTALLONLINE=1 bash +curl https://get.acme.sh | bash ``` Or: ``` -wget -O - https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh | INSTALLONLINE=1 bash +wget -O - https://get.acme.sh | bash ``` From 2b45dba57c0ba5f71eaa8dd5e2d3997f81e92bfe Mon Sep 17 00:00:00 2001 From: Sergei Filippov Date: Fri, 15 Apr 2016 22:50:40 +1200 Subject: [PATCH 0099/1348] README rewrite Refactoring the README. Cleaned up: - Spelling - Grammar - Formatting Doing my part to help out the maintainer of this awesome tool! Thank you @neilpang --- README.md | 212 +++++++++++++++++++++++++++++------------------------- 1 file changed, 114 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index e9c08865..443f8069 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -# A acme Shell script: acme.sh -A acme protocol client in pure bash language. -Fully ACME protocol implementation. -Simple, Powerful and very easy to use, you only need 3 minutes to learn. +# An ACME Shell script: acme.sh +- An ACME protocol client written purely in Bash (Unix shell) language. +- Fully ACME protocol implementation. +- Simple, powerful and very easy to use. You only need 3 minutes to learn. -Simplest shell script for LetsEncrypt free Certificate client -Pure written in bash, no dependencies to python or LetsEncrypt official client. -Just one script, to issue, renew your certificates automatically. +- Simplest shell script for Let's Encrypt free certificate client. +- Purely written in Bash with no dependencies on python or Let's Encrypt official client. +- Just one script, to issue, renew and install your certificates automatically. -Probably it's the smallest&easiest&smartest shell script to automatically issue & renew the free certificates from LetsEncrypt. +It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. -NOT require to be `root/sudoer`. +DOES NOT require `root/sudoer` access. Wiki: https://github.com/Neilpang/acme.sh/wiki @@ -30,62 +30,76 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki 14. Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_le.sh -For all the build status, check our daily build project: +For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): https://github.com/Neilpang/acmetest -#Supported Mode +# Supported Mode + 1. Webroot mode 2. Standalone mode 3. Apache mode 4. Dns mode # Upgrade from 1.x to 2.x + You can simply uninstall 1.x and re-install 2.x. -2.x is 100% compatible to 1.x. You will feel nothing changed. +2.x is 100% compatible to 1.x. You will feel right at home as if nothing has changed. # le.sh renamed to acme.sh NOW! -All configurations are 100% compatible. You just need to uninstall `le.sh` and re-install `acme.sh` again. -Nothing broken. -#How to install +All configurations are 100% compatible between `le.sh` and `acme.sh`. You just need to uninstall `le.sh` and re-install `acme.sh` again. +Nothing will be broken during the process. + +# How to install ### 1. Install online: Check this project:https://github.com/Neilpang/get.acme.sh -``` +```bash curl https://get.acme.sh | bash ``` Or: -``` + +```bash wget -O - https://get.acme.sh | bash ``` ### 2. Or, Install from git: + Clone this project: -``` + +```bash git clone https://github.com/Neilpang/acme.sh.git -cd acme.sh +cd ./acme.sh ./acme.sh --install ``` -You don't have to be root then, although it is recommended. +You `don't have to be root` then, although `it is recommended`. + +The installer will perform 3 actions: -Which does 3 jobs: -* create and copy `acme.sh` to your home dir: `~/.acme.sh/` -All the certs will be placed in this folder. -* create alias : `acme.sh=~/.acme.sh/acme.sh`. -* create everyday cron job to check and renew the cert if needed. +1. Create and copy `acme.sh` to your home dir (`$HOME`): `~/.acme.sh/`. +All certs will be placed in this folder. +2. Create alia for: `acme.sh=~/.acme.sh/acme.sh`. +3. Create everyday cron job to check and renew the cert if needed. + +Cron entry example: + +```bash +0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null +``` -After install, you must close current terminal and reopen again to make the alias take effect. +After the installation, you must close current terminal and reopen again to make the alias take effect. Ok, you are ready to issue cert now. Show help message: + ``` root@v1:~# acme.sh https://github.com/Neilpang/acme.sh @@ -134,45 +148,42 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for acme.sh - - - ``` # Just issue a cert: -Example 1: -Only one domain: -``` -acme.sh --issue -d aa.com -w /home/wwwroot/aa.com -``` -Example 2: -Multiple domains in the same cert: +**Example 1:** Single domain. +```bash +acme.sh --issue -d aa.com -w /home/wwwroot/aa.com ``` -acme.sh --issue -d aa.com -d www.aa.com -d cp.aa.com -w /home/wwwroot/aa.com + +**Example 2:** Multiple domains in the same cert. + +```bash +acme.sh --issue -d aa.com -d www.aa.com -d cp.aa.com -w /home/wwwroot/aa.com ``` -The parameter `/home/wwwroot/aa.com` is the web root folder, You must have `write` access to this folder. +The parameter `/home/wwwroot/aa.com` is the web root folder. You **MUST** have `write access` to this folder. -Second argument "aa.com" is the main domain you want to issue cert for. -You must have at least domain there. +Second argument **"aa.com"** is the main domain you want to issue cert for. +You must have at least a domain there. -You must point and bind all the domains to the same webroot dir:`/home/wwwroot/aa.com` +You must point and bind all the domains to the same webroot dir: `/home/wwwroot/aa.com`. -The cert will be placed in `~/.acme.sh/aa.com/` +Generate/issued certs will be placed in `~/.acme.sh/aa.com/` The issued cert will be renewed every 80 days automatically. - More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert # Install issued cert to apache/nginx etc. -After you issue a cert, you probably want to install the cert to your nginx/apache or other servers to use. -``` -acme.sh --installcert -d aa.com \ +After you issue a cert, you probably want to install the cert with your nginx/apache or other servers you may be using. + +```bash +acme.sh --installcert -d aa.com \ --certpath /path/to/certfile/in/apache/nginx \ --keypath /path/to/keyfile/in/apache/nginx \ --capath /path/to/ca/certfile/apache/nginx \ @@ -184,43 +195,48 @@ Only the domain is required, all the other parameters are optional. Install the issued cert/key to the production apache or nginx path. -The cert will be renewed every 80 days by default (which is configurable), Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload` +The cert will be `renewed every 80 days by default` (which is configurable). Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`. +# Use Standalone server to issue cert -# Use Standalone server to issue cert -(requires you be root/sudoer, or you have permission to listen tcp 80 port): -Same usage as all above, just give `no` as the webroot. -The tcp `80` port must be free to listen, otherwise you will be prompted to free the `80` port and try again. +**(requires you be root/sudoer, or you have permission to listen tcp 80 port)** -``` -acme.sh --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com +Same usage as above, just give `no` as `--webroot` or `-w`. + +The tcp `80` port **MUST** be free to listen, otherwise you will be prompted to free the `80` port and try again. + +```bash +acme.sh --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com ``` More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert +# Use Apache mode + +**(requires you be root/sudoer, since it is required to interact with apache server)** + +If you are running a web server, apache or nginx, it is recommended to use the `Webroot mode`. -# Use Apache mode -(requires you be root/sudoer, since it is required to interact with apache server): -If you are running a web server, apache or nginx, it is recommended to use the Webroot mode. -Particularly, if you are running an apache server, you can use apache mode instead. Which doesn't write any file to your web root folder. +Particularly, if you are running an apache server, you should use apache mode instead. This mode doesn't write any files to your web root folder. -Just set string "apache" to the first argument, it will use apache plugin automatically. +Just set string "apache" as the second argument, it will force use of apache plugin automatically. ``` -acme.sh --issue --apache -d aa.com -d www.aa.com -d user.aa.com +acme.sh --issue --apache -d aa.com -d www.aa.com -d user.aa.com ``` More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert - # Use DNS mode: -Support the dns-01 challenge. -``` -acme.sh --issue --dns -d aa.com -d www.aa.com -d user.aa.com +Support the `dns-01` challenge. + +```bash +acme.sh --issue --dns -d aa.com -d www.aa.com -d user.aa.com ``` -You will get the output like bellow: +You should get the output like below: + ``` Add the following txt record: Domain:_acme-challenge.aa.com @@ -229,86 +245,86 @@ Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c Add the following txt record: Domain:_acme-challenge.www.aa.com Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -``` Please add those txt records to the domains. Waiting for the dns to take effect. -Then just retry with 'renew' command: - ``` -acme.sh --renew -d aa.com + +Then just rerun with `renew` argument: + +```bash +acme.sh --renew -d aa.com ``` Ok, it's finished. +# Automatic DNS API integration -#Automatic dns api integeration +If your DNS provider supports API access, we can use API to automatically issue the certs. -If your dns provider supports api access, we can use api to automatically issue certs. -You don't have do anything manually. +You don't have do anything manually! -###Currently we support: +### Currently acme.sh supports: -1. Cloudflare.com api -2. Dnspod.cn api -3. Cloudxns.com api +1. Cloudflare.com API +2. Dnspod.cn API +3. Cloudxns.com API 4. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 -More apis are coming soon.... +##### More APIs are coming soon... -If your dns provider is not in the supported list above, you can write your own script api easily. +If your DNS provider is not on the supported list above, you can write your own script API easily. If you do please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute to the project. For more details: [How to use dns api](dnsapi) - # Issue ECC certificate: -LetsEncrypt now can issue ECDSA certificate. + +`Let's Encrypt` now can issue **ECDSA** certificates. + And we also support it. Just set the `length` parameter with a prefix `ec-`. + For example: -Single domain: -``` -acme.sh --issue -w /home/wwwroot/aa.com -d aa.com --keylength ec-256 -``` +### Single domain ECC cerfiticate: -SAN multiple domains: +```bash +acme.sh --issue -w /home/wwwroot/aa.com -d aa.com --keylength ec-256 ``` -acme.sh --issue -w /home/wwwroot/aa.com -d aa.com -d www.aa.com --keylength ec-256 + +SAN multi domain ECC certificate: + +```bash +acme.sh --issue -w /home/wwwroot/aa.com -d aa.com -d www.aa.com --keylength ec-256 ``` Please look at the last parameter above. Valid values are: -1. ec-256 (prime256v1, "ECDSA P-256") -2. ec-384 (secp384r1, "ECDSA P-384") -3. ec-521 (secp521r1, "ECDSA P-521", which is not supported by letsencrypt yet.) - - +1. **ec-256 (prime256v1, "ECDSA P-256")** +2. **ec-384 (secp384r1, "ECDSA P-384")** +3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)** -#Under the Hood +# Under the Hood -Speak ACME language with bash directly to Let's encrypt. +Speak ACME language using bash, directly to "Let's Encrypt". TODO: - -#Acknowledgment +# Acknowledgment 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme 3. letsencrypt: https://github.com/letsencrypt/letsencrypt - - -#License & Other +# License & Other License is GPLv3 Please Star and Fork me. -Issues and pull requests are welcomed. +[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcomed. From fb675223244a24b7d0d9a6f61829ccfda1a20815 Mon Sep 17 00:00:00 2001 From: Sergei Filippov Date: Fri, 15 Apr 2016 23:41:15 +1200 Subject: [PATCH 0100/1348] Update dns-myapi.sh --- dnsapi/dns-myapi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns-myapi.sh b/dnsapi/dns-myapi.sh index 9d53c7f7..4236e41c 100644 --- a/dnsapi/dns-myapi.sh +++ b/dnsapi/dns-myapi.sh @@ -3,7 +3,7 @@ #Here is a sample custom api script. #This file name is "dns-myapi.sh" #So, here must be a method dns-myapi-add() -#Which will be called by le.sh to add the txt record to your api system. +#Which will be called by acme.sh to add the txt record to your api system. #returns 0 meanst success, otherwise error. From 937cbf6df88a72503da7c0583787a98007dc8331 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 15 Apr 2016 20:45:08 +0800 Subject: [PATCH 0101/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 443f8069..8170bd13 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki 5. FreeBSD with bash [![](https://cdn.rawgit.com/Neilpang/letest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 6. pfsense with bash and curl 7. openSUSE [![](https://cdn.rawgit.com/Neilpang/letest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with bash, curl. https://github.com/Neilpang/le/issues/94) +8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with bash and curl) 9. Archlinux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 10. fedora [![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 11. Kali Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) From 41e3eafa900e97fd5f93a9b82507c379fecf9313 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 15 Apr 2016 21:27:32 +0800 Subject: [PATCH 0102/1348] skip creating accountkey/domainkey if already existing --- acme.sh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 12628c5b..09e2241f 100755 --- a/acme.sh +++ b/acme.sh @@ -321,7 +321,7 @@ createDomainKey() { return 0 else _err "Domain key exists, do you want to overwrite the key?" - _err "Set FORCE=1, and try again." + _err "Add '--force', and try again." return 1 fi fi @@ -1003,8 +1003,13 @@ issue() { usingApache="" fi - createAccountKey $Le_Domain $Le_Keylength - + if [[ ! -f "$ACCOUNT_KEY_PATH" ]] ; then + if ! createAccountKey $Le_Domain $Le_Keylength ; then + _err "Create account key error." + return 1 + fi + fi + if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then return 1 fi @@ -1038,9 +1043,11 @@ issue() { _info "Skip register account key" fi - if ! createDomainKey $Le_Domain $Le_Keylength ; then - _err "Create domain key error." - return 1 + if [[ ! -f "$CERT_KEY_PATH" ]] ; then + if ! createDomainKey $Le_Domain $Le_Keylength ; then + _err "Create domain key error." + return 1 + fi fi if ! createCSR $Le_Domain $Le_Alt ; then From 635695ec84485f83781bf435b6f0009653430b7d Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 17:25:26 +0800 Subject: [PATCH 0103/1348] add `--useragent` to specify user-aggent for install or issue or other command --- acme.sh | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/acme.sh b/acme.sh index 09e2241f..d115b869 100755 --- a/acme.sh +++ b/acme.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -VER=2.1.0 +VER=2.1.1 PROJECT_NAME="acme.sh" @@ -685,8 +685,10 @@ _initpath() { _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" - if [[ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]] ; then - source "$_DEFAULT_ACCOUNT_CONF_PATH" + if [[ -z "$ACCOUNT_CONF_PATH" ]] ; then + if [[ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]] ; then + source "$_DEFAULT_ACCOUNT_CONF_PATH" + fi fi if [[ -z "$ACCOUNT_CONF_PATH" ]] ; then @@ -1670,7 +1672,7 @@ _initconf() { #ACCOUNT_KEY_HASH=account key hash -USER_AGENT=\"$DEFAULT_USER_AGENT\" +USER_AGENT=\"$USER_AGENT\" #USER_PATH="" @@ -1732,11 +1734,12 @@ _precheck() { } install() { + if ! _initpath ; then _err "Install failed." return 1 fi - + if ! _precheck ; then _err "Pre-check failed, can not install." return 1 @@ -1760,7 +1763,7 @@ install() { fi _info "Installing to $LE_WORKING_DIR" - + if ! mkdir -p "$LE_WORKING_DIR" ; then _err "Can not craete working dir: $LE_WORKING_DIR" return 1 @@ -1807,11 +1810,9 @@ install() { if [[ ! -f "$ACCOUNT_CONF_PATH" ]] ; then _initconf fi - - _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" if [[ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]] ; then - _setopt "$ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" + _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" fi installcronjob @@ -1890,7 +1891,8 @@ Parameters: --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. --accountconf Specifies a customized account config file. - --home Specifies the home dir for $PROJECT_NAME + --home Specifies the home dir for $PROJECT_NAME . + --useragent Specifies the user agent string. it will be saved for future use too. " } @@ -1935,6 +1937,8 @@ _process() { _fullchainpath="no" _reloadcmd="no" _password="" + _accountconf="" + _useragent="" while (( ${#} )); do case "${1}" in @@ -2087,7 +2091,7 @@ _process() { _fullchainpath="$2" shift ;; - --reloadcmd) + --reloadcmd|--reloadCmd) _reloadcmd="$2" shift ;; @@ -2096,14 +2100,19 @@ _process() { shift ;; --accountconf) - ACCOUNT_CONF_PATH="$2" + _accountconf="$2" + ACCOUNT_CONF_PATH="$_accountconf" shift ;; --home) LE_WORKING_DIR="$2" shift ;; - + --useragent) + _useragent="$2" + USER_AGENT="$_useragent" + shift + ;; *) _err "Unknown parameter : $1" return 1 @@ -2155,6 +2164,10 @@ _process() { ;; esac + if [[ "$_useragent" ]] ; then + _saveaccountconf "USER_AGENT" "$_useragent" + fi + } From 93c9216b69ba3a21e7c2976bd70377c7a7121031 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 17:27:30 +0800 Subject: [PATCH 0104/1348] update doc --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8170bd13..665806c0 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Show help message: ``` root@v1:~# acme.sh https://github.com/Neilpang/acme.sh -v2.1.0 +v2.1.1 Usage: acme.sh command ...[parameters].... Commands: --help, -h Show this help message. @@ -147,7 +147,9 @@ Parameters: --reloadcmd "service nginx reload" After issue/renew, it's used to reload the server. --accountconf Specifies a customized account config file. - --home Specifies the home dir for acme.sh + --home Specifies the home dir for acme.sh . + --useragent Specifies the user agent string. it will be saved for future use too. + ``` # Just issue a cert: From b5eb4b904e1c677097064d900d36f4f09ca8d3db Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 17:56:45 +0800 Subject: [PATCH 0105/1348] add `--accountkey` and `--accountemail` --- README.md | 2 ++ acme.sh | 25 +++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 665806c0..12bc5a16 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,8 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for acme.sh . --useragent Specifies the user agent string. it will be saved for future use too. + --accountemail Specifies the account email for registering, Only valid for the '--install' command. + --accountkey Specifyes the account key path, Only valid for the '--install' command. ``` diff --git a/acme.sh b/acme.sh index d115b869..2909a480 100755 --- a/acme.sh +++ b/acme.sh @@ -246,12 +246,13 @@ createAccountKey() { account=$1 length=$2 - + _debug account "$account" + _debug length "$length" if [[ "$length" == "ec-"* ]] ; then length=2048 fi - if [[ -z "$2" ]] ; then + if [[ -z "$2" ]] || [[ "$2" == "no" ]] ; then _info "Use default length 2048" length=2048 fi @@ -1893,6 +1894,8 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME . --useragent Specifies the user agent string. it will be saved for future use too. + --accountemail Specifies the account email for registering, Only valid for the '--install' command. + --accountkey Specifyes the account key path, Only valid for the '--install' command. " } @@ -1939,6 +1942,8 @@ _process() { _password="" _accountconf="" _useragent="" + _accountemail="" + _accountkey="" while (( ${#} )); do case "${1}" in @@ -2113,6 +2118,16 @@ _process() { USER_AGENT="$_useragent" shift ;; + --accountemail ) + _accountemail="$2" + ACCOUNT_EMAIL="$_accountemail" + shift + ;; + --accountkey ) + _accountkey="$2" + ACCOUNT_KEY_PATH="$_accountkey" + shift + ;; *) _err "Unknown parameter : $1" return 1 @@ -2167,6 +2182,12 @@ _process() { if [[ "$_useragent" ]] ; then _saveaccountconf "USER_AGENT" "$_useragent" fi + if [[ "$_accountemail" ]] ; then + _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" + fi + if [[ "$_accountkey" ]] ; then + _saveaccountconf "ACCOUNT_KEY_PATH" "$_accountkey" + fi } From 06625071163831b02a947a418274409d5e51f014 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 18:15:36 +0800 Subject: [PATCH 0106/1348] add `--days` only valid for `-issue` command. --- README.md | 3 ++- acme.sh | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 12bc5a16..f28da338 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,8 @@ Parameters: --home Specifies the home dir for acme.sh . --useragent Specifies the user agent string. it will be saved for future use too. --accountemail Specifies the account email for registering, Only valid for the '--install' command. - --accountkey Specifyes the account key path, Only valid for the '--install' command. + --accountkey Specifies the account key path, Only valid for the '--install' command. + --days Specifies the days to renew the cert when using '--issue' command. The max value is 80 days. ``` diff --git a/acme.sh b/acme.sh index 2909a480..bfe86b72 100755 --- a/acme.sh +++ b/acme.sh @@ -1366,7 +1366,7 @@ issue() { Le_CertCreateTimeStr=$(date -u ) _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\"" - if [[ ! "$Le_RenewalDays" ]] ; then + if [[ -z "$Le_RenewalDays" ]] || [[ "$Le_RenewalDays" -lt "0" ]] || [[ "$Le_RenewalDays" -gt "80" ]] ; then Le_RenewalDays=80 fi @@ -1895,7 +1895,8 @@ Parameters: --home Specifies the home dir for $PROJECT_NAME . --useragent Specifies the user agent string. it will be saved for future use too. --accountemail Specifies the account email for registering, Only valid for the '--install' command. - --accountkey Specifyes the account key path, Only valid for the '--install' command. + --accountkey Specifies the account key path, Only valid for the '--install' command. + --days Specifies the days to renew the cert when using '--issue' command. The max value is 80 days. " } @@ -2128,6 +2129,11 @@ _process() { ACCOUNT_KEY_PATH="$_accountkey" shift ;; + --days ) + _days="$2" + Le_RenewalDays="$_days" + shift + ;; *) _err "Unknown parameter : $1" return 1 From 5ef501c5ece35003eaa341f1c73b6838b0bbe528 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 18:31:00 +0800 Subject: [PATCH 0107/1348] More. restore apache on error --- acme.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index bfe86b72..cfaab324 100755 --- a/acme.sh +++ b/acme.sh @@ -818,10 +818,12 @@ _restoreApache() { fi cp -p "$APACHE_CONF_BACKUP_DIR/$httpdconfname" "$httpdconf" + _debug "Restored: $httpdconf." if ! apachectl -t ; then _err "Sorry, restore apache config error, please contact me." return 1; fi + _debug "Restored successfully." rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" return 0 } @@ -886,7 +888,7 @@ Allow from all return 0 } -_clearup () { +_clearup() { _stopserver $serverproc serverproc="" _restoreApache @@ -977,7 +979,7 @@ issue() { if [[ "$Le_Webroot" == *"no"* ]] ; then _info "Standalone mode." - if ! command -v "nc" > /dev/null ; then + if ! _exists "nc" ; then _err "Please install netcat(nc) tools first." return 1 fi @@ -1009,11 +1011,17 @@ issue() { if [[ ! -f "$ACCOUNT_KEY_PATH" ]] ; then if ! createAccountKey $Le_Domain $Le_Keylength ; then _err "Create account key error." + if [[ "$usingApache" ]] ; then + _restoreApache + fi return 1 fi fi if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then + if [[ "$usingApache" ]] ; then + _restoreApache + fi return 1 fi @@ -1049,12 +1057,14 @@ issue() { if [[ ! -f "$CERT_KEY_PATH" ]] ; then if ! createDomainKey $Le_Domain $Le_Keylength ; then _err "Create domain key error." + _clearup return 1 fi fi if ! createCSR $Le_Domain $Le_Alt ; then _err "Create CSR error." + _clearup return 1 fi @@ -1171,6 +1181,7 @@ issue() { ) if [[ "$?" != "0" ]] ; then + _clearup return 1 fi dnsadded='1' @@ -1181,6 +1192,7 @@ issue() { _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\"" _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." + _clearup return 1 fi @@ -1216,6 +1228,7 @@ issue() { _info "Standalone mode server" _startserver "$keyauthorization" & if [[ "$?" != "0" ]] ; then + _clearup return 1 fi serverproc="$!" From b2817897774c63bb32ff625207e77f2031cb8ae6 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 19:05:53 +0800 Subject: [PATCH 0108/1348] add `--certhome` for `--install` command to save all the certs. --- README.md | 1 + acme.sh | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f28da338..ebcbed50 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for acme.sh . + --certhome Specifies the home dir to save all the certs, only valid for '--install' command. --useragent Specifies the user agent string. it will be saved for future use too. --accountemail Specifies the account email for registering, Only valid for the '--install' command. --accountkey Specifies the account key path, Only valid for the '--install' command. diff --git a/acme.sh b/acme.sh index cfaab324..b467bdaa 100755 --- a/acme.sh +++ b/acme.sh @@ -740,18 +740,24 @@ _initpath() { if [[ "$DEBUG" -ge "2" ]] ; then CURL="$CURL -L --trace-ascii $dp " fi - - domain="$1" - + + _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" if [[ -z "$ACCOUNT_KEY_PATH" ]] ; then - ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" + ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" fi + + domain="$1" if [[ -z "$domain" ]] ; then return 0 fi - domainhome="$LE_WORKING_DIR/$domain" + _DEFAULT_CERT_HOME="$LE_WORKING_DIR" + if [[ -z "$CERT_HOME" ]] ; then + CERT_HOME="$_DEFAULT_CERT_HOME" + fi + + domainhome="$CERT_HOME/$domain" mkdir -p "$domainhome" if [[ -z "$DOMAIN_PATH" ]] ; then @@ -1428,7 +1434,7 @@ renewAll() { _initpath _info "renewAll" - for d in $(ls -F ${LE_WORKING_DIR}/ | grep [^.].*[.].*/$ ) ; do + for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do d=$(echo $d | cut -d '/' -f 1) _info "renew $d" @@ -1679,6 +1685,7 @@ _initconf() { #ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. #ACCOUNT_KEY_PATH=\"/path/to/account.key\" +#CERT_HOME=\"/path/to/cert/home\" #STAGE=1 # Use the staging api #FORCE=1 # Force to issue cert @@ -1829,6 +1836,14 @@ install() { _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" fi + if [[ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]] ; then + _saveaccountconf "CERT_HOME" "$CERT_HOME" + fi + + if [[ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]] ; then + _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH" + fi + installcronjob _info OK @@ -1906,6 +1921,7 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME . + --certhome Specifies the home dir to save all the certs. --useragent Specifies the user agent string. it will be saved for future use too. --accountemail Specifies the account email for registering, Only valid for the '--install' command. --accountkey Specifies the account key path, Only valid for the '--install' command. @@ -1958,6 +1974,7 @@ _process() { _useragent="" _accountemail="" _accountkey="" + _certhome="" while (( ${#} )); do case "${1}" in @@ -2127,6 +2144,11 @@ _process() { LE_WORKING_DIR="$2" shift ;; + --certhome) + _certhome="$2" + CERT_HOME="$_certhome" + shift + ;; --useragent) _useragent="$2" USER_AGENT="$_useragent" @@ -2204,9 +2226,7 @@ _process() { if [[ "$_accountemail" ]] ; then _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" fi - if [[ "$_accountkey" ]] ; then - _saveaccountconf "ACCOUNT_KEY_PATH" "$_accountkey" - fi + } From 6f93064114195b82c83579e1b8597670f8379c51 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 19:23:44 +0800 Subject: [PATCH 0109/1348] fix bug: multi webroots --- acme.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index b467bdaa..d1f4e2f1 100755 --- a/acme.sh +++ b/acme.sh @@ -1009,7 +1009,6 @@ issue() { _err "set up apache error. Report error to me." return 1 fi - wellknown_path="$ACME_DIR" else usingApache="" fi @@ -1242,19 +1241,21 @@ issue() { _debug serverproc $serverproc else - if [[ -z "$wellknown_path" ]] ; then + if [[ "$_currentRoot" == "apache" ]] ; then + wellknown_path="$ACME_DIR" + else wellknown_path="$_currentRoot/.well-known/acme-challenge" + if [[ ! -d "$_currentRoot/.well-known" ]] ; then + removelevel='1' + elif [[ ! -d "$_currentRoot/.well-known/acme-challenge" ]] ; then + removelevel='2' + else + removelevel='3' + fi fi + _debug wellknown_path "$wellknown_path" - - if [[ ! -d "$_currentRoot/.well-known" ]] ; then - removelevel='1' - elif [[ ! -d "$_currentRoot/.well-known/acme-challenge" ]] ; then - removelevel='2' - else - removelevel='3' - fi - + token="$(echo -e -n "$keyauthorization" | cut -d '.' -f 1)" _debug "writing token:$token to $wellknown_path/$token" From eac18b1c99ca294c5ac8e8585a747f7ea3b6ffeb Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 19:38:11 +0800 Subject: [PATCH 0110/1348] fix compatible for sh --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d1f4e2f1..95870cea 100755 --- a/acme.sh +++ b/acme.sh @@ -62,7 +62,11 @@ _exists() { _err "Usage: _exists cmd" return 1 fi - command -v $cmd >/dev/null 2>&1 + if type command >/dev/null 2>&1 ; then + command -v $cmd >/dev/null 2>&1 + else + type $cmd >/dev/null 2>&1 + fi ret="$?" _debug2 "$cmd exists=$ret" return $ret From 8f7ad693a843fca054a80c6556e963b7fb9e4c62 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 20:02:41 +0800 Subject: [PATCH 0111/1348] fix compatible for `sh` --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 95870cea..ba516bc3 100755 --- a/acme.sh +++ b/acme.sh @@ -50,7 +50,7 @@ _debug() { } _debug2() { - if [[ "$DEBUG" -ge "2" ]] ; then + if [[ "$DEBUG" ]] && [[ "$DEBUG" -ge "2" ]] ; then _debug "$@" fi return @@ -735,13 +735,13 @@ _initpath() { HTTP_HEADER="$LE_WORKING_DIR/http.header" WGET="wget -q" - if [[ "$DEBUG" -ge "2" ]] ; then + if [[ "$DEBUG" ]] && [[ "$DEBUG" -ge "2" ]] ; then WGET="$WGET -d " fi dp="$LE_WORKING_DIR/curl.dump" CURL="curl -L --silent" - if [[ "$DEBUG" -ge "2" ]] ; then + if [[ "$DEBUG" ]] && [[ "$DEBUG" -ge "2" ]] ; then CURL="$CURL -L --trace-ascii $dp " fi From 6ed1c718b92bddcf729f842aa0f0b79c6c1ee391 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 20:06:26 +0800 Subject: [PATCH 0112/1348] minor, install without dnsapi --- acme.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index ba516bc3..1fcee01d 100755 --- a/acme.sh +++ b/acme.sh @@ -1825,8 +1825,10 @@ install() { _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" fi - mkdir -p $LE_WORKING_DIR/dnsapi - cp dnsapi/* $LE_WORKING_DIR/dnsapi/ + if [[ -d "dnsapi" ]] ; then + mkdir -p $LE_WORKING_DIR/dnsapi + cp dnsapi/* $LE_WORKING_DIR/dnsapi/ + fi #to keep compatible mv the .acc file to .key file if [[ -f "$LE_WORKING_DIR/account.acc" ]] ; then From 036e9d107483434dcb6bdc8b4701d244cfcfc8f6 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 21:01:40 +0800 Subject: [PATCH 0113/1348] fix compatible for sh --- acme.sh | 4 ++-- dnsapi/dns-cf.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 1fcee01d..0cafab94 100755 --- a/acme.sh +++ b/acme.sh @@ -1982,7 +1982,7 @@ _process() { _accountemail="" _accountkey="" _certhome="" - while (( ${#} )); do + while [[ ${#} -gt 0 ]] ; do case "${1}" in --help|-h) @@ -2247,7 +2247,7 @@ fi if [[ -z "$1" ]] ; then showhelp else - if [[ "$1" == "-"* ]] ; then + if echo "$1" | grep "^-" >/dev/null 2>&1 ; then _process "$@" else "$@" diff --git a/dnsapi/dns-cf.sh b/dnsapi/dns-cf.sh index dc56bf13..b2d67c7a 100755 --- a/dnsapi/dns-cf.sh +++ b/dnsapi/dns-cf.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env sh # @@ -12,7 +12,7 @@ CF_Api="https://api.cloudflare.com/client/v4/" ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns-cf-add() { +dns-cf-add(){ fulldomain=$1 txtvalue=$2 From dceb3acacea4faf84c216c1cb736fc75b31f92bf Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 21:52:24 +0800 Subject: [PATCH 0114/1348] fix compatible for sh --- acme.sh | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 0cafab94..72a297a8 100755 --- a/acme.sh +++ b/acme.sh @@ -56,7 +56,19 @@ _debug2() { return } -_exists() { +_startswith(){ + _str="$1" + _sub="$2" + echo $_str | grep ^$_sub >/dev/null 2>&1 +} + +_contains(){ + _str="$1" + _sub="$2" + echo $_str | grep $_sub >/dev/null 2>&1 +} + +_exists(){ cmd="$1" if [[ -z "$cmd" ]] ; then _err "Usage: _exists cmd" @@ -252,7 +264,7 @@ createAccountKey() { length=$2 _debug account "$account" _debug length "$length" - if [[ "$length" == "ec-"* ]] ; then + if _startswith "$length" "ec-" ; then length=2048 fi @@ -283,7 +295,7 @@ createDomainKey() { domain=$1 length=$2 isec="" - if [[ "$length" == "ec-"* ]] ; then + if _startswith "$length" "ec-" ; then isec="1" length=$(printf $length | cut -d '-' -f 2-100) eccname="$length" @@ -583,14 +595,14 @@ _setopt() { if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then _debug2 OK - if [[ "$__val" == *"&"* ]] ; then + if _contains "$__val" "&" ; then __val="$(echo $__val | sed 's/&/\\&/g')" fi text="$(cat $__conf)" echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then - if [[ "$__val" == *"&"* ]] ; then + if _contains "$__val" "&" ; then __val="$(echo $__val | sed 's/&/\\&/g')" fi text="$(cat $__conf)" @@ -798,7 +810,7 @@ _initpath() { _apachePath() { httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" - if [[ "$httpdconfname" == '/'* ]] ; then + if _startswith "$httpdconfname" '/' ; then httpdconf="$httpdconfname" httpdconfname="$(basename $httpdconfname)" else @@ -987,7 +999,7 @@ issue() { fi - if [[ "$Le_Webroot" == *"no"* ]] ; then + if _contains "$Le_Webroot" "no" ; then _info "Standalone mode." if ! _exists "nc" ; then _err "Please install netcat(nc) tools first." @@ -1008,7 +1020,7 @@ issue() { fi fi - if [[ "$Le_Webroot" == *"apache"* ]] ; then + if _contains "$Le_Webroot" "apache" ; then if ! _setApache ; then _err "set up apache error. Report error to me." return 1 @@ -1097,7 +1109,7 @@ issue() { let "_index+=1" vtype="$VTYPE_HTTP" - if [[ "$_currentRoot" == "dns"* ]] ; then + if _startswith "$_currentRoot" "dns" ; then vtype="$VTYPE_DNS" fi _info "Getting token for domain" $d @@ -2040,7 +2052,7 @@ _process() { --domain|-d) _dvalue="$2" - if [[ -z "$_dvalue" ]] || [[ "$_dvalue" == "-"* ]] ; then + if [[ -z "$_dvalue" ]] || _startswith "$_dvalue" "-" ; then _err "'$_dvalue' is not a valid domain for parameter '$1'" return 1 fi @@ -2064,7 +2076,7 @@ _process() { STAGE="1" ;; --debug) - if [[ "$2" == "-"* ]] || [[ -z "$2" ]]; then + if [[ -z "$2" ]] || _startswith "$2" "-" ; then DEBUG="1" else DEBUG="$2" @@ -2098,7 +2110,7 @@ _process() { ;; --dns) wvalue="dns" - if [[ "$2" != "-"* ]] ; then + if ! _startswith "$2" "-" ; then wvalue="$2" shift fi From eccec5f6d5bd7dde81a21cee3a7bf23a573d8822 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 22:19:29 +0800 Subject: [PATCH 0115/1348] fix compatible for sh. '-' is not allowed in function name. --- acme.sh | 17 ++++++++++++++--- dnsapi/dns-cf.sh | 2 +- dnsapi/dns-cx.sh | 2 +- dnsapi/dns-dp.sh | 2 +- dnsapi/dns-myapi.sh | 6 +++--- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index 72a297a8..67910b64 100755 --- a/acme.sh +++ b/acme.sh @@ -956,8 +956,19 @@ issue() { Le_ReloadCmd="$8" Le_RealFullChainPath="$9" - _initpath $Le_Domain + #remove these later. + if [[ "$Le_Webroot" == "dns-cf" ]] ; then + Le_Webroot="dns_cf" + fi + if [[ "$Le_Webroot" == "dns-dp" ]] ; then + Le_Webroot="dns_dp" + fi + if [[ "$Le_Webroot" == "dns-cx" ]] ; then + Le_Webroot="dns_cx" + fi + _initpath $Le_Domain + if [[ -f "$DOMAIN_CONF" ]] ; then Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2) if [[ -z "$FORCE" ]] && [[ "$Le_NextRenewTime" ]] && [[ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ]] ; then @@ -1189,7 +1200,7 @@ issue() { return 1 fi - addcommand="$_currentRoot-add" + addcommand="$_currentRoot_add" if ! _exists $addcommand ; then _err "It seems that your api file is not correct, it must have a function named: $addcommand" return 1 @@ -1924,7 +1935,7 @@ Parameters: --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --standalone Use standalone mode. --apache Use apache mode. - --dns [dns-cf|dns-dp|dns-cx|/path/to/api/file] Use dns mode or dns api. + --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. diff --git a/dnsapi/dns-cf.sh b/dnsapi/dns-cf.sh index b2d67c7a..69216e50 100755 --- a/dnsapi/dns-cf.sh +++ b/dnsapi/dns-cf.sh @@ -12,7 +12,7 @@ CF_Api="https://api.cloudflare.com/client/v4/" ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns-cf-add(){ +dns_cf_add(){ fulldomain=$1 txtvalue=$2 diff --git a/dnsapi/dns-cx.sh b/dnsapi/dns-cx.sh index 2a455a32..130eecf9 100644 --- a/dnsapi/dns-cx.sh +++ b/dnsapi/dns-cx.sh @@ -14,7 +14,7 @@ CX_Api="https://www.cloudxns.net/api2" ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns-cx-add() { +dns_cx_add() { fulldomain=$1 txtvalue=$2 diff --git a/dnsapi/dns-dp.sh b/dnsapi/dns-dp.sh index f58b9d3a..8a7b3362 100644 --- a/dnsapi/dns-dp.sh +++ b/dnsapi/dns-dp.sh @@ -14,7 +14,7 @@ DP_Api="https://dnsapi.cn" ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns-dp-add() { +dns_dp_add() { fulldomain=$1 txtvalue=$2 diff --git a/dnsapi/dns-myapi.sh b/dnsapi/dns-myapi.sh index 4236e41c..cc26ab35 100644 --- a/dnsapi/dns-myapi.sh +++ b/dnsapi/dns-myapi.sh @@ -1,8 +1,8 @@ #!/bin/bash #Here is a sample custom api script. -#This file name is "dns-myapi.sh" -#So, here must be a method dns-myapi-add() +#This file name is "dns_myapi.sh" +#So, here must be a method dns_myapi-add() #Which will be called by acme.sh to add the txt record to your api system. #returns 0 meanst success, otherwise error. @@ -11,7 +11,7 @@ ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns-myapi-add() { +dns_myapi_add() { fulldomain=$1 txtvalue=$2 _err "Not implemented!" From 158f22f733c8d00411cd6d5d214f93a09b294dbd Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 22:31:17 +0800 Subject: [PATCH 0116/1348] fix compatible for sh. rename api. '-' is not allowed in the function name. --- acme.sh | 2 +- dnsapi/README.md | 14 +++++++------- dnsapi/{dns-cf.sh => dns_cf.sh} | 0 dnsapi/{dns-cx.sh => dns_cx.sh} | 0 dnsapi/{dns-dp.sh => dns_dp.sh} | 0 dnsapi/{dns-myapi.sh => dns_myapi.sh} | 0 6 files changed, 8 insertions(+), 8 deletions(-) rename dnsapi/{dns-cf.sh => dns_cf.sh} (100%) rename dnsapi/{dns-cx.sh => dns_cx.sh} (100%) rename dnsapi/{dns-dp.sh => dns_dp.sh} (100%) rename dnsapi/{dns-myapi.sh => dns_myapi.sh} (100%) diff --git a/acme.sh b/acme.sh index 67910b64..b9718aca 100755 --- a/acme.sh +++ b/acme.sh @@ -1200,7 +1200,7 @@ issue() { return 1 fi - addcommand="$_currentRoot_add" + addcommand="${_currentRoot}_add" if ! _exists $addcommand ; then _err "It seems that your api file is not correct, it must have a function named: $addcommand" return 1 diff --git a/dnsapi/README.md b/dnsapi/README.md index b397e556..951d909e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -15,7 +15,7 @@ export CF_Email="xxxx@sss.com" Ok, let's issue cert now: ``` -le.sh --issue --dns dns-cf -d aa.com -d www.aa.com +le.sh --issue --dns dns_cf -d aa.com -d www.aa.com ``` The `CF_Key` and `CF_Email` will be saved in `~/.le/account.conf`, when next time you use cloudflare api, it will reuse this key. @@ -37,7 +37,7 @@ export DP_Key="sADDsdasdgdsf" Ok, let's issue cert now: ``` -le.sh --issue --dns dns-dp -d aa.com -d www.aa.com +le.sh --issue --dns dns_dp -d aa.com -d www.aa.com ``` The `DP_Id` and `DP_Key` will be saved in `~/.le/account.conf`, when next time you use dnspod.cn api, it will reuse this key. @@ -58,7 +58,7 @@ export CX_Secret="sADDsdasdgdsf" Ok, let's issue cert now: ``` -le.sh --issue --dns dns-cx -d aa.com -d www.aa.com +le.sh --issue --dns dns_cx -d aa.com -d www.aa.com ``` The `CX_Key` and `CX_Secret` will be saved in `~/.le/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. @@ -71,15 +71,15 @@ If your api is not supported yet, you can write your own dns api. Let's assume you want to name it 'myapi', -1. Create a bash script named `~/.le/dns-myapi.sh`, -2. In the scrypt, you must have a function named `dns-myapi-add()`. Which will be called by le.sh to add dns records. +1. Create a bash script named `~/.le/dns_myapi.sh`, +2. In the scrypt, you must have a function named `dns_myapi-add()`. Which will be called by le.sh to add dns records. 3. Then you can use your api to issue cert like: ``` -le.sh --issue --dns dns-myapi -d aa.com -d www.aa.com +le.sh --issue --dns dns_myapi -d aa.com -d www.aa.com ``` -For more details, please check our sample script: [dns-myapi.sh](dns-myapi.sh) +For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) diff --git a/dnsapi/dns-cf.sh b/dnsapi/dns_cf.sh similarity index 100% rename from dnsapi/dns-cf.sh rename to dnsapi/dns_cf.sh diff --git a/dnsapi/dns-cx.sh b/dnsapi/dns_cx.sh similarity index 100% rename from dnsapi/dns-cx.sh rename to dnsapi/dns_cx.sh diff --git a/dnsapi/dns-dp.sh b/dnsapi/dns_dp.sh similarity index 100% rename from dnsapi/dns-dp.sh rename to dnsapi/dns_dp.sh diff --git a/dnsapi/dns-myapi.sh b/dnsapi/dns_myapi.sh similarity index 100% rename from dnsapi/dns-myapi.sh rename to dnsapi/dns_myapi.sh From 99dc89c051990f5c6c087c47a90d38a088f5744d Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Apr 2016 23:10:46 +0800 Subject: [PATCH 0117/1348] v2.2.0. It's time to declare that we are `sh` compatible, not only `bash`. --- README.md | 17 +++++++++-------- acme.sh | 4 ++-- dnsapi/dns_cx.sh | 2 +- dnsapi/dns_dp.sh | 2 +- dnsapi/dns_myapi.sh | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ebcbed50..d6b8ed2f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # An ACME Shell script: acme.sh -- An ACME protocol client written purely in Bash (Unix shell) language. +- An ACME protocol client written purely in Shell (Unix shell) language. +- It's `sh` compatible, not only `bash`. - Fully ACME protocol implementation. - Simple, powerful and very easy to use. You only need 3 minutes to learn. - Simplest shell script for Let's Encrypt free certificate client. -- Purely written in Bash with no dependencies on python or Let's Encrypt official client. +- Purely written in Shell with no dependencies on python or Let's Encrypt official client. - Just one script, to issue, renew and install your certificates automatically. It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. @@ -18,10 +19,10 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki 2. Debian [![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 3. CentOS [![](https://cdn.rawgit.com/Neilpang/letest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 4. Windows (cygwin with curl, openssl and crontab included) [![](https://cdn.rawgit.com/Neilpang/letest/master/status/windows.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -5. FreeBSD with bash [![](https://cdn.rawgit.com/Neilpang/letest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -6. pfsense with bash and curl +5. FreeBSD [![](https://cdn.rawgit.com/Neilpang/letest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) +6. pfsense with curl 7. openSUSE [![](https://cdn.rawgit.com/Neilpang/letest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with bash and curl) +8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with curl) 9. Archlinux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 10. fedora [![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 11. Kali Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) @@ -58,14 +59,14 @@ Nothing will be broken during the process. Check this project:https://github.com/Neilpang/get.acme.sh ```bash -curl https://get.acme.sh | bash +curl https://get.acme.sh | sh ``` Or: ```bash -wget -O - https://get.acme.sh | bash +wget -O - https://get.acme.sh | sh ``` @@ -315,7 +316,7 @@ Valid values are: # Under the Hood -Speak ACME language using bash, directly to "Let's Encrypt". +Speak ACME language using shell, directly to "Let's Encrypt". TODO: diff --git a/acme.sh b/acme.sh index b9718aca..7d9899e5 100755 --- a/acme.sh +++ b/acme.sh @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -VER=2.1.1 +#!/usr/bin/env sh +VER=2.2.0 PROJECT_NAME="acme.sh" diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 130eecf9..30b9bbfa 100644 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env sh # Cloudxns.com Domain api # diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 8a7b3362..dc9d433b 100644 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env sh # Dnspod.cn Domain api # diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index cc26ab35..f06cc1e6 100644 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env sh #Here is a sample custom api script. #This file name is "dns_myapi.sh" From 8663fb7e64e5e3a712c39f2d2cb7cf6bca7b5ef0 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 07:38:43 +0800 Subject: [PATCH 0118/1348] revert to bash. there are some issue with sh need to fix yet. --- acme.sh | 420 ++++++++++++++++++++++---------------------- dnsapi/dns_cf.sh | 2 +- dnsapi/dns_cx.sh | 2 +- dnsapi/dns_dp.sh | 2 +- dnsapi/dns_myapi.sh | 2 +- 5 files changed, 214 insertions(+), 214 deletions(-) diff --git a/acme.sh b/acme.sh index 7d9899e5..af4e87ff 100755 --- a/acme.sh +++ b/acme.sh @@ -1,5 +1,5 @@ -#!/usr/bin/env sh -VER=2.2.0 +#!/usr/bin/env bash +VER=2.2.1 PROJECT_NAME="acme.sh" @@ -23,13 +23,13 @@ END_CSR="-----END CERTIFICATE REQUEST-----" BEGIN_CERT="-----BEGIN CERTIFICATE-----" END_CERT="-----END CERTIFICATE-----" -if [[ -z "$AGREEMENT" ]] ; then +if [ -z "$AGREEMENT" ] ; then AGREEMENT="$DEFAULT_AGREEMENT" fi _info() { - if [[ -z "$2" ]] ; then + if [ -z "$2" ] ; then echo "[$(date)] $1" else echo "[$(date)] $1"="'$2'" @@ -42,7 +42,7 @@ _err() { } _debug() { - if [[ -z "$DEBUG" ]] ; then + if [ -z "$DEBUG" ] ; then return fi _err "$@" @@ -50,7 +50,7 @@ _debug() { } _debug2() { - if [[ "$DEBUG" ]] && [[ "$DEBUG" -ge "2" ]] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then _debug "$@" fi return @@ -70,7 +70,7 @@ _contains(){ _exists(){ cmd="$1" - if [[ -z "$cmd" ]] ; then + if [ -z "$cmd" ] ; then _err "Usage: _exists cmd" return 1 fi @@ -90,7 +90,7 @@ _h2b() { j=2 while [ '1' ] ; do h=$(printf $hex | cut -c $i-$j) - if [[ -z "$h" ]] ; then + if [ -z "$h" ] ; then break; fi printf "\x$h" @@ -103,7 +103,7 @@ _h2b() { _sed_i() { options="$1" filename="$2" - if [[ -z "$filename" ]] ; then + if [ -z "$filename" ] ; then _err "Usage:_sed_i options filename" return 1 fi @@ -123,13 +123,13 @@ _getfile() { filename="$1" startline="$2" endline="$3" - if [[ -z "$endline" ]] ; then + if [ -z "$endline" ] ; then _err "Usage: file startline endline" return 1 fi i="$(grep -n -- "$startline" $filename | cut -d : -f 1)" - if [[ -z "$i" ]] ; then + if [ -z "$i" ] ; then _err "Can not find start line: $startline" return 1 fi @@ -137,7 +137,7 @@ _getfile() { _debug i $i j="$(grep -n -- "$endline" $filename | cut -d : -f 1)" - if [[ -z "$j" ]] ; then + if [ -z "$j" ] ; then _err "Can not find end line: $endline" return 1 fi @@ -150,7 +150,7 @@ _getfile() { #Usage: multiline _base64() { - if [[ "$1" ]] ; then + if [ "$1" ] ; then openssl base64 -e else openssl base64 -e | tr -d '\r\n' @@ -159,7 +159,7 @@ _base64() { #Usage: multiline _dbase64() { - if [[ "$1" ]] ; then + if [ "$1" ] ; then openssl base64 -d -A else openssl base64 -d @@ -170,12 +170,12 @@ _dbase64() { #Output Base64-encoded digest _digest() { alg="$1" - if [[ -z "$alg" ]] ; then + if [ -z "$alg" ] ; then _err "Usage: _digest hashalg" return 1 fi - if [[ "$alg" == "sha256" ]] ; then + if [ "$alg" = "sha256" ] ; then openssl dgst -sha256 -binary | _base64 else _err "$alg is not supported yet" @@ -189,12 +189,12 @@ _digest() { _sign() { keyfile="$1" alg="$2" - if [[ -z "$alg" ]] ; then + if [ -z "$alg" ] ; then _err "Usage: _sign keyfile hashalg" return 1 fi - if [[ "$alg" == "sha256" ]] ; then + if [ "$alg" = "sha256" ] ; then openssl dgst -sha256 -sign "$keyfile" | _base64 else _err "$alg is not supported yet" @@ -233,20 +233,20 @@ _ss() { toPkcs() { domain="$1" pfxPassword="$2" - if [[ -z "$domain" ]] ; then + if [ -z "$domain" ] ; then echo "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]" return 1 fi _initpath "$domain" - if [[ "$pfxPassword" ]] ; then + if [ "$pfxPassword" ] ; then openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" else openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" fi - if [[ "$?" == "0" ]] ; then + if [ "$?" = "0" ] ; then _info "Success, Pfx is exported to: $CERT_PFX_PATH" fi @@ -255,7 +255,7 @@ toPkcs() { #domain [2048] createAccountKey() { _info "Creating account key" - if [[ -z "$1" ]] ; then + if [ -z "$1" ] ; then echo Usage: $PROJECT_ENTRY --createAccountKey -d domain.com [--accountkeylength 2048] return fi @@ -268,13 +268,13 @@ createAccountKey() { length=2048 fi - if [[ -z "$2" ]] || [[ "$2" == "no" ]] ; then + if [ -z "$2" ] || [ "$2" = "no" ] ; then _info "Use default length 2048" length=2048 fi _initpath - if [[ -f "$ACCOUNT_KEY_PATH" ]] ; then + if [ -f "$ACCOUNT_KEY_PATH" ] ; then _info "Account key exists, skip" return else @@ -287,7 +287,7 @@ createAccountKey() { #domain length createDomainKey() { _info "Creating domain key" - if [[ -z "$1" ]] ; then + if [ -z "$1" ] ; then echo Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ] return fi @@ -301,8 +301,8 @@ createDomainKey() { eccname="$length" fi - if [[ -z "$length" ]] ; then - if [[ "$isec" ]] ; then + if [ -z "$length" ] ; then + if [ "$isec" ] ; then length=256 else length=2048 @@ -310,14 +310,14 @@ createDomainKey() { fi _info "Use length $length" - if [[ "$isec" ]] ; then - if [[ "$length" == "256" ]] ; then + if [ "$isec" ] ; then + if [ "$length" = "256" ] ; then eccname="prime256v1" fi - if [[ "$length" == "384" ]] ; then + if [ "$length" = "384" ] ; then eccname="secp384r1" fi - if [[ "$length" == "521" ]] ; then + if [ "$length" = "521" ] ; then eccname="secp521r1" fi _info "Using ec name: $eccname" @@ -325,15 +325,15 @@ createDomainKey() { _initpath $domain - if [[ ! -f "$CERT_KEY_PATH" ]] || ( [[ "$FORCE" ]] && ! [[ "$IS_RENEW" ]] ); then + if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then #generate account key - if [[ "$isec" ]] ; then + if [ "$isec" ] ; then openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH" else openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH" fi else - if [[ "$IS_RENEW" ]] ; then + if [ "$IS_RENEW" ] ; then _info "Domain key exists, skip" return 0 else @@ -348,7 +348,7 @@ createDomainKey() { # domain domainlist createCSR() { _info "Creating csr" - if [[ -z "$1" ]] ; then + if [ -z "$1" ] ; then echo Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ] return fi @@ -357,12 +357,12 @@ createCSR() { domainlist=$2 - if [[ -f "$CSR_PATH" ]] && [[ "$IS_RENEW" ]] && [[ -z "$FORCE" ]]; then + if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then _info "CSR exists, skip" return fi - if [[ -z "$domainlist" ]] || [[ "$domainlist" == "no" ]]; then + if [ -z "$domainlist" ] || [ "$domainlist" = "no" ]; then #single domain _info "Single domain" $domain printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$DOMAIN_SSL_CONF" @@ -410,7 +410,7 @@ _stat() { #keyfile _calcjwk() { keyfile="$1" - if [[ -z "$keyfile" ]] ; then + if [ -z "$keyfile" ] ; then _err "Usage: _calcjwk keyfile" return 1 fi @@ -418,7 +418,7 @@ _calcjwk() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "RSA key" pub_exp=$(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 fi _debug2 pub_exp "$pub_exp" @@ -489,13 +489,13 @@ _post() { if _exists "curl" ; then CURL="$CURL --dump-header $HTTP_HEADER " - if [[ "$needbase64" ]] ; then + if [ "$needbase64" ] ; then response="$($CURL -A "User-Agent: $USER_AGENT" -X POST --data "$body" $url | _base64)" else response="$($CURL -A "User-Agent: $USER_AGENT" -X POST --data "$body" $url)" fi else - if [[ "$needbase64" ]] ; then + if [ "$needbase64" ] ; then response="$($WGET -S -O - --user-agent="$USER_AGENT" --post-data="$body" $url 2>"$HTTP_HEADER" | _base64)" else response="$($WGET -S -O - --user-agent="$USER_AGENT" --post-data="$body" $url 2>"$HTTP_HEADER")" @@ -512,14 +512,14 @@ _get() { onlyheader="$2" _debug url $url if _exists "curl" ; then - if [[ "$onlyheader" ]] ; then + if [ "$onlyheader" ] ; then $CURL -I -A "User-Agent: $USER_AGENT" $url else $CURL -A "User-Agent: $USER_AGENT" $url fi else _debug "WGET" "$WGET" - if [[ "$onlyheader" ]] ; then + if [ "$onlyheader" ] ; then eval $WGET --user-agent=\"$USER_AGENT\" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else eval $WGET --user-agent=\"$USER_AGENT\" -O - $url @@ -535,7 +535,7 @@ _send_signed_request() { payload=$2 needbase64=$3 keyfile=$4 - if [[ -z "$keyfile" ]] ; then + if [ -z "$keyfile" ] ; then keyfile="$ACCOUNT_KEY_PATH" fi _debug url $url @@ -585,11 +585,11 @@ _setopt() { __sep="$3" __val="$4" __end="$5" - if [[ -z "$__opt" ]] ; then + if [ -z "$__opt" ] ; then echo usage: _setopt '"file" "opt" "=" "value" [";"]' return fi - if [[ ! -f "$__conf" ]] ; then + if [ ! -f "$__conf" ] ; then touch "$__conf" fi @@ -620,7 +620,7 @@ _setopt() { _savedomainconf() { key="$1" value="$2" - if [[ "$DOMAIN_CONF" ]] ; then + if [ "$DOMAIN_CONF" ] ; then _setopt $DOMAIN_CONF "$key" "=" "$value" else _err "DOMAIN_CONF is empty, can not save $key=$value" @@ -631,7 +631,7 @@ _savedomainconf() { _saveaccountconf() { key="$1" value="$2" - if [[ "$ACCOUNT_CONF_PATH" ]] ; then + if [ "$ACCOUNT_CONF_PATH" ] ; then _setopt $ACCOUNT_CONF_PATH "$key" "=" "\"$value\"" else _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" @@ -657,7 +657,7 @@ _startserver() { _debug "_NC" "$_NC" # while true ; do - if [[ "$DEBUG" ]] ; then + if [ "$DEBUG" ] ; then if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; fi @@ -666,7 +666,7 @@ _startserver() { echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 fi fi - if [[ "$?" != "0" ]] ; then + if [ "$?" != "0" ] ; then _err "nc listen error." exit 1 fi @@ -676,11 +676,11 @@ _startserver() { _stopserver(){ pid="$1" _debug "pid" "$pid" - if [[ -z "$pid" ]] ; then + if [ -z "$pid" ] ; then return fi - if [[ "$(ps | grep "$pid")" ]] ; then + if [ "$(ps | grep "$pid")" ] ; then _debug "Found proc process, kill it." kill -s 9 $pid > /dev/null fi @@ -696,35 +696,35 @@ _stopserver(){ _initpath() { - if [[ -z "$LE_WORKING_DIR" ]] ; then + if [ -z "$LE_WORKING_DIR" ] ; then LE_WORKING_DIR=$HOME/.$PROJECT_NAME fi _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" - if [[ -z "$ACCOUNT_CONF_PATH" ]] ; then - if [[ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]] ; then - source "$_DEFAULT_ACCOUNT_CONF_PATH" + if [ -z "$ACCOUNT_CONF_PATH" ] ; then + if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ] ; then + . "$_DEFAULT_ACCOUNT_CONF_PATH" fi fi - if [[ -z "$ACCOUNT_CONF_PATH" ]] ; then + if [ -z "$ACCOUNT_CONF_PATH" ] ; then ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi - if [[ -f "$ACCOUNT_CONF_PATH" ]] ; then - source "$ACCOUNT_CONF_PATH" + if [ -f "$ACCOUNT_CONF_PATH" ] ; then + . "$ACCOUNT_CONF_PATH" fi - if [[ "$IN_CRON" ]] ; then - if [[ ! "$_USER_PATH_EXPORTED" ]] ; then + if [ "$IN_CRON" ] ; then + if [ ! "$_USER_PATH_EXPORTED" ] ; then _USER_PATH_EXPORTED=1 export PATH="$USER_PATH:$PATH" fi fi - if [[ -z "$API" ]] ; then - if [[ -z "$STAGE" ]] ; then + if [ -z "$API" ] ; then + if [ -z "$STAGE" ] ; then API="$DEFAULT_CA" else API="$STAGE_CA" @@ -732,77 +732,77 @@ _initpath() { fi fi - if [[ -z "$ACME_DIR" ]] ; then + if [ -z "$ACME_DIR" ] ; then ACME_DIR="/home/.acme" fi - if [[ -z "$APACHE_CONF_BACKUP_DIR" ]] ; then + if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR" fi - if [[ -z "$USER_AGENT" ]] ; then + if [ -z "$USER_AGENT" ] ; then USER_AGENT="$DEFAULT_USER_AGENT" fi HTTP_HEADER="$LE_WORKING_DIR/http.header" WGET="wget -q" - if [[ "$DEBUG" ]] && [[ "$DEBUG" -ge "2" ]] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then WGET="$WGET -d " fi dp="$LE_WORKING_DIR/curl.dump" CURL="curl -L --silent" - if [[ "$DEBUG" ]] && [[ "$DEBUG" -ge "2" ]] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then CURL="$CURL -L --trace-ascii $dp " fi _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" - if [[ -z "$ACCOUNT_KEY_PATH" ]] ; then + if [ -z "$ACCOUNT_KEY_PATH" ] ; then ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" fi domain="$1" - if [[ -z "$domain" ]] ; then + if [ -z "$domain" ] ; then return 0 fi _DEFAULT_CERT_HOME="$LE_WORKING_DIR" - if [[ -z "$CERT_HOME" ]] ; then + if [ -z "$CERT_HOME" ] ; then CERT_HOME="$_DEFAULT_CERT_HOME" fi domainhome="$CERT_HOME/$domain" mkdir -p "$domainhome" - if [[ -z "$DOMAIN_PATH" ]] ; then + if [ -z "$DOMAIN_PATH" ] ; then DOMAIN_PATH="$domainhome" fi - if [[ -z "$DOMAIN_CONF" ]] ; then + if [ -z "$DOMAIN_CONF" ] ; then DOMAIN_CONF="$domainhome/$domain.conf" fi - if [[ -z "$DOMAIN_SSL_CONF" ]] ; then + if [ -z "$DOMAIN_SSL_CONF" ] ; then DOMAIN_SSL_CONF="$domainhome/$domain.ssl.conf" fi - if [[ -z "$CSR_PATH" ]] ; then + if [ -z "$CSR_PATH" ] ; then CSR_PATH="$domainhome/$domain.csr" fi - if [[ -z "$CERT_KEY_PATH" ]] ; then + if [ -z "$CERT_KEY_PATH" ] ; then CERT_KEY_PATH="$domainhome/$domain.key" fi - if [[ -z "$CERT_PATH" ]] ; then + if [ -z "$CERT_PATH" ] ; then CERT_PATH="$domainhome/$domain.cer" fi - if [[ -z "$CA_CERT_PATH" ]] ; then + if [ -z "$CA_CERT_PATH" ] ; then CA_CERT_PATH="$domainhome/ca.cer" fi - if [[ -z "$CERT_FULLCHAIN_PATH" ]] ; then + if [ -z "$CERT_FULLCHAIN_PATH" ] ; then CERT_FULLCHAIN_PATH="$domainhome/fullchain.cer" fi - if [[ -z "$CERT_PFX_PATH" ]] ; then + if [ -z "$CERT_PFX_PATH" ] ; then CERT_PFX_PATH="$domainhome/$domain.pfx" fi } @@ -818,7 +818,7 @@ _apachePath() { httpdconf="$httpdroot/$httpdconfname" fi - if [[ ! -f $httpdconf ]] ; then + if [ ! -f $httpdconf ] ; then _err "Apache Config file not found" $httpdconf return 1 fi @@ -826,7 +826,7 @@ _apachePath() { } _restoreApache() { - if [[ -z "$usingApache" ]] ; then + if [ -z "$usingApache" ] ; then return 0 fi _initpath @@ -834,7 +834,7 @@ _restoreApache() { return 1 fi - if [[ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]] ; then + if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then _debug "No config file to restore." return 0 fi @@ -870,7 +870,7 @@ _setApache() { apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)" apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" - if [[ "$apacheVer" ]] && [[ "$apacheMajer" -ge "2" ]] && [[ "$apacheMinor" -ge "4" ]] ; then + if [ "$apacheVer" ] && [ "$apacheMajer" -ge "2" ] && [ "$apacheMinor" -ge "4" ] ; then echo " Alias /.well-known/acme-challenge $ACME_DIR @@ -896,7 +896,7 @@ Allow from all return 1; fi - if [[ ! -d "$ACME_DIR" ]] ; then + if [ ! -d "$ACME_DIR" ] ; then mkdir -p "$ACME_DIR" chmod 755 "$ACME_DIR" fi @@ -919,18 +919,18 @@ _clearup() { # webroot removelevel tokenfile _clearupwebbroot() { __webroot="$1" - if [[ -z "$__webroot" ]] ; then + if [ -z "$__webroot" ] ; then _debug "no webroot specified, skip" return 0 fi - if [[ "$2" == '1' ]] ; then + if [ "$2" = '1' ] ; then _debug "remove $__webroot/.well-known" rm -rf "$__webroot/.well-known" - elif [[ "$2" == '2' ]] ; then + elif [ "$2" = '2' ] ; then _debug "remove $__webroot/.well-known/acme-challenge" rm -rf "$__webroot/.well-known/acme-challenge" - elif [[ "$2" == '3' ]] ; then + elif [ "$2" = '3' ] ; then _debug "remove $__webroot/.well-known/acme-challenge/$3" rm -rf "$__webroot/.well-known/acme-challenge/$3" else @@ -942,7 +942,7 @@ _clearupwebbroot() { } issue() { - if [[ -z "$2" ]] ; then + if [ -z "$2" ] ; then echo "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " return 1 fi @@ -957,21 +957,21 @@ issue() { Le_RealFullChainPath="$9" #remove these later. - if [[ "$Le_Webroot" == "dns-cf" ]] ; then + if [ "$Le_Webroot" = "dns-cf" ] ; then Le_Webroot="dns_cf" fi - if [[ "$Le_Webroot" == "dns-dp" ]] ; then + if [ "$Le_Webroot" = "dns-dp" ] ; then Le_Webroot="dns_dp" fi - if [[ "$Le_Webroot" == "dns-cx" ]] ; then + if [ "$Le_Webroot" = "dns-cx" ] ; then Le_Webroot="dns_cx" fi _initpath $Le_Domain - if [[ -f "$DOMAIN_CONF" ]] ; then + if [ -f "$DOMAIN_CONF" ] ; then Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2) - if [[ -z "$FORCE" ]] && [[ "$Le_NextRenewTime" ]] && [[ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ]] ; then + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" return 2 fi @@ -987,25 +987,25 @@ issue() { _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" _setopt "$DOMAIN_CONF" "Le_RealFullChainPath" "=" "\"$Le_RealFullChainPath\"" - if [[ "$Le_Alt" == "no" ]] ; then + if [ "$Le_Alt" = "no" ] ; then Le_Alt="" fi - if [[ "$Le_Keylength" == "no" ]] ; then + if [ "$Le_Keylength" = "no" ] ; then Le_Keylength="" fi - if [[ "$Le_RealCertPath" == "no" ]] ; then + if [ "$Le_RealCertPath" = "no" ] ; then Le_RealCertPath="" fi - if [[ "$Le_RealKeyPath" == "no" ]] ; then + if [ "$Le_RealKeyPath" = "no" ] ; then Le_RealKeyPath="" fi - if [[ "$Le_RealCACertPath" == "no" ]] ; then + if [ "$Le_RealCACertPath" = "no" ] ; then Le_RealCACertPath="" fi - if [[ "$Le_ReloadCmd" == "no" ]] ; then + if [ "$Le_ReloadCmd" = "no" ] ; then Le_ReloadCmd="" fi - if [[ "$Le_RealFullChainPath" == "no" ]] ; then + if [ "$Le_RealFullChainPath" = "no" ] ; then Le_RealFullChainPath="" fi @@ -1017,13 +1017,13 @@ issue() { return 1 fi - if [[ -z "$Le_HTTPPort" ]] ; then + if [ -z "$Le_HTTPPort" ] ; then Le_HTTPPort=80 fi _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" netprc="$(_ss "$Le_HTTPPort" | grep "$Le_HTTPPort")" - if [[ "$netprc" ]] ; then + if [ "$netprc" ] ; then _err "$netprc" _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" _err "Please stop it first" @@ -1040,10 +1040,10 @@ issue() { usingApache="" fi - if [[ ! -f "$ACCOUNT_KEY_PATH" ]] ; then + if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then if ! createAccountKey $Le_Domain $Le_Keylength ; then _err "Create account key error." - if [[ "$usingApache" ]] ; then + if [ "$usingApache" ] ; then _restoreApache fi return 1 @@ -1051,7 +1051,7 @@ issue() { fi if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then - if [[ "$usingApache" ]] ; then + if [ "$usingApache" ] ; then _restoreApache fi return 1 @@ -1062,18 +1062,18 @@ issue() { accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | _digest "sha256" )" accountkeyhash="$(echo $accountkeyhash$API | _digest "sha256" )" - if [[ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ]] ; then + if [ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ] ; then _info "Registering account" regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' - if [[ "$ACCOUNT_EMAIL" ]] ; then + if [ "$ACCOUNT_EMAIL" ] ; then regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' fi _send_signed_request "$API/acme/new-reg" "$regjson" - if [[ "$code" == "" ]] || [[ "$code" == '201' ]] ; then + if [ "$code" = "" ] || [ "$code" = '201' ] ; then _info "Registered" echo $response > $LE_WORKING_DIR/account.json - elif [[ "$code" == '409' ]] ; then + elif [ "$code" = '409' ] ; then _info "Already registered" else _err "Register account Error: $response" @@ -1086,7 +1086,7 @@ issue() { _info "Skip register account key" fi - if [[ ! -f "$CERT_KEY_PATH" ]] ; then + if [ ! -f "$CERT_KEY_PATH" ] ; then if ! createDomainKey $Le_Domain $Le_Keylength ; then _err "Create domain key error." _clearup @@ -1104,7 +1104,7 @@ issue() { # verify each domain _info "Verify each domain" sep='#' - if [[ -z "$vlist" ]] ; then + if [ -z "$vlist" ] ; then alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) _index=1 _currentRoot="" @@ -1113,7 +1113,7 @@ issue() { _info "Getting webroot for domain" $d _w="$(echo $Le_Webroot | cut -d , -f $_index)" _debug _w "$_w" - if [[ "$_w" ]] ; then + if [ "$_w" ] ; then _currentRoot="$_w" fi _debug "_currentRoot" "$_currentRoot" @@ -1125,7 +1125,7 @@ issue() { fi _info "Getting token for domain" $d _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" - if [[ ! -z "$code" ]] && [[ ! "$code" == '201' ]] ; then + if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then _err "new-authz error: $response" _clearup return 1 @@ -1159,7 +1159,7 @@ issue() { keyauthorization=$(echo $ventry | cut -d $sep -f 2) vtype=$(echo $ventry | cut -d $sep -f 4) _currentRoot=$(echo $ventry | cut -d $sep -f 5) - if [[ "$vtype" == "$VTYPE_DNS" ]] ; then + if [ "$vtype" = "$VTYPE_DNS" ] ; then dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" @@ -1168,22 +1168,22 @@ issue() { #dns #1. check use api d_api="" - if [[ -f "$LE_WORKING_DIR/$d/$_currentRoot" ]] ; then + if [ -f "$LE_WORKING_DIR/$d/$_currentRoot" ] ; then d_api="$LE_WORKING_DIR/$d/$_currentRoot" - elif [[ -f "$LE_WORKING_DIR/$d/$_currentRoot.sh" ]] ; then + elif [ -f "$LE_WORKING_DIR/$d/$_currentRoot.sh" ] ; then d_api="$LE_WORKING_DIR/$d/$_currentRoot.sh" - elif [[ -f "$LE_WORKING_DIR/$_currentRoot" ]] ; then + elif [ -f "$LE_WORKING_DIR/$_currentRoot" ] ; then d_api="$LE_WORKING_DIR/$_currentRoot" - elif [[ -f "$LE_WORKING_DIR/$_currentRoot.sh" ]] ; then + elif [ -f "$LE_WORKING_DIR/$_currentRoot.sh" ] ; then d_api="$LE_WORKING_DIR/$_currentRoot.sh" - elif [[ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot" ]] ; then + elif [ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot" ] ; then d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot" - elif [[ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" ]] ; then + elif [ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" ] ; then d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" fi _debug d_api "$d_api" - if [[ "$d_api" ]] ; then + if [ "$d_api" ] ; then _info "Found domain api file: $d_api" else _err "Add the following TXT record:" @@ -1195,7 +1195,7 @@ issue() { fi ( - if ! source $d_api ; then + if ! . $d_api ; then _err "Load file $d_api error. Please check your api file and try again." return 1 fi @@ -1212,7 +1212,7 @@ issue() { fi ) - if [[ "$?" != "0" ]] ; then + if [ "$?" != "0" ] ; then _clearup return 1 fi @@ -1220,7 +1220,7 @@ issue() { fi done - if [[ "$dnsadded" == '0' ]] ; then + if [ "$dnsadded" = '0' ] ; then _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\"" _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." @@ -1230,7 +1230,7 @@ issue() { fi - if [[ "$dnsadded" == '1' ]] ; then + if [ "$dnsadded" = '1' ] ; then _info "Sleep 60 seconds for the txt records to take effect" sleep 60 fi @@ -1255,11 +1255,11 @@ issue() { _debug "_currentRoot" "$_currentRoot" - if [[ "$vtype" == "$VTYPE_HTTP" ]] ; then - if [[ "$_currentRoot" == "no" ]] ; then + if [ "$vtype" = "$VTYPE_HTTP" ] ; then + if [ "$_currentRoot" = "no" ] ; then _info "Standalone mode server" _startserver "$keyauthorization" & - if [[ "$?" != "0" ]] ; then + if [ "$?" != "0" ] ; then _clearup return 1 fi @@ -1268,13 +1268,13 @@ issue() { _debug serverproc $serverproc else - if [[ "$_currentRoot" == "apache" ]] ; then + if [ "$_currentRoot" = "apache" ] ; then wellknown_path="$ACME_DIR" else wellknown_path="$_currentRoot/.well-known/acme-challenge" - if [[ ! -d "$_currentRoot/.well-known" ]] ; then + if [ ! -d "$_currentRoot/.well-known" ] ; then removelevel='1' - elif [[ ! -d "$_currentRoot/.well-known/acme-challenge" ]] ; then + elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ] ; then removelevel='2' else removelevel='3' @@ -1288,7 +1288,7 @@ issue() { mkdir -p "$wellknown_path" echo -n "$keyauthorization" > "$wellknown_path/$token" - if [[ ! "$usingApache" ]] ; then + if [ ! "$usingApache" ] ; then webroot_owner=$(_stat $_currentRoot) _debug "Changing owner/group of .well-known to $webroot_owner" chown -R $webroot_owner "$_currentRoot/.well-known" @@ -1299,7 +1299,7 @@ issue() { _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" - if [[ ! -z "$code" ]] && [[ ! "$code" == '202' ]] ; then + if [ ! -z "$code" ] && [ ! "$code" = '202' ] ; then _err "$d:Challenge error: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup @@ -1307,13 +1307,13 @@ issue() { fi waittimes=0 - if [[ -z "$MAX_RETRY_TIMES" ]] ; then + if [ -z "$MAX_RETRY_TIMES" ] ; then MAX_RETRY_TIMES=30 fi - while [[ "1" ]] ; do + while [ "1" ] ; do let "waittimes+=1" - if [[ "$waittimes" -ge "$MAX_RETRY_TIMES" ]] ; then + if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ] ; then _err "$d:Timeout" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup @@ -1324,7 +1324,7 @@ issue() { sleep 5 _debug "checking" response="$(_get $uri)" - if [[ "$?" != "0" ]] ; then + if [ "$?" != "0" ] ; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup @@ -1332,7 +1332,7 @@ issue() { fi status=$(echo $response | egrep -o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') - if [[ "$status" == "valid" ]] ; then + if [ "$status" = "valid" ] ; then _info "Success" _stopserver $serverproc serverproc="" @@ -1340,7 +1340,7 @@ issue() { break; fi - if [[ "$status" == "invalid" ]] ; then + if [ "$status" = "invalid" ] ; then error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4) _err "$d:Verify error:$error" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" @@ -1348,7 +1348,7 @@ issue() { return 1; fi - if [[ "$status" == "pending" ]] ; then + if [ "$status" = "pending" ] ; then _info "Pending" else _err "$d:Verify error:$response" @@ -1370,7 +1370,7 @@ issue() { Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)" _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" - if [[ "$Le_LinkCert" ]] ; then + if [ "$Le_LinkCert" ] ; then echo "$BEGIN_CERT" > "$CERT_PATH" _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" echo "$END_CERT" >> "$CERT_PATH" @@ -1380,14 +1380,14 @@ issue() { _info "Your cert is in $CERT_PATH" cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" - if [[ ! "$USER_PATH" ]] || [[ ! "$IN_CRON" ]] ; then + if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ] ; then USER_PATH="$PATH" _saveaccountconf "USER_PATH" "$USER_PATH" fi fi - if [[ -z "$Le_LinkCert" ]] ; then + if [ -z "$Le_LinkCert" ] ; then response="$(echo $response | _dbase64 "multiline" )" _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" return 1 @@ -1398,7 +1398,7 @@ issue() { Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" - if [[ "$Le_LinkIssuer" ]] ; then + if [ "$Le_LinkIssuer" ] ; then echo "$BEGIN_CERT" > "$CA_CERT_PATH" _get "$Le_LinkIssuer" | _base64 "multiline" >> "$CA_CERT_PATH" echo "$END_CERT" >> "$CA_CERT_PATH" @@ -1413,7 +1413,7 @@ issue() { Le_CertCreateTimeStr=$(date -u ) _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\"" - if [[ -z "$Le_RenewalDays" ]] || [[ "$Le_RenewalDays" -lt "0" ]] || [[ "$Le_RenewalDays" -gt "80" ]] ; then + if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "80" ] ; then Le_RenewalDays=80 fi @@ -1432,20 +1432,20 @@ issue() { renew() { Le_Domain="$1" - if [[ -z "$Le_Domain" ]] ; then + if [ -z "$Le_Domain" ] ; then _err "Usage: $PROJECT_ENTRY --renew -d domain.com" return 1 fi _initpath $Le_Domain - if [[ ! -f "$DOMAIN_CONF" ]] ; then + if [ ! -f "$DOMAIN_CONF" ] ; then _info "$Le_Domain is not a issued domain, skip." return 0; fi - source "$DOMAIN_CONF" - if [[ -z "$FORCE" ]] && [[ "$Le_NextRenewTime" ]] && [[ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ]] ; then + . "$DOMAIN_CONF" + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" return 2 fi @@ -1507,7 +1507,7 @@ renewAll() { installcert() { Le_Domain="$1" - if [[ -z "$Le_Domain" ]] ; then + if [ -z "$Le_Domain" ] ; then echo "Usage: $PROJECT_ENTRY --installcert -d domain.com [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" return 1 fi @@ -1526,19 +1526,19 @@ installcert() { _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" _setopt "$DOMAIN_CONF" "Le_RealFullChainPath" "=" "\"$Le_RealFullChainPath\"" - if [[ "$Le_RealCertPath" ]] ; then - if [[ -f "$Le_RealCertPath" ]] ; then + if [ "$Le_RealCertPath" ] ; then + if [ -f "$Le_RealCertPath" ] ; then cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak fi cat "$CERT_PATH" > "$Le_RealCertPath" fi - if [[ "$Le_RealCACertPath" ]] ; then - if [[ "$Le_RealCACertPath" == "$Le_RealCertPath" ]] ; then + if [ "$Le_RealCACertPath" ] ; then + if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ] ; then echo "" >> "$Le_RealCACertPath" cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" else - if [[ -f "$Le_RealCACertPath" ]] ; then + if [ -f "$Le_RealCACertPath" ] ; then cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak fi cat "$CA_CERT_PATH" > "$Le_RealCACertPath" @@ -1546,21 +1546,21 @@ installcert() { fi - if [[ "$Le_RealKeyPath" ]] ; then - if [[ -f "$Le_RealKeyPath" ]] ; then + if [ "$Le_RealKeyPath" ] ; then + if [ -f "$Le_RealKeyPath" ] ; then cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak fi cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" fi - if [[ "$Le_RealFullChainPath" ]] ; then - if [[ -f "$Le_RealFullChainPath" ]] ; then + if [ "$Le_RealFullChainPath" ] ; then + if [ -f "$Le_RealFullChainPath" ] ; then cp -p "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak fi cat "$CERT_FULLCHAIN_PATH" > "$Le_RealFullChainPath" fi - if [[ "$Le_ReloadCmd" ]] ; then + if [ "$Le_ReloadCmd" ] ; then _info "Run Le_ReloadCmd: $Le_ReloadCmd" (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") fi @@ -1578,7 +1578,7 @@ installcronjob() { _info "Installing cron job" if ! crontab -l | grep "$PROJECT_ENTRY --cron" ; then - if [[ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]] ; then + if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ] ; then lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" else _err "Can not install cronjob, $PROJECT_ENTRY not found." @@ -1586,7 +1586,7 @@ installcronjob() { fi crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab - fi - if [[ "$?" != "0" ]] ; then + if [ "$?" != "0" ] ; then _err "Install cron job failed. You need to manually renew your certs." _err "Or you can add cronjob by yourself:" _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" @@ -1600,7 +1600,7 @@ uninstallcronjob() { fi _info "Removing cron job" cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")" - if [[ "$cr" ]] ; then + if [ "$cr" ] ; then crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab - LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" @@ -1611,25 +1611,25 @@ uninstallcronjob() { revoke() { Le_Domain="$1" - if [[ -z "$Le_Domain" ]] ; then + if [ -z "$Le_Domain" ] ; then echo "Usage: $PROJECT_ENTRY --revoke -d domain.com" return 1 fi _initpath $Le_Domain - if [[ ! -f "$DOMAIN_CONF" ]] ; then + if [ ! -f "$DOMAIN_CONF" ] ; then _err "$Le_Domain is not a issued domain, skip." return 1; fi - if [[ ! -f "$CERT_PATH" ]] ; then + if [ ! -f "$CERT_PATH" ] ; then _err "Cert for $Le_Domain $CERT_PATH is not found, skip." return 1 fi cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}"| tr -d "\r\n" | _urlencode)" - if [[ -z "$cert" ]] ; then + if [ -z "$cert" ] ; then _err "Cert for $Le_Domain is empty found, skip." return 1 fi @@ -1639,7 +1639,7 @@ revoke() { _info "Try domain key first." if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then - if [[ -z "$response" ]] ; then + if [ -z "$response" ] ; then _info "Revoke success." rm -f $CERT_PATH return 0 @@ -1652,7 +1652,7 @@ revoke() { _info "Then try account key." if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH" ; then - if [[ -z "$response" ]] ; then + if [ -z "$response" ] ; then _info "Revoke success." rm -f $CERT_PATH return 0 @@ -1676,36 +1676,36 @@ _detect_profile() { local SHELLTYPE SHELLTYPE="$(basename "/$SHELL")" - if [[ "$SHELLTYPE" = "bash" ]] ; then - if [[ -f "$HOME/.bashrc" ]] ; then + if [ "$SHELLTYPE" = "bash" ] ; then + if [ -f "$HOME/.bashrc" ] ; then DETECTED_PROFILE="$HOME/.bashrc" - elif [[ -f "$HOME/.bash_profile" ]] ; then + elif [ -f "$HOME/.bash_profile" ] ; then DETECTED_PROFILE="$HOME/.bash_profile" fi - elif [[ "$SHELLTYPE" = "zsh" ]] ; then + elif [ "$SHELLTYPE" = "zsh" ] ; then DETECTED_PROFILE="$HOME/.zshrc" fi - if [[ -z "$DETECTED_PROFILE" ]] ; then - if [[ -f "$HOME/.profile" ]] ; then + if [ -z "$DETECTED_PROFILE" ] ; then + if [ -f "$HOME/.profile" ] ; then DETECTED_PROFILE="$HOME/.profile" - elif [[ -f "$HOME/.bashrc" ]] ; then + elif [ -f "$HOME/.bashrc" ] ; then DETECTED_PROFILE="$HOME/.bashrc" - elif [[ -f "$HOME/.bash_profile" ]] ; then + elif [ -f "$HOME/.bash_profile" ] ; then DETECTED_PROFILE="$HOME/.bash_profile" - elif [[ -f "$HOME/.zshrc" ]] ; then + elif [ -f "$HOME/.zshrc" ] ; then DETECTED_PROFILE="$HOME/.zshrc" fi fi - if [[ ! -z "$DETECTED_PROFILE" ]] ; then + if [ ! -z "$DETECTED_PROFILE" ] ; then echo "$DETECTED_PROFILE" fi } _initconf() { _initpath - if [[ ! -f "$ACCOUNT_CONF_PATH" ]] ; then + if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then echo "#ACCOUNT_CONF_PATH=xxxx #Account configurations: @@ -1760,7 +1760,7 @@ _precheck() { _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." _err "We need to set cron job to renew the certs automatically." _err "Otherwise, your certs will not be able to be renewed automatically." - if [[ -z "$FORCE" ]] ; then + if [ -z "$FORCE" ] ; then _err "Please add '--force' and try install again to go without crontab." _err "./$PROJECT_ENTRY --install --force" return 1 @@ -1795,10 +1795,10 @@ install() { fi #convert from le - if [[ -d "$HOME/.le" ]] ; then + if [ -d "$HOME/.le" ] ; then for envfile in "le.env" "le.sh.env" do - if [[ -f "$HOME/.le/$envfile" ]] ; then + if [ -f "$HOME/.le/$envfile" ] ; then if grep "le.sh" "$HOME/.le/$envfile" >/dev/null ; then _upgrading="1" _info "You are upgrading from le.sh" @@ -1820,7 +1820,7 @@ install() { cp $PROJECT_ENTRY "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" - if [[ "$?" != "0" ]] ; then + if [ "$?" != "0" ] ; then _err "Install failed, can not copy $PROJECT_ENTRY" return 1 fi @@ -1828,11 +1828,11 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" _profile="$(_detect_profile)" - if [[ "$_profile" ]] ; then + if [ "$_profile" ] ; then _debug "Found profile: $_profile" _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" - if [[ "$_upgrading" == "1" ]] ; then + if [ "$_upgrading" ] && [ "$_upgrading" = "1" ] ; then echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile" echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile" echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile" @@ -1842,35 +1842,35 @@ install() { _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" echo "" >> "$_profile" - _setopt "$_profile" "source \"$LE_WORKING_DIR/$PROJECT_NAME.env\"" + _setopt "$_profile" ". \"$LE_WORKING_DIR/$PROJECT_NAME.env\"" _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" else _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" fi - if [[ -d "dnsapi" ]] ; then + if [ -d "dnsapi" ] ; then mkdir -p $LE_WORKING_DIR/dnsapi cp dnsapi/* $LE_WORKING_DIR/dnsapi/ fi #to keep compatible mv the .acc file to .key file - if [[ -f "$LE_WORKING_DIR/account.acc" ]] ; then + if [ -f "$LE_WORKING_DIR/account.acc" ] ; then mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key" fi - if [[ ! -f "$ACCOUNT_CONF_PATH" ]] ; then + if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then _initconf fi - if [[ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]] ; then + if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ] ; then _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" fi - if [[ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]] ; then + if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ] ; then _saveaccountconf "CERT_HOME" "$CERT_HOME" fi - if [[ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]] ; then + if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ] ; then _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH" fi @@ -1884,7 +1884,7 @@ uninstall() { _initpath _profile="$(_detect_profile)" - if [[ "$_profile" ]] ; then + if [ "$_profile" ] ; then text="$(cat $_profile)" echo "$text" | sed "s|^source.*$PROJECT_NAME.env.*$||" > "$_profile" fi @@ -1962,7 +1962,7 @@ Parameters: _installOnline() { _info "Installing from online archive." - if [[ ! "$BRANCH" ]] ; then + if [ ! "$BRANCH" ] ; then BRANCH="master" fi _initpath @@ -2005,7 +2005,7 @@ _process() { _accountemail="" _accountkey="" _certhome="" - while [[ ${#} -gt 0 ]] ; do + while [ ${#} -gt 0 ] ; do case "${1}" in --help|-h) @@ -2063,15 +2063,15 @@ _process() { --domain|-d) _dvalue="$2" - if [[ -z "$_dvalue" ]] || _startswith "$_dvalue" "-" ; then + if [ -z "$_dvalue" ] || _startswith "$_dvalue" "-" ; then _err "'$_dvalue' is not a valid domain for parameter '$1'" return 1 fi - if [[ -z "$_domain" ]] ; then + if [ -z "$_domain" ] ; then _domain="$_dvalue" else - if [[ "$_altdomains" == "no" ]] ; then + if [ "$_altdomains" = "no" ] ; then _altdomains="$_dvalue" else _altdomains="$_altdomains,$_dvalue" @@ -2087,7 +2087,7 @@ _process() { STAGE="1" ;; --debug) - if [[ -z "$2" ]] || _startswith "$2" "-" ; then + if [ -z "$2" ] || _startswith "$2" "-" ; then DEBUG="1" else DEBUG="$2" @@ -2096,7 +2096,7 @@ _process() { ;; --webroot|-w) wvalue="$2" - if [[ -z "$_webroot" ]] ; then + if [ -z "$_webroot" ] ; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" @@ -2105,7 +2105,7 @@ _process() { ;; --standalone) wvalue="no" - if [[ -z "$_webroot" ]] ; then + if [ -z "$_webroot" ] ; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" @@ -2113,7 +2113,7 @@ _process() { ;; --apache) wvalue="apache" - if [[ -z "$_webroot" ]] ; then + if [ -z "$_webroot" ] ; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" @@ -2125,7 +2125,7 @@ _process() { wvalue="$2" shift fi - if [[ -z "$_webroot" ]] ; then + if [ -z "$_webroot" ] ; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" @@ -2250,10 +2250,10 @@ _process() { ;; esac - if [[ "$_useragent" ]] ; then + if [ "$_useragent" ] ; then _saveaccountconf "USER_AGENT" "$_useragent" fi - if [[ "$_accountemail" ]] ; then + if [ "$_accountemail" ] ; then _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" fi @@ -2261,13 +2261,13 @@ _process() { } -if [[ "$INSTALLONLINE" ]] ; then +if [ "$INSTALLONLINE" ] ; then INSTALLONLINE="" _installOnline $BRANCH exit fi -if [[ -z "$1" ]] ; then +if [ -z "$1" ] ; then showhelp else if echo "$1" | grep "^-" >/dev/null 2>&1 ; then diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 69216e50..c5eaac46 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash # diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 30b9bbfa..3ebb7bfe 100644 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash # Cloudxns.com Domain api # diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index dc9d433b..f47d4bd5 100644 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash # Dnspod.cn Domain api # diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index f06cc1e6..3c5b8651 100644 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash #Here is a sample custom api script. #This file name is "dns_myapi.sh" From c191ab7c074d277da0eeb6e3bb9d8c8f4dbb0497 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 12:02:36 +0800 Subject: [PATCH 0119/1348] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d6b8ed2f..29926844 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # An ACME Shell script: acme.sh - An ACME protocol client written purely in Shell (Unix shell) language. -- It's `sh` compatible, not only `bash`. - Fully ACME protocol implementation. - Simple, powerful and very easy to use. You only need 3 minutes to learn. From 00a506053c7672ea656640adb852cea79d78fae3 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 17:33:08 +0800 Subject: [PATCH 0120/1348] compatible to dash --- acme.sh | 103 +++++++++++++++++++++++++++++++++++++---------- dnsapi/dns_cf.sh | 2 +- dnsapi/dns_cx.sh | 2 +- dnsapi/dns_dp.sh | 2 +- 4 files changed, 85 insertions(+), 24 deletions(-) diff --git a/acme.sh b/acme.sh index af4e87ff..2c167996 100755 --- a/acme.sh +++ b/acme.sh @@ -28,6 +28,13 @@ if [ -z "$AGREEMENT" ] ; then fi + +_URGLY_PRINTF="" +if [ "$(printf '\x41')" = '\x41' ] ; then + _URGLY_PRINTF=1 +fi + + _info() { if [ -z "$2" ] ; then echo "[$(date)] $1" @@ -84,18 +91,71 @@ _exists(){ return $ret } +#a + b +_math(){ + expr "$@" +} + +_h_char_2_dec() { + _ch=$1 + case "${_ch}" in + a|A) + echo -n 10 + ;; + b|B) + echo -n 11 + ;; + c|C) + echo -n 12 + ;; + d|D) + echo -n 13 + ;; + e|E) + echo -n 14 + ;; + f|F) + echo -n 15 + ;; + *) + echo -n $_ch + ;; + esac + +} + _h2b() { hex=$(cat) i=1 j=2 + if _exists let ; then + uselet="1" + fi + _debug uselet "$uselet" while [ '1' ] ; do - h=$(printf $hex | cut -c $i-$j) - if [ -z "$h" ] ; then - break; + if [ -z "$_URGLY_PRINTF" ] ; then + h=$(printf $hex | cut -c $i-$j) + if [ -z "$h" ] ; then + break; + fi + printf "\x$h" + else + ic=$(printf $hex | cut -c $i) + jc=$(printf $hex | cut -c $j) + if [ -z "$ic$jc" ] ; then + break; + fi + ic="$(_h_char_2_dec $ic)" + jc="$(_h_char_2_dec $jc)" + printf '\'"$(printf %o "$(_math $ic \* 16 + $jc)")" fi - printf "\x$h" - let "i+=2" - let "j+=2" + if [ "$uselet" ] ; then + let "i+=2" + let "j+=2" + else + i="$(_math $i + 2)" + j="$(_math $j + 2)" + fi done } @@ -133,7 +193,7 @@ _getfile() { _err "Can not find start line: $startline" return 1 fi - let "i+=1" + _debug i $i j="$(grep -n -- "$endline" $filename | cut -d : -f 1)" @@ -141,10 +201,10 @@ _getfile() { _err "Can not find end line: $endline" return 1 fi - let "j-=1" + _debug j $j - sed -n $i,${j}p "$filename" + sed -n $i,${j}p "$filename" | head -n -1 | tail -n +2 } @@ -427,7 +487,8 @@ _calcjwk() { _debug2 e "$e" modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2 ) - n=$(echo $modulus| _h2b | _base64 | _urlencode ) + _debug2 modulus "$modulus" + n=$(echo -n $modulus| _h2b | _base64 | _urlencode ) jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' _debug2 jwk "$jwk" @@ -440,28 +501,28 @@ _calcjwk() { _debug2 crv $crv pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + pubi=$(_math $pubi + 1) _debug2 pubi $pubi - let "pubi=pubi+1" pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + pubj=$(_math $pubj + 1) _debug2 pubj $pubj - let "pubj=pubj-1" pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug2 pubtext "$pubtext" xlen="$(printf "$pubtext" | tr -d ':' | wc -c)" - let "xlen=xlen/4" + xlen=$(_math $xlen / 4) _debug2 xlen $xlen - - let "xend=xlen+1" + + xend=$(_math $xend + 1) x="$(printf $pubtext | cut -d : -f 2-$xend)" _debug2 x $x x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)" _debug2 x64 $x64 - - let "xend+=1" + + xend=$(_math $xend + 1) y="$(printf $pubtext | cut -d : -f $xend-10000)" _debug2 y $y @@ -1117,7 +1178,7 @@ issue() { _currentRoot="$_w" fi _debug "_currentRoot" "$_currentRoot" - let "_index+=1" + _index=$(_math $_index + 1) vtype="$VTYPE_HTTP" if _startswith "$_currentRoot" "dns" ; then @@ -1312,7 +1373,7 @@ issue() { fi while [ "1" ] ; do - let "waittimes+=1" + waittimes=$(_math $waittimes + 1) if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ] ; then _err "$d:Timeout" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" @@ -1418,8 +1479,8 @@ issue() { fi _setopt "$DOMAIN_CONF" "Le_RenewalDays" "=" "$Le_RenewalDays" - - let "Le_NextRenewTime=Le_CertCreateTime+Le_RenewalDays*24*60*60" + + Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) _setopt "$DOMAIN_CONF" "Le_NextRenewTime" "=" "$Le_NextRenewTime" Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index c5eaac46..a6c15763 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -112,7 +112,7 @@ _get_root() { return 1 fi p=$i - let "i+=1" + i=$(expr $i + 1) done return 1 } diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 3ebb7bfe..19758022 100644 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -159,7 +159,7 @@ _get_root() { return 1 fi p=$i - let "i+=1" + i=$(expr $i + 1) done return 1 } diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index f47d4bd5..a5043799 100644 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -165,7 +165,7 @@ _get_root() { return 1 fi p=$i - let "i+=1" + i=$(expr $i + 1) done return 1 } From f4312b44286bc2073a72244a6606f9c44f1b002b Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 18:54:06 +0800 Subject: [PATCH 0121/1348] fix --- acme.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 2c167996..c569e4b6 100755 --- a/acme.sh +++ b/acme.sh @@ -30,7 +30,7 @@ fi _URGLY_PRINTF="" -if [ "$(printf '\x41')" = '\x41' ] ; then +if [ "$(printf '\x41')" != 'A' ] ; then _URGLY_PRINTF=1 fi @@ -132,6 +132,7 @@ _h2b() { uselet="1" fi _debug uselet "$uselet" + _debug _URGLY_PRINTF "$_URGLY_PRINTF" while [ '1' ] ; do if [ -z "$_URGLY_PRINTF" ] ; then h=$(printf $hex | cut -c $i-$j) @@ -150,8 +151,8 @@ _h2b() { printf '\'"$(printf %o "$(_math $ic \* 16 + $jc)")" fi if [ "$uselet" ] ; then - let "i+=2" - let "j+=2" + let "i+=2" >/dev/null + let "j+=2" >/dev/null else i="$(_math $i + 2)" j="$(_math $j + 2)" From c1c7d87bc5398c9975ace931293ec9ea33ab4b69 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 18:56:03 +0800 Subject: [PATCH 0122/1348] minor. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index af4e87ff..752e8d72 100755 --- a/acme.sh +++ b/acme.sh @@ -1163,7 +1163,7 @@ issue() { dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" - txt="$(echo -e -n $keyauthorization | _digest "sha256" | _urlencode)" + txt="$(echo -n $keyauthorization | _digest "sha256" | _urlencode)" _debug txt "$txt" #dns #1. check use api From c5f2df5c9304120eb740a188e1f533a54414e925 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 19:16:48 +0800 Subject: [PATCH 0123/1348] fix compatible for sh. head -n -1 is not supported on pfsense. --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 7d3b30c0..0453240d 100755 --- a/acme.sh +++ b/acme.sh @@ -194,7 +194,7 @@ _getfile() { _err "Can not find start line: $startline" return 1 fi - + i="$(_math $i + 1)" _debug i $i j="$(grep -n -- "$endline" $filename | cut -d : -f 1)" @@ -202,10 +202,10 @@ _getfile() { _err "Can not find end line: $endline" return 1 fi - + j="$(_math $j - 1)" _debug j $j - sed -n $i,${j}p "$filename" | head -n -1 | tail -n +2 + sed -n $i,${j}p "$filename" } From 0a7c9364427f925130b24233f608a55986a56761 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 19:47:22 +0800 Subject: [PATCH 0124/1348] modify shebang to bash after install if bash is installed. --- acme.sh | 29 +++++++++++++++++++++++++++-- dnsapi/dns_cf.sh | 2 +- dnsapi/dns_cx.sh | 2 +- dnsapi/dns_dp.sh | 2 +- dnsapi/dns_myapi.sh | 2 +- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 0453240d..697dc233 100755 --- a/acme.sh +++ b/acme.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh VER=2.2.1 PROJECT_NAME="acme.sh" @@ -1844,6 +1844,19 @@ _precheck() { return 0 } +_setShebang() { + _file="$1" + _shebang="$2" + if [ -z "$_shebang" ] ; then + _err "Usage: file shebang" + return 1 + fi + cp "$_file" "$_file.tmp" + echo "$_shebang" > "$_file" + sed -n 2,99999p "$_file.tmp" >> "$_file" + rm -f "$_file.tmp" +} + install() { if ! _initpath ; then @@ -1937,7 +1950,19 @@ install() { fi installcronjob - + + #Modify shebang + if _exists bash ; then + _info "Good, bash is installed, change the shebang to use bash as prefered." + _shebang='#!/usr/bin/env bash' + _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" + if [ -d "$LE_WORKING_DIR/dnsapi" ] ; then + for _apifile in $(ls "$LE_WORKING_DIR/dnsapi/"*.sh) ; do + _setShebang "$_apifile" "$_shebang" + done + fi + fi + _info OK } diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index a6c15763..2aac3404 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 19758022..070a2ad6 100644 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # Cloudxns.com Domain api # diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index a5043799..510384ab 100644 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # Dnspod.cn Domain api # diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index 3c5b8651..f06cc1e6 100644 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh #Here is a sample custom api script. #This file name is "dns_myapi.sh" From fc33dbb54e5d07d086ba5a1c97c8f0ea7aa4d333 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 20:49:28 +0800 Subject: [PATCH 0125/1348] fix compatible --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 697dc233..8882b095 100755 --- a/acme.sh +++ b/acme.sh @@ -720,12 +720,12 @@ _startserver() { _debug "_NC" "$_NC" # while true ; do if [ "$DEBUG" ] ; then - if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; + if ! echo -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then + echo -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; fi else - if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 + if ! echo -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then + echo -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 fi fi if [ "$?" != "0" ] ; then From a1048c48e467de9feb8f13042affda4d4194e9d3 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 17 Apr 2016 20:58:56 +0800 Subject: [PATCH 0126/1348] fix compatible for dash --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 8882b095..001ef04b 100755 --- a/acme.sh +++ b/acme.sh @@ -720,12 +720,12 @@ _startserver() { _debug "_NC" "$_NC" # while true ; do if [ "$DEBUG" ] ; then - if ! echo -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then - echo -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; fi else - if ! echo -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then - echo -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 fi fi if [ "$?" != "0" ] ; then From a79b26af6cc3b6419e4eca3bed73147105a218a4 Mon Sep 17 00:00:00 2001 From: Richard van Dijk Date: Mon, 18 Apr 2016 02:37:35 +0200 Subject: [PATCH 0127/1348] fix renewAll bug $CERT_HOME is required by renewAll, but wasn't initialized. --- acme.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 001ef04b..303da6f1 100755 --- a/acme.sh +++ b/acme.sh @@ -824,17 +824,17 @@ _initpath() { ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" fi + _DEFAULT_CERT_HOME="$LE_WORKING_DIR" + if [ -z "$CERT_HOME" ] ; then + CERT_HOME="$_DEFAULT_CERT_HOME" + fi + domain="$1" if [ -z "$domain" ] ; then return 0 fi - _DEFAULT_CERT_HOME="$LE_WORKING_DIR" - if [ -z "$CERT_HOME" ] ; then - CERT_HOME="$_DEFAULT_CERT_HOME" - fi - domainhome="$CERT_HOME/$domain" mkdir -p "$domainhome" From 2d39b3df8893cd256257fe1f32ca6b0485a90dcf Mon Sep 17 00:00:00 2001 From: Richard van Dijk Date: Sun, 17 Apr 2016 23:44:01 +0200 Subject: [PATCH 0128/1348] fix renewAll bug $CERT_HOME is required by renewAll, but wasn't initialized. --- acme.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 752e8d72..d55ab3b8 100755 --- a/acme.sh +++ b/acme.sh @@ -762,17 +762,17 @@ _initpath() { ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" fi + _DEFAULT_CERT_HOME="$LE_WORKING_DIR" + if [ -z "$CERT_HOME" ] ; then + CERT_HOME="$_DEFAULT_CERT_HOME" + fi + domain="$1" if [ -z "$domain" ] ; then return 0 fi - _DEFAULT_CERT_HOME="$LE_WORKING_DIR" - if [ -z "$CERT_HOME" ] ; then - CERT_HOME="$_DEFAULT_CERT_HOME" - fi - domainhome="$CERT_HOME/$domain" mkdir -p "$domainhome" From db0534ed970f9ca27ce13eb22323cdc511ab0ad3 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 18 Apr 2016 21:33:21 +0800 Subject: [PATCH 0129/1348] fix bug, uninstall env --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d55ab3b8..66ea5c9b 100755 --- a/acme.sh +++ b/acme.sh @@ -1886,7 +1886,7 @@ uninstall() { _profile="$(_detect_profile)" if [ "$_profile" ] ; then text="$(cat $_profile)" - echo "$text" | sed "s|^source.*$PROJECT_NAME.env.*$||" > "$_profile" + echo "$text" | sed "s|^[.] \"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" > "$_profile" fi rm -f $LE_WORKING_DIR/$PROJECT_ENTRY From 641989fdee337d108c8598762df291d61b0e9ee0 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 18 Apr 2016 22:43:33 +0800 Subject: [PATCH 0130/1348] NO_DETECT_SH --- acme.sh | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index fbddc39d..74536ec2 100755 --- a/acme.sh +++ b/acme.sh @@ -1951,15 +1951,17 @@ install() { installcronjob - #Modify shebang - if _exists bash ; then - _info "Good, bash is installed, change the shebang to use bash as prefered." - _shebang='#!/usr/bin/env bash' - _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" - if [ -d "$LE_WORKING_DIR/dnsapi" ] ; then - for _apifile in $(ls "$LE_WORKING_DIR/dnsapi/"*.sh) ; do - _setShebang "$_apifile" "$_shebang" - done + if [ -z "$NO_DETECT_SH" ] ; then + #Modify shebang + if _exists bash ; then + _info "Good, bash is installed, change the shebang to use bash as prefered." + _shebang='#!/usr/bin/env bash' + _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" + if [ -d "$LE_WORKING_DIR/dnsapi" ] ; then + for _apifile in $(ls "$LE_WORKING_DIR/dnsapi/"*.sh) ; do + _setShebang "$_apifile" "$_shebang" + done + fi fi fi From 51e85716ee8a13ccfc15163880f6ac6b37c791f6 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 19 Apr 2016 18:34:04 +0800 Subject: [PATCH 0131/1348] minor: fix apachectl error message --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 66ea5c9b..2e3a6aa2 100755 --- a/acme.sh +++ b/acme.sh @@ -809,6 +809,11 @@ _initpath() { _apachePath() { + if ! _exists apachectl ; then + _err "'apachecrl not found. It seems that apache is not installed, or you are not root user.'" + _err "Please use webroot mode to try again." + return 1 + fi httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" if _startswith "$httpdconfname" '/' ; then httpdconf="$httpdconfname" From 80a0a7b5c598e62507eff8b6c043bd1cbae82d17 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 19 Apr 2016 18:36:15 +0800 Subject: [PATCH 0132/1348] minor: fix apachectl error message (#160) --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 74536ec2..49170ff5 100755 --- a/acme.sh +++ b/acme.sh @@ -871,6 +871,11 @@ _initpath() { _apachePath() { + if ! _exists apachectl ; then + _err "'apachecrl not found. It seems that apache is not installed, or you are not root user.'" + _err "Please use webroot mode to try again." + return 1 + fi httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" if _startswith "$httpdconfname" '/' ; then httpdconf="$httpdconfname" From f321c3c7ea7513870cdaa5a757eb67b356e47ac1 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 19 Apr 2016 21:56:44 +0800 Subject: [PATCH 0133/1348] fix issue for nc on windows. --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 2e3a6aa2..dd24899c 100755 --- a/acme.sh +++ b/acme.sh @@ -658,8 +658,8 @@ _startserver() { _debug "_NC" "$_NC" # while true ; do if [ "$DEBUG" ] ; then - if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then - echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; + if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then + echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; fi else if ! echo -e -n "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then From c8b6fe62a1637e01cf582925f299c59438fdbe8e Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 19 Apr 2016 22:01:51 +0800 Subject: [PATCH 0134/1348] fix compatible for windows nc --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 49170ff5..a39cdb61 100755 --- a/acme.sh +++ b/acme.sh @@ -720,8 +720,8 @@ _startserver() { _debug "_NC" "$_NC" # while true ; do if [ "$DEBUG" ] ; then - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort -vv ; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort -vv ; + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; fi else if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then From 0cca212843afa86c14fbccb6f1130817a8d9babc Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 19 Apr 2016 23:17:38 +0800 Subject: [PATCH 0135/1348] v2.2.2 support sh --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a39cdb61..81f170b7 100755 --- a/acme.sh +++ b/acme.sh @@ -1,5 +1,5 @@ #!/usr/bin/env sh -VER=2.2.1 +VER=2.2.2 PROJECT_NAME="acme.sh" From 6de38fbf081c37ce3212538063a1f8fcbf1171b1 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 19 Apr 2016 23:42:10 +0800 Subject: [PATCH 0136/1348] sh --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29926844..57920aac 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ - An ACME protocol client written purely in Shell (Unix shell) language. - Fully ACME protocol implementation. - Simple, powerful and very easy to use. You only need 3 minutes to learn. - +- Bash, dash and sh compatible. - Simplest shell script for Let's Encrypt free certificate client. - Purely written in Shell with no dependencies on python or Let's Encrypt official client. - Just one script, to issue, renew and install your certificates automatically. From 998c92d57ee23e441f4bd71c735fa2ba7ce267b5 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 20 Apr 2016 22:38:26 +0800 Subject: [PATCH 0137/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57920aac..1d342790 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki 11. Kali Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 12. Oracle Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) 13. Cloud Linux https://github.com/Neilpang/le/issues/111 -14. Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_le.sh +14. Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From daf5650445520de8ccdf56f219f5aa05f784d8b9 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 21 Apr 2016 21:09:08 +0800 Subject: [PATCH 0138/1348] Update README.md --- README.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1d342790..5e0b87bb 100644 --- a/README.md +++ b/README.md @@ -14,21 +14,22 @@ DOES NOT require `root/sudoer` access. Wiki: https://github.com/Neilpang/acme.sh/wiki #Tested OS -1. Ubuntu [![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -2. Debian [![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -3. CentOS [![](https://cdn.rawgit.com/Neilpang/letest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -4. Windows (cygwin with curl, openssl and crontab included) [![](https://cdn.rawgit.com/Neilpang/letest/master/status/windows.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -5. FreeBSD [![](https://cdn.rawgit.com/Neilpang/letest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -6. pfsense with curl -7. openSUSE [![](https://cdn.rawgit.com/Neilpang/letest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -8. Alpine Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) (with curl) -9. Archlinux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -10. fedora [![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -11. Kali Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -12. Oracle Linux [![](https://cdn.rawgit.com/Neilpang/letest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status) -13. Cloud Linux https://github.com/Neilpang/le/issues/111 -14. Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh - +| NO | Status| Platform| +|----|-------|---------| +|1|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu +|2|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian +|3|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS +|4|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/windows.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included) +|5|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD +|6|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/pfsense.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense +|7|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE +|8|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Alpine Linux (with curl) +|9|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Archlinux +|10|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|fedora +|11|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux +|12|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux +|13|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh +|14|--| Cloud Linux https://github.com/Neilpang/le/issues/111 For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From 1f60d2bbb4da83bd10e5602799882233b5f5619b Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 21 Apr 2016 21:12:48 +0800 Subject: [PATCH 0139/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e0b87bb..334ac9f3 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ - Simplest shell script for Let's Encrypt free certificate client. - Purely written in Shell with no dependencies on python or Let's Encrypt official client. - Just one script, to issue, renew and install your certificates automatically. +- DOES NOT require `root/sudoer` access. It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. -DOES NOT require `root/sudoer` access. Wiki: https://github.com/Neilpang/acme.sh/wiki From d9ded9f3f3d7b89d8d05d5bde4295fad7c150688 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 21 Apr 2016 21:43:28 +0800 Subject: [PATCH 0140/1348] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 334ac9f3..0c587f5d 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ cd ./acme.sh You `don't have to be root` then, although `it is recommended`. +Advanced Installation: https://github.com/Neilpang/acme.sh/wiki/How-to-install + The installer will perform 3 actions: 1. Create and copy `acme.sh` to your home dir (`$HOME`): `~/.acme.sh/`. From 0103f59f826ae19972dfbd569f13d21322745c6a Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 21 Apr 2016 22:48:40 +0800 Subject: [PATCH 0141/1348] remove unnecessary kill. --- acme.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 81f170b7..04af7860 100755 --- a/acme.sh +++ b/acme.sh @@ -747,11 +747,7 @@ _stopserver(){ kill -s 9 $pid > /dev/null fi - for ncid in $(echo $(ps | grep nc) | cut -d " " -f 1) ; do - _debug "kill $ncid" - kill -s 9 $ncid > /dev/null - done - + _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 } From 14f3dbb71aa16cb0c61efc58695dfe09d4ca44c9 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 22 Apr 2016 20:50:43 +0800 Subject: [PATCH 0142/1348] minor, fix sed_i --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 04af7860..dd3076b6 100755 --- a/acme.sh +++ b/acme.sh @@ -168,10 +168,10 @@ _sed_i() { _err "Usage:_sed_i options filename" return 1 fi - - if sed -h 2>&1 | grep "\-i[SUFFIX]" ; then + _debug2 options "$options" + if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then _debug "Using sed -i" - sed -i "" + sed -i "$options" "$filename" else _debug "No -i support in sed" text="$(cat $filename)" From e4739512e6acd3a57fdc5274c493545b6322c0dc Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 23 Apr 2016 14:03:04 +0800 Subject: [PATCH 0143/1348] minor, remove kill. the following _get call will cause the nc exit. --- acme.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/acme.sh b/acme.sh index dd3076b6..78b29573 100755 --- a/acme.sh +++ b/acme.sh @@ -742,12 +742,6 @@ _stopserver(){ return fi - if [ "$(ps | grep "$pid")" ] ; then - _debug "Found proc process, kill it." - kill -s 9 $pid > /dev/null - fi - - _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 } From 230234e701ce39bbc52915756d3e9bf56a464fc1 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 24 Apr 2016 13:51:42 +0800 Subject: [PATCH 0144/1348] fix issue for openBSD --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 78b29573..385589fc 100755 --- a/acme.sh +++ b/acme.sh @@ -1188,7 +1188,7 @@ issue() { return 1 fi - entry="$(printf $response | egrep -o '\{[^{]*"type":"'$vtype'"[^}]*')" + entry="$(printf "$response" | egrep -o '\{[^{]*"type":"'$vtype'"[^}]*')" _debug entry "$entry" token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" From 63c6a3b089de5820beb31c025255b19cc08ca39c Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 24 Apr 2016 13:57:50 +0800 Subject: [PATCH 0145/1348] Support OpenBSD --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c587f5d..a8d78b95 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |11|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux |12|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux |13|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh -|14|--| Cloud Linux https://github.com/Neilpang/le/issues/111 +|14|-----| Cloud Linux https://github.com/Neilpang/le/issues/111 +|15|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From 5bdad8448cec1348fc0ea4f0f5d9fc286bc1206d Mon Sep 17 00:00:00 2001 From: Jens Kubieziel Date: Sun, 24 Apr 2016 10:50:09 +0000 Subject: [PATCH 0146/1348] Fix some typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8d78b95..59cd5d67 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Nothing will be broken during the process. ### 1. Install online: -Check this project:https://github.com/Neilpang/get.acme.sh +Check this project: https://github.com/Neilpang/get.acme.sh ```bash curl https://get.acme.sh | sh @@ -90,7 +90,7 @@ The installer will perform 3 actions: 1. Create and copy `acme.sh` to your home dir (`$HOME`): `~/.acme.sh/`. All certs will be placed in this folder. -2. Create alia for: `acme.sh=~/.acme.sh/acme.sh`. +2. Create alias for: `acme.sh=~/.acme.sh/acme.sh`. 3. Create everyday cron job to check and renew the cert if needed. Cron entry example: From ac0a1661f3c3f14fde76d41000734a3cb4bc5acf Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 24 Apr 2016 22:16:03 +0800 Subject: [PATCH 0147/1348] remove echo -e --- acme.sh | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index 385589fc..2ab446cc 100755 --- a/acme.sh +++ b/acme.sh @@ -1340,11 +1340,11 @@ issue() { _debug wellknown_path "$wellknown_path" - token="$(echo -e -n "$keyauthorization" | cut -d '.' -f 1)" + token="$(printf "$keyauthorization" | cut -d '.' -f 1)" _debug "writing token:$token to $wellknown_path/$token" mkdir -p "$wellknown_path" - echo -n "$keyauthorization" > "$wellknown_path/$token" + printf "$keyauthorization" > "$wellknown_path/$token" if [ ! "$usingApache" ] ; then webroot_owner=$(_stat $_currentRoot) _debug "Changing owner/group of .well-known to $webroot_owner" @@ -1897,21 +1897,19 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" + _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" + if [ "$_upgrading" ] && [ "$_upgrading" = "1" ] ; then + echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile" + echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile" + echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile" + fi + + _setopt "$_envfile" "LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" + _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + _profile="$(_detect_profile)" if [ "$_profile" ] ; then _debug "Found profile: $_profile" - - _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" - if [ "$_upgrading" ] && [ "$_upgrading" = "1" ] ; then - echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile" - echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile" - echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile" - fi - - _setopt "$_envfile" "LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" - _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" - - echo "" >> "$_profile" _setopt "$_profile" ". \"$LE_WORKING_DIR/$PROJECT_NAME.env\"" _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" else From 4fa08fc78c29013eeb3abf396290ca4ff6db9618 Mon Sep 17 00:00:00 2001 From: Indust <603170673m@gmail.com> Date: Sun, 24 Apr 2016 22:54:40 +0800 Subject: [PATCH 0148/1348] fix record update error for cloudxns (#167) thanks. --- dnsapi/dns_cx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 070a2ad6..dc9c532b 100644 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -69,7 +69,7 @@ existing_records() { return 1 fi count=0 - seg=$(printf "$response" | grep -o "{[^{]*host\":\"$_sub_domain[^}]*}") + seg=$(printf "$response" | grep -o "{[^{]*host\":\"$_sub_domain\"[^}]*}") _debug seg "$seg" if [ -z "$seg" ] ; then return 0 From 2b3fc6656cf98f9989ca91ba63e79f08a7103f22 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 24 Apr 2016 23:10:54 +0800 Subject: [PATCH 0149/1348] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 59cd5d67..bbcf90ce 100644 --- a/README.md +++ b/README.md @@ -211,8 +211,6 @@ The cert will be `renewed every 80 days by default` (which is configurable). Onc **(requires you be root/sudoer, or you have permission to listen tcp 80 port)** -Same usage as above, just give `no` as `--webroot` or `-w`. - The tcp `80` port **MUST** be free to listen, otherwise you will be prompted to free the `80` port and try again. ```bash From ff3bce3287d872c5bfca65614837eadf375a6ff1 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 24 Apr 2016 23:16:45 +0800 Subject: [PATCH 0150/1348] minor, remove 'cp -p', for unnecessary warning message for Proxmox. --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 2ab446cc..37fd8237 100755 --- a/acme.sh +++ b/acme.sh @@ -896,7 +896,7 @@ _restoreApache() { return 0 fi - cp -p "$APACHE_CONF_BACKUP_DIR/$httpdconfname" "$httpdconf" + cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" > "$httpdconf" _debug "Restored: $httpdconf." if ! apachectl -t ; then _err "Sorry, restore apache config error, please contact me." @@ -915,7 +915,7 @@ _setApache() { #backup the conf _debug "Backup apache config file" $httpdconf - cp -p $httpdconf $APACHE_CONF_BACKUP_DIR/ + cp $httpdconf $APACHE_CONF_BACKUP_DIR/ _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" _info "In case there is an error that can not be restored automatically, you may try restore it yourself." _info "The backup file will be deleted on sucess, just forget it." @@ -1585,7 +1585,7 @@ installcert() { if [ "$Le_RealCertPath" ] ; then if [ -f "$Le_RealCertPath" ] ; then - cp -p "$Le_RealCertPath" "$Le_RealCertPath".bak + cp "$Le_RealCertPath" "$Le_RealCertPath".bak fi cat "$CERT_PATH" > "$Le_RealCertPath" fi @@ -1596,7 +1596,7 @@ installcert() { cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" else if [ -f "$Le_RealCACertPath" ] ; then - cp -p "$Le_RealCACertPath" "$Le_RealCACertPath".bak + cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak fi cat "$CA_CERT_PATH" > "$Le_RealCACertPath" fi @@ -1605,14 +1605,14 @@ installcert() { if [ "$Le_RealKeyPath" ] ; then if [ -f "$Le_RealKeyPath" ] ; then - cp -p "$Le_RealKeyPath" "$Le_RealKeyPath".bak + cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak fi cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" fi if [ "$Le_RealFullChainPath" ] ; then if [ -f "$Le_RealFullChainPath" ] ; then - cp -p "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak + cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak fi cat "$CERT_FULLCHAIN_PATH" > "$Le_RealFullChainPath" fi From 620f86130c6c606e52b09c9f1e95ed4e8cc3b70b Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 25 Apr 2016 13:48:03 +0800 Subject: [PATCH 0151/1348] Update README.md --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index bbcf90ce..d256cbe1 100644 --- a/README.md +++ b/README.md @@ -16,21 +16,21 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki #Tested OS | NO | Status| Platform| |----|-------|---------| -|1|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu -|2|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian -|3|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS -|4|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/windows.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included) -|5|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD -|6|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/pfsense.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense -|7|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE -|8|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Alpine Linux (with curl) -|9|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Archlinux -|10|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|fedora -|11|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux -|12|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux -|13|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh +|1|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu +|2|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian +|3|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS +|4|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/windows.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included) +|5|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD +|6|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/pfsense.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense +|7|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE +|8|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Alpine Linux (with curl) +|9|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Archlinux +|10|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|fedora +|11|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux +|12|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux +|13|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh |14|-----| Cloud Linux https://github.com/Neilpang/le/issues/111 -|15|[![](https://cdn.rawgit.com/Neilpang/letest/master/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD +|15|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From 990d46d659b748234a7c4087b355988fe08789f4 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 25 Apr 2016 13:49:02 +0800 Subject: [PATCH 0152/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d256cbe1..b1d38a08 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |1|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu |2|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian |3|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS -|4|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/windows.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included) +|4|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/windows-cygwin.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included) |5|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD |6|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/pfsense.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense |7|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE From bfdf1f482e0b012f0be88f271d1fe1fe37947ec1 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 25 Apr 2016 20:01:37 +0800 Subject: [PATCH 0153/1348] umask --- acme.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acme.sh b/acme.sh index 37fd8237..60575b5c 100755 --- a/acme.sh +++ b/acme.sh @@ -1,4 +1,7 @@ #!/usr/bin/env sh + +umask 077 + VER=2.2.2 PROJECT_NAME="acme.sh" From 762978f8d8a7fcc7308e4b8c6e5b1cf3747014e6 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 26 Apr 2016 08:11:40 +0800 Subject: [PATCH 0154/1348] remove umask, just chmod for the "$LE_WORKING_DIR" --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 60575b5c..0a00662c 100755 --- a/acme.sh +++ b/acme.sh @@ -1,7 +1,5 @@ #!/usr/bin/env sh -umask 077 - VER=2.2.2 PROJECT_NAME="acme.sh" @@ -1891,6 +1889,8 @@ install() { return 1 fi + chmod 700 "$LE_WORKING_DIR" + cp $PROJECT_ENTRY "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" if [ "$?" != "0" ] ; then From 4d2f38b03a10f37043578b5bdf7ae19a7d8ef448 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 27 Apr 2016 22:14:15 +0800 Subject: [PATCH 0155/1348] minor, just refactor some code. --- acme.sh | 159 ++++++++++++++++++++++++++------------------------------ 1 file changed, 74 insertions(+), 85 deletions(-) diff --git a/acme.sh b/acme.sh index 0a00662c..e84011cf 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.2.2 +VER=2.2.3 PROJECT_NAME="acme.sh" @@ -684,7 +684,17 @@ _savedomainconf() { key="$1" value="$2" if [ "$DOMAIN_CONF" ] ; then - _setopt $DOMAIN_CONF "$key" "=" "$value" + _setopt "$DOMAIN_CONF" "$key" "=" "\"$value\"" + else + _err "DOMAIN_CONF is empty, can not save $key=$value" + fi +} + +#_cleardomainconf key +_cleardomainconf() { + key="$1" + if [ "$DOMAIN_CONF" ] ; then + _sed_i "s/^$key.*$//" "$DOMAIN_CONF" else _err "DOMAIN_CONF is empty, can not save $key=$value" fi @@ -695,7 +705,7 @@ _saveaccountconf() { key="$1" value="$2" if [ "$ACCOUNT_CONF_PATH" ] ; then - _setopt $ACCOUNT_CONF_PATH "$key" "=" "\"$value\"" + _setopt "$ACCOUNT_CONF_PATH" "$key" "=" "\"$value\"" else _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" fi @@ -1035,15 +1045,10 @@ issue() { fi fi - _setopt "$DOMAIN_CONF" "Le_Domain" "=" "$Le_Domain" - _setopt "$DOMAIN_CONF" "Le_Alt" "=" "$Le_Alt" - _setopt "$DOMAIN_CONF" "Le_Webroot" "=" "$Le_Webroot" - _setopt "$DOMAIN_CONF" "Le_Keylength" "=" "$Le_Keylength" - _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" - _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" - _setopt "$DOMAIN_CONF" "Le_RealFullChainPath" "=" "\"$Le_RealFullChainPath\"" + _savedomainconf "Le_Domain" "$Le_Domain" + _savedomainconf "Le_Alt" "$Le_Alt" + _savedomainconf "Le_Webroot" "$Le_Webroot" + _savedomainconf "Le_Keylength" "$Le_Keylength" if [ "$Le_Alt" = "no" ] ; then Le_Alt="" @@ -1051,22 +1056,6 @@ issue() { if [ "$Le_Keylength" = "no" ] ; then Le_Keylength="" fi - if [ "$Le_RealCertPath" = "no" ] ; then - Le_RealCertPath="" - fi - if [ "$Le_RealKeyPath" = "no" ] ; then - Le_RealKeyPath="" - fi - if [ "$Le_RealCACertPath" = "no" ] ; then - Le_RealCACertPath="" - fi - if [ "$Le_ReloadCmd" = "no" ] ; then - Le_ReloadCmd="" - fi - if [ "$Le_RealFullChainPath" = "no" ] ; then - Le_RealFullChainPath="" - fi - if _contains "$Le_Webroot" "no" ; then _info "Standalone mode." @@ -1078,7 +1067,7 @@ issue() { if [ -z "$Le_HTTPPort" ] ; then Le_HTTPPort=80 fi - _setopt "$DOMAIN_CONF" "Le_HTTPPort" "=" "$Le_HTTPPort" + _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" netprc="$(_ss "$Le_HTTPPort" | grep "$Le_HTTPPort")" if [ "$netprc" ] ; then @@ -1279,7 +1268,7 @@ issue() { done if [ "$dnsadded" = '0' ] ; then - _setopt "$DOMAIN_CONF" "Le_Vlist" "=" "\"$vlist\"" + _savedomainconf "Le_Vlist" "$vlist" _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup @@ -1426,7 +1415,7 @@ issue() { Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)" - _setopt "$DOMAIN_CONF" "Le_LinkCert" "=" "$Le_LinkCert" + _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ "$Le_LinkCert" ] ; then echo "$BEGIN_CERT" > "$CERT_PATH" @@ -1451,10 +1440,10 @@ issue() { return 1 fi - _setopt "$DOMAIN_CONF" 'Le_Vlist' '=' "\"\"" + _cleardomainconf "Le_Vlist" Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) - _setopt "$DOMAIN_CONF" "Le_LinkIssuer" "=" "$Le_LinkIssuer" + _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ] ; then echo "$BEGIN_CERT" > "$CA_CERT_PATH" @@ -1466,22 +1455,22 @@ issue() { fi Le_CertCreateTime=$(date -u "+%s") - _setopt "$DOMAIN_CONF" "Le_CertCreateTime" "=" "$Le_CertCreateTime" + _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" Le_CertCreateTimeStr=$(date -u ) - _setopt "$DOMAIN_CONF" "Le_CertCreateTimeStr" "=" "\"$Le_CertCreateTimeStr\"" + _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "80" ] ; then Le_RenewalDays=80 fi - _setopt "$DOMAIN_CONF" "Le_RenewalDays" "=" "$Le_RenewalDays" + _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) - _setopt "$DOMAIN_CONF" "Le_NextRenewTime" "=" "$Le_NextRenewTime" + _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) - _setopt "$DOMAIN_CONF" "Le_NextRenewTimeStr" "=" "\"$Le_NextRenewTimeStr\"" + _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" @@ -1518,47 +1507,12 @@ renew() { renewAll() { _initpath - _info "renewAll" - for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do d=$(echo $d | cut -d '/' -f 1) - _info "renew $d" - - Le_LinkCert="" - Le_Domain="" - Le_Alt="no" - Le_Webroot="" - Le_Keylength="" - Le_LinkIssuer="" - - Le_CertCreateTime="" - Le_CertCreateTimeStr="" - Le_RenewalDays="" - Le_NextRenewTime="" - Le_NextRenewTimeStr="" - - Le_RealCertPath="" - Le_RealKeyPath="" - - Le_RealCACertPath="" - - Le_ReloadCmd="" - Le_RealFullChainPath="" - - DOMAIN_PATH="" - DOMAIN_CONF="" - DOMAIN_SSL_CONF="" - CSR_PATH="" - CERT_KEY_PATH="" - CERT_PATH="" - CA_CERT_PATH="" - CERT_PFX_PATH="" - CERT_FULLCHAIN_PATH="" - ACCOUNT_KEY_PATH="" - - wellknown_path="" - - renew "$d" + ( + _info "Renew: $d" + renew "$d" + ) done } @@ -1578,13 +1532,32 @@ installcert() { _initpath $Le_Domain - _setopt "$DOMAIN_CONF" "Le_RealCertPath" "=" "\"$Le_RealCertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealCACertPath" "=" "\"$Le_RealCACertPath\"" - _setopt "$DOMAIN_CONF" "Le_RealKeyPath" "=" "\"$Le_RealKeyPath\"" - _setopt "$DOMAIN_CONF" "Le_ReloadCmd" "=" "\"$Le_ReloadCmd\"" - _setopt "$DOMAIN_CONF" "Le_RealFullChainPath" "=" "\"$Le_RealFullChainPath\"" + _savedomainconf "Le_RealCertPath" "$Le_RealCertPath" + _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath" + _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath" + _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd" + _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath" + if [ "$Le_RealCertPath" = "no" ] ; then + Le_RealCertPath="" + fi + if [ "$Le_RealKeyPath" = "no" ] ; then + Le_RealKeyPath="" + fi + if [ "$Le_RealCACertPath" = "no" ] ; then + Le_RealCACertPath="" + fi + if [ "$Le_ReloadCmd" = "no" ] ; then + Le_ReloadCmd="" + fi + if [ "$Le_RealFullChainPath" = "no" ] ; then + Le_RealFullChainPath="" + fi + + _installed="0" if [ "$Le_RealCertPath" ] ; then + _installed=1 + _info "Installing cert to:$Le_RealCertPath" if [ -f "$Le_RealCertPath" ] ; then cp "$Le_RealCertPath" "$Le_RealCertPath".bak fi @@ -1592,6 +1565,8 @@ installcert() { fi if [ "$Le_RealCACertPath" ] ; then + _installed=1 + _info "Installing CA to:$Le_RealCACertPath" if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ] ; then echo "" >> "$Le_RealCACertPath" cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" @@ -1605,6 +1580,8 @@ installcert() { if [ "$Le_RealKeyPath" ] ; then + _installed=1 + _info "Installing key to:$Le_RealKeyPath" if [ -f "$Le_RealKeyPath" ] ; then cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak fi @@ -1612,6 +1589,8 @@ installcert() { fi if [ "$Le_RealFullChainPath" ] ; then + _installed=1 + _info "Installing full chain to:$Le_RealFullChainPath" if [ -f "$Le_RealFullChainPath" ] ; then cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak fi @@ -1619,8 +1598,18 @@ installcert() { fi if [ "$Le_ReloadCmd" ] ; then + _installed=1 _info "Run Le_ReloadCmd: $Le_ReloadCmd" - (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") + if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") ; then + _info "Reload success." + else + _err "Reload error for :$Le_Domain" + fi + fi + + if [ "$_installed" = "0" ] ; then + _err "Nothing to install. You don't specify any parameter." + return 1 fi } @@ -2083,7 +2072,7 @@ _process() { _keypath="no" _capath="no" _fullchainpath="no" - _reloadcmd="no" + _reloadcmd="" _password="" _accountconf="" _useragent="" @@ -2116,7 +2105,7 @@ _process() { --renew|-r) _CMD="renew" ;; - --renewAll|-renewall) + --renewAll|--renewall) _CMD="renewAll" ;; --revoke) From ca2a96b3f312ed9decff046b638087fd816cde84 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 27 Apr 2016 22:29:35 +0800 Subject: [PATCH 0156/1348] ignore the installcert error for 'issue' --- acme.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index e84011cf..fd29e322 100755 --- a/acme.sh +++ b/acme.sh @@ -1474,7 +1474,10 @@ issue() { installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" - + if [ "$?" = "9" ] ; then + #ignore the empty install error. + return 0 + fi } renew() { @@ -1609,7 +1612,7 @@ installcert() { if [ "$_installed" = "0" ] ; then _err "Nothing to install. You don't specify any parameter." - return 1 + return 9 fi } From 01f54558b9ee70e88a248f1e284625106ae62ecb Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 27 Apr 2016 23:34:29 +0800 Subject: [PATCH 0157/1348] fix error message. --- acme.sh | 9 +++++++-- dnsapi/dns_cf.sh | 2 +- dnsapi/dns_cx.sh | 2 +- dnsapi/dns_dp.sh | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index fd29e322..e6985e93 100755 --- a/acme.sh +++ b/acme.sh @@ -1473,11 +1473,16 @@ issue() { _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" - installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" - if [ "$?" = "9" ] ; then + _output="$(installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" 2>&1)" + _ret="$?" + if [ "$_ret" = "9" ] ; then #ignore the empty install error. return 0 fi + if [ "$_ret" != "0" ] ; then + _err "$_output" + return 1 + fi } renew() { diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 2aac3404..2c7f53f9 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -102,7 +102,7 @@ _get_root() { return 1 fi - if printf $response | grep \"name\":\"$h\" ; then + if printf $response | grep \"name\":\"$h\" >/dev/null ; then _domain_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | head -1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ] ; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index dc9c532b..53a277e5 100644 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -144,7 +144,7 @@ _get_root() { return 1; fi - if printf "$response" | grep "$h." ; then + if printf "$response" | grep "$h." >/dev/null ; then seg=$(printf "$response" | grep -o "{[^{]*$h\.[^}]*\}" ) _debug seg "$seg" _domain_id=$(printf "$seg" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 510384ab..b267db8b 100644 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -152,7 +152,7 @@ _get_root() { return 1 fi - if printf "$response" | grep "Action completed successful" ; then + if printf "$response" | grep "Action completed successful" >/dev/null ; then _domain_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ] ; then From c53da1ef7264f96eddefcc37c8e3361591f3b266 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 3 May 2016 20:41:40 +0800 Subject: [PATCH 0158/1348] fix bug. when the webroot contains 'no' or 'apache' --- acme.sh | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index e6985e93..e393405c 100755 --- a/acme.sh +++ b/acme.sh @@ -76,6 +76,29 @@ _contains(){ echo $_str | grep $_sub >/dev/null 2>&1 } +_hasfield() { + _str="$1" + _field="$2" + _sep="$3" + if [ -z "$_field" ] ; then + _err "Usage: str field [sep]" + return 1 + fi + + if [ -z "$_sep" ] ; then + _sep="," + fi + + for f in $(echo "$_str" | tr ',' ' ') ; do + if [ "$f" = "$_field" ] ; then + _debug "'$_str' contains '$_field'" + return 0 #contains ok + fi + done + _debug "'$_str' does not contain '$_field'" + return 1 #not contains +} + _exists(){ cmd="$1" if [ -z "$cmd" ] ; then @@ -1057,7 +1080,7 @@ issue() { Le_Keylength="" fi - if _contains "$Le_Webroot" "no" ; then + if _hasfield "$Le_Webroot" "no" ; then _info "Standalone mode." if ! _exists "nc" ; then _err "Please install netcat(nc) tools first." @@ -1078,7 +1101,7 @@ issue() { fi fi - if _contains "$Le_Webroot" "apache" ; then + if _hasfield "$Le_Webroot" "apache" ; then if ! _setApache ; then _err "set up apache error. Report error to me." return 1 From 94dc5f330c735b0311353d4a627760fb3814f395 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 7 May 2016 17:11:01 +0800 Subject: [PATCH 0159/1348] install alias for csh --- acme.sh | 67 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/acme.sh b/acme.sh index e393405c..e81d5e1c 100755 --- a/acme.sh +++ b/acme.sh @@ -1873,6 +1873,41 @@ _setShebang() { rm -f "$_file.tmp" } +_installalias() { + _initpath + + _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" + if [ "$_upgrading" ] && [ "$_upgrading" = "1" ] ; then + echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile" + echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile" + echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile" + fi + + _setopt "$_envfile" "LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" + _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + + _profile="$(_detect_profile)" + if [ "$_profile" ] ; then + _debug "Found profile: $_profile" + _setopt "$_profile" ". \"$_envfile\"" + _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" + else + _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" + fi + + + #for csh + _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh" + _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + + _csh_profile="$HOME/.cshrc" + if [ -f "$_csh_profile" ] ; then + _setopt "$_csh_profile" "source \"$_cshfile\"" + fi + +} + install() { if ! _initpath ; then @@ -1920,34 +1955,12 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" - _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" - if [ "$_upgrading" ] && [ "$_upgrading" = "1" ] ; then - echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile" - echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile" - echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile" - fi - - _setopt "$_envfile" "LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" - _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" - - _profile="$(_detect_profile)" - if [ "$_profile" ] ; then - _debug "Found profile: $_profile" - _setopt "$_profile" ". \"$LE_WORKING_DIR/$PROJECT_NAME.env\"" - _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" - else - _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" - fi + _installalias if [ -d "dnsapi" ] ; then mkdir -p $LE_WORKING_DIR/dnsapi cp dnsapi/* $LE_WORKING_DIR/dnsapi/ fi - - #to keep compatible mv the .acc file to .key file - if [ -f "$LE_WORKING_DIR/account.acc" ] ; then - mv "$LE_WORKING_DIR/account.acc" "$LE_WORKING_DIR/account.key" - fi if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then _initconf @@ -1991,9 +2004,15 @@ uninstall() { _profile="$(_detect_profile)" if [ "$_profile" ] ; then text="$(cat $_profile)" - echo "$text" | sed "s|^[.] \"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" > "$_profile" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" > "$_profile" fi + _csh_profile="$HOME/.cshrc" + if [ -f "$_csh_profile" ] ; then + text="$(cat $_csh_profile)" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_csh_profile" + fi + rm -f $LE_WORKING_DIR/$PROJECT_ENTRY _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." From a4270efac9f6600f3bcaef48df4b82f197743614 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 7 May 2016 23:33:42 +0800 Subject: [PATCH 0160/1348] fix wget support in dns api --- acme.sh | 31 +++++++++++++++++++------------ dnsapi/dns_cf.sh | 30 +++++++++++++++++------------- dnsapi/dns_cx.sh | 13 +++++++++---- dnsapi/dns_dp.sh | 9 ++++----- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/acme.sh b/acme.sh index e81d5e1c..cc4ae546 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.2.3 +VER=2.2.4 PROJECT_NAME="acme.sh" @@ -567,24 +567,29 @@ _calcjwk() { _debug2 HEADER "$HEADER" } -# body url [needbase64] +# body url [needbase64] [POST] _post() { body="$1" url="$2" needbase64="$3" + httpmethod="$4" + if [ -z "$httpmethod" ] ; then + httpmethod="POST" + fi + _debug $httpmethod if _exists "curl" ; then CURL="$CURL --dump-header $HTTP_HEADER " if [ "$needbase64" ] ; then - response="$($CURL -A "User-Agent: $USER_AGENT" -X POST --data "$body" $url | _base64)" + response="$($CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" $url | _base64)" else - response="$($CURL -A "User-Agent: $USER_AGENT" -X POST --data "$body" $url)" + response="$($CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" $url)" fi else if [ "$needbase64" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --post-data="$body" $url 2>"$HTTP_HEADER" | _base64)" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --method $httpmethod --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --body-data="$body" $url 2>"$HTTP_HEADER" | _base64)" else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --post-data="$body" $url 2>"$HTTP_HEADER")" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --method $httpmethod --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --body-data="$body" $url 2>"$HTTP_HEADER")" fi _sed_i "s/^ *//g" "$HTTP_HEADER" fi @@ -594,21 +599,22 @@ _post() { # url getheader _get() { + _debug GET url="$1" onlyheader="$2" _debug url $url if _exists "curl" ; then if [ "$onlyheader" ] ; then - $CURL -I -A "User-Agent: $USER_AGENT" $url + $CURL -I -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url else - $CURL -A "User-Agent: $USER_AGENT" $url + $CURL -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url fi else _debug "WGET" "$WGET" if [ "$onlyheader" ] ; then - eval $WGET --user-agent=\"$USER_AGENT\" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' + $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else - eval $WGET --user-agent=\"$USER_AGENT\" -O - $url + $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url fi fi ret=$? @@ -1061,8 +1067,9 @@ issue() { _initpath $Le_Domain if [ -f "$DOMAIN_CONF" ] ; then - Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2) - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then + Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2 | tr -d "'\"") + _debug Le_NextRenewTime "$Le_NextRenewTime" + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(date -u "+%s" ) -lt $Le_NextRenewTime ] ; then _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" return 2 fi diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 2c7f53f9..7a02df2e 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -7,7 +7,7 @@ #CF_Email="xxxx@sss.com" -CF_Api="https://api.cloudflare.com/client/v4/" +CF_Api="https://api.cloudflare.com/client/v4" ######## Public functions ##################### @@ -36,18 +36,18 @@ dns_cf_add(){ _debug _domain "$_domain" _debug "Getting txt records" - _cf_rest GET "/zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain" + _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain" - if [ "$?" != "0" ] || ! printf $response | grep \"success\":true > /dev/null ; then + if ! printf "$response" | grep \"success\":true > /dev/null ; then _err "Error" return 1 fi - count=$(printf $response | grep -o \"count\":[^,]* | cut -d : -f 2) - + count=$(printf "$response" | grep -o \"count\":[^,]* | cut -d : -f 2) + _debug count "$count" 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 _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then if printf $response | grep $fulldomain > /dev/null ; then _info "Added, sleeping 10 seconds" sleep 10 @@ -61,10 +61,10 @@ dns_cf_add(){ _err "Add txt record error." else _info "Updating record" - record_id=$(printf $response | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") + record_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \"| head -1) _debug "record_id" $record_id - _cf_rest PUT "/zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" + _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" if [ "$?" == "0" ]; then _info "Updated, sleeping 10 seconds" sleep 10 @@ -117,17 +117,21 @@ _get_root() { return 1 } - _cf_rest() { m=$1 ep="$2" + data="$3" _debug $ep - if [ "$3" ] ; then - data="$3" + + _H1="X-Auth-Email: $CF_Email" + _H2="X-Auth-Key: $CF_Key" + _H3="Content-Type: application/json" + + if [ "$data" ] ; then _debug data "$data" - response="$(curl --silent -X $m "$CF_Api/$ep" -H "X-Auth-Email: $CF_Email" -H "X-Auth-Key: $CF_Key" -H "Content-Type: application/json" --data $data)" + response="$(_post "$data" "$CF_Api/$ep" "" $m)" else - response="$(curl --silent -X $m "$CF_Api/$ep" -H "X-Auth-Email: $CF_Email" -H "X-Auth-Key: $CF_Key" -H "Content-Type: application/json")" + response="$(_get "$CF_Api/$ep")" fi if [ "$?" != "0" ] ; then diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 53a277e5..8c9d1b34 100644 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -183,11 +183,16 @@ _rest() { _debug sec "$sec" hmac=$(printf "$sec"| openssl md5 |cut -d " " -f 2) _debug hmac "$hmac" - - if [ "$3" ] ; then - response="$(curl --silent -X $m "$url" -H "API-KEY: $CX_Key" -H "API-REQUEST-DATE: $cdate" -H "API-HMAC: $hmac" -H 'Content-Type: application/json' -d "$data")" + + _H1="API-KEY: $CX_Key" + _H2="API-REQUEST-DATE: $cdate" + _H3="API-HMAC: $hmac" + _H4="Content-Type: application/json" + + if [ "$data" ] ; then + response="$(_post "$data" "$url" "" $m)" else - response="$(curl --silent -X $m "$url" -H "API-KEY: $CX_Key" -H "API-REQUEST-DATE: $cdate" -H "API-HMAC: $hmac" -H 'Content-Type: application/json')" + response="$(_get "$url")" fi if [ "$?" != "0" ] ; then diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index b267db8b..67f26899 100644 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -71,7 +71,6 @@ existing_records() { if printf "$response" | grep "Action completed successful" >/dev/null ; then count=$(printf "$response" | grep 'TXT' | wc -l) - record_id=$(printf "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) return 0 else @@ -175,17 +174,17 @@ _get_root() { _rest() { m=$1 ep="$2" + data="$3" _debug $ep url="$REST_API/$ep" _debug url "$url" - if [ "$3" ] ; then - data="$3" + if [ "$data" ] ; then _debug2 data "$data" - response="$(curl --silent -X $m "$url" -d $data)" + response="$(_post $data "$url")" else - response="$(curl --silent -X $m "$url" )" + response="$(_get "$url")" fi if [ "$?" != "0" ] ; then From 6626371d87f125490154c06a0a5fcb3bd5cf9c94 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 8 May 2016 00:44:03 +0800 Subject: [PATCH 0161/1348] minor. create the csh only when necessary. --- acme.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index cc4ae546..667ce587 100755 --- a/acme.sh +++ b/acme.sh @@ -1905,11 +1905,10 @@ _installalias() { #for csh _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh" - _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" - _csh_profile="$HOME/.cshrc" if [ -f "$_csh_profile" ] ; then + _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" _setopt "$_csh_profile" "source \"$_cshfile\"" fi From 218dc3390f4666348d10671f485cc7468d356649 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 8 May 2016 18:20:56 +0800 Subject: [PATCH 0162/1348] support lexicon dns api --- dnsapi/dns_lexicon.sh | 109 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 dnsapi/dns_lexicon.sh diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh new file mode 100644 index 00000000..b5cb8a04 --- /dev/null +++ b/dnsapi/dns_lexicon.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env sh + +# dns api wrapper of lexicon for acme.sh + +lexicon_url="https://github.com/AnalogJ/lexicon" +lexicon_cmd="lexicon" + +wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_lexicon_add() { + fulldomain=$1 + txtvalue=$2 + + domain=$(printf "$fulldomain" | cut -d . -f 2-999) + + if ! _exists $lexicon_cmd ; then + _err "Please install $lexicon_cmd first: $wiki" + return 1 + fi + + if [ -z "$PROVIDER" ] ; then + _err "Please define env PROVIDER first: $wiki" + return 1 + fi + + _savedomainconf PROVIDER "$PROVIDER" + export PROVIDER + + Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr [a-z] [A-Z]) + eval Lx_name_v="\$$Lx_name" + _debug "$Lx_name" "$Lx_name_v" + if [ "$Lx_name_v" ] ; then + _saveaccountconf $Lx_name "$Lx_name_v" + export "$Lx_name" + fi + + Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr [a-z] [A-Z]) + eval Lx_token_v="\$$Lx_token" + _debug "$Lx_token" "$Lx_token_v" + if [ "$Lx_token_v" ] ; then + _saveaccountconf $Lx_token "$Lx_token_v" + export "$Lx_token" + fi + + Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr [a-z] [A-Z]) + eval Lx_password_v="\$$Lx_password" + _debug "$Lx_password" "$Lx_password_v" + if [ "$Lx_password_v" ] ; then + _saveaccountconf $Lx_password "$Lx_password_v" + export "$Lx_password" + fi + + Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr [a-z] [A-Z]) + eval Lx_domaintoken_v="\$$Lx_domaintoken" + _debug "$Lx_domaintoken" "$Lx_domaintoken_v" + if [ "$Lx_domaintoken_v" ] ; then + export "$Lx_domaintoken" + _saveaccountconf $Lx_domaintoken "$Lx_domaintoken_v" + fi + + $lexicon_cmd "$PROVIDER" create ${domain} TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" + +} + + + + + + + + +#################### Private functions bellow ################################## + +_info() { + if [[ -z "$2" ]] ; then + echo "[$(date)] $1" + else + echo "[$(date)] $1"="'$2'" + fi +} + +_err() { + _info "$@" >&2 + return 1 +} + +_debug() { + if [[ -z "$DEBUG" ]] ; then + return + fi + _err "$@" + return 0 +} + +_debug2() { + if [[ "$DEBUG" -ge "2" ]] ; then + _debug "$@" + fi + return +} + + + + +#################### Private functions bellow ################################## + From 9bf69d30e0d7478a5f93dfa564eba6409ae33b76 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 8 May 2016 09:19:17 +0800 Subject: [PATCH 0163/1348] exec mode --- dnsapi/dns_cx.sh | 0 dnsapi/dns_dp.sh | 0 dnsapi/dns_lexicon.sh | 0 dnsapi/dns_myapi.sh | 0 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 dnsapi/dns_cx.sh mode change 100644 => 100755 dnsapi/dns_dp.sh mode change 100644 => 100755 dnsapi/dns_lexicon.sh mode change 100644 => 100755 dnsapi/dns_myapi.sh diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh old mode 100644 new mode 100755 From 2ed01ff040dd6ace2ea8ac757890aaafdda7f978 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 8 May 2016 18:29:30 +0800 Subject: [PATCH 0164/1348] lexicon dns api: (DigitalOcean, DNSimple, DnsMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b1d38a08..5490e5e7 100644 --- a/README.md +++ b/README.md @@ -278,6 +278,8 @@ You don't have do anything manually! 2. Dnspod.cn API 3. Cloudxns.com API 4. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 +5. 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.) ##### More APIs are coming soon... From 1786a5e55a4cd2e96aee56ccd1a4a568c4356f83 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 8 May 2016 21:21:07 +0800 Subject: [PATCH 0165/1348] fix issue --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 667ce587..eb3b38fe 100755 --- a/acme.sh +++ b/acme.sh @@ -1890,7 +1890,7 @@ _installalias() { echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile" fi - _setopt "$_envfile" "LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" + _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" _profile="$(_detect_profile)" From 61579ec3295e3707b52f04e9823fd12aed1c9eba Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 8 May 2016 21:47:37 +0800 Subject: [PATCH 0166/1348] Update README.md --- dnsapi/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 951d909e..17095ed5 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -83,4 +83,8 @@ For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) +# Use lexicon dns api + +https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api + From 7939b419f7f40f897ec5b0b4db10974d278e46c2 Mon Sep 17 00:00:00 2001 From: Alistair Nixon Date: Mon, 9 May 2016 11:18:38 +0100 Subject: [PATCH 0167/1348] fix issue where keyauthorization starts with a - character (#184) --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index eb3b38fe..e1662b04 100755 --- a/acme.sh +++ b/acme.sh @@ -1360,11 +1360,11 @@ issue() { _debug wellknown_path "$wellknown_path" - token="$(printf "$keyauthorization" | cut -d '.' -f 1)" + token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)" _debug "writing token:$token to $wellknown_path/$token" mkdir -p "$wellknown_path" - printf "$keyauthorization" > "$wellknown_path/$token" + printf "%s" "$keyauthorization" > "$wellknown_path/$token" if [ ! "$usingApache" ] ; then webroot_owner=$(_stat $_currentRoot) _debug "Changing owner/group of .well-known to $webroot_owner" From acafa585f46202fc9991ee70e13f9743f918a450 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 9 May 2016 22:28:45 +0800 Subject: [PATCH 0168/1348] support tcsh --- acme.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/acme.sh b/acme.sh index e1662b04..190c9b51 100755 --- a/acme.sh +++ b/acme.sh @@ -1911,6 +1911,14 @@ _installalias() { _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" _setopt "$_csh_profile" "source \"$_cshfile\"" fi + + #for tcsh + _tcsh_profile="$HOME/.tcshrc" + if [ -f "$_tcsh_profile" ] ; then + _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + _setopt "$_tcsh_profile" "source \"$_cshfile\"" + fi } @@ -2019,6 +2027,12 @@ uninstall() { echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_csh_profile" fi + _tcsh_profile="$HOME/.tcshrc" + if [ -f "$_tcsh_profile" ] ; then + text="$(cat $_tcsh_profile)" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_tcsh_profile" + fi + rm -f $LE_WORKING_DIR/$PROJECT_ENTRY _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." From c839b2b03935d310f688c1b064e5f703b4b30755 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 9 May 2016 22:36:48 +0800 Subject: [PATCH 0169/1348] minor, add comments --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 190c9b51..cbee98fa 100755 --- a/acme.sh +++ b/acme.sh @@ -567,7 +567,7 @@ _calcjwk() { _debug2 HEADER "$HEADER" } -# body url [needbase64] [POST] +# body url [needbase64] [POST|PUT] _post() { body="$1" url="$2" From d3595686f6df3ec4de63718e7c1c2df9efcf3dca Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 9 May 2016 22:56:19 +0800 Subject: [PATCH 0170/1348] fix issue. return the actual retcode. --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index cbee98fa..fa58c387 100755 --- a/acme.sh +++ b/acme.sh @@ -2393,6 +2393,10 @@ _process() { return 1 ;; esac + _ret="$?" + if [ "$_ret" != "0" ] ; then + return $_ret + fi if [ "$_useragent" ] ; then _saveaccountconf "USER_AGENT" "$_useragent" From 8f48168c734414d2f4cf5db2f2440556e34b1955 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 10 May 2016 23:20:50 +0800 Subject: [PATCH 0171/1348] minor --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index fa58c387..5e6c9d6a 100755 --- a/acme.sh +++ b/acme.sh @@ -579,11 +579,11 @@ _post() { fi _debug $httpmethod if _exists "curl" ; then - CURL="$CURL --dump-header $HTTP_HEADER " + _CURL="$CURL --dump-header $HTTP_HEADER " if [ "$needbase64" ] ; then - response="$($CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" $url | _base64)" + response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" $url | _base64)" else - response="$($CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" $url)" + response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" $url)" fi else if [ "$needbase64" ] ; then @@ -846,7 +846,7 @@ _initpath() { dp="$LE_WORKING_DIR/curl.dump" CURL="curl -L --silent" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - CURL="$CURL -L --trace-ascii $dp " + CURL="$CURL --trace-ascii $dp " fi _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" From 06e8b869b9032d87f8732f6ad6861ec304d77a04 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 11 May 2016 13:27:33 +0800 Subject: [PATCH 0172/1348] Update README.md --- dnsapi/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 17095ed5..7a208cdd 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -18,7 +18,7 @@ Ok, let's issue cert now: le.sh --issue --dns dns_cf -d aa.com -d www.aa.com ``` -The `CF_Key` and `CF_Email` will be saved in `~/.le/account.conf`, when next time you use cloudflare api, it will reuse this key. +The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. @@ -40,7 +40,7 @@ Ok, let's issue cert now: le.sh --issue --dns dns_dp -d aa.com -d www.aa.com ``` -The `DP_Id` and `DP_Key` will be saved in `~/.le/account.conf`, when next time you use dnspod.cn api, it will reuse this key. +The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf`, when next time you use dnspod.cn api, it will reuse this key. ## Use Cloudxns.com domain api to automatically issue cert @@ -61,7 +61,7 @@ Ok, let's issue cert now: le.sh --issue --dns dns_cx -d aa.com -d www.aa.com ``` -The `CX_Key` and `CX_Secret` will be saved in `~/.le/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. +The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. @@ -71,7 +71,7 @@ If your api is not supported yet, you can write your own dns api. Let's assume you want to name it 'myapi', -1. Create a bash script named `~/.le/dns_myapi.sh`, +1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, 2. In the scrypt, you must have a function named `dns_myapi-add()`. Which will be called by le.sh to add dns records. 3. Then you can use your api to issue cert like: From 1953957506ffa42c397b4c711e327665a64cb130 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 13 May 2016 21:14:00 +0800 Subject: [PATCH 0173/1348] minor, polish code --- acme.sh | 114 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/acme.sh b/acme.sh index 5e6c9d6a..b1f9558b 100755 --- a/acme.sh +++ b/acme.sh @@ -40,7 +40,7 @@ _info() { if [ -z "$2" ] ; then echo "[$(date)] $1" else - echo "[$(date)] $1"="'$2'" + echo "[$(date)] $1='$2'" fi } @@ -67,13 +67,13 @@ _debug2() { _startswith(){ _str="$1" _sub="$2" - echo $_str | grep ^$_sub >/dev/null 2>&1 + echo "$_str" | grep "^$_sub" >/dev/null 2>&1 } _contains(){ _str="$1" _sub="$2" - echo $_str | grep $_sub >/dev/null 2>&1 + echo "$_str" | grep "$_sub" >/dev/null 2>&1 } _hasfield() { @@ -106,9 +106,9 @@ _exists(){ return 1 fi if type command >/dev/null 2>&1 ; then - command -v $cmd >/dev/null 2>&1 + command -v "$cmd" >/dev/null 2>&1 else - type $cmd >/dev/null 2>&1 + type "$cmd" >/dev/null 2>&1 fi ret="$?" _debug2 "$cmd exists=$ret" @@ -124,27 +124,27 @@ _h_char_2_dec() { _ch=$1 case "${_ch}" in a|A) - echo -n 10 + printf "10" ;; b|B) - echo -n 11 + printf "11" ;; c|C) - echo -n 12 + printf "12" ;; d|D) - echo -n 13 + printf "13" ;; e|E) - echo -n 14 + printf "14" ;; f|F) - echo -n 15 + printf "15" ;; *) - echo -n $_ch + printf "%s" "$_ch" ;; - esac + esac } @@ -157,21 +157,21 @@ _h2b() { fi _debug uselet "$uselet" _debug _URGLY_PRINTF "$_URGLY_PRINTF" - while [ '1' ] ; do + while true ; do if [ -z "$_URGLY_PRINTF" ] ; then - h=$(printf $hex | cut -c $i-$j) + h="$(printf $hex | cut -c $i-$j)" if [ -z "$h" ] ; then break; fi printf "\x$h" else - ic=$(printf $hex | cut -c $i) - jc=$(printf $hex | cut -c $j) + ic="$(printf $hex | cut -c $i)" + jc="$(printf $hex | cut -c $j)" if [ -z "$ic$jc" ] ; then break; fi - ic="$(_h_char_2_dec $ic)" - jc="$(_h_char_2_dec $jc)" + ic="$(_h_char_2_dec "$ic")" + jc="$(_h_char_2_dec "$jc")" printf '\'"$(printf %o "$(_math $ic \* 16 + $jc)")" fi if [ "$uselet" ] ; then @@ -198,7 +198,7 @@ _sed_i() { sed -i "$options" "$filename" else _debug "No -i support in sed" - text="$(cat $filename)" + text="$(cat "$filename")" echo "$text" | sed "$options" > "$filename" fi } @@ -213,23 +213,23 @@ _getfile() { return 1 fi - i="$(grep -n -- "$startline" $filename | cut -d : -f 1)" + i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)" if [ -z "$i" ] ; then _err "Can not find start line: $startline" return 1 fi - i="$(_math $i + 1)" - _debug i $i + i="$(_math "$i" + 1)" + _debug i "$i" - j="$(grep -n -- "$endline" $filename | cut -d : -f 1)" + j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)" if [ -z "$j" ] ; then _err "Can not find end line: $endline" return 1 fi - j="$(_math $j - 1)" - _debug j $j + j="$(_math "$j" - 1)" + _debug j "$j" - sed -n $i,${j}p "$filename" + sed -n "$i,${j}p" "$filename" } @@ -293,7 +293,7 @@ _ss() { if _exists "ss" ; then _debug "Using: ss" - ss -ntpl | grep :$_port" " + ss -ntpl | grep ":$_port " return 0 fi @@ -301,12 +301,12 @@ _ss() { _debug "Using: netstat" if netstat -h 2>&1 | grep "\-p proto" >/dev/null ; then #for windows version netstat tool - netstat -anb -p tcp | grep "LISTENING" | grep :$_port" " + netstat -anb -p tcp | grep "LISTENING" | grep ":$_port " else if netstat -help 2>&1 | grep "\-p protocol" >/dev/null ; then - netstat -an -p tcp | grep LISTEN | grep :$_port" " + netstat -an -p tcp | grep LISTEN | grep ":$_port " else - netstat -ntpl | grep :$_port" " + netstat -ntpl | grep ":$_port " fi fi return 0 @@ -434,11 +434,11 @@ createDomainKey() { createCSR() { _info "Creating csr" if [ -z "$1" ] ; then - echo Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ] + echo "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]" return fi domain=$1 - _initpath $domain + _initpath "$domain" domainlist=$2 @@ -449,7 +449,7 @@ createCSR() { if [ -z "$domainlist" ] || [ "$domainlist" = "no" ]; then #single domain - _info "Single domain" $domain + _info "Single domain" "$domain" printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$DOMAIN_SSL_CONF" openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" else @@ -513,7 +513,7 @@ _calcjwk() { modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2 ) _debug2 modulus "$modulus" - n=$(echo -n $modulus| _h2b | _base64 | _urlencode ) + n="$(printf "%s" "$modulus"| _h2b | _base64 | _urlencode )" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' _debug2 jwk "$jwk" @@ -523,36 +523,36 @@ _calcjwk() { _debug "EC key" EC_SIGN="1" crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" - _debug2 crv $crv + _debug2 crv "$crv" pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math $pubi + 1) - _debug2 pubi $pubi + _debug2 pubi "$pubi" pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math $pubj + 1) - _debug2 pubj $pubj + _debug2 pubj "$pubj" pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug2 pubtext "$pubtext" xlen="$(printf "$pubtext" | tr -d ':' | wc -c)" xlen=$(_math $xlen / 4) - _debug2 xlen $xlen + _debug2 xlen "$xlen" - xend=$(_math $xend + 1) + xend=$(_math "$xend" + 1) x="$(printf $pubtext | cut -d : -f 2-$xend)" - _debug2 x $x + _debug2 x "$x" x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)" - _debug2 x64 $x64 + _debug2 x64 "$x64" - xend=$(_math $xend + 1) + xend=$(_math "$xend" + 1) y="$(printf $pubtext | cut -d : -f $xend-10000)" - _debug2 y $y + _debug2 y "$y" y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)" - _debug2 y64 $y64 + _debug2 y64 "$y64" jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}' _debug2 jwk "$jwk" @@ -581,19 +581,19 @@ _post() { if _exists "curl" ; then _CURL="$CURL --dump-header $HTTP_HEADER " if [ "$needbase64" ] ; then - response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" $url | _base64)" + response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" | _base64)" else - response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" $url)" + response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )" fi else if [ "$needbase64" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --method $httpmethod --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --body-data="$body" $url 2>"$HTTP_HEADER" | _base64)" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --method $httpmethod --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --method $httpmethod --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --body-data="$body" $url 2>"$HTTP_HEADER")" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --method $httpmethod --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --body-data="$body" "$url" 2>"$HTTP_HEADER")" fi _sed_i "s/^ *//g" "$HTTP_HEADER" fi - echo -n "$response" + printf "%s" "$response" } @@ -760,12 +760,12 @@ _startserver() { _debug "_NC" "$_NC" # while true ; do if [ "$DEBUG" ] ; then - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; + if ! printf "%s" "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then + printf "%s" "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; fi else - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 + if ! printf "%s" "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then + printf "%s" "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 fi fi if [ "$?" != "0" ] ; then @@ -1210,7 +1210,11 @@ issue() { entry="$(printf "$response" | egrep -o '\{[^{]*"type":"'$vtype'"[^}]*')" _debug entry "$entry" - + if [ -z "$entry" ] ; then + _err "Error, can not get domain token $d" + _clearup + return 1 + fi token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token $token From 484d9d2ad86959bb426e89bd3b664828e2036fbf Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 13 May 2016 21:33:52 +0800 Subject: [PATCH 0174/1348] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index b1f9558b..b8dac173 100755 --- a/acme.sh +++ b/acme.sh @@ -578,6 +578,7 @@ _post() { httpmethod="POST" fi _debug $httpmethod + _debug "url" "$url" if _exists "curl" ; then _CURL="$CURL --dump-header $HTTP_HEADER " if [ "$needbase64" ] ; then From 8fb9a709b0d4b2627888bf55a8809faed24bc84c Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 13 May 2016 21:58:29 +0800 Subject: [PATCH 0175/1348] fix issue, Wget 1.13.4 doesn't support "--method" --- acme.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index b8dac173..2b1438f2 100755 --- a/acme.sh +++ b/acme.sh @@ -588,9 +588,17 @@ _post() { fi else if [ "$needbase64" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --method $httpmethod --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + if [ "$httpmethod"="POST" ] ; then + response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + else + response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + fi else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --method $httpmethod --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --body-data="$body" "$url" 2>"$HTTP_HEADER")" + if [ "$httpmethod"="POST" ] ; then + response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" + else + response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" + fi fi _sed_i "s/^ *//g" "$HTTP_HEADER" fi From 2c554a4bbb0f94a4ed756292276df7edd28efcae Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 13 May 2016 22:25:40 +0800 Subject: [PATCH 0176/1348] minor --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 2b1438f2..76d9b37b 100755 --- a/acme.sh +++ b/acme.sh @@ -769,12 +769,12 @@ _startserver() { _debug "_NC" "$_NC" # while true ; do if [ "$DEBUG" ] ; then - if ! printf "%s" "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then - printf "%s" "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; fi else - if ! printf "%s" "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then - printf "%s" "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 fi fi if [ "$?" != "0" ] ; then From 4e1f39cdecb01c09f9e352b64c9940053227fef6 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 14 May 2016 19:47:03 +0800 Subject: [PATCH 0177/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5490e5e7..e3dd109d 100644 --- a/README.md +++ b/README.md @@ -326,7 +326,7 @@ TODO: # Acknowledgment 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme -3. letsencrypt: https://github.com/letsencrypt/letsencrypt +3. Certbot: https://github.com/certbot/certbot # License & Other From 5778811a18a101f403c0e483d1ba9315bd67ff41 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 16 May 2016 22:42:32 +0800 Subject: [PATCH 0178/1348] minor, fix apache version --- acme.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 76d9b37b..cc5f6a45 100755 --- a/acme.sh +++ b/acme.sh @@ -963,8 +963,8 @@ _setApache() { fi #backup the conf - _debug "Backup apache config file" $httpdconf - cp $httpdconf $APACHE_CONF_BACKUP_DIR/ + _debug "Backup apache config file" "$httpdconf" + cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/" _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" _info "In case there is an error that can not be restored automatically, you may try restore it yourself." _info "The backup file will be deleted on sucess, just forget it." @@ -976,14 +976,14 @@ _setApache() { apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)" apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" - if [ "$apacheVer" ] && [ "$apacheMajer" -ge "2" ] && [ "$apacheMinor" -ge "4" ] ; then + if [ "$apacheVer" ] && [ "$apacheMajer$apacheMinor" -ge "24" ] ; then echo " Alias /.well-known/acme-challenge $ACME_DIR Require all granted - " >> $httpdconf + " >> "$httpdconf" else echo " Alias /.well-known/acme-challenge $ACME_DIR @@ -992,7 +992,7 @@ Alias /.well-known/acme-challenge $ACME_DIR Order allow,deny Allow from all - " >> $httpdconf + " >> "$httpdconf" fi From 2ee5d873db78930925e1f60bf21aead9c7f9c65e Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 21 May 2016 14:33:40 +0800 Subject: [PATCH 0179/1348] fix for the new let's encrypt format --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index cc5f6a45..510987e7 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.2.4 +VER=2.2.5 PROJECT_NAME="acme.sh" @@ -667,7 +667,7 @@ _send_signed_request() { _debug2 body "$body" - response="$(_post "$body" $url "$needbase64" )" + response="$(_post "$body" $url "$needbase64" | tr -d "\r\n ")" responseHeaders="$(cat $HTTP_HEADER)" @@ -1401,7 +1401,7 @@ issue() { MAX_RETRY_TIMES=30 fi - while [ "1" ] ; do + while true ; do waittimes=$(_math $waittimes + 1) if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ] ; then _err "$d:Timeout" @@ -1413,7 +1413,7 @@ issue() { _debug "sleep 5 secs to verify" sleep 5 _debug "checking" - response="$(_get $uri)" + response="$(_get $uri | tr -d "\r\n ")" if [ "$?" != "0" ] ; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" From 78768e985b7f3d9dd7cd28ba54c8707af3446aa1 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 21 May 2016 14:47:23 +0800 Subject: [PATCH 0180/1348] minor, add more apache debug info --- acme.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 510987e7..153c74e2 100755 --- a/acme.sh +++ b/acme.sh @@ -916,16 +916,19 @@ _apachePath() { return 1 fi httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" + _debug httpdconfname "$httpdconfname" if _startswith "$httpdconfname" '/' ; then httpdconf="$httpdconfname" httpdconfname="$(basename $httpdconfname)" else httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" + _debug httpdroot "$httpdroot" httpdconf="$httpdroot/$httpdconfname" fi + _debug httpdconf "$httpdconf" - if [ ! -f $httpdconf ] ; then - _err "Apache Config file not found" $httpdconf + if [ ! -f "$httpdconf" ] ; then + _err "Apache Config file not found" "$httpdconf" return 1 fi return 0 From 8f63baf7e4a291324aaee95ecaf0bcbb3df084c7 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 21 May 2016 15:33:10 +0800 Subject: [PATCH 0181/1348] fix centos apache issue --- acme.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 153c74e2..1e747dbd 100755 --- a/acme.sh +++ b/acme.sh @@ -924,9 +924,10 @@ _apachePath() { httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" _debug httpdroot "$httpdroot" httpdconf="$httpdroot/$httpdconfname" + httpdconfname="$(basename $httpdconfname)" fi _debug httpdconf "$httpdconf" - + _debug httpdconfname "$httpdconfname" if [ ! -f "$httpdconf" ] ; then _err "Apache Config file not found" "$httpdconf" return 1 @@ -967,7 +968,11 @@ _setApache() { #backup the conf _debug "Backup apache config file" "$httpdconf" - cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/" + if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/" ; then + _err "Can not backup apache config file, so abort. Don't worry, your apache config is not changed." + _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT" + return 1 + fi _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" _info "In case there is an error that can not be restored automatically, you may try restore it yourself." _info "The backup file will be deleted on sucess, just forget it." From 8d5618c44a2ab973aa7eb243db740e22c742b809 Mon Sep 17 00:00:00 2001 From: raunsbaekdk Date: Sat, 21 May 2016 16:59:39 +0200 Subject: [PATCH 0182/1348] Bash does not support double equal sign (#192) use single equal sign '=' instead. --- dnsapi/dns_cf.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 7a02df2e..7015467d 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -45,7 +45,7 @@ dns_cf_add(){ count=$(printf "$response" | grep -o \"count\":[^,]* | cut -d : -f 2) _debug count "$count" - if [ "$count" == "0" ] ; then + 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 $response | grep $fulldomain > /dev/null ; then @@ -65,7 +65,7 @@ dns_cf_add(){ _debug "record_id" $record_id _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" - if [ "$?" == "0" ]; then + if [ "$?" = "0" ]; then _info "Updated, sleeping 10 seconds" sleep 10 #todo: check if the record takes effect From bb276fc985ea4b6585ac9530efc03e20215d9ad8 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 23 May 2016 13:32:50 +0800 Subject: [PATCH 0183/1348] minor. --- dnsapi/dns_cx.sh | 4 ++-- dnsapi/dns_dp.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 8c9d1b34..33e05e4b 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -44,13 +44,13 @@ dns_cx_add() { return 1 fi - if [ "$count" == "0" ] ; then + if [ "$count" = "0" ] ; then add_record $_domain $_sub_domain $txtvalue else update_record $_domain $_sub_domain $txtvalue fi - if [ "$?" == "0" ] ; then + if [ "$?" = "0" ] ; then return 0 fi return 1 diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 67f26899..39046e2a 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -44,7 +44,7 @@ dns_dp_add() { return 1 fi - if [ "$count" == "0" ] ; then + if [ "$count" = "0" ] ; then add_record $_domain $_sub_domain $txtvalue else update_record $_domain $_sub_domain $txtvalue From eae290992f2a087afd34c7d86331d99709e23455 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 23 May 2016 22:02:43 +0800 Subject: [PATCH 0184/1348] minor, fix normalize json --- acme.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 1e747dbd..8661bc17 100755 --- a/acme.sh +++ b/acme.sh @@ -480,6 +480,10 @@ _time2str() { } +_normalizeJson() { + sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n" +} + _stat() { #Linux if stat -c '%U:%G' "$1" 2>/dev/null ; then @@ -667,7 +671,11 @@ _send_signed_request() { _debug2 body "$body" - response="$(_post "$body" $url "$needbase64" | tr -d "\r\n ")" + response="$(_post "$body" $url "$needbase64")" + + _debug2 original "$response" + + response="$( echo "$response" | _normalizeJson )" responseHeaders="$(cat $HTTP_HEADER)" @@ -1421,7 +1429,7 @@ issue() { _debug "sleep 5 secs to verify" sleep 5 _debug "checking" - response="$(_get $uri | tr -d "\r\n ")" + response="$(_get $uri | _normalizeJson )" if [ "$?" != "0" ] ; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" @@ -1486,7 +1494,7 @@ issue() { if [ -z "$Le_LinkCert" ] ; then - response="$(echo $response | _dbase64 "multiline" )" + response="$(echo $response | _dbase64 "multiline" | _normalizeJson )" _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" return 1 fi From 39c8f79f3ef8b1e16c21198fbc8f2936d806a1d8 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 29 May 2016 14:08:39 +0800 Subject: [PATCH 0185/1348] add '--httpport' for servers that is behind a reverse proxy or load balancer --- README.md | 54 ++---------------------------------------------------- acme.sh | 11 +++++++++-- 2 files changed, 11 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index e3dd109d..508972f5 100644 --- a/README.md +++ b/README.md @@ -105,58 +105,8 @@ Ok, you are ready to issue cert now. Show help message: ``` -root@v1:~# acme.sh -https://github.com/Neilpang/acme.sh -v2.1.1 -Usage: acme.sh command ...[parameters].... -Commands: - --help, -h Show this help message. - --version, -v Show version info. - --install Install acme.sh to your system. - --uninstall Uninstall acme.sh, and uninstall the cron job. - --issue Issue a cert. - --installcert Install the issued cert to apache/nginx or any other server. - --renew, -r Renew a cert. - --renewAll Renew all the certs - --revoke Revoke a cert. - --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. - --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically. - --cron Run cron job to renew all the certs. - --toPkcs Export the certificate and key to a pfx file. - --createAccountKey, -cak Create an account private key, professional use. - --createDomainKey, -cdk Create an domain private key, professional use. - --createCSR, -ccsr Create CSR , professional use. - -Parameters: - --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. - --force, -f Used to force to install or force to renew a cert immediately. - --staging, --test Use staging server, just for test. - --debug Output debug info. - - --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. - --standalone Use standalone mode. - --apache Use apache mode. - --dns [dns-cf|dns-dp|dns-cx|/path/to/api/file] Use dns mode or dns api. - - --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. - --accountkeylength, -ak [2048] Specifies the account key length. - - 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. - --keypath /path/to/real/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. - --fullchainpath /path/to/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. - - --accountconf Specifies a customized account config file. - --home Specifies the home dir for acme.sh . - --certhome Specifies the home dir to save all the certs, only valid for '--install' command. - --useragent Specifies the user agent string. it will be saved for future use too. - --accountemail Specifies the account email for registering, Only valid for the '--install' command. - --accountkey Specifies the account key path, Only valid for the '--install' command. - --days Specifies the days to renew the cert when using '--issue' command. The max value is 80 days. + +root@v1:~# acme.sh -h ``` diff --git a/acme.sh b/acme.sh index 8661bc17..d239375b 100755 --- a/acme.sh +++ b/acme.sh @@ -775,6 +775,7 @@ _startserver() { fi _debug "_NC" "$_NC" + _debug Le_HTTPPort "$Le_HTTPPort" # while true ; do if [ "$DEBUG" ] ; then if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then @@ -2124,12 +2125,12 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME . - --certhome Specifies the home dir to save all the certs. + --certhome Specifies the home dir to save all the certs, only valid for '--install' command. --useragent Specifies the user agent string. it will be saved for future use too. --accountemail Specifies the account email for registering, Only valid for the '--install' command. --accountkey Specifies the account key path, Only valid for the '--install' command. --days Specifies the days to renew the cert when using '--issue' command. The max value is 80 days. - + --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. " } @@ -2178,6 +2179,7 @@ _process() { _accountemail="" _accountkey="" _certhome="" + _httpport="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -2372,6 +2374,11 @@ _process() { Le_RenewalDays="$_days" shift ;; + --httpport ) + _httpport="$2" + Le_HTTPPort="$_httpport" + shift + ;; *) _err "Unknown parameter : $1" return 1 From c835ab025a021c5dbbf04dbe2acbe25baecea355 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 30 May 2016 21:28:03 +0800 Subject: [PATCH 0186/1348] add more log --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d239375b..66feabab 100755 --- a/acme.sh +++ b/acme.sh @@ -1431,6 +1431,7 @@ issue() { sleep 5 _debug "checking" response="$(_get $uri | _normalizeJson )" + _debug2 response "$response" if [ "$?" != "0" ] ; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" @@ -1448,7 +1449,7 @@ issue() { fi if [ "$status" = "invalid" ] ; then - error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4) + error="$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4)" _err "$d:Verify error:$error" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup From b7ec6789b36f2675d093ec958ba32f1bf3dd342d Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 30 May 2016 21:55:49 +0800 Subject: [PATCH 0187/1348] add more log --- acme.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 66feabab..d5061c7b 100755 --- a/acme.sh +++ b/acme.sh @@ -1449,8 +1449,15 @@ issue() { fi if [ "$status" = "invalid" ] ; then - error="$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4)" - _err "$d:Verify error:$error" + error="$(echo $response | egrep -o '"error":{[^}]*}')" + _debug2 error "$error" + errordetail="$(echo $error | grep -o '"detail": *"[^"]*"' | cut -d '"' -f 4)" + _debug2 errordetail "$errordetail" + if [ "$errordetail" ] ; then + _err "$d:Verify error:$errordetail" + else + _err "$d:Verify error:$error" + fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup return 1; From 6e180343332631adc51557842e7a4f481fe4875b Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 30 May 2016 22:06:30 +0800 Subject: [PATCH 0188/1348] fix error message. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d5061c7b..a1deb92d 100755 --- a/acme.sh +++ b/acme.sh @@ -1449,7 +1449,7 @@ issue() { fi if [ "$status" = "invalid" ] ; then - error="$(echo $response | egrep -o '"error":{[^}]*}')" + error="$(echo $response | tr -d "\r\n" | egrep -o '"error":{[^}]*}')" _debug2 error "$error" errordetail="$(echo $error | grep -o '"detail": *"[^"]*"' | cut -d '"' -f 4)" _debug2 errordetail "$errordetail" From 16679b572f1fae22445e2d63ada289c584c96d9e Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 31 May 2016 12:12:30 +0800 Subject: [PATCH 0189/1348] add more debug info --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a1deb92d..05bd4b12 100755 --- a/acme.sh +++ b/acme.sh @@ -590,6 +590,7 @@ _post() { else response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )" fi + _ret="$?" else if [ "$needbase64" ] ; then if [ "$httpmethod"="POST" ] ; then @@ -604,10 +605,12 @@ _post() { response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" fi fi + _ret="$?" _sed_i "s/^ *//g" "$HTTP_HEADER" fi + _debug "_ret" "$_ret" printf "%s" "$response" - + return $_ret } # url getheader From 7012b91f0553fe1df911a47bdfbdf2ff8c185eb7 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 31 May 2016 12:28:43 +0800 Subject: [PATCH 0190/1348] add err check for post and get --- acme.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 05bd4b12..80156362 100755 --- a/acme.sh +++ b/acme.sh @@ -658,7 +658,10 @@ _send_signed_request() { nonceurl="$API/directory" nonce="$(_get $nonceurl "onlyheader" | grep -o "Replay-Nonce:.*$" | head -1 | tr -d "\r\n" | cut -d ' ' -f 2)" - + if [ "$?" != "0" ] ; then + _err "Can not connect to $nonceurl to get nonce." + return 1 + fi _debug nonce "$nonce" protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" @@ -675,7 +678,10 @@ _send_signed_request() { response="$(_post "$body" $url "$needbase64")" - + if [ "$?" != "0" ] ; then + _err "Can not post to $url." + return 1 + fi _debug2 original "$response" response="$( echo "$response" | _normalizeJson )" @@ -1434,13 +1440,13 @@ issue() { sleep 5 _debug "checking" response="$(_get $uri | _normalizeJson )" - _debug2 response "$response" if [ "$?" != "0" ] ; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup return 1 fi + _debug2 response "$response" status=$(echo $response | egrep -o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') if [ "$status" = "valid" ] ; then From a272ee4f59bc19cf5d5bd3449bb79bc09106c297 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 31 May 2016 20:16:57 +0800 Subject: [PATCH 0191/1348] fix get nonce --- acme.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 80156362..c3d9d76f 100755 --- a/acme.sh +++ b/acme.sh @@ -657,11 +657,17 @@ _send_signed_request() { _debug2 payload64 $payload64 nonceurl="$API/directory" - nonce="$(_get $nonceurl "onlyheader" | grep -o "Replay-Nonce:.*$" | head -1 | tr -d "\r\n" | cut -d ' ' -f 2)" + _headers="$(_get $nonceurl "onlyheader")" + if [ "$?" != "0" ] ; then _err "Can not connect to $nonceurl to get nonce." return 1 fi + + _debug2 _headers "$_headers" + + nonce="$( echo "$_headers" | grep "Replay-Nonce:" | head -1 | tr -d "\r\n " | cut -d ':' -f 2)" + _debug nonce "$nonce" protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" From c4d8fd83d446ab53161d4310f3b6157037b62a24 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 31 May 2016 20:32:58 +0800 Subject: [PATCH 0192/1348] check return code --- acme.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index c3d9d76f..8f9bc65a 100755 --- a/acme.sh +++ b/acme.sh @@ -1242,7 +1242,13 @@ issue() { vtype="$VTYPE_DNS" fi _info "Getting token for domain" $d - _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" + + if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" ; then + _err "Can not get domain token." + _clearup + return 1 + fi + if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then _err "new-authz error: $response" _clearup @@ -1419,7 +1425,12 @@ issue() { fi fi - _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" + if ! _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" ; then + _err "$d:Can not get challenge: $response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + return 1 + fi if [ ! -z "$code" ] && [ ! "$code" = '202' ] ; then _err "$d:Challenge error: $response" @@ -1494,7 +1505,11 @@ issue() { _clearup _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)" - _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" + + if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" ; then + _err "Sign failed." + return 1 + fi Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)" From 9aaf36cd0c3fbff1e05ad16a57292b579cf3d654 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 31 May 2016 21:20:10 +0800 Subject: [PATCH 0193/1348] add curl error message. --- acme.sh | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 8f9bc65a..40909f75 100755 --- a/acme.sh +++ b/acme.sh @@ -586,9 +586,9 @@ _post() { if _exists "curl" ; then _CURL="$CURL --dump-header $HTTP_HEADER " if [ "$needbase64" ] ; then - response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" | _base64)" + response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" 2>"$HTTP_ERROR_FILE" | _base64)" else - response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )" + response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" 2>"$HTTP_ERROR_FILE" )" fi _ret="$?" else @@ -609,6 +609,9 @@ _post() { _sed_i "s/^ *//g" "$HTTP_HEADER" fi _debug "_ret" "$_ret" + if [ "$ret" != "0" ] ; then + _err "$(cat "$HTTP_ERROR_FILE")" + fi printf "%s" "$response" return $_ret } @@ -621,19 +624,24 @@ _get() { _debug url $url if _exists "curl" ; then if [ "$onlyheader" ] ; then - $CURL -I -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url + $CURL -I -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url 2>"$HTTP_ERROR_FILE" else - $CURL -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url + $CURL -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url 2>"$HTTP_ERROR_FILE" fi + ret=$? else _debug "WGET" "$WGET" if [ "$onlyheader" ] ; then $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else - $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url + $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url 2>"$HTTP_ERROR_FILE" fi + ret=$? + fi + + if [ "$ret" != "0" ] ; then + _err "$(cat "$HTTP_ERROR_FILE")" fi - ret=$? return $ret } @@ -870,6 +878,7 @@ _initpath() { fi HTTP_HEADER="$LE_WORKING_DIR/http.header" + HTTP_ERROR_FILE="$LE_WORKING_DIR/http.err" WGET="wget -q" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then @@ -1456,13 +1465,16 @@ issue() { _debug "sleep 5 secs to verify" sleep 5 _debug "checking" - response="$(_get $uri | _normalizeJson )" + response="$(_get $uri)" if [ "$?" != "0" ] ; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup return 1 fi + _debug2 original "$response" + + response="$(echo "$response" | _normalizeJson )" _debug2 response "$response" status=$(echo $response | egrep -o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') From ec9fc8cbf7062f57f736109c19c9384c27e3d6a4 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 31 May 2016 21:38:41 +0800 Subject: [PATCH 0194/1348] add more debug message --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 40909f75..83ad3d2a 100755 --- a/acme.sh +++ b/acme.sh @@ -585,6 +585,7 @@ _post() { _debug "url" "$url" if _exists "curl" ; then _CURL="$CURL --dump-header $HTTP_HEADER " + _debug "_CURL" "$_CURL" if [ "$needbase64" ] ; then response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" 2>"$HTTP_ERROR_FILE" | _base64)" else @@ -592,6 +593,7 @@ _post() { fi _ret="$?" else + _debug "WGET" "$WGET" if [ "$needbase64" ] ; then if [ "$httpmethod"="POST" ] ; then response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" @@ -623,6 +625,7 @@ _get() { onlyheader="$2" _debug url $url if _exists "curl" ; then + _debug "CURL" "$CURL" if [ "$onlyheader" ] ; then $CURL -I -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url 2>"$HTTP_ERROR_FILE" else @@ -638,7 +641,7 @@ _get() { fi ret=$? fi - + _debug "ret" "$ret" if [ "$ret" != "0" ] ; then _err "$(cat "$HTTP_ERROR_FILE")" fi From d65e3d9a6ee751594ba24ead2f46d1636a97adf5 Mon Sep 17 00:00:00 2001 From: rajcz Date: Fri, 3 Jun 2016 12:12:34 +0200 Subject: [PATCH 0195/1348] typos --- dnsapi/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 7a208cdd..42e6a3ab 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -15,7 +15,7 @@ export CF_Email="xxxx@sss.com" Ok, let's issue cert now: ``` -le.sh --issue --dns dns_cf -d aa.com -d www.aa.com +acme.sh --issue --dns dns_cf -d aa.com -d www.aa.com ``` The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. @@ -37,7 +37,7 @@ export DP_Key="sADDsdasdgdsf" Ok, let's issue cert now: ``` -le.sh --issue --dns dns_dp -d aa.com -d www.aa.com +acme.sh --issue --dns dns_dp -d aa.com -d www.aa.com ``` The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf`, when next time you use dnspod.cn api, it will reuse this key. @@ -58,7 +58,7 @@ export CX_Secret="sADDsdasdgdsf" Ok, let's issue cert now: ``` -le.sh --issue --dns dns_cx -d aa.com -d www.aa.com +acme.sh --issue --dns dns_cx -d aa.com -d www.aa.com ``` The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. @@ -76,7 +76,7 @@ Let's assume you want to name it 'myapi', 3. Then you can use your api to issue cert like: ``` -le.sh --issue --dns dns_myapi -d aa.com -d www.aa.com +acme.sh --issue --dns dns_myapi -d aa.com -d www.aa.com ``` For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) From 199067e8ab741ea89039a371dc73f58d527c1e5f Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 5 Jun 2016 19:53:22 +0800 Subject: [PATCH 0196/1348] add Mageia status --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 508972f5..a1ebd8a2 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |13|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh |14|-----| Cloud Linux https://github.com/Neilpang/le/issues/111 |15|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD +|16|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From cc7fdbd661761fda037fc3a085a31328cb398391 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 7 Jun 2016 11:27:36 +0800 Subject: [PATCH 0197/1348] minor, remove the unnecessary error file --- acme.sh | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 83ad3d2a..c0f67841 100755 --- a/acme.sh +++ b/acme.sh @@ -587,9 +587,9 @@ _post() { _CURL="$CURL --dump-header $HTTP_HEADER " _debug "_CURL" "$_CURL" if [ "$needbase64" ] ; then - response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" 2>"$HTTP_ERROR_FILE" | _base64)" + response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" | _base64)" else - response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" 2>"$HTTP_ERROR_FILE" )" + response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )" fi _ret="$?" else @@ -611,9 +611,6 @@ _post() { _sed_i "s/^ *//g" "$HTTP_HEADER" fi _debug "_ret" "$_ret" - if [ "$ret" != "0" ] ; then - _err "$(cat "$HTTP_ERROR_FILE")" - fi printf "%s" "$response" return $_ret } @@ -627,9 +624,9 @@ _get() { if _exists "curl" ; then _debug "CURL" "$CURL" if [ "$onlyheader" ] ; then - $CURL -I -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url 2>"$HTTP_ERROR_FILE" + $CURL -I -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url else - $CURL -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url 2>"$HTTP_ERROR_FILE" + $CURL -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url fi ret=$? else @@ -637,14 +634,11 @@ _get() { if [ "$onlyheader" ] ; then $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else - $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url 2>"$HTTP_ERROR_FILE" + $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url fi ret=$? fi _debug "ret" "$ret" - if [ "$ret" != "0" ] ; then - _err "$(cat "$HTTP_ERROR_FILE")" - fi return $ret } @@ -881,7 +875,6 @@ _initpath() { fi HTTP_HEADER="$LE_WORKING_DIR/http.header" - HTTP_ERROR_FILE="$LE_WORKING_DIR/http.err" WGET="wget -q" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then From bf233fbd48fd3258c4c978abbd000f847cb84c6a Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 7 Jun 2016 13:05:27 +0800 Subject: [PATCH 0198/1348] minor --- dnsapi/dns_lexicon.sh | 40 ---------------------------------------- dnsapi/dns_myapi.sh | 26 ++++++++------------------ 2 files changed, 8 insertions(+), 58 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index b5cb8a04..5e78a2d9 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -67,43 +67,3 @@ dns_lexicon_add() { - - - - - -#################### Private functions bellow ################################## - -_info() { - if [[ -z "$2" ]] ; then - echo "[$(date)] $1" - else - echo "[$(date)] $1"="'$2'" - fi -} - -_err() { - _info "$@" >&2 - return 1 -} - -_debug() { - if [[ -z "$DEBUG" ]] ; then - return - fi - _err "$@" - return 0 -} - -_debug2() { - if [[ "$DEBUG" -ge "2" ]] ; then - _debug "$@" - fi - return -} - - - - -#################### Private functions bellow ################################## - diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index f06cc1e6..a29b9ff1 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -2,15 +2,15 @@ #Here is a sample custom api script. #This file name is "dns_myapi.sh" -#So, here must be a method dns_myapi-add() +#So, here must be a method dns_myapi_add() #Which will be called by acme.sh to add the txt record to your api system. -#returns 0 meanst success, otherwise error. +#returns 0 means success, otherwise error. ######## Public functions ##################### -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_myapi_add() { fulldomain=$1 txtvalue=$2 @@ -22,16 +22,12 @@ dns_myapi_add() { - - - #################### Private functions bellow ################################## - _info() { - if [[ -z "$2" ]] ; then + if [ -z "$2" ] ; then echo "[$(date)] $1" else - echo "[$(date)] $1"="'$2'" + echo "[$(date)] $1='$2'" fi } @@ -41,7 +37,7 @@ _err() { } _debug() { - if [[ -z "$DEBUG" ]] ; then + if [ -z "$DEBUG" ] ; then return fi _err "$@" @@ -49,14 +45,8 @@ _debug() { } _debug2() { - if [[ "$DEBUG" -ge "2" ]] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then _debug "$@" fi return -} - - - - -#################### Private functions bellow ################################## - +} \ No newline at end of file From 900352521042b7c4f2532494052acf879a69399d Mon Sep 17 00:00:00 2001 From: Jeremy Fleischman Date: Mon, 6 Jun 2016 22:23:32 -0700 Subject: [PATCH 0199/1348] typo --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index c0f67841..a7032f7d 100755 --- a/acme.sh +++ b/acme.sh @@ -2030,7 +2030,7 @@ install() { _info "Installing to $LE_WORKING_DIR" if ! mkdir -p "$LE_WORKING_DIR" ; then - _err "Can not craete working dir: $LE_WORKING_DIR" + _err "Can not create working dir: $LE_WORKING_DIR" return 1 fi From c083e078d444d2ea3bc90b62c5cc561671d5767a Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 9 Jun 2016 12:06:37 +0800 Subject: [PATCH 0200/1348] minor, remove unnecessary message --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 83ad3d2a..7ea96324 100755 --- a/acme.sh +++ b/acme.sh @@ -987,7 +987,7 @@ _restoreApache() { cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" > "$httpdconf" _debug "Restored: $httpdconf." - if ! apachectl -t ; then + if ! apachectl -t >/dev/null 2>&1 ; then _err "Sorry, restore apache config error, please contact me." return 1; fi @@ -1040,7 +1040,7 @@ Allow from all fi - if ! apachectl -t ; then + if ! apachectl -t >/dev/null 2>&1; then _err "Sorry, apache config error, please contact me." _restoreApache return 1; From ee1737a52eedfa183410deadf2e02d2060015994 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 9 Jun 2016 12:45:30 +0800 Subject: [PATCH 0201/1348] minor, ignore empty -d value --- acme.sh | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index 64a762af..fffac609 100755 --- a/acme.sh +++ b/acme.sh @@ -2284,20 +2284,23 @@ _process() { --domain|-d) _dvalue="$2" - if [ -z "$_dvalue" ] || _startswith "$_dvalue" "-" ; then - _err "'$_dvalue' is not a valid domain for parameter '$1'" - return 1 - fi - - if [ -z "$_domain" ] ; then - _domain="$_dvalue" - else - if [ "$_altdomains" = "no" ] ; then - _altdomains="$_dvalue" + if [ "$_dvalue" ] ; then + if _startswith "$_dvalue" "-" ; then + _err "'$_dvalue' is not a valid domain for parameter '$1'" + return 1 + fi + + if [ -z "$_domain" ] ; then + _domain="$_dvalue" else - _altdomains="$_altdomains,$_dvalue" + if [ "$_altdomains" = "no" ] ; then + _altdomains="$_dvalue" + else + _altdomains="$_altdomains,$_dvalue" + fi fi fi + shift ;; From 6d7eda3e8d91640c026d534eedb19ad8dc7689f3 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 9 Jun 2016 14:18:54 +0800 Subject: [PATCH 0202/1348] v2.2.6 Add "--list" command --- acme.sh | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index fffac609..60bd3656 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.2.5 +VER=2.2.6 PROJECT_NAME="acme.sh" @@ -1631,6 +1631,23 @@ renewAll() { } +list() { + _initpath + printf "Main_Domain|SAN_Domains|Created|Renew\n" + for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do + d=$(echo $d | cut -d '/' -f 1) + ( + _initpath $d + if [ -f "$DOMAIN_CONF" ] ; then + . "$DOMAIN_CONF" + printf "$Le_Domain|$Le_Alt|$Le_CertCreateTimeStr|$Le_NextRenewTimeStr\n" + fi + ) + done + + +} + installcert() { Le_Domain="$1" if [ -z "$Le_Domain" ] ; then @@ -2138,6 +2155,7 @@ Commands: --renew, -r Renew a cert. --renewAll Renew all the certs --revoke Revoke a cert. + --list List all the certs --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically. --cron Run cron job to renew all the certs. @@ -2258,6 +2276,9 @@ _process() { --revoke) _CMD="revoke" ;; + --list) + _CMD="list" + ;; --installcronjob) _CMD="installcronjob" ;; @@ -2456,6 +2477,9 @@ _process() { revoke) revoke "$_domain" ;; + list) + list + ;; installcronjob) installcronjob ;; uninstallcronjob) uninstallcronjob ;; cron) cron ;; From 0e38c60da35620059ca3aa99a0982276260fc3c4 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 13 Jun 2016 10:13:20 +0800 Subject: [PATCH 0203/1348] add "--dnssleep". The time in seconds to wait for all the txt records to take effect in dns api mode. Default 60 seconds. --- acme.sh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 60bd3656..b52a88da 100755 --- a/acme.sh +++ b/acme.sh @@ -1364,8 +1364,14 @@ issue() { fi if [ "$dnsadded" = '1' ] ; then - _info "Sleep 60 seconds for the txt records to take effect" - sleep 60 + if [ -z "$Le_DNSSleep" ] ; then + Le_DNSSleep=60 + else + _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" + fi + + _info "Sleep $Le_DNSSleep seconds for the txt records to take effect" + sleep $Le_DNSSleep fi _debug "ok, let's start to verify" @@ -2174,6 +2180,7 @@ Parameters: --standalone Use standalone mode. --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. + --dnssleep [60] The time in seconds to wait for all the txt records to take effect in dns api mode. Default 60 seconds. --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. @@ -2244,6 +2251,7 @@ _process() { _accountkey="" _certhome="" _httpport="" + _dnssleep="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -2376,6 +2384,12 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; + --dnssleep) + _dnssleep="$2" + Le_DNSSleep="$_dnssleep" + shift + ;; + --keylength|-k) _keylength="$2" accountkeylength="$2" From 054cb72e555fc0ff773407a02f64ba39558adf74 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 13 Jun 2016 14:49:00 +0800 Subject: [PATCH 0204/1348] minor, save days only when necessary --- acme.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index b52a88da..693b2534 100755 --- a/acme.sh +++ b/acme.sh @@ -1142,8 +1142,9 @@ issue() { if [ -z "$Le_HTTPPort" ] ; then Le_HTTPPort=80 - fi - _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" + else + _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" + fi netprc="$(_ss "$Le_HTTPPort" | grep "$Le_HTTPPort")" if [ "$netprc" ] ; then @@ -1574,9 +1575,9 @@ issue() { if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "80" ] ; then Le_RenewalDays=80 - fi - - _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" + else + _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" + fi Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" From d07e8f91c4160b967d58c5b6bc0fd1bddd713695 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 14 Jun 2016 12:00:19 +0800 Subject: [PATCH 0205/1348] Update README.md --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 42e6a3ab..01d8314c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -72,7 +72,7 @@ If your api is not supported yet, you can write your own dns api. Let's assume you want to name it 'myapi', 1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, -2. In the scrypt, you must have a function named `dns_myapi-add()`. Which will be called by le.sh to add dns records. +2. In the scrypt, you must have a function named `dns_myapi_add()`. Which will be called by acme.sh to add dns records. 3. Then you can use your api to issue cert like: ``` From dcf4f8f64ebd29925be3f034cadfc8f736a05e1b Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 14 Jun 2016 13:07:33 +0800 Subject: [PATCH 0206/1348] minor, format the output of "--list" --- acme.sh | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 693b2534..21f3293a 100755 --- a/acme.sh +++ b/acme.sh @@ -1638,19 +1638,27 @@ renewAll() { } + list() { + local _raw="$1" _initpath - printf "Main_Domain|SAN_Domains|Created|Renew\n" - for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do - d=$(echo $d | cut -d '/' -f 1) - ( - _initpath $d - if [ -f "$DOMAIN_CONF" ] ; then - . "$DOMAIN_CONF" - printf "$Le_Domain|$Le_Alt|$Le_CertCreateTimeStr|$Le_NextRenewTimeStr\n" - fi - ) - done + + _sep="|" + if [ "$_raw" ] ; then + printf "Main_Domain${_sep}SAN_Domains${_sep}Created${_sep}Renew\n" + for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do + d=$(echo $d | cut -d '/' -f 1) + ( + _initpath $d + if [ -f "$DOMAIN_CONF" ] ; then + . "$DOMAIN_CONF" + printf "$Le_Domain${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr\n" + fi + ) + done + else + list "raw" | column -t -s "$_sep" + fi } @@ -2203,6 +2211,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 80 days. --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. + --listraw Only used for '--list' command, list the certs in raw format. " } @@ -2253,6 +2262,7 @@ _process() { _certhome="" _httpport="" _dnssleep="" + _listraw="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -2464,6 +2474,10 @@ _process() { Le_HTTPPort="$_httpport" shift ;; + --listraw ) + _listraw="raw" + ;; + *) _err "Unknown parameter : $1" return 1 @@ -2493,7 +2507,7 @@ _process() { revoke "$_domain" ;; list) - list + list "$_listraw" ;; installcronjob) installcronjob ;; uninstallcronjob) uninstallcronjob ;; From 5fc5016d2c0aa758852353a43f60215429c0ffc2 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 15 Jun 2016 13:46:45 +0800 Subject: [PATCH 0207/1348] minor, fix apache error message. --- acme.sh | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 21f3293a..6bfd5c90 100755 --- a/acme.sh +++ b/acme.sh @@ -995,6 +995,18 @@ _setApache() { return 1 fi + #test the conf first + _info "Checking if there is an error in your apache config file before we start." + _msg="$(apachectl -t 2>&1 )" + if [ "$?" != "0" ] ; then + _err "Sorry, apache config has error, please fix it by yourself first, then try again." + _err "Don't worry, we have not made any changes to your system." + _err "$_msg" + return 1; + else + _info "OK" + fi + #backup the conf _debug "Backup apache config file" "$httpdconf" if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/" ; then @@ -1032,10 +1044,14 @@ Allow from all " >> "$httpdconf" fi - - if ! apachectl -t >/dev/null 2>&1; then - _err "Sorry, apache config error, please contact me." - _restoreApache + _msg="$(apachectl -t 2>&1 )" + if [ "$?" != "0" ] ; then + _err "Sorry, apache config error" + if _restoreApache ; then + _err "We have restored your apache config file." + else + _err "Sorry, we are not able to restore the config file, please contact me." + fi return 1; fi From 869578ce4acfa384c3e2b9c5dea3dc74b19a3fff Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 15 Jun 2016 13:57:27 +0800 Subject: [PATCH 0208/1348] minor, fix apache error messaage. --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 6bfd5c90..d7b3659e 100755 --- a/acme.sh +++ b/acme.sh @@ -996,11 +996,11 @@ _setApache() { fi #test the conf first - _info "Checking if there is an error in your apache config file before we start." + _info "Checking if there is an error in the apache config file before starting." _msg="$(apachectl -t 2>&1 )" if [ "$?" != "0" ] ; then - _err "Sorry, apache config has error, please fix it by yourself first, then try again." - _err "Don't worry, we have not made any changes to your system." + _err "Sorry, apache config file has error, please fix it first, then try again." + _err "Don't worry, there is nothing changed to your system." _err "$_msg" return 1; else @@ -1010,7 +1010,7 @@ _setApache() { #backup the conf _debug "Backup apache config file" "$httpdconf" if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/" ; then - _err "Can not backup apache config file, so abort. Don't worry, your 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" return 1 fi @@ -1048,9 +1048,9 @@ Allow from all if [ "$?" != "0" ] ; then _err "Sorry, apache config error" if _restoreApache ; then - _err "We have restored your apache config file." + _err "The apache config file is restored." else - _err "Sorry, we are not able to restore the config file, please contact me." + _err "Sorry, The apache config file can not be restored, please report bug." fi return 1; fi From e22bcf7cb4e7c49226f9129b226c763874d0e324 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Jun 2016 13:23:44 +0800 Subject: [PATCH 0209/1348] support tls (#215) * support tls-sni-01 '--tls' and '--tlsport' * fix tls doc --- README.md | 14 +++ acme.sh | 291 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 249 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index a1ebd8a2..0f9e6841 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,20 @@ acme.sh --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert +# Use Standalone tls server to issue cert + +**(requires you be root/sudoer, or you have permission to listen tcp 443 port)** + +acme.sh supports `tls-sni-01` validation. + +The tcp `443` port **MUST** be free to listen, otherwise you will be prompted to free the `443` port and try again. + +```bash +acme.sh --issue --tls -d aa.com -d www.aa.com -d cp.aa.com +``` + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + # Use Apache mode **(requires you be root/sudoer, since it is required to interact with apache server)** diff --git a/acme.sh b/acme.sh index d7b3659e..b08f8856 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.2.6 +VER=2.2.7 PROJECT_NAME="acme.sh" @@ -17,6 +17,10 @@ STAGE_CA="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" +VTYPE_TLS="tls-sni-01" +VTYPE_TLS2="tls-sni-02" + +W_TLS="tls" BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" END_CSR="-----END CERTIFICATE REQUEST-----" @@ -251,7 +255,7 @@ _dbase64() { fi } -#Usage: hashalg +#Usage: hashalg [outputhex] #Output Base64-encoded digest _digest() { alg="$1" @@ -260,8 +264,14 @@ _digest() { return 1 fi + outputhex="$2" + if [ "$alg" = "sha256" ] ; then - openssl dgst -sha256 -binary | _base64 + if [ "$outputhex" ] ; then + echo $(openssl dgst -sha256 -hex | cut -d = -f 2) + else + openssl dgst -sha256 -binary | _base64 + fi else _err "$alg is not supported yet" return 1 @@ -288,6 +298,86 @@ _sign() { } +# _createkey 2048|ec-256 file +_createkey() { + length="$1" + f="$2" + isec="" + if _startswith "$length" "ec-" ; then + isec="1" + length=$(printf $length | cut -d '-' -f 2-100) + eccname="$length" + fi + + if [ -z "$length" ] ; then + if [ "$isec" ] ; then + length=256 + else + length=2048 + fi + fi + _info "Use length $length" + + if [ "$isec" ] ; then + if [ "$length" = "256" ] ; then + eccname="prime256v1" + fi + if [ "$length" = "384" ] ; then + eccname="secp384r1" + fi + if [ "$length" = "521" ] ; then + eccname="secp521r1" + fi + _info "Using ec name: $eccname" + fi + + #generate account key + if [ "$isec" ] ; then + openssl ecparam -name $eccname -genkey 2>/dev/null > "$f" + else + openssl genrsa $length 2>/dev/null > "$f" + fi +} + +#_createcsr cn san_list keyfile csrfile conf +_createcsr() { + _debug _createcsr + domain="$1" + domainlist="$2" + key="$3" + csr="$4" + csrconf="$5" + _debug2 domain "$domain" + _debug2 domainlist "$domainlist" + if [ -z "$domainlist" ] || [ "$domainlist" = "no" ]; then + #single domain + _info "Single domain" "$domain" + printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$csrconf" + openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr" + else + if _contains "$domainlist" "," ; then + alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" + else + alt="DNS:$domainlist" + fi + #multi + _info "Multi domain" "$alt" + printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nsubjectAltName=$alt" > "$csrconf" + openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr" + fi +} + +#_signcsr key csr conf cert +_signcsr() { + key="$1" + csr="$2" + conf="$3" + cert="$4" + + openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" + +} + _ss() { _port="$1" @@ -364,7 +454,7 @@ createAccountKey() { return else #generate account key - openssl genrsa $length 2>/dev/null > "$ACCOUNT_KEY_PATH" + _createkey $length "$ACCOUNT_KEY_PATH" fi } @@ -378,45 +468,12 @@ createDomainKey() { fi domain=$1 - length=$2 - isec="" - if _startswith "$length" "ec-" ; then - isec="1" - length=$(printf $length | cut -d '-' -f 2-100) - eccname="$length" - fi - - if [ -z "$length" ] ; then - if [ "$isec" ] ; then - length=256 - else - length=2048 - fi - fi - _info "Use length $length" - - if [ "$isec" ] ; then - if [ "$length" = "256" ] ; then - eccname="prime256v1" - fi - if [ "$length" = "384" ] ; then - eccname="secp384r1" - fi - if [ "$length" = "521" ] ; then - eccname="secp521r1" - fi - _info "Using ec name: $eccname" - fi - _initpath $domain + length=$2 + if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then - #generate account key - if [ "$isec" ] ; then - openssl ecparam -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH" - else - openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH" - fi + _createkey "$length" "$CERT_KEY_PATH" else if [ "$IS_RENEW" ] ; then _info "Domain key exists, skip" @@ -447,19 +504,8 @@ createCSR() { return fi - if [ -z "$domainlist" ] || [ "$domainlist" = "no" ]; then - #single domain - _info "Single domain" "$domain" - printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$DOMAIN_SSL_CONF" - openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" - else - alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" - #multi - _info "Multi domain" "$alt" - printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n[SAN]\nsubjectAltName=$alt" > "$DOMAIN_SSL_CONF" - openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -reqexts SAN -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" - fi - + _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" + } _urlencode() { @@ -819,11 +865,54 @@ _stopserver(){ if [ -z "$pid" ] ; then return fi - + _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 + _get "http://localhost:$Le_TLSPort" >/dev/null 2>&1 } + +# _starttlsserver san_a san_b port content +_starttlsserver() { + _info "Starting tls server." + san_a="$1" + san_b="$2" + port="$3" + content="$4" + + _debug san_a "$san_a" + _debug san_b "$san_b" + _debug port "$port" + + #create key TLS_KEY + if ! _createkey "2048" "$TLS_KEY" ; then + _err "Create tls validation key error." + return 1 + fi + + #create csr + alt="$san_a" + if [ "$san_b" ] ; then + alt="$alt,$san_b" + fi + if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" ; then + _err "Create tls validation csr error." + return 1 + fi + + #self signed + if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT" ; then + _err "Create tls validation cert error." + return 1 + fi + + #start openssl + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & + serverproc="$!" + sleep 2 + _debug serverproc $serverproc +} + _initpath() { if [ -z "$LE_WORKING_DIR" ] ; then @@ -935,6 +1024,20 @@ _initpath() { if [ -z "$CERT_PFX_PATH" ] ; then CERT_PFX_PATH="$domainhome/$domain.pfx" fi + + if [ -z "$TLS_CONF" ] ; then + TLS_CONF="$domainhome/tls.valdation.conf" + fi + if [ -z "$TLS_CERT" ] ; then + TLS_CERT="$domainhome/tls.valdation.cert" + fi + if [ -z "$TLS_KEY" ] ; then + TLS_KEY="$domainhome/tls.valdation.key" + fi + if [ -z "$TLS_CSR" ] ; then + TLS_CSR="$domainhome/tls.valdation.csr" + fi + } @@ -1073,6 +1176,12 @@ _clearup() { _stopserver $serverproc serverproc="" _restoreApache + if [ -z "$DEBUG" ] ; then + rm -f "$TLS_CONF" + rm -f "$TLS_CERT" + rm -f "$TLS_KEY" + rm -f "$TLS_CSR" + fi } # webroot removelevel tokenfile @@ -1171,6 +1280,24 @@ issue() { fi fi + if _hasfield "$Le_Webroot" "$W_TLS" ; then + _info "Standalone tls mode." + + if [ -z "$Le_TLSPort" ] ; then + Le_TLSPort=443 + else + _savedomainconf "Le_TLSPort" "$Le_TLSPort" + fi + + netprc="$(_ss "$Le_TLSPort" | grep "$Le_TLSPort")" + if [ "$netprc" ] ; then + _err "$netprc" + _err "tcp port $Le_TLSPort is already used by $(echo "$netprc" | cut -d : -f 4)" + _err "Please stop it first" + return 1 + fi + fi + if _hasfield "$Le_Webroot" "apache" ; then if ! _setApache ; then _err "set up apache error. Report error to me." @@ -1263,6 +1390,11 @@ issue() { if _startswith "$_currentRoot" "dns" ; then vtype="$VTYPE_DNS" fi + + if [ "$_currentRoot" = "$W_TLS" ] ; then + vtype="$VTYPE_TLS" + fi + _info "Getting token for domain" $d if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" ; then @@ -1406,7 +1538,7 @@ issue() { _debug "keyauthorization" "$keyauthorization" _debug "uri" "$uri" removelevel="" - token="" + token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)" _debug "_currentRoot" "$_currentRoot" @@ -1439,7 +1571,6 @@ issue() { _debug wellknown_path "$wellknown_path" - token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)" _debug "writing token:$token to $wellknown_path/$token" mkdir -p "$wellknown_path" @@ -1451,6 +1582,37 @@ issue() { fi fi + + elif [ "$vtype" = "$VTYPE_TLS" ] ; then + #create A + #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )" + #_debug2 _hash_A "$_hash_A" + #_x="$(echo $_hash_A | cut -c 1-32)" + #_debug2 _x "$_x" + #_y="$(echo $_hash_A | cut -c 33-64)" + #_debug2 _y "$_y" + #_SAN_A="$_x.$_y.token.acme.invalid" + #_debug2 _SAN_A "$_SAN_A" + + #create B + _hash_B="$(printf "%s" $keyauthorization | _digest "sha256" "hex" )" + _debug2 _hash_B "$_hash_B" + _x="$(echo $_hash_B | cut -c 1-32)" + _debug2 _x "$_x" + _y="$(echo $_hash_B | cut -c 33-64)" + _debug2 _y "$_y" + + #_SAN_B="$_x.$_y.ka.acme.invalid" + + _SAN_B="$_x.$_y.acme.invalid" + _debug2 _SAN_B "$_SAN_B" + + if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" ; then + _err "Start tls server error." + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + return 1 + fi fi if ! _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" ; then @@ -2203,6 +2365,7 @@ Parameters: --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --standalone Use standalone mode. + --tls Use standalone tls mode. --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. --dnssleep [60] The time in seconds to wait for all the txt records to take effect in dns api mode. Default 60 seconds. @@ -2227,6 +2390,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 80 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. --listraw Only used for '--list' command, list the certs in raw format. " } @@ -2277,6 +2441,7 @@ _process() { _accountkey="" _certhome="" _httpport="" + _tlsport="" _dnssleep="" _listraw="" while [ ${#} -gt 0 ] ; do @@ -2399,6 +2564,14 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; + --tls) + wvalue="$W_TLS" + if [ -z "$_webroot" ] ; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; --dns) wvalue="dns" if ! _startswith "$2" "-" ; then @@ -2490,6 +2663,12 @@ _process() { Le_HTTPPort="$_httpport" shift ;; + --tlsport ) + _tlsport="$2" + Le_TLSPort="$_tlsport" + shift + ;; + --listraw ) _listraw="raw" ;; From 63a195e5cca733db1715afb71b3e22e8c9a82694 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Jun 2016 18:09:55 +0800 Subject: [PATCH 0210/1348] minor: fix user-agent string. --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index b08f8856..55cddcf3 100755 --- a/acme.sh +++ b/acme.sh @@ -633,9 +633,9 @@ _post() { _CURL="$CURL --dump-header $HTTP_HEADER " _debug "_CURL" "$_CURL" if [ "$needbase64" ] ; then - response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" | _base64)" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" | _base64)" else - response="$($_CURL -A "User-Agent: $USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )" fi _ret="$?" else @@ -670,9 +670,9 @@ _get() { if _exists "curl" ; then _debug "CURL" "$CURL" if [ "$onlyheader" ] ; then - $CURL -I -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url + $CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url else - $CURL -A "User-Agent: $USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url + $CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url fi ret=$? else From 331c4bb669aac468dafb68216fb3c16d6674f49a Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Jun 2016 20:54:22 +0800 Subject: [PATCH 0211/1348] minor, add more debug info --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 55cddcf3..d0f1970c 100755 --- a/acme.sh +++ b/acme.sh @@ -907,7 +907,12 @@ _starttlsserver() { fi #start openssl - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port ) & + else + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & + fi + serverproc="$!" sleep 2 _debug serverproc $serverproc From fbad6a392d01f6dc5c093c31a7fd7e1fdb74f6e4 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Jun 2016 20:57:54 +0800 Subject: [PATCH 0212/1348] opps --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d0f1970c..5b1faae8 100755 --- a/acme.sh +++ b/acme.sh @@ -907,7 +907,7 @@ _starttlsserver() { fi #start openssl - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port ) & else (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & From 423966a50579942aa2f1995f0894ad32a4b6833b Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Jun 2016 21:35:34 +0800 Subject: [PATCH 0213/1348] minor, add more debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5b1faae8..e85896b7 100755 --- a/acme.sh +++ b/acme.sh @@ -908,7 +908,7 @@ _starttlsserver() { #start openssl if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port ) & + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -tlsextdebug ) & else (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & fi From cc179731135b42cad3f0d8d43e5d4f9a69ccef03 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 18 Jun 2016 11:29:28 +0800 Subject: [PATCH 0214/1348] return the error code in cron --- acme.sh | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index e85896b7..5fd8f517 100755 --- a/acme.sh +++ b/acme.sh @@ -28,6 +28,8 @@ END_CSR="-----END CERTIFICATE REQUEST-----" BEGIN_CERT="-----BEGIN CERTIFICATE-----" END_CERT="-----END CERTIFICATE-----" +RENEW_SKIP=2 + if [ -z "$AGREEMENT" ] ; then AGREEMENT="$DEFAULT_AGREEMENT" fi @@ -1207,7 +1209,7 @@ _clearupwebbroot() { _debug "remove $__webroot/.well-known/acme-challenge/$3" rm -rf "$__webroot/.well-known/acme-challenge/$3" else - _info "Skip for removelevel:$2" + _debug "Skip for removelevel:$2" fi return 0 @@ -1247,7 +1249,7 @@ issue() { _debug Le_NextRenewTime "$Le_NextRenewTime" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(date -u "+%s" ) -lt $Le_NextRenewTime ] ; then _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" - return 2 + return $RENEW_SKIP fi fi @@ -1798,7 +1800,7 @@ renew() { . "$DOMAIN_CONF" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" - return 2 + return $RENEW_SKIP fi IS_RENEW="1" @@ -1809,16 +1811,33 @@ renew() { return $res } +#renewAll [stopRenewOnError] renewAll() { _initpath + _stopRenewOnError="$1" + _debug "_stopRenewOnError" "$_stopRenewOnError" + _ret="0" for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do d=$(echo $d | cut -d '/' -f 1) ( _info "Renew: $d" renew "$d" ) + rc="$?" + _debug "Return code: $rc" + if [ "$rc" != "0" ] ; then + if [ "$rc" = "$RENEW_SKIP" ] ; then + _info "Skipped $d" + elif [ "$_stopRenewOnError" ] ; then + _err "Error renew $d, stop now." + return $rc + else + _ret="$rc" + _err "Error renew $d, Go ahead to next one." + fi + fi done - + return $_ret } @@ -2332,7 +2351,9 @@ uninstall() { cron() { IN_CRON=1 renewAll + _ret="$?" IN_CRON="" + return $_ret } version() { @@ -2397,6 +2418,7 @@ Parameters: --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. --listraw Only used for '--list' command, list the certs in raw format. + --stopRenewOnError, -se Only valid for '--renewall' command. Stop to renew all if one cert has error in renewal. " } @@ -2449,6 +2471,7 @@ _process() { _tlsport="" _dnssleep="" _listraw="" + _stopRenewOnError="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -2677,7 +2700,9 @@ _process() { --listraw ) _listraw="raw" ;; - + --stopRenewOnError|--stoprenewonerror|-se ) + _stopRenewOnError="1" + ;; *) _err "Unknown parameter : $1" return 1 @@ -2701,7 +2726,7 @@ _process() { renew "$_domain" ;; renewAll) - renewAll + renewAll "$_stopRenewOnError" ;; revoke) revoke "$_domain" From 5aa146a53fa8a204e0de7cf0909a58db6df83eca Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 18 Jun 2016 12:28:23 +0800 Subject: [PATCH 0215/1348] fix bug --- acme.sh | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index 5fd8f517..aa33b06e 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.2.7 +VER=2.2.8 PROJECT_NAME="acme.sh" @@ -375,9 +375,12 @@ _signcsr() { csr="$2" conf="$3" cert="$4" + _debug "_signcsr" - openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" - + _msg="$(openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" + _ret="$?" + _debug "$_msg" + return $_ret } _ss() { @@ -869,7 +872,7 @@ _stopserver(){ fi _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 - _get "http://localhost:$Le_TLSPort" >/dev/null 2>&1 + _get "https://localhost:$Le_TLSPort" >/dev/null 2>&1 } @@ -910,9 +913,9 @@ _starttlsserver() { #start openssl if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -tlsextdebug ) & + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -naccept 1 -tlsextdebug ) & else - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -naccept 1 >/dev/null 2>&1) & fi serverproc="$!" @@ -1791,7 +1794,7 @@ renew() { fi _initpath $Le_Domain - + _info "Renew: $Le_Domain" if [ ! -f "$DOMAIN_CONF" ] ; then _info "$Le_Domain is not a issued domain, skip." return 0; @@ -1819,8 +1822,7 @@ renewAll() { _ret="0" for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do d=$(echo $d | cut -d '/' -f 1) - ( - _info "Renew: $d" + ( renew "$d" ) rc="$?" From 8814a348a859b105f537641d3c146d5300f8e5fb Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 19 Jun 2016 14:39:24 +0800 Subject: [PATCH 0216/1348] minor, do not write the default user agent. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index aa33b06e..62e38185 100755 --- a/acme.sh +++ b/acme.sh @@ -2118,7 +2118,7 @@ _initconf() { #ACCOUNT_KEY_HASH=account key hash -USER_AGENT=\"$USER_AGENT\" +#USER_AGENT=\"$USER_AGENT\" #USER_PATH="" From 13d7cae9e22db91654af94526330d82701ecaa48 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 20 Jun 2016 18:35:40 +0800 Subject: [PATCH 0217/1348] add --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted. --- acme.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 62e38185..68ffad04 100755 --- a/acme.sh +++ b/acme.sh @@ -985,6 +985,11 @@ _initpath() { if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then CURL="$CURL --trace-ascii $dp " fi + + if [ "$Le_Insecure" ] ; then + WGET="$WGET --no-check-certificate " + CURL="$CURL --insecure " + fi _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" if [ -z "$ACCOUNT_KEY_PATH" ] ; then @@ -1765,7 +1770,11 @@ issue() { Le_RenewalDays=80 else _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" - fi + fi + + if [ "$Le_Insecure" ] ; then + _savedomainconf "Le_Insecure" "$Le_Insecure" + fi Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" @@ -2421,6 +2430,7 @@ Parameters: --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer. --listraw Only used for '--list' command, list the certs in raw format. --stopRenewOnError, -se Only valid for '--renewall' command. Stop to renew all 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. " } @@ -2474,6 +2484,7 @@ _process() { _dnssleep="" _listraw="" _stopRenewOnError="" + _insecure="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -2705,6 +2716,10 @@ _process() { --stopRenewOnError|--stoprenewonerror|-se ) _stopRenewOnError="1" ;; + --insecure) + _insecure="1" + Le_Insecure="$_insecure" + ;; *) _err "Unknown parameter : $1" return 1 From 2ce87fe264e067d12fe950d09c3bfe569a506dfc Mon Sep 17 00:00:00 2001 From: bruncsak Date: Thu, 23 Jun 2016 14:11:43 +0200 Subject: [PATCH 0218/1348] bug fix to respect the --accountkeylength flag (#219) Thanks. --- acme.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 68ffad04..6aa76118 100755 --- a/acme.sh +++ b/acme.sh @@ -2633,11 +2633,13 @@ _process() { --keylength|-k) _keylength="$2" - accountkeylength="$2" + if [ "$_accountkeylength" = "no" ] ; then + _accountkeylength="$2" + fi shift ;; --accountkeylength|-ak) - accountkeylength="$2" + _accountkeylength="$2" shift ;; From c8e9a31ee5d2ec7622f02dca75221f4d9f9445e4 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 24 Jun 2016 22:27:22 +0800 Subject: [PATCH 0219/1348] add `--nocron`, for not installing default cronjob. --- acme.sh | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/acme.sh b/acme.sh index 6aa76118..ef50f50f 100755 --- a/acme.sh +++ b/acme.sh @@ -2156,20 +2156,25 @@ _initconf() { fi } +# nocron _precheck() { + _nocron="$1" + if ! _exists "curl" && ! _exists "wget"; then _err "Please install curl or wget first, we need to access http resources." return 1 fi - if ! _exists "crontab" ; then - _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." - _err "We need to set cron job to renew the certs automatically." - _err "Otherwise, your certs will not be able to be renewed automatically." - if [ -z "$FORCE" ] ; then - _err "Please add '--force' and try install again to go without crontab." - _err "./$PROJECT_ENTRY --install --force" - return 1 + if [ -z "$_nocron" ] ; then + if ! _exists "crontab" ; then + _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." + _err "We need to set cron job to renew the certs automatically." + _err "Otherwise, your certs will not be able to be renewed automatically." + if [ -z "$FORCE" ] ; then + _err "Please add '--force' and try install again to go without crontab." + _err "./$PROJECT_ENTRY --install --force" + return 1 + fi fi fi @@ -2243,14 +2248,15 @@ _installalias() { } +# nocron install() { - + _nocron="$1" if ! _initpath ; then _err "Install failed." return 1 fi - if ! _precheck ; then + if ! _precheck "$_nocron" ; then _err "Pre-check failed, can not install." return 1 fi @@ -2313,7 +2319,9 @@ install() { _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH" fi - installcronjob + if [ -z "$_nocron" ] ; then + installcronjob + fi if [ -z "$NO_DETECT_SH" ] ; then #Modify shebang @@ -2429,8 +2437,9 @@ Parameters: --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. --listraw Only used for '--list' command, list the certs in raw format. - --stopRenewOnError, -se Only valid for '--renewall' command. Stop to renew all if one cert has error in renewal. + --stopRenewOnError, -se Only valid for '--renewall' 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. + --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. " } @@ -2485,6 +2494,7 @@ _process() { _listraw="" _stopRenewOnError="" _insecure="" + _nocron="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -2722,6 +2732,9 @@ _process() { _insecure="1" Le_Insecure="$_insecure" ;; + --nocron) + _nocron="1" + ;; *) _err "Unknown parameter : $1" return 1 @@ -2733,7 +2746,7 @@ _process() { case "${_CMD}" in - install) install ;; + install) install "$_nocron" ;; uninstall) uninstall ;; issue) issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" From 687cfcc2b143a618abc74f620a1a8a2fa4221ce8 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 25 Jun 2016 09:29:23 +0800 Subject: [PATCH 0220/1348] minor add error code --- acme.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/acme.sh b/acme.sh index ef50f50f..b22f2123 100755 --- a/acme.sh +++ b/acme.sh @@ -643,6 +643,9 @@ _post() { response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )" fi _ret="$?" + if [ "$_ret" != "0" ] ; then + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + fi else _debug "WGET" "$WGET" if [ "$needbase64" ] ; then @@ -659,6 +662,9 @@ _post() { fi fi _ret="$?" + if [ "$_ret" != "0" ] ; then + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" + fi _sed_i "s/^ *//g" "$HTTP_HEADER" fi _debug "_ret" "$_ret" From 87ab2d9085448d864a2b3827560582f69ab70322 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 25 Jun 2016 09:40:00 +0800 Subject: [PATCH 0221/1348] minor, add more debug info --- acme.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b22f2123..c2f185e8 100755 --- a/acme.sh +++ b/acme.sh @@ -644,7 +644,11 @@ _post() { fi _ret="$?" if [ "$_ret" != "0" ] ; then - _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + _err "Here is the curl dump log:" + _err "$(cat "$_CURL_DUMP")" + fi fi else _debug "WGET" "$WGET" @@ -986,10 +990,10 @@ _initpath() { WGET="$WGET -d " fi - dp="$LE_WORKING_DIR/curl.dump" + _CURL_DUMP="$LE_WORKING_DIR/curl.dump" CURL="curl -L --silent" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - CURL="$CURL --trace-ascii $dp " + CURL="$CURL --trace-ascii $_CURL_DUMP " fi if [ "$Le_Insecure" ] ; then From 523c7682fa55bab785f7b4833e2e060b17db874c Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 26 Jun 2016 10:09:51 +0800 Subject: [PATCH 0222/1348] minor: add MAX_RENEW --- acme.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index c2f185e8..b12264e0 100755 --- a/acme.sh +++ b/acme.sh @@ -20,6 +20,8 @@ VTYPE_DNS="dns-01" VTYPE_TLS="tls-sni-01" VTYPE_TLS2="tls-sni-02" +MAX_RENEW=80 + W_TLS="tls" BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" @@ -1776,8 +1778,8 @@ issue() { Le_CertCreateTimeStr=$(date -u ) _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" - if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "80" ] ; then - Le_RenewalDays=80 + if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ] ; then + Le_RenewalDays=$MAX_RENEW else _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" fi @@ -2443,7 +2445,7 @@ Parameters: --useragent Specifies the user agent string. it will be saved for future use too. --accountemail Specifies the account email for registering, Only valid for the '--install' command. --accountkey Specifies the account key path, Only valid for the '--install' command. - --days Specifies the days to renew the cert when using '--issue' command. The max value is 80 days. + --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. --listraw Only used for '--list' command, list the certs in raw format. From e4a19585735731a86de1fd0449d638f8783c5cd1 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 26 Jun 2016 11:49:41 +0800 Subject: [PATCH 0223/1348] support apache2ctl --- acme.sh | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index b12264e0..440e6b71 100755 --- a/acme.sh +++ b/acme.sh @@ -1069,18 +1069,23 @@ _initpath() { _apachePath() { + _APAHECTL="apachectl" if ! _exists apachectl ; then - _err "'apachecrl not found. It seems that apache is not installed, or you are not root user.'" - _err "Please use webroot mode to try again." - return 1 + if _exists apache2ctl ; then + _APAHECTL="apache2ctl" + else + _err "'apachecrl not found. It seems that apache is not installed, or you are not root user.'" + _err "Please use webroot mode to try again." + return 1 + fi fi - httpdconfname="$(apachectl -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" + httpdconfname="$($_APAHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" _debug httpdconfname "$httpdconfname" if _startswith "$httpdconfname" '/' ; then httpdconf="$httpdconfname" httpdconfname="$(basename $httpdconfname)" else - httpdroot="$(apachectl -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" + httpdroot="$($_APAHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" _debug httpdroot "$httpdroot" httpdconf="$httpdroot/$httpdconfname" httpdconfname="$(basename $httpdconfname)" @@ -1110,7 +1115,7 @@ _restoreApache() { cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" > "$httpdconf" _debug "Restored: $httpdconf." - if ! apachectl -t >/dev/null 2>&1 ; then + if ! $_APAHECTL -t >/dev/null 2>&1 ; then _err "Sorry, restore apache config error, please contact me." return 1; fi @@ -1127,7 +1132,7 @@ _setApache() { #test the conf first _info "Checking if there is an error in the apache config file before starting." - _msg="$(apachectl -t 2>&1 )" + _msg="$($_APAHECTL -t 2>&1 )" if [ "$?" != "0" ] ; then _err "Sorry, apache config file has error, please fix it first, then try again." _err "Don't worry, there is nothing changed to your system." @@ -1150,7 +1155,7 @@ _setApache() { #add alias - apacheVer="$(apachectl -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2 )" + apacheVer="$($_APAHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2 )" _debug "apacheVer" "$apacheVer" apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)" apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" @@ -1174,7 +1179,7 @@ Allow from all " >> "$httpdconf" fi - _msg="$(apachectl -t 2>&1 )" + _msg="$($_APAHECTL -t 2>&1 )" if [ "$?" != "0" ] ; then _err "Sorry, apache config error" if _restoreApache ; then @@ -1190,8 +1195,8 @@ Allow from all chmod 755 "$ACME_DIR" fi - if ! apachectl graceful ; then - _err "Sorry, apachectl graceful error, please contact me." + if ! $_APAHECTL graceful ; then + _err "Sorry, $_APAHECTL graceful error, please contact me." _restoreApache return 1; fi From 52677b0a885cfe271937d64259155f0a6a74d357 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 26 Jun 2016 13:30:47 +0800 Subject: [PATCH 0224/1348] 2.2.9 support --upgrade --- acme.sh | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 440e6b71..b712a145 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.2.8 +VER=2.2.9 PROJECT_NAME="acme.sh" @@ -2272,7 +2272,10 @@ install() { _err "Install failed." return 1 fi - + if [ "$_nocron" ] ; then + _debug "Skip install cron job" + fi + if ! _precheck "$_nocron" ; then _err "Pre-check failed, can not install." return 1 @@ -2357,8 +2360,12 @@ install() { _info OK } +# nocron uninstall() { - uninstallcronjob + _nocron="$1" + if [ -z "$_nocron" ] ; then + uninstallcronjob + fi _initpath _profile="$(_detect_profile)" @@ -2405,6 +2412,7 @@ Commands: --version, -v Show version info. --install Install $PROJECT_NAME to your system. --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job. + --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT --issue Issue a cert. --installcert Install the issued cert to apache/nginx or any other server. --renew, -r Renew a cert. @@ -2460,8 +2468,10 @@ Parameters: " } +# nocron _installOnline() { _info "Installing from online archive." + _nocron="$1" if [ ! "$BRANCH" ] ; then BRANCH="master" fi @@ -2477,7 +2487,7 @@ _installOnline() { tar xzf $localname cd "$PROJECT_NAME-$BRANCH" chmod +x $PROJECT_ENTRY - if ./$PROJECT_ENTRY install ; then + if ./$PROJECT_ENTRY install "$_nocron" ; then _info "Install success!" fi @@ -2486,6 +2496,16 @@ _installOnline() { rm -f "$localname" } +upgrade() { + if ( + cd $LE_WORKING_DIR + _installOnline "nocron" + ) ; then + _info "Upgrade success!" + else + _err "Upgrade failed!" + fi +} _process() { _CMD="" @@ -2529,6 +2549,9 @@ _process() { --uninstall) _CMD="uninstall" ;; + --upgrade) + _CMD="upgrade" + ;; --issue) _CMD="issue" ;; @@ -2765,6 +2788,7 @@ _process() { case "${_CMD}" in install) install "$_nocron" ;; uninstall) uninstall ;; + upgrade) upgrade ;; issue) issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" ;; From bc96082fa9b0fe4b5e9952de9e4c3dcd268f95f2 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 27 Jun 2016 10:32:51 +0800 Subject: [PATCH 0225/1348] typos --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b712a145..c75812c2 100755 --- a/acme.sh +++ b/acme.sh @@ -1074,7 +1074,7 @@ _apachePath() { if _exists apache2ctl ; then _APAHECTL="apache2ctl" else - _err "'apachecrl not found. It seems that apache is not installed, or you are not root user.'" + _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'" _err "Please use webroot mode to try again." return 1 fi @@ -2464,7 +2464,7 @@ Parameters: --listraw Only used for '--list' command, list the certs in raw format. --stopRenewOnError, -se Only valid for '--renewall' 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. - --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. " } @@ -2787,7 +2787,7 @@ _process() { case "${_CMD}" in install) install "$_nocron" ;; - uninstall) uninstall ;; + uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" From 61623d22d81f6671c5820685069497a443a64152 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Jul 2016 13:03:59 +0800 Subject: [PATCH 0226/1348] fix bug: re-generate domain key if the key length is different. --- acme.sh | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index c75812c2..5c5886a9 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.2.9 +VER=2.3.0 PROJECT_NAME="acme.sh" @@ -829,6 +829,19 @@ _cleardomainconf() { fi } +#_readdomainconf key +_readdomainconf() { + key="$1" + if [ "$DOMAIN_CONF" ] ; then + ( + eval $(grep "^$key *=" "$DOMAIN_CONF") + eval "printf \"%s\" \"\$$key\"" + ) + else + _err "DOMAIN_CONF is empty, can not read $key" + fi +} + #_saveaccountconf key value _saveaccountconf() { key="$1" @@ -1270,7 +1283,7 @@ issue() { _initpath $Le_Domain if [ -f "$DOMAIN_CONF" ] ; then - Le_NextRenewTime=$(grep "^Le_NextRenewTime=" "$DOMAIN_CONF" | cut -d '=' -f 2 | tr -d "'\"") + Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(date -u "+%s" ) -lt $Le_NextRenewTime ] ; then _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" @@ -1281,15 +1294,12 @@ issue() { _savedomainconf "Le_Domain" "$Le_Domain" _savedomainconf "Le_Alt" "$Le_Alt" _savedomainconf "Le_Webroot" "$Le_Webroot" - _savedomainconf "Le_Keylength" "$Le_Keylength" + if [ "$Le_Alt" = "no" ] ; then Le_Alt="" fi - if [ "$Le_Keylength" = "no" ] ; then - Le_Keylength="" - fi - + if _hasfield "$Le_Webroot" "no" ; then _info "Standalone mode." if ! _exists "nc" ; then @@ -1385,7 +1395,9 @@ issue() { _info "Skip register account key" fi - if [ ! -f "$CERT_KEY_PATH" ] ; then + _key=$(_readdomainconf Le_Keylength) + _debug "Read key length:$_key" + if [ "$Le_Keylength" != "$_key" ] ; then if ! createDomainKey $Le_Domain $Le_Keylength ; then _err "Create domain key error." _clearup @@ -1393,6 +1405,11 @@ issue() { fi fi + _savedomainconf "Le_Keylength" "$Le_Keylength" + if [ "$Le_Keylength" = "no" ] ; then + Le_Keylength="" + fi + if ! createCSR $Le_Domain $Le_Alt ; then _err "Create CSR error." _clearup From d8d10bc4786bfd3769f15cbc533f9c4e5276e4e8 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Jul 2016 13:13:41 +0800 Subject: [PATCH 0227/1348] opps --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5c5886a9..70bf2d89 100755 --- a/acme.sh +++ b/acme.sh @@ -1397,7 +1397,7 @@ issue() { _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" - if [ "$Le_Keylength" != "$_key" ] ; then + if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ] ; then if ! createDomainKey $Le_Domain $Le_Keylength ; then _err "Create domain key error." _clearup From 58f41a194ae9196ec0c82f3cb1ca78ac5b226608 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Jul 2016 13:21:22 +0800 Subject: [PATCH 0228/1348] minor --- acme.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 70bf2d89..24f7c884 100755 --- a/acme.sh +++ b/acme.sh @@ -1395,6 +1395,10 @@ issue() { _info "Skip register account key" fi + if [ "$Le_Keylength" = "no" ] ; then + Le_Keylength="" + fi + _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ] ; then @@ -1406,9 +1410,7 @@ issue() { fi _savedomainconf "Le_Keylength" "$Le_Keylength" - if [ "$Le_Keylength" = "no" ] ; then - Le_Keylength="" - fi + if ! createCSR $Le_Domain $Le_Alt ; then _err "Create CSR error." From d0b748a4f285a9bc5d9fc03fa9b1d2d165a5aeac Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Jul 2016 13:46:35 +0800 Subject: [PATCH 0229/1348] add more debug message. --- acme.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 24f7c884..f520f02c 100755 --- a/acme.sh +++ b/acme.sh @@ -652,7 +652,7 @@ _post() { _err "$(cat "$_CURL_DUMP")" fi fi - else + elif _exists "wget" ; then _debug "WGET" "$WGET" if [ "$needbase64" ] ; then if [ "$httpmethod"="POST" ] ; then @@ -672,6 +672,9 @@ _post() { _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" fi _sed_i "s/^ *//g" "$HTTP_HEADER" + else + _ret="$?" + _err "Neither curl nor wget is found, can not do $httpmethod." fi _debug "_ret" "$_ret" printf "%s" "$response" @@ -692,7 +695,7 @@ _get() { $CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url fi ret=$? - else + elif _exists "wget" ; then _debug "WGET" "$WGET" if [ "$onlyheader" ] ; then $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' @@ -700,6 +703,9 @@ _get() { $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url fi ret=$? + else + ret=$? + _err "Neither curl nor wget is found, can not do GET." fi _debug "ret" "$ret" return $ret @@ -2517,7 +2523,7 @@ _installOnline() { upgrade() { if ( - cd $LE_WORKING_DIR + cd "$LE_WORKING_DIR" _installOnline "nocron" ) ; then _info "Upgrade success!" From 0bbe6eef89e3f36e824b31b68f040b36b075c2eb Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 3 Jul 2016 12:46:18 +0800 Subject: [PATCH 0230/1348] minor --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index f520f02c..90baf766 100755 --- a/acme.sh +++ b/acme.sh @@ -2508,8 +2508,10 @@ _installOnline() { _debug "Download error." return 1 fi + ( _info "Extracting $localname" tar xzf $localname + cd "$PROJECT_NAME-$BRANCH" chmod +x $PROJECT_ENTRY if ./$PROJECT_ENTRY install "$_nocron" ; then @@ -2517,8 +2519,10 @@ _installOnline() { fi cd .. + rm -rf "$PROJECT_NAME-$BRANCH" rm -f "$localname" + ) } upgrade() { From 096d8992a1b96f140df7a0cdd12b11a377a6b7fb Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 4 Jul 2016 20:40:29 +0800 Subject: [PATCH 0231/1348] fix upgrade issue --- acme.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acme.sh b/acme.sh index 90baf766..5b75d153 100755 --- a/acme.sh +++ b/acme.sh @@ -2531,8 +2531,10 @@ upgrade() { _installOnline "nocron" ) ; then _info "Upgrade success!" + exit 0 else _err "Upgrade failed!" + exit 1 fi } From 3e99ffe692f7aac12103b9f3488007b987dc1875 Mon Sep 17 00:00:00 2001 From: Trevor Goodyear Date: Mon, 4 Jul 2016 13:00:17 -0400 Subject: [PATCH 0232/1348] Update README.md to fix typo: scrypt -> script --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 01d8314c..ec8ce6d6 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -72,7 +72,7 @@ If your api is not supported yet, you can write your own dns api. Let's assume you want to name it 'myapi', 1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, -2. In the scrypt, you must have a function named `dns_myapi_add()`. Which will be called by acme.sh to add dns records. +2. In the script, you must have a function named `dns_myapi_add()`. Which will be called by acme.sh to add dns records. 3. Then you can use your api to issue cert like: ``` From 4c0d3f1b75887f4fb3671907b185b4781378d2eb Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 8 Jul 2016 11:50:47 +0800 Subject: [PATCH 0233/1348] minor. remove the ugly return code for installcert. --- acme.sh | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 5b75d153..ee4ee77c 100755 --- a/acme.sh +++ b/acme.sh @@ -1825,16 +1825,10 @@ issue() { _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" - _output="$(installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" 2>&1)" - _ret="$?" - if [ "$_ret" = "9" ] ; then - #ignore the empty install error. - return 0 - fi - if [ "$_ret" != "0" ] ; then - _err "$_output" - return 1 + if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ] ; then + installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" fi + } renew() { @@ -2010,7 +2004,7 @@ installcert() { if [ "$_installed" = "0" ] ; then _err "Nothing to install. You don't specify any parameter." - return 9 + return 1 fi } From b3752e78b6e9e7e04082632e3edbbe427f190c15 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 8 Jul 2016 12:29:47 +0800 Subject: [PATCH 0234/1348] minor, remove error message. --- acme.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/acme.sh b/acme.sh index ee4ee77c..2221cd7c 100755 --- a/acme.sh +++ b/acme.sh @@ -2002,10 +2002,6 @@ installcert() { fi fi - if [ "$_installed" = "0" ] ; then - _err "Nothing to install. You don't specify any parameter." - return 1 - fi } From 32dfc387c888ae9173302c868b07572a124a8706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Fri, 8 Jul 2016 15:42:21 +0200 Subject: [PATCH 0235/1348] Add missing escape in regular expression. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a missing escape of a { character in one of the regular expressions passed to grep. This adds that. Signed-off-by: Toke Høiland-Jørgensen --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5b75d153..47663329 100755 --- a/acme.sh +++ b/acme.sh @@ -1725,7 +1725,7 @@ issue() { fi if [ "$status" = "invalid" ] ; then - error="$(echo $response | tr -d "\r\n" | egrep -o '"error":{[^}]*}')" + error="$(echo $response | tr -d "\r\n" | egrep -o '"error":\{[^}]*}')" _debug2 error "$error" errordetail="$(echo $error | grep -o '"detail": *"[^"]*"' | cut -d '"' -f 4)" _debug2 errordetail "$errordetail" From 7270f277a73d4d1c5a2e985a1bebcf4f808c13bc Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 9 Jul 2016 15:55:36 +0800 Subject: [PATCH 0236/1348] minor: less debug message --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 2221cd7c..fa8a45ec 100755 --- a/acme.sh +++ b/acme.sh @@ -163,8 +163,8 @@ _h2b() { if _exists let ; then uselet="1" fi - _debug uselet "$uselet" - _debug _URGLY_PRINTF "$_URGLY_PRINTF" + _debug2 uselet "$uselet" + _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" while true ; do if [ -z "$_URGLY_PRINTF" ] ; then h="$(printf $hex | cut -c $i-$j)" From bdbf323feee2a510fc6701e6b290e54882ed8fd4 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 9 Jul 2016 17:25:27 +0800 Subject: [PATCH 0237/1348] remove the default value 'no' --- acme.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index fa8a45ec..a81bdfa7 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.3.0 +VER=2.3.1 PROJECT_NAME="acme.sh" @@ -943,6 +943,7 @@ _starttlsserver() { fi #start openssl + _debug "openssl s_server -cert \"$TLS_CERT\" -key \"$TLS_KEY\" -accept $port -naccept 1 -tlsextdebug" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -naccept 1 -tlsextdebug ) & else @@ -2533,12 +2534,12 @@ _process() { _domain="" _altdomains="no" _webroot="" - _keylength="no" - _accountkeylength="no" - _certpath="no" - _keypath="no" - _capath="no" - _fullchainpath="no" + _keylength="" + _accountkeylength="" + _certpath="" + _keypath="" + _capath="" + _fullchainpath="" _reloadcmd="" _password="" _accountconf="" From dcf9cb581defd0381ec29e93b45e7ebb2eaba753 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 15 Jul 2016 16:40:03 +0800 Subject: [PATCH 0238/1348] minor, add more debug info --- acme.sh | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 414941e4..f3e5c234 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.3.1 +VER=2.3.2 PROJECT_NAME="acme.sh" @@ -902,9 +902,23 @@ _stopserver(){ return fi - _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 - _get "https://localhost:$Le_TLSPort" >/dev/null 2>&1 - + _debug2 "Le_HTTPPort" "$Le_HTTPPort" + if [ "$Le_HTTPPort" ] ; then + if [ "$DEBUG" ] ; then + _get "http://localhost:$Le_HTTPPort" + else + _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 + fi + fi + + _debug2 "Le_TLSPort" "$Le_TLSPort" + if [ "$Le_TLSPort" ] ; then + if [ "$DEBUG" ] ; then + _get "https://localhost:$Le_TLSPort" + else + _get "https://localhost:$Le_TLSPort" >/dev/null 2>&1 + fi + fi } @@ -1244,19 +1258,25 @@ _clearupwebbroot() { return 0 fi + _rmpath="" if [ "$2" = '1' ] ; then - _debug "remove $__webroot/.well-known" - rm -rf "$__webroot/.well-known" + _rmpath="$__webroot/.well-known" elif [ "$2" = '2' ] ; then - _debug "remove $__webroot/.well-known/acme-challenge" - rm -rf "$__webroot/.well-known/acme-challenge" + _rmpath="$__webroot/.well-known/acme-challenge" elif [ "$2" = '3' ] ; then - _debug "remove $__webroot/.well-known/acme-challenge/$3" - rm -rf "$__webroot/.well-known/acme-challenge/$3" + _rmpath="$__webroot/.well-known/acme-challenge/$3" else _debug "Skip for removelevel:$2" fi + if [ "$_rmpath" ] ; then + if [ "$DEBUG" ] ; then + _debug "Debugging, skip removing: $_rmpath" + else + rm -rf "$_rmpath" + fi + fi + return 0 } @@ -1735,6 +1755,11 @@ issue() { else _err "$d:Verify error:$error" fi + if [ "$DEBUG" ] ; then + if [ "$vtype" = "$VTYPE_HTTP" ] ; then + _get "http://$d/.well-known/acme-challenge/$token" + fi + fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup return 1; @@ -2806,6 +2831,9 @@ _process() { shift 1 done + if [ "$DEBUG" ] ; then + version + fi case "${_CMD}" in install) install "$_nocron" ;; From 4a4dacb52cc014776bf6d00419926076b448f72f Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 15 Jul 2016 22:56:16 +0800 Subject: [PATCH 0239/1348] minor, change default dns sleep time from 60 seconds to 120 seconds. --- acme.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index f3e5c234..b0cf57e4 100755 --- a/acme.sh +++ b/acme.sh @@ -22,6 +22,8 @@ VTYPE_TLS2="tls-sni-02" MAX_RENEW=80 +DEFAULT_DNS_SLEEP=120 + W_TLS="tls" BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" @@ -1592,7 +1594,7 @@ issue() { if [ "$dnsadded" = '1' ] ; then if [ -z "$Le_DNSSleep" ] ; then - Le_DNSSleep=60 + Le_DNSSleep=$DEFAULT_DNS_SLEEP else _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" fi @@ -2479,7 +2481,7 @@ Parameters: --tls Use standalone tls mode. --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. - --dnssleep [60] The time in seconds to wait for all the txt records to take effect in dns api mode. Default 60 seconds. + --dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds. --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. From fa989a554d6d932f8b85f673fa6345b97f803979 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 16 Jul 2016 21:57:29 +0800 Subject: [PATCH 0240/1348] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0f9e6841..9492cc35 100644 --- a/README.md +++ b/README.md @@ -302,4 +302,6 @@ Please Star and Fork me. [Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcomed. +# Donate +1. PayPal: donate@acme.sh From c3dd3ef0d7cd7108d95fa97fb0b8639207982e82 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 20 Jul 2016 22:18:07 +0800 Subject: [PATCH 0241/1348] typos --- acme.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index b0cf57e4..2e7f9983 100755 --- a/acme.sh +++ b/acme.sh @@ -1105,23 +1105,23 @@ _initpath() { _apachePath() { - _APAHECTL="apachectl" + _APACHECTL="apachectl" if ! _exists apachectl ; then if _exists apache2ctl ; then - _APAHECTL="apache2ctl" + _APACHECTL="apache2ctl" else _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'" _err "Please use webroot mode to try again." return 1 fi fi - httpdconfname="$($_APAHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" + httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" _debug httpdconfname "$httpdconfname" if _startswith "$httpdconfname" '/' ; then httpdconf="$httpdconfname" httpdconfname="$(basename $httpdconfname)" else - httpdroot="$($_APAHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" + httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" _debug httpdroot "$httpdroot" httpdconf="$httpdroot/$httpdconfname" httpdconfname="$(basename $httpdconfname)" @@ -1151,7 +1151,7 @@ _restoreApache() { cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" > "$httpdconf" _debug "Restored: $httpdconf." - if ! $_APAHECTL -t >/dev/null 2>&1 ; then + if ! $_APACHECTL -t >/dev/null 2>&1 ; then _err "Sorry, restore apache config error, please contact me." return 1; fi @@ -1168,7 +1168,7 @@ _setApache() { #test the conf first _info "Checking if there is an error in the apache config file before starting." - _msg="$($_APAHECTL -t 2>&1 )" + _msg="$($_APACHECTL -t 2>&1 )" if [ "$?" != "0" ] ; then _err "Sorry, apache config file has error, please fix it first, then try again." _err "Don't worry, there is nothing changed to your system." @@ -1191,7 +1191,7 @@ _setApache() { #add alias - apacheVer="$($_APAHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2 )" + apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2 )" _debug "apacheVer" "$apacheVer" apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)" apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" @@ -1215,7 +1215,7 @@ Allow from all " >> "$httpdconf" fi - _msg="$($_APAHECTL -t 2>&1 )" + _msg="$($_APACHECTL -t 2>&1 )" if [ "$?" != "0" ] ; then _err "Sorry, apache config error" if _restoreApache ; then @@ -1231,8 +1231,8 @@ Allow from all chmod 755 "$ACME_DIR" fi - if ! $_APAHECTL graceful ; then - _err "Sorry, $_APAHECTL graceful error, please contact me." + if ! $_APACHECTL graceful ; then + _err "Sorry, $_APACHECTL graceful error, please contact me." _restoreApache return 1; fi From c9c31c04c3cfea37153a097bc99d6145a4557078 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 21 Jul 2016 10:48:37 +0800 Subject: [PATCH 0242/1348] typos --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 2e7f9983..2c6e480a 100755 --- a/acme.sh +++ b/acme.sh @@ -2111,7 +2111,7 @@ revoke() { return 0 else _err "Revoke error by domain key." - _err "$resource" + _err "$response" fi fi @@ -2124,7 +2124,7 @@ revoke() { return 0 else _err "Revoke error." - _debug "$resource" + _debug "$response" fi fi return 1 From 32fdc196977662704eba6197c5f14dde32990180 Mon Sep 17 00:00:00 2001 From: Tim O'Brien Date: Fri, 22 Jul 2016 14:17:33 -0700 Subject: [PATCH 0243/1348] Support for shells without 'stat' (busybox ash) - the _stat command can now return an error - the issue() command chown command isn't run if _stat fails --- acme.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 2c6e480a..bcd0e78f 100755 --- a/acme.sh +++ b/acme.sh @@ -549,6 +549,7 @@ _stat() { if stat -f '%Su:%Sg' "$1" 2>/dev/null ; then return fi + return 3; #error, 'stat' not found } #keyfile @@ -1656,9 +1657,12 @@ issue() { mkdir -p "$wellknown_path" printf "%s" "$keyauthorization" > "$wellknown_path/$token" if [ ! "$usingApache" ] ; then - webroot_owner=$(_stat $_currentRoot) - _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R $webroot_owner "$_currentRoot/.well-known" + if webroot_owner=$(_stat $_currentRoot) ; then + _debug "Changing owner/group of .well-known to $webroot_owner" + chown -R $webroot_owner "$_currentRoot/.well-known" + else + _debug "not chaning owner/group of webroot"; + fi fi fi From 3ad08e951521e78819d21e43288428fc4708de4f Mon Sep 17 00:00:00 2001 From: Tim O'Brien Date: Mon, 25 Jul 2016 11:07:34 -0700 Subject: [PATCH 0244/1348] Changed _stat exit code, added line return, added README link to wiki --- README.md | 1 + acme.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9492cc35..200b5f0a 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |14|-----| Cloud Linux https://github.com/Neilpang/le/issues/111 |15|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD |16|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia +|17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): diff --git a/acme.sh b/acme.sh index bcd0e78f..1149aef6 100755 --- a/acme.sh +++ b/acme.sh @@ -549,7 +549,8 @@ _stat() { if stat -f '%Su:%Sg' "$1" 2>/dev/null ; then return fi - return 3; #error, 'stat' not found + + return 1; #error, 'stat' not found } #keyfile From 30de13b4df55837231253ba55120e80af8a3f87f Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 29 Jul 2016 18:07:16 +0800 Subject: [PATCH 0245/1348] support Godaddy domaain api --- README.md | 5 +- acme.sh | 9 +++- dnsapi/README.md | 26 +++++++++++ dnsapi/dns_gd.sh | 118 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 dnsapi/dns_gd.sh diff --git a/README.md b/README.md index 200b5f0a..a074c18d 100644 --- a/README.md +++ b/README.md @@ -243,8 +243,9 @@ You don't have do anything manually! 1. Cloudflare.com API 2. Dnspod.cn API 3. Cloudxns.com API -4. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 -5. lexicon dns api: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api +4. Godaddy.com API +5. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 +6. 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.) ##### More APIs are coming soon... diff --git a/acme.sh b/acme.sh index 1149aef6..a2cfd9f7 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.3.2 +VER=2.3.3 PROJECT_NAME="acme.sh" @@ -640,6 +640,7 @@ _post() { fi _debug $httpmethod _debug "url" "$url" + _debug2 "body" "$body" if _exists "curl" ; then _CURL="$CURL --dump-header $HTTP_HEADER " _debug "_CURL" "$_CURL" @@ -2217,6 +2218,12 @@ _initconf() { # #CX_Secret=\"sADDsdasdgdsf\" +####################### +#Godaddy.com: +#GD_Key=\"sdfdsgdgdfdasfds\" +# +#GD_Secret=\"sADDsdasdfsdfdssdgdsf\" + " > $ACCOUNT_CONF_PATH fi } diff --git a/dnsapi/README.md b/dnsapi/README.md index ec8ce6d6..3098e03f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -64,6 +64,32 @@ acme.sh --issue --dns dns_cx -d aa.com -d www.aa.com The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. +## Use Godaddy.com domain api to automatically issue cert + +We support Godaddy integeration. + +First you need to login to your Godaddy account to get your api key and api secret. + +https://developer.godaddy.com/keys/ + +Please Create a Production key, instead of a Test key. + + +``` +export GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" + +export GD_Secret="asdfsdafdsfdsfdsfdsfdsafd" + +``` + +Ok, let's issue cert now: +``` +acme.sh --issue --dns dns_gd -d aa.com -d www.aa.com +``` + +The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. + + # Use custom api diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh new file mode 100644 index 00000000..01a2c3d6 --- /dev/null +++ b/dnsapi/dns_gd.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env sh + +#Godaddy domain api +# +#GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#GD_Secret="asdfsdfsfsdfsdfdfsdf" + + +GD_Api="https://api.godaddy.com/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gd_add(){ + fulldomain=$1 + txtvalue=$2 + + if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ] ; then + _err "You don't specify godaddy api key and secret yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf GD_Key "$GD_Key" + _saveaccountconf GD_Secret "$GD_Secret" + + _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" + + + _info "Adding record" + if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then + if [ "$response" == "{}" ] ; then + _info "Added, sleeping 10 seconds" + sleep 10 + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + _err "$response" + return 1 + fi + fi + _err "Add txt record error." + +} + + + + + +#################### Private functions bellow ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while [ '1' ] ; do + h=$(printf $domain | cut -d . -f $i-100) + if [ -z "$h" ] ; then + #not valid + return 1; + fi + + if ! _gd_rest GET "domains/$h" ; then + return 1 + fi + + if printf "$response" | grep '"code":"NOT_FOUND"' >/dev/null ; then + _debug "$h not found" + else + _sub_domain=$(printf $domain | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(expr $i + 1) + done + return 1 +} + +_gd_rest() { + m=$1 + ep="$2" + data="$3" + _debug $ep + + _H1="Authorization: sso-key $GD_Key:$GD_Secret" + _H2="Content-Type: application/json" + + if [ "$data" ] ; then + _debug data "$data" + response="$(_post "$data" "$GD_Api/$ep" "" $m)" + else + response="$(_get "$GD_Api/$ep")" + fi + + if [ "$?" != "0" ] ; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + + From 0886e67df76042459e08ca18a0e2ae68c3b77680 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 1 Aug 2016 17:08:01 +0800 Subject: [PATCH 0246/1348] chmod +x --- dnsapi/dns_gd.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 dnsapi/dns_gd.sh diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh old mode 100644 new mode 100755 From c93ec9331b43f8c136222acb644293273351afdc Mon Sep 17 00:00:00 2001 From: Acris Liu Date: Tue, 2 Aug 2016 01:21:00 +0800 Subject: [PATCH 0247/1348] Update agreement to LE-SA-v1.1.1-August-1-2016.pdf --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a2cfd9f7..87c55396 100755 --- a/acme.sh +++ b/acme.sh @@ -9,7 +9,7 @@ PROJECT_ENTRY="acme.sh" PROJECT="https://github.com/Neilpang/$PROJECT_NAME" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" -DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" +DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" DEFAULT_USER_AGENT="$PROJECT_ENTRY client: $PROJECT" From 30684246d2334dccc414c15d5a702793233c1f1a Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 2 Aug 2016 10:04:29 +0800 Subject: [PATCH 0248/1348] new version number 2.3.4 for LE-SA-v1.1.1-August-1-2016.pdf agreement to LE-SA-v1.1.1-August-1-2016.pdf --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 87c55396..5e9e38c2 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.3.3 +VER=2.3.4 PROJECT_NAME="acme.sh" From f574e5813f3e2996dd9532910da0f12106b2b3d4 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 2 Aug 2016 10:56:40 +0800 Subject: [PATCH 0249/1348] add the new reg hash --- acme.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index 5e9e38c2..c0cdbd54 100755 --- a/acme.sh +++ b/acme.sh @@ -1401,19 +1401,19 @@ issue() { accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) thumbprint=$(echo -n "$accountkey_json" | _digest "sha256" | _urlencode) + regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' + if [ "$ACCOUNT_EMAIL" ] ; then + regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' + fi + accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | _digest "sha256" )" - accountkeyhash="$(echo $accountkeyhash$API | _digest "sha256" )" + accountkeyhash="$(echo $accountkeyhash$API$regjson | _digest "sha256" )" if [ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ] ; then - _info "Registering account" - regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ] ; then - regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' - fi - _send_signed_request "$API/acme/new-reg" "$regjson" - + _info "Registering account" + _send_signed_request "$API/acme/new-reg" "$regjson" if [ "$code" = "" ] || [ "$code" = '201' ] ; then _info "Registered" - echo $response > $LE_WORKING_DIR/account.json + echo "$response" > $LE_WORKING_DIR/account.json elif [ "$code" = '409' ] ; then _info "Already registered" else From 1e6b68f5d187fa3d64c889d04a77ee1c79726282 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 2 Aug 2016 21:47:35 +0800 Subject: [PATCH 0250/1348] fix https://github.com/Neilpang/acme.sh/issues/244 Update renew days for renew/renewall --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index c0cdbd54..7a9cd91c 100755 --- a/acme.sh +++ b/acme.sh @@ -1879,6 +1879,10 @@ renew() { return 0; fi + if [ "$Le_RenewalDays" ] ; then + _savedomainconf Le_RenewalDays "$Le_RenewalDays" + fi + . "$DOMAIN_CONF" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" From fe09757cb31cf32818c9c001a389798231b8bd77 Mon Sep 17 00:00:00 2001 From: Jim Ma Date: Fri, 5 Aug 2016 21:31:12 +0800 Subject: [PATCH 0251/1348] dns_cx.sh prefix and suffix domain bug fixed --- dnsapi/dns_cx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 33e05e4b..b0cf36d0 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -145,7 +145,7 @@ _get_root() { fi if printf "$response" | grep "$h." >/dev/null ; then - seg=$(printf "$response" | grep -o "{[^{]*$h\.[^}]*\}" ) + seg=$(printf "$response" | grep -o "{[^{]*\"$h\.\"[^}]*\}" ) _debug seg "$seg" _domain_id=$(printf "$seg" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" From ec603beeb0fdf68a1b07035b41d84a5f288aa7f7 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 7 Aug 2016 10:21:27 +0800 Subject: [PATCH 0252/1348] skip verify (#256) skip domain verify if the authorization is already valid --- acme.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/acme.sh b/acme.sh index 7a9cd91c..db66fd46 100755 --- a/acme.sh +++ b/acme.sh @@ -26,6 +26,8 @@ DEFAULT_DNS_SLEEP=120 W_TLS="tls" +STATE_VERIFIED="verified_ok" + BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" END_CSR="-----END CERTIFICATE REQUEST-----" @@ -1508,6 +1510,14 @@ issue() { keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" + if [ "$STAGE" ] ; then + if printf "$response" | grep '"status":"valid"' >/dev/null 2>&1 ; then + _info "$d is already verified, skip." + keyauthorization=$STATE_VERIFIED + _debug keyauthorization "$keyauthorization" + fi + fi + dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" _debug dvlist "$dvlist" @@ -1524,6 +1534,12 @@ issue() { keyauthorization=$(echo $ventry | cut -d $sep -f 2) vtype=$(echo $ventry | cut -d $sep -f 4) _currentRoot=$(echo $ventry | cut -d $sep -f 5) + + if [ "$keyauthorization" == "$STATE_VERIFIED" ] ; then + _info "$d is already verified, skip $vtype." + continue + fi + if [ "$vtype" = "$VTYPE_DNS" ] ; then dnsadded='0' txtdomain="_acme-challenge.$d" @@ -1616,6 +1632,12 @@ issue() { uri=$(echo $ventry | cut -d $sep -f 3) vtype=$(echo $ventry | cut -d $sep -f 4) _currentRoot=$(echo $ventry | cut -d $sep -f 5) + + if [ "$keyauthorization" == "$STATE_VERIFIED" ] ; then + _info "$d is already verified, skip $vtype." + continue + fi + _info "Verifying:$d" _debug "d" "$d" _debug "keyauthorization" "$keyauthorization" From d35bf517800c3fbf08e400118c8750645f420ec5 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 7 Aug 2016 10:23:52 +0800 Subject: [PATCH 0253/1348] 2.3.5: skip domain verify if the authorization is already valid, add to production server. --- acme.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index db66fd46..228237ca 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.3.4 +VER=2.3.5 PROJECT_NAME="acme.sh" @@ -1510,14 +1510,14 @@ issue() { keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" - if [ "$STAGE" ] ; then - if printf "$response" | grep '"status":"valid"' >/dev/null 2>&1 ; then - _info "$d is already verified, skip." - keyauthorization=$STATE_VERIFIED - _debug keyauthorization "$keyauthorization" - fi + + if printf "$response" | grep '"status":"valid"' >/dev/null 2>&1 ; then + _info "$d is already verified, skip." + keyauthorization=$STATE_VERIFIED + _debug keyauthorization "$keyauthorization" fi + dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" _debug dvlist "$dvlist" From 75da0713d26c5f7402cb719d195a729f71f37d75 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 7 Aug 2016 14:25:55 +0800 Subject: [PATCH 0254/1348] tls mode: -naccept is not supported by many old openssl versions. (#257) So I remove it. and use 2 GET requests to make openssl sever exit. --- acme.sh | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index 228237ca..a10f7ef6 100755 --- a/acme.sh +++ b/acme.sh @@ -688,26 +688,36 @@ _post() { return $_ret } -# url getheader +# url getheader timeout _get() { _debug GET url="$1" onlyheader="$2" + t="$3" _debug url $url + _debug "timeout" "$t" if _exists "curl" ; then - _debug "CURL" "$CURL" + _CURL="$CURL" + if [ "$t" ] ; then + _CURL="$_CURL --connect-timeout $t" + fi + _debug "_CURL" "$_CURL" if [ "$onlyheader" ] ; then - $CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url + $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url else - $CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url + $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url fi ret=$? elif _exists "wget" ; then - _debug "WGET" "$WGET" + _WGET="$WGET" + if [ "$t" ] ; then + _WGET="$_WGET --timeout=$t" + fi + _debug "_WGET" "$_WGET" if [ "$onlyheader" ] ; then - $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' + $_WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else - $WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url + $_WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url fi ret=$? else @@ -921,9 +931,11 @@ _stopserver(){ _debug2 "Le_TLSPort" "$Le_TLSPort" if [ "$Le_TLSPort" ] ; then if [ "$DEBUG" ] ; then - _get "https://localhost:$Le_TLSPort" + _get "https://localhost:$Le_TLSPort" "" 1 + _get "https://localhost:$Le_TLSPort" "" 1 else - _get "https://localhost:$Le_TLSPort" >/dev/null 2>&1 + _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1 + _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1 fi fi } @@ -966,9 +978,9 @@ _starttlsserver() { #start openssl _debug "openssl s_server -cert \"$TLS_CERT\" -key \"$TLS_KEY\" -accept $port -naccept 1 -tlsextdebug" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -naccept 1 -tlsextdebug ) & + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -tlsextdebug ) & else - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -naccept 1 >/dev/null 2>&1) & + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & fi serverproc="$!" From 08928b486bbaad0abad250f9f98541cda13b630e Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 7 Aug 2016 14:47:57 +0800 Subject: [PATCH 0255/1348] minor: add version to useragent --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a10f7ef6..64a0e94b 100755 --- a/acme.sh +++ b/acme.sh @@ -11,7 +11,7 @@ PROJECT="https://github.com/Neilpang/$PROJECT_NAME" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" -DEFAULT_USER_AGENT="$PROJECT_ENTRY client: $PROJECT" +DEFAULT_USER_AGENT="$PROJECT_ENTRY client v$VER : $PROJECT" STAGE_CA="https://acme-staging.api.letsencrypt.org" From bd5e57d8798872e6a3dba813665b85b11cd0b856 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 8 Aug 2016 10:17:10 +0800 Subject: [PATCH 0256/1348] https://github.com/Neilpang/acme.sh/issues/258 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 64a0e94b..5ec2d44b 100755 --- a/acme.sh +++ b/acme.sh @@ -1547,7 +1547,7 @@ issue() { vtype=$(echo $ventry | cut -d $sep -f 4) _currentRoot=$(echo $ventry | cut -d $sep -f 5) - if [ "$keyauthorization" == "$STATE_VERIFIED" ] ; then + if [ "$keyauthorization" = "$STATE_VERIFIED" ] ; then _info "$d is already verified, skip $vtype." continue fi @@ -1645,7 +1645,7 @@ issue() { vtype=$(echo $ventry | cut -d $sep -f 4) _currentRoot=$(echo $ventry | cut -d $sep -f 5) - if [ "$keyauthorization" == "$STATE_VERIFIED" ] ; then + if [ "$keyauthorization" = "$STATE_VERIFIED" ] ; then _info "$d is already verified, skip $vtype." continue fi From d190a43e0a61ac5e4303196ba2c2647fc5ed6de1 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 8 Aug 2016 10:19:51 +0800 Subject: [PATCH 0257/1348] https://github.com/Neilpang/acme.sh/issues/258 --- dnsapi/dns_gd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 01a2c3d6..c25de32d 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -38,7 +38,7 @@ dns_gd_add(){ _info "Adding record" if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then - if [ "$response" == "{}" ] ; then + if [ "$response" = "{}" ] ; then _info "Added, sleeping 10 seconds" sleep 10 #todo: check if the record takes effect From 22ea4004e16cfb7af341e15d8186364fd17faec7 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 10 Aug 2016 21:54:08 +0800 Subject: [PATCH 0258/1348] Support SunOS/Solaris (#260) Support SunOS/Solaris * Support Solaris * Support SunOS/Open Solaris --- acme.sh | 142 +++++++++++++++++++++++++++++------------------ dnsapi/dns_cf.sh | 6 +- dnsapi/dns_cx.sh | 8 +-- dnsapi/dns_dp.sh | 2 +- 4 files changed, 96 insertions(+), 62 deletions(-) diff --git a/acme.sh b/acme.sh index 5ec2d44b..0d842860 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.3.5 +VER=2.3.6 PROJECT_NAME="acme.sh" @@ -76,6 +76,13 @@ _debug2() { return } +_debug3() { + if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; then + _debug "$@" + fi + return +} + _startswith(){ _str="$1" _sub="$2" @@ -215,6 +222,14 @@ _sed_i() { fi } +_egrep_o() { + if _contains "$(egrep -o 2>&1)" "egrep: illegal option -- o" ; then + sed -n 's/.*\('"$1"'\).*/\1/p' + else + egrep -o "$1" + fi +} + #Usage: file startline endline _getfile() { filename="$1" @@ -406,6 +421,9 @@ _ss() { else if netstat -help 2>&1 | grep "\-p protocol" >/dev/null ; then netstat -an -p tcp | grep LISTEN | grep ":$_port " + elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null ; then + #for solaris + netstat -an -P tcp | grep "\.$_port " else netstat -ntpl | grep ":$_port " fi @@ -535,6 +553,11 @@ _time2str() { return fi + #Soaris + if _exists adb ; then + echo $(echo "0t${1}=Y" | adb) + fi + } _normalizeJson() { @@ -569,66 +592,67 @@ _calcjwk() { if [ "${#pub_exp}" = "5" ] ; then pub_exp=0$pub_exp fi - _debug2 pub_exp "$pub_exp" + _debug3 pub_exp "$pub_exp" e=$(echo $pub_exp | _h2b | _base64) - _debug2 e "$e" + _debug3 e "$e" modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2 ) - _debug2 modulus "$modulus" + _debug3 modulus "$modulus" n="$(printf "%s" "$modulus"| _h2b | _base64 | _urlencode )" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' - _debug2 jwk "$jwk" + _debug3 jwk "$jwk" HEADER='{"alg": "RS256", "jwk": '$jwk'}' - HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' + HEADERPLACE_PART1='{"nonce": "' + HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "EC key" EC_SIGN="1" crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" - _debug2 crv "$crv" + _debug3 crv "$crv" pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math $pubi + 1) - _debug2 pubi "$pubi" + _debug3 pubi "$pubi" pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math $pubj + 1) - _debug2 pubj "$pubj" + _debug3 pubj "$pubj" pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" - _debug2 pubtext "$pubtext" + _debug3 pubtext "$pubtext" xlen="$(printf "$pubtext" | tr -d ':' | wc -c)" xlen=$(_math $xlen / 4) - _debug2 xlen "$xlen" + _debug3 xlen "$xlen" xend=$(_math "$xend" + 1) x="$(printf $pubtext | cut -d : -f 2-$xend)" - _debug2 x "$x" + _debug3 x "$x" x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)" - _debug2 x64 "$x64" + _debug3 x64 "$x64" xend=$(_math "$xend" + 1) y="$(printf $pubtext | cut -d : -f $xend-10000)" - _debug2 y "$y" + _debug3 y "$y" y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)" - _debug2 y64 "$y64" + _debug3 y64 "$y64" jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}' - _debug2 jwk "$jwk" + _debug3 jwk "$jwk" HEADER='{"alg": "ES256", "jwk": '$jwk'}' - HEADERPLACE='{"nonce": "NONCE", "alg": "ES256", "jwk": '$jwk'}' - + HEADERPLACE_PART1='{"nonce": "' + HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' else _err "Only RSA or EC key is supported." return 1 fi - _debug2 HEADER "$HEADER" + _debug3 HEADER "$HEADER" } # body url [needbase64] [POST|PUT] _post() { @@ -744,8 +768,8 @@ _send_signed_request() { return 1 fi - payload64=$(echo -n $payload | _base64 | _urlencode) - _debug2 payload64 $payload64 + payload64=$(printf "%s" "$payload" | _base64 | _urlencode) + _debug3 payload64 $payload64 nonceurl="$API/directory" _headers="$(_get $nonceurl "onlyheader")" @@ -755,23 +779,23 @@ _send_signed_request() { return 1 fi - _debug2 _headers "$_headers" + _debug3 _headers "$_headers" nonce="$( echo "$_headers" | grep "Replay-Nonce:" | head -1 | tr -d "\r\n " | cut -d ':' -f 2)" - _debug nonce "$nonce" + _debug3 nonce "$nonce" - protected="$(printf "$HEADERPLACE" | sed "s/NONCE/$nonce/" )" - _debug2 protected "$protected" + protected="$HEADERPLACE_PART1$nonce$HEADERPLACE_PART2" + _debug3 protected "$protected" protected64="$(printf "$protected" | _base64 | _urlencode)" - _debug2 protected64 "$protected64" + _debug3 protected64 "$protected64" - sig=$(echo -n "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode) - _debug2 sig "$sig" + sig=$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode) + _debug3 sig "$sig" body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - _debug2 body "$body" + _debug3 body "$body" response="$(_post "$body" $url "$needbase64")" @@ -808,15 +832,15 @@ _setopt() { touch "$__conf" fi - if grep -H -n "^$__opt$__sep" "$__conf" > /dev/null ; then - _debug2 OK + if grep -n "^$__opt$__sep" "$__conf" > /dev/null ; then + _debug3 OK if _contains "$__val" "&" ; then __val="$(echo $__val | sed 's/&/\\&/g')" fi text="$(cat $__conf)" echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" - elif grep -H -n "^#$__opt$__sep" "$__conf" > /dev/null ; then + elif grep -n "^#$__opt$__sep" "$__conf" > /dev/null ; then if _contains "$__val" "&" ; then __val="$(echo $__val | sed 's/&/\\&/g')" fi @@ -824,10 +848,10 @@ _setopt() { echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" else - _debug2 APP + _debug3 APP echo "$__opt$__sep$__val$__end" >> "$__conf" fi - _debug "$(grep -H -n "^$__opt$__sep" $__conf)" + _debug2 "$(grep -n "^$__opt$__sep" $__conf)" } #_savedomainconf key value @@ -922,9 +946,9 @@ _stopserver(){ _debug2 "Le_HTTPPort" "$Le_HTTPPort" if [ "$Le_HTTPPort" ] ; then if [ "$DEBUG" ] ; then - _get "http://localhost:$Le_HTTPPort" + _get "http://localhost:$Le_HTTPPort" "" 1 else - _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 + _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1 fi fi @@ -1412,8 +1436,8 @@ issue() { return 1 fi - accountkey_json=$(echo -n "$jwk" | tr -d ' ' ) - thumbprint=$(echo -n "$accountkey_json" | _digest "sha256" | _urlencode) + accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) + thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' if [ "$ACCOUNT_EMAIL" ] ; then @@ -1506,17 +1530,17 @@ issue() { return 1 fi - entry="$(printf "$response" | egrep -o '\{[^{]*"type":"'$vtype'"[^}]*')" + entry="$(printf "%s\n" "$response" | _egrep_o '[^{]*"type":"'$vtype'"[^}]*')" _debug entry "$entry" if [ -z "$entry" ] ; then _err "Error, can not get domain token $d" _clearup return 1 fi - token="$(printf "$entry" | egrep -o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" + token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token $token - uri="$(printf "$entry" | egrep -o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" _debug uri $uri keyauthorization="$token.$thumbprint" @@ -1556,7 +1580,7 @@ issue() { dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" - txt="$(echo -n $keyauthorization | _digest "sha256" | _urlencode)" + txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)" _debug txt "$txt" #dns #1. check use api @@ -1778,7 +1802,7 @@ issue() { response="$(echo "$response" | _normalizeJson )" _debug2 response "$response" - status=$(echo $response | egrep -o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') + status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') if [ "$status" = "valid" ] ; then _info "Success" _stopserver $serverproc @@ -1788,9 +1812,9 @@ issue() { fi if [ "$status" = "invalid" ] ; then - error="$(echo $response | tr -d "\r\n" | egrep -o '"error":\{[^}]*}')" + error="$(echo "$response" | _egrep_o '"error":\{[^}]*}')" _debug2 error "$error" - errordetail="$(echo $error | grep -o '"detail": *"[^"]*"' | cut -d '"' -f 4)" + errordetail="$(echo $error | _egrep_o '"detail": *"[^"]*"' | cut -d '"' -f 4)" _debug2 errordetail "$errordetail" if [ "$errordetail" ] ; then _err "$d:Verify error:$errordetail" @@ -1830,7 +1854,7 @@ issue() { fi - Le_LinkCert="$(grep -i -o '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)" + Le_LinkCert="$(grep -i '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)" _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ "$Le_LinkCert" ] ; then @@ -1852,7 +1876,7 @@ issue() { if [ -z "$Le_LinkCert" ] ; then response="$(echo $response | _dbase64 "multiline" | _normalizeJson )" - _err "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" + _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" return 1 fi @@ -1925,7 +1949,7 @@ renew() { IS_RENEW="1" issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" - local res=$? + res=$? IS_RENEW="" return $res @@ -1961,7 +1985,7 @@ renewAll() { list() { - local _raw="$1" + _raw="$1" _initpath _sep="|" @@ -1978,7 +2002,11 @@ list() { ) done else - list "raw" | column -t -s "$_sep" + if _exists column ; then + list "raw" | column -t -s "$_sep" + else + list "raw" | tr '|' '\t' + fi fi @@ -2094,7 +2122,11 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi - crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab - + if _exists uname && uname -a | grep solaris >/dev/null ; then + crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab -- + else + crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab - + fi fi if [ "$?" != "0" ] ; then _err "Install cron job failed. You need to manually renew your certs." @@ -2111,7 +2143,11 @@ uninstallcronjob() { _info "Removing cron job" cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")" if [ "$cr" ] ; then - crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab - + if _exists uname && uname -a | grep solaris >/dev/null ; then + crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -- + else + crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab - + fi LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" fi @@ -2181,9 +2217,7 @@ _detect_profile() { return fi - local DETECTED_PROFILE DETECTED_PROFILE='' - local SHELLTYPE SHELLTYPE="$(basename "/$SHELL")" if [ "$SHELLTYPE" = "bash" ] ; then diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 7015467d..23dea1c8 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -43,7 +43,7 @@ dns_cf_add(){ return 1 fi - count=$(printf "$response" | grep -o \"count\":[^,]* | cut -d : -f 2) + count=$(printf "%s\n" "$response" | _egrep_o \"count\":[^,]* | cut -d : -f 2) _debug count "$count" if [ "$count" = "0" ] ; then _info "Adding record" @@ -61,7 +61,7 @@ dns_cf_add(){ _err "Add txt record error." else _info "Updating record" - record_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \"| head -1) + record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \"| head -1) _debug "record_id" $record_id _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" @@ -103,7 +103,7 @@ _get_root() { fi if printf $response | grep \"name\":\"$h\" >/dev/null ; then - _domain_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | head -1 | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | head -1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ] ; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) _domain=$h diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index b0cf36d0..60951722 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -69,7 +69,7 @@ existing_records() { return 1 fi count=0 - seg=$(printf "$response" | grep -o "{[^{]*host\":\"$_sub_domain\"[^}]*}") + seg=$(printf "%s\n" "$response" | _egrep_o "{[^{]*host\":\"$_sub_domain\"[^}]*}") _debug seg "$seg" if [ -z "$seg" ] ; then return 0 @@ -77,7 +77,7 @@ existing_records() { if printf "$response" | grep '"type":"TXT"' > /dev/null ; then count=1 - record_id=$(printf "$seg" | grep -o \"record_id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") + record_id=$(printf "%s\n" "$seg" | _egrep_o \"record_id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug record_id "$record_id" return 0 fi @@ -145,9 +145,9 @@ _get_root() { fi if printf "$response" | grep "$h." >/dev/null ; then - seg=$(printf "$response" | grep -o "{[^{]*\"$h\.\"[^}]*\}" ) + seg=$(printf "%s" "$response" | _egrep_o "{[^{]*\"$h\.\"[^}]*\}" ) _debug seg "$seg" - _domain_id=$(printf "$seg" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s" "$seg" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ] ; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 39046e2a..49e8c77f 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -152,7 +152,7 @@ _get_root() { fi if printf "$response" | grep "Action completed successful" >/dev/null ; then - _domain_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ] ; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) From e3c66532c5dd7f1bf9614f9639fd7805bb7b682d Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 10 Aug 2016 23:13:14 +0800 Subject: [PATCH 0259/1348] Support Solaris --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 0d842860..e50c3131 100755 --- a/acme.sh +++ b/acme.sh @@ -423,7 +423,7 @@ _ss() { netstat -an -p tcp | grep LISTEN | grep ":$_port " elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null ; then #for solaris - netstat -an -P tcp | grep "\.$_port " + netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" else netstat -ntpl | grep ":$_port " fi From 527dd31c7095850e002e860c95c0f05e9ed60f65 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 11 Aug 2016 13:47:38 +0800 Subject: [PATCH 0260/1348] Support SunOS, Solaris --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a074c18d..0f5572f6 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |15|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD |16|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) +|18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From 43822d37a7ea5c4b009188be9def515bde956f6a Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 13 Aug 2016 19:22:25 +0800 Subject: [PATCH 0261/1348] Support RSA and ECDSA dual certs (#262) * Support RSA and ECDSA dual certs * minor * fix RSA and ECC dual certs * minor --- acme.sh | 296 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 207 insertions(+), 89 deletions(-) diff --git a/acme.sh b/acme.sh index e50c3131..59703528 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.3.6 +VER=2.4.0 PROJECT_NAME="acme.sh" @@ -36,6 +36,9 @@ END_CERT="-----END CERTIFICATE-----" RENEW_SKIP=2 +ECC_SEP="_" +ECC_SUFFIX="${ECC_SEP}ecc" + if [ -z "$AGREEMENT" ] ; then AGREEMENT="$DEFAULT_AGREEMENT" fi @@ -47,25 +50,62 @@ if [ "$(printf '\x41')" != 'A' ] ; then _URGLY_PRINTF=1 fi +__green() { + printf '\033[1;31;32m' + printf -- "$1" + printf '\033[0m' +} + +__red() { + printf '\033[1;31;40m' + printf -- "$1" + printf '\033[0m' +} _info() { if [ -z "$2" ] ; then - echo "[$(date)] $1" + printf -- "[$(date)] $1" + else + printf -- "[$(date)] $1='$2'" + fi + printf "\n" +} + + + +_err_e() { + if [ -z "$2" ] ; then + __red "$1" >&2 else - echo "[$(date)] $1='$2'" + __red "$1='$2'" >&2 fi } _err() { - _info "$@" >&2 + printf -- "[$(date)] " >&2 + _err_e "$@" + printf "\n" return 1 } +_usage() { + version + _err_e "$@" + printf "\n" +} + _debug() { if [ -z "$DEBUG" ] ; then return fi - _err "$@" + + if [ -z "$2" ] ; then + printf -- "[$(date)] $1" >&2 + else + printf -- "[$(date)] $1='$2'" >&2 + fi + + printf "\n" return 0 } @@ -89,10 +129,16 @@ _startswith(){ echo "$_str" | grep "^$_sub" >/dev/null 2>&1 } +_endswith(){ + _str="$1" + _sub="$2" + echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1 +} + _contains(){ _str="$1" _sub="$2" - echo "$_str" | grep "$_sub" >/dev/null 2>&1 + echo "$_str" | grep -- "$_sub" >/dev/null 2>&1 } _hasfield() { @@ -100,7 +146,7 @@ _hasfield() { _field="$2" _sep="$3" if [ -z "$_field" ] ; then - _err "Usage: str field [sep]" + _usage "Usage: str field [sep]" return 1 fi @@ -121,7 +167,7 @@ _hasfield() { _exists(){ cmd="$1" if [ -z "$cmd" ] ; then - _err "Usage: _exists cmd" + _usage "Usage: _exists cmd" return 1 fi if type command >/dev/null 2>&1 ; then @@ -208,7 +254,7 @@ _sed_i() { options="$1" filename="$2" if [ -z "$filename" ] ; then - _err "Usage:_sed_i options filename" + _usage "Usage:_sed_i options filename" return 1 fi _debug2 options "$options" @@ -236,7 +282,7 @@ _getfile() { startline="$2" endline="$3" if [ -z "$endline" ] ; then - _err "Usage: file startline endline" + _usage "Usage: file startline endline" return 1 fi @@ -283,7 +329,7 @@ _dbase64() { _digest() { alg="$1" if [ -z "$alg" ] ; then - _err "Usage: _digest hashalg" + _usage "Usage: _digest hashalg" return 1 fi @@ -308,7 +354,7 @@ _sign() { keyfile="$1" alg="$2" if [ -z "$alg" ] ; then - _err "Usage: _sign keyfile hashalg" + _usage "Usage: _sign keyfile hashalg" return 1 fi @@ -321,27 +367,29 @@ _sign() { } +#keylength +_isEccKey() { + _length="$1" + + if [ -z "$_length" ] ;then + return 1 + fi + + [ "$_length" != "1024" ] \ + && [ "$_length" != "2048" ] \ + && [ "$_length" != "3172" ] \ + && [ "$_length" != "4096" ] \ + && [ "$_length" != "8192" ] +} + # _createkey 2048|ec-256 file _createkey() { length="$1" f="$2" - isec="" + eccname="$length" if _startswith "$length" "ec-" ; then - isec="1" length=$(printf $length | cut -d '-' -f 2-100) - eccname="$length" - fi - if [ -z "$length" ] ; then - if [ "$isec" ] ; then - length=256 - else - length=2048 - fi - fi - _info "Use length $length" - - if [ "$isec" ] ; then if [ "$length" = "256" ] ; then eccname="prime256v1" fi @@ -351,15 +399,27 @@ _createkey() { if [ "$length" = "521" ] ; then eccname="secp521r1" fi - _info "Using ec name: $eccname" + fi - #generate account key - if [ "$isec" ] ; then + if [ -z "$length" ] ; then + length=2048 + fi + + _info "Use length $length" + + if _isEccKey "$length" ; then + _info "Using ec name: $eccname" openssl ecparam -name $eccname -genkey 2>/dev/null > "$f" else + _info "Using RSA: $length" openssl genrsa $length 2>/dev/null > "$f" fi + + if [ "$?" != "0" ] ; then + _err "Create key error." + return 1 + fi } #_createcsr cn san_list keyfile csrfile conf @@ -385,7 +445,7 @@ _createcsr() { fi #multi _info "Multi domain" "$alt" - printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nsubjectAltName=$alt" > "$csrconf" + printf -- "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nsubjectAltName=$alt" > "$csrconf" openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr" fi } @@ -434,16 +494,19 @@ _ss() { return 1 } +#domain [password] [isEcc] toPkcs() { domain="$1" pfxPassword="$2" if [ -z "$domain" ] ; then - echo "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]" + _usage "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]" return 1 fi - _initpath "$domain" + _isEcc="$3" + _initpath "$domain" "$_isEcc" + if [ "$pfxPassword" ] ; then openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" else @@ -460,7 +523,7 @@ toPkcs() { createAccountKey() { _info "Creating account key" if [ -z "$1" ] ; then - echo Usage: $PROJECT_ENTRY --createAccountKey -d domain.com [--accountkeylength 2048] + _usage "Usage: $PROJECT_ENTRY --createAccountKey -d domain.com [--accountkeylength 2048]" return fi @@ -488,18 +551,18 @@ createAccountKey() { } -#domain length +#domain [length] createDomainKey() { _info "Creating domain key" if [ -z "$1" ] ; then - echo Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ] + _usage "Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ]" return fi domain=$1 - _initpath $domain - length=$2 + + _initpath $domain "$length" if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then _createkey "$length" "$CERT_KEY_PATH" @@ -516,23 +579,30 @@ createDomainKey() { } -# domain domainlist +# domain domainlist isEcc createCSR() { _info "Creating csr" if [ -z "$1" ] ; then - echo "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]" + _usage "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]" return fi - domain=$1 - _initpath "$domain" - domainlist=$2 + domain="$1" + domainlist="$2" + _isEcc="$3" + + _initpath "$domain" "$_isEcc" if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then _info "CSR exists, skip" return fi + if [ ! -f "$CERT_KEY_PATH" ] ; then + _err "The key file is not found: $CERT_KEY_PATH" + _err "Please create the key file first." + return 1 + fi _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" } @@ -582,7 +652,7 @@ _stat() { _calcjwk() { keyfile="$1" if [ -z "$keyfile" ] ; then - _err "Usage: _calcjwk keyfile" + _usage "Usage: _calcjwk keyfile" return 1 fi EC_SIGN="" @@ -825,7 +895,7 @@ _setopt() { __val="$4" __end="$5" if [ -z "$__opt" ] ; then - echo usage: _setopt '"file" "opt" "=" "value" [";"]' + _usage usage: _setopt '"file" "opt" "=" "value" [";"]' return fi if [ ! -f "$__conf" ] ; then @@ -1012,6 +1082,7 @@ _starttlsserver() { _debug serverproc $serverproc } +#[domain] [keylength] _initpath() { if [ -z "$LE_WORKING_DIR" ] ; then @@ -1091,55 +1162,67 @@ _initpath() { fi domain="$1" - + length="$2" if [ -z "$domain" ] ; then return 0 fi - domainhome="$CERT_HOME/$domain" - mkdir -p "$domainhome" if [ -z "$DOMAIN_PATH" ] ; then + domainhome="$CERT_HOME/$domain" + domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" + DOMAIN_PATH="$domainhome" + + if _isEccKey "$length" ; then + DOMAIN_PATH="$domainhomeecc" + else + if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ] ; then + _info "The domain '$domain' seems to be a ECC domain, please add '$(__red "--ecc")' parameter next time." + DOMAIN_PATH="$domainhomeecc" + fi + fi + _debug DOMAIN_PATH "$DOMAIN_PATH" fi + if [ -z "$DOMAIN_CONF" ] ; then - DOMAIN_CONF="$domainhome/$domain.conf" + DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" fi if [ -z "$DOMAIN_SSL_CONF" ] ; then - DOMAIN_SSL_CONF="$domainhome/$domain.ssl.conf" + DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.ssl.conf" fi if [ -z "$CSR_PATH" ] ; then - CSR_PATH="$domainhome/$domain.csr" + CSR_PATH="$DOMAIN_PATH/$domain.csr" fi if [ -z "$CERT_KEY_PATH" ] ; then - CERT_KEY_PATH="$domainhome/$domain.key" + CERT_KEY_PATH="$DOMAIN_PATH/$domain.key" fi if [ -z "$CERT_PATH" ] ; then - CERT_PATH="$domainhome/$domain.cer" + CERT_PATH="$DOMAIN_PATH/$domain.cer" fi if [ -z "$CA_CERT_PATH" ] ; then - CA_CERT_PATH="$domainhome/ca.cer" + CA_CERT_PATH="$DOMAIN_PATH/ca.cer" fi if [ -z "$CERT_FULLCHAIN_PATH" ] ; then - CERT_FULLCHAIN_PATH="$domainhome/fullchain.cer" + CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer" fi if [ -z "$CERT_PFX_PATH" ] ; then - CERT_PFX_PATH="$domainhome/$domain.pfx" + CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx" fi if [ -z "$TLS_CONF" ] ; then - TLS_CONF="$domainhome/tls.valdation.conf" + TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" fi if [ -z "$TLS_CERT" ] ; then - TLS_CERT="$domainhome/tls.valdation.cert" + TLS_CERT="$DOMAIN_PATH/tls.valdation.cert" fi if [ -z "$TLS_KEY" ] ; then - TLS_KEY="$domainhome/tls.valdation.key" + TLS_KEY="$DOMAIN_PATH/tls.valdation.key" fi if [ -z "$TLS_CSR" ] ; then - TLS_CSR="$domainhome/tls.valdation.csr" + TLS_CSR="$DOMAIN_PATH/tls.valdation.csr" fi } @@ -1326,7 +1409,7 @@ _clearupwebbroot() { issue() { if [ -z "$2" ] ; then - echo "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 fi Le_Webroot="$1" @@ -1350,7 +1433,10 @@ issue() { Le_Webroot="dns_cx" fi - _initpath $Le_Domain + if [ ! "$IS_RENEW" ] ; then + _initpath $Le_Domain "$Le_Keylength" + mkdir -p "$DOMAIN_PATH" + fi if [ -f "$DOMAIN_CONF" ] ; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) @@ -1482,7 +1568,7 @@ issue() { _savedomainconf "Le_Keylength" "$Le_Keylength" - if ! createCSR $Le_Domain $Le_Alt ; then + if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" ; then _err "Create CSR error." _clearup return 1 @@ -1861,7 +1947,7 @@ issue() { echo "$BEGIN_CERT" > "$CERT_PATH" _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" echo "$END_CERT" >> "$CERT_PATH" - _info "Cert success." + _info "$(__green "Cert success.")" cat "$CERT_PATH" _info "Your cert is in $CERT_PATH" @@ -1918,22 +2004,26 @@ issue() { if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ] ; then - installcert $Le_Domain "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" + _installcert fi } +#domain [isEcc] renew() { Le_Domain="$1" if [ -z "$Le_Domain" ] ; then - _err "Usage: $PROJECT_ENTRY --renew -d domain.com" + _usage "Usage: $PROJECT_ENTRY --renew -d domain.com [--ecc]" return 1 fi - _initpath $Le_Domain - _info "Renew: $Le_Domain" + _isEcc="$2" + + _initpath $Le_Domain "$_isEcc" + + _info "Renew: '$Le_Domain'" if [ ! -f "$DOMAIN_CONF" ] ; then - _info "$Le_Domain is not a issued domain, skip." + _info "'$Le_Domain' is not a issued domain, skip." return 0; fi @@ -1961,10 +2051,15 @@ renewAll() { _stopRenewOnError="$1" _debug "_stopRenewOnError" "$_stopRenewOnError" _ret="0" + for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do d=$(echo $d | cut -d '/' -f 1) - ( - renew "$d" + ( + if _endswith $d "$ECC_SUFFIX" ; then + _isEcc=$(echo $d | cut -d "$ECC_SEP" -f 2) + d=$(echo $d | cut -d "$ECC_SEP" -f 1) + fi + renew "$d" "$_isEcc" ) rc="$?" _debug "Return code: $rc" @@ -1990,14 +2085,18 @@ list() { _sep="|" if [ "$_raw" ] ; then - printf "Main_Domain${_sep}SAN_Domains${_sep}Created${_sep}Renew\n" + printf "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew\n" for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do d=$(echo $d | cut -d '/' -f 1) ( - _initpath $d + if _endswith $d "$ECC_SUFFIX" ; then + _isEcc=$(echo $d | cut -d "$ECC_SEP" -f 2) + d=$(echo $d | cut -d "$ECC_SEP" -f 1) + fi + _initpath $d "$_isEcc" if [ -f "$DOMAIN_CONF" ] ; then . "$DOMAIN_CONF" - printf "$Le_Domain${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr\n" + printf "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr\n" fi ) done @@ -2005,7 +2104,7 @@ list() { if _exists column ; then list "raw" | column -t -s "$_sep" else - list "raw" | tr '|' '\t' + list "raw" | tr "$_sep" '\t' fi fi @@ -2015,7 +2114,7 @@ list() { installcert() { Le_Domain="$1" if [ -z "$Le_Domain" ] ; then - echo "Usage: $PROJECT_ENTRY --installcert -d domain.com [--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] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" return 1 fi @@ -2024,8 +2123,19 @@ installcert() { Le_RealCACertPath="$4" Le_ReloadCmd="$5" Le_RealFullChainPath="$6" + _isEcc="$7" + + _initpath $Le_Domain "$_isEcc" + if [ ! -d "$DOMAIN_PATH" ] ; then + _err "Domain is not valid:'$Le_Domain'" + return 1 + fi + + _installcert +} - _initpath $Le_Domain + +_installcert() { _savedomainconf "Le_RealCertPath" "$Le_RealCertPath" _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath" @@ -2053,7 +2163,7 @@ installcert() { if [ "$Le_RealCertPath" ] ; then _installed=1 _info "Installing cert to:$Le_RealCertPath" - if [ -f "$Le_RealCertPath" ] ; then + if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ] ; then cp "$Le_RealCertPath" "$Le_RealCertPath".bak fi cat "$CERT_PATH" > "$Le_RealCertPath" @@ -2066,7 +2176,7 @@ installcert() { echo "" >> "$Le_RealCACertPath" cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" else - if [ -f "$Le_RealCACertPath" ] ; then + if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ] ; then cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak fi cat "$CA_CERT_PATH" > "$Le_RealCACertPath" @@ -2077,7 +2187,7 @@ installcert() { if [ "$Le_RealKeyPath" ] ; then _installed=1 _info "Installing key to:$Le_RealKeyPath" - if [ -f "$Le_RealKeyPath" ] ; then + if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ] ; then cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak fi cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" @@ -2086,7 +2196,7 @@ installcert() { if [ "$Le_RealFullChainPath" ] ; then _installed=1 _info "Installing full chain to:$Le_RealFullChainPath" - if [ -f "$Le_RealFullChainPath" ] ; then + if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ] ; then cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak fi cat "$CERT_FULLCHAIN_PATH" > "$Le_RealFullChainPath" @@ -2096,7 +2206,7 @@ installcert() { _installed=1 _info "Run Le_ReloadCmd: $Le_ReloadCmd" if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") ; then - _info "Reload success." + _info "$(__green "Reload success")" else _err "Reload error for :$Le_Domain" fi @@ -2158,11 +2268,13 @@ uninstallcronjob() { revoke() { Le_Domain="$1" if [ -z "$Le_Domain" ] ; then - echo "Usage: $PROJECT_ENTRY --revoke -d domain.com" + _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com" return 1 fi - _initpath $Le_Domain + _isEcc="$2" + + _initpath $Le_Domain "$_isEcc" if [ ! -f "$DOMAIN_CONF" ] ; then _err "$Le_Domain is not a issued domain, skip." return 1; @@ -2341,7 +2453,7 @@ _setShebang() { _file="$1" _shebang="$2" if [ -z "$_shebang" ] ; then - _err "Usage: file shebang" + _usage "Usage: file shebang" return 1 fi cp "$_file" "$_file.tmp" @@ -2592,6 +2704,7 @@ Parameters: --stopRenewOnError, -se Only valid for '--renewall' 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. --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 '--installcert', '--renew', '--revoke', '--toPkcs' and '--createCSR' " } @@ -2665,6 +2778,7 @@ _process() { _stopRenewOnError="" _insecure="" _nocron="" + _ecc="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -2908,6 +3022,10 @@ _process() { --nocron) _nocron="1" ;; + --ecc) + _ecc="isEcc" + ;; + *) _err "Unknown parameter : $1" return 1 @@ -2929,16 +3047,16 @@ _process() { issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" ;; installcert) - installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" + installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc" ;; renew) - renew "$_domain" + renew "$_domain" "$_ecc" ;; renewAll) renewAll "$_stopRenewOnError" ;; revoke) - revoke "$_domain" + revoke "$_domain" "$_ecc" ;; list) list "$_listraw" @@ -2947,7 +3065,7 @@ _process() { uninstallcronjob) uninstallcronjob ;; cron) cron ;; toPkcs) - toPkcs "$_domain" "$_password" + toPkcs "$_domain" "$_password" "$_ecc" ;; createAccountKey) createAccountKey "$_domain" "$_accountkeylength" @@ -2956,7 +3074,7 @@ _process() { createDomainKey "$_domain" "$_keylength" ;; createCSR) - createCSR "$_domain" "$_altdomains" + createCSR "$_domain" "$_altdomains" "$_ecc" ;; *) From 31a5487cba4fea1cf3a42f7d898ddc57fd5ab8ed Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 13 Aug 2016 20:37:52 +0800 Subject: [PATCH 0262/1348] fix dual certs --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 59703528..dc62bcd2 100755 --- a/acme.sh +++ b/acme.sh @@ -84,14 +84,14 @@ _err_e() { _err() { printf -- "[$(date)] " >&2 _err_e "$@" - printf "\n" + printf "\n" >&2 return 1 } _usage() { version _err_e "$@" - printf "\n" + printf "\n" >&2 } _debug() { @@ -105,7 +105,7 @@ _debug() { printf -- "[$(date)] $1='$2'" >&2 fi - printf "\n" + printf "\n" >&2 return 0 } @@ -546,7 +546,7 @@ createAccountKey() { return else #generate account key - _createkey $length "$ACCOUNT_KEY_PATH" + _createkey "$length" "$ACCOUNT_KEY_PATH" fi } From fac1e367c9a5c6c58e26dafd3ca10e891bc90a5d Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 14 Aug 2016 22:37:21 +0800 Subject: [PATCH 0263/1348] 2.4.1 fix bug. --- acme.sh | 118 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 31 deletions(-) diff --git a/acme.sh b/acme.sh index dc62bcd2..aa3cf0fe 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.4.0 +VER=2.4.1 PROJECT_NAME="acme.sh" @@ -45,11 +45,6 @@ fi -_URGLY_PRINTF="" -if [ "$(printf '\x41')" != 'A' ] ; then - _URGLY_PRINTF=1 -fi - __green() { printf '\033[1;31;32m' printf -- "$1" @@ -72,26 +67,24 @@ _info() { } - _err_e() { if [ -z "$2" ] ; then __red "$1" >&2 else __red "$1='$2'" >&2 fi + printf "\n" >&2 } _err() { printf -- "[$(date)] " >&2 - _err_e "$@" - printf "\n" >&2 + _err_e "$@" return 1 } _usage() { version _err_e "$@" - printf "\n" >&2 } _debug() { @@ -213,6 +206,12 @@ _h_char_2_dec() { } + +_URGLY_PRINTF="" +if [ "$(printf '\x41')" != 'A' ] ; then + _URGLY_PRINTF=1 +fi + _h2b() { hex=$(cat) i=1 @@ -363,7 +362,7 @@ _sign() { else _err "$alg is not supported yet" return 1 - fi + fi } @@ -724,6 +723,46 @@ _calcjwk() { _debug3 HEADER "$HEADER" } + + +_mktemp() { + if _exists mktemp ; then + mktemp + fi +} + +_inithttp() { + + if [ -z "$HTTP_HEADER" ] ; then + HTTP_HEADER="$(_mktemp)" + _debug2 HTTP_HEADER "$HTTP_HEADER" + fi + + if [ -z "$CURL" ] ; then + CURL="curl -L --silent --dump-header $HTTP_HEADER " + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + _CURL_DUMP="$(_mktemp)" + CURL="$CURL --trace-ascii $_CURL_DUMP " + fi + + if [ "$HTTPS_INSECURE" ] ; then + CURL="$CURL --insecure " + fi + fi + + if [ -z "$WGET" ] ; then + WGET="wget -q" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + WGET="$WGET -d " + fi + if [ "$HTTPS_INSECURE" ] ; then + WGET="$WGET --no-check-certificate " + fi + fi + +} + + # body url [needbase64] [POST|PUT] _post() { body="$1" @@ -737,8 +776,11 @@ _post() { _debug $httpmethod _debug "url" "$url" _debug2 "body" "$body" + + _inithttp + if _exists "curl" ; then - _CURL="$CURL --dump-header $HTTP_HEADER " + _CURL="$CURL" _debug "_CURL" "$_CURL" if [ "$needbase64" ] ; then response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" | _base64)" @@ -790,6 +832,9 @@ _get() { t="$3" _debug url $url _debug "timeout" "$t" + + _inithttp + if _exists "curl" ; then _CURL="$CURL" if [ "$t" ] ; then @@ -802,6 +847,13 @@ _get() { $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url fi ret=$? + if [ "$ret" != "0" ] ; then + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + _err "Here is the curl dump log:" + _err "$(cat "$_CURL_DUMP")" + fi + fi elif _exists "wget" ; then _WGET="$WGET" if [ "$t" ] ; then @@ -814,6 +866,9 @@ _get() { $_WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url fi ret=$? + if [ "$ret" != "0" ] ; then + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" + fi else ret=$? _err "Neither curl nor wget is found, can not do GET." @@ -822,6 +877,7 @@ _get() { return $ret } + # url payload needbase64 keyfile _send_signed_request() { url=$1 @@ -970,6 +1026,16 @@ _saveaccountconf() { fi } +#_clearaccountconf key +_clearaccountconf() { + key="$1" + if [ "$ACCOUNT_CONF_PATH" ] ; then + _sed_i "s/^$key.*$//" "$ACCOUNT_CONF_PATH" + else + _err "ACCOUNT_CONF_PATH is empty, can not clear $key" + fi +} + _startserver() { content="$1" _debug "startserver: $$" @@ -1134,22 +1200,6 @@ _initpath() { fi HTTP_HEADER="$LE_WORKING_DIR/http.header" - - WGET="wget -q" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - WGET="$WGET -d " - fi - - _CURL_DUMP="$LE_WORKING_DIR/curl.dump" - CURL="curl -L --silent" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - CURL="$CURL --trace-ascii $_CURL_DUMP " - fi - - if [ "$Le_Insecure" ] ; then - WGET="$WGET --no-check-certificate " - CURL="$CURL --insecure " - fi _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" if [ -z "$ACCOUNT_KEY_PATH" ] ; then @@ -1969,6 +2019,10 @@ issue() { _cleardomainconf "Le_Vlist" Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) + if ! _contains "$Le_LinkIssuer" ":" ; then + Le_LinkIssuer="$API$Le_LinkIssuer" + fi + _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ] ; then @@ -1992,8 +2046,10 @@ issue() { _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" fi - if [ "$Le_Insecure" ] ; then - _savedomainconf "Le_Insecure" "$Le_Insecure" + if [ "$HTTPS_INSECURE" ] ; then + _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" + else + _clearaccountconf "HTTPS_INSECURE" fi Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) @@ -3017,7 +3073,7 @@ _process() { ;; --insecure) _insecure="1" - Le_Insecure="$_insecure" + HTTPS_INSECURE="1" ;; --nocron) _nocron="1" From d529eb6d003123709ded71b4daa20894f8fac27a Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 14 Aug 2016 23:20:53 +0800 Subject: [PATCH 0264/1348] minor --- acme.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index aa3cf0fe..083fd0c3 100755 --- a/acme.sh +++ b/acme.sh @@ -824,6 +824,7 @@ _post() { return $_ret } + # url getheader timeout _get() { _debug GET @@ -848,7 +849,7 @@ _get() { fi ret=$? if [ "$ret" != "0" ] ; then - _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then _err "Here is the curl dump log:" _err "$(cat "$_CURL_DUMP")" @@ -867,7 +868,7 @@ _get() { fi ret=$? if [ "$ret" != "0" ] ; then - _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" fi else ret=$? From df9547ae391cc58b85468cff746089ab212f718f Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 15 Aug 2016 19:15:19 +0800 Subject: [PATCH 0265/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 083fd0c3..03f954ba 100755 --- a/acme.sh +++ b/acme.sh @@ -2777,7 +2777,7 @@ _installOnline() { _info "Downloading $target" localname="$BRANCH.tar.gz" if ! _get "$target" > $localname ; then - _debug "Download error." + _err "Download error." return 1 fi ( From a8df88ab91b15e5c6893e070bf960a47475d99e5 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 15 Aug 2016 21:14:36 +0800 Subject: [PATCH 0266/1348] https://github.com/Neilpang/acme.sh/issues/263 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 03f954ba..445e6447 100755 --- a/acme.sh +++ b/acme.sh @@ -733,7 +733,7 @@ _mktemp() { _inithttp() { - if [ -z "$HTTP_HEADER" ] ; then + if [ -z "$HTTP_HEADER" ] || ! touch "HTTP_HEADER" ; then HTTP_HEADER="$(_mktemp)" _debug2 HTTP_HEADER "$HTTP_HEADER" fi @@ -2772,7 +2772,7 @@ _installOnline() { if [ ! "$BRANCH" ] ; then BRANCH="master" fi - _initpath + target="$PROJECT/archive/$BRANCH.tar.gz" _info "Downloading $target" localname="$BRANCH.tar.gz" From 933c169da56de27de8e051eefbd0a8ad30cb47ed Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 17 Aug 2016 13:17:06 +0800 Subject: [PATCH 0267/1348] minor --- acme.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 445e6447..cee3e3b9 100755 --- a/acme.sh +++ b/acme.sh @@ -1200,7 +1200,9 @@ _initpath() { USER_AGENT="$DEFAULT_USER_AGENT" fi - HTTP_HEADER="$LE_WORKING_DIR/http.header" + if [ -z "$HTTP_HEADER" ] ; then + HTTP_HEADER="$LE_WORKING_DIR/http.header" + fi _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" if [ -z "$ACCOUNT_KEY_PATH" ] ; then @@ -1236,6 +1238,13 @@ _initpath() { _debug DOMAIN_PATH "$DOMAIN_PATH" fi + if [ ! -d "$DOMAIN_PATH" ] ; then + if ! mkdir -p "$DOMAIN_PATH" ; then + _err "Can not create domain path: $DOMAIN_PATH" + return 1 + fi + fi + if [ -z "$DOMAIN_CONF" ] ; then DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" fi From 66f08eb23600d20630b95a36691aecb924d97fe8 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 22 Aug 2016 13:36:39 +0800 Subject: [PATCH 0268/1348] minor format output --- acme.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index cee3e3b9..41ca9665 100755 --- a/acme.sh +++ b/acme.sh @@ -2010,7 +2010,8 @@ issue() { _info "$(__green "Cert success.")" cat "$CERT_PATH" - _info "Your cert is in $CERT_PATH" + _info "Your cert is in $( __green " $CERT_PATH ")" + _info "Your cert key is in $( __green " $CERT_KEY_PATH ")" cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ] ; then @@ -2039,9 +2040,9 @@ issue() { echo "$BEGIN_CERT" > "$CA_CERT_PATH" _get "$Le_LinkIssuer" | _base64 "multiline" >> "$CA_CERT_PATH" echo "$END_CERT" >> "$CA_CERT_PATH" - _info "The intermediate CA cert is in $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: $CERT_FULLCHAIN_PATH" + _info "And the full chain certs is there: $( __green " $CERT_FULLCHAIN_PATH ")" fi Le_CertCreateTime=$(date -u "+%s") From 6d4e903b08975e049db79f53daf4b52ba7ea1a4c Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 23 Aug 2016 10:03:50 +0800 Subject: [PATCH 0269/1348] https://github.com/Neilpang/acme.sh/issues/270 --- acme.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 41ca9665..e0050e8d 100755 --- a/acme.sh +++ b/acme.sh @@ -1231,8 +1231,7 @@ _initpath() { DOMAIN_PATH="$domainhomeecc" else if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ] ; then - _info "The domain '$domain' seems to be a ECC domain, please add '$(__red "--ecc")' parameter next time." - DOMAIN_PATH="$domainhomeecc" + _info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert." fi fi _debug DOMAIN_PATH "$DOMAIN_PATH" From 5fbc47eb3ad4fb01e1bee0d31ad6931233e4c261 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 23 Aug 2016 22:53:43 +0800 Subject: [PATCH 0270/1348] fixd createAccountKey https://github.com/Neilpang/acme.sh/issues/271 --- acme.sh | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/acme.sh b/acme.sh index e0050e8d..571d4280 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.4.1 +VER=2.4.2 PROJECT_NAME="acme.sh" @@ -376,7 +376,7 @@ _isEccKey() { [ "$_length" != "1024" ] \ && [ "$_length" != "2048" ] \ - && [ "$_length" != "3172" ] \ + && [ "$_length" != "3072" ] \ && [ "$_length" != "4096" ] \ && [ "$_length" != "8192" ] } @@ -518,28 +518,26 @@ toPkcs() { } -#domain [2048] +#[2048] createAccountKey() { _info "Creating account key" if [ -z "$1" ] ; then - _usage "Usage: $PROJECT_ENTRY --createAccountKey -d domain.com [--accountkeylength 2048]" + _usage "Usage: $PROJECT_ENTRY --createAccountKey --accountkeylength 2048" return fi - account=$1 - length=$2 - _debug account "$account" - _debug length "$length" + length=$1 if _startswith "$length" "ec-" ; then length=2048 fi - if [ -z "$2" ] || [ "$2" = "no" ] ; then + if [ -z "$length" ] || [ "$length" = "no" ] ; then _info "Use default length 2048" length=2048 fi + _debug length "$length" _initpath - + if [ -f "$ACCOUNT_KEY_PATH" ] ; then _info "Account key exists, skip" return @@ -1214,12 +1212,11 @@ _initpath() { CERT_HOME="$_DEFAULT_CERT_HOME" fi - domain="$1" - length="$2" - if [ -z "$domain" ] ; then + if [ -z "$1" ] ; then return 0 fi - + domain="$1" + _ilength="$2" if [ -z "$DOMAIN_PATH" ] ; then domainhome="$CERT_HOME/$domain" @@ -1227,7 +1224,7 @@ _initpath() { DOMAIN_PATH="$domainhome" - if _isEccKey "$length" ; then + if _isEccKey "$_ilength" ; then DOMAIN_PATH="$domainhomeecc" else if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ] ; then @@ -1565,7 +1562,11 @@ issue() { fi if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then - if ! createAccountKey $Le_Domain $Le_Keylength ; then + _acck="no" + if [ "$Le_Keylength" ] ; then + _acck="$Le_Keylength" + fi + if ! createAccountKey "$_acck" ; then _err "Create account key error." if [ "$usingApache" ] ; then _restoreApache @@ -1799,7 +1800,7 @@ issue() { _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" fi - _info "Sleep $Le_DNSSleep seconds for the txt records to take effect" + _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" sleep $Le_DNSSleep fi @@ -3134,7 +3135,7 @@ _process() { toPkcs "$_domain" "$_password" "$_ecc" ;; createAccountKey) - createAccountKey "$_domain" "$_accountkeylength" + createAccountKey "$_accountkeylength" ;; createDomainKey) createDomainKey "$_domain" "$_keylength" From d4d1f0f4a94892d710d554001aef39e43756466e Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 23 Aug 2016 23:16:19 +0800 Subject: [PATCH 0271/1348] Add donate list --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0f5572f6..81767734 100644 --- a/README.md +++ b/README.md @@ -308,3 +308,5 @@ Please Star and Fork me. # Donate 1. PayPal: donate@acme.sh +[Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) + From a6014bf04e9245028bc0a86b1c69bd23f05aa7ae Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 24 Aug 2016 18:46:23 +0800 Subject: [PATCH 0272/1348] support sha1 --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 571d4280..ceb02d3e 100755 --- a/acme.sh +++ b/acme.sh @@ -334,11 +334,11 @@ _digest() { outputhex="$2" - if [ "$alg" = "sha256" ] ; then + if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ] ; then - echo $(openssl dgst -sha256 -hex | cut -d = -f 2) + echo $(openssl dgst -$alg -hex | cut -d = -f 2) else - openssl dgst -sha256 -binary | _base64 + openssl dgst -$alg -binary | _base64 fi else _err "$alg is not supported yet" From 690a5e205daf5ad8d58a1be4b21e9ba676d7f18d Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 10:45:41 +0800 Subject: [PATCH 0273/1348] Support Ovh domain api (#273) * support ovh * fix success link * fix OVH issues. * v2.4.3 Support OVH domain api --- acme.sh | 30 ++--- dnsapi/dns_ovh.sh | 302 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 317 insertions(+), 15 deletions(-) create mode 100644 dnsapi/dns_ovh.sh diff --git a/acme.sh b/acme.sh index ceb02d3e..ce150f4a 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.4.2 +VER=2.4.3 PROJECT_NAME="acme.sh" @@ -169,7 +169,7 @@ _exists(){ type "$cmd" >/dev/null 2>&1 fi ret="$?" - _debug2 "$cmd exists=$ret" + _debug3 "$cmd exists=$ret" return $ret } @@ -219,8 +219,8 @@ _h2b() { if _exists let ; then uselet="1" fi - _debug2 uselet "$uselet" - _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" + _debug3 uselet "$uselet" + _debug3 _URGLY_PRINTF "$_URGLY_PRINTF" while true ; do if [ -z "$_URGLY_PRINTF" ] ; then h="$(printf $hex | cut -c $i-$j)" @@ -336,7 +336,7 @@ _digest() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ] ; then - echo $(openssl dgst -$alg -hex | cut -d = -f 2) + openssl dgst -$alg -hex | cut -d = -f 2 | tr -d ' ' else openssl dgst -$alg -binary | _base64 fi @@ -781,9 +781,9 @@ _post() { _CURL="$CURL" _debug "_CURL" "$_CURL" if [ "$needbase64" ] ; then - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" | _base64)" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" --data "$body" "$url" )" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" )" fi _ret="$?" if [ "$_ret" != "0" ] ; then @@ -797,15 +797,15 @@ _post() { _debug "WGET" "$WGET" if [ "$needbase64" ] ; then if [ "$httpmethod"="POST" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" fi else if [ "$httpmethod"="POST" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" fi fi _ret="$?" @@ -841,9 +841,9 @@ _get() { fi _debug "_CURL" "$_CURL" if [ "$onlyheader" ] ; then - $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url + $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url else - $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" $url + $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url fi ret=$? if [ "$ret" != "0" ] ; then @@ -860,9 +860,9 @@ _get() { fi _debug "_WGET" "$_WGET" if [ "$onlyheader" ] ; then - $_WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' + $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else - $_WGET --user-agent="$USER_AGENT" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url + $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url fi ret=$? if [ "$ret" != "0" ] ; then diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh new file mode 100644 index 00000000..443aec6f --- /dev/null +++ b/dnsapi/dns_ovh.sh @@ -0,0 +1,302 @@ +#!/usr/bin/env sh + + +#Applcation Key +#OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#Application Secret +#OVH_AS="sdfsafsdfsdfdsfsdfsa" +# +#Consumer Key +#OVH_CK="sdfsdfsdfsdfsdfdsf" + + +#OVH_END_POINT=ovh-eu + + +#'ovh-eu' +OVH_EU='https://eu.api.ovh.com/1.0' + +#'ovh-ca': +OVH_CA='https://ca.api.ovh.com/1.0' + +#'kimsufi-eu' +KSF_EU='https://eu.api.kimsufi.com/1.0' + +#'kimsufi-ca' +KSF_CA='https://ca.api.kimsufi.com/1.0' + +#'soyoustart-eu' +SYS_EU='https://eu.api.soyoustart.com/1.0' + +#'soyoustart-ca' +SYS_CA='https://ca.api.soyoustart.com/1.0' + +#'runabove-ca' +RAV_CA='https://api.runabove.com/1.0' + + +wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api" + +ovh_success="https://github.com/Neilpang/acme.sh/wiki/OVH-Success" + + + +_ovh_get_api() { + _ogaep="$1" + + case "${_ogaep}" in + + ovh-eu|ovheu) + printf "%s" $OVH_EU + return + ;; + ovh-ca|ovhca) + printf "%s" $OVH_CA + return + ;; + kimsufi-eu|kimsufieu) + printf "%s" $KSF_EU + return + ;; + kimsufi-ca|kimsufica) + printf "%s" $KSF_CA + return + ;; + soyoustart-eu|soyoustarteu) + printf "%s" $SYS_EU + return + ;; + soyoustart-ca|soyoustartca) + printf "%s" $SYS_CA + return + ;; + runabove-ca|runaboveca) + printf "%s" $RAV_CA + return + ;; + + + *) + _err "Unknown parameter : $1" + return 1 + ;; + esac +} + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ovh_add(){ + fulldomain=$1 + txtvalue=$2 + + if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ] ; then + _err "You don't specify OVH application key and application secret yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf OVH_AK "$OVH_AK" + _saveaccountconf OVH_AS "$OVH_AS" + + + if [ -z "$OVH_END_POINT" ] ; then + OVH_END_POINT="ovh-eu" + fi + _info "Using OVH endpoint: $OVH_END_POINT" + if [ "$OVH_END_POINT" != "ovh-eu" ] ; then + _saveaccountconf OVH_END_POINT "$OVH_END_POINT" + fi + + OVH_API="$(_ovh_get_api $OVH_END_POINT )" + _debug OVH_API "$OVH_API" + + if [ -z "$OVH_CK" ] ; then + _info "OVH consumer key is empty, Let's get one:" + if ! _ovh_authentication ; then + _err "Can not get consumer key." + fi + #return and wait for retry. + return 1; + fi + + + _info "Checking authentication" + + response="$(_ovh_rest GET "domain/")" + if _contains "$response" "INVALID_CREDENTIAL" ; then + _err "The consumer key is invalid: $OVH_CK" + _err "Please retry to create a new one." + _clearaccountconf OVH_CK + return 1 + fi + _info "Consumer key is ok." + + _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" + _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" + + if _contains "$response" '\[\]' || _contains "$response" "This service does not exist" ; then + _info "Adding record" + if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then + if _contains "$response" "$txtvalue" ; then + _ovh_rest POST "domain/zone/$_domain/refresh" + _debug "Refresh:$response" + _info "Added, sleeping 10 seconds" + sleep 10 + return 0 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 1) + if [ -z "$record_id" ] ; then + _err "Can not get record id." + return 1 + fi + _debug "record_id" $record_id + + if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}" ; then + if _contains "$response" "null" ; then + _ovh_rest POST "domain/zone/$_domain/refresh" + _debug "Refresh:$response" + _info "Updated, sleeping 10 seconds" + sleep 10 + return 0; + fi + fi + _err "Update error" + return 1 + fi + +} + + +#################### Private functions bellow ################################## + +_ovh_authentication() { + + _H1="X-Ovh-Application: $OVH_AK" + _H2="Content-type: application/json" + _H3="" + _H4="" + + _ovhdata='{"accessRules": [{"method": "GET","path": "/*"},{"method": "POST","path": "/*"},{"method": "PUT","path": "/*"},{"method": "DELETE","path": "/*"}],"redirection":"'$ovh_success'"}' + + response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" + _debug3 response "$response" + validationUrl="$(echo "$response" | _egrep_o "validationUrl\":\"[^\"]*\"" | _egrep_o "http.*\"" | tr -d '"')" + if [ -z "$validationUrl" ] ; then + _err "Unable to get validationUrl" + return 1 + fi + _debug validationUrl "$validationUrl" + + consumerKey="$(echo "$response" | _egrep_o "consumerKey\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')" + if [ -z "$consumerKey" ] ; then + _err "Unable to get consumerKey" + return 1 + fi + _debug consumerKey "$consumerKey" + + OVH_CK="$consumerKey" + _saveaccountconf OVH_CK "$OVH_CK" + + _info "Please open this link to do authentication: $(__green "$validationUrl" )" + + _info "Here is a guide for you: $(__green "$wiki" )" + _info "Please retry after the authentication is done." + +} + + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while [ '1' ] ; do + h=$(printf $domain | cut -d . -f $i-100) + if [ -z "$h" ] ; then + #not valid + return 1; + fi + + if ! _ovh_rest GET "domain/zone/$h" ; then + return 1 + fi + + if ! _contains "$response" "This service does not exist" >/dev/null ; then + _sub_domain=$(printf $domain | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(expr $i + 1) + done + return 1 +} + +_ovh_timestamp() { + _H1="" + _H2="" + _H3="" + _H4="" + _H5="" + _get "$OVH_API/auth/time" "" 30 +} + +_ovh_rest() { + m=$1 + ep="$2" + data="$3" + _debug $ep + + + _ovh_url="$OVH_API/$ep" + _debug2 _ovh_url "$_ovh_url" + _ovh_t="$(_ovh_timestamp)" + _debug2 _ovh_t "$_ovh_t" + _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t" + _debug _ovh_p "$_ovh_p" + _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" + _debug2 _ovh_hex "$_ovh_hex" + + + _H1="X-Ovh-Application: $OVH_AK" + _H2="X-Ovh-Signature: \$1\$$_ovh_hex" + _debug2 _H2 "$_H2" + _H3="X-Ovh-Timestamp: $_ovh_t" + _H4="X-Ovh-Consumer: $OVH_CK" + _H5="Content-Type: application/json;charset=utf-8" + if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] ; then + _debug data "$data" + response="$(_post "$data" "$_ovh_url" "" $m)" + else + response="$(_get "$_ovh_url")" + fi + + if [ "$?" != "0" ] ; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + + From 73ba54a502af6ee307b4b3106d7db61390c8fe39 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 11:03:25 +0800 Subject: [PATCH 0274/1348] Support OVH domain api --- dnsapi/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 3098e03f..5aa52cdf 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -89,7 +89,9 @@ acme.sh --issue --dns dns_gd -d aa.com -d www.aa.com The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. +## Use OVH/kimsufi/soyoustart/runabove API +https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api # Use custom api From dfdc402fbb69d19ef3be926516d737a0e76251a4 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 12:03:19 +0800 Subject: [PATCH 0275/1348] fix typo --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ce150f4a..afae703d 100755 --- a/acme.sh +++ b/acme.sh @@ -731,7 +731,7 @@ _mktemp() { _inithttp() { - if [ -z "$HTTP_HEADER" ] || ! touch "HTTP_HEADER" ; then + if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER" ; then HTTP_HEADER="$(_mktemp)" _debug2 HTTP_HEADER "$HTTP_HEADER" fi From e2053b22b4f2236d6f70797a541bdafdbe0cf990 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 13:06:04 +0800 Subject: [PATCH 0276/1348] minor, fix format --- acme.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index afae703d..3da84b25 100755 --- a/acme.sh +++ b/acme.sh @@ -1498,7 +1498,8 @@ issue() { Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(date -u "+%s" ) -lt $Le_NextRenewTime ] ; then - _info "Skip, Next renewal time is: $(grep "^Le_NextRenewTimeStr" "$DOMAIN_CONF" | cut -d '=' -f 2)" + _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" + _info "Add '$(__red '--force')' to force to renew." return $RENEW_SKIP fi fi @@ -2088,7 +2089,7 @@ renew() { _initpath $Le_Domain "$_isEcc" - _info "Renew: '$Le_Domain'" + _info "$(__green "Renew: '$Le_Domain'")" if [ ! -f "$DOMAIN_CONF" ] ; then _info "'$Le_Domain' is not a issued domain, skip." return 0; @@ -2100,7 +2101,8 @@ renew() { . "$DOMAIN_CONF" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then - _info "Skip, Next renewal time is: $Le_NextRenewTimeStr" + _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" + _info "Add '$(__red '--force')' to force to renew." return $RENEW_SKIP fi From 36246ad9ac456588475b24a1c22c99db16be996a Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 13:10:13 +0800 Subject: [PATCH 0277/1348] Add OVH, kimsufi, soyoustart and runabove api --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 81767734..e24f5b32 100644 --- a/README.md +++ b/README.md @@ -245,8 +245,9 @@ You don't have do anything manually! 2. Dnspod.cn API 3. Cloudxns.com API 4. Godaddy.com API -5. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 -6. lexicon dns api: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api +5. OVH, kimsufi, soyoustart and runabove API +6. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 +7. 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.) ##### More APIs are coming soon... From 78009539d1d055660115f3186a35e8520a9e977f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Sodr=C3=A9?= Date: Thu, 25 Aug 2016 01:14:56 -0400 Subject: [PATCH 0278/1348] Add option for a custom ca-bundle file. (#274) * Add option for a custom ca-bundle file. * Renamed option cacert to ca-bundle. * Save CA_BUNDLE path in configuration file. * Store absolule path to ca-bundle file --- acme.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/acme.sh b/acme.sh index 3da84b25..aa8a43eb 100755 --- a/acme.sh +++ b/acme.sh @@ -743,6 +743,10 @@ _inithttp() { CURL="$CURL --trace-ascii $_CURL_DUMP " fi + if [ "$CA_BUNDLE" ] ; then + CURL="$CURL --cacert $CA_BUNDLE " + fi + if [ "$HTTPS_INSECURE" ] ; then CURL="$CURL --insecure " fi @@ -753,6 +757,9 @@ _inithttp() { if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then WGET="$WGET -d " fi + if [ "$CA_BUNDLE" ] ; then + WGET="$WGET --ca-certificate $CA_BUNDLE " + fi if [ "$HTTPS_INSECURE" ] ; then WGET="$WGET --no-check-certificate " fi @@ -2058,6 +2065,12 @@ issue() { _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" fi + if [ "$CA_BUNDLE" ] ; then + _saveaccountconf CA_BUNDLE "$CA_BUNDLE" + else + _clearaccountconf "CA_BUNDLE" + fi + if [ "$HTTPS_INSECURE" ] ; then _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" else @@ -2772,6 +2785,7 @@ Parameters: --listraw Only used for '--list' command, list the certs in raw format. --stopRenewOnError, -se Only valid for '--renewall' 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. + --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate. --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 '--installcert', '--renew', '--revoke', '--toPkcs' and '--createCSR' " @@ -2846,6 +2860,7 @@ _process() { _listraw="" _stopRenewOnError="" _insecure="" + _ca_bundle="" _nocron="" _ecc="" while [ ${#} -gt 0 ] ; do @@ -3088,6 +3103,11 @@ _process() { _insecure="1" HTTPS_INSECURE="1" ;; + --ca-bundle) + _ca_bundle=$(readlink -f $2) + CA_BUNDLE="$_ca_bundle" + shift + ;; --nocron) _nocron="1" ;; From 775bd1abd0d4d0893b30946fd506b8912c4a2481 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 13:17:42 +0800 Subject: [PATCH 0279/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index aa8a43eb..2308e3fe 100755 --- a/acme.sh +++ b/acme.sh @@ -3104,7 +3104,7 @@ _process() { HTTPS_INSECURE="1" ;; --ca-bundle) - _ca_bundle=$(readlink -f $2) + _ca_bundle="$(readlink -f $2)" CA_BUNDLE="$_ca_bundle" shift ;; From 3aae1ae3d9aa0cef72bce70bc2fd1d144464eaa9 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 21:46:31 +0800 Subject: [PATCH 0280/1348] minor, fix _mktemp --- acme.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 2308e3fe..118e4879 100755 --- a/acme.sh +++ b/acme.sh @@ -722,11 +722,19 @@ _calcjwk() { _debug3 HEADER "$HEADER" } +_time() { + date -u "+%s" +} _mktemp() { if _exists mktemp ; then mktemp fi + if [ -d "/tmp" ] ; then + echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" + return 0 + fi + _err "Can not create temp file." } _inithttp() { @@ -1504,7 +1512,7 @@ issue() { if [ -f "$DOMAIN_CONF" ] ; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(date -u "+%s" ) -lt $Le_NextRenewTime ] ; then + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(_time) -lt $Le_NextRenewTime ] ; then _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" _info "Add '$(__red '--force')' to force to renew." return $RENEW_SKIP @@ -2053,7 +2061,7 @@ issue() { _info "And the full chain certs is there: $( __green " $CERT_FULLCHAIN_PATH ")" fi - Le_CertCreateTime=$(date -u "+%s") + Le_CertCreateTime=$(_time) _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" Le_CertCreateTimeStr=$(date -u ) @@ -2113,7 +2121,7 @@ renew() { fi . "$DOMAIN_CONF" - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(date -u "+%s" )" -lt "$Le_NextRenewTime" ] ; then + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ] ; then _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" _info "Add '$(__red '--force')' to force to renew." return $RENEW_SKIP From df1c9d88a82c6346afc4d8813c5259dddc021554 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 22:13:34 +0800 Subject: [PATCH 0281/1348] Update README.md --- README.md | 50 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index e24f5b32..cd824ff6 100644 --- a/README.md +++ b/README.md @@ -46,17 +46,9 @@ https://github.com/Neilpang/acmetest 3. Apache mode 4. Dns mode -# Upgrade from 1.x to 2.x -You can simply uninstall 1.x and re-install 2.x. -2.x is 100% compatible to 1.x. You will feel right at home as if nothing has changed. -# le.sh renamed to acme.sh NOW! - -All configurations are 100% compatible between `le.sh` and `acme.sh`. You just need to uninstall `le.sh` and re-install `acme.sh` again. -Nothing will be broken during the process. - -# How to install +# 1. How to install ### 1. Install online: @@ -113,7 +105,7 @@ root@v1:~# acme.sh -h ``` -# Just issue a cert: +# 2. Just issue a cert: **Example 1:** Single domain. @@ -141,7 +133,7 @@ The issued cert will be renewed every 80 days automatically. More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# Install issued cert to apache/nginx etc. +# 3. Install issued cert to apache/nginx etc. After you issue a cert, you probably want to install the cert with your nginx/apache or other servers you may be using. @@ -160,7 +152,7 @@ Install the issued cert/key to the production apache or nginx path. The cert will be `renewed every 80 days by default` (which is configurable). Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`. -# Use Standalone server to issue cert +# 4. Use Standalone server to issue cert **(requires you be root/sudoer, or you have permission to listen tcp 80 port)** @@ -172,7 +164,7 @@ acme.sh --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# Use Standalone tls server to issue cert +# 5. Use Standalone tls server to issue cert **(requires you be root/sudoer, or you have permission to listen tcp 443 port)** @@ -186,7 +178,7 @@ acme.sh --issue --tls -d aa.com -d www.aa.com -d cp.aa.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# Use Apache mode +# 6. Use Apache mode **(requires you be root/sudoer, since it is required to interact with apache server)** @@ -202,7 +194,7 @@ acme.sh --issue --apache -d aa.com -d www.aa.com -d user.aa.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# Use DNS mode: +# 7. Use DNS mode: Support the `dns-01` challenge. @@ -233,7 +225,7 @@ acme.sh --renew -d aa.com Ok, it's finished. -# Automatic DNS API integration +# 8. Automatic DNS API integration If your DNS provider supports API access, we can use API to automatically issue the certs. @@ -256,7 +248,7 @@ If your DNS provider is not on the supported list above, you can write your own For more details: [How to use dns api](dnsapi) -# Issue ECC certificate: +# 9. Issue ECC certificate: `Let's Encrypt` now can issue **ECDSA** certificates. @@ -286,6 +278,30 @@ Valid values are: 2. **ec-384 (secp384r1, "ECDSA P-384")** 3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)** + +# 10. How to renew the cert + +No, you don't need to renew the certs manually. All the certs will be renewed automatically every 80 days. + +However, you can also force to renew any cert: + +``` +acme.sh --renew -d aa.com --force +``` + +or, for ECC cert: +``` +acme.sh --renew -d aa.com --force --ecc +``` + +# 11. How to upgrade `acme.sh` +acme.sh is in developing, it's strongly recommended to use the latest code. + +You can update acme.sh to the latest code: +``` +acme.sh --upgrade +``` + # Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". From cbcd7e0f86dfc9db87e75e48dbc0c7fdd808d2fc Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Aug 2016 22:27:48 +0800 Subject: [PATCH 0282/1348] minor, fix format --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 118e4879..568450db 100755 --- a/acme.sh +++ b/acme.sh @@ -405,13 +405,13 @@ _createkey() { length=2048 fi - _info "Use length $length" + _debug "Use length $length" if _isEccKey "$length" ; then - _info "Using ec name: $eccname" + _debug "Using ec name: $eccname" openssl ecparam -name $eccname -genkey 2>/dev/null > "$f" else - _info "Using RSA: $length" + _debug "Using RSA: $length" openssl genrsa $length 2>/dev/null > "$f" fi @@ -532,7 +532,7 @@ createAccountKey() { fi if [ -z "$length" ] || [ "$length" = "no" ] ; then - _info "Use default length 2048" + _debug "Use default length 2048" length=2048 fi _debug length "$length" @@ -1766,8 +1766,8 @@ issue() { _info "Found domain api file: $d_api" else _err "Add the following TXT record:" - _err "Domain: $txtdomain" - _err "TXT value: $txt" + _err "Domain: '$(__green $txtdomain)'" + _err "TXT value: '$(__green $txt)'" _err "Please be aware that you prepend _acme-challenge. before your domain" _err "so the resulting subdomain will be: $txtdomain" continue From 10afcaca2fbef40033651f950ab991b13377f0cb Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 27 Aug 2016 13:52:13 +0800 Subject: [PATCH 0283/1348] Support issue cert from existing CSR (#276) fix https://github.com/Neilpang/acme.sh/issues/212 --- acme.sh | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 172 insertions(+), 18 deletions(-) diff --git a/acme.sh b/acme.sh index 568450db..9f525a65 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.4.3 +VER=2.4.4 PROJECT_NAME="acme.sh" @@ -463,6 +463,60 @@ _signcsr() { return $_ret } +#_csrfile +_readSubjectFromCSR() { + _csrfile="$1" + if [ -z "$_csrfile" ] ; then + _usage "_readSubjectFromCSR mycsr.csr" + return 1 + fi + openssl req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 +} + +#_csrfile +#echo comma separated domain list +_readSubjectAltNamesFromCSR() { + _csrfile="$1" + if [ -z "$_csrfile" ] ; then + _usage "_readSubjectAltNamesFromCSR mycsr.csr" + return 1 + fi + + _csrsubj="$(_readSubjectFromCSR "$_csrfile")" + _debug _csrsubj "$_csrsubj" + + _dnsAltnames="$(openssl req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' ')" + _debug _dnsAltnames "$_dnsAltnames" + + if _contains "$_dnsAltnames," "DNS:$_csrsubj," ; then + _debug "AltNames contains subject" + _dnsAltnames="$(echo "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")" + else + _debug "AltNames doesn't contain subject" + fi + + echo "$_dnsAltnames" | sed "s/DNS://g" +} + +#_csrfile +_readKeyLengthFromCSR() { + _csrfile="$1" + if [ -z "$_csrfile" ] ; then + _usage "_readAllDomainListFromCSR mycsr.csr" + return 1 + fi + + _outcsr="$(openssl req -noout -text -in "$_csrfile")" + if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey" ; then + _debug "ECC CSR" + echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' + else + _debug "RSA CSR" + echo "$_outcsr" | _egrep_o "^ *Public-Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + fi +} + + _ss() { _port="$1" @@ -1478,6 +1532,7 @@ _clearupwebbroot() { } +#webroot, domain domainlist keylength issue() { if [ -z "$2" ] ; then _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " @@ -1631,25 +1686,29 @@ issue() { Le_Keylength="" fi - _key=$(_readdomainconf Le_Keylength) - _debug "Read key length:$_key" - if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ] ; then - if ! createDomainKey $Le_Domain $Le_Keylength ; then - _err "Create domain key error." + + if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ] ; then + _info "Signing from existing CSR." + else + _key=$(_readdomainconf Le_Keylength) + _debug "Read key length:$_key" + if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ] ; then + if ! createDomainKey $Le_Domain $Le_Keylength ; then + _err "Create domain key error." + _clearup + return 1 + fi + fi + + if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" ; then + _err "Create CSR error." _clearup return 1 fi fi - + _savedomainconf "Le_Keylength" "$Le_Keylength" - - if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" ; then - _err "Create CSR error." - _clearup - return 1 - fi - vlist="$Le_Vlist" # verify each domain _info "Verify each domain" @@ -2169,6 +2228,82 @@ renewAll() { } +#csr webroot +signcsr(){ + _csrfile="$1" + _csrW="$2" + if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then + _usage "Usage: $PROJECT_ENTRY --signcsr --csr mycsr.csr -w /path/to/webroot/a.com/ " + return 1 + fi + + _initpath + + _csrsubj=$(_readSubjectFromCSR "$_csrfile") + if [ "$?" != "0" ] || [ -z "$_csrsubj" ] ; then + _err "Can not read subject from csr: $_csrfile" + return 1 + fi + + _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") + if [ "$?" != "0" ] ; then + _err "Can not read domain list from csr: $_csrfile" + return 1 + fi + _debug "_csrdomainlist" "$_csrdomainlist" + + _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") + if [ "$?" != "0" ] || [ -z "$_csrkeylength" ] ; then + _err "Can not read key length from csr: $_csrfile" + return 1 + fi + + _initpath "$_csrsubj" "$_csrkeylength" + mkdir -p "$DOMAIN_PATH" + + _info "Copy csr to: $CSR_PATH" + cp "$_csrfile" "$CSR_PATH" + + issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" + +} + +showcsr() { + _csrfile="$1" + _csrd="$2" + if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then + _usage "Usage: $PROJECT_ENTRY --showcsr --csr mycsr.csr" + return 1 + fi + + _initpath + + _csrsubj=$(_readSubjectFromCSR "$_csrfile") + if [ "$?" != "0" ] || [ -z "$_csrsubj" ] ; then + _err "Can not read subject from csr: $_csrfile" + return 1 + fi + + _info "Subject=$_csrsubj" + + _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") + if [ "$?" != "0" ] ; then + _err "Can not read domain list from csr: $_csrfile" + return 1 + fi + _debug "_csrdomainlist" "$_csrdomainlist" + + _info "SubjectAltNames=$_csrdomainlist" + + + _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") + if [ "$?" != "0" ] || [ -z "$_csrkeylength" ] ; then + _err "Can not read key length from csr: $_csrfile" + return 1 + fi + _info "KeyLength=$_csrkeylength" +} + list() { _raw="$1" _initpath @@ -2741,13 +2876,15 @@ Commands: --version, -v Show version info. --install Install $PROJECT_NAME to your system. --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job. - --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT + --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT . --issue Issue a cert. + --signcsr Issue a cert from an existing csr. --installcert Install the issued cert to apache/nginx or any other server. --renew, -r Renew a cert. - --renewAll Renew all the certs + --renewAll Renew all the certs. --revoke Revoke a cert. - --list List all the certs + --list List all the certs. + --showcsr Show the content of a csr. --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically. --cron Run cron job to renew all the certs. @@ -2796,6 +2933,7 @@ Parameters: --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate. --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 '--installcert', '--renew', '--revoke', '--toPkcs' and '--createCSR' + --csr Specifies the input csr. " } @@ -2871,6 +3009,7 @@ _process() { _ca_bundle="" _nocron="" _ecc="" + _csr="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -2894,6 +3033,12 @@ _process() { --issue) _CMD="issue" ;; + --signcsr) + _CMD="signcsr" + ;; + --showcsr) + _CMD="showcsr" + ;; --installcert|-i) _CMD="installcert" ;; @@ -3122,7 +3267,10 @@ _process() { --ecc) _ecc="isEcc" ;; - + --csr) + _csr="$2" + shift + ;; *) _err "Unknown parameter : $1" return 1 @@ -3143,6 +3291,12 @@ _process() { issue) issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" ;; + signcsr) + signcsr "$_csr" "$_webroot" + ;; + showcsr) + showcsr "$_csr" "$_domain" + ;; installcert) installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc" ;; From 8371b030cf00b99b516a4ea2ff09e1ca349974f6 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 27 Aug 2016 14:00:26 +0800 Subject: [PATCH 0284/1348] Issue a cert from existing CSR --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index cd824ff6..7fc302b0 100644 --- a/README.md +++ b/README.md @@ -302,6 +302,11 @@ You can update acme.sh to the latest code: acme.sh --upgrade ``` +# 12. Issue a cert from existing CSR + +https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR + + # Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". From 5980ebc79a74767311456082bd84db86a92c4312 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 27 Aug 2016 15:44:03 +0800 Subject: [PATCH 0285/1348] minor, do not output the key file if using signcsr --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 9f525a65..e797fb63 100755 --- a/acme.sh +++ b/acme.sh @@ -2086,7 +2086,11 @@ issue() { cat "$CERT_PATH" _info "Your cert is in $( __green " $CERT_PATH ")" - _info "Your cert key is in $( __green " $CERT_KEY_PATH ")" + + if [ -f "$CERT_KEY_PATH" ] ; then + _info "Your cert key is in $( __green " $CERT_KEY_PATH ")" + fi + cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ] ; then From 1643b476eb322c431697aab35ae5aa075483ce35 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 27 Aug 2016 20:00:47 +0800 Subject: [PATCH 0286/1348] fix bugs. --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index e797fb63..d4493b06 100755 --- a/acme.sh +++ b/acme.sh @@ -470,7 +470,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - openssl req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 + openssl req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile @@ -485,24 +485,24 @@ _readSubjectAltNamesFromCSR() { _csrsubj="$(_readSubjectFromCSR "$_csrfile")" _debug _csrsubj "$_csrsubj" - _dnsAltnames="$(openssl req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' ')" + _dnsAltnames="$(openssl req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" _debug _dnsAltnames "$_dnsAltnames" if _contains "$_dnsAltnames," "DNS:$_csrsubj," ; then _debug "AltNames contains subject" - _dnsAltnames="$(echo "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")" + _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")" else _debug "AltNames doesn't contain subject" fi - echo "$_dnsAltnames" | sed "s/DNS://g" + printf "%s" "$_dnsAltnames" | sed "s/DNS://g" } #_csrfile _readKeyLengthFromCSR() { _csrfile="$1" if [ -z "$_csrfile" ] ; then - _usage "_readAllDomainListFromCSR mycsr.csr" + _usage "_readKeyLengthFromCSR mycsr.csr" return 1 fi @@ -581,7 +581,7 @@ createAccountKey() { fi length=$1 - if _startswith "$length" "ec-" ; then + if _isEccKey "$length" ; then length=2048 fi From 2d12b68952c554963147f4640670c4964fa2dcc6 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 2 Sep 2016 20:55:11 +0800 Subject: [PATCH 0287/1348] minor --- acme.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index d4493b06..58dbbd0a 100755 --- a/acme.sh +++ b/acme.sh @@ -46,15 +46,23 @@ fi __green() { - printf '\033[1;31;32m' + if [ -t 1 ] ; then + printf '\033[1;31;32m' + fi printf -- "$1" - printf '\033[0m' + if [ -t 1 ] ; then + printf '\033[0m' + fi } __red() { - printf '\033[1;31;40m' + if [ -t 1 ] ; then + printf '\033[1;31;40m' + fi printf -- "$1" - printf '\033[0m' + if [ -t 1 ] ; then + printf '\033[0m' + fi } _info() { From f3e4cea34f2c5086aea000a6ba5d67425bbf26b7 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 2 Sep 2016 22:37:49 +0800 Subject: [PATCH 0288/1348] work in the current dir, without installation (#279) --- acme.sh | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 58dbbd0a..d9e0a12a 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.4.4 +VER=2.4.5 PROJECT_NAME="acme.sh" @@ -8,6 +8,10 @@ PROJECT_ENTRY="acme.sh" PROJECT="https://github.com/Neilpang/$PROJECT_NAME" +DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME" +_SCRIPT_="$0" + + DEFAULT_CA="https://acme-v01.api.letsencrypt.org" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" @@ -91,7 +95,6 @@ _err() { } _usage() { - version _err_e "$@" } @@ -1227,10 +1230,37 @@ _starttlsserver() { #[domain] [keylength] _initpath() { + if [ -z "$_SCRIPT_HOME" ] ; then + if _exists readlink && _exists dirname ; then + _debug "Lets guess script dir." + _debug "_SCRIPT_" "$_SCRIPT_" + _script="$(readlink -f "$_SCRIPT_")" + _debug "_script" "$_script" + _script_home="$(dirname "$_script")" + _debug "_script_home" "$_script_home" + if [ -d "$_script_home" ] ; then + _SCRIPT_HOME="$_script_home" + else + _err "It seems the script home is not correct:$_script_home" + fi + fi + fi + + if [ -z "$LE_WORKING_DIR" ] ; then - LE_WORKING_DIR=$HOME/.$PROJECT_NAME + if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ] ; then + _debug "It seems tha $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" + LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + else + LE_WORKING_DIR="$_SCRIPT_HOME" + fi fi + if [ -z "$LE_WORKING_DIR" ] ; then + _debug "Using default home:$DEFAULT_INSTALL_HOME" + LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + fi + _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" if [ -z "$ACCOUNT_CONF_PATH" ] ; then @@ -2743,6 +2773,11 @@ _installalias() { # nocron install() { + + if [ -z "$LE_WORKING_DIR" ] ; then + LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + fi + _nocron="$1" if ! _initpath ; then _err "Install failed." From 08ee072f11be76d7b9268d836c0912cd7c369a03 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 6 Sep 2016 19:37:41 +0800 Subject: [PATCH 0289/1348] minor, fix color --- acme.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index d9e0a12a..c68215a3 100755 --- a/acme.sh +++ b/acme.sh @@ -47,24 +47,27 @@ if [ -z "$AGREEMENT" ] ; then AGREEMENT="$DEFAULT_AGREEMENT" fi - +__INTERACTIVE="" +if [ -t 1 ] ; then + __INTERACTIVE="1" +fi __green() { - if [ -t 1 ] ; then + if [ "$__INTERACTIVE" ] ; then printf '\033[1;31;32m' fi printf -- "$1" - if [ -t 1 ] ; then + if [ "$__INTERACTIVE" ] ; then printf '\033[0m' fi } __red() { - if [ -t 1 ] ; then + if [ "$__INTERACTIVE" ] ; then printf '\033[1;31;40m' fi printf -- "$1" - if [ -t 1 ] ; then + if [ "$__INTERACTIVE" ] ; then printf '\033[0m' fi } From b0070f03af98cedd49dbf30e1ddd53f4a2849ed0 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 6 Sep 2016 23:26:22 +0800 Subject: [PATCH 0290/1348] support '--pre-hook', '--post-hook' and '--renew-hook' --- acme.sh | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index c68215a3..ec8901c2 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.4.5 +VER=2.5.0 PROJECT_NAME="acme.sh" @@ -1573,6 +1573,58 @@ _clearupwebbroot() { } +_on_before_issue() { + #run pre hook + if [ "$Le_PreHook" ] ; then + _info "Run pre hook:'$Le_PreHook'" + if ! ( + cd "$DOMAIN_PATH" && eval "$Le_PreHook" + ) ; then + _err "Error when run pre hook." + return 1 + fi + fi +} + +_on_issue_err() { + #run the post hook + if [ "$Le_PostHook" ] ; then + _info "Run post hook:'$Le_PostHook'" + if ! ( + cd "$DOMAIN_PATH" && eval "$Le_PostHook" + ) ; then + _err "Error when run post hook." + return 1 + fi + fi +} + +_on_issue_success() { + #run the post hook + if [ "$Le_PostHook" ] ; then + _info "Run post hook:'$Le_PostHook'" + if ! ( + cd "$DOMAIN_PATH" && eval "$Le_PostHook" + ) ; then + _err "Error when run post hook." + return 1 + fi + fi + + #run renew hook + if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ] ; then + _info "Run renew hook:'$Le_RenewHook'" + if ! ( + cd "$DOMAIN_PATH" && eval "$Le_RenewHook" + ) ; then + _err "Error when run renew hook." + return 1 + fi + fi + +} + + #webroot, domain domainlist keylength issue() { if [ -z "$2" ] ; then @@ -1588,6 +1640,9 @@ issue() { Le_RealCACertPath="$7" Le_ReloadCmd="$8" Le_RealFullChainPath="$9" + Le_PreHook="${10}" + Le_PostHook="${11}" + Le_RenewHook="${12}" #remove these later. if [ "$Le_Webroot" = "dns-cf" ] ; then @@ -1619,6 +1674,14 @@ issue() { _savedomainconf "Le_Alt" "$Le_Alt" _savedomainconf "Le_Webroot" "$Le_Webroot" + _savedomainconf "Le_PreHook" "$Le_PreHook" + _savedomainconf "Le_PostHook" "$Le_PostHook" + _savedomainconf "Le_RenewHook" "$Le_RenewHook" + + if ! _on_before_issue ; then + _err "_on_before_issue." + return 1 + fi if [ "$Le_Alt" = "no" ] ; then Le_Alt="" @@ -1628,6 +1691,7 @@ issue() { _info "Standalone mode." if ! _exists "nc" ; then _err "Please install netcat(nc) tools first." + _on_issue_err return 1 fi @@ -1642,6 +1706,7 @@ issue() { _err "$netprc" _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" _err "Please stop it first" + _on_issue_err return 1 fi fi @@ -1660,6 +1725,7 @@ issue() { _err "$netprc" _err "tcp port $Le_TLSPort is already used by $(echo "$netprc" | cut -d : -f 4)" _err "Please stop it first" + _on_issue_err return 1 fi fi @@ -1667,6 +1733,7 @@ issue() { if _hasfield "$Le_Webroot" "apache" ; then if ! _setApache ; then _err "set up apache error. Report error to me." + _on_issue_err return 1 fi else @@ -1683,6 +1750,7 @@ issue() { if [ "$usingApache" ] ; then _restoreApache fi + _on_issue_err return 1 fi fi @@ -1691,6 +1759,7 @@ issue() { if [ "$usingApache" ] ; then _restoreApache fi + _on_issue_err return 1 fi @@ -1715,6 +1784,7 @@ issue() { else _err "Register account Error: $response" _clearup + _on_issue_err return 1 fi ACCOUNT_KEY_HASH="$accountkeyhash" @@ -1737,6 +1807,7 @@ issue() { if ! createDomainKey $Le_Domain $Le_Keylength ; then _err "Create domain key error." _clearup + _on_issue_err return 1 fi fi @@ -1744,6 +1815,7 @@ issue() { if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" ; then _err "Create CSR error." _clearup + _on_issue_err return 1 fi fi @@ -1783,12 +1855,14 @@ issue() { if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" ; then _err "Can not get domain token." _clearup + _on_issue_err return 1 fi if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then _err "new-authz error: $response" _clearup + _on_issue_err return 1 fi @@ -1797,6 +1871,7 @@ issue() { if [ -z "$entry" ] ; then _err "Error, can not get domain token $d" _clearup + _on_issue_err return 1 fi token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" @@ -1876,23 +1951,27 @@ issue() { ( if ! . $d_api ; then _err "Load file $d_api error. Please check your api file and try again." + _on_issue_err return 1 fi addcommand="${_currentRoot}_add" if ! _exists $addcommand ; then _err "It seems that your api file is not correct, it must have a function named: $addcommand" + _on_issue_err return 1 fi if ! $addcommand $txtdomain $txt ; then _err "Error add txt for domain:$txtdomain" + _on_issue_err return 1 fi ) if [ "$?" != "0" ] ; then _clearup + _on_issue_err return 1 fi dnsadded='1' @@ -1904,6 +1983,7 @@ issue() { _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup + _on_issue_err return 1 fi @@ -1952,6 +2032,7 @@ issue() { _startserver "$keyauthorization" & if [ "$?" != "0" ] ; then _clearup + _on_issue_err return 1 fi serverproc="$!" @@ -2017,6 +2098,7 @@ issue() { _err "Start tls server error." _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup + _on_issue_err return 1 fi fi @@ -2025,6 +2107,7 @@ issue() { _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup + _on_issue_err return 1 fi @@ -2032,6 +2115,7 @@ issue() { _err "$d:Challenge error: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup + _on_issue_err return 1 fi @@ -2046,6 +2130,7 @@ issue() { _err "$d:Timeout" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup + _on_issue_err return 1 fi @@ -2057,6 +2142,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup + _on_issue_err return 1 fi _debug2 original "$response" @@ -2090,6 +2176,7 @@ issue() { fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup + _on_issue_err return 1; fi @@ -2099,6 +2186,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup + _on_issue_err return 1 fi @@ -2112,6 +2200,7 @@ issue() { if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" ; then _err "Sign failed." + _on_issue_err return 1 fi @@ -2144,6 +2233,7 @@ issue() { if [ -z "$Le_LinkCert" ] ; then response="$(echo $response | _dbase64 "multiline" | _normalizeJson )" _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" + _on_issue_err return 1 fi @@ -2195,6 +2285,7 @@ issue() { Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" + _on_issue_success if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ] ; then _installcert @@ -2232,7 +2323,7 @@ renew() { fi IS_RENEW="1" - issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" + issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" res=$? IS_RENEW="" @@ -2984,6 +3075,9 @@ Parameters: --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 '--installcert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. + --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. + --renew-hook Command to be run once for each successfully renewed certificate. " } @@ -3060,6 +3154,9 @@ _process() { _nocron="" _ecc="" _csr="" + _pre_hook="" + _post_hook="" + _renew_hook="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -3321,6 +3418,18 @@ _process() { _csr="$2" shift ;; + --pre-hook) + _pre_hook="$2" + shift + ;; + --post-hook) + _post_hook="$2" + shift + ;; + --renew-hook) + _renew_hook="$2" + shift + ;; *) _err "Unknown parameter : $1" return 1 @@ -3339,7 +3448,7 @@ _process() { uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" ;; signcsr) signcsr "$_csr" "$_webroot" From 7b164426566d8c1a6eb085b40128c6ec5dd5a993 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 10 Sep 2016 18:04:59 +0800 Subject: [PATCH 0291/1348] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index ec8901c2..1e8fd545 100755 --- a/acme.sh +++ b/acme.sh @@ -797,6 +797,7 @@ _time() { _mktemp() { if _exists mktemp ; then mktemp + return fi if [ -d "/tmp" ] ; then echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" From 0c9546ccb0d1de464e43ef16e460e83a1c43d3ad Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 15 Sep 2016 10:41:47 +0800 Subject: [PATCH 0292/1348] fix https://github.com/Neilpang/acme.sh/issues/288 add --ocsp-must-staple, --ocsp --- acme.sh | 66 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/acme.sh b/acme.sh index 1e8fd545..76015113 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.0 +VER=2.5.1 PROJECT_NAME="acme.sh" @@ -163,11 +163,11 @@ _hasfield() { for f in $(echo "$_str" | tr ',' ' ') ; do if [ "$f" = "$_field" ] ; then - _debug "'$_str' contains '$_field'" + _debug2 "'$_str' contains '$_field'" return 0 #contains ok fi done - _debug "'$_str' does not contain '$_field'" + _debug2 "'$_str' does not contain '$_field'" return 1 #not contains } @@ -440,16 +440,20 @@ _createcsr() { _debug _createcsr domain="$1" domainlist="$2" - key="$3" + csrkey="$3" csr="$4" csrconf="$5" _debug2 domain "$domain" _debug2 domainlist "$domainlist" + _debug2 csrkey "$csrkey" + _debug2 csr "$csr" + _debug2 csrconf "$csrconf" + + 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" ]; then #single domain _info "Single domain" "$domain" - printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$csrconf" - openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr" else if _contains "$domainlist" "," ; then alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" @@ -458,9 +462,13 @@ _createcsr() { fi #multi _info "Multi domain" "$alt" - printf -- "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nsubjectAltName=$alt" > "$csrconf" - openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr" + printf -- "\nsubjectAltName=$alt" >> "$csrconf" + fi + if [ "$Le_OCSP_Stable" ] ; then + _savedomainconf Le_OCSP_Stable "$Le_OCSP_Stable" + printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >> "$csrconf" fi + openssl req -new -sha256 -key "$csrkey" -subj "/CN=$domain" -config "$csrconf" -out "$csr" } #_signcsr key csr conf cert @@ -1066,56 +1074,56 @@ _setopt() { #_savedomainconf key value #save to domain.conf _savedomainconf() { - key="$1" - value="$2" + _sdkey="$1" + _sdvalue="$2" if [ "$DOMAIN_CONF" ] ; then - _setopt "$DOMAIN_CONF" "$key" "=" "\"$value\"" + _setopt "$DOMAIN_CONF" "$_sdkey" "=" "\"$_sdvalue\"" else - _err "DOMAIN_CONF is empty, can not save $key=$value" + _err "DOMAIN_CONF is empty, can not save $_sdkey=$_sdvalue" fi } #_cleardomainconf key _cleardomainconf() { - key="$1" + _sdkey="$1" if [ "$DOMAIN_CONF" ] ; then - _sed_i "s/^$key.*$//" "$DOMAIN_CONF" + _sed_i "s/^$_sdkey.*$//" "$DOMAIN_CONF" else - _err "DOMAIN_CONF is empty, can not save $key=$value" + _err "DOMAIN_CONF is empty, can not save $_sdkey=$value" fi } #_readdomainconf key _readdomainconf() { - key="$1" + _sdkey="$1" if [ "$DOMAIN_CONF" ] ; then ( - eval $(grep "^$key *=" "$DOMAIN_CONF") - eval "printf \"%s\" \"\$$key\"" + eval $(grep "^$_sdkey *=" "$DOMAIN_CONF") + eval "printf \"%s\" \"\$$_sdkey\"" ) else - _err "DOMAIN_CONF is empty, can not read $key" + _err "DOMAIN_CONF is empty, can not read $_sdkey" fi } #_saveaccountconf key value _saveaccountconf() { - key="$1" - value="$2" + _sckey="$1" + _scvalue="$2" if [ "$ACCOUNT_CONF_PATH" ] ; then - _setopt "$ACCOUNT_CONF_PATH" "$key" "=" "\"$value\"" + _setopt "$ACCOUNT_CONF_PATH" "$_sckey" "=" "\"$_scvalue\"" else - _err "ACCOUNT_CONF_PATH is empty, can not save $key=$value" + _err "ACCOUNT_CONF_PATH is empty, can not save $_sckey=$_scvalue" fi } #_clearaccountconf key _clearaccountconf() { - key="$1" + _scvalue="$1" if [ "$ACCOUNT_CONF_PATH" ] ; then - _sed_i "s/^$key.*$//" "$ACCOUNT_CONF_PATH" + _sed_i "s/^$_scvalue.*$//" "$ACCOUNT_CONF_PATH" else - _err "ACCOUNT_CONF_PATH is empty, can not clear $key" + _err "ACCOUNT_CONF_PATH is empty, can not clear $_scvalue" fi } @@ -1357,7 +1365,7 @@ _initpath() { fi if [ -z "$DOMAIN_SSL_CONF" ] ; then - DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.ssl.conf" + DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf" fi if [ -z "$CSR_PATH" ] ; then @@ -3079,6 +3087,7 @@ Parameters: --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. --renew-hook Command to be run once for each successfully renewed certificate. + --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. " } @@ -3431,6 +3440,9 @@ _process() { _renew_hook="$2" shift ;; + --ocsp-must-staple|--ocsp) + Le_OCSP_Stable="1" + ;; *) _err "Unknown parameter : $1" return 1 From 811bff6db072bf7251c271e4d9109d577ea66a57 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 17 Sep 2016 12:29:50 +0800 Subject: [PATCH 0293/1348] minor, hide debug info --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 76015113..efd27dbb 100755 --- a/acme.sh +++ b/acme.sh @@ -1172,7 +1172,7 @@ _stopserver(){ _debug2 "Le_HTTPPort" "$Le_HTTPPort" if [ "$Le_HTTPPort" ] ; then - if [ "$DEBUG" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; then _get "http://localhost:$Le_HTTPPort" "" 1 else _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1 @@ -1181,7 +1181,7 @@ _stopserver(){ _debug2 "Le_TLSPort" "$Le_TLSPort" if [ "$Le_TLSPort" ] ; then - if [ "$DEBUG" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; _get "https://localhost:$Le_TLSPort" "" 1 _get "https://localhost:$Le_TLSPort" "" 1 else From 3324c0ae797b24d569012f16a3516dfe7f05bf95 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 17 Sep 2016 12:52:47 +0800 Subject: [PATCH 0294/1348] opps --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index efd27dbb..7cc7bb14 100755 --- a/acme.sh +++ b/acme.sh @@ -1181,7 +1181,7 @@ _stopserver(){ _debug2 "Le_TLSPort" "$Le_TLSPort" if [ "$Le_TLSPort" ] ; then - if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; + if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; then _get "https://localhost:$Le_TLSPort" "" 1 _get "https://localhost:$Le_TLSPort" "" 1 else From 267f283a31c7df68ae5852d0b04d8ef6bb36a1b3 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 18 Sep 2016 13:06:15 +0800 Subject: [PATCH 0295/1348] fix bug, upgrade in current dir without installation. --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7cc7bb14..f4791bc2 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.1 +VER=2.5.2 PROJECT_NAME="acme.sh" @@ -3125,6 +3125,8 @@ _installOnline() { upgrade() { if ( + _initpath + export LE_WORKING_DIR cd "$LE_WORKING_DIR" _installOnline "nocron" ) ; then From 5ea6e9c9c0b99168d4c85b6ae35f3455a9282281 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 19 Sep 2016 23:07:43 +0800 Subject: [PATCH 0296/1348] support "--logfile" --- acme.sh | 78 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/acme.sh b/acme.sh index f4791bc2..98782d1f 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.2 +VER=2.5.3 PROJECT_NAME="acme.sh" @@ -72,27 +72,31 @@ __red() { fi } +__mytee() { + tee -a $1 +} + _info() { if [ -z "$2" ] ; then - printf -- "[$(date)] $1" + printf -- "[$(date)] $1" | __mytee $LOG_FILE else - printf -- "[$(date)] $1='$2'" + printf -- "[$(date)] $1='$2'" | __mytee $LOG_FILE fi - printf "\n" + printf "\n" | __mytee $LOG_FILE } _err_e() { if [ -z "$2" ] ; then - __red "$1" >&2 + __red "$1" | __mytee $LOG_FILE >&2 else - __red "$1='$2'" >&2 + __red "$1='$2'" | __mytee $LOG_FILE >&2 fi - printf "\n" >&2 + printf "\n" | __mytee $LOG_FILE >&2 } _err() { - printf -- "[$(date)] " >&2 + printf -- "[$(date)] " | __mytee $LOG_FILE >&2 _err_e "$@" return 1 } @@ -107,12 +111,12 @@ _debug() { fi if [ -z "$2" ] ; then - printf -- "[$(date)] $1" >&2 + printf -- "[$(date)] $1" | __mytee $LOG_FILE >&2 else - printf -- "[$(date)] $1='$2'" >&2 + printf -- "[$(date)] $1='$2'" | __mytee $LOG_FILE >&2 fi - printf "\n" >&2 + printf "\n" | __mytee $LOG_FILE >&2 return 0 } @@ -1239,9 +1243,7 @@ _starttlsserver() { _debug serverproc $serverproc } -#[domain] [keylength] -_initpath() { - +__initHome() { if [ -z "$_SCRIPT_HOME" ] ; then if _exists readlink && _exists dirname ; then _debug "Lets guess script dir." @@ -1284,7 +1286,13 @@ _initpath() { if [ -z "$ACCOUNT_CONF_PATH" ] ; then ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi - +} + +#[domain] [keylength] +_initpath() { + + __initHome + if [ -f "$ACCOUNT_CONF_PATH" ] ; then . "$ACCOUNT_CONF_PATH" fi @@ -2741,6 +2749,8 @@ _initconf() { #ACCOUNT_KEY_PATH=\"/path/to/account.key\" #CERT_HOME=\"/path/to/cert/home\" +#LOG_FILE=\"/var/log/$PROJECT_NAME.log\" + #STAGE=1 # Use the staging api #FORCE=1 # Force to issue cert #DEBUG=1 # Debug mode @@ -3058,6 +3068,7 @@ Parameters: --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. + --logfile /path/to/logfile Specifies the log file. These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: @@ -3138,6 +3149,17 @@ upgrade() { fi } +_processAccountConf() { + if [ "$_useragent" ] ; then + _saveaccountconf "USER_AGENT" "$_useragent" + fi + + if [ "$_accountemail" ] ; then + _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" + fi + +} + _process() { _CMD="" _domain="" @@ -3169,6 +3191,7 @@ _process() { _pre_hook="" _post_hook="" _renew_hook="" + _logfile="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -3445,6 +3468,12 @@ _process() { --ocsp-must-staple|--ocsp) Le_OCSP_Stable="1" ;; + --logfile) + _logfile="$2" + LOG_FILE="$_logfile" + shift + ;; + *) _err "Unknown parameter : $1" return 1 @@ -3454,6 +3483,14 @@ _process() { shift 1 done + if [ "${_CMD}" != "install" ] ; then + __initHome + if [ "$_logfile" ] ; then + _saveaccountconf "LOG_FILE" "$_logfile" + fi + _processAccountConf + fi + if [ "$DEBUG" ] ; then version fi @@ -3513,13 +3550,12 @@ _process() { return $_ret fi - if [ "$_useragent" ] ; then - _saveaccountconf "USER_AGENT" "$_useragent" - fi - if [ "$_accountemail" ] ; then - _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" + if [ "${_CMD}" = "install" ] ; then + if [ "$_logfile" ] ; then + _saveaccountconf "LOG_FILE" "$_logfile" + fi + _processAccountConf fi - } From d0871bdae3022cd2c1db9c4935c45a64103a9668 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 20 Sep 2016 19:08:02 +0800 Subject: [PATCH 0297/1348] rename "--logfile" to "--log", and give a default log file --- acme.sh | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 98782d1f..e6f01aad 100755 --- a/acme.sh +++ b/acme.sh @@ -16,6 +16,7 @@ DEFAULT_CA="https://acme-v01.api.letsencrypt.org" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" DEFAULT_USER_AGENT="$PROJECT_ENTRY client v$VER : $PROJECT" +DEFAULT_ACCOUNT_EMAIL="" STAGE_CA="https://acme-staging.api.letsencrypt.org" @@ -1286,6 +1287,8 @@ __initHome() { if [ -z "$ACCOUNT_CONF_PATH" ] ; then ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi + + DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log" } #[domain] [keylength] @@ -2749,7 +2752,7 @@ _initconf() { #ACCOUNT_KEY_PATH=\"/path/to/account.key\" #CERT_HOME=\"/path/to/cert/home\" -#LOG_FILE=\"/var/log/$PROJECT_NAME.log\" +#LOG_FILE=\"$DEFAULT_LOG_FILE\" #STAGE=1 # Use the staging api #FORCE=1 # Force to issue cert @@ -3029,6 +3032,7 @@ version() { } showhelp() { + _initpath version echo "Usage: $PROJECT_ENTRY command ...[parameters].... Commands: @@ -3068,7 +3072,7 @@ Parameters: --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. - --logfile /path/to/logfile Specifies the log file. + --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: @@ -3152,10 +3156,14 @@ upgrade() { _processAccountConf() { if [ "$_useragent" ] ; then _saveaccountconf "USER_AGENT" "$_useragent" + elif [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ] ; then + _saveaccountconf "USER_AGENT" "$USER_AGENT" fi if [ "$_accountemail" ] ; then _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" + elif [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ] ; then + _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL" fi } @@ -3192,6 +3200,7 @@ _process() { _post_hook="" _renew_hook="" _logfile="" + _log="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -3468,10 +3477,15 @@ _process() { --ocsp-must-staple|--ocsp) Le_OCSP_Stable="1" ;; - --logfile) + --log|--logfile) + _log="1" _logfile="$2" + if [ -z "$_logfile" ] || _startswith "$_logfile" '-' ; then + _logfile="" + else + shift + fi LOG_FILE="$_logfile" - shift ;; *) @@ -3485,9 +3499,13 @@ _process() { if [ "${_CMD}" != "install" ] ; then __initHome + if [ "$_log" ] && [ -z "$_logfile" ] ; then + _logfile="$DEFAULT_LOG_FILE" + fi if [ "$_logfile" ] ; then _saveaccountconf "LOG_FILE" "$_logfile" fi + LOG_FILE="$_logfile" _processAccountConf fi @@ -3551,8 +3569,11 @@ _process() { fi if [ "${_CMD}" = "install" ] ; then - if [ "$_logfile" ] ; then - _saveaccountconf "LOG_FILE" "$_logfile" + if [ "$_log" ] ; then + if [ -z "$LOG_FILE" ] ; then + LOG_FILE="$DEFAULT_LOG_FILE" + fi + _saveaccountconf "LOG_FILE" "$LOG_FILE" fi _processAccountConf fi From 89002ed29810fd052b0be575611c3802d8e85796 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 20 Sep 2016 20:22:25 +0800 Subject: [PATCH 0298/1348] support AUTO_UPGRADE. In the cron job, try to upgrade acme.sh if "AUTO_UPGRADE" is set. --- acme.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e6f01aad..24bf6087 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.3 +VER=2.5.4 PROJECT_NAME="acme.sh" @@ -2754,6 +2754,8 @@ _initconf() { #LOG_FILE=\"$DEFAULT_LOG_FILE\" +#AUTO_UPGRADE="" + #STAGE=1 # Use the staging api #FORCE=1 # Force to issue cert #DEBUG=1 # Debug mode @@ -3020,6 +3022,19 @@ uninstall() { cron() { IN_CRON=1 + _initpath + if [ "$AUTO_UPGRADE" ] ; then + export LE_WORKING_DIR + ( + . $LE_WORKING_DIR/$PROJECT_ENTRY >/dev/null + if ! upgrade ; then + _err "Cron:Upgrade failed!" + return 1 + fi + ) + . $LE_WORKING_DIR/$PROJECT_ENTRY >/dev/null + _info "Auto upgraded to: $VER" + fi renewAll _ret="$?" IN_CRON="" From 1ab630435d192dfc0d77409492294acb9d0078bb Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 20 Sep 2016 20:34:33 +0800 Subject: [PATCH 0299/1348] fix color when upgrade in cronjob --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 24bf6087..5f7225be 100755 --- a/acme.sh +++ b/acme.sh @@ -3033,6 +3033,11 @@ cron() { fi ) . $LE_WORKING_DIR/$PROJECT_ENTRY >/dev/null + + if [ -t 1 ] ; then + __INTERACTIVE="1" + fi + _info "Auto upgraded to: $VER" fi renewAll From 028e17475f11777a19087f39ee7542cf7bbcd056 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 20 Sep 2016 21:03:43 +0800 Subject: [PATCH 0300/1348] minor, renew time minus 1 day --- acme.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 5f7225be..76d76e7c 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.4 +VER=2.5.5 PROJECT_NAME="acme.sh" @@ -2300,11 +2300,14 @@ issue() { fi Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) - _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" + Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" - + + Le_NextRenewTime=$(_math $Le_NextRenewTime - 86400) + _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" + _on_issue_success if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ] ; then From 251d1c5c9f7c77fe6b308447f63b29b3ff0f591d Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 20 Sep 2016 22:23:49 +0800 Subject: [PATCH 0301/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 76d76e7c..9b8e11dd 100755 --- a/acme.sh +++ b/acme.sh @@ -2757,7 +2757,7 @@ _initconf() { #LOG_FILE=\"$DEFAULT_LOG_FILE\" -#AUTO_UPGRADE="" +#AUTO_UPGRADE=\"1\" #STAGE=1 # Use the staging api #FORCE=1 # Force to issue cert From 276b51d927a18ff5062984b2b2fa4135f4be1f84 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 21 Sep 2016 13:09:22 +0800 Subject: [PATCH 0302/1348] minor --- acme.sh | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index 9b8e11dd..2882d8b4 100755 --- a/acme.sh +++ b/acme.sh @@ -1177,7 +1177,7 @@ _stopserver(){ _debug2 "Le_HTTPPort" "$Le_HTTPPort" if [ "$Le_HTTPPort" ] ; then - if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ] ; then _get "http://localhost:$Le_HTTPPort" "" 1 else _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1 @@ -1186,7 +1186,7 @@ _stopserver(){ _debug2 "Le_TLSPort" "$Le_TLSPort" if [ "$Le_TLSPort" ] ; then - if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ] ; then _get "https://localhost:$Le_TLSPort" "" 1 _get "https://localhost:$Le_TLSPort" "" 1 else @@ -2191,6 +2191,7 @@ issue() { fi if [ "$DEBUG" ] ; then if [ "$vtype" = "$VTYPE_HTTP" ] ; then + _debug "Debug: get token url." _get "http://$d/.well-known/acme-challenge/$token" fi fi @@ -3610,14 +3611,9 @@ if [ "$INSTALLONLINE" ] ; then exit fi -if [ -z "$1" ] ; then - showhelp -else - if echo "$1" | grep "^-" >/dev/null 2>&1 ; then - _process "$@" - else - "$@" - fi -fi +[ -z "$1" ] && showhelp && exit + + +if _startswith "$1" '-' ; then _process "$@" ; else "$@"; fi ; exit From ecd685755b1a2efa1c4de06e74b2fe9fd1495fd4 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 21 Sep 2016 13:18:46 +0800 Subject: [PATCH 0303/1348] fix auto upgrade --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2882d8b4..791a31db 100755 --- a/acme.sh +++ b/acme.sh @@ -3612,7 +3612,7 @@ if [ "$INSTALLONLINE" ] ; then fi -[ -z "$1" ] && showhelp && exit +[ -z "$1" ] && showhelp if _startswith "$1" '-' ; then _process "$@" ; else "$@"; fi ; exit From e69a7c38d98ecac1ae9a892edb76e6ce0b888c53 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 21 Sep 2016 13:27:05 +0800 Subject: [PATCH 0304/1348] fix auto upgrade --- acme.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 791a31db..df4c7e4a 100755 --- a/acme.sh +++ b/acme.sh @@ -3612,8 +3612,9 @@ if [ "$INSTALLONLINE" ] ; then fi -[ -z "$1" ] && showhelp +[ -z "$1" ] && showhelp -if _startswith "$1" '-' ; then _process "$@" ; else "$@"; fi ; exit + +if _startswith "$1" '-' ; then _process "$@" ; else "$@"; fi ; \ No newline at end of file From 319e0ae3cf5d6fe6577a01ac71d30f057367457d Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 21 Sep 2016 13:39:39 +0800 Subject: [PATCH 0305/1348] fix auto upgrade --- acme.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index df4c7e4a..b9f69bc9 100755 --- a/acme.sh +++ b/acme.sh @@ -3613,8 +3613,11 @@ fi -[ -z "$1" ] && showhelp +main() { + [ -z "$1" ] && showhelp && return + if _startswith "$1" '-' ; then _process "$@"; else "$@";fi +} -if _startswith "$1" '-' ; then _process "$@" ; else "$@"; fi ; \ No newline at end of file +main "$@" \ No newline at end of file From 18e46962c2c26c676b31a26f196f078aa26b0a3d Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 22 Sep 2016 13:15:25 +0800 Subject: [PATCH 0306/1348] fix https://github.com/Neilpang/acme.sh/issues/297 --- acme.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index b9f69bc9..91557b8d 100755 --- a/acme.sh +++ b/acme.sh @@ -1244,12 +1244,20 @@ _starttlsserver() { _debug serverproc $serverproc } +#file +_readlink() { + _rf="$1" + if ! readlink -f "$_rf" 2>/dev/null; then + readlink "$_rf" + fi +} + __initHome() { if [ -z "$_SCRIPT_HOME" ] ; then if _exists readlink && _exists dirname ; then _debug "Lets guess script dir." _debug "_SCRIPT_" "$_SCRIPT_" - _script="$(readlink -f "$_SCRIPT_")" + _script="$(_readlink "$_SCRIPT_")" _debug "_script" "$_script" _script_home="$(dirname "$_script")" _debug "_script_home" "$_script_home" From cfdaff5a46ed6bbd4ea716a1e6f0dc8b79a1bdf7 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 22 Sep 2016 20:36:33 +0800 Subject: [PATCH 0307/1348] fix cf --- dnsapi/dns_cf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 23dea1c8..7cd286a1 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -48,7 +48,7 @@ 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 $response | grep $fulldomain > /dev/null ; then + if printf -- "%s" "$response" | grep $fulldomain > /dev/null ; then _info "Added, sleeping 10 seconds" sleep 10 #todo: check if the record takes effect From 7da50703fbd3b1159c1840ae59fb367b6d059d40 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 22 Sep 2016 21:38:11 +0800 Subject: [PATCH 0308/1348] minor --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 91557b8d..c18a7c35 100755 --- a/acme.sh +++ b/acme.sh @@ -1248,6 +1248,10 @@ _starttlsserver() { _readlink() { _rf="$1" if ! readlink -f "$_rf" 2>/dev/null; then + if _startswith "$_rf" "\./$PROJECT_ENTRY" ; then + printf -- "%s" "$(pwd)/$PROJECT_ENTRY" + return 0 + fi readlink "$_rf" fi } @@ -1272,7 +1276,7 @@ __initHome() { if [ -z "$LE_WORKING_DIR" ] ; then if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ] ; then - _debug "It seems tha $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" + _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" else LE_WORKING_DIR="$_SCRIPT_HOME" @@ -1283,6 +1287,7 @@ __initHome() { _debug "Using default home:$DEFAULT_INSTALL_HOME" LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" fi + export LE_WORKING_DIR _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" From 0c00e870c6ab2455a3840d889441afc4a2ca0087 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 22 Sep 2016 23:17:50 +0800 Subject: [PATCH 0309/1348] Support Authorization deactivation https://github.com/Neilpang/acme.sh/issues/291 --- acme.sh | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index c18a7c35..60210c73 100755 --- a/acme.sh +++ b/acme.sh @@ -1883,7 +1883,7 @@ issue() { vtype="$VTYPE_TLS" fi - _info "Getting token for domain" $d + _info "Getting new-authz for domain" $d if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" ; then _err "Can not get domain token." @@ -2720,6 +2720,82 @@ revoke() { return 1 } + +#domain vtype +_deactivate() { + _d_domain="$1" + _d_type="$2" + _initpath + + _d_i=0 + _d_max_retry=9 + while [ "$_d_i" -lt "$_d_max_retry" ] ; + do + _d_i="$(_math $_d_i + 1)" + if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$_d_domain\"}}" ; then + _err "Can not get domain token." + return 1 + fi + + authzUri="$(echo "$responseHeaders" | grep "^Location:" | cut -d ' ' -f 2)" + _info "authzUri" "$authzUri" + + if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then + _err "new-authz error: $response" + return 1 + fi + + entry="$(printf "%s\n" "$response" | _egrep_o '[^{]*"status":"valid","uri"[^}]*')" + _debug entry "$entry" + + if [ -z "$entry" ] ; then + _info "No valid entry found." + break + fi + + _vtype="$(printf "%s\n" "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')" + _debug _vtype $_vtype + _info "Found $_vtype" + + + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" + _debug uri $uri + + if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ] ; then + _info "Skip $_vtype" + continue + fi + + _info "Deactivate: $_vtype" + + if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" ; then + _err "Can not deactivate $_vtype." + return 1 + fi + + done + _debug "$_d_i" + if [ "$_d_i" -lt "$_d_max_retry" ] ; then + _info "Deactivated success!" + else + _err "Deactivate failed." + fi + +} + +deactivate() { + _d_domain="$1" + _d_type="$2" + _initpath + + if [ -z "$_d_domain" ] ; then + _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com" + return 1 + fi + + _deactivate "$_d_domain" $_d_type +} + # Detect profile file if not specified as environment variable _detect_profile() { if [ -n "$PROFILE" -a -f "$PROFILE" ] ; then @@ -3093,6 +3169,7 @@ Commands: --createAccountKey, -cak Create an account private key, professional use. --createDomainKey, -cdk Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. + --deactivate Deactivate the domain authz, professional use. Parameters: --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. @@ -3303,7 +3380,9 @@ _process() { --createCSR|--createcsr|-ccr) _CMD="createCSR" ;; - + --deactivate) + _CMD="deactivate" + ;; --domain|-d) _dvalue="$2" @@ -3575,6 +3654,9 @@ _process() { revoke) revoke "$_domain" "$_ecc" ;; + deactivate) + deactivate "$_domain" + ;; list) list "$_listraw" ;; From 48f02fb61bb4874218292a6d724a35dd95cc7982 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 22 Sep 2016 23:23:27 +0800 Subject: [PATCH 0310/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 60210c73..5b9f2a7f 100755 --- a/acme.sh +++ b/acme.sh @@ -2737,7 +2737,7 @@ _deactivate() { return 1 fi - authzUri="$(echo "$responseHeaders" | grep "^Location:" | cut -d ' ' -f 2)" + authzUri="$(echo "$responseHeaders" | grep "^Location:" | cut -d ' ' -f 2 | tr -d "\r\n")" _info "authzUri" "$authzUri" if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then From fb2029e7175ae7ed3627a5d2570004b0e547659f Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 22 Sep 2016 23:25:32 +0800 Subject: [PATCH 0311/1348] add more info --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5b9f2a7f..97936078 100755 --- a/acme.sh +++ b/acme.sh @@ -2749,7 +2749,7 @@ _deactivate() { _debug entry "$entry" if [ -z "$entry" ] ; then - _info "No valid entry found." + _info "No more valid entry found." break fi @@ -2773,6 +2773,8 @@ _deactivate() { return 1 fi + _info "Deactivate: $_vtype success." + done _debug "$_d_i" if [ "$_d_i" -lt "$_d_max_retry" ] ; then From 3f4513b3a9087fa6c3b41ccef988aafa3754831f Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 23 Sep 2016 22:35:13 +0800 Subject: [PATCH 0312/1348] Support deactivate in bulk --- acme.sh | 55 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/acme.sh b/acme.sh index 97936078..64172445 100755 --- a/acme.sh +++ b/acme.sh @@ -29,6 +29,8 @@ MAX_RENEW=80 DEFAULT_DNS_SLEEP=120 +NO_VALUE="no" + W_TLS="tls" STATE_VERIFIED="verified_ok" @@ -456,7 +458,7 @@ _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" ]; then + if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then #single domain _info "Single domain" "$domain" else @@ -612,7 +614,7 @@ createAccountKey() { length=2048 fi - if [ -z "$length" ] || [ "$length" = "no" ] ; then + if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ] ; then _debug "Use default length 2048" length=2048 fi @@ -1716,11 +1718,11 @@ issue() { return 1 fi - if [ "$Le_Alt" = "no" ] ; then + if [ "$Le_Alt" = "$NO_VALUE" ] ; then Le_Alt="" fi - if _hasfield "$Le_Webroot" "no" ; then + if _hasfield "$Le_Webroot" "$NO_VALUE" ; then _info "Standalone mode." if ! _exists "nc" ; then _err "Please install netcat(nc) tools first." @@ -1774,7 +1776,7 @@ issue() { fi if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then - _acck="no" + _acck="$NO_VALUE" if [ "$Le_Keylength" ] ; then _acck="$Le_Keylength" fi @@ -1826,7 +1828,7 @@ issue() { _info "Skip register account key" fi - if [ "$Le_Keylength" = "no" ] ; then + if [ "$Le_Keylength" = "$NO_VALUE" ] ; then Le_Keylength="" fi @@ -2060,7 +2062,7 @@ issue() { if [ "$vtype" = "$VTYPE_HTTP" ] ; then - if [ "$_currentRoot" = "no" ] ; then + if [ "$_currentRoot" = "$NO_VALUE" ] ; then _info "Standalone mode server" _startserver "$keyauthorization" & if [ "$?" != "0" ] ; then @@ -2541,19 +2543,19 @@ _installcert() { _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd" _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath" - if [ "$Le_RealCertPath" = "no" ] ; then + if [ "$Le_RealCertPath" = "$NO_VALUE" ] ; then Le_RealCertPath="" fi - if [ "$Le_RealKeyPath" = "no" ] ; then + if [ "$Le_RealKeyPath" = "$NO_VALUE" ] ; then Le_RealKeyPath="" fi - if [ "$Le_RealCACertPath" = "no" ] ; then + if [ "$Le_RealCACertPath" = "$NO_VALUE" ] ; then Le_RealCACertPath="" fi - if [ "$Le_ReloadCmd" = "no" ] ; then + if [ "$Le_ReloadCmd" = "$NO_VALUE" ] ; then Le_ReloadCmd="" fi - if [ "$Le_RealFullChainPath" = "no" ] ; then + if [ "$Le_RealFullChainPath" = "$NO_VALUE" ] ; then Le_RealFullChainPath="" fi @@ -2738,7 +2740,7 @@ _deactivate() { fi authzUri="$(echo "$responseHeaders" | grep "^Location:" | cut -d ' ' -f 2 | tr -d "\r\n")" - _info "authzUri" "$authzUri" + _debug "authzUri" "$authzUri" if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then _err "new-authz error: $response" @@ -2786,16 +2788,21 @@ _deactivate() { } deactivate() { - _d_domain="$1" + _d_domain_list="$1" _d_type="$2" _initpath - - if [ -z "$_d_domain" ] ; then - _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com" + _debug _d_domain_list "$_d_domain_list" + if [ -z "$(echo $_d_domain_list | cut -d , -f 1 )" ] ; then + _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" return 1 fi - - _deactivate "$_d_domain" $_d_type + for _d_dm in $(echo "$_d_domain_list" | tr ',' ' ' ) ; + do + if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ] ; then + continue + fi + _deactivate "$_d_dm" $_d_type + done } # Detect profile file if not specified as environment variable @@ -3287,7 +3294,7 @@ _processAccountConf() { _process() { _CMD="" _domain="" - _altdomains="no" + _altdomains="$NO_VALUE" _webroot="" _keylength="" _accountkeylength="" @@ -3398,7 +3405,7 @@ _process() { if [ -z "$_domain" ] ; then _domain="$_dvalue" else - if [ "$_altdomains" = "no" ] ; then + if [ "$_altdomains" = "$NO_VALUE" ] ; then _altdomains="$_dvalue" else _altdomains="$_altdomains,$_dvalue" @@ -3433,7 +3440,7 @@ _process() { shift ;; --standalone) - wvalue="no" + wvalue="$NO_VALUE" if [ -z "$_webroot" ] ; then _webroot="$wvalue" else @@ -3476,7 +3483,7 @@ _process() { --keylength|-k) _keylength="$2" - if [ "$_accountkeylength" = "no" ] ; then + if [ "$_accountkeylength" = "$NO_VALUE" ] ; then _accountkeylength="$2" fi shift @@ -3657,7 +3664,7 @@ _process() { revoke "$_domain" "$_ecc" ;; deactivate) - deactivate "$_domain" + deactivate "$_domain,$_altdomains" ;; list) list "$_listraw" From 0463b5d6cdc63a69977b89a19791edc560b43d7a Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 23 Sep 2016 23:14:03 +0800 Subject: [PATCH 0313/1348] support "--local-address" to specify a listening ip address in standalone mode if the server have multiple ips. By default, the standalone server listens to 0.0.0.0 --- acme.sh | 208 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 138 insertions(+), 70 deletions(-) diff --git a/acme.sh b/acme.sh index 64172445..0ce08d69 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.5 +VER=2.5.6 PROJECT_NAME="acme.sh" @@ -25,6 +25,8 @@ VTYPE_DNS="dns-01" VTYPE_TLS="tls-sni-01" VTYPE_TLS2="tls-sni-02" +LOCAL_ANY_ADDRESS="0.0.0.0" + MAX_RENEW=80 DEFAULT_DNS_SLEEP=120 @@ -178,6 +180,35 @@ _hasfield() { return 1 #not contains } +_getfield(){ + _str="$1" + _findex="$2" + _sep="$3" + + if [ -z "$_findex" ] ; then + _usage "Usage: str field [sep]" + return 1 + fi + + if [ -z "$_sep" ] ; then + _sep="," + fi + + _ffi=$_findex + while [ "$_ffi" -gt "0" ] + do + _fv="$(echo "$_str" | cut -d $_sep -f $_ffi)" + if [ "$_fv" ] ; then + printf -- "%s" "$_fv" + return 0 + fi + _ffi="$(_math $_ffi - 1)" + done + + printf -- "%s" "$_str" + +} + _exists(){ cmd="$1" if [ -z "$cmd" ] ; then @@ -559,7 +590,7 @@ _ss() { _debug "Using: netstat" if netstat -h 2>&1 | grep "\-p proto" >/dev/null ; then #for windows version netstat tool - netstat -anb -p tcp | grep "LISTENING" | grep ":$_port " + netstat -an -p tcp | grep "LISTENING" | grep ":$_port " else if netstat -help 2>&1 | grep "\-p protocol" >/dev/null ; then netstat -an -p tcp | grep LISTEN | grep ":$_port " @@ -1134,20 +1165,24 @@ _clearaccountconf() { fi } +# content localaddress _startserver() { content="$1" + ncaddr="$2" + _debug "ncaddr" "$ncaddr" + _debug "startserver: $$" nchelp="$(nc -h 2>&1)" if echo "$nchelp" | grep "\-q[ ,]" >/dev/null ; then - _NC="nc -q 1 -l" + _NC="nc -q 1 -l $ncaddr" else if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then - _NC="nc -c -l" + _NC="nc -c -l $ncaddr" elif echo "$nchelp" | grep "\-N" |grep "Shutdown the network socket after EOF on stdin" >/dev/null ; then - _NC="nc -N -l" + _NC="nc -N -l $ncaddr" else - _NC="nc -l" + _NC="nc -l $ncaddr" fi fi @@ -1234,7 +1269,7 @@ _starttlsserver() { fi #start openssl - _debug "openssl s_server -cert \"$TLS_CERT\" -key \"$TLS_KEY\" -accept $port -naccept 1 -tlsextdebug" + _debug "openssl s_server -cert \"$TLS_CERT\" -key \"$TLS_KEY\" -accept $port -tlsextdebug" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -tlsextdebug ) & else @@ -1609,6 +1644,78 @@ _clearupwebbroot() { } _on_before_issue() { + + if _hasfield "$Le_Webroot" "$NO_VALUE" ; then + if ! _exists "nc" ; then + _err "Please install netcat(nc) tools first." + return 1 + fi + elif ! _hasfield "$Le_Webroot" "$W_TLS" ; then + #no need to check anymore + return 0 + fi + + _debug Le_LocalAddress "$Le_LocalAddress" + + alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) + _index=1 + _currentRoot="" + _addrIndex=1 + for d in $alldomains + do + _debug "Check for domain" $d + _currentRoot="$(_getfield "$Le_Webroot" $_index)" + _debug "_currentRoot" "$_currentRoot" + _index=$(_math $_index + 1) + _checkport="" + if [ "$_currentRoot" = "$NO_VALUE" ] ; then + _info "Standalone mode." + if [ -z "$Le_HTTPPort" ] ; then + Le_HTTPPort=80 + else + _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" + fi + _checkport="$Le_HTTPPort" + elif [ "$_currentRoot" = "$W_TLS" ] ; then + _info "Standalone tls mode." + if [ -z "$Le_TLSPort" ] ; then + Le_TLSPort=443 + else + _savedomainconf "Le_TLSPort" "$Le_TLSPort" + fi + _checkport="$Le_TLSPort" + fi + + if [ "$_checkport" ] ; then + _debug _checkport "$_checkport" + _checkaddr="$(_getfield "$Le_LocalAddress" $_addrIndex)" + _debug _checkaddr "$_checkaddr" + + _addrIndex="$(_math $_addrIndex + 1)" + + _netprc="$(_ss "$_checkport" | grep "$_checkport")" + netprc="$(echo "$_netprc" | grep "$_checkaddr")" + if [ -z "$netprc" ] ; then + netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")" + fi + if [ "$netprc" ] ; then + _err "$netprc" + _err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)" + _err "Please stop it first" + return 1 + fi + fi + done + + if _hasfield "$Le_Webroot" "apache" ; then + if ! _setApache ; then + _err "set up apache error. Report error to me." + return 1 + fi + else + usingApache="" + fi + #run pre hook if [ "$Le_PreHook" ] ; then _info "Run pre hook:'$Le_PreHook'" @@ -1678,6 +1785,7 @@ issue() { Le_PreHook="${10}" Le_PostHook="${11}" Le_RenewHook="${12}" + Le_LocalAddress="${13}" #remove these later. if [ "$Le_Webroot" = "dns-cf" ] ; then @@ -1712,69 +1820,17 @@ issue() { _savedomainconf "Le_PreHook" "$Le_PreHook" _savedomainconf "Le_PostHook" "$Le_PostHook" _savedomainconf "Le_RenewHook" "$Le_RenewHook" - - if ! _on_before_issue ; then - _err "_on_before_issue." - return 1 - fi - + _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" + if [ "$Le_Alt" = "$NO_VALUE" ] ; then Le_Alt="" fi - - if _hasfield "$Le_Webroot" "$NO_VALUE" ; then - _info "Standalone mode." - if ! _exists "nc" ; then - _err "Please install netcat(nc) tools first." - _on_issue_err - return 1 - fi - - if [ -z "$Le_HTTPPort" ] ; then - Le_HTTPPort=80 - else - _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" - fi - - netprc="$(_ss "$Le_HTTPPort" | grep "$Le_HTTPPort")" - if [ "$netprc" ] ; then - _err "$netprc" - _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)" - _err "Please stop it first" - _on_issue_err - return 1 - fi - fi - if _hasfield "$Le_Webroot" "$W_TLS" ; then - _info "Standalone tls mode." - - if [ -z "$Le_TLSPort" ] ; then - Le_TLSPort=443 - else - _savedomainconf "Le_TLSPort" "$Le_TLSPort" - fi - - netprc="$(_ss "$Le_TLSPort" | grep "$Le_TLSPort")" - if [ "$netprc" ] ; then - _err "$netprc" - _err "tcp port $Le_TLSPort is already used by $(echo "$netprc" | cut -d : -f 4)" - _err "Please stop it first" - _on_issue_err - return 1 - fi - fi - - if _hasfield "$Le_Webroot" "apache" ; then - if ! _setApache ; then - _err "set up apache error. Report error to me." - _on_issue_err - return 1 - fi - else - usingApache="" + if ! _on_before_issue ; then + _err "_on_before_issue." + return 1 fi - + if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then _acck="$NO_VALUE" if [ "$Le_Keylength" ] ; then @@ -1869,7 +1925,7 @@ issue() { do _info "Getting webroot for domain" $d _w="$(echo $Le_Webroot | cut -d , -f $_index)" - _debug _w "$_w" + _info _w "$_w" if [ "$_w" ] ; then _currentRoot="$_w" fi @@ -2037,6 +2093,7 @@ issue() { _debug "ok, let's start to verify" + _ncIndex=1 ventries=$(echo "$vlist" | tr ',' ' ' ) for ventry in $ventries do @@ -2064,7 +2121,9 @@ issue() { if [ "$vtype" = "$VTYPE_HTTP" ] ; then if [ "$_currentRoot" = "$NO_VALUE" ] ; then _info "Standalone mode server" - _startserver "$keyauthorization" & + _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex" )" + _ncIndex="$(_math $_ncIndex + 1)" + _startserver "$keyauthorization" "$_ncaddr" & if [ "$?" != "0" ] ; then _clearup _on_issue_err @@ -2129,7 +2188,9 @@ issue() { _SAN_B="$_x.$_y.acme.invalid" _debug2 _SAN_B "$_SAN_B" - if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" ; then + _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex" )" + _ncIndex="$(_math $_ncIndex + 1)" + if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then _err "Start tls server error." _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup @@ -2362,7 +2423,7 @@ renew() { fi IS_RENEW="1" - issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" + issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" res=$? IS_RENEW="" @@ -3215,6 +3276,7 @@ Parameters: --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 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 '--renewall' 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. @@ -3324,6 +3386,7 @@ _process() { _renew_hook="" _logfile="" _log="" + _local_address="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -3447,6 +3510,11 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; + --local-address) + lvalue="$2" + _local_address="$_local_address$lvalue," + shift + ;; --apache) wvalue="apache" if [ -z "$_webroot" ] ; then @@ -3643,7 +3711,7 @@ _process() { uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" ;; signcsr) signcsr "$_csr" "$_webroot" From 0ba95a3dd4d628306e6cc4e2ac3536bcf9026b65 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 24 Sep 2016 13:43:08 +0800 Subject: [PATCH 0314/1348] fix auto upgrade --- acme.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 0ce08d69..0da53e88 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.6 +VER=2.5.7 PROJECT_NAME="acme.sh" @@ -3189,7 +3189,6 @@ cron() { if [ "$AUTO_UPGRADE" ] ; then export LE_WORKING_DIR ( - . $LE_WORKING_DIR/$PROJECT_ENTRY >/dev/null if ! upgrade ; then _err "Cron:Upgrade failed!" return 1 @@ -3206,7 +3205,7 @@ cron() { renewAll _ret="$?" IN_CRON="" - return $_ret + exit $_ret } version() { From 0407c4e0f79fe8e9a1014b480ea4e29cf424f3ae Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 24 Sep 2016 14:01:28 +0800 Subject: [PATCH 0315/1348] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 0da53e88..82b63bb2 100755 --- a/acme.sh +++ b/acme.sh @@ -2794,6 +2794,7 @@ _deactivate() { _d_max_retry=9 while [ "$_d_i" -lt "$_d_max_retry" ] ; do + _info "Deactivate: $_d_domain" _d_i="$(_math $_d_i + 1)" if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$_d_domain\"}}" ; then _err "Can not get domain token." From 86c017ec9d9a3c94e8b92425c7f851e4572c11c9 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 24 Sep 2016 14:17:04 +0800 Subject: [PATCH 0316/1348] fix deactivate return code --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 82b63bb2..831f5ae2 100755 --- a/acme.sh +++ b/acme.sh @@ -2863,7 +2863,9 @@ deactivate() { if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ] ; then continue fi - _deactivate "$_d_dm" $_d_type + if ! _deactivate "$_d_dm" $_d_type ; then + return 1 + fi done } From d404e92d16f5ee7d6506f19d3c13cc114c4737da Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 24 Sep 2016 23:53:53 +0800 Subject: [PATCH 0317/1348] Fetch agreement tos dynamically, fix https://github.com/Neilpang/acme.sh/issues/253 --- acme.sh | 160 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 58 deletions(-) diff --git a/acme.sh b/acme.sh index 831f5ae2..fba3caaa 100755 --- a/acme.sh +++ b/acme.sh @@ -48,9 +48,6 @@ RENEW_SKIP=2 ECC_SEP="_" ECC_SUFFIX="${ECC_SEP}ecc" -if [ -z "$AGREEMENT" ] ; then - AGREEMENT="$DEFAULT_AGREEMENT" -fi __INTERACTIVE="" if [ -t 1 ] ; then @@ -1767,6 +1764,93 @@ _on_issue_success() { } + +_regAccount() { + _initpath + if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then + _acck="no" + if [ "$Le_Keylength" ] ; then + _acck="$Le_Keylength" + fi + if ! createAccountKey "$_acck" ; then + _err "Create account key error." + return 1 + fi + fi + + if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then + return 1 + fi + + _updateTos="" + _reg_res="new-reg" + while true ; + do + _debug AGREEMENT "$AGREEMENT" + accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) + thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) + + regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}' + + if [ "$ACCOUNT_EMAIL" ] ; then + regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' + fi + + if [ -z "$_updateTos" ] ; then + _info "Registering account" + + if ! _send_signed_request "$API/acme/new-reg" "$regjson" ; then + _err "Register account Error: $response" + return 1 + fi + + if [ "$code" = "" ] || [ "$code" = '201' ] ; then + echo "$response" > $LE_WORKING_DIR/account.json + _info "Registered" + elif [ "$code" = '409' ] ; then + _info "Already registered" + else + _err "Register account Error: $response" + return 1 + fi + + _accUri="$(echo "$responseHeaders" | grep "^Location:" | cut -d ' ' -f 2| tr -d "\r\n")" + _debug "_accUri" "$_accUri" + ACCOUNT_URL="$_accUri" + _saveaccountconf ACCOUNT_URL "$ACCOUNT_URL" + + _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _egrep_o "<.*>" | tr -d '<>')" + _debug "_tos" "$_tos" + if [ -z "$_tos" ] ; then + _debug "Use default tos: $DEFAULT_AGREEMENT" + _tos="$DEFAULT_AGREEMENT" + fi + if [ "$_tos" != "$AGREEMENT" ]; then + _updateTos=1 + AGREEMENT="$_tos" + _reg_res="reg" + continue + fi + + else + _debug "Update tos: $_tos" + if ! _send_signed_request "$_accUri" "$regjson" ; then + _err "Update tos error." + return 1 + fi + if [ "$code" = '202' ] ; then + _debug "Update tos success." + else + _err "Update tos error." + return 1 + fi + fi + return 0 + done + +} + + #webroot, domain domainlist keylength issue() { if [ -z "$2" ] ; then @@ -1826,69 +1910,21 @@ issue() { Le_Alt="" fi + if [ "$Le_Keylength" = "$NO_VALUE" ] ; then + Le_Keylength="" + fi + if ! _on_before_issue ; then _err "_on_before_issue." return 1 fi - if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then - _acck="$NO_VALUE" - if [ "$Le_Keylength" ] ; then - _acck="$Le_Keylength" - fi - if ! createAccountKey "$_acck" ; then - _err "Create account key error." - if [ "$usingApache" ] ; then - _restoreApache - fi - _on_issue_err - return 1 - fi - fi - - if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then - if [ "$usingApache" ] ; then - _restoreApache - fi + if ! _regAccount ; then _on_issue_err return 1 fi - accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) - - regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ] ; then - regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' - fi - - accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | _digest "sha256" )" - accountkeyhash="$(echo $accountkeyhash$API$regjson | _digest "sha256" )" - if [ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ] ; then - _info "Registering account" - _send_signed_request "$API/acme/new-reg" "$regjson" - if [ "$code" = "" ] || [ "$code" = '201' ] ; then - _info "Registered" - echo "$response" > $LE_WORKING_DIR/account.json - elif [ "$code" = '409' ] ; then - _info "Already registered" - else - _err "Register account Error: $response" - _clearup - _on_issue_err - return 1 - fi - ACCOUNT_KEY_HASH="$accountkeyhash" - _saveaccountconf "ACCOUNT_KEY_HASH" "$ACCOUNT_KEY_HASH" - else - _info "Skip register account key" - fi - if [ "$Le_Keylength" = "$NO_VALUE" ] ; then - Le_Keylength="" - fi - - if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ] ; then _info "Signing from existing CSR." else @@ -2301,13 +2337,18 @@ issue() { return 1 fi - + _rcert="$response" Le_LinkCert="$(grep -i '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)" _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ "$Le_LinkCert" ] ; then echo "$BEGIN_CERT" > "$CERT_PATH" - _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" + + if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then + _debug "Get cert failed. Let's try last response." + printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" + fi + echo "$END_CERT" >> "$CERT_PATH" _info "$(__green "Cert success.")" cat "$CERT_PATH" @@ -2918,6 +2959,9 @@ _initconf() { #ACCOUNT_KEY_PATH=\"/path/to/account.key\" #CERT_HOME=\"/path/to/cert/home\" +#ACCOUNT_URL=\"\" + + #LOG_FILE=\"$DEFAULT_LOG_FILE\" #AUTO_UPGRADE=\"1\" From eb59817e81fdb6273333a652c8fa7f4ba8709b2b Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 25 Sep 2016 10:56:06 +0800 Subject: [PATCH 0318/1348] Support `updateaccount` and `registeraccount`. fix https://github.com/Neilpang/acme.sh/issues/70 --- acme.sh | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index fba3caaa..8532b4f5 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.7 +VER=2.5.8 PROJECT_NAME="acme.sh" @@ -1763,7 +1763,15 @@ _on_issue_success() { } +updateaccount() { + _initpath + _regAccount +} +registeraccount() { + _initpath + _regAccount +} _regAccount() { _initpath @@ -1839,9 +1847,9 @@ _regAccount() { return 1 fi if [ "$code" = '202' ] ; then - _debug "Update tos success." + _info "Update success." else - _err "Update tos error." + _err "Update error." return 1 fi fi @@ -2970,7 +2978,6 @@ _initconf() { #FORCE=1 # Force to issue cert #DEBUG=1 # Debug mode -#ACCOUNT_KEY_HASH=account key hash #USER_AGENT=\"$USER_AGENT\" @@ -3282,6 +3289,8 @@ Commands: --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically. --cron Run cron job to renew all the certs. --toPkcs Export the certificate and key to a pfx file. + --updateaccount Update account info. + --registeraccount Register account key. --createAccountKey, -cak Create an account private key, professional use. --createDomainKey, -cdk Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. @@ -3501,7 +3510,12 @@ _process() { --deactivate) _CMD="deactivate" ;; - + --updateaccount) + _CMD="updateaccount" + ;; + --registeraccount) + _CMD="registeraccount" + ;; --domain|-d) _dvalue="$2" @@ -3779,7 +3793,13 @@ _process() { ;; deactivate) deactivate "$_domain,$_altdomains" - ;; + ;; + registeraccount) + registeraccount + ;; + updateaccount) + updateaccount + ;; list) list "$_listraw" ;; From a73c5b3355c6afb889363ca486db82c0946b1702 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 25 Sep 2016 21:58:59 +0800 Subject: [PATCH 0319/1348] support log level --- acme.sh | 90 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 29 deletions(-) diff --git a/acme.sh b/acme.sh index 8532b4f5..4ca70877 100755 --- a/acme.sh +++ b/acme.sh @@ -48,6 +48,12 @@ RENEW_SKIP=2 ECC_SEP="_" ECC_SUFFIX="${ECC_SEP}ecc" +LOG_LEVEL_1=1 +LOG_LEVEL_2=2 +LOG_LEVEL_3=3 +DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" + +_DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh" __INTERACTIVE="" if [ -t 1 ] ; then @@ -74,66 +80,65 @@ __red() { fi } -__mytee() { - tee -a $1 -} -_info() { +_printargs() { if [ -z "$2" ] ; then - printf -- "[$(date)] $1" | __mytee $LOG_FILE + printf -- "[$(date)] $1" else - printf -- "[$(date)] $1='$2'" | __mytee $LOG_FILE + printf -- "[$(date)] $1='$2'" fi - printf "\n" | __mytee $LOG_FILE + printf "\n" } -_err_e() { - if [ -z "$2" ] ; then - __red "$1" | __mytee $LOG_FILE >&2 - else - __red "$1='$2'" | __mytee $LOG_FILE >&2 - fi - printf "\n" | __mytee $LOG_FILE >&2 +_log() { + [ -z "$LOG_FILE" ] && return + _printargs "$@" >> "$LOG_FILE" +} + +_info() { + _log "$@" + _printargs "$@" } + _err() { - printf -- "[$(date)] " | __mytee $LOG_FILE >&2 - _err_e "$@" + _log "$@" + __red "$(_printargs "$@")" >&2 return 1 } _usage() { - _err_e "$@" + __red "$@" } + _debug() { + if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ] ; then + _log "$@" + fi if [ -z "$DEBUG" ] ; then return fi - - if [ -z "$2" ] ; then - printf -- "[$(date)] $1" | __mytee $LOG_FILE >&2 - else - printf -- "[$(date)] $1='$2'" | __mytee $LOG_FILE >&2 - fi - - printf "\n" | __mytee $LOG_FILE >&2 - return 0 + _printargs "$@" >&2 } _debug2() { + if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ] ; then + _log "$@" + fi if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then _debug "$@" fi - return } _debug3() { + if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ] ; then + _log "$@" + fi if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; then _debug "$@" fi - return } _startswith(){ @@ -1726,6 +1731,13 @@ _on_before_issue() { } _on_issue_err() { + if [ "$LOG_FILE" ] ; then + _err "Please check log file for more details: $LOG_FILE" + else + _err "Please use add '--debug' or '--log' to check more details." + _err "See: $_DEBUG_WIKI" + fi + #run the post hook if [ "$Le_PostHook" ] ; then _info "Run post hook:'$Le_PostHook'" @@ -2971,6 +2983,7 @@ _initconf() { #LOG_FILE=\"$DEFAULT_LOG_FILE\" +LOG_LEVEL=1 #AUTO_UPGRADE=\"1\" @@ -3312,6 +3325,7 @@ Parameters: --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. + --log-level 1|2 Specifies the log level, default is 1. These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: @@ -3442,6 +3456,7 @@ _process() { _logfile="" _log="" _local_address="" + _log_level="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -3739,8 +3754,15 @@ _process() { shift fi LOG_FILE="$_logfile" + if [ -z "$LOG_LEVEL" ] ; then + LOG_LEVEL="$DEFAULT_LOG_LEVEL" + fi + ;; + --log-level) + _log_level="$1" + LOG_LEVEL="$_log_level" + shift ;; - *) _err "Unknown parameter : $1" return 1 @@ -3759,6 +3781,12 @@ _process() { _saveaccountconf "LOG_FILE" "$_logfile" fi LOG_FILE="$_logfile" + + if [ "$_log_level" ] ; then + _saveaccountconf "LOG_LEVEL" "$_log_level" + LOG_LEVEL="$_log_level" + fi + _processAccountConf fi @@ -3837,6 +3865,10 @@ _process() { fi _saveaccountconf "LOG_FILE" "$LOG_FILE" fi + + if [ "$_log_level" ] ; then + _saveaccountconf "LOG_LEVEL" "$_log_level" + fi _processAccountConf fi From 6b5000369711670428188e97f6be4e037954a156 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 25 Sep 2016 22:26:41 +0800 Subject: [PATCH 0320/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4ca70877..798fc287 100755 --- a/acme.sh +++ b/acme.sh @@ -2983,7 +2983,7 @@ _initconf() { #LOG_FILE=\"$DEFAULT_LOG_FILE\" -LOG_LEVEL=1 +#LOG_LEVEL=1 #AUTO_UPGRADE=\"1\" From e4b8d9b9d67247482a0114d11bbabe3e13fbfea7 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 25 Sep 2016 22:54:58 +0800 Subject: [PATCH 0321/1348] minor, No need to save ACCOUNT_URL --- acme.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/acme.sh b/acme.sh index 798fc287..52aa33df 100755 --- a/acme.sh +++ b/acme.sh @@ -1836,8 +1836,6 @@ _regAccount() { _accUri="$(echo "$responseHeaders" | grep "^Location:" | cut -d ' ' -f 2| tr -d "\r\n")" _debug "_accUri" "$_accUri" - ACCOUNT_URL="$_accUri" - _saveaccountconf ACCOUNT_URL "$ACCOUNT_URL" _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _egrep_o "<.*>" | tr -d '<>')" _debug "_tos" "$_tos" @@ -2979,7 +2977,6 @@ _initconf() { #ACCOUNT_KEY_PATH=\"/path/to/account.key\" #CERT_HOME=\"/path/to/cert/home\" -#ACCOUNT_URL=\"\" #LOG_FILE=\"$DEFAULT_LOG_FILE\" From fbd2038fa77cff942ebed4216242613066cfeebf Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 26 Sep 2016 13:08:19 +0800 Subject: [PATCH 0322/1348] minor --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 52aa33df..65aa4eb2 100755 --- a/acme.sh +++ b/acme.sh @@ -104,7 +104,7 @@ _info() { _err() { _log "$@" - __red "$(_printargs "$@")" >&2 + __red "$(_printargs "$@")\n" >&2 return 1 } @@ -3407,13 +3407,13 @@ upgrade() { _processAccountConf() { if [ "$_useragent" ] ; then _saveaccountconf "USER_AGENT" "$_useragent" - elif [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ] ; then + elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ] ; then _saveaccountconf "USER_AGENT" "$USER_AGENT" fi if [ "$_accountemail" ] ; then _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" - elif [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ] ; then + elif [ "$ACCOUNT_EMAIL" ] && [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ] ; then _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL" fi From 30c2d84c6da8c2f02dbd17b377aa3ce2cbd0f577 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 26 Sep 2016 13:33:09 +0800 Subject: [PATCH 0323/1348] minor: remove useless hook. --- acme.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 65aa4eb2..14f7acf2 100755 --- a/acme.sh +++ b/acme.sh @@ -1646,7 +1646,7 @@ _clearupwebbroot() { } _on_before_issue() { - + _debug _on_before_issue if _hasfield "$Le_Webroot" "$NO_VALUE" ; then if ! _exists "nc" ; then _err "Please install netcat(nc) tools first." @@ -1731,6 +1731,7 @@ _on_before_issue() { } _on_issue_err() { + _debug _on_issue_err if [ "$LOG_FILE" ] ; then _err "Please check log file for more details: $LOG_FILE" else @@ -1751,6 +1752,7 @@ _on_issue_err() { } _on_issue_success() { + _debug _on_issue_success #run the post hook if [ "$Le_PostHook" ] ; then _info "Run post hook:'$Le_PostHook'" @@ -2096,20 +2098,17 @@ issue() { ( if ! . $d_api ; then _err "Load file $d_api error. Please check your api file and try again." - _on_issue_err return 1 fi addcommand="${_currentRoot}_add" if ! _exists $addcommand ; then _err "It seems that your api file is not correct, it must have a function named: $addcommand" - _on_issue_err return 1 fi if ! $addcommand $txtdomain $txt ; then _err "Error add txt for domain:$txtdomain" - _on_issue_err return 1 fi ) From 30bfc2cea73aa4faf729ade3bd9cc51f3e953d43 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 27 Sep 2016 13:11:08 +0800 Subject: [PATCH 0324/1348] fix https://github.com/Neilpang/acme.sh/issues/304 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 14f7acf2..bf634f1c 100755 --- a/acme.sh +++ b/acme.sh @@ -3755,7 +3755,7 @@ _process() { fi ;; --log-level) - _log_level="$1" + _log_level="$2" LOG_LEVEL="$_log_level" shift ;; From b19ba13affe9fb3cbd427340f353567fb2eb6050 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 27 Sep 2016 21:27:43 +0800 Subject: [PATCH 0325/1348] fix for Mac osx --- acme.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index bf634f1c..e748a063 100755 --- a/acme.sh +++ b/acme.sh @@ -104,7 +104,8 @@ _info() { _err() { _log "$@" - __red "$(_printargs "$@")\n" >&2 + __red "$(_printargs "$@")" >&2 + printf "\n" >&2 return 1 } @@ -844,8 +845,11 @@ _time() { _mktemp() { if _exists mktemp ; then - mktemp - return + if mktemp 2>/dev/null ; then + return + elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null ; then + return + fi fi if [ -d "/tmp" ] ; then echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" From 150e9c8a48a857d04d2bc8264bce5e5e3e0a9468 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 27 Sep 2016 22:03:42 +0800 Subject: [PATCH 0326/1348] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7fc302b0..6c37179d 100644 --- a/README.md +++ b/README.md @@ -133,9 +133,9 @@ The issued cert will be renewed every 80 days automatically. More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# 3. Install issued cert to apache/nginx etc. +# 3. Install the issued cert to apache/nginx etc. -After you issue a cert, you probably want to install the cert with your nginx/apache or other servers you may be using. +After you issue a cert, you probably want to install/copy the cert to your nginx/apache or other servers you may be using. ```bash acme.sh --installcert -d aa.com \ @@ -148,7 +148,7 @@ acme.sh --installcert -d aa.com \ Only the domain is required, all the other parameters are optional. -Install the issued cert/key to the production apache or nginx path. +Install/copy the issued cert/key to the production apache or nginx path. The cert will be `renewed every 80 days by default` (which is configurable). Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`. @@ -302,7 +302,7 @@ You can update acme.sh to the latest code: acme.sh --upgrade ``` -# 12. Issue a cert from existing CSR +# 12. Issue a cert from an existing CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR @@ -318,7 +318,7 @@ TODO: 2. ACME protocol: https://github.com/ietf-wg-acme/acme 3. Certbot: https://github.com/certbot/certbot -# License & Other +# License & Others License is GPLv3 From 5c48e139d4962ef3e0fde2d0dc24dc89290a8459 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 27 Sep 2016 23:43:18 +0800 Subject: [PATCH 0327/1348] support individual ca accounts --- acme.sh | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index e748a063..f4156411 100755 --- a/acme.sh +++ b/acme.sh @@ -848,6 +848,7 @@ _mktemp() { if mktemp 2>/dev/null ; then return elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null ; then + #for Mac osx return fi fi @@ -1345,6 +1346,8 @@ __initHome() { fi DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log" + + DEFAULT_CA_HOME="$LE_WORKING_DIR/ca" } #[domain] [keylength] @@ -1362,6 +1365,10 @@ _initpath() { export PATH="$USER_PATH:$PATH" fi fi + + if [ -z "$CA_HOME" ] ; then + CA_HOME="$DEFAULT_CA_HOME" + fi if [ -z "$API" ] ; then if [ -z "$STAGE" ] ; then @@ -1372,6 +1379,19 @@ _initpath() { fi fi + _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')" + CA_DIR="$CA_HOME/$_API_HOST" + + _DEFAULT_CA_CONF="$CA_DIR/ca.conf" + + if [ -z "$CA_CONF" ] ; then + CA_CONF="$_DEFAULT_CA_CONF" + fi + + if [ -f "$CA_CONF" ] ; then + . "$CA_CONF" + fi + if [ -z "$ACME_DIR" ] ; then ACME_DIR="/home/.acme" fi @@ -1388,11 +1408,20 @@ _initpath() { HTTP_HEADER="$LE_WORKING_DIR/http.header" fi - _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key" + _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" + _OLD_ACCOUNT_JSON="$LE_WORKING_DIR/account.json" + + _DEFAULT_ACCOUNT_KEY_PATH="$CA_DIR/account.key" + _DEFAULT_ACCOUNT_JSON_PATH="$CA_DIR/account.json" if [ -z "$ACCOUNT_KEY_PATH" ] ; then ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" fi + if [ -z "$ACCOUNT_JSON_PATH" ] ; then + ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" + fi + + _DEFAULT_CERT_HOME="$LE_WORKING_DIR" if [ -z "$CERT_HOME" ] ; then CERT_HOME="$_DEFAULT_CERT_HOME" @@ -1401,6 +1430,9 @@ _initpath() { if [ -z "$1" ] ; then return 0 fi + + mkdir -p "$CA_DIR" + domain="$1" _ilength="$2" @@ -1793,6 +1825,17 @@ registeraccount() { _regAccount() { _initpath + + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" + mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" + fi + + if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then + _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" + mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" + fi + if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then _acck="no" if [ "$Le_Keylength" ] ; then @@ -1831,7 +1874,7 @@ _regAccount() { fi if [ "$code" = "" ] || [ "$code" = '201' ] ; then - echo "$response" > $LE_WORKING_DIR/account.json + echo "$response" > $ACCOUNT_JSON_PATH _info "Registered" elif [ "$code" = '409' ] ; then _info "Already registered" @@ -2447,6 +2490,9 @@ issue() { Le_NextRenewTime=$(_math $Le_NextRenewTime - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" + Le_API="$API" + _savedomainconf "Le_API" "$Le_API" + _on_issue_success if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ] ; then @@ -2478,6 +2524,11 @@ renew() { fi . "$DOMAIN_CONF" + + if [ "$Le_API" ] ; then + API="$Le_API" + fi + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ] ; then _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" _info "Add '$(__red '--force')' to force to renew." From 950172dc01b0ad65cd5e4500018eef62c9663747 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 27 Sep 2016 23:52:52 +0800 Subject: [PATCH 0328/1348] debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index f4156411..45f94e16 100755 --- a/acme.sh +++ b/acme.sh @@ -1948,6 +1948,7 @@ issue() { if [ "$Le_Webroot" = "dns-cx" ] ; then Le_Webroot="dns_cx" fi + _debug "Using api: $API" if [ ! "$IS_RENEW" ] ; then _initpath $Le_Domain "$Le_Keylength" From f6dcd989951822fece88059089c5a6e24d7b682e Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 28 Sep 2016 13:07:51 +0800 Subject: [PATCH 0329/1348] save api first --- acme.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 45f94e16..049143bf 100755 --- a/acme.sh +++ b/acme.sh @@ -1974,6 +1974,9 @@ issue() { _savedomainconf "Le_RenewHook" "$Le_RenewHook" _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" + Le_API="$API" + _savedomainconf "Le_API" "$Le_API" + if [ "$Le_Alt" = "$NO_VALUE" ] ; then Le_Alt="" fi @@ -2490,9 +2493,7 @@ issue() { Le_NextRenewTime=$(_math $Le_NextRenewTime - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - - Le_API="$API" - _savedomainconf "Le_API" "$Le_API" + _on_issue_success From 65de3110a9ccc210036ec48e34225b8d2028eec0 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 28 Sep 2016 13:13:08 +0800 Subject: [PATCH 0330/1348] minor, fix error message --- acme.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index e748a063..5f4f2336 100755 --- a/acme.sh +++ b/acme.sh @@ -104,13 +104,19 @@ _info() { _err() { _log "$@" - __red "$(_printargs "$@")" >&2 + printf -- "[$(date)] " >&2 + if [ -z "$2" ] ; then + __red "$1" >&2 + else + __red "$1='$2'" >&2 + fi printf "\n" >&2 return 1 } _usage() { - __red "$@" + __red "$@" >&2 + printf "\n" >&2 } From f08ffe9feb366b657aee9d9abd9aa7dc3637339d Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 28 Sep 2016 13:26:02 +0800 Subject: [PATCH 0331/1348] v2.6.0 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 049143bf..9829b2e0 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.5.8 +VER=2.6.0 PROJECT_NAME="acme.sh" From 6bf281f905002b6832137ff6700e0f9aadc19874 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 28 Sep 2016 22:05:43 +0800 Subject: [PATCH 0332/1348] support '--auto-upgrade' --- acme.sh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 75a0e68f..cd1b1b4d 100755 --- a/acme.sh +++ b/acme.sh @@ -3312,7 +3312,7 @@ uninstall() { cron() { IN_CRON=1 _initpath - if [ "$AUTO_UPGRADE" ] ; then + if [ "$AUTO_UPGRADE" = "1" ] ; then export LE_WORKING_DIR ( if ! upgrade ; then @@ -3416,6 +3416,7 @@ Parameters: --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed. --renew-hook Command to be run once for each successfully renewed certificate. --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. + --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. " } @@ -3479,6 +3480,12 @@ _processAccountConf() { _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL" fi + if [ "$_auto_upgrade" ] ; then + _saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade" + elif [ "$AUTO_UPGRADE" ] ; then + _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" + fi + } _process() { @@ -3516,6 +3523,7 @@ _process() { _log="" _local_address="" _log_level="" + _auto_upgrade="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -3807,7 +3815,7 @@ _process() { --log|--logfile) _log="1" _logfile="$2" - if [ -z "$_logfile" ] || _startswith "$_logfile" '-' ; then + if _startswith "$_logfile" '-' ; then _logfile="" else shift @@ -3822,6 +3830,16 @@ _process() { LOG_LEVEL="$_log_level" shift ;; + --auto-upgrade) + _auto_upgrade="$2" + if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-' ; then + _auto_upgrade="1" + else + shift + fi + AUTO_UPGRADE="$_auto_upgrade" + ;; + *) _err "Unknown parameter : $1" return 1 From 59649e9b1e5ec81961bd8b45655772adffd06c0e Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 28 Sep 2016 22:11:00 +0800 Subject: [PATCH 0333/1348] support --auto-upgrade --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 6c37179d..aeef0098 100644 --- a/README.md +++ b/README.md @@ -302,6 +302,17 @@ You can update acme.sh to the latest code: acme.sh --upgrade ``` +You can enable auto upgrade: +``` +acme.sh --upgrade --auto-upgrade +``` +Then **acme.sh** will keep up to date automatically. + +Disable auto upgrade: +``` +acme.sh --upgrade --auto-upgrade 0 +``` + # 12. Issue a cert from an existing CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR From ad752b317d6fd0abe9340ce42ba16169e348a9fb Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 29 Sep 2016 22:19:03 +0800 Subject: [PATCH 0334/1348] support csr that contains empty CN field. fix https://github.com/Neilpang/acme.sh/issues/306 --- acme.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index cd1b1b4d..4c884d69 100755 --- a/acme.sh +++ b/acme.sh @@ -2597,10 +2597,11 @@ signcsr(){ _initpath _csrsubj=$(_readSubjectFromCSR "$_csrfile") - if [ "$?" != "0" ] || [ -z "$_csrsubj" ] ; then + if [ "$?" != "0" ] ; then _err "Can not read subject from csr: $_csrfile" return 1 fi + _debug _csrsubj "$_csrsubj" _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") if [ "$?" != "0" ] ; then @@ -2609,6 +2610,19 @@ signcsr(){ fi _debug "_csrdomainlist" "$_csrdomainlist" + + if [ -z "$_csrsubj" ] ; then + _csrsubj="$(_getfield "$_csrdomainlist" 1)" + _debug _csrsubj "$_csrsubj" + _csrdomainlist="$(echo "$_csrdomainlist" | cut -d , -f 2-)" + _debug "_csrdomainlist" "$_csrdomainlist" + fi + + if [ -z "$_csrsubj" ] ; then + _err "Can not read subject from csr: $_csrfile" + return 1 + fi + _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") if [ "$?" != "0" ] || [ -z "$_csrkeylength" ] ; then _err "Can not read key length from csr: $_csrfile" From fe04faf67529233138084c0b4086fa475c29c124 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 30 Sep 2016 21:27:23 +0800 Subject: [PATCH 0335/1348] Add Chinese link --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index aeef0098..fcd8c28c 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ It's probably the `easiest&smallest&smartest` shell script to automatically issu Wiki: https://github.com/Neilpang/acme.sh/wiki +# [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) + #Tested OS | NO | Status| Platform| |----|-------|---------| From ef858ef0622e878bf3e7925ab40732ef69241a58 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 30 Sep 2016 21:37:39 +0800 Subject: [PATCH 0336/1348] use head -n --- acme.sh | 6 +++--- dnsapi/dns_cf.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 4c884d69..13dc865d 100755 --- a/acme.sh +++ b/acme.sh @@ -1049,7 +1049,7 @@ _send_signed_request() { _debug3 _headers "$_headers" - nonce="$( echo "$_headers" | grep "Replay-Nonce:" | head -1 | tr -d "\r\n " | cut -d ':' -f 2)" + nonce="$( echo "$_headers" | grep "Replay-Nonce:" | head -n 1 | tr -d "\r\n " | cut -d ':' -f 2)" _debug3 nonce "$nonce" @@ -2412,7 +2412,7 @@ issue() { fi _rcert="$response" - Le_LinkCert="$(grep -i '^Location.*$' $HTTP_HEADER | head -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)" _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ "$Le_LinkCert" ] ; then @@ -2451,7 +2451,7 @@ issue() { _cleardomainconf "Le_Vlist" - Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) + Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -n 1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) if ! _contains "$Le_LinkIssuer" ":" ; then Le_LinkIssuer="$API$Le_LinkIssuer" fi diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 7cd286a1..19d95c1a 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -61,7 +61,7 @@ dns_cf_add(){ _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \"| head -1) + record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \"| head -n 1) _debug "record_id" $record_id _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" @@ -103,7 +103,7 @@ _get_root() { fi if printf $response | grep \"name\":\"$h\" >/dev/null ; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | head -1 | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | head -n 1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ] ; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) _domain=$h From fdcb6b721c660235c0d8bdcada9086622575e3b8 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 30 Sep 2016 22:13:27 +0800 Subject: [PATCH 0337/1348] fix for busybox --- acme.sh | 28 +++++++++++++++++++++++----- dnsapi/dns_cx.sh | 4 ++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 13dc865d..3b3891fa 100755 --- a/acme.sh +++ b/acme.sh @@ -1246,6 +1246,24 @@ _stopserver(){ fi } +# sleep sec +_sleep() { + _sleep_sec="$1" + if [ "$__INTERACTIVE" ] ; then + printf "\n" + _sleep_c="$_sleep_sec" + while [ "$_sleep_c" -ge "0" ] ; + do + printf "\r" + __green "$_sleep_c" + _sleep_c="$(_math $_sleep_c - 1)" + sleep 1 + done + printf "\n" + else + sleep "$_sleep_sec" + fi +} # _starttlsserver san_a san_b port content _starttlsserver() { @@ -1290,7 +1308,7 @@ _starttlsserver() { fi serverproc="$!" - sleep 2 + _sleep 2 _debug serverproc $serverproc } @@ -2070,7 +2088,7 @@ issue() { return 1 fi - entry="$(printf "%s\n" "$response" | _egrep_o '[^{]*"type":"'$vtype'"[^}]*')" + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ] ; then _err "Error, can not get domain token $d" @@ -2198,7 +2216,7 @@ issue() { fi _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" - sleep $Le_DNSSleep + _sleep $Le_DNSSleep fi _debug "ok, let's start to verify" @@ -2366,7 +2384,7 @@ issue() { fi if [ "$status" = "invalid" ] ; then - error="$(echo "$response" | _egrep_o '"error":\{[^}]*}')" + error="$(echo "$response" | _egrep_o '"error":\{[^\}]*\}')" _debug2 error "$error" errordetail="$(echo $error | _egrep_o '"detail": *"[^"]*"' | cut -d '"' -f 4)" _debug2 errordetail "$errordetail" @@ -2944,7 +2962,7 @@ _deactivate() { return 1 fi - entry="$(printf "%s\n" "$response" | _egrep_o '[^{]*"status":"valid","uri"[^}]*')" + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"status":"valid","uri"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ] ; then diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 60951722..1a2e04e7 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -69,7 +69,7 @@ existing_records() { return 1 fi count=0 - seg=$(printf "%s\n" "$response" | _egrep_o "{[^{]*host\":\"$_sub_domain\"[^}]*}") + seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") _debug seg "$seg" if [ -z "$seg" ] ; then return 0 @@ -145,7 +145,7 @@ _get_root() { fi if printf "$response" | grep "$h." >/dev/null ; then - seg=$(printf "%s" "$response" | _egrep_o "{[^{]*\"$h\.\"[^}]*\}" ) + seg=$(printf "%s" "$response" | _egrep_o "\{[^\{]*\"$h\.\"[^\}]*\}" ) _debug seg "$seg" _domain_id=$(printf "%s" "$seg" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" From c583d6bb49a7ade30c511b0ed6f4fc21be7f721b Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 30 Sep 2016 22:43:24 +0800 Subject: [PATCH 0338/1348] fix sleep display --- acme.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 3b3891fa..90dd23e4 100755 --- a/acme.sh +++ b/acme.sh @@ -1250,16 +1250,15 @@ _stopserver(){ _sleep() { _sleep_sec="$1" if [ "$__INTERACTIVE" ] ; then - printf "\n" _sleep_c="$_sleep_sec" while [ "$_sleep_c" -ge "0" ] ; do - printf "\r" + printf "\r \r" __green "$_sleep_c" _sleep_c="$(_math $_sleep_c - 1)" sleep 1 done - printf "\n" + printf "\r" else sleep "$_sleep_sec" fi @@ -1308,7 +1307,7 @@ _starttlsserver() { fi serverproc="$!" - _sleep 2 + sleep 2 _debug serverproc $serverproc } From 6ae0f7f5c6f207d47a2a72a882e50b6ae76d6ba5 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 2 Oct 2016 23:37:37 +0800 Subject: [PATCH 0339/1348] support "--listen-v4" and "--listen-v6" (#311) https://github.com/Neilpang/acme.sh/issues/310 --- acme.sh | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 90dd23e4..ca892060 100755 --- a/acme.sh +++ b/acme.sh @@ -1199,8 +1199,16 @@ _startserver() { fi fi - _debug "_NC" "$_NC" _debug Le_HTTPPort "$Le_HTTPPort" + _debug Le_Listen_V4 "$Le_Listen_V4" + _debug Le_Listen_V6 "$Le_Listen_V6" + if [ "$Le_Listen_V4" ] ; then + _NC="$_NC -4" + elif [ "$Le_Listen_V6" ] ; then + _NC="$_NC -6" + fi + _debug "_NC" "$_NC" + # while true ; do if [ "$DEBUG" ] ; then if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then @@ -1264,13 +1272,14 @@ _sleep() { fi } -# _starttlsserver san_a san_b port content +# _starttlsserver san_a san_b port content _ncaddr _starttlsserver() { _info "Starting tls server." san_a="$1" san_b="$2" port="$3" content="$4" + opaddr="$5" _debug san_a "$san_a" _debug san_b "$san_b" @@ -1298,12 +1307,27 @@ _starttlsserver() { return 1 fi + __S_OPENSSL="openssl s_server -cert $TLS_CERT -key $TLS_KEY " + if [ "$opaddr" ] ; then + __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" + else + __S_OPENSSL="$__S_OPENSSL -accept $port" + fi + + _debug Le_Listen_V4 "$Le_Listen_V4" + _debug Le_Listen_V6 "$Le_Listen_V6" + if [ "$Le_Listen_V4" ] ; then + __S_OPENSSL="$__S_OPENSSL -4" + elif [ "$Le_Listen_V6" ] ; then + __S_OPENSSL="$__S_OPENSSL -6" + fi + #start openssl - _debug "openssl s_server -cert \"$TLS_CERT\" -key \"$TLS_KEY\" -accept $port -tlsextdebug" + _debug "$__S_OPENSSL" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -tlsextdebug ) & + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | $__S_OPENSSL -tlsextdebug ) & else - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | $__S_OPENSSL >/dev/null 2>&1) & fi serverproc="$!" @@ -1997,6 +2021,16 @@ issue() { _savedomainconf "Le_RenewHook" "$Le_RenewHook" _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" + + if [ "$Le_Listen_V4" ] ; then + _savedomainconf "Le_Listen_V4" "$Le_Listen_V4" + _cleardomainconf Le_Listen_V6 + elif [ "$Le_Listen_V6" ] ; then + _savedomainconf "Le_Listen_V6" "$Le_Listen_V6" + _cleardomainconf Le_Listen_V4 + fi + + Le_API="$API" _savedomainconf "Le_API" "$Le_API" @@ -3435,7 +3469,7 @@ Parameters: --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 server listening address, in case you have multiple ip addresses. + --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 '--renewall' 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. @@ -3448,6 +3482,8 @@ Parameters: --renew-hook Command to be run once for each successfully renewed certificate. --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. + --listen-v4 Force standalone/tls server to listen at ipv4. + --listen-v6 Force standalone/tls server to listen at ipv6. " } @@ -3555,6 +3591,8 @@ _process() { _local_address="" _log_level="" _auto_upgrade="" + _listen_v4="" + _listen_v6="" while [ ${#} -gt 0 ] ; do case "${1}" in @@ -3870,6 +3908,14 @@ _process() { fi AUTO_UPGRADE="$_auto_upgrade" ;; + --listen-v4) + _listen_v4="1" + Le_Listen_V4="$_listen_v4" + ;; + --listen-v6) + _listen_v6="1" + Le_Listen_V6="$_listen_v6" + ;; *) _err "Unknown parameter : $1" From 50827188ffb591b1229ae1b2dce64635a3d16ebc Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 2 Oct 2016 23:54:21 +0800 Subject: [PATCH 0340/1348] minor: save on success --- acme.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index ca892060..f171e8e8 100755 --- a/acme.sh +++ b/acme.sh @@ -2022,15 +2022,6 @@ issue() { _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" - if [ "$Le_Listen_V4" ] ; then - _savedomainconf "Le_Listen_V4" "$Le_Listen_V4" - _cleardomainconf Le_Listen_V6 - elif [ "$Le_Listen_V6" ] ; then - _savedomainconf "Le_Listen_V6" "$Le_Listen_V6" - _cleardomainconf Le_Listen_V4 - fi - - Le_API="$API" _savedomainconf "Le_API" "$Le_API" @@ -2542,6 +2533,14 @@ issue() { _clearaccountconf "HTTPS_INSECURE" fi + if [ "$Le_Listen_V4" ] ; then + _savedomainconf "Le_Listen_V4" "$Le_Listen_V4" + _cleardomainconf Le_Listen_V6 + elif [ "$Le_Listen_V6" ] ; then + _savedomainconf "Le_Listen_V6" "$Le_Listen_V6" + _cleardomainconf Le_Listen_V4 + fi + Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) From 9f43c270e69303f23a48d5967d364e86297ce36b Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 3 Oct 2016 22:08:40 +0800 Subject: [PATCH 0341/1348] fix wget --- acme.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index f171e8e8..0a4e7061 100755 --- a/acme.sh +++ b/acme.sh @@ -952,6 +952,10 @@ _post() { fi fi _ret="$?" + if [ "$_ret" = "8" ] ; then + _ret=0 + _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." + fi if [ "$_ret" != "0" ] ; then _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" fi @@ -1008,6 +1012,10 @@ _get() { $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url fi ret=$? + if [ "$_ret" = "8" ] ; then + _ret=0 + _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." + fi if [ "$ret" != "0" ] ; then _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" fi @@ -1068,7 +1076,7 @@ _send_signed_request() { response="$(_post "$body" $url "$needbase64")" if [ "$?" != "0" ] ; then - _err "Can not post to $url." + _err "Can not post to $url" return 1 fi _debug2 original "$response" From c2c8f32010c255acd7382f0ea2922cbce348facb Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 3 Oct 2016 22:29:48 +0800 Subject: [PATCH 0342/1348] fix for wget --- acme.sh | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 0a4e7061..0d663a4b 100755 --- a/acme.sh +++ b/acme.sh @@ -1027,6 +1027,13 @@ _get() { return $ret } +_head_n() { + head -n $1 +} + +_tail_n() { + tail -n $1 +} # url payload needbase64 keyfile _send_signed_request() { @@ -1057,7 +1064,7 @@ _send_signed_request() { _debug3 _headers "$_headers" - nonce="$( echo "$_headers" | grep "Replay-Nonce:" | head -n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + nonce="$( echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" _debug3 nonce "$nonce" @@ -1087,7 +1094,7 @@ _send_signed_request() { _debug2 responseHeaders "$responseHeaders" _debug2 response "$response" - code="$(grep "^HTTP" $HTTP_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )" + code="$(grep "^HTTP" $HTTP_HEADER | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n" )" _debug code $code } @@ -1938,10 +1945,10 @@ _regAccount() { return 1 fi - _accUri="$(echo "$responseHeaders" | grep "^Location:" | cut -d ' ' -f 2| tr -d "\r\n")" + _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2| tr -d "\r\n")" _debug "_accUri" "$_accUri" - _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _egrep_o "<.*>" | tr -d '<>')" + _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')" _debug "_tos" "$_tos" if [ -z "$_tos" ] ; then _debug "Use default tos: $DEFAULT_AGREEMENT" @@ -2462,7 +2469,7 @@ issue() { fi _rcert="$response" - Le_LinkCert="$(grep -i '^Location.*$' $HTTP_HEADER | head -n 1 | tr -d "\r\n" | cut -d " " -f 2)" + Le_LinkCert="$(grep -i '^Location.*$' $HTTP_HEADER | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ "$Le_LinkCert" ] ; then @@ -2501,7 +2508,7 @@ issue() { _cleardomainconf "Le_Vlist" - Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -n 1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) + Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | _head_n 1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) if ! _contains "$Le_LinkIssuer" ":" ; then Le_LinkIssuer="$API$Le_LinkIssuer" fi @@ -2994,7 +3001,7 @@ _deactivate() { return 1 fi - authzUri="$(echo "$responseHeaders" | grep "^Location:" | cut -d ' ' -f 2 | tr -d "\r\n")" + authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "authzUri" "$authzUri" if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then From 656bd330f81a6bee6c9ba00012d59c190eba01cd Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 4 Oct 2016 20:55:31 +0800 Subject: [PATCH 0343/1348] change default renew days o 60. fix https://github.com/Neilpang/acme.sh/issues/314 https://github.com/Neilpang/acme.sh/issues/281 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 0d663a4b..cf83f250 100755 --- a/acme.sh +++ b/acme.sh @@ -27,7 +27,7 @@ VTYPE_TLS2="tls-sni-02" LOCAL_ANY_ADDRESS="0.0.0.0" -MAX_RENEW=80 +MAX_RENEW=60 DEFAULT_DNS_SLEEP=120 From d2ae7e78ef266d8629618fefedd76f65492f7ed3 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 4 Oct 2016 21:17:19 +0800 Subject: [PATCH 0344/1348] 60 days --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fcd8c28c..1e3623e8 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ You must point and bind all the domains to the same webroot dir: `/home/wwwroot/ Generate/issued certs will be placed in `~/.acme.sh/aa.com/` -The issued cert will be renewed every 80 days automatically. +The issued cert will be renewed every **60** days automatically. More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert @@ -152,7 +152,7 @@ Only the domain is required, all the other parameters are optional. Install/copy the issued cert/key to the production apache or nginx path. -The cert will be `renewed every 80 days by default` (which is configurable). Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`. +The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`. # 4. Use Standalone server to issue cert @@ -283,7 +283,7 @@ Valid values are: # 10. How to renew the cert -No, you don't need to renew the certs manually. All the certs will be renewed automatically every 80 days. +No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. However, you can also force to renew any cert: From 3d826bed3afdb2b9f61d069c3810f9cff9aa284c Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 4 Oct 2016 23:35:56 +0800 Subject: [PATCH 0345/1348] fix for ncat on centos, try without '-p' first (#315) --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index cf83f250..e6c5b71c 100755 --- a/acme.sh +++ b/acme.sh @@ -1226,12 +1226,12 @@ _startserver() { # while true ; do if [ "$DEBUG" ] ; then - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; fi else - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1 fi fi if [ "$?" != "0" ] ; then From aa7b82de04a330a0d66e3a345210b822f3447b77 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 5 Oct 2016 12:15:06 +0800 Subject: [PATCH 0346/1348] minor --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index cf83f250..ab2de269 100755 --- a/acme.sh +++ b/acme.sh @@ -4058,4 +4058,8 @@ main() { if _startswith "$1" '-' ; then _process "$@"; else "$@";fi } -main "$@" \ No newline at end of file + +main "$@" + + + From 19ab2a29ce835cf233dc23b6109c55ce7f9b754b Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 5 Oct 2016 13:03:45 +0800 Subject: [PATCH 0347/1348] fix tail for solaris --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5d22b074..b3ab3d61 100755 --- a/acme.sh +++ b/acme.sh @@ -1032,7 +1032,10 @@ _head_n() { } _tail_n() { - tail -n $1 + if ! tail -n $1 2>/dev/null ; then + #fix for solaris + tail -$1 + fi } # url payload needbase64 keyfile From bb25febd70cc45e257b349495113c7f282ab8ea0 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 5 Oct 2016 22:09:15 +0800 Subject: [PATCH 0348/1348] Checkdomain (#317) * check if domains are changed * fix output info --- acme.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b3ab3d61..c385beb3 100755 --- a/acme.sh +++ b/acme.sh @@ -2024,9 +2024,18 @@ issue() { Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(_time) -lt $Le_NextRenewTime ] ; then - _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" - _info "Add '$(__red '--force')' to force to renew." - return $RENEW_SKIP + _saved_domain=$(_readdomainconf Le_Domain) + _debug _saved_domain "$_saved_domain" + _saved_alt=$(_readdomainconf Le_Alt) + _debug _saved_alt "$_saved_alt" + if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ] ; then + _info "Domains not changed." + _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" + _info "Add '$(__red '--force')' to force to renew." + return $RENEW_SKIP + else + _info "Domains have changed." + fi fi fi From d6f0c2b52b4bb0438d05bb26bed8825a15fbd923 Mon Sep 17 00:00:00 2001 From: Maxim Zalysin Date: Sun, 9 Oct 2016 16:56:04 +0300 Subject: [PATCH 0349/1348] Add support PowerDNS API (#322) * Add support PowerDNS API * Small fixes --- README.md | 3 +- acme.sh | 7 +++ dnsapi/README.md | 27 ++++++++-- dnsapi/dns_pdns.sh | 127 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 4 deletions(-) create mode 100755 dnsapi/dns_pdns.sh diff --git a/README.md b/README.md index 1e3623e8..c207704b 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,8 @@ You don't have do anything manually! 4. Godaddy.com API 5. OVH, kimsufi, soyoustart and runabove API 6. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 -7. lexicon dns api: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api +7. PowerDNS API, see: https://doc.powerdns.com/md/httpapi/README/ +8. 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.) ##### More APIs are coming soon... diff --git a/acme.sh b/acme.sh index c385beb3..9387dcec 100755 --- a/acme.sh +++ b/acme.sh @@ -3173,6 +3173,13 @@ _initconf() { # #GD_Secret=\"sADDsdasdfsdfdssdgdsf\" +####################### +#PowerDNS: +#PDNS_Url=\"http://ns.example.com:8081\" +#PDNS_ServerId=\"localhost\" +#PDNS_Token=\"0123456789ABCDEF\" +#PDNS_Ttl=60 + " > $ACCOUNT_CONF_PATH fi } diff --git a/dnsapi/README.md b/dnsapi/README.md index 5aa52cdf..e17406e3 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -66,7 +66,7 @@ The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf`, when n ## Use Godaddy.com domain api to automatically issue cert -We support Godaddy integeration. +We support Godaddy integration. First you need to login to your Godaddy account to get your api key and api secret. @@ -89,6 +89,29 @@ acme.sh --issue --dns dns_gd -d aa.com -d www.aa.com The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. +## Use PowerDNS embedded api to automatically issue cert + +We support PowerDNS embedded API integration. + +First you need to enable api and set your api-token in PowerDNS configuration. + +https://doc.powerdns.com/md/httpapi/README/ + +``` +export PDNS_Url="http://ns.example.com:8081" +export PDNS_ServerId="localhost" +export PDNS_Token="0123456789ABCDEF" +export PDNS_Ttl=60 + +``` + +Ok, let's issue cert now: +``` +acme.sh --issue --dns dns_pdns -d aa.com -d www.aa.com +``` + +The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf`. + ## Use OVH/kimsufi/soyoustart/runabove API https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api @@ -109,8 +132,6 @@ acme.sh --issue --dns dns_myapi -d aa.com -d www.aa.com For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) - - # Use lexicon dns api https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh new file mode 100755 index 00000000..842a5b82 --- /dev/null +++ b/dnsapi/dns_pdns.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env sh + +#PowerDNS Emdedded API +#https://doc.powerdns.com/md/httpapi/api_spec/ +# +#PDNS_Url="http://ns.example.com:8081" +#PDNS_ServerId="localhost" +#PDNS_Token="0123456789ABCDEF" +#PDNS_Ttl=60 + +######## Public functions ##################### +#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" +dns_pdns_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$PDNS_Url" ] ; then + _err "You don't specify PowerDNS address." + _err "Please set PDNS_Url and try again." + return 1 + fi + + if [ -z "$PDNS_ServerId" ] ; then + _err "You don't specify PowerDNS server id." + _err "Please set you PDNS_ServerId and try again." + return 1 + fi + + if [ -z "$PDNS_Token" ] ; then + _err "You don't specify PowerDNS token." + _err "Please create you PDNS_Token and try again." + return 1 + fi + + if [ -z "$PDNS_Ttl" ] ; then + PDNS_Ttl=60 + fi + + #save the api addr and key to the account conf file. + _saveaccountconf PDNS_Url "$PDNS_Url" + _saveaccountconf PDNS_ServerId "$PDNS_ServerId" + _saveaccountconf PDNS_Token "$PDNS_Token" + + _debug "First detect the root zone" + if ! _get_root $fulldomain ; then + _err "invalid domain" + return 1 + fi + _debug _domain "$_domain" + + if ! set_record "$_domain" "$fulldomain" "$txtvalue" ; then + return 1 + fi + + return 0 +} + +set_record() { + _info "Adding record" + root=$1 + full=$2 + txtvalue=$3 + + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"name\": \"$full.\", \"changetype\": \"REPLACE\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}" ; then + _err "Set txt record error." + return 1 + fi + if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify" ; then + _err "Notify servers error." + return 1 + fi + return 0 +} + +#################### Private functions bellow ################################## +#_acme-challenge.www.domain.com +#returns +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + p=1 + + if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones" ; then + _zones_response=$response + fi + + while [ '1' ] ; do + h=$(printf $domain | cut -d . -f $i-100) + if [ -z "$h" ] ; then + return 1 + fi + + if printf "$_zones_response" | grep "\"name\": \"$h.\"" >/dev/null ; then + _domain=$h + return 0 + fi + + p=$i + i=$(expr $i + 1) + done + _debug "$domain not found" + return 1 +} + +_pdns_rest() { + method=$1 + ep=$2 + data=$3 + + _H1="X-API-Key: $PDNS_Token" + + if [ ! "$method" = "GET" ] ; then + _debug data "$data" + response="$(_post "$data" "$PDNS_Url$ep" "" "$method")" + else + response="$(_get "$PDNS_Url$ep")" + fi + + if [ "$?" != "0" ] ; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + + return 0 +} \ No newline at end of file From b9311282eb6ecf381dc4c2c0acbdb2085fdfe8f2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 9 Oct 2016 22:15:15 +0800 Subject: [PATCH 0350/1348] minor fix pdns api --- dnsapi/dns_pdns.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 842a5b82..30c6d658 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -8,6 +8,8 @@ #PDNS_Token="0123456789ABCDEF" #PDNS_Ttl=60 +DEFAULT_PDNS_TTL=60 + ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" dns_pdns_add() { @@ -33,13 +35,17 @@ dns_pdns_add() { fi if [ -z "$PDNS_Ttl" ] ; then - PDNS_Ttl=60 + PDNS_Ttl=$DEFAULT_PDNS_TTL fi #save the api addr and key to the account conf file. _saveaccountconf PDNS_Url "$PDNS_Url" _saveaccountconf PDNS_ServerId "$PDNS_ServerId" _saveaccountconf PDNS_Token "$PDNS_Token" + + if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ] ; then + _saveaccountconf PDNS_Ttl "$PDNS_Ttl" + fi _debug "First detect the root zone" if ! _get_root $fulldomain ; then From 483ebc81410a87fbbe4f30343606d2e29aa55758 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 9 Oct 2016 22:17:45 +0800 Subject: [PATCH 0351/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c207704b..609de73c 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,7 @@ You don't have do anything manually! 4. Godaddy.com API 5. OVH, kimsufi, soyoustart and runabove API 6. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 -7. PowerDNS API, see: https://doc.powerdns.com/md/httpapi/README/ +7. PowerDNS API 8. 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.) From 095fe2ed1b1e338e012174a6244d7e34ab9035ee Mon Sep 17 00:00:00 2001 From: root Date: Sun, 9 Oct 2016 22:19:35 +0800 Subject: [PATCH 0352/1348] minor --- dnsapi/dns_ovh.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 dnsapi/dns_ovh.sh diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh old mode 100644 new mode 100755 From 66990cf872e1c9c7878b11be8a03854ca62bb128 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 9 Oct 2016 22:27:25 +0800 Subject: [PATCH 0353/1348] minor --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 9387dcec..19a8296c 100755 --- a/acme.sh +++ b/acme.sh @@ -1368,7 +1368,7 @@ _readlink() { __initHome() { if [ -z "$_SCRIPT_HOME" ] ; then if _exists readlink && _exists dirname ; then - _debug "Lets guess script dir." + _debug "Lets find script dir." _debug "_SCRIPT_" "$_SCRIPT_" _script="$(_readlink "$_SCRIPT_")" _debug "_script" "$_script" @@ -3362,7 +3362,7 @@ install() { if [ -z "$NO_DETECT_SH" ] ; then #Modify shebang if _exists bash ; then - _info "Good, bash is installed, change the shebang to use bash as prefered." + _info "Good, bash is found, so change the shebang to use bash as prefered." _shebang='#!/usr/bin/env bash' _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" if [ -d "$LE_WORKING_DIR/dnsapi" ] ; then From f78babfaa0ad334cdb6056bed02562abb1c8749a Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 10 Oct 2016 19:47:16 +0800 Subject: [PATCH 0354/1348] nc (#324) --- acme.sh | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 19a8296c..fc7aa7b7 100755 --- a/acme.sh +++ b/acme.sh @@ -1205,26 +1205,30 @@ _startserver() { _debug "startserver: $$" nchelp="$(nc -h 2>&1)" - if echo "$nchelp" | grep "\-q[ ,]" >/dev/null ; then - _NC="nc -q 1 -l $ncaddr" - else - if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then - _NC="nc -c -l $ncaddr" - elif echo "$nchelp" | grep "\-N" |grep "Shutdown the network socket after EOF on stdin" >/dev/null ; then - _NC="nc -N -l $ncaddr" - else - _NC="nc -l $ncaddr" - fi - fi - _debug Le_HTTPPort "$Le_HTTPPort" _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" + _NC="nc" + if [ "$Le_Listen_V4" ] ; then _NC="$_NC -4" elif [ "$Le_Listen_V6" ] ; then _NC="$_NC -6" fi + + if echo "$nchelp" | grep "\-q[ ,]" >/dev/null ; then + _NC="$_NC -q 1 -l $ncaddr" + else + if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then + _NC="$_NC -c -l $ncaddr" + elif echo "$nchelp" | grep "\-N" |grep "Shutdown the network socket after EOF on stdin" >/dev/null ; then + _NC="$_NC -N -l $ncaddr" + else + _NC="$_NC -l $ncaddr" + fi + fi + + _debug "_NC" "$_NC" # while true ; do From 81f27e907723079c82789d82ceb14977a2554e4b Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 11 Oct 2016 18:05:32 +0800 Subject: [PATCH 0355/1348] minor, get the error info, if it contains CRLF --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 19a8296c..98df2e48 100755 --- a/acme.sh +++ b/acme.sh @@ -2435,7 +2435,7 @@ issue() { fi if [ "$status" = "invalid" ] ; then - error="$(echo "$response" | _egrep_o '"error":\{[^\}]*\}')" + error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*\}')" _debug2 error "$error" errordetail="$(echo $error | _egrep_o '"detail": *"[^"]*"' | cut -d '"' -f 4)" _debug2 errordetail "$errordetail" @@ -2447,7 +2447,7 @@ issue() { if [ "$DEBUG" ] ; then if [ "$vtype" = "$VTYPE_HTTP" ] ; then _debug "Debug: get token url." - _get "http://$d/.well-known/acme-challenge/$token" + _get "http://$d/.well-known/acme-challenge/$token" "" 1 fi fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" From b15cfc2c5a5f8f7a80ae01d270b91652721e288a Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 11 Oct 2016 18:30:38 +0800 Subject: [PATCH 0356/1348] minor --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7536a2d9..9ff54d32 100755 --- a/acme.sh +++ b/acme.sh @@ -2439,9 +2439,9 @@ issue() { fi if [ "$status" = "invalid" ] ; then - error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*\}')" + error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*')" _debug2 error "$error" - errordetail="$(echo $error | _egrep_o '"detail": *"[^"]*"' | cut -d '"' -f 4)" + errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)" _debug2 errordetail "$errordetail" if [ "$errordetail" ] ; then _err "$d:Verify error:$errordetail" From a61fe418b2b6b8c8d53a678feda57aab9a556902 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 11 Oct 2016 20:56:59 +0800 Subject: [PATCH 0357/1348] support deploy api --- acme.sh | 138 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 113 insertions(+), 25 deletions(-) diff --git a/acme.sh b/acme.sh index 9ff54d32..3e3f7799 100755 --- a/acme.sh +++ b/acme.sh @@ -11,6 +11,7 @@ PROJECT="https://github.com/Neilpang/$PROJECT_NAME" DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME" _SCRIPT_="$0" +_SUB_FOLDERS="dnsapi deploy" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" @@ -1987,6 +1988,29 @@ _regAccount() { } +# domain folder file +_findHook() { + _hookdomain="$1" + _hookcat="$2" + _hookname="$3" + + if [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ] ; then + d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname" + elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ] ; then + d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" + elif [ -f "$LE_WORKING_DIR/$_hookname" ] ; then + d_api="$LE_WORKING_DIR/$_hookname" + elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ] ; then + d_api="$LE_WORKING_DIR/$_hookname.sh" + elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ] ; then + d_api="$LE_WORKING_DIR/$_hookcat/$_hookname" + elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ] ; then + d_api="$LE_WORKING_DIR/$_hookcat/$_hookname.sh" + fi + + printf "%s" "$d_api" +} + #webroot, domain domainlist keylength issue() { if [ -z "$2" ] ; then @@ -2196,22 +2220,9 @@ issue() { _debug txtdomain "$txtdomain" txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)" _debug txt "$txt" - #dns - #1. check use api - d_api="" - if [ -f "$LE_WORKING_DIR/$d/$_currentRoot" ] ; then - d_api="$LE_WORKING_DIR/$d/$_currentRoot" - elif [ -f "$LE_WORKING_DIR/$d/$_currentRoot.sh" ] ; then - d_api="$LE_WORKING_DIR/$d/$_currentRoot.sh" - elif [ -f "$LE_WORKING_DIR/$_currentRoot" ] ; then - d_api="$LE_WORKING_DIR/$_currentRoot" - elif [ -f "$LE_WORKING_DIR/$_currentRoot.sh" ] ; then - d_api="$LE_WORKING_DIR/$_currentRoot.sh" - elif [ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot" ] ; then - d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot" - elif [ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" ] ; then - d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" - fi + + d_api="$(_findHook $d dnsapi $_currentRoot)" + _debug d_api "$d_api" if [ "$d_api" ] ; then @@ -2627,6 +2638,15 @@ renew() { IS_RENEW="1" issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" res=$? + if [ "$res" != "0" ] ; then + return $res + fi + + if [ "$Le_DeployHook" ] ; then + deploy $Le_Domain "$Le_DeployHook" "$Le_Keylength" + res=$? + fi + IS_RENEW="" return $res @@ -2788,6 +2808,56 @@ list() { } +deploy() { + Le_Domain="$1" + Le_DeployHook="$2" + _isEcc="$3" + if [ -z "$Le_DeployHook" ] ; then + _usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] " + return 1 + fi + + _initpath $Le_Domain "$_isEcc" + if [ ! -d "$DOMAIN_PATH" ] ; then + _err "Domain is not valid:'$Le_Domain'" + return 1 + fi + + _deployApi="$(_findHook $Le_Domain deploy $Le_DeployHook)" + if [ -z "$_deployApi" ] ; then + _err "The deploy hook $Le_DeployHook is not found." + return 1 + fi + _debug _deployApi "$_deployApi" + + _savedomainconf Le_DeployHook "$Le_DeployHook" + + if ! ( + if ! . $_deployApi ; then + _err "Load file $_deployApi error. Please check your api file and try again." + return 1 + fi + + d_command="${Le_DeployHook}_deploy" + if ! _exists $d_command ; then + _err "It seems that your api file is not correct, it must have a function named: $d_command" + return 1 + fi + + if ! $d_command $Le_Domain "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH" ; then + _err "Error deploy for domain:$Le_Domain" + _on_issue_err + return 1 + fi + ) ; then + _err "Deploy error." + return 1 + else + _info "$(__green Success)" + fi + +} + installcert() { Le_Domain="$1" if [ -z "$Le_Domain" ] ; then @@ -3338,10 +3408,13 @@ install() { _installalias - if [ -d "dnsapi" ] ; then - mkdir -p $LE_WORKING_DIR/dnsapi - cp dnsapi/* $LE_WORKING_DIR/dnsapi/ - fi + for subf in $_SUB_FOLDERS ; do + if [ -d "$subf" ] ; then + mkdir -p $LE_WORKING_DIR/$subf + cp $subf/* $LE_WORKING_DIR/$subf/ + fi + done + if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then _initconf @@ -3369,11 +3442,13 @@ install() { _info "Good, bash is found, so change the shebang to use bash as prefered." _shebang='#!/usr/bin/env bash' _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" - if [ -d "$LE_WORKING_DIR/dnsapi" ] ; then - for _apifile in $(ls "$LE_WORKING_DIR/dnsapi/"*.sh) ; do - _setShebang "$_apifile" "$_shebang" - done - fi + for subf in $_SUB_FOLDERS ; do + if [ -d "$LE_WORKING_DIR/$subf" ] ; then + for _apifile in "$LE_WORKING_DIR/$subf/"*.sh ; do + _setShebang "$_apifile" "$_shebang" + done + fi + done fi fi @@ -3453,6 +3528,7 @@ Commands: --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT . --issue Issue a cert. --signcsr Issue a cert from an existing csr. + --deploy Deploy the cert to your server. --installcert Install the issued cert to apache/nginx or any other server. --renew, -r Renew a cert. --renewAll Renew all the certs. @@ -3517,6 +3593,7 @@ Parameters: --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. --renew-hook Command to be run once for each successfully renewed certificate. + --deploy-hook The hook file to deploy cert --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. --listen-v4 Force standalone/tls server to listen at ipv4. @@ -3623,6 +3700,7 @@ _process() { _pre_hook="" _post_hook="" _renew_hook="" + _deploy_hook="" _logfile="" _log="" _local_address="" @@ -3653,6 +3731,9 @@ _process() { --issue) _CMD="issue" ;; + --deploy) + _CMD="deploy" + ;; --signcsr) _CMD="signcsr" ;; @@ -3915,6 +3996,10 @@ _process() { _renew_hook="$2" shift ;; + --deploy-hook) + _deploy_hook="$2" + shift + ;; --ocsp-must-staple|--ocsp) Le_OCSP_Stable="1" ;; @@ -3992,6 +4077,9 @@ _process() { issue) issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" ;; + deploy) + deploy "$_domain" "$_deploy_hook" "$_ecc" + ;; signcsr) signcsr "$_csr" "$_webroot" ;; From 661f05837c803ff4bd078e1f051816b102b56a99 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 12 Oct 2016 21:48:18 +0800 Subject: [PATCH 0358/1348] minor --- acme.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 9ff54d32..b56d7698 100755 --- a/acme.sh +++ b/acme.sh @@ -3965,13 +3965,15 @@ _process() { if [ "${_CMD}" != "install" ] ; then __initHome - if [ "$_log" ] && [ -z "$_logfile" ] ; then - _logfile="$DEFAULT_LOG_FILE" + if [ "$_log" ]; then + if [ -z "$_logfile" ] ; then + _logfile="$DEFAULT_LOG_FILE" + fi fi if [ "$_logfile" ] ; then _saveaccountconf "LOG_FILE" "$_logfile" + LOG_FILE="$_logfile" fi - LOG_FILE="$_logfile" if [ "$_log_level" ] ; then _saveaccountconf "LOG_LEVEL" "$_log_level" From d9130c985242c89a2aee0a3b9807da335da08c1d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 12 Oct 2016 22:38:28 +0800 Subject: [PATCH 0359/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index b56d7698..16e8d32c 100755 --- a/acme.sh +++ b/acme.sh @@ -93,7 +93,7 @@ _printargs() { _log() { [ -z "$LOG_FILE" ] && return - _printargs "$@" >> "$LOG_FILE" + _printargs "$@" >> $LOG_FILE } _info() { From caa2e45a8c163e1758fdb00cf15ccd8c1f65b594 Mon Sep 17 00:00:00 2001 From: Peter Lyons Date: Wed, 12 Oct 2016 20:14:36 -0600 Subject: [PATCH 0360/1348] use RFC2606 example.com domain in docs (#327) https://www.rfc-editor.org/rfc/rfc2606.txt --- README.md | 36 ++++++++++++++++++------------------ acme.sh | 2 +- dnsapi/README.md | 12 ++++++------ 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 609de73c..e86392ec 100644 --- a/README.md +++ b/README.md @@ -112,23 +112,23 @@ root@v1:~# acme.sh -h **Example 1:** Single domain. ```bash -acme.sh --issue -d aa.com -w /home/wwwroot/aa.com +acme.sh --issue -d example.com -w /home/wwwroot/example.com ``` **Example 2:** Multiple domains in the same cert. ```bash -acme.sh --issue -d aa.com -d www.aa.com -d cp.aa.com -w /home/wwwroot/aa.com +acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com ``` -The parameter `/home/wwwroot/aa.com` is the web root folder. You **MUST** have `write access` to this folder. +The parameter `/home/wwwroot/example.com` is the web root folder. You **MUST** have `write access` to this folder. -Second argument **"aa.com"** is the main domain you want to issue cert for. +Second argument **"example.com"** is the main domain you want to issue cert for. You must have at least a domain there. -You must point and bind all the domains to the same webroot dir: `/home/wwwroot/aa.com`. +You must point and bind all the domains to the same webroot dir: `/home/wwwroot/example.com`. -Generate/issued certs will be placed in `~/.acme.sh/aa.com/` +Generate/issued certs will be placed in `~/.acme.sh/example.com/` The issued cert will be renewed every **60** days automatically. @@ -140,7 +140,7 @@ More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert After you issue a cert, you probably want to install/copy the cert to your nginx/apache or other servers you may be using. ```bash -acme.sh --installcert -d aa.com \ +acme.sh --installcert -d example.com \ --certpath /path/to/certfile/in/apache/nginx \ --keypath /path/to/keyfile/in/apache/nginx \ --capath /path/to/ca/certfile/apache/nginx \ @@ -161,7 +161,7 @@ The cert will be `renewed every **60** days by default` (which is configurable). The tcp `80` port **MUST** be free to listen, otherwise you will be prompted to free the `80` port and try again. ```bash -acme.sh --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com +acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com ``` More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert @@ -175,7 +175,7 @@ acme.sh supports `tls-sni-01` validation. The tcp `443` port **MUST** be free to listen, otherwise you will be prompted to free the `443` port and try again. ```bash -acme.sh --issue --tls -d aa.com -d www.aa.com -d cp.aa.com +acme.sh --issue --tls -d example.com -d www.example.com -d cp.example.com ``` More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert @@ -191,7 +191,7 @@ Particularly, if you are running an apache server, you should use apache mode in Just set string "apache" as the second argument, it will force use of apache plugin automatically. ``` -acme.sh --issue --apache -d aa.com -d www.aa.com -d user.aa.com +acme.sh --issue --apache -d example.com -d www.example.com -d user.example.com ``` More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert @@ -201,18 +201,18 @@ More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert Support the `dns-01` challenge. ```bash -acme.sh --issue --dns -d aa.com -d www.aa.com -d user.aa.com +acme.sh --issue --dns -d example.com -d www.example.com -d user.example.com ``` You should get the output like below: ``` Add the following txt record: -Domain:_acme-challenge.aa.com +Domain:_acme-challenge.example.com Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c Add the following txt record: -Domain:_acme-challenge.www.aa.com +Domain:_acme-challenge.www.example.com Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Please add those txt records to the domains. Waiting for the dns to take effect. @@ -222,7 +222,7 @@ Please add those txt records to the domains. Waiting for the dns to take effect. Then just rerun with `renew` argument: ```bash -acme.sh --renew -d aa.com +acme.sh --renew -d example.com ``` Ok, it's finished. @@ -264,13 +264,13 @@ For example: ### Single domain ECC cerfiticate: ```bash -acme.sh --issue -w /home/wwwroot/aa.com -d aa.com --keylength ec-256 +acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256 ``` SAN multi domain ECC certificate: ```bash -acme.sh --issue -w /home/wwwroot/aa.com -d aa.com -d www.aa.com --keylength ec-256 +acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength ec-256 ``` Please look at the last parameter above. @@ -289,12 +289,12 @@ No, you don't need to renew the certs manually. All the certs will be renewed a However, you can also force to renew any cert: ``` -acme.sh --renew -d aa.com --force +acme.sh --renew -d example.com --force ``` or, for ECC cert: ``` -acme.sh --renew -d aa.com --force --ecc +acme.sh --renew -d example.com --force --ecc ``` # 11. How to upgrade `acme.sh` diff --git a/acme.sh b/acme.sh index 16e8d32c..09920730 100755 --- a/acme.sh +++ b/acme.sh @@ -3130,7 +3130,7 @@ _initconf() { #Account configurations: #Here are the supported macros, uncomment them to make them take effect. -#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account. +#ACCOUNT_EMAIL=aaa@example.com # the account email used to register account. #ACCOUNT_KEY_PATH=\"/path/to/account.key\" #CERT_HOME=\"/path/to/cert/home\" diff --git a/dnsapi/README.md b/dnsapi/README.md index e17406e3..94603154 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -15,7 +15,7 @@ export CF_Email="xxxx@sss.com" Ok, let's issue cert now: ``` -acme.sh --issue --dns dns_cf -d aa.com -d www.aa.com +acme.sh --issue --dns dns_cf -d example.com -d www.example.com ``` The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. @@ -37,7 +37,7 @@ export DP_Key="sADDsdasdgdsf" Ok, let's issue cert now: ``` -acme.sh --issue --dns dns_dp -d aa.com -d www.aa.com +acme.sh --issue --dns dns_dp -d example.com -d www.example.com ``` The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf`, when next time you use dnspod.cn api, it will reuse this key. @@ -58,7 +58,7 @@ export CX_Secret="sADDsdasdgdsf" Ok, let's issue cert now: ``` -acme.sh --issue --dns dns_cx -d aa.com -d www.aa.com +acme.sh --issue --dns dns_cx -d example.com -d www.example.com ``` The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. @@ -84,7 +84,7 @@ export GD_Secret="asdfsdafdsfdsfdsfdsfdsafd" Ok, let's issue cert now: ``` -acme.sh --issue --dns dns_gd -d aa.com -d www.aa.com +acme.sh --issue --dns dns_gd -d example.com -d www.example.com ``` The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. @@ -107,7 +107,7 @@ export PDNS_Ttl=60 Ok, let's issue cert now: ``` -acme.sh --issue --dns dns_pdns -d aa.com -d www.aa.com +acme.sh --issue --dns dns_pdns -d example.com -d www.example.com ``` The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf`. @@ -127,7 +127,7 @@ Let's assume you want to name it 'myapi', 3. Then you can use your api to issue cert like: ``` -acme.sh --issue --dns dns_myapi -d aa.com -d www.aa.com +acme.sh --issue --dns dns_myapi -d example.com -d www.example.com ``` For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) From c9febbdd876888e2b16c1b6b57f7658c63bea91e Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 19 Oct 2016 22:14:42 +0800 Subject: [PATCH 0361/1348] fix for centos ncat and debian default netcat (#330) --- acme.sh | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 09920730..0ea9584f 100755 --- a/acme.sh +++ b/acme.sh @@ -1231,14 +1231,29 @@ _startserver() { _debug "_NC" "$_NC" + #for centos ncat + if _contains "$nchelp" "nmap.org" ; then + _debug "Using ncat: nmap.org" + if [ "$DEBUG" ] ; then + if printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; then + return + fi + else + if printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1; then + return + fi + fi + _err "ncat listen error." + fi + # while true ; do if [ "$DEBUG" ] ; then - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; fi else - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1 + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 fi fi if [ "$?" != "0" ] ; then From ecf0a710e13cc233d897c6634e0f632dbae2f0ed Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 21 Oct 2016 18:26:35 +0800 Subject: [PATCH 0362/1348] fix typo --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 0ea9584f..1e6b0a56 100755 --- a/acme.sh +++ b/acme.sh @@ -939,13 +939,13 @@ _post() { elif _exists "wget" ; then _debug "WGET" "$WGET" if [ "$needbase64" ] ; then - if [ "$httpmethod"="POST" ] ; then + if [ "$httpmethod" = "POST" ] ; then response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" else response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" fi else - if [ "$httpmethod"="POST" ] ; then + if [ "$httpmethod" = "POST" ] ; then response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" else response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" From 9774b01b0ed721bc49caf915ad6a50c85eacec85 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 23 Oct 2016 14:56:52 +0800 Subject: [PATCH 0363/1348] 2.6.1 support IDN (#335) * Support IDN * fix deactivate idn name * 2.6.1 support IDN --- acme.sh | 53 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 1e6b0a56..5a0ee4e7 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.0 +VER=2.6.1 PROJECT_NAME="acme.sh" @@ -482,6 +482,42 @@ _createkey() { fi } + +#domain +_is_idn() { + _is_idn_d="$1" + echo "$_is_idn_d" | grep "[^0-9a-zA-Z.,]" >/dev/null 2>&1 +} + +#aa.com +#aa.com,bb.com,cc.com +_idn() { + __idn_d="$1" + if ! _is_idn "$__idn_d" ; then + printf "%s" "$__idn_d" + return 0 + fi + + if _exists idn ; then + if _contains "$__idn_d" ',' ; then + _i_first="1" + for f in $(echo "$__idn_d" | tr ',' ' ') ; do + [ -z "$f" ] && continue + if [ -z "$_i_first" ] ; then + printf "%s" "," + else + _i_first="" + fi + idn "$f" | tr -d "\r\n" + done + else + idn "$__idn_d" | tr -d "\r\n" + fi + else + _err "Please install idn to process IDN names." + fi +} + #_createcsr cn san_list keyfile csrfile conf _createcsr() { _debug _createcsr @@ -502,6 +538,8 @@ _createcsr() { #single domain _info "Single domain" "$domain" else + domainlist="$(_idn $domainlist)" + _debug2 domainlist "$domainlist" if _contains "$domainlist" "," ; then alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" else @@ -515,7 +553,10 @@ _createcsr() { _savedomainconf Le_OCSP_Stable "$Le_OCSP_Stable" printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >> "$csrconf" fi - openssl req -new -sha256 -key "$csrkey" -subj "/CN=$domain" -config "$csrconf" -out "$csr" + + _csr_cn="$(_idn "$domain")" + _debug2 _csr_cn "$_csr_cn" + openssl req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" } #_signcsr key csr conf cert @@ -2144,7 +2185,7 @@ issue() { _info "Getting new-authz for domain" $d - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" ; then + if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$d")\"}}" ; then _err "Can not get domain token." _clearup _on_issue_err @@ -3027,7 +3068,7 @@ _deactivate() { do _info "Deactivate: $_d_domain" _d_i="$(_math $_d_i + 1)" - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$_d_domain\"}}" ; then + if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_d_domain")\"}}" ; then _err "Can not get domain token." return 1 fi @@ -3727,6 +3768,10 @@ _process() { _err "'$_dvalue' is not a valid domain for parameter '$1'" return 1 fi + if _is_idn "$_dvalue" && ! _exists idn ; then + _err "It seems that $_dvalue is an IDN( Internationalized Domain Names), please install 'idn' command first." + return 1 + fi if [ -z "$_domain" ] ; then _domain="$_dvalue" From aba5c634ae3865280c3496fabf48b5790434040d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 23 Oct 2016 15:04:52 +0800 Subject: [PATCH 0364/1348] minor, add output info for installing alias. fix https://github.com/Neilpang/acme.sh/issues/332 --- acme.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acme.sh b/acme.sh index 5a0ee4e7..b283ff6b 100755 --- a/acme.sh +++ b/acme.sh @@ -3310,6 +3310,7 @@ _installalias() { _profile="$(_detect_profile)" if [ "$_profile" ] ; then _debug "Found profile: $_profile" + _info "Installing alias to '$_profile'" _setopt "$_profile" ". \"$_envfile\"" _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" else @@ -3321,6 +3322,7 @@ _installalias() { _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh" _csh_profile="$HOME/.cshrc" if [ -f "$_csh_profile" ] ; then + _info "Installing alias to '$_csh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" _setopt "$_csh_profile" "source \"$_cshfile\"" @@ -3329,6 +3331,7 @@ _installalias() { #for tcsh _tcsh_profile="$HOME/.tcshrc" if [ -f "$_tcsh_profile" ] ; then + _info "Installing alias to '$_tcsh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" _setopt "$_tcsh_profile" "source \"$_cshfile\"" From 9aa3be7f9f585ad25f40eed66483f82db0d433a1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 23 Oct 2016 15:10:09 +0800 Subject: [PATCH 0365/1348] add _uninstallalias --- acme.sh | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b283ff6b..4096288d 100755 --- a/acme.sh +++ b/acme.sh @@ -3447,26 +3447,36 @@ uninstall() { fi _initpath + _uninstallalias + + rm -f $LE_WORKING_DIR/$PROJECT_ENTRY + _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." + +} + +_uninstallalias() { + _initpath + _profile="$(_detect_profile)" if [ "$_profile" ] ; then + _info "Uninstalling alias from: '$_profile'" text="$(cat $_profile)" echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" > "$_profile" fi _csh_profile="$HOME/.cshrc" if [ -f "$_csh_profile" ] ; then + _info "Uninstalling alias from: '$_csh_profile'" text="$(cat $_csh_profile)" echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_csh_profile" fi _tcsh_profile="$HOME/.tcshrc" if [ -f "$_tcsh_profile" ] ; then + _info "Uninstalling alias from: '$_csh_profile'" text="$(cat $_tcsh_profile)" echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_tcsh_profile" fi - - rm -f $LE_WORKING_DIR/$PROJECT_ENTRY - _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." } From 049be10406501f9f9d294cd18841818ff1e3d226 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 23 Oct 2016 20:36:32 +0800 Subject: [PATCH 0366/1348] fix idn to support European chars https://github.com/Neilpang/acme.sh/issues/331#issuecomment-255583889 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4096288d..3eccc3c7 100755 --- a/acme.sh +++ b/acme.sh @@ -486,7 +486,10 @@ _createkey() { #domain _is_idn() { _is_idn_d="$1" - echo "$_is_idn_d" | grep "[^0-9a-zA-Z.,]" >/dev/null 2>&1 + _debug2 _is_idn_d "$_is_idn_d" + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d "[0-9a-zA-Z.,-]") + _debug2 _idn_temp "$_idn_temp" + [ "$_idn_temp" ] } #aa.com From 9910ff5fa17caac7f95a93d16d2dc59eebf64117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 25 Oct 2016 14:49:22 +0200 Subject: [PATCH 0367/1348] Allow saved password strings to have special characters. (#334) --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3eccc3c7..a1d19fd6 100755 --- a/acme.sh +++ b/acme.sh @@ -1224,7 +1224,7 @@ _saveaccountconf() { _sckey="$1" _scvalue="$2" if [ "$ACCOUNT_CONF_PATH" ] ; then - _setopt "$ACCOUNT_CONF_PATH" "$_sckey" "=" "\"$_scvalue\"" + _setopt "$ACCOUNT_CONF_PATH" "$_sckey" "=" "'$_scvalue'" else _err "ACCOUNT_CONF_PATH is empty, can not save $_sckey=$_scvalue" fi From 3db446633c504a45300ac067519e4aee870753ee Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 25 Oct 2016 21:09:01 +0800 Subject: [PATCH 0368/1348] add deploy api --- deploy/myapi.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 deploy/myapi.sh diff --git a/deploy/myapi.sh b/deploy/myapi.sh new file mode 100644 index 00000000..52e313e7 --- /dev/null +++ b/deploy/myapi.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env sh + +#Here is a sample custom api script. +#This file name is "myapi.sh" +#So, here must be a method myapi_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + + + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +myapi_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + + _err "Not implemented yet" + return 1 + +} + + From 800e3f45995bb63e864f5279897c72b446299916 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 25 Oct 2016 23:02:49 +0800 Subject: [PATCH 0369/1348] support dns_xxx_rm function fix https://github.com/Neilpang/acme.sh/issues/79 --- acme.sh | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 5c2e3922..ce125793 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.1 +VER=2.6.2 PROJECT_NAME="acme.sh" @@ -1771,6 +1771,7 @@ _clearup() { _stopserver $serverproc serverproc="" _restoreApache + _clearupdns if [ -z "$DEBUG" ] ; then rm -f "$TLS_CONF" rm -f "$TLS_CERT" @@ -1779,6 +1780,62 @@ _clearup() { fi } +_clearupdns() { + _debug "_clearupdns" + if [ "$dnsadded" != 1 ] || [ -z "$vlist" ] ; then + _info "Dns not added, skip." + return + fi + + ventries=$(echo "$vlist" | tr ',' ' ' ) + for ventry in $ventries + do + d=$(echo $ventry | cut -d $sep -f 1) + keyauthorization=$(echo $ventry | cut -d $sep -f 2) + vtype=$(echo $ventry | cut -d $sep -f 4) + _currentRoot=$(echo $ventry | cut -d $sep -f 5) + + if [ "$keyauthorization" = "$STATE_VERIFIED" ] ; then + _info "$d is already verified, skip $vtype." + continue + fi + + if [ "$vtype" != "$VTYPE_DNS" ] ; then + _info "Skip $d for $vtype" + continue + fi + + d_api="$(_findHook $d dnsapi $_currentRoot)" + _debug d_api "$d_api" + + if [ -z "$d_api" ] ; then + _info "Not Found domain api file: $d_api" + continue + fi + + ( + if ! . $d_api ; then + _err "Load file $d_api error. Please check your api file and try again." + return 1 + fi + + rmcommand="${_currentRoot}_rm" + if ! _exists $rmcommand ; then + _err "It seems that your api file doesn't define $rmcommand" + return 1 + fi + + txtdomain="_acme-challenge.$d" + + if ! $rmcommand $txtdomain ; then + _err "Error removing txt for domain:$txtdomain" + return 1 + fi + ) + + done +} + # webroot removelevel tokenfile _clearupwebbroot() { __webroot="$1" @@ -2037,7 +2094,7 @@ _regAccount() { if [ "$code" = '202' ] ; then _info "Update success." else - _err "Update error." + _err "Update account error." return 1 fi fi From 5d6fd8099fb85084086bfb6ae9ae4ac149432df7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 25 Oct 2016 23:08:02 +0800 Subject: [PATCH 0370/1348] add dns_xxx_rm function https://github.com/Neilpang/acme.sh/issues/79 --- dnsapi/dns_cf.sh | 4 ++++ dnsapi/dns_cx.sh | 9 +++++++++ dnsapi/dns_dp.sh | 9 +++++++++ dnsapi/dns_gd.sh | 7 +++++++ dnsapi/dns_lexicon.sh | 9 +++++++++ dnsapi/dns_myapi.sh | 5 +++++ dnsapi/dns_ovh.sh | 7 +++++++ dnsapi/dns_pdns.sh | 8 ++++++++ 8 files changed, 58 insertions(+) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 19d95c1a..b2dc7eb8 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -78,7 +78,11 @@ dns_cf_add(){ } +#fulldomain +dns_cf_rm() { + fulldomain=$1 +} #################### Private functions bellow ################################## diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 1a2e04e7..ae162d62 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -56,6 +56,15 @@ dns_cx_add() { return 1 } + + +#fulldomain +dns_cx_rm() { + fulldomain=$1 + +} + + #usage: root sub #return if the sub record already exists. #echos the existing records count. diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 49e8c77f..898806bd 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -51,6 +51,15 @@ dns_dp_add() { fi } + +#fulldomain +dns_dp_rm() { + fulldomain=$1 + +} + + + #usage: root sub #return if the sub record already exists. #echos the existing records count. diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index c25de32d..0f399b41 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -55,6 +55,13 @@ dns_gd_add(){ +#fulldomain +dns_gd_rm() { + fulldomain=$1 + +} + + #################### Private functions bellow ################################## diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 5e78a2d9..34f7637c 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -66,4 +66,13 @@ dns_lexicon_add() { } +#fulldomain +dns_lexicon_rm() { + fulldomain=$1 + +} + + + + diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index a29b9ff1..73b1ea85 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -20,6 +20,11 @@ dns_myapi_add() { +#fulldomain +dns_myapi_rm() { + fulldomain=$1 + +} #################### Private functions bellow ################################## diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 443aec6f..b31d02fc 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -183,6 +183,13 @@ dns_ovh_add(){ } +#fulldomain +dns_ovh_rm() { + fulldomain=$1 + +} + + #################### Private functions bellow ################################## _ovh_authentication() { diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 30c6d658..aa7a2c45 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -61,6 +61,14 @@ dns_pdns_add() { return 0 } + +#fulldomain +dns_pdns_rm() { + fulldomain=$1 + +} + + set_record() { _info "Adding record" root=$1 From 0fb206fe15107ca80a9199a0efec4e4a006ebb44 Mon Sep 17 00:00:00 2001 From: Philippe Kueck Date: Wed, 26 Oct 2016 11:52:26 +0200 Subject: [PATCH 0371/1348] add nsupdate script for dns-01 --- dnsapi/dns_nsupdate.sh | 94 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100755 dnsapi/dns_nsupdate.sh diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh new file mode 100755 index 00000000..fd16c563 --- /dev/null +++ b/dnsapi/dns_nsupdate.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash + + +######## Public functions ##################### + +#Usage: dns_nsupdate_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nsupdate_add() { + fulldomain=$1 + txtvalue=$2 + _checkKeyFile || return 1 + NSUPDATE_SERVER=${NSUPDATE_SERVER:-localhost} + # save the dns server and key to the account conf file. + _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" + _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" + tmp=$(mktemp --tmpdir acme_nsupdate.XXXXXX) + cat > ${tmp} < ${tmp} <&2 + return 1 +} + +_debug() { + if [ -z "$DEBUG" ] ; then + return + fi + _err "$@" + return 0 +} + +_debug2() { + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + _debug "$@" + fi + return +} From 2d279c4c5cb49405d01a996a0ea11c0e8711662f Mon Sep 17 00:00:00 2001 From: Philippe Kueck Date: Wed, 26 Oct 2016 11:57:45 +0200 Subject: [PATCH 0372/1348] add nsupdate to sample config --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index ce125793..cbd7f0dd 100755 --- a/acme.sh +++ b/acme.sh @@ -3363,6 +3363,11 @@ _initconf() { # #GD_Secret=\"sADDsdasdfsdfdssdgdsf\" +####################### +#nsupdate: +#NSUPDATE_KEY=\"/path/to/update.key\" +#NSUPDATE_SERVER=\"192.168.0.1\" + ####################### #PowerDNS: #PDNS_Url=\"http://ns.example.com:8081\" From 54d61bdc4ac46437c16f81fe0593c92610fce0e3 Mon Sep 17 00:00:00 2001 From: Philippe Kueck Date: Wed, 26 Oct 2016 16:14:47 +0200 Subject: [PATCH 0373/1348] - get rid of bash-only syntax like ${foo:-bar} - use sh instead of bash - remove redundant functions _info, _err, _debug and _debug2 - get rid of mktemp, pipe commands directly to nsupdate --- dnsapi/dns_nsupdate.sh | 46 +++++++----------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index fd16c563..56023322 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ######## Public functions ##################### @@ -8,18 +8,16 @@ dns_nsupdate_add() { fulldomain=$1 txtvalue=$2 _checkKeyFile || return 1 - NSUPDATE_SERVER=${NSUPDATE_SERVER:-localhost} + [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" # save the dns server and key to the account conf file. _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" - tmp=$(mktemp --tmpdir acme_nsupdate.XXXXXX) - cat > ${tmp} < ${tmp} <&2 - return 1 -} - -_debug() { - if [ -z "$DEBUG" ] ; then - return - fi - _err "$@" - return 0 -} - -_debug2() { - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - _debug "$@" - fi - return -} From 998783eb9d9b4124c2cf884c2d2735ef9feba76c Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 27 Oct 2016 00:06:03 +0800 Subject: [PATCH 0374/1348] Support ECC account key. fix https://github.com/Neilpang/acme.sh/issues/76 https://tools.ietf.org/html/rfc3278#section-8.2 http://bitcoin.stackexchange.com/questions/2376/ecdsa-r-s-encoding-as-a-signature http://davidederosa.com/basic-blockchain-programming/elliptic-curve-digital-signatures/ --- acme.sh | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index ce125793..23abbef7 100755 --- a/acme.sh +++ b/acme.sh @@ -419,13 +419,29 @@ _sign() { return 1 fi + _sign_openssl="openssl dgst -sign $keyfile " if [ "$alg" = "sha256" ] ; then - openssl dgst -sha256 -sign "$keyfile" | _base64 + _sign_openssl="$_sign_openssl -$alg" else _err "$alg is not supported yet" return 1 fi + if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then + $_sign_openssl | _base64 + elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then + _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)" + _debug3 "_signedECText" "$_signedECText" + _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" + _debug3 "_ec_r" "$_ec_r" + _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" + _debug3 "_ec_s" "$_ec_s" + printf "%s" "$_ec_r$_ec_s" | _h2b | _base64 + else + _err "Unknown key file format." + return 1 + fi + } #keylength @@ -695,9 +711,6 @@ createAccountKey() { fi length=$1 - if _isEccKey "$length" ; then - length=2048 - fi if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ] ; then _debug "Use default length 2048" @@ -852,7 +865,7 @@ _calcjwk() { _debug3 pubi "$pubi" pubj="$(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" pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" @@ -862,7 +875,7 @@ _calcjwk() { xlen=$(_math $xlen / 4) _debug3 xlen "$xlen" - xend=$(_math "$xend" + 1) + xend=$(_math "$xlen" + 1) x="$(printf $pubtext | cut -d : -f 2-$xend)" _debug3 x "$x" From 3afa4b210db4ec9a42edf3e332a8a768c8791c20 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 27 Oct 2016 20:07:20 +0800 Subject: [PATCH 0375/1348] add retry for temp authz request error --- acme.sh | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 23abbef7..e9e61525 100755 --- a/acme.sh +++ b/acme.sh @@ -2282,11 +2282,27 @@ issue() { _info "Getting new-authz for domain" $d - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$d")\"}}" ; then - _err "Can not get domain token." - _clearup - _on_issue_err - return 1 + _Max_new_authz_retry_times=5 + _authz_i=0 + while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ] ; do + _info "Try new-authz for the $_authz_i time." + if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$d")\"}}" ; then + _err "Can not get domain token." + _clearup + _on_issue_err + return 1 + fi + if ! _contains "$response" "An error occurred while processing your request" ; then + _info "The new-authz request is ok." + break + fi + _authz_i="$(_math "$_authz_i" + 1)" + _info "Sleep $_authz_i to retry." + _sleep "$_authz_i" + done; + + if [ "$_authz_i" = "$_Max_new_authz_retry_times" ] ; then + _debug "new-authz retry reach the max $_Max_new_authz_retry_times times." fi if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then From f940b2a58ee109a26a0367312155c20ccfb502b5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 27 Oct 2016 22:10:58 +0800 Subject: [PATCH 0376/1348] add retry to deactivate command --- acme.sh | 67 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/acme.sh b/acme.sh index e9e61525..675b1d56 100755 --- a/acme.sh +++ b/acme.sh @@ -2140,6 +2140,39 @@ _findHook() { printf "%s" "$d_api" } +#domain +__get_domain_new_authz() { + _gdnd="$1" + _info "Getting new-authz for domain" "$_gdnd" + + _Max_new_authz_retry_times=5 + _authz_i=0 + while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ] ; do + _info "Try new-authz for the $_authz_i time." + if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}" ; then + _err "Can not get domain new authz." + return 1 + fi + if ! _contains "$response" "An error occurred while processing your request" ; then + _info "The new-authz request is ok." + break + fi + _authz_i="$(_math "$_authz_i" + 1)" + _info "Sleep $_authz_i to retry." + _sleep "$_authz_i" + done; + + if [ "$_authz_i" = "$_Max_new_authz_retry_times" ] ; then + _debug "new-authz retry reach the max $_Max_new_authz_retry_times times." + fi + + if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then + _err "new-authz error: $response" + return 1 + fi + +} + #webroot, domain domainlist keylength issue() { if [ -z "$2" ] ; then @@ -2280,33 +2313,7 @@ issue() { vtype="$VTYPE_TLS" fi - _info "Getting new-authz for domain" $d - - _Max_new_authz_retry_times=5 - _authz_i=0 - while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ] ; do - _info "Try new-authz for the $_authz_i time." - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$d")\"}}" ; then - _err "Can not get domain token." - _clearup - _on_issue_err - return 1 - fi - if ! _contains "$response" "An error occurred while processing your request" ; then - _info "The new-authz request is ok." - break - fi - _authz_i="$(_math "$_authz_i" + 1)" - _info "Sleep $_authz_i to retry." - _sleep "$_authz_i" - done; - - if [ "$_authz_i" = "$_Max_new_authz_retry_times" ] ; then - _debug "new-authz retry reach the max $_Max_new_authz_retry_times times." - fi - - if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then - _err "new-authz error: $response" + if ! __get_domain_new_authz "$d" ; then _clearup _on_issue_err return 1 @@ -3227,8 +3234,10 @@ _deactivate() { do _info "Deactivate: $_d_domain" _d_i="$(_math $_d_i + 1)" - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_d_domain")\"}}" ; then - _err "Can not get domain token." + + + if ! __get_domain_new_authz "$_d_domain" ; then + _err "Can not get domain new authz token." return 1 fi From 9e45ac939bad20916091b7eec7060808643649e6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 27 Oct 2016 22:47:19 +0800 Subject: [PATCH 0377/1348] minor, add message --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 675b1d56..a09b1153 100755 --- a/acme.sh +++ b/acme.sh @@ -2158,7 +2158,7 @@ __get_domain_new_authz() { break fi _authz_i="$(_math "$_authz_i" + 1)" - _info "Sleep $_authz_i to retry." + _info "The server is busy, Sleep $_authz_i to retry." _sleep "$_authz_i" done; From 5982f4bcf03807afff020eb4581e1ba9a73daec1 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 28 Oct 2016 18:07:04 +0800 Subject: [PATCH 0378/1348] rename JWK_HEADER --- acme.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index a09b1153..bd4da527 100755 --- a/acme.sh +++ b/acme.sh @@ -851,9 +851,9 @@ _calcjwk() { jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' _debug3 jwk "$jwk" - HEADER='{"alg": "RS256", "jwk": '$jwk'}' - HEADERPLACE_PART1='{"nonce": "' - HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' + JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART1='{"nonce": "' + JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "EC key" EC_SIGN="1" @@ -892,15 +892,15 @@ _calcjwk() { jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}' _debug3 jwk "$jwk" - HEADER='{"alg": "ES256", "jwk": '$jwk'}' - HEADERPLACE_PART1='{"nonce": "' - HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' + JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART1='{"nonce": "' + JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' else _err "Only RSA or EC key is supported." return 1 fi - _debug3 HEADER "$HEADER" + _debug3 JWK_HEADER "$JWK_HEADER" } _time() { @@ -1129,7 +1129,7 @@ _send_signed_request() { _debug3 nonce "$nonce" - protected="$HEADERPLACE_PART1$nonce$HEADERPLACE_PART2" + protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" protected64="$(printf "$protected" | _base64 | _urlencode)" @@ -1138,7 +1138,7 @@ _send_signed_request() { sig=$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode) _debug3 sig "$sig" - body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" _debug3 body "$body" From 1befee5aca2d6adb388ded34d169cdbb4a14757d Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Oct 2016 20:56:18 +0800 Subject: [PATCH 0379/1348] fix performance --- acme.sh | 87 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/acme.sh b/acme.sh index bd4da527..389377a1 100755 --- a/acme.sh +++ b/acme.sh @@ -833,6 +833,13 @@ _calcjwk() { _usage "Usage: _calcjwk keyfile" return 1 fi + + if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ] ; then + _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" + return 0 + fi + + EC_SIGN="" if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "RSA key" @@ -901,6 +908,7 @@ _calcjwk() { fi _debug3 JWK_HEADER "$JWK_HEADER" + __CACHED_JWK_KEY_FILE="$keyfile" } _time() { @@ -929,35 +937,44 @@ _inithttp() { HTTP_HEADER="$(_mktemp)" _debug2 HTTP_HEADER "$HTTP_HEADER" fi - - if [ -z "$CURL" ] ; then - CURL="curl -L --silent --dump-header $HTTP_HEADER " + + if [ "$__HTTP_INITIALIZED" ] ; then + if [ "$_ACME_CURL$_ACME_WGET" ] ; then + _debug2 "Http already initialized." + return 0 + fi + fi + + if [ -z "$_ACME_CURL" ] && _exists "curl" ; then + _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER " if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then _CURL_DUMP="$(_mktemp)" - CURL="$CURL --trace-ascii $_CURL_DUMP " + _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " fi if [ "$CA_BUNDLE" ] ; then - CURL="$CURL --cacert $CA_BUNDLE " + _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " fi if [ "$HTTPS_INSECURE" ] ; then - CURL="$CURL --insecure " + _ACME_CURL="$_ACME_CURL --insecure " fi fi - if [ -z "$WGET" ] ; then - WGET="wget -q" + if [ -z "$_ACME_WGET" ] && _exists "wget"; then + _ACME_WGET="wget -q" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - WGET="$WGET -d " + _ACME_WGET="$_ACME_WGET -d " fi if [ "$CA_BUNDLE" ] ; then - WGET="$WGET --ca-certificate $CA_BUNDLE " + _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " fi if [ "$HTTPS_INSECURE" ] ; then - WGET="$WGET --no-check-certificate " + _ACME_WGET="$_ACME_WGET --no-check-certificate " fi fi + + __HTTP_INITIALIZED=1 } @@ -978,8 +995,8 @@ _post() { _inithttp - if _exists "curl" ; then - _CURL="$CURL" + if [ "$_ACME_CURL" ] ; then + _CURL="$_ACME_CURL" _debug "_CURL" "$_CURL" if [ "$needbase64" ] ; then response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" @@ -994,19 +1011,19 @@ _post() { _err "$(cat "$_CURL_DUMP")" fi fi - elif _exists "wget" ; then - _debug "WGET" "$WGET" + elif [ "$_ACME_WGET" ] ; then + _debug "_ACME_WGET" "$_ACME_WGET" if [ "$needbase64" ] ; then if [ "$httpmethod" = "POST" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" fi else if [ "$httpmethod" = "POST" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" fi fi _ret="$?" @@ -1039,8 +1056,8 @@ _get() { _inithttp - if _exists "curl" ; then - _CURL="$CURL" + if [ "$_ACME_CURL" ] ; then + _CURL="$_ACME_CURL" if [ "$t" ] ; then _CURL="$_CURL --connect-timeout $t" fi @@ -1058,8 +1075,8 @@ _get() { _err "$(cat "$_CURL_DUMP")" fi fi - elif _exists "wget" ; then - _WGET="$WGET" + elif [ "$_ACME_WGET" ] ; then + _WGET="$_ACME_WGET" if [ "$t" ] ; then _WGET="$_WGET --timeout=$t" fi @@ -3194,19 +3211,23 @@ revoke() { data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" uri="$API/acme/revoke-cert" - _info "Try domain key first." - if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then - if [ -z "$response" ] ; then - _info "Revoke success." - rm -f $CERT_PATH - return 0 - else - _err "Revoke error by domain key." - _err "$response" + if [ -f "$CERT_KEY_PATH" ] ; then + _info "Try domain key first." + if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then + if [ -z "$response" ] ; then + _info "Revoke success." + rm -f $CERT_PATH + return 0 + else + _err "Revoke error by domain key." + _err "$response" + fi fi + else + _info "Domain key file doesn't exists." fi - _info "Then try account key." + _info "Try account key." if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH" ; then if [ -z "$response" ] ; then From 00bcbd367f6e14929b0b1a8c8d822ffe92b3e22c Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Oct 2016 21:30:40 +0800 Subject: [PATCH 0380/1348] fix performance, use cached nonce --- acme.sh | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 389377a1..a6dc30c4 100755 --- a/acme.sh +++ b/acme.sh @@ -1132,18 +1132,23 @@ _send_signed_request() { payload64=$(printf "%s" "$payload" | _base64 | _urlencode) _debug3 payload64 $payload64 - nonceurl="$API/directory" - _headers="$(_get $nonceurl "onlyheader")" - - if [ "$?" != "0" ] ; then - _err "Can not connect to $nonceurl to get nonce." - return 1 + if [ -z "$_CACHED_NONCE" ] ; then + _debug2 "Get nonce." + nonceurl="$API/directory" + _headers="$(_get $nonceurl "onlyheader")" + + if [ "$?" != "0" ] ; then + _err "Can not connect to $nonceurl to get nonce." + return 1 + fi + + _debug3 _headers "$_headers" + + _CACHED_NONCE="$( echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + else + _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" fi - - _debug3 _headers "$_headers" - - nonce="$( echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - + nonce="$_CACHED_NONCE" _debug3 nonce "$nonce" protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" @@ -1160,6 +1165,7 @@ _send_signed_request() { response="$(_post "$body" $url "$needbase64")" + _CACHED_NONCE="" if [ "$?" != "0" ] ; then _err "Can not post to $url" return 1 @@ -1168,12 +1174,14 @@ _send_signed_request() { response="$( echo "$response" | _normalizeJson )" - responseHeaders="$(cat $HTTP_HEADER)" + responseHeaders="$(cat "$HTTP_HEADER")" _debug2 responseHeaders "$responseHeaders" _debug2 response "$response" code="$(grep "^HTTP" $HTTP_HEADER | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n" )" _debug code $code + + _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" } From 8a29fbc850b49c76ad6da65a9f81344e609ef1c4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Oct 2016 22:45:19 +0800 Subject: [PATCH 0381/1348] do not register account if already registered --- acme.sh | 111 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/acme.sh b/acme.sh index a6dc30c4..9b37b2e8 100755 --- a/acme.sh +++ b/acme.sh @@ -1223,60 +1223,85 @@ _setopt() { _debug2 "$(grep -n "^$__opt$__sep" $__conf)" } -#_savedomainconf key value -#save to domain.conf -_savedomainconf() { - _sdkey="$1" - _sdvalue="$2" - if [ "$DOMAIN_CONF" ] ; then - _setopt "$DOMAIN_CONF" "$_sdkey" "=" "\"$_sdvalue\"" + +#_save_conf file key value +#save to conf +_save_conf() { + _s_c_f="$1" + _sdkey="$2" + _sdvalue="$3" + if [ "$_s_c_f" ] ; then + _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'" else - _err "DOMAIN_CONF is empty, can not save $_sdkey=$_sdvalue" + _err "config file is empty, can not save $_sdkey=$_sdvalue" fi } -#_cleardomainconf key -_cleardomainconf() { - _sdkey="$1" - if [ "$DOMAIN_CONF" ] ; then - _sed_i "s/^$_sdkey.*$//" "$DOMAIN_CONF" +#_clear_conf file key +_clear_conf() { + _c_c_f="$1" + _sdkey="$2" + if [ "$_c_c_f" ] ; then + _sed_i "s/^$_sdkey.*$//" "$_c_c_f" else - _err "DOMAIN_CONF is empty, can not save $_sdkey=$value" + _err "config file is empty, can not clear" fi } -#_readdomainconf key -_readdomainconf() { - _sdkey="$1" - if [ "$DOMAIN_CONF" ] ; then +#_read_conf file key +_read_conf() { + _r_c_f="$1" + _sdkey="$2" + if [ -f "$_r_c_f" ] ; then ( - eval $(grep "^$_sdkey *=" "$DOMAIN_CONF") + eval $(grep "^$_sdkey *=" "$_r_c_f") eval "printf \"%s\" \"\$$_sdkey\"" ) else - _err "DOMAIN_CONF is empty, can not read $_sdkey" + _err "config file is empty, can not read $_sdkey" fi } + +#_savedomainconf key value +#save to domain.conf +_savedomainconf() { + _save_conf "$DOMAIN_CONF" "$1" "$2" +} + +#_cleardomainconf key +_cleardomainconf() { + _clear_conf "$DOMAIN_CONF" "$1" +} + +#_readdomainconf key +_readdomainconf() { + _read_conf "$DOMAIN_CONF" "$1" +} + #_saveaccountconf key value _saveaccountconf() { - _sckey="$1" - _scvalue="$2" - if [ "$ACCOUNT_CONF_PATH" ] ; then - _setopt "$ACCOUNT_CONF_PATH" "$_sckey" "=" "'$_scvalue'" - else - _err "ACCOUNT_CONF_PATH is empty, can not save $_sckey=$_scvalue" - fi + _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2" } #_clearaccountconf key _clearaccountconf() { - _scvalue="$1" - if [ "$ACCOUNT_CONF_PATH" ] ; then - _sed_i "s/^$_scvalue.*$//" "$ACCOUNT_CONF_PATH" - else - _err "ACCOUNT_CONF_PATH is empty, can not clear $_scvalue" - fi + _clear_conf "$ACCOUNT_CONF_PATH" "$1" +} + +#_savecaconf key value +_savecaconf() { + _save_conf "$CA_CONF" "$1" "$2" +} + +#_readcaconf key +_readcaconf() { + _read_conf "$CA_CONF" "$1" +} + +#_clearaccountconf key +_clearcaconf() { + _clear_conf "$CA_CONF" "$1" } # content localaddress @@ -2047,6 +2072,10 @@ registeraccount() { _regAccount } +__calcAccountKeyHash() { + cat "$ACCOUNT_KEY_PATH" | _digest sha256 +} + _regAccount() { _initpath @@ -2131,6 +2160,10 @@ _regAccount() { fi if [ "$code" = '202' ] ; then _info "Update success." + + CA_KEY_HASH="$(__calcAccountKeyHash)" + _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" + _savecaconf CA_KEY_HASH "$CA_KEY_HASH" else _err "Update account error." return 1 @@ -2280,11 +2313,15 @@ issue() { return 1 fi - if ! _regAccount ; then - _on_issue_err - return 1 - fi + _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")" + _debug2 _saved_account_key_hash "$_saved_account_key_hash" + if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ] ; then + if ! _regAccount ; then + _on_issue_err + return 1 + fi + fi if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ] ; then _info "Signing from existing CSR." From cae203be71d7ffe2cd2d37ffc328b0b941e46d50 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 28 Oct 2016 23:30:32 +0800 Subject: [PATCH 0382/1348] fix thumbprint --- acme.sh | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 9b37b2e8..858a57da 100755 --- a/acme.sh +++ b/acme.sh @@ -2109,8 +2109,6 @@ _regAccount() { while true ; do _debug AGREEMENT "$AGREEMENT" - accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}' @@ -2348,8 +2346,8 @@ issue() { _savedomainconf "Le_Keylength" "$Le_Keylength" vlist="$Le_Vlist" - # verify each domain - _info "Verify each domain" + + _info "Getting domain auth token for each domain" sep='#' if [ -z "$vlist" ] ; then alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) @@ -2380,7 +2378,12 @@ issue() { _on_issue_err return 1 fi - + + if [ -z "$thumbprint" ] ; then + accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) + thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) + fi + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ] ; then @@ -2394,7 +2397,7 @@ issue() { uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" _debug uri $uri - + keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" From d7c6679d7002f0e4f1d2f55707cddd662f3af958 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 28 Oct 2016 23:58:01 +0800 Subject: [PATCH 0383/1348] fix issue performance. Reduce the time cost from about 20 seconds down to 8 seconds (#348) * rename JWK_HEADER * fix performance * fix performance, use cached nonce * do not register account if already registered * fix thumbprint --- acme.sh | 263 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 166 insertions(+), 97 deletions(-) diff --git a/acme.sh b/acme.sh index a09b1153..858a57da 100755 --- a/acme.sh +++ b/acme.sh @@ -833,6 +833,13 @@ _calcjwk() { _usage "Usage: _calcjwk keyfile" return 1 fi + + if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ] ; then + _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" + return 0 + fi + + EC_SIGN="" if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "RSA key" @@ -851,9 +858,9 @@ _calcjwk() { jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' _debug3 jwk "$jwk" - HEADER='{"alg": "RS256", "jwk": '$jwk'}' - HEADERPLACE_PART1='{"nonce": "' - HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' + JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART1='{"nonce": "' + JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "EC key" EC_SIGN="1" @@ -892,15 +899,16 @@ _calcjwk() { jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}' _debug3 jwk "$jwk" - HEADER='{"alg": "ES256", "jwk": '$jwk'}' - HEADERPLACE_PART1='{"nonce": "' - HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' + JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART1='{"nonce": "' + JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' else _err "Only RSA or EC key is supported." return 1 fi - _debug3 HEADER "$HEADER" + _debug3 JWK_HEADER "$JWK_HEADER" + __CACHED_JWK_KEY_FILE="$keyfile" } _time() { @@ -929,35 +937,44 @@ _inithttp() { HTTP_HEADER="$(_mktemp)" _debug2 HTTP_HEADER "$HTTP_HEADER" fi - - if [ -z "$CURL" ] ; then - CURL="curl -L --silent --dump-header $HTTP_HEADER " + + if [ "$__HTTP_INITIALIZED" ] ; then + if [ "$_ACME_CURL$_ACME_WGET" ] ; then + _debug2 "Http already initialized." + return 0 + fi + fi + + if [ -z "$_ACME_CURL" ] && _exists "curl" ; then + _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER " if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then _CURL_DUMP="$(_mktemp)" - CURL="$CURL --trace-ascii $_CURL_DUMP " + _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " fi if [ "$CA_BUNDLE" ] ; then - CURL="$CURL --cacert $CA_BUNDLE " + _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " fi if [ "$HTTPS_INSECURE" ] ; then - CURL="$CURL --insecure " + _ACME_CURL="$_ACME_CURL --insecure " fi fi - if [ -z "$WGET" ] ; then - WGET="wget -q" + if [ -z "$_ACME_WGET" ] && _exists "wget"; then + _ACME_WGET="wget -q" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - WGET="$WGET -d " + _ACME_WGET="$_ACME_WGET -d " fi if [ "$CA_BUNDLE" ] ; then - WGET="$WGET --ca-certificate $CA_BUNDLE " + _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " fi if [ "$HTTPS_INSECURE" ] ; then - WGET="$WGET --no-check-certificate " + _ACME_WGET="$_ACME_WGET --no-check-certificate " fi fi + + __HTTP_INITIALIZED=1 } @@ -978,8 +995,8 @@ _post() { _inithttp - if _exists "curl" ; then - _CURL="$CURL" + if [ "$_ACME_CURL" ] ; then + _CURL="$_ACME_CURL" _debug "_CURL" "$_CURL" if [ "$needbase64" ] ; then response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" @@ -994,19 +1011,19 @@ _post() { _err "$(cat "$_CURL_DUMP")" fi fi - elif _exists "wget" ; then - _debug "WGET" "$WGET" + elif [ "$_ACME_WGET" ] ; then + _debug "_ACME_WGET" "$_ACME_WGET" if [ "$needbase64" ] ; then if [ "$httpmethod" = "POST" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" fi else if [ "$httpmethod" = "POST" ] ; then - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" else - response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" fi fi _ret="$?" @@ -1039,8 +1056,8 @@ _get() { _inithttp - if _exists "curl" ; then - _CURL="$CURL" + if [ "$_ACME_CURL" ] ; then + _CURL="$_ACME_CURL" if [ "$t" ] ; then _CURL="$_CURL --connect-timeout $t" fi @@ -1058,8 +1075,8 @@ _get() { _err "$(cat "$_CURL_DUMP")" fi fi - elif _exists "wget" ; then - _WGET="$WGET" + elif [ "$_ACME_WGET" ] ; then + _WGET="$_ACME_WGET" if [ "$t" ] ; then _WGET="$_WGET --timeout=$t" fi @@ -1115,21 +1132,26 @@ _send_signed_request() { payload64=$(printf "%s" "$payload" | _base64 | _urlencode) _debug3 payload64 $payload64 - nonceurl="$API/directory" - _headers="$(_get $nonceurl "onlyheader")" - - if [ "$?" != "0" ] ; then - _err "Can not connect to $nonceurl to get nonce." - return 1 + if [ -z "$_CACHED_NONCE" ] ; then + _debug2 "Get nonce." + nonceurl="$API/directory" + _headers="$(_get $nonceurl "onlyheader")" + + if [ "$?" != "0" ] ; then + _err "Can not connect to $nonceurl to get nonce." + return 1 + fi + + _debug3 _headers "$_headers" + + _CACHED_NONCE="$( echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + else + _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" fi - - _debug3 _headers "$_headers" - - nonce="$( echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - + nonce="$_CACHED_NONCE" _debug3 nonce "$nonce" - protected="$HEADERPLACE_PART1$nonce$HEADERPLACE_PART2" + protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" protected64="$(printf "$protected" | _base64 | _urlencode)" @@ -1138,11 +1160,12 @@ _send_signed_request() { sig=$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode) _debug3 sig "$sig" - body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" _debug3 body "$body" response="$(_post "$body" $url "$needbase64")" + _CACHED_NONCE="" if [ "$?" != "0" ] ; then _err "Can not post to $url" return 1 @@ -1151,12 +1174,14 @@ _send_signed_request() { response="$( echo "$response" | _normalizeJson )" - responseHeaders="$(cat $HTTP_HEADER)" + responseHeaders="$(cat "$HTTP_HEADER")" _debug2 responseHeaders "$responseHeaders" _debug2 response "$response" code="$(grep "^HTTP" $HTTP_HEADER | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n" )" _debug code $code + + _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" } @@ -1198,60 +1223,85 @@ _setopt() { _debug2 "$(grep -n "^$__opt$__sep" $__conf)" } -#_savedomainconf key value -#save to domain.conf -_savedomainconf() { - _sdkey="$1" - _sdvalue="$2" - if [ "$DOMAIN_CONF" ] ; then - _setopt "$DOMAIN_CONF" "$_sdkey" "=" "\"$_sdvalue\"" + +#_save_conf file key value +#save to conf +_save_conf() { + _s_c_f="$1" + _sdkey="$2" + _sdvalue="$3" + if [ "$_s_c_f" ] ; then + _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'" else - _err "DOMAIN_CONF is empty, can not save $_sdkey=$_sdvalue" + _err "config file is empty, can not save $_sdkey=$_sdvalue" fi } -#_cleardomainconf key -_cleardomainconf() { - _sdkey="$1" - if [ "$DOMAIN_CONF" ] ; then - _sed_i "s/^$_sdkey.*$//" "$DOMAIN_CONF" +#_clear_conf file key +_clear_conf() { + _c_c_f="$1" + _sdkey="$2" + if [ "$_c_c_f" ] ; then + _sed_i "s/^$_sdkey.*$//" "$_c_c_f" else - _err "DOMAIN_CONF is empty, can not save $_sdkey=$value" + _err "config file is empty, can not clear" fi } -#_readdomainconf key -_readdomainconf() { - _sdkey="$1" - if [ "$DOMAIN_CONF" ] ; then +#_read_conf file key +_read_conf() { + _r_c_f="$1" + _sdkey="$2" + if [ -f "$_r_c_f" ] ; then ( - eval $(grep "^$_sdkey *=" "$DOMAIN_CONF") + eval $(grep "^$_sdkey *=" "$_r_c_f") eval "printf \"%s\" \"\$$_sdkey\"" ) else - _err "DOMAIN_CONF is empty, can not read $_sdkey" + _err "config file is empty, can not read $_sdkey" fi } + +#_savedomainconf key value +#save to domain.conf +_savedomainconf() { + _save_conf "$DOMAIN_CONF" "$1" "$2" +} + +#_cleardomainconf key +_cleardomainconf() { + _clear_conf "$DOMAIN_CONF" "$1" +} + +#_readdomainconf key +_readdomainconf() { + _read_conf "$DOMAIN_CONF" "$1" +} + #_saveaccountconf key value _saveaccountconf() { - _sckey="$1" - _scvalue="$2" - if [ "$ACCOUNT_CONF_PATH" ] ; then - _setopt "$ACCOUNT_CONF_PATH" "$_sckey" "=" "'$_scvalue'" - else - _err "ACCOUNT_CONF_PATH is empty, can not save $_sckey=$_scvalue" - fi + _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2" } #_clearaccountconf key _clearaccountconf() { - _scvalue="$1" - if [ "$ACCOUNT_CONF_PATH" ] ; then - _sed_i "s/^$_scvalue.*$//" "$ACCOUNT_CONF_PATH" - else - _err "ACCOUNT_CONF_PATH is empty, can not clear $_scvalue" - fi + _clear_conf "$ACCOUNT_CONF_PATH" "$1" +} + +#_savecaconf key value +_savecaconf() { + _save_conf "$CA_CONF" "$1" "$2" +} + +#_readcaconf key +_readcaconf() { + _read_conf "$CA_CONF" "$1" +} + +#_clearaccountconf key +_clearcaconf() { + _clear_conf "$CA_CONF" "$1" } # content localaddress @@ -2022,6 +2072,10 @@ registeraccount() { _regAccount } +__calcAccountKeyHash() { + cat "$ACCOUNT_KEY_PATH" | _digest sha256 +} + _regAccount() { _initpath @@ -2055,8 +2109,6 @@ _regAccount() { while true ; do _debug AGREEMENT "$AGREEMENT" - accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}' @@ -2106,6 +2158,10 @@ _regAccount() { fi if [ "$code" = '202' ] ; then _info "Update success." + + CA_KEY_HASH="$(__calcAccountKeyHash)" + _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" + _savecaconf CA_KEY_HASH "$CA_KEY_HASH" else _err "Update account error." return 1 @@ -2255,11 +2311,15 @@ issue() { return 1 fi - if ! _regAccount ; then - _on_issue_err - return 1 - fi + _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")" + _debug2 _saved_account_key_hash "$_saved_account_key_hash" + if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ] ; then + if ! _regAccount ; then + _on_issue_err + return 1 + fi + fi if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ] ; then _info "Signing from existing CSR." @@ -2286,8 +2346,8 @@ issue() { _savedomainconf "Le_Keylength" "$Le_Keylength" vlist="$Le_Vlist" - # verify each domain - _info "Verify each domain" + + _info "Getting domain auth token for each domain" sep='#' if [ -z "$vlist" ] ; then alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) @@ -2318,7 +2378,12 @@ issue() { _on_issue_err return 1 fi - + + if [ -z "$thumbprint" ] ; then + accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) + thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) + fi + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ] ; then @@ -2332,7 +2397,7 @@ issue() { uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" _debug uri $uri - + keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" @@ -3194,19 +3259,23 @@ revoke() { data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" uri="$API/acme/revoke-cert" - _info "Try domain key first." - if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then - if [ -z "$response" ] ; then - _info "Revoke success." - rm -f $CERT_PATH - return 0 - else - _err "Revoke error by domain key." - _err "$response" + if [ -f "$CERT_KEY_PATH" ] ; then + _info "Try domain key first." + if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then + if [ -z "$response" ] ; then + _info "Revoke success." + rm -f $CERT_PATH + return 0 + else + _err "Revoke error by domain key." + _err "$response" + fi fi + else + _info "Domain key file doesn't exists." fi - _info "Then try account key." + _info "Try account key." if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH" ; then if [ -z "$response" ] ; then From 5dbf664a6bd02e72f581bbf77412c477de49a336 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 29 Oct 2016 10:53:45 +0800 Subject: [PATCH 0384/1348] minor, reduce the sleep time. --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 858a57da..4b7bedff 100755 --- a/acme.sh +++ b/acme.sh @@ -1476,7 +1476,7 @@ _starttlsserver() { fi serverproc="$!" - sleep 2 + sleep 1 _debug serverproc $serverproc } @@ -2541,7 +2541,7 @@ issue() { return 1 fi serverproc="$!" - sleep 2 + sleep 1 _debug serverproc $serverproc else @@ -2641,8 +2641,8 @@ issue() { return 1 fi - _debug "sleep 5 secs to verify" - sleep 5 + _debug "sleep 2 secs to verify" + sleep 2 _debug "checking" response="$(_get $uri)" if [ "$?" != "0" ] ; then From f345cc66cf2f4eb34c55440e685480a1dc3cc4b9 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 29 Oct 2016 10:55:16 +0800 Subject: [PATCH 0385/1348] Dev (#349) * rename JWK_HEADER * fix performance * fix performance, use cached nonce * do not register account if already registered * fix thumbprint * minor, reduce the sleep time. --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 858a57da..4b7bedff 100755 --- a/acme.sh +++ b/acme.sh @@ -1476,7 +1476,7 @@ _starttlsserver() { fi serverproc="$!" - sleep 2 + sleep 1 _debug serverproc $serverproc } @@ -2541,7 +2541,7 @@ issue() { return 1 fi serverproc="$!" - sleep 2 + sleep 1 _debug serverproc $serverproc else @@ -2641,8 +2641,8 @@ issue() { return 1 fi - _debug "sleep 5 secs to verify" - sleep 5 + _debug "sleep 2 secs to verify" + sleep 2 _debug "checking" response="$(_get $uri)" if [ "$?" != "0" ] ; then From 18256c49231bd5be7ee71f42a0e9c0640da22b30 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 29 Oct 2016 11:08:18 +0800 Subject: [PATCH 0386/1348] fix issue cache jwk for ecc key only --- acme.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 4b7bedff..04105854 100755 --- a/acme.sh +++ b/acme.sh @@ -834,15 +834,18 @@ _calcjwk() { return 1 fi - if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ] ; then - _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" - return 0 - fi + EC_SIGN="" if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "RSA key" + + if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ] ; then + _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" + return 0 + fi + pub_exp=$(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 pub_exp=0$pub_exp @@ -861,6 +864,7 @@ _calcjwk() { JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' + __CACHED_JWK_KEY_FILE="$keyfile" elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "EC key" EC_SIGN="1" @@ -908,7 +912,7 @@ _calcjwk() { fi _debug3 JWK_HEADER "$JWK_HEADER" - __CACHED_JWK_KEY_FILE="$keyfile" + } _time() { From 8c76b8bc36003b1e5488d0cd71ca9758c34a8b29 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 29 Oct 2016 11:15:45 +0800 Subject: [PATCH 0387/1348] do not cache thumbprint for issues for ecc account key --- acme.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index 04105854..19c2c1f7 100755 --- a/acme.sh +++ b/acme.sh @@ -833,10 +833,7 @@ _calcjwk() { _usage "Usage: _calcjwk keyfile" return 1 fi - - - EC_SIGN="" if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "RSA key" @@ -2383,11 +2380,10 @@ issue() { return 1 fi - if [ -z "$thumbprint" ] ; then - accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) - fi - + + accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) + thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ] ; then From ae2db62f1cddfe96cff9c79ac74236edd69c8c2c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 29 Oct 2016 12:14:48 +0800 Subject: [PATCH 0388/1348] fix issues for ECC account key. --- acme.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index 19c2c1f7..d6fb1c47 100755 --- a/acme.sh +++ b/acme.sh @@ -833,16 +833,16 @@ _calcjwk() { _usage "Usage: _calcjwk keyfile" return 1 fi - + + if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ] ; then + _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" + return 0 + fi + + EC_SIGN="" if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "RSA key" - - if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ] ; then - _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" - return 0 - fi - pub_exp=$(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 pub_exp=0$pub_exp @@ -861,7 +861,6 @@ _calcjwk() { JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' - __CACHED_JWK_KEY_FILE="$keyfile" elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then _debug "EC key" EC_SIGN="1" @@ -897,7 +896,7 @@ _calcjwk() { y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)" _debug3 y64 "$y64" - jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}' + jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' _debug3 jwk "$jwk" JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}' @@ -909,7 +908,7 @@ _calcjwk() { fi _debug3 JWK_HEADER "$JWK_HEADER" - + __CACHED_JWK_KEY_FILE="$keyfile" } _time() { @@ -2380,10 +2379,11 @@ issue() { return 1 fi - - accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) - + if [ -z "$thumbprint" ] ; then + accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) + thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) + fi + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ] ; then From 72518d4827c3609b64311dc2d9716d48eac16a1a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 29 Oct 2016 17:43:38 +0800 Subject: [PATCH 0389/1348] fix performance --- acme.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index d6fb1c47..eaecba18 100755 --- a/acme.sh +++ b/acme.sh @@ -2292,8 +2292,12 @@ issue() { _savedomainconf "Le_PreHook" "$Le_PreHook" _savedomainconf "Le_PostHook" "$Le_PostHook" _savedomainconf "Le_RenewHook" "$Le_RenewHook" - _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" + if [ "$Le_LocalAddress" ] ; then + _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" + else + _cleardomainconf "Le_LocalAddress" + fi Le_API="$API" _savedomainconf "Le_API" "$Le_API" @@ -2719,9 +2723,14 @@ issue() { if [ "$Le_LinkCert" ] ; then echo "$BEGIN_CERT" > "$CERT_PATH" - if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then - _debug "Get cert failed. Let's try last response." - printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" + #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then + # _debug "Get cert failed. Let's try last response." + # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" + #fi + + if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" ; then + _debug "Try cert link." + _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" fi echo "$END_CERT" >> "$CERT_PATH" From 0d2c26735e98d71261fbeff836fb176c791920bd Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 29 Oct 2016 21:33:34 +0800 Subject: [PATCH 0390/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index eaecba18..0575e0b6 100755 --- a/acme.sh +++ b/acme.sh @@ -2073,7 +2073,7 @@ registeraccount() { } __calcAccountKeyHash() { - cat "$ACCOUNT_KEY_PATH" | _digest sha256 + [ -f "$ACCOUNT_KEY_PATH" ] && cat "$ACCOUNT_KEY_PATH" | _digest sha256 } _regAccount() { From fb3be8509de0c196bd83cad97c2a9c2370cba864 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 29 Oct 2016 22:59:53 +0800 Subject: [PATCH 0391/1348] Add gentoo linux --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e86392ec..684ec399 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |16|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) |18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris +|18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From 5961d443393ccc4c716b2ca270109436b4ccd130 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 30 Oct 2016 17:26:00 +0800 Subject: [PATCH 0392/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 684ec399..bd0cbd24 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |16|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) |18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris -|18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux +|19|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From 02d54a783a5844de89b5afc4d45ae9906d9b54c2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 31 Oct 2016 21:12:11 +0800 Subject: [PATCH 0393/1348] fix for idn on solaris --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 0575e0b6..d4e75804 100755 --- a/acme.sh +++ b/acme.sh @@ -504,7 +504,7 @@ _createkey() { _is_idn() { _is_idn_d="$1" _debug2 _is_idn_d "$_is_idn_d" - _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d "[0-9a-zA-Z.,-]") + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '[0-9]' | tr -d '[a-z]' | tr -d 'A-Z' | tr -d '.,-') _debug2 _idn_temp "$_idn_temp" [ "$_idn_temp" ] } From 2a1e06f8a9d070b8e7d5a14a6a1e058bd4dd4280 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 31 Oct 2016 21:22:04 +0800 Subject: [PATCH 0394/1348] add --quiet for idn --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d4e75804..bb773241 100755 --- a/acme.sh +++ b/acme.sh @@ -528,7 +528,7 @@ _idn() { else _i_first="" fi - idn "$f" | tr -d "\r\n" + idn --quiet "$f" | tr -d "\r\n" done else idn "$__idn_d" | tr -d "\r\n" From 93fc48a2dbbe6cc0d07737b8d8c4b756162536fe Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 1 Nov 2016 19:14:33 +0800 Subject: [PATCH 0395/1348] add more error check --- acme.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index bb773241..e1b1cf45 100755 --- a/acme.sh +++ b/acme.sh @@ -1846,7 +1846,7 @@ _clearup() { _clearupdns() { _debug "_clearupdns" if [ "$dnsadded" != 1 ] || [ -z "$vlist" ] ; then - _info "Dns not added, skip." + _debug "Dns not added, skip." return fi @@ -2567,7 +2567,15 @@ issue() { _debug "writing token:$token to $wellknown_path/$token" mkdir -p "$wellknown_path" - printf "%s" "$keyauthorization" > "$wellknown_path/$token" + + if ! printf "%s" "$keyauthorization" > "$wellknown_path/$token" ; then + _err "$d:Can not write token to file : $wellknown_path/$token" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err + return 1 + fi + if [ ! "$usingApache" ] ; then if webroot_owner=$(_stat $_currentRoot) ; then _debug "Changing owner/group of .well-known to $webroot_owner" From 7e512bad969b1dbc64ac6fae4bd9711b259cba6c Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 1 Nov 2016 19:31:20 +0800 Subject: [PATCH 0396/1348] fix apache mode --- acme.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index e1b1cf45..c2956ce7 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.2 +VER=2.6.3 PROJECT_NAME="acme.sh" @@ -1937,9 +1937,6 @@ _on_before_issue() { _err "Please install netcat(nc) tools first." return 1 fi - elif ! _hasfield "$Le_Webroot" "$W_TLS" ; then - #no need to check anymore - return 0 fi _debug Le_LocalAddress "$Le_LocalAddress" From 610e0f21d62843166955dea03610a33af80fd533 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 1 Nov 2016 20:29:58 +0800 Subject: [PATCH 0397/1348] fix apache error checks --- acme.sh | 54 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index c2956ce7..888de5ed 100755 --- a/acme.sh +++ b/acme.sh @@ -918,15 +918,18 @@ _time() { _mktemp() { if _exists mktemp ; then if mktemp 2>/dev/null ; then - return + return 0 elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null ; then #for Mac osx - return + return 0 fi fi if [ -d "/tmp" ] ; then echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" return 0 + elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR" ; then + echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp" + return 0 fi _err "Can not create temp file." } @@ -1540,6 +1543,10 @@ __initHome() { DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log" DEFAULT_CA_HOME="$LE_WORKING_DIR/ca" + + if [ -z "$LE_TEMP_DIR" ] ; then + LE_TEMP_DIR="$LE_WORKING_DIR/tmp" + fi } #[domain] [keylength] @@ -1693,6 +1700,21 @@ _initpath() { } +_exec() { + if [ -z "$_EXEC_TEMP_ERR" ] ; then + _EXEC_TEMP_ERR="$(_mktemp)" + fi + + if [ "$_EXEC_TEMP_ERR" ] ; then + "$@" 2>"$_EXEC_TEMP_ERR" + else + "$@" + fi +} + +_exec_err() { + [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" +} _apachePath() { _APACHECTL="apachectl" @@ -1705,8 +1727,20 @@ _apachePath() { return 1 fi fi + + if ! _exec $_APACHECTL -V ; then + _exec_err + return 1 + fi + httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" _debug httpdconfname "$httpdconfname" + + if [ -z "$httpdconfname" ] ; then + _err "Can not read apache config file." + return 1 + fi + if _startswith "$httpdconfname" '/' ; then httpdconf="$httpdconfname" httpdconfname="$(basename $httpdconfname)" @@ -1741,7 +1775,8 @@ _restoreApache() { cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" > "$httpdconf" _debug "Restored: $httpdconf." - if ! $_APACHECTL -t >/dev/null 2>&1 ; then + if ! _exec $_APACHECTL -t ; then + _exec_err _err "Sorry, restore apache config error, please contact me." return 1; fi @@ -1758,11 +1793,11 @@ _setApache() { #test the conf first _info "Checking if there is an error in the apache config file before starting." - _msg="$($_APACHECTL -t 2>&1 )" - if [ "$?" != "0" ] ; then - _err "Sorry, apache config file has error, please fix it first, then try again." + + if ! _exec $_APACHECTL -t >/dev/null ; then + _exec_err + _err "The apache config file has error, please fix it first, then try again." _err "Don't worry, there is nothing changed to your system." - _err "$_msg" return 1; else _info "OK" @@ -1821,8 +1856,9 @@ Allow from all chmod 755 "$ACME_DIR" fi - if ! $_APACHECTL graceful ; then - _err "Sorry, $_APACHECTL graceful error, please contact me." + if ! _exec $_APACHECTL graceful ; then + _exec_err + _err "$_APACHECTL graceful error, please contact me." _restoreApache return 1; fi From e7d4352292c082b60f1914297b66383ab4d58547 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 1 Nov 2016 20:38:00 +0800 Subject: [PATCH 0398/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 888de5ed..2a11ba2b 100755 --- a/acme.sh +++ b/acme.sh @@ -1728,7 +1728,7 @@ _apachePath() { fi fi - if ! _exec $_APACHECTL -V ; then + if ! _exec $_APACHECTL -V >/dev/null ; then _exec_err return 1 fi From c243829234b334846327dd88d16ffcd3492f64eb Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 2 Nov 2016 23:02:42 +0800 Subject: [PATCH 0399/1348] add issue template --- .github/ISSUE_TEMPLATE.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..4abbb7ab --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,25 @@ + + +Steps to reproduce +------------------ + + +Debug log +----------------- + +``` +acme.sh --issue ..... --debug 2 +``` + + From 1cbf416b10def006e9727e1e624c25d49121f629 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 2 Nov 2016 23:22:36 +0800 Subject: [PATCH 0400/1348] minor, add more log --- acme.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 2a11ba2b..28d80b1e 100755 --- a/acme.sh +++ b/acme.sh @@ -1145,14 +1145,15 @@ _send_signed_request() { return 1 fi - _debug3 _headers "$_headers" + _debug2 _headers "$_headers" _CACHED_NONCE="$( echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + _debug2 _CACHED_NONCE "$_CACHED_NONCE" else _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" fi nonce="$_CACHED_NONCE" - _debug3 nonce "$nonce" + _debug2 nonce "$nonce" protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" From 3c33cdfa3da68000a40b85304821705f0deea951 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 3 Nov 2016 19:19:51 +0800 Subject: [PATCH 0401/1348] Update README.md --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bd0cbd24..b762268e 100644 --- a/README.md +++ b/README.md @@ -138,15 +138,24 @@ More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert # 3. Install the issued cert to apache/nginx etc. -After you issue a cert, you probably want to install/copy the cert to your nginx/apache or other servers you may be using. +After you issue a cert, you probably want to install/copy the cert to your nginx/apache or other servers. +You **MUST** use this command to copy the certs to the target files, **Do NOT** use the certs files in **.acme.sh/** folder, they are for internal use only, the folder structure may change in future. +**nginx** example ```bash acme.sh --installcert -d example.com \ ---certpath /path/to/certfile/in/apache/nginx \ ---keypath /path/to/keyfile/in/apache/nginx \ ---capath /path/to/ca/certfile/apache/nginx \ ---fullchainpath path/to/fullchain/certfile/apache/nginx \ ---reloadcmd "service apache2|nginx reload" +--keypath /path/to/keyfile/in/nginx/key.pem \ +--fullchainpath path/to/fullchain/nginx/cert.pem \ +--reloadcmd "service nginx restart" +``` + +**apache** example +```bash +acme.sh --installcert -d example.com \ +--certpath /path/to/certfile/in/apache/cert.pem \ +--keypath /path/to/keyfile/in/apache/key.pem \ +--fullchainpath path/to/fullchain/certfile/apache/fullchain.pem \ +--reloadcmd "service apache2 restart" ``` Only the domain is required, all the other parameters are optional. From 9d548d81ac22f1613b4fe83b5e3b06a283fd2294 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Nov 2016 22:03:41 +0800 Subject: [PATCH 0402/1348] add more debug info --- acme.sh | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 28d80b1e..3f4fbebb 100755 --- a/acme.sh +++ b/acme.sh @@ -91,6 +91,30 @@ _printargs() { printf "\n" } +_dlg_versions() { + echo "Diagnosis versions: " + echo "openssl:" + if _exists openssl ; then + openssl version 2>&1 + else + echo "openssl doesn't exists." + fi + + echo "apache:" + if [ "$_APACHECTL" ] && _exists "$_APACHECTL" ; then + _APACHECTL -V 2>&1 + else + echo "apache doesn't exists." + fi + + echo "nc:" + if _exists "nc" ; then + nc -h 2>&1 + else + _debug "nc doesn't exists." + fi +} + _log() { [ -z "$LOG_FILE" ] && return @@ -2058,6 +2082,10 @@ _on_issue_err() { _err "See: $_DEBUG_WIKI" fi + if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ] ; then + _debug "$(_dlg_versions)" + fi + #run the post hook if [ "$Le_PostHook" ] ; then _info "Run post hook:'$Le_PostHook'" @@ -4358,7 +4386,9 @@ _process() { _processAccountConf fi - + + _debug2 LE_WORKING_DIR "$LE_WORKING_DIR" + if [ "$DEBUG" ] ; then version fi From 29b751095713fbd1f7a22242e652aa84ef2b380b Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Nov 2016 22:22:01 +0800 Subject: [PATCH 0403/1348] add sign error check. --- acme.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3f4fbebb..18453b6d 100755 --- a/acme.sh +++ b/acme.sh @@ -1185,7 +1185,13 @@ _send_signed_request() { protected64="$(printf "$protected" | _base64 | _urlencode)" _debug3 protected64 "$protected64" - sig=$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode) + if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")" ; then + _err "Sign request failed." + return 1 + fi + _debug3 _sig_t "$_sig_t" + + sig="$(printf "%s" "$_sig_t" | _urlencode)" _debug3 sig "$sig" body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" From d22b7938dae42e92d0af60f060c56ea4354f851c Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Nov 2016 22:45:50 +0800 Subject: [PATCH 0404/1348] fix old version openssl issue for ecc key --- acme.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/acme.sh b/acme.sh index 18453b6d..b1703ec8 100755 --- a/acme.sh +++ b/acme.sh @@ -891,6 +891,26 @@ _calcjwk() { crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" + if [ -z "$crv" ] ; then + _debug "Let's try ASN1 OID" + crv_oid="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" + case "${crv_oid}" in + "prime256v1") + crv="P-256" + ;; + "secp384r1") + crv="P-384" + ;; + "secp521r1") + crv="P-521" + ;; + *) + _err "ECC oid : $crv_oid" + return 1 + ;; + _debug3 crv "$crv" + fi + pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math $pubi + 1) _debug3 pubi "$pubi" From 067d586c1c2f17360d05ff79cae747f8bd7bc5a6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Nov 2016 22:47:45 +0800 Subject: [PATCH 0405/1348] typo --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index b1703ec8..2c1aacf4 100755 --- a/acme.sh +++ b/acme.sh @@ -908,6 +908,7 @@ _calcjwk() { _err "ECC oid : $crv_oid" return 1 ;; + esac _debug3 crv "$crv" fi From cae9cee295ccedeb5dda0f84042bcf9ed462f3d1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Nov 2016 22:53:33 +0800 Subject: [PATCH 0406/1348] add debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 2c1aacf4..8e86b03e 100755 --- a/acme.sh +++ b/acme.sh @@ -894,6 +894,7 @@ _calcjwk() { if [ -z "$crv" ] ; then _debug "Let's try ASN1 OID" crv_oid="$(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" case "${crv_oid}" in "prime256v1") crv="P-256" From 67184d7b20e9622b91ea23a2640de10105f84213 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Nov 2016 23:34:06 +0800 Subject: [PATCH 0407/1348] add more error check --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 8e86b03e..653dd042 100755 --- a/acme.sh +++ b/acme.sh @@ -454,7 +454,12 @@ _sign() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then $_sign_openssl | _base64 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then - _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)" + if ! _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)" ; then + _err "Sign failed: $_sign_openssl" + _err "Key file: $keyfile" + _err "Key content:$(cat "$keyfile")" + return 1 + fi _debug3 "_signedECText" "$_signedECText" _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" _debug3 "_ec_r" "$_ec_r" From d018be5d36e83428ab43ef51c67104f675f96f5a Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Nov 2016 23:45:08 +0800 Subject: [PATCH 0408/1348] hide private key from the log --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 653dd042..83bca1d8 100755 --- a/acme.sh +++ b/acme.sh @@ -457,7 +457,7 @@ _sign() { if ! _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)" ; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" - _err "Key content:$(cat "$keyfile")" + _err "Key content:$(cat "$keyfile" | wc -l) lises" return 1 fi _debug3 "_signedECText" "$_signedECText" From f06c1e6c78911fc56125fb9499e4a03fb03a0b57 Mon Sep 17 00:00:00 2001 From: nytral Date: Sun, 6 Nov 2016 12:37:13 +0100 Subject: [PATCH 0409/1348] luadns bash script --- dnsapi/dns_lua.sh | 147 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 dnsapi/dns_lua.sh diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh new file mode 100644 index 00000000..fc0bb8b0 --- /dev/null +++ b/dnsapi/dns_lua.sh @@ -0,0 +1,147 @@ +#!/usr/bin/env bash + + +# +#LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#LUA_Email="xxxx%40sss.com" + +LUA_Api="https://api.luadns.com/v1" +LUA_auth=$(printf $LUA_Email:$LUA_Key | base64) +# _ACME_CURL="curl -L --silent -u $LUA_Email:$LUA_Key " + +#printf $LUA_Api +#exit +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_lua_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ] ; then + _err "You don't specify luadns api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf LUA_Key "$LUA_Key" + _saveaccountconf LUA_Email "$LUA_Email" + + _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" + _LUA_rest GET "zones/${_domain_id}/records" + + if ! printf "$response" | grep \"id\": > /dev/null ; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o \"name\":\"$fulldomain\" | wc -l) + _debug count "$count" + if [ "$count" = "0" ] ; then + _info "Adding record" + if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep $fulldomain > /dev/null ; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\" | cut -d: -f2|cut -d, -f1 ) + _debug "record_id" $record_id + + _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" + if [ "$?" = "0" ]; then + _info "Updated!" + #todo: check if the record takes effect + return 0; + fi + _err "Update error" + return 1 + fi + +} + + +#fulldomain +dns_lua_rm() { + fulldomain=$1 + +} + + +#################### Private functions bellow ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + if ! _LUA_rest GET "zones" ; then + return 1 + fi + while [ '1' ] ; do + h=$(printf $domain | cut -d . -f $i-100) + if [ -z "$h" ] ; then + #not valid + return 1; + fi + + if printf $response | grep \"name\":\"$h\" >/dev/null ; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$h\" | cut -d : -f 2 | cut -d , -f 1) + if [ "$_domain_id" ] ; then + _sub_domain=$(printf $domain | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(expr $i + 1) + done + return 1 +} + +_LUA_rest() { + m=$1 + ep="$2" + data="$3" + _debug $ep + + _H1="Accept: application/json" + _H2="Authorization: Basic $LUA_auth" + if [ "$data" ] ; then + _debug data "$data" + response="$(_post "$data" "$LUA_Api/$ep" "" $m)" + else + response="$(_get "$LUA_Api/$ep")" + fi + + if [ "$?" != "0" ] ; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + + From a43d6972251b30ee183cae13cbc54a4f3605f51a Mon Sep 17 00:00:00 2001 From: nytral Date: Sun, 6 Nov 2016 12:42:27 +0100 Subject: [PATCH 0410/1348] cleanup --- dnsapi/dns_lua.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index fc0bb8b0..3e14b386 100644 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -4,14 +4,11 @@ # #LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" # -#LUA_Email="xxxx%40sss.com" +#LUA_Email="user@luadns.net" LUA_Api="https://api.luadns.com/v1" LUA_auth=$(printf $LUA_Email:$LUA_Key | base64) -# _ACME_CURL="curl -L --silent -u $LUA_Email:$LUA_Key " -#printf $LUA_Api -#exit ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" From 2be4a5e4861477465e5249b9b996c69ffc990c3f Mon Sep 17 00:00:00 2001 From: nytral Date: Sun, 6 Nov 2016 14:39:22 +0100 Subject: [PATCH 0411/1348] use _base64 --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 3e14b386..dfc10afd 100644 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -7,7 +7,7 @@ #LUA_Email="user@luadns.net" LUA_Api="https://api.luadns.com/v1" -LUA_auth=$(printf $LUA_Email:$LUA_Key | base64) +LUA_auth=$(printf $LUA_Email:$LUA_Key | _base64) ######## Public functions ##################### From 662df85e548045e70e89c392150709bd92b60e99 Mon Sep 17 00:00:00 2001 From: nytral Date: Sun, 6 Nov 2016 15:09:08 +0100 Subject: [PATCH 0412/1348] s/bash/sh/ --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index dfc10afd..acc796f4 100644 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # From 56e0269e5e90ac6fe535404e786af7f7921308b1 Mon Sep 17 00:00:00 2001 From: nytral Date: Sun, 6 Nov 2016 15:12:25 +0100 Subject: [PATCH 0413/1348] email contact added --- dnsapi/dns_lua.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index acc796f4..09265ce9 100644 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -1,5 +1,6 @@ #!/usr/bin/env sh +# bug reports to justmwa@users.noreply.github.com # #LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" From 1d9f76e2c80cd0be134926421284d1b0ffbc7a5a Mon Sep 17 00:00:00 2001 From: nytral Date: Sun, 6 Nov 2016 15:24:23 +0100 Subject: [PATCH 0414/1348] working email contact added --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 09265ce9..a59e0d0b 100644 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -# bug reports to justmwa@users.noreply.github.com +# bug reports to dev@1e.ca # #LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" From 57e58ce76cce210992e05db818d9066bbe7e6226 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 6 Nov 2016 23:08:45 +0800 Subject: [PATCH 0415/1348] set default account key to 2048. Some old platforms doesn't support ecc signing. --- acme.sh | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/acme.sh b/acme.sh index 83bca1d8..1bea19d9 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.3 +VER=2.6.4 PROJECT_NAME="acme.sh" @@ -19,6 +19,9 @@ DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016. DEFAULT_USER_AGENT="$PROJECT_ENTRY client v$VER : $PROJECT" DEFAULT_ACCOUNT_EMAIL="" +DEFAULT_ACCOUNT_KEY_LENGTH=2048 +DEFAULT_DOMAIN_KEY_LENGTH=2048 + STAGE_CA="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" @@ -739,15 +742,24 @@ createAccountKey() { return fi + length=$1 + _create_account_key "$length" + +} + +_create_account_key() { + length=$1 if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ] ; then - _debug "Use default length 2048" - length=2048 + _debug "Use default length $DEFAULT_ACCOUNT_KEY_LENGTH" + length="$DEFAULT_ACCOUNT_KEY_LENGTH" fi + _debug length "$length" _initpath + mkdir -p "$CA_DIR" if [ -f "$ACCOUNT_KEY_PATH" ] ; then _info "Account key exists, skip" return @@ -769,6 +781,11 @@ createDomainKey() { domain=$1 length=$2 + if [ -z "$length" ] ; then + _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH" + length="$DEFAULT_DOMAIN_KEY_LENGTH" + fi + _initpath $domain "$length" if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then @@ -1319,7 +1336,7 @@ _read_conf() { eval "printf \"%s\" \"\$$_sdkey\"" ) else - _err "config file is empty, can not read $_sdkey" + _debug "config file is empty, can not read $_sdkey" fi } @@ -2163,16 +2180,21 @@ updateaccount() { } registeraccount() { + _reg_length="$1" _initpath - _regAccount + _regAccount "$_reg_length" } __calcAccountKeyHash() { [ -f "$ACCOUNT_KEY_PATH" ] && cat "$ACCOUNT_KEY_PATH" | _digest sha256 } + +#keylength _regAccount() { _initpath + _reg_length="$1" + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" @@ -2185,11 +2207,7 @@ _regAccount() { fi if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then - _acck="no" - if [ "$Le_Keylength" ] ; then - _acck="$Le_Keylength" - fi - if ! createAccountKey "$_acck" ; then + if ! _create_account_key "$_reg_length" ; then _err "Create account key error." return 1 fi @@ -2414,10 +2432,12 @@ issue() { _debug2 _saved_account_key_hash "$_saved_account_key_hash" if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ] ; then - if ! _regAccount ; then + if ! _regAccount "$_accountkeylength"; then _on_issue_err return 1 fi + else + _debug "_saved_account_key_hash is not changed, skip register account." fi if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ] ; then @@ -4232,9 +4252,6 @@ _process() { --keylength|-k) _keylength="$2" - if [ "$_accountkeylength" = "$NO_VALUE" ] ; then - _accountkeylength="$2" - fi shift ;; --accountkeylength|-ak) @@ -4458,7 +4475,7 @@ _process() { deactivate "$_domain,$_altdomains" ;; registeraccount) - registeraccount + registeraccount "$_accountkeylength" ;; updateaccount) updateaccount From 5be1449db5a2870cae7eeea0b5cf78a4694b1459 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 6 Nov 2016 23:26:38 +0800 Subject: [PATCH 0416/1348] add APACHE_HTTPD_CONF https://github.com/Neilpang/acme.sh/issues/363 --- acme.sh | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index 1bea19d9..b07b1dcd 100755 --- a/acme.sh +++ b/acme.sh @@ -1808,22 +1808,28 @@ _apachePath() { return 1 fi - httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" - _debug httpdconfname "$httpdconfname" - - if [ -z "$httpdconfname" ] ; then - _err "Can not read apache config file." - return 1 - fi - - if _startswith "$httpdconfname" '/' ; then - httpdconf="$httpdconfname" + if [ "$APACHE_HTTPD_CONF" ] ; then + _saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF" + httpdconf="$APACHE_HTTPD_CONF" httpdconfname="$(basename $httpdconfname)" else - httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" - _debug httpdroot "$httpdroot" - httpdconf="$httpdroot/$httpdconfname" - httpdconfname="$(basename $httpdconfname)" + httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" + _debug httpdconfname "$httpdconfname" + + if [ -z "$httpdconfname" ] ; then + _err "Can not read apache config file." + return 1 + fi + + if _startswith "$httpdconfname" '/' ; then + httpdconf="$httpdconfname" + httpdconfname="$(basename $httpdconfname)" + else + httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" + _debug httpdroot "$httpdroot" + httpdconf="$httpdroot/$httpdconfname" + httpdconfname="$(basename $httpdconfname)" + fi fi _debug httpdconf "$httpdconf" _debug httpdconfname "$httpdconfname" From f58e83ee8764c4faa1736e608621166d35bebe2d Mon Sep 17 00:00:00 2001 From: nytral Date: Sun, 6 Nov 2016 16:52:43 +0100 Subject: [PATCH 0417/1348] READMEs edit --- README.md | 1 + dnsapi/README.md | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/README.md b/README.md index b762268e..79b5a52f 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,7 @@ You don't have do anything manually! 7. PowerDNS API 8. 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.) +9. LuaDNS.com API ##### More APIs are coming soon... diff --git a/dnsapi/README.md b/dnsapi/README.md index 94603154..19769111 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -136,4 +136,22 @@ For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api +## Use LuaDNS domain API + +Get your API token at https://api.luadns.com/settings + +``` +export LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" + +export LUA_Email="xxxx@sss.com" + +``` + +To issue a cert: +``` +acme.sh --issue --dns dns_lua --dnssleep 3 -d example.com -d www.example.com +``` + +The `LUA_Key` and `LUA_Email` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. + From 20a6ab3d1a8b4ee0d2bf58388cf8d5a1d473cb41 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 7 Nov 2016 20:59:10 +0800 Subject: [PATCH 0418/1348] find hook file in current dir first --- acme.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index b07b1dcd..e077d2e6 100755 --- a/acme.sh +++ b/acme.sh @@ -2297,8 +2297,12 @@ _findHook() { _hookdomain="$1" _hookcat="$2" _hookname="$3" - - if [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ] ; then + + if [ -f "$_SCRIPT_HOME/$_hookdomain/$_hookname" ] ; then + d_api="$_SCRIPT_HOME/$_hookdomain/$_hookname" + elif [ -f "$_SCRIPT_HOME/$_hookdomain/$_hookname.sh" ] ; then + d_api="$_SCRIPT_HOME/$_hookdomain/$_hookname.sh" + elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ] ; then d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname" elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ] ; then d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" From 803fb243bfceecb4ecb054cb914a161411b2538a Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 21:50:59 +0100 Subject: [PATCH 0419/1348] adding DNSMadeEasy API --- README.md | 1 + dnsapi/README.md | 19 ++++++ dnsapi/dns_me.sh | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100755 dnsapi/dns_me.sh diff --git a/README.md b/README.md index 79b5a52f..104532bf 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,7 @@ You don't have do anything manually! 8. 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.) 9. LuaDNS.com API +10. DNSMadeEasy.com API ##### More APIs are coming soon... diff --git a/dnsapi/README.md b/dnsapi/README.md index 19769111..7eff6de1 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -154,4 +154,23 @@ acme.sh --issue --dns dns_lua --dnssleep 3 -d example.com -d www.example.c The `LUA_Key` and `LUA_Email` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. +## Use DNSMadeEasy domain API + +Get your API credentials at https://cp.dnsmadeeasy.com/account/info + +``` +export ME_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" + +export ME_Secret="qdfqsdfkjdskfj" + +``` + +To issue a cert: +``` +acme.sh --issue --dns dns_me --dnssleep 3 -d example.com -d www.example.com +``` + +The `ME_Key` and `ME_Secret` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. + + diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh new file mode 100755 index 00000000..fffd8d49 --- /dev/null +++ b/dnsapi/dns_me.sh @@ -0,0 +1,148 @@ +#!/bin/sh + +# bug reports to dev@1e.ca + +# ME_Key=qmlkdjflmkqdjf +# ME_Secret=qmsdlkqmlksdvnnpae + +ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_me_add(){ + fulldomain=$1 + txtvalue=$2 + + if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ] ; then + _err "You didn't specify DNSMadeEasy api key and secret yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf ME_Key "$ME_Key" + _saveaccountconf ME_Secret "$ME_Secret" + + _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" + _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" + + if ! printf "$response" | grep \"totalRecords\": > /dev/null ; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o \"totalRecords\":[^,]* | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ] ; then + _info "Adding record" + if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep id: > /dev/null ; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | cut -d : -f 2 | head -n 1) + _debug "record_id" $record_id + + _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" + if [ "$?" = "0" ]; then + _info "Updated" + #todo: check if the record takes effect + return 0; + fi + _err "Update error" + return 1 + fi + +} + + +#fulldomain +dns_me_rm() { + fulldomain=$1 + +} + + +#################### Private functions bellow ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while [ '1' ] ; do + h=$(printf $domain | cut -d . -f $i-100) + if [ -z "$h" ] ; then + #not valid + return 1; + fi + + if ! _me_rest GET "name?domainname=$h" ; then + return 1 + fi + + if printf $response | grep \"name\":\"$h\" >/dev/null ; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | head -n 1 | cut -d : -f 2 ) + if [ "$_domain_id" ] ; then + _sub_domain=$(printf $domain | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(expr $i + 1) + done + return 1 +} + +_me_rest() { + m=$1 + ep="$2" + data="$3" + _debug $ep + + cdate=$(date -Ru) + hmac=$(printf "$cdate" | openssl dgst -sha1 -hmac $ME_Secret | cut -d = -f 2 | tr -d ' ') + + _H1="x-dnsme-apiKey: $ME_Key" + _H2="x-dnsme-requestDate: $cdate" + _H3="x-dnsme-hmac: $hmac" + + if [ "$data" ] ; then + _debug data "$data" + response="$(_post "$data" "$ME_Api/$ep" "" $m)" + else + response="$(_get "$ME_Api/$ep")" + fi + + if [ "$?" != "0" ] ; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + + From 49e1f7d8bf8fc9b38918c03255badc5ccca1f383 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 22:16:00 +0100 Subject: [PATCH 0420/1348] bugfix --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index fffd8d49..4234ac9c 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -46,7 +46,7 @@ dns_me_add(){ if [ "$count" = "0" ] ; then _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep id: > /dev/null ; then + if [ "$?" = "0" ]; then _info "Added" #todo: check if the record takes effect return 0 From 4fe7b6cd65df54833da378f3b2bec36b7c5202c2 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 22:16:53 +0100 Subject: [PATCH 0421/1348] better bugfix --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 4234ac9c..b379fe98 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -46,7 +46,7 @@ dns_me_add(){ if [ "$count" = "0" ] ; then _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if [ "$?" = "0" ]; then + if printf -- "%s" "$response" | grep \"id\": > /dev/null ; then _info "Added" #todo: check if the record takes effect return 0 From 0b5bff01e1a43cc531813c7a359e47735751a8aa Mon Sep 17 00:00:00 2001 From: nytral Date: Tue, 8 Nov 2016 14:13:05 +0100 Subject: [PATCH 0422/1348] s/bash/sh/ --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index b379fe98..d8dd7e45 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh # bug reports to dev@1e.ca From b001840dee20d31423a7fb29e18ac9177b7f9a4c Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 8 Nov 2016 21:27:39 +0800 Subject: [PATCH 0423/1348] minor: add _hmac function --- acme.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/acme.sh b/acme.sh index e077d2e6..c52ce70c 100755 --- a/acme.sh +++ b/acme.sh @@ -436,6 +436,31 @@ _digest() { } +#Usage: hashalg secret [outputhex] +#Output Base64-encoded hmac +_hmac() { + alg="$1" + hmac_sec="$2" + outputhex="$3" + + if [ -z "$hmac_sec" ] ; then + _usage "Usage: _hmac hashalg secret [outputhex]" + return 1 + fi + + if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then + if [ "$outputhex" ] ; then + openssl dgst -$alg -hmac "$hmac_sec" | cut -d = -f 2 | tr -d ' ' + else + openssl dgst -$alg -hmac "$hmac_sec" -binary | _base64 + fi + else + _err "$alg is not supported yet" + return 1 + fi + +} + #Usage: keyfile hashalg #Output: Base64-encoded signature value _sign() { From 22b83d76303eadfa05e6da859fa1e1b8ae769ea6 Mon Sep 17 00:00:00 2001 From: nytral Date: Tue, 8 Nov 2016 15:56:46 +0100 Subject: [PATCH 0424/1348] _hmac use and generic date --- dnsapi/dns_me.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index d8dd7e45..3135718e 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -123,8 +123,8 @@ _me_rest() { data="$3" _debug $ep - cdate=$(date -Ru) - hmac=$(printf "$cdate" | openssl dgst -sha1 -hmac $ME_Secret | cut -d = -f 2 | tr -d ' ') + cdate=$(date -u +"%a, %d %b %Y %T %Z") + hmac=$(printf "$cdate" | _hmac sha1 "$ME_Secret" 1) _H1="x-dnsme-apiKey: $ME_Key" _H2="x-dnsme-requestDate: $cdate" From 4c2a384159a94ac01976326d6458e171bcddb319 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 19:30:39 +0800 Subject: [PATCH 0425/1348] Add shfmt to format source code --- .travis.yml | 11 + acme.sh | 2390 ++++++++++++++++++++--------------------- deploy/myapi.sh | 9 +- dnsapi/dns_cf.sh | 68 +- dnsapi/dns_cx.sh | 100 +- dnsapi/dns_dp.sh | 16 +- dnsapi/dns_gd.sh | 51 +- dnsapi/dns_lexicon.sh | 38 +- dnsapi/dns_lua.sh | 64 +- dnsapi/dns_myapi.sh | 15 +- dnsapi/dns_ovh.sh | 185 ++-- dnsapi/dns_pdns.sh | 36 +- 12 files changed, 1439 insertions(+), 1544 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..6b71b4b8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: bash + +env: + global: + - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 + +script: + - curl -sSL $SHFMT_URL -o ~/shfmt + - chmod +x ~/shfmt + - ~/shfmt -l -w -i 2 . + - git diff --exit-code || echo "Run shfmt to fix the formatting issues" diff --git a/acme.sh b/acme.sh index c52ce70c..47a4f6d0 100755 --- a/acme.sh +++ b/acme.sh @@ -60,33 +60,32 @@ DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" _DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh" __INTERACTIVE="" -if [ -t 1 ] ; then +if [ -t 1 ]; then __INTERACTIVE="1" fi __green() { - if [ "$__INTERACTIVE" ] ; then + if [ "$__INTERACTIVE" ]; then printf '\033[1;31;32m' fi printf -- "$1" - if [ "$__INTERACTIVE" ] ; then + if [ "$__INTERACTIVE" ]; then printf '\033[0m' fi } __red() { - if [ "$__INTERACTIVE" ] ; then + if [ "$__INTERACTIVE" ]; then printf '\033[1;31;40m' fi printf -- "$1" - if [ "$__INTERACTIVE" ] ; then + if [ "$__INTERACTIVE" ]; then printf '\033[0m' fi } - _printargs() { - if [ -z "$2" ] ; then + if [ -z "$2" ]; then printf -- "[$(date)] $1" else printf -- "[$(date)] $1='$2'" @@ -97,31 +96,30 @@ _printargs() { _dlg_versions() { echo "Diagnosis versions: " echo "openssl:" - if _exists openssl ; then + if _exists openssl; then openssl version 2>&1 else echo "openssl doesn't exists." fi - + echo "apache:" - if [ "$_APACHECTL" ] && _exists "$_APACHECTL" ; then + if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then _APACHECTL -V 2>&1 else echo "apache doesn't exists." fi - + echo "nc:" - if _exists "nc" ; then + if _exists "nc"; then nc -h 2>&1 else _debug "nc doesn't exists." fi } - _log() { [ -z "$LOG_FILE" ] && return - _printargs "$@" >> $LOG_FILE + _printargs "$@" >>$LOG_FILE } _info() { @@ -129,11 +127,10 @@ _info() { _printargs "$@" } - _err() { _log "$@" printf -- "[$(date)] " >&2 - if [ -z "$2" ] ; then + if [ -z "$2" ]; then __red "$1" >&2 else __red "$1='$2'" >&2 @@ -143,52 +140,51 @@ _err() { } _usage() { - __red "$@" >&2 + __red "$@" >&2 printf "\n" >&2 } - _debug() { - if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ] ; then + if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ]; then _log "$@" fi - if [ -z "$DEBUG" ] ; then + if [ -z "$DEBUG" ]; then return fi _printargs "$@" >&2 } _debug2() { - if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ] ; then + if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ]; then _log "$@" fi - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _debug "$@" fi } _debug3() { - if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ] ; then + if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ]; then _log "$@" fi - if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ]; then _debug "$@" fi } -_startswith(){ +_startswith() { _str="$1" _sub="$2" echo "$_str" | grep "^$_sub" >/dev/null 2>&1 } -_endswith(){ +_endswith() { _str="$1" _sub="$2" echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1 } -_contains(){ +_contains() { _str="$1" _sub="$2" echo "$_str" | grep -- "$_sub" >/dev/null 2>&1 @@ -198,17 +194,17 @@ _hasfield() { _str="$1" _field="$2" _sep="$3" - if [ -z "$_field" ] ; then + if [ -z "$_field" ]; then _usage "Usage: str field [sep]" return 1 fi - - if [ -z "$_sep" ] ; then + + if [ -z "$_sep" ]; then _sep="," fi - - for f in $(echo "$_str" | tr ',' ' ') ; do - if [ "$f" = "$_field" ] ; then + + for f in $(echo "$_str" | tr ',' ' '); do + if [ "$f" = "$_field" ]; then _debug2 "'$_str' contains '$_field'" return 0 #contains ok fi @@ -217,42 +213,41 @@ _hasfield() { return 1 #not contains } -_getfield(){ +_getfield() { _str="$1" _findex="$2" _sep="$3" - - if [ -z "$_findex" ] ; then + + if [ -z "$_findex" ]; then _usage "Usage: str field [sep]" return 1 fi - - if [ -z "$_sep" ] ; then + + if [ -z "$_sep" ]; then _sep="," fi _ffi=$_findex - while [ "$_ffi" -gt "0" ] - do - _fv="$(echo "$_str" | cut -d $_sep -f $_ffi)" - if [ "$_fv" ] ; then + while [ "$_ffi" -gt "0" ]; do + _fv="$(echo "$_str" | cut -d $_sep -f $_ffi)" + if [ "$_fv" ]; then printf -- "%s" "$_fv" return 0 fi _ffi="$(_math $_ffi - 1)" done - + printf -- "%s" "$_str" } -_exists(){ +_exists() { cmd="$1" - if [ -z "$cmd" ] ; then + if [ -z "$cmd" ]; then _usage "Usage: _exists cmd" return 1 fi - if type command >/dev/null 2>&1 ; then + if type command >/dev/null 2>&1; then command -v "$cmd" >/dev/null 2>&1 else type "$cmd" >/dev/null 2>&1 @@ -263,41 +258,40 @@ _exists(){ } #a + b -_math(){ +_math() { expr "$@" } _h_char_2_dec() { _ch=$1 case "${_ch}" in - a|A) + a | A) printf "10" - ;; - b|B) + ;; + b | B) printf "11" - ;; - c|C) + ;; + c | C) printf "12" - ;; - d|D) + ;; + d | D) printf "13" - ;; - e|E) + ;; + e | E) printf "14" - ;; - f|F) + ;; + f | F) printf "15" - ;; + ;; *) printf "%s" "$_ch" - ;; + ;; esac } - _URGLY_PRINTF="" -if [ "$(printf '\x41')" != 'A' ] ; then +if [ "$(printf '\x41')" != 'A' ]; then _URGLY_PRINTF=1 fi @@ -305,35 +299,35 @@ _h2b() { hex=$(cat) i=1 j=2 - if _exists let ; then + if _exists let; then uselet="1" fi _debug3 uselet "$uselet" _debug3 _URGLY_PRINTF "$_URGLY_PRINTF" - while true ; do - if [ -z "$_URGLY_PRINTF" ] ; then + while true; do + if [ -z "$_URGLY_PRINTF" ]; then h="$(printf $hex | cut -c $i-$j)" - if [ -z "$h" ] ; then - break; + if [ -z "$h" ]; then + break fi printf "\x$h" else ic="$(printf $hex | cut -c $i)" jc="$(printf $hex | cut -c $j)" - if [ -z "$ic$jc" ] ; then - break; + if [ -z "$ic$jc" ]; then + break fi ic="$(_h_char_2_dec "$ic")" jc="$(_h_char_2_dec "$jc")" printf '\'"$(printf %o "$(_math $ic \* 16 + $jc)")" fi - if [ "$uselet" ] ; then + if [ "$uselet" ]; then let "i+=2" >/dev/null let "j+=2" >/dev/null else i="$(_math $i + 2)" j="$(_math $j + 2)" - fi + fi done } @@ -341,7 +335,7 @@ _h2b() { _sed_i() { options="$1" filename="$2" - if [ -z "$filename" ] ; then + if [ -z "$filename" ]; then _usage "Usage:_sed_i options filename" return 1 fi @@ -352,12 +346,12 @@ _sed_i() { else _debug "No -i support in sed" text="$(cat "$filename")" - echo "$text" | sed "$options" > "$filename" + echo "$text" | sed "$options" >"$filename" fi } _egrep_o() { - if _contains "$(egrep -o 2>&1)" "egrep: illegal option -- o" ; then + if _contains "$(egrep -o 2>&1)" "egrep: illegal option -- o"; then sed -n 's/.*\('"$1"'\).*/\1/p' else egrep -o "$1" @@ -369,34 +363,34 @@ _getfile() { filename="$1" startline="$2" endline="$3" - if [ -z "$endline" ] ; then + if [ -z "$endline" ]; then _usage "Usage: file startline endline" return 1 fi - - i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)" - if [ -z "$i" ] ; then + + i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)" + if [ -z "$i" ]; then _err "Can not find start line: $startline" return 1 fi i="$(_math "$i" + 1)" _debug i "$i" - - j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)" - if [ -z "$j" ] ; then + + j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)" + if [ -z "$j" ]; then _err "Can not find end line: $endline" return 1 fi j="$(_math "$j" - 1)" _debug j "$j" - - sed -n "$i,${j}p" "$filename" + + sed -n "$i,${j}p" "$filename" } #Usage: multiline _base64() { - if [ "$1" ] ; then + if [ "$1" ]; then openssl base64 -e else openssl base64 -e | tr -d '\r\n' @@ -405,7 +399,7 @@ _base64() { #Usage: multiline _dbase64() { - if [ "$1" ] ; then + if [ "$1" ]; then openssl base64 -d -A else openssl base64 -d @@ -416,15 +410,15 @@ _dbase64() { #Output Base64-encoded digest _digest() { alg="$1" - if [ -z "$alg" ] ; then + if [ -z "$alg" ]; then _usage "Usage: _digest hashalg" return 1 fi - + outputhex="$2" - + if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then - if [ "$outputhex" ] ; then + if [ "$outputhex" ]; then openssl dgst -$alg -hex | cut -d = -f 2 | tr -d ' ' else openssl dgst -$alg -binary | _base64 @@ -442,14 +436,14 @@ _hmac() { alg="$1" hmac_sec="$2" outputhex="$3" - - if [ -z "$hmac_sec" ] ; then - _usage "Usage: _hmac hashalg secret [outputhex]" + + if [ -z "$hmac_sec" ]; then + _usage "Usage: _hmac hashalg secret [outputhex]" return 1 fi if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then - if [ "$outputhex" ] ; then + if [ "$outputhex" ]; then openssl dgst -$alg -hmac "$hmac_sec" | cut -d = -f 2 | tr -d ' ' else openssl dgst -$alg -hmac "$hmac_sec" -binary | _base64 @@ -466,23 +460,23 @@ _hmac() { _sign() { keyfile="$1" alg="$2" - if [ -z "$alg" ] ; then + if [ -z "$alg" ]; then _usage "Usage: _sign keyfile hashalg" return 1 fi - + _sign_openssl="openssl dgst -sign $keyfile " - if [ "$alg" = "sha256" ] ; then + if [ "$alg" = "sha256" ]; then _sign_openssl="$_sign_openssl -$alg" else _err "$alg is not supported yet" return 1 fi - - 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 - elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then - if ! _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)" ; then + elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then + if ! _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" _err "Key content:$(cat "$keyfile" | wc -l) lises" @@ -498,22 +492,22 @@ _sign() { _err "Unknown key file format." return 1 fi - + } #keylength _isEccKey() { _length="$1" - if [ -z "$_length" ] ;then + if [ -z "$_length" ]; then return 1 fi [ "$_length" != "1024" ] \ - && [ "$_length" != "2048" ] \ - && [ "$_length" != "3072" ] \ - && [ "$_length" != "4096" ] \ - && [ "$_length" != "8192" ] + && [ "$_length" != "2048" ] \ + && [ "$_length" != "3072" ] \ + && [ "$_length" != "4096" ] \ + && [ "$_length" != "8192" ] } # _createkey 2048|ec-256 file @@ -521,42 +515,41 @@ _createkey() { length="$1" f="$2" eccname="$length" - if _startswith "$length" "ec-" ; then + if _startswith "$length" "ec-"; then length=$(printf $length | cut -d '-' -f 2-100) - if [ "$length" = "256" ] ; then + if [ "$length" = "256" ]; then eccname="prime256v1" fi - if [ "$length" = "384" ] ; then + if [ "$length" = "384" ]; then eccname="secp384r1" fi - if [ "$length" = "521" ] ; then + if [ "$length" = "521" ]; then eccname="secp521r1" fi fi - if [ -z "$length" ] ; then - length=2048 + if [ -z "$length" ]; then + length=2048 fi - + _debug "Use length $length" - if _isEccKey "$length" ; then + if _isEccKey "$length"; then _debug "Using ec name: $eccname" - openssl ecparam -name $eccname -genkey 2>/dev/null > "$f" + openssl ecparam -name $eccname -genkey 2>/dev/null >"$f" else _debug "Using RSA: $length" - openssl genrsa $length 2>/dev/null > "$f" + openssl genrsa $length 2>/dev/null >"$f" fi - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Create key error." return 1 fi } - #domain _is_idn() { _is_idn_d="$1" @@ -570,17 +563,17 @@ _is_idn() { #aa.com,bb.com,cc.com _idn() { __idn_d="$1" - if ! _is_idn "$__idn_d" ; then + if ! _is_idn "$__idn_d"; then printf "%s" "$__idn_d" return 0 fi - - if _exists idn ; then - if _contains "$__idn_d" ',' ; then + + if _exists idn; then + if _contains "$__idn_d" ','; then _i_first="1" - for f in $(echo "$__idn_d" | tr ',' ' ') ; do + for f in $(echo "$__idn_d" | tr ',' ' '); do [ -z "$f" ] && continue - if [ -z "$_i_first" ] ; then + if [ -z "$_i_first" ]; then printf "%s" "," else _i_first="" @@ -608,29 +601,29 @@ _createcsr() { _debug2 csrkey "$csrkey" _debug2 csr "$csr" _debug2 csrconf "$csrconf" - - printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" > "$csrconf" - + + 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 #single domain _info "Single domain" "$domain" else domainlist="$(_idn $domainlist)" _debug2 domainlist "$domainlist" - if _contains "$domainlist" "," ; then + if _contains "$domainlist" ","; then alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" else alt="DNS:$domainlist" fi #multi _info "Multi domain" "$alt" - printf -- "\nsubjectAltName=$alt" >> "$csrconf" + printf -- "\nsubjectAltName=$alt" >>"$csrconf" fi - if [ "$Le_OCSP_Stable" ] ; then + if [ "$Le_OCSP_Stable" ]; then _savedomainconf Le_OCSP_Stable "$Le_OCSP_Stable" - printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >> "$csrconf" + printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" fi - + _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" openssl req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" @@ -643,8 +636,8 @@ _signcsr() { conf="$3" cert="$4" _debug "_signcsr" - - _msg="$(openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" + + _msg="$(openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" _ret="$?" _debug "$_msg" return $_ret @@ -653,48 +646,48 @@ _signcsr() { #_csrfile _readSubjectFromCSR() { _csrfile="$1" - if [ -z "$_csrfile" ] ; then + if [ -z "$_csrfile" ]; then _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - openssl req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + openssl req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile #echo comma separated domain list _readSubjectAltNamesFromCSR() { _csrfile="$1" - if [ -z "$_csrfile" ] ; then + if [ -z "$_csrfile" ]; then _usage "_readSubjectAltNamesFromCSR mycsr.csr" return 1 fi - + _csrsubj="$(_readSubjectFromCSR "$_csrfile")" _debug _csrsubj "$_csrsubj" - - _dnsAltnames="$(openssl req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" + + _dnsAltnames="$(openssl req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" _debug _dnsAltnames "$_dnsAltnames" - - if _contains "$_dnsAltnames," "DNS:$_csrsubj," ; then + + if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then _debug "AltNames contains subject" _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")" else _debug "AltNames doesn't contain subject" fi - + printf "%s" "$_dnsAltnames" | sed "s/DNS://g" } #_csrfile _readKeyLengthFromCSR() { _csrfile="$1" - if [ -z "$_csrfile" ] ; then + if [ -z "$_csrfile" ]; then _usage "_readKeyLengthFromCSR mycsr.csr" return 1 fi - - _outcsr="$(openssl req -noout -text -in "$_csrfile")" - if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey" ; then + + _outcsr="$(openssl req -noout -text -in "$_csrfile")" + if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else @@ -703,25 +696,24 @@ _readKeyLengthFromCSR() { fi } - _ss() { _port="$1" - - if _exists "ss" ; then + + if _exists "ss"; then _debug "Using: ss" ss -ntpl | grep ":$_port " return 0 fi - if _exists "netstat" ; then + if _exists "netstat"; then _debug "Using: netstat" - if netstat -h 2>&1 | grep "\-p proto" >/dev/null ; then + if netstat -h 2>&1 | grep "\-p proto" >/dev/null; then #for windows version netstat tool netstat -an -p tcp | grep "LISTENING" | grep ":$_port " else - if netstat -help 2>&1 | grep "\-p protocol" >/dev/null ; then + if netstat -help 2>&1 | grep "\-p protocol" >/dev/null; then netstat -an -p tcp | grep LISTEN | grep ":$_port " - elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null ; then + elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then #for solaris netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" else @@ -738,22 +730,22 @@ _ss() { toPkcs() { domain="$1" pfxPassword="$2" - if [ -z "$domain" ] ; then + if [ -z "$domain" ]; then _usage "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]" return 1 fi _isEcc="$3" - + _initpath "$domain" "$_isEcc" - if [ "$pfxPassword" ] ; then + if [ "$pfxPassword" ]; then openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" else openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" fi - - if [ "$?" = "0" ] ; then + + if [ "$?" = "0" ]; then _info "Success, Pfx is exported to: $CERT_PFX_PATH" fi @@ -762,11 +754,11 @@ toPkcs() { #[2048] createAccountKey() { _info "Creating account key" - if [ -z "$1" ] ; then + if [ -z "$1" ]; then _usage "Usage: $PROJECT_ENTRY --createAccountKey --accountkeylength 2048" return fi - + length=$1 _create_account_key "$length" @@ -775,17 +767,17 @@ createAccountKey() { _create_account_key() { length=$1 - - if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ] ; then + + if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ]; then _debug "Use default length $DEFAULT_ACCOUNT_KEY_LENGTH" length="$DEFAULT_ACCOUNT_KEY_LENGTH" fi - + _debug length "$length" _initpath mkdir -p "$CA_DIR" - if [ -f "$ACCOUNT_KEY_PATH" ] ; then + if [ -f "$ACCOUNT_KEY_PATH" ]; then _info "Account key exists, skip" return else @@ -798,25 +790,25 @@ _create_account_key() { #domain [length] createDomainKey() { _info "Creating domain key" - if [ -z "$1" ] ; then + if [ -z "$1" ]; then _usage "Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ]" return fi - + domain=$1 length=$2 - - if [ -z "$length" ] ; then + + if [ -z "$length" ]; then _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH" length="$DEFAULT_DOMAIN_KEY_LENGTH" fi - - _initpath $domain "$length" - if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then + _initpath $domain "$length" + + if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then _createkey "$length" "$CERT_KEY_PATH" else - if [ "$IS_RENEW" ] ; then + if [ "$IS_RENEW" ]; then _info "Domain key exists, skip" return 0 else @@ -831,29 +823,29 @@ createDomainKey() { # domain domainlist isEcc createCSR() { _info "Creating csr" - if [ -z "$1" ] ; then + if [ -z "$1" ]; then _usage "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]" return fi - + domain="$1" domainlist="$2" _isEcc="$3" - + _initpath "$domain" "$_isEcc" - - if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then + + if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then _info "CSR exists, skip" return fi - - if [ ! -f "$CERT_KEY_PATH" ] ; then + + if [ ! -f "$CERT_KEY_PATH" ]; then _err "The key file is not found: $CERT_KEY_PATH" _err "Please create the key file first." return 1 fi _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" - + } _urlencode() { @@ -863,20 +855,20 @@ _urlencode() { _time2str() { #BSD - if date -u -d@$1 2>/dev/null ; then + if date -u -d@$1 2>/dev/null; then return fi - + #Linux - if date -u -r $1 2>/dev/null ; then + if date -u -r $1 2>/dev/null; then return fi - + #Soaris - if _exists adb ; then + if _exists adb; then echo $(echo "0t${1}=Y" | adb) fi - + } _normalizeJson() { @@ -885,92 +877,91 @@ _normalizeJson() { _stat() { #Linux - if stat -c '%U:%G' "$1" 2>/dev/null ; then + if stat -c '%U:%G' "$1" 2>/dev/null; then return fi - + #BSD - if stat -f '%Su:%Sg' "$1" 2>/dev/null ; then + if stat -f '%Su:%Sg' "$1" 2>/dev/null; then return fi - - return 1; #error, 'stat' not found + + return 1 #error, 'stat' not found } #keyfile _calcjwk() { keyfile="$1" - if [ -z "$keyfile" ] ; then + if [ -z "$keyfile" ]; then _usage "Usage: _calcjwk keyfile" return 1 fi - - if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ] ; then + + if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ]; then _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" return 0 fi - - + EC_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 _debug "RSA key" - pub_exp=$(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 + pub_exp=$(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 pub_exp=0$pub_exp fi _debug3 pub_exp "$pub_exp" - + e=$(echo $pub_exp | _h2b | _base64) _debug3 e "$e" - - modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2 ) + + modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus"| _h2b | _base64 | _urlencode )" + n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' _debug3 jwk "$jwk" - + JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' 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" EC_SIGN="1" - crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" - - if [ -z "$crv" ] ; then + + if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" - crv_oid="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv_oid="$(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" case "${crv_oid}" in "prime256v1") - crv="P-256" - ;; + crv="P-256" + ;; "secp384r1") - crv="P-384" - ;; + crv="P-384" + ;; "secp521r1") - crv="P-521" - ;; + crv="P-521" + ;; *) - _err "ECC oid : $crv_oid" - return 1 - ;; + _err "ECC oid : $crv_oid" + return 1 + ;; esac _debug3 crv "$crv" fi - - pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + + pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math $pubi + 1) _debug3 pubi "$pubi" - - pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + + pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math $pubj - 1) _debug3 pubj "$pubj" - - pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + + pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" - + xlen="$(printf "$pubtext" | tr -d ':' | wc -c)" xlen=$(_math $xlen / 4) _debug3 xlen "$xlen" @@ -978,20 +969,20 @@ _calcjwk() { xend=$(_math "$xlen" + 1) x="$(printf $pubtext | cut -d : -f 2-$xend)" _debug3 x "$x" - + x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)" _debug3 x64 "$x64" xend=$(_math "$xend" + 1) y="$(printf $pubtext | cut -d : -f $xend-10000)" _debug3 y "$y" - + y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)" _debug3 y64 "$y64" - + jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' _debug3 jwk "$jwk" - + JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' @@ -1009,18 +1000,18 @@ _time() { } _mktemp() { - if _exists mktemp ; then - if mktemp 2>/dev/null ; then + if _exists mktemp; then + if mktemp 2>/dev/null; then return 0 - elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null ; then + elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then #for Mac osx return 0 fi fi - if [ -d "/tmp" ] ; then + if [ -d "/tmp" ]; then echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" return 0 - elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR" ; then + elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp" return 0 fi @@ -1029,52 +1020,51 @@ _mktemp() { _inithttp() { - if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER" ; then + if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then HTTP_HEADER="$(_mktemp)" _debug2 HTTP_HEADER "$HTTP_HEADER" fi - - if [ "$__HTTP_INITIALIZED" ] ; then - if [ "$_ACME_CURL$_ACME_WGET" ] ; then + + if [ "$__HTTP_INITIALIZED" ]; then + if [ "$_ACME_CURL$_ACME_WGET" ]; then _debug2 "Http already initialized." return 0 fi fi - - if [ -z "$_ACME_CURL" ] && _exists "curl" ; then + + if [ -z "$_ACME_CURL" ] && _exists "curl"; then _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER " - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _CURL_DUMP="$(_mktemp)" _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " fi - if [ "$CA_BUNDLE" ] ; then + if [ "$CA_BUNDLE" ]; then _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " fi - if [ "$HTTPS_INSECURE" ] ; then + if [ "$HTTPS_INSECURE" ]; then _ACME_CURL="$_ACME_CURL --insecure " fi fi - + if [ -z "$_ACME_WGET" ] && _exists "wget"; then _ACME_WGET="wget -q" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _ACME_WGET="$_ACME_WGET -d " fi - if [ "$CA_BUNDLE" ] ; then + if [ "$CA_BUNDLE" ]; then _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " fi - if [ "$HTTPS_INSECURE" ] ; then + if [ "$HTTPS_INSECURE" ]; then _ACME_WGET="$_ACME_WGET --no-check-certificate " fi fi - + __HTTP_INITIALIZED=1 } - # body url [needbase64] [POST|PUT] _post() { body="$1" @@ -1082,53 +1072,53 @@ _post() { needbase64="$3" httpmethod="$4" - if [ -z "$httpmethod" ] ; then + if [ -z "$httpmethod" ]; then httpmethod="POST" fi _debug $httpmethod _debug "url" "$url" _debug2 "body" "$body" - + _inithttp - - if [ "$_ACME_CURL" ] ; then + + if [ "$_ACME_CURL" ]; then _CURL="$_ACME_CURL" _debug "_CURL" "$_CURL" - if [ "$needbase64" ] ; then + if [ "$needbase64" ]; then response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" )" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")" fi _ret="$?" - if [ "$_ret" != "0" ] ; then + if [ "$_ret" != "0" ]; then _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _err "Here is the curl dump log:" _err "$(cat "$_CURL_DUMP")" fi fi - elif [ "$_ACME_WGET" ] ; then + elif [ "$_ACME_WGET" ]; then _debug "_ACME_WGET" "$_ACME_WGET" - if [ "$needbase64" ] ; then - if [ "$httpmethod" = "POST" ] ; then + if [ "$needbase64" ]; then + if [ "$httpmethod" = "POST" ]; then response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" else response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" fi else - if [ "$httpmethod" = "POST" ] ; then + if [ "$httpmethod" = "POST" ]; then response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" else response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" fi fi _ret="$?" - if [ "$_ret" = "8" ] ; then + if [ "$_ret" = "8" ]; then _ret=0 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." fi - if [ "$_ret" != "0" ] ; then - _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" + if [ "$_ret" != "0" ]; then + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" fi _sed_i "s/^ *//g" "$HTTP_HEADER" else @@ -1140,7 +1130,6 @@ _post() { return $_ret } - # url getheader timeout _get() { _debug GET @@ -1152,43 +1141,43 @@ _get() { _inithttp - if [ "$_ACME_CURL" ] ; then + if [ "$_ACME_CURL" ]; then _CURL="$_ACME_CURL" - if [ "$t" ] ; then + if [ "$t" ]; then _CURL="$_CURL --connect-timeout $t" fi _debug "_CURL" "$_CURL" - if [ "$onlyheader" ] ; then + if [ "$onlyheader" ]; then $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url else - $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url + $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url fi ret=$? - if [ "$ret" != "0" ] ; then + if [ "$ret" != "0" ]; then _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _err "Here is the curl dump log:" _err "$(cat "$_CURL_DUMP")" fi fi - elif [ "$_ACME_WGET" ] ; then + elif [ "$_ACME_WGET" ]; then _WGET="$_ACME_WGET" - if [ "$t" ] ; then + if [ "$t" ]; then _WGET="$_WGET --timeout=$t" fi _debug "_WGET" "$_WGET" - if [ "$onlyheader" ] ; then + if [ "$onlyheader" ]; then $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' else - $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url + $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url fi ret=$? - if [ "$_ret" = "8" ] ; then + if [ "$_ret" = "8" ]; then _ret=0 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." fi - if [ "$ret" != "0" ] ; then - _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" + if [ "$ret" != "0" ]; then + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" fi else ret=$? @@ -1203,7 +1192,7 @@ _head_n() { } _tail_n() { - if ! tail -n $1 2>/dev/null ; then + if ! tail -n $1 2>/dev/null; then #fix for solaris tail -$1 fi @@ -1215,80 +1204,78 @@ _send_signed_request() { payload=$2 needbase64=$3 keyfile=$4 - if [ -z "$keyfile" ] ; then + if [ -z "$keyfile" ]; then keyfile="$ACCOUNT_KEY_PATH" fi _debug url $url _debug payload "$payload" - - if ! _calcjwk "$keyfile" ; then + + if ! _calcjwk "$keyfile"; then return 1 fi payload64=$(printf "%s" "$payload" | _base64 | _urlencode) _debug3 payload64 $payload64 - - if [ -z "$_CACHED_NONCE" ] ; then + + if [ -z "$_CACHED_NONCE" ]; then _debug2 "Get nonce." nonceurl="$API/directory" _headers="$(_get $nonceurl "onlyheader")" - - if [ "$?" != "0" ] ; then + + if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." return 1 fi - + _debug2 _headers "$_headers" - - _CACHED_NONCE="$( echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + + _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" _debug2 _CACHED_NONCE "$_CACHED_NONCE" else _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" fi nonce="$_CACHED_NONCE" _debug2 nonce "$nonce" - + protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" - + protected64="$(printf "$protected" | _base64 | _urlencode)" _debug3 protected64 "$protected64" - if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")" ; then + if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then _err "Sign request failed." return 1 fi _debug3 _sig_t "$_sig_t" - + sig="$(printf "%s" "$_sig_t" | _urlencode)" _debug3 sig "$sig" - + body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" _debug3 body "$body" - response="$(_post "$body" $url "$needbase64")" _CACHED_NONCE="" - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Can not post to $url" return 1 fi _debug2 original "$response" - - response="$( echo "$response" | _normalizeJson )" + + response="$(echo "$response" | _normalizeJson)" responseHeaders="$(cat "$HTTP_HEADER")" - + _debug2 responseHeaders "$responseHeaders" - _debug2 response "$response" - code="$(grep "^HTTP" $HTTP_HEADER | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n" )" + _debug2 response "$response" + code="$(grep "^HTTP" $HTTP_HEADER | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" _debug code $code - + _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" } - #setopt "file" "opt" "=" "value" [";"] _setopt() { __conf="$1" @@ -1296,44 +1283,43 @@ _setopt() { __sep="$3" __val="$4" __end="$5" - if [ -z "$__opt" ] ; then - _usage usage: _setopt '"file" "opt" "=" "value" [";"]' + if [ -z "$__opt" ]; then + _usage usage: _setopt '"file" "opt" "=" "value" [";"]' return fi - if [ ! -f "$__conf" ] ; then + if [ ! -f "$__conf" ]; then touch "$__conf" fi - if grep -n "^$__opt$__sep" "$__conf" > /dev/null ; then + if grep -n "^$__opt$__sep" "$__conf" >/dev/null; then _debug3 OK - if _contains "$__val" "&" ; then + if _contains "$__val" "&"; then __val="$(echo $__val | sed 's/&/\\&/g')" fi text="$(cat $__conf)" - echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" - elif grep -n "^#$__opt$__sep" "$__conf" > /dev/null ; then - if _contains "$__val" "&" ; then + elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then + if _contains "$__val" "&"; then __val="$(echo $__val | sed 's/&/\\&/g')" fi text="$(cat $__conf)" - echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf" + echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" else _debug3 APP - echo "$__opt$__sep$__val$__end" >> "$__conf" + echo "$__opt$__sep$__val$__end" >>"$__conf" fi _debug2 "$(grep -n "^$__opt$__sep" $__conf)" } - #_save_conf file key value #save to conf _save_conf() { _s_c_f="$1" _sdkey="$2" _sdvalue="$3" - if [ "$_s_c_f" ] ; then + if [ "$_s_c_f" ]; then _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'" else _err "config file is empty, can not save $_sdkey=$_sdvalue" @@ -1344,8 +1330,8 @@ _save_conf() { _clear_conf() { _c_c_f="$1" _sdkey="$2" - if [ "$_c_c_f" ] ; then - _sed_i "s/^$_sdkey.*$//" "$_c_c_f" + if [ "$_c_c_f" ]; then + _sed_i "s/^$_sdkey.*$//" "$_c_c_f" else _err "config file is empty, can not clear" fi @@ -1355,17 +1341,16 @@ _clear_conf() { _read_conf() { _r_c_f="$1" _sdkey="$2" - if [ -f "$_r_c_f" ] ; then - ( - eval $(grep "^$_sdkey *=" "$_r_c_f") - eval "printf \"%s\" \"\$$_sdkey\"" - ) + if [ -f "$_r_c_f" ]; then + ( + eval $(grep "^$_sdkey *=" "$_r_c_f") + eval "printf \"%s\" \"\$$_sdkey\"" + ) else _debug "config file is empty, can not read $_sdkey" fi } - #_savedomainconf key value #save to domain.conf _savedomainconf() { @@ -1415,84 +1400,83 @@ _startserver() { _debug "startserver: $$" nchelp="$(nc -h 2>&1)" - + _debug Le_HTTPPort "$Le_HTTPPort" _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" _NC="nc" - - if [ "$Le_Listen_V4" ] ; then + + if [ "$Le_Listen_V4" ]; then _NC="$_NC -4" - elif [ "$Le_Listen_V6" ] ; then + elif [ "$Le_Listen_V6" ]; then _NC="$_NC -6" fi - - if echo "$nchelp" | grep "\-q[ ,]" >/dev/null ; then + + if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then _NC="$_NC -q 1 -l $ncaddr" else - if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then + if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null; then _NC="$_NC -c -l $ncaddr" - elif echo "$nchelp" | grep "\-N" |grep "Shutdown the network socket after EOF on stdin" >/dev/null ; then + elif echo "$nchelp" | grep "\-N" | grep "Shutdown the network socket after EOF on stdin" >/dev/null; then _NC="$_NC -N -l $ncaddr" else _NC="$_NC -l $ncaddr" fi fi - _debug "_NC" "$_NC" #for centos ncat - if _contains "$nchelp" "nmap.org" ; then + if _contains "$nchelp" "nmap.org"; then _debug "Using ncat: nmap.org" - if [ "$DEBUG" ] ; then - if printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; then + if [ "$DEBUG" ]; then + if printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort; then return fi - else - if printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1; then + else + if printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort >/dev/null 2>&1; then return fi fi _err "ncat listen error." fi - -# while true ; do - if [ "$DEBUG" ] ; then - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ; - fi - else - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1 - fi + + # while true ; do + if [ "$DEBUG" ]; then + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort fi - if [ "$?" != "0" ] ; then - _err "nc listen error." - exit 1 + else + if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort >/dev/null 2>&1; then + printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort >/dev/null 2>&1 fi -# done + fi + if [ "$?" != "0" ]; then + _err "nc listen error." + exit 1 + fi + # done } -_stopserver(){ +_stopserver() { pid="$1" _debug "pid" "$pid" - if [ -z "$pid" ] ; then + if [ -z "$pid" ]; then return fi _debug2 "Le_HTTPPort" "$Le_HTTPPort" - if [ "$Le_HTTPPort" ] ; then - if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ] ; then + if [ "$Le_HTTPPort" ]; then + if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then _get "http://localhost:$Le_HTTPPort" "" 1 else _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1 fi fi - + _debug2 "Le_TLSPort" "$Le_TLSPort" - if [ "$Le_TLSPort" ] ; then - if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ] ; then + if [ "$Le_TLSPort" ]; then + if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then _get "https://localhost:$Le_TLSPort" "" 1 _get "https://localhost:$Le_TLSPort" "" 1 else @@ -1505,10 +1489,9 @@ _stopserver(){ # sleep sec _sleep() { _sleep_sec="$1" - if [ "$__INTERACTIVE" ] ; then + if [ "$__INTERACTIVE" ]; then _sleep_c="$_sleep_sec" - while [ "$_sleep_c" -ge "0" ] ; - do + while [ "$_sleep_c" -ge "0" ]; do printf "\r \r" __green "$_sleep_c" _sleep_c="$(_math $_sleep_c - 1)" @@ -1528,35 +1511,35 @@ _starttlsserver() { port="$3" content="$4" opaddr="$5" - + _debug san_a "$san_a" _debug san_b "$san_b" _debug port "$port" - + #create key TLS_KEY - if ! _createkey "2048" "$TLS_KEY" ; then + if ! _createkey "2048" "$TLS_KEY"; then _err "Create tls validation key error." return 1 fi - + #create csr alt="$san_a" - if [ "$san_b" ] ; then + 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"; then _err "Create tls validation csr error." return 1 fi - + #self signed - if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT" ; then + if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT"; then _err "Create tls validation cert error." return 1 fi - + __S_OPENSSL="openssl s_server -cert $TLS_CERT -key $TLS_KEY " - if [ "$opaddr" ] ; then + if [ "$opaddr" ]; then __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" else __S_OPENSSL="$__S_OPENSSL -accept $port" @@ -1564,18 +1547,18 @@ _starttlsserver() { _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" - if [ "$Le_Listen_V4" ] ; then + if [ "$Le_Listen_V4" ]; then __S_OPENSSL="$__S_OPENSSL -4" - elif [ "$Le_Listen_V6" ] ; then + elif [ "$Le_Listen_V6" ]; then __S_OPENSSL="$__S_OPENSSL -6" fi - + #start openssl _debug "$__S_OPENSSL" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | $__S_OPENSSL -tlsextdebug ) & + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | $__S_OPENSSL -tlsextdebug) & else - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | $__S_OPENSSL >/dev/null 2>&1) & + (printf "HTTP/1.1 200 OK\r\n\r\n$content" | $__S_OPENSSL >/dev/null 2>&1) & fi serverproc="$!" @@ -1587,24 +1570,24 @@ _starttlsserver() { _readlink() { _rf="$1" if ! readlink -f "$_rf" 2>/dev/null; then - if _startswith "$_rf" "\./$PROJECT_ENTRY" ; then + if _startswith "$_rf" "\./$PROJECT_ENTRY"; then printf -- "%s" "$(pwd)/$PROJECT_ENTRY" return 0 fi - readlink "$_rf" + readlink "$_rf" fi } __initHome() { - if [ -z "$_SCRIPT_HOME" ] ; then - if _exists readlink && _exists dirname ; then + if [ -z "$_SCRIPT_HOME" ]; then + if _exists readlink && _exists dirname; then _debug "Lets find script dir." _debug "_SCRIPT_" "$_SCRIPT_" _script="$(_readlink "$_SCRIPT_")" _debug "_script" "$_script" _script_home="$(dirname "$_script")" _debug "_script_home" "$_script_home" - if [ -d "$_script_home" ] ; then + if [ -d "$_script_home" ]; then _SCRIPT_HOME="$_script_home" else _err "It seems the script home is not correct:$_script_home" @@ -1612,17 +1595,16 @@ __initHome() { fi fi - - if [ -z "$LE_WORKING_DIR" ] ; then - if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ] ; then + if [ -z "$LE_WORKING_DIR" ]; then + if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" else LE_WORKING_DIR="$_SCRIPT_HOME" fi fi - - if [ -z "$LE_WORKING_DIR" ] ; then + + if [ -z "$LE_WORKING_DIR" ]; then _debug "Using default home:$DEFAULT_INSTALL_HOME" LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" fi @@ -1630,21 +1612,21 @@ __initHome() { _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" - if [ -z "$ACCOUNT_CONF_PATH" ] ; then - if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ] ; then + if [ -z "$ACCOUNT_CONF_PATH" ]; then + if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then . "$_DEFAULT_ACCOUNT_CONF_PATH" fi fi - - if [ -z "$ACCOUNT_CONF_PATH" ] ; then + + if [ -z "$ACCOUNT_CONF_PATH" ]; then ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi - + DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log" - + DEFAULT_CA_HOME="$LE_WORKING_DIR/ca" - - if [ -z "$LE_TEMP_DIR" ] ; then + + if [ -z "$LE_TEMP_DIR" ]; then LE_TEMP_DIR="$LE_WORKING_DIR/tmp" fi } @@ -1654,161 +1636,160 @@ _initpath() { __initHome - if [ -f "$ACCOUNT_CONF_PATH" ] ; then + if [ -f "$ACCOUNT_CONF_PATH" ]; then . "$ACCOUNT_CONF_PATH" fi - if [ "$IN_CRON" ] ; then - if [ ! "$_USER_PATH_EXPORTED" ] ; then + if [ "$IN_CRON" ]; then + if [ ! "$_USER_PATH_EXPORTED" ]; then _USER_PATH_EXPORTED=1 export PATH="$USER_PATH:$PATH" fi fi - - if [ -z "$CA_HOME" ] ; then + + if [ -z "$CA_HOME" ]; then CA_HOME="$DEFAULT_CA_HOME" fi - if [ -z "$API" ] ; then - if [ -z "$STAGE" ] ; then + if [ -z "$API" ]; then + if [ -z "$STAGE" ]; then API="$DEFAULT_CA" else API="$STAGE_CA" _info "Using stage api:$API" - fi + fi fi - + _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')" CA_DIR="$CA_HOME/$_API_HOST" - + _DEFAULT_CA_CONF="$CA_DIR/ca.conf" - - if [ -z "$CA_CONF" ] ; then + + if [ -z "$CA_CONF" ]; then CA_CONF="$_DEFAULT_CA_CONF" fi - - if [ -f "$CA_CONF" ] ; then + + if [ -f "$CA_CONF" ]; then . "$CA_CONF" fi - if [ -z "$ACME_DIR" ] ; then + if [ -z "$ACME_DIR" ]; then ACME_DIR="/home/.acme" fi - - if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then + + if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR" fi - - if [ -z "$USER_AGENT" ] ; then + + if [ -z "$USER_AGENT" ]; then USER_AGENT="$DEFAULT_USER_AGENT" fi - - if [ -z "$HTTP_HEADER" ] ; then + + if [ -z "$HTTP_HEADER" ]; then HTTP_HEADER="$LE_WORKING_DIR/http.header" fi _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" _OLD_ACCOUNT_JSON="$LE_WORKING_DIR/account.json" - + _DEFAULT_ACCOUNT_KEY_PATH="$CA_DIR/account.key" _DEFAULT_ACCOUNT_JSON_PATH="$CA_DIR/account.json" - if [ -z "$ACCOUNT_KEY_PATH" ] ; then + if [ -z "$ACCOUNT_KEY_PATH" ]; then ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" fi - - if [ -z "$ACCOUNT_JSON_PATH" ] ; then + + if [ -z "$ACCOUNT_JSON_PATH" ]; then ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" fi - - + _DEFAULT_CERT_HOME="$LE_WORKING_DIR" - if [ -z "$CERT_HOME" ] ; then + if [ -z "$CERT_HOME" ]; then CERT_HOME="$_DEFAULT_CERT_HOME" fi - if [ -z "$1" ] ; then + if [ -z "$1" ]; then return 0 fi - + mkdir -p "$CA_DIR" - + domain="$1" _ilength="$2" - if [ -z "$DOMAIN_PATH" ] ; then + if [ -z "$DOMAIN_PATH" ]; then domainhome="$CERT_HOME/$domain" domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" - + DOMAIN_PATH="$domainhome" - - if _isEccKey "$_ilength" ; then + + if _isEccKey "$_ilength"; then DOMAIN_PATH="$domainhomeecc" else - if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ] ; then + if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then _info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert." fi fi _debug DOMAIN_PATH "$DOMAIN_PATH" fi - - if [ ! -d "$DOMAIN_PATH" ] ; then - if ! mkdir -p "$DOMAIN_PATH" ; then + + if [ ! -d "$DOMAIN_PATH" ]; then + if ! mkdir -p "$DOMAIN_PATH"; then _err "Can not create domain path: $DOMAIN_PATH" return 1 fi fi - - if [ -z "$DOMAIN_CONF" ] ; then + + if [ -z "$DOMAIN_CONF" ]; then DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" fi - - if [ -z "$DOMAIN_SSL_CONF" ] ; then + + if [ -z "$DOMAIN_SSL_CONF" ]; then DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf" fi - - if [ -z "$CSR_PATH" ] ; then + + if [ -z "$CSR_PATH" ]; then CSR_PATH="$DOMAIN_PATH/$domain.csr" fi - if [ -z "$CERT_KEY_PATH" ] ; then + if [ -z "$CERT_KEY_PATH" ]; then CERT_KEY_PATH="$DOMAIN_PATH/$domain.key" fi - if [ -z "$CERT_PATH" ] ; then + if [ -z "$CERT_PATH" ]; then CERT_PATH="$DOMAIN_PATH/$domain.cer" fi - if [ -z "$CA_CERT_PATH" ] ; then + if [ -z "$CA_CERT_PATH" ]; then CA_CERT_PATH="$DOMAIN_PATH/ca.cer" fi - if [ -z "$CERT_FULLCHAIN_PATH" ] ; then + if [ -z "$CERT_FULLCHAIN_PATH" ]; then CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer" fi - if [ -z "$CERT_PFX_PATH" ] ; then + if [ -z "$CERT_PFX_PATH" ]; then CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx" fi - - if [ -z "$TLS_CONF" ] ; then + + if [ -z "$TLS_CONF" ]; then TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" fi - if [ -z "$TLS_CERT" ] ; then + if [ -z "$TLS_CERT" ]; then TLS_CERT="$DOMAIN_PATH/tls.valdation.cert" fi - if [ -z "$TLS_KEY" ] ; then + if [ -z "$TLS_KEY" ]; then TLS_KEY="$DOMAIN_PATH/tls.valdation.key" fi - if [ -z "$TLS_CSR" ] ; then + if [ -z "$TLS_CSR" ]; then TLS_CSR="$DOMAIN_PATH/tls.valdation.csr" fi - + } _exec() { - if [ -z "$_EXEC_TEMP_ERR" ] ; then + if [ -z "$_EXEC_TEMP_ERR" ]; then _EXEC_TEMP_ERR="$(_mktemp)" fi - if [ "$_EXEC_TEMP_ERR" ] ; then + if [ "$_EXEC_TEMP_ERR" ]; then "$@" 2>"$_EXEC_TEMP_ERR" else - "$@" + "$@" fi } @@ -1818,39 +1799,39 @@ _exec_err() { _apachePath() { _APACHECTL="apachectl" - if ! _exists apachectl ; then - if _exists apache2ctl ; then - _APACHECTL="apache2ctl" + if ! _exists apachectl; then + if _exists apache2ctl; then + _APACHECTL="apache2ctl" else _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'" _err "Please use webroot mode to try again." return 1 fi fi - - if ! _exec $_APACHECTL -V >/dev/null ; then + + if ! _exec $_APACHECTL -V >/dev/null; then _exec_err return 1 fi - - if [ "$APACHE_HTTPD_CONF" ] ; then + + if [ "$APACHE_HTTPD_CONF" ]; then _saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF" httpdconf="$APACHE_HTTPD_CONF" httpdconfname="$(basename $httpdconfname)" else - httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )" + httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"')" _debug httpdconfname "$httpdconfname" - - if [ -z "$httpdconfname" ] ; then + + if [ -z "$httpdconfname" ]; then _err "Can not read apache config file." return 1 fi - - if _startswith "$httpdconfname" '/' ; then + + if _startswith "$httpdconfname" '/'; then httpdconf="$httpdconfname" httpdconfname="$(basename $httpdconfname)" else - httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )" + httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"')" _debug httpdroot "$httpdroot" httpdconf="$httpdroot/$httpdconfname" httpdconfname="$(basename $httpdconfname)" @@ -1858,7 +1839,7 @@ _apachePath() { fi _debug httpdconf "$httpdconf" _debug httpdconfname "$httpdconfname" - if [ ! -f "$httpdconf" ] ; then + if [ ! -f "$httpdconf" ]; then _err "Apache Config file not found" "$httpdconf" return 1 fi @@ -1866,52 +1847,52 @@ _apachePath() { } _restoreApache() { - if [ -z "$usingApache" ] ; then + if [ -z "$usingApache" ]; then return 0 fi _initpath - if ! _apachePath ; then + if ! _apachePath; then return 1 fi - - if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then + + if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]; then _debug "No config file to restore." return 0 fi - - cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" > "$httpdconf" + + cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf" _debug "Restored: $httpdconf." - if ! _exec $_APACHECTL -t ; then + if ! _exec $_APACHECTL -t; then _exec_err _err "Sorry, restore apache config error, please contact me." - return 1; + return 1 fi _debug "Restored successfully." rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" - return 0 + return 0 } _setApache() { _initpath - if ! _apachePath ; then + if ! _apachePath; then return 1 fi #test the conf first _info "Checking if there is an error in the apache config file before starting." - - if ! _exec $_APACHECTL -t >/dev/null ; then + + if ! _exec $_APACHECTL -t >/dev/null; then _exec_err _err "The apache config file has error, please fix it first, then try again." _err "Don't worry, there is nothing changed to your system." - return 1; + return 1 else _info "OK" fi - + #backup the conf _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 "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT" return 1 @@ -1919,22 +1900,22 @@ _setApache() { _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" _info "In case there is an error that can not be restored automatically, you may try restore it yourself." _info "The backup file will be deleted on sucess, just forget it." - + #add alias - - apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2 )" + + apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2)" _debug "apacheVer" "$apacheVer" apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)" apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" - if [ "$apacheVer" ] && [ "$apacheMajer$apacheMinor" -ge "24" ] ; then + if [ "$apacheVer" ] && [ "$apacheMajer$apacheMinor" -ge "24" ]; then echo " Alias /.well-known/acme-challenge $ACME_DIR Require all granted - " >> "$httpdconf" + " >>"$httpdconf" else echo " Alias /.well-known/acme-challenge $ACME_DIR @@ -1943,30 +1924,30 @@ Alias /.well-known/acme-challenge $ACME_DIR Order allow,deny Allow from all - " >> "$httpdconf" + " >>"$httpdconf" fi - _msg="$($_APACHECTL -t 2>&1 )" - if [ "$?" != "0" ] ; then + _msg="$($_APACHECTL -t 2>&1)" + if [ "$?" != "0" ]; then _err "Sorry, apache config error" - if _restoreApache ; then + if _restoreApache; then _err "The apache config file is restored." else _err "Sorry, The apache config file can not be restored, please report bug." fi - return 1; + return 1 fi - - if [ ! -d "$ACME_DIR" ] ; then + + if [ ! -d "$ACME_DIR" ]; then mkdir -p "$ACME_DIR" chmod 755 "$ACME_DIR" fi - - if ! _exec $_APACHECTL graceful ; then - _exec_err + + if ! _exec $_APACHECTL graceful; then + _exec_err _err "$_APACHECTL graceful error, please contact me." _restoreApache - return 1; + return 1 fi usingApache="1" return 0 @@ -1977,7 +1958,7 @@ _clearup() { serverproc="" _restoreApache _clearupdns - if [ -z "$DEBUG" ] ; then + if [ -z "$DEBUG" ]; then rm -f "$TLS_CONF" rm -f "$TLS_CERT" rm -f "$TLS_KEY" @@ -1987,154 +1968,152 @@ _clearup() { _clearupdns() { _debug "_clearupdns" - if [ "$dnsadded" != 1 ] || [ -z "$vlist" ] ; then + if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then _debug "Dns not added, skip." return fi - ventries=$(echo "$vlist" | tr ',' ' ' ) - for ventry in $ventries - do + ventries=$(echo "$vlist" | tr ',' ' ') + for ventry in $ventries; do d=$(echo $ventry | cut -d $sep -f 1) keyauthorization=$(echo $ventry | cut -d $sep -f 2) vtype=$(echo $ventry | cut -d $sep -f 4) _currentRoot=$(echo $ventry | cut -d $sep -f 5) - if [ "$keyauthorization" = "$STATE_VERIFIED" ] ; then + if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." continue fi - if [ "$vtype" != "$VTYPE_DNS" ] ; then + if [ "$vtype" != "$VTYPE_DNS" ]; then _info "Skip $d for $vtype" continue fi - + d_api="$(_findHook $d dnsapi $_currentRoot)" _debug d_api "$d_api" - - if [ -z "$d_api" ] ; then + + if [ -z "$d_api" ]; then _info "Not Found domain api file: $d_api" continue fi - + ( - if ! . $d_api ; then + if ! . $d_api; then _err "Load file $d_api error. Please check your api file and try again." return 1 fi - + rmcommand="${_currentRoot}_rm" - if ! _exists $rmcommand ; then + if ! _exists $rmcommand; then _err "It seems that your api file doesn't define $rmcommand" return 1 fi - + txtdomain="_acme-challenge.$d" - - if ! $rmcommand $txtdomain ; then + + if ! $rmcommand $txtdomain; then _err "Error removing txt for domain:$txtdomain" return 1 fi ) - + done } # webroot removelevel tokenfile _clearupwebbroot() { __webroot="$1" - if [ -z "$__webroot" ] ; then + if [ -z "$__webroot" ]; then _debug "no webroot specified, skip" return 0 fi - + _rmpath="" - if [ "$2" = '1' ] ; then + if [ "$2" = '1' ]; then _rmpath="$__webroot/.well-known" - elif [ "$2" = '2' ] ; then + elif [ "$2" = '2' ]; then _rmpath="$__webroot/.well-known/acme-challenge" - elif [ "$2" = '3' ] ; then + elif [ "$2" = '3' ]; then _rmpath="$__webroot/.well-known/acme-challenge/$3" else _debug "Skip for removelevel:$2" fi - - if [ "$_rmpath" ] ; then - if [ "$DEBUG" ] ; then + + if [ "$_rmpath" ]; then + if [ "$DEBUG" ]; then _debug "Debugging, skip removing: $_rmpath" else rm -rf "$_rmpath" fi fi - + return 0 } _on_before_issue() { _debug _on_before_issue - if _hasfield "$Le_Webroot" "$NO_VALUE" ; then - if ! _exists "nc" ; then + if _hasfield "$Le_Webroot" "$NO_VALUE"; then + if ! _exists "nc"; then _err "Please install netcat(nc) tools first." return 1 fi fi _debug Le_LocalAddress "$Le_LocalAddress" - - alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) + + alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') _index=1 _currentRoot="" _addrIndex=1 - for d in $alldomains - do + for d in $alldomains; do _debug "Check for domain" $d _currentRoot="$(_getfield "$Le_Webroot" $_index)" _debug "_currentRoot" "$_currentRoot" _index=$(_math $_index + 1) _checkport="" - if [ "$_currentRoot" = "$NO_VALUE" ] ; then + if [ "$_currentRoot" = "$NO_VALUE" ]; then _info "Standalone mode." - if [ -z "$Le_HTTPPort" ] ; then + if [ -z "$Le_HTTPPort" ]; then Le_HTTPPort=80 else - _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" + _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" fi _checkport="$Le_HTTPPort" - elif [ "$_currentRoot" = "$W_TLS" ] ; then + elif [ "$_currentRoot" = "$W_TLS" ]; then _info "Standalone tls mode." - if [ -z "$Le_TLSPort" ] ; then + if [ -z "$Le_TLSPort" ]; then Le_TLSPort=443 else - _savedomainconf "Le_TLSPort" "$Le_TLSPort" + _savedomainconf "Le_TLSPort" "$Le_TLSPort" fi _checkport="$Le_TLSPort" fi - - if [ "$_checkport" ] ; then + + if [ "$_checkport" ]; then _debug _checkport "$_checkport" _checkaddr="$(_getfield "$Le_LocalAddress" $_addrIndex)" _debug _checkaddr "$_checkaddr" - + _addrIndex="$(_math $_addrIndex + 1)" - + _netprc="$(_ss "$_checkport" | grep "$_checkport")" netprc="$(echo "$_netprc" | grep "$_checkaddr")" - if [ -z "$netprc" ] ; then + if [ -z "$netprc" ]; then netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")" fi - if [ "$netprc" ] ; then + if [ "$netprc" ]; then _err "$netprc" - _err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)" + _err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)" _err "Please stop it first" return 1 fi fi done - if _hasfield "$Le_Webroot" "apache" ; then - if ! _setApache ; then + if _hasfield "$Le_Webroot" "apache"; then + if ! _setApache; then _err "set up apache error. Report error to me." return 1 fi @@ -2143,11 +2122,11 @@ _on_before_issue() { fi #run pre hook - if [ "$Le_PreHook" ] ; then + if [ "$Le_PreHook" ]; then _info "Run pre hook:'$Le_PreHook'" if ! ( cd "$DOMAIN_PATH" && eval "$Le_PreHook" - ) ; then + ); then _err "Error when run pre hook." return 1 fi @@ -2156,23 +2135,23 @@ _on_before_issue() { _on_issue_err() { _debug _on_issue_err - if [ "$LOG_FILE" ] ; then + if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" else _err "Please use add '--debug' or '--log' to check more details." _err "See: $_DEBUG_WIKI" fi - - if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ] ; then + + if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then _debug "$(_dlg_versions)" fi - + #run the post hook - if [ "$Le_PostHook" ] ; then + if [ "$Le_PostHook" ]; then _info "Run post hook:'$Le_PostHook'" if ! ( cd "$DOMAIN_PATH" && eval "$Le_PostHook" - ) ; then + ); then _err "Error when run post hook." return 1 fi @@ -2182,27 +2161,27 @@ _on_issue_err() { _on_issue_success() { _debug _on_issue_success #run the post hook - if [ "$Le_PostHook" ] ; then + if [ "$Le_PostHook" ]; then _info "Run post hook:'$Le_PostHook'" if ! ( cd "$DOMAIN_PATH" && eval "$Le_PostHook" - ) ; then + ); then _err "Error when run post hook." return 1 fi fi - + #run renew hook - if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ] ; then + if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ]; then _info "Run renew hook:'$Le_RenewHook'" if ! ( cd "$DOMAIN_PATH" && eval "$Le_RenewHook" - ) ; then + ); then _err "Error when run renew hook." return 1 fi - fi - + fi + } updateaccount() { @@ -2220,70 +2199,67 @@ __calcAccountKeyHash() { [ -f "$ACCOUNT_KEY_PATH" ] && cat "$ACCOUNT_KEY_PATH" | _digest sha256 } - #keylength _regAccount() { _initpath _reg_length="$1" - - + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" fi - + if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" fi - - if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then - if ! _create_account_key "$_reg_length" ; then + + if [ ! -f "$ACCOUNT_KEY_PATH" ]; then + if ! _create_account_key "$_reg_length"; then _err "Create account key error." return 1 fi fi - - if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then + + if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi _updateTos="" _reg_res="new-reg" - while true ; - do + while true; do _debug AGREEMENT "$AGREEMENT" - + regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ] ; then + if [ "$ACCOUNT_EMAIL" ]; then regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' fi - if [ -z "$_updateTos" ] ; then + if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "$API/acme/new-reg" "$regjson" ; then + if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then _err "Register account Error: $response" return 1 fi - if [ "$code" = "" ] || [ "$code" = '201' ] ; then - echo "$response" > $ACCOUNT_JSON_PATH + if [ "$code" = "" ] || [ "$code" = '201' ]; then + echo "$response" >$ACCOUNT_JSON_PATH _info "Registered" - elif [ "$code" = '409' ] ; then + elif [ "$code" = '409' ]; then _info "Already registered" else _err "Register account Error: $response" return 1 fi - _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2| tr -d "\r\n")" + _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')" _debug "_tos" "$_tos" - if [ -z "$_tos" ] ; then + if [ -z "$_tos" ]; then _debug "Use default tos: $DEFAULT_AGREEMENT" _tos="$DEFAULT_AGREEMENT" fi @@ -2293,16 +2269,16 @@ _regAccount() { _reg_res="reg" continue fi - + else _debug "Update tos: $_tos" - if ! _send_signed_request "$_accUri" "$regjson" ; then + if ! _send_signed_request "$_accUri" "$regjson"; then _err "Update tos error." return 1 fi - if [ "$code" = '202' ] ; then + if [ "$code" = '202' ]; then _info "Update success." - + CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" _savecaconf CA_KEY_HASH "$CA_KEY_HASH" @@ -2316,28 +2292,27 @@ _regAccount() { } - # domain folder file _findHook() { _hookdomain="$1" _hookcat="$2" _hookname="$3" - - if [ -f "$_SCRIPT_HOME/$_hookdomain/$_hookname" ] ; then + + if [ -f "$_SCRIPT_HOME/$_hookdomain/$_hookname" ]; then d_api="$_SCRIPT_HOME/$_hookdomain/$_hookname" - elif [ -f "$_SCRIPT_HOME/$_hookdomain/$_hookname.sh" ] ; then + elif [ -f "$_SCRIPT_HOME/$_hookdomain/$_hookname.sh" ]; then d_api="$_SCRIPT_HOME/$_hookdomain/$_hookname.sh" - elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ] ; then + elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname" - elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ] ; then + elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" - elif [ -f "$LE_WORKING_DIR/$_hookname" ] ; then + elif [ -f "$LE_WORKING_DIR/$_hookname" ]; then d_api="$LE_WORKING_DIR/$_hookname" - elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ] ; then + elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ]; then d_api="$LE_WORKING_DIR/$_hookname.sh" - elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ] ; then + elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ]; then d_api="$LE_WORKING_DIR/$_hookcat/$_hookname" - elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ] ; then + elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ]; then d_api="$LE_WORKING_DIR/$_hookcat/$_hookname.sh" fi @@ -2348,29 +2323,29 @@ _findHook() { __get_domain_new_authz() { _gdnd="$1" _info "Getting new-authz for domain" "$_gdnd" - + _Max_new_authz_retry_times=5 _authz_i=0 - while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ] ; do + while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do _info "Try new-authz for the $_authz_i time." - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}" ; then + if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then _err "Can not get domain new authz." return 1 fi - if ! _contains "$response" "An error occurred while processing your request" ; then + if ! _contains "$response" "An error occurred while processing your request"; then _info "The new-authz request is ok." break fi _authz_i="$(_math "$_authz_i" + 1)" _info "The server is busy, Sleep $_authz_i to retry." _sleep "$_authz_i" - done; + done - if [ "$_authz_i" = "$_Max_new_authz_retry_times" ] ; then + if [ "$_authz_i" = "$_Max_new_authz_retry_times" ]; then _debug "new-authz retry reach the max $_Max_new_authz_retry_times times." fi - - if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then + + if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then _err "new-authz error: $response" return 1 fi @@ -2379,7 +2354,7 @@ __get_domain_new_authz() { #webroot, domain domainlist keylength issue() { - if [ -z "$2" ] ; then + if [ -z "$2" ]; then _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " return 1 fi @@ -2396,36 +2371,36 @@ issue() { Le_PostHook="${11}" Le_RenewHook="${12}" Le_LocalAddress="${13}" - + #remove these later. - if [ "$Le_Webroot" = "dns-cf" ] ; then + if [ "$Le_Webroot" = "dns-cf" ]; then Le_Webroot="dns_cf" fi - if [ "$Le_Webroot" = "dns-dp" ] ; then + if [ "$Le_Webroot" = "dns-dp" ]; then Le_Webroot="dns_dp" fi - if [ "$Le_Webroot" = "dns-cx" ] ; then + if [ "$Le_Webroot" = "dns-cx" ]; then Le_Webroot="dns_cx" fi _debug "Using api: $API" - - if [ ! "$IS_RENEW" ] ; then + + if [ ! "$IS_RENEW" ]; then _initpath $Le_Domain "$Le_Keylength" mkdir -p "$DOMAIN_PATH" fi - if [ -f "$DOMAIN_CONF" ] ; then + if [ -f "$DOMAIN_CONF" ]; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(_time) -lt $Le_NextRenewTime ] ; then + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(_time) -lt $Le_NextRenewTime ]; then _saved_domain=$(_readdomainconf Le_Domain) _debug _saved_domain "$_saved_domain" _saved_alt=$(_readdomainconf Le_Alt) _debug _saved_alt "$_saved_alt" - if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ] ; then + if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ]; then _info "Domains not changed." _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" - _info "Add '$(__red '--force')' to force to renew." + _info "Add '$(__red '--force')' to force to renew." return $RENEW_SKIP else _info "Domains have changed." @@ -2433,40 +2408,40 @@ issue() { fi fi - _savedomainconf "Le_Domain" "$Le_Domain" - _savedomainconf "Le_Alt" "$Le_Alt" - _savedomainconf "Le_Webroot" "$Le_Webroot" - - _savedomainconf "Le_PreHook" "$Le_PreHook" - _savedomainconf "Le_PostHook" "$Le_PostHook" - _savedomainconf "Le_RenewHook" "$Le_RenewHook" - - if [ "$Le_LocalAddress" ] ; then - _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" + _savedomainconf "Le_Domain" "$Le_Domain" + _savedomainconf "Le_Alt" "$Le_Alt" + _savedomainconf "Le_Webroot" "$Le_Webroot" + + _savedomainconf "Le_PreHook" "$Le_PreHook" + _savedomainconf "Le_PostHook" "$Le_PostHook" + _savedomainconf "Le_RenewHook" "$Le_RenewHook" + + if [ "$Le_LocalAddress" ]; then + _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" else _cleardomainconf "Le_LocalAddress" fi Le_API="$API" _savedomainconf "Le_API" "$Le_API" - - if [ "$Le_Alt" = "$NO_VALUE" ] ; then + + if [ "$Le_Alt" = "$NO_VALUE" ]; then Le_Alt="" fi - - if [ "$Le_Keylength" = "$NO_VALUE" ] ; then + + if [ "$Le_Keylength" = "$NO_VALUE" ]; then Le_Keylength="" fi - - if ! _on_before_issue ; then + + if ! _on_before_issue; then _err "_on_before_issue." return 1 fi _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")" _debug2 _saved_account_key_hash "$_saved_account_key_hash" - - if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ] ; then + + if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then if ! _regAccount "$_accountkeylength"; then _on_issue_err return 1 @@ -2475,13 +2450,13 @@ issue() { _debug "_saved_account_key_hash is not changed, skip register account." fi - if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ] ; then + if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ]; then _info "Signing from existing CSR." else _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" - if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ] ; then - if ! createDomainKey $Le_Domain $Le_Keylength ; then + if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then + if ! createDomainKey $Le_Domain $Le_Keylength; then _err "Create domain key error." _clearup _on_issue_err @@ -2489,7 +2464,7 @@ issue() { fi fi - if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" ; then + if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then _err "Create CSR error." _clearup _on_issue_err @@ -2497,50 +2472,49 @@ issue() { fi fi - _savedomainconf "Le_Keylength" "$Le_Keylength" - + _savedomainconf "Le_Keylength" "$Le_Keylength" + vlist="$Le_Vlist" _info "Getting domain auth token for each domain" sep='#' - if [ -z "$vlist" ] ; then - alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' ) + if [ -z "$vlist" ]; then + alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') _index=1 _currentRoot="" - for d in $alldomains - do + for d in $alldomains; do _info "Getting webroot for domain" $d _w="$(echo $Le_Webroot | cut -d , -f $_index)" _info _w "$_w" - if [ "$_w" ] ; then + if [ "$_w" ]; then _currentRoot="$_w" fi _debug "_currentRoot" "$_currentRoot" _index=$(_math $_index + 1) - + vtype="$VTYPE_HTTP" - if _startswith "$_currentRoot" "dns" ; then + if _startswith "$_currentRoot" "dns"; then vtype="$VTYPE_DNS" fi - - if [ "$_currentRoot" = "$W_TLS" ] ; then + + if [ "$_currentRoot" = "$W_TLS" ]; then vtype="$VTYPE_TLS" fi - - if ! __get_domain_new_authz "$d" ; then + + if ! __get_domain_new_authz "$d"; then _clearup _on_issue_err return 1 fi - - if [ -z "$thumbprint" ] ; then - accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' ) + + if [ -z "$thumbprint" ]; then + accountkey_json=$(printf "%s" "$jwk" | tr -d ' ') thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) fi - - entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" - if [ -z "$entry" ] ; then + if [ -z "$entry" ]; then _err "Error, can not get domain token $d" _clearup _on_issue_err @@ -2548,44 +2522,41 @@ issue() { fi token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token $token - - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" + + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" _debug uri $uri keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" - - if printf "$response" | grep '"status":"valid"' >/dev/null 2>&1 ; then + if printf "$response" | grep '"status":"valid"' >/dev/null 2>&1; then _info "$d is already verified, skip." keyauthorization=$STATE_VERIFIED _debug keyauthorization "$keyauthorization" fi - dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" _debug dvlist "$dvlist" - + vlist="$vlist$dvlist," done #add entry dnsadded="" - ventries=$(echo "$vlist" | tr ',' ' ' ) - for ventry in $ventries - do + ventries=$(echo "$vlist" | tr ',' ' ') + for ventry in $ventries; do d=$(echo $ventry | cut -d $sep -f 1) keyauthorization=$(echo $ventry | cut -d $sep -f 2) vtype=$(echo $ventry | cut -d $sep -f 4) _currentRoot=$(echo $ventry | cut -d $sep -f 5) - if [ "$keyauthorization" = "$STATE_VERIFIED" ] ; then + if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." continue fi - if [ "$vtype" = "$VTYPE_DNS" ] ; then + if [ "$vtype" = "$VTYPE_DNS" ]; then dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" @@ -2595,8 +2566,8 @@ issue() { d_api="$(_findHook $d dnsapi $_currentRoot)" _debug d_api "$d_api" - - if [ "$d_api" ] ; then + + if [ "$d_api" ]; then _info "Found domain api file: $d_api" else _err "Add the following TXT record:" @@ -2606,26 +2577,26 @@ issue() { _err "so the resulting subdomain will be: $txtdomain" continue fi - + ( - if ! . $d_api ; then + if ! . $d_api; then _err "Load file $d_api error. Please check your api file and try again." return 1 fi - + addcommand="${_currentRoot}_add" - if ! _exists $addcommand ; then + if ! _exists $addcommand; then _err "It seems that your api file is not correct, it must have a function named: $addcommand" return 1 fi - - if ! $addcommand $txtdomain $txt ; then + + if ! $addcommand $txtdomain $txt; then _err "Error add txt for domain:$txtdomain" return 1 fi ) - - if [ "$?" != "0" ] ; then + + if [ "$?" != "0" ]; then _clearup _on_issue_err return 1 @@ -2634,41 +2605,40 @@ issue() { fi done - if [ "$dnsadded" = '0' ] ; then - _savedomainconf "Le_Vlist" "$vlist" + if [ "$dnsadded" = '0' ]; then + _savedomainconf "Le_Vlist" "$vlist" _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup _on_issue_err return 1 fi - + fi - - if [ "$dnsadded" = '1' ] ; then - if [ -z "$Le_DNSSleep" ] ; then + + if [ "$dnsadded" = '1' ]; then + if [ -z "$Le_DNSSleep" ]; then Le_DNSSleep=$DEFAULT_DNS_SLEEP else - _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" + _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" fi _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" _sleep $Le_DNSSleep fi - + _debug "ok, let's start to verify" _ncIndex=1 - ventries=$(echo "$vlist" | tr ',' ' ' ) - for ventry in $ventries - do + ventries=$(echo "$vlist" | tr ',' ' ') + for ventry in $ventries; do d=$(echo $ventry | cut -d $sep -f 1) keyauthorization=$(echo $ventry | cut -d $sep -f 2) uri=$(echo $ventry | cut -d $sep -f 3) vtype=$(echo $ventry | cut -d $sep -f 4) _currentRoot=$(echo $ventry | cut -d $sep -f 5) - if [ "$keyauthorization" = "$STATE_VERIFIED" ] ; then + if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." continue fi @@ -2682,14 +2652,13 @@ issue() { _debug "_currentRoot" "$_currentRoot" - - if [ "$vtype" = "$VTYPE_HTTP" ] ; then - if [ "$_currentRoot" = "$NO_VALUE" ] ; then + if [ "$vtype" = "$VTYPE_HTTP" ]; then + if [ "$_currentRoot" = "$NO_VALUE" ]; then _info "Standalone mode server" - _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex" )" + _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" _ncIndex="$(_math $_ncIndex + 1)" _startserver "$keyauthorization" "$_ncaddr" & - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _clearup _on_issue_err return 1 @@ -2699,13 +2668,13 @@ issue() { _debug serverproc $serverproc else - if [ "$_currentRoot" = "apache" ] ; then + if [ "$_currentRoot" = "apache" ]; then wellknown_path="$ACME_DIR" else wellknown_path="$_currentRoot/.well-known/acme-challenge" - if [ ! -d "$_currentRoot/.well-known" ] ; then + if [ ! -d "$_currentRoot/.well-known" ]; then removelevel='1' - elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ] ; then + elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ]; then removelevel='2' else removelevel='3' @@ -2718,7 +2687,7 @@ issue() { mkdir -p "$wellknown_path" - if ! printf "%s" "$keyauthorization" > "$wellknown_path/$token" ; then + if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then _err "$d:Can not write token to file : $wellknown_path/$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup @@ -2726,18 +2695,18 @@ issue() { return 1 fi - if [ ! "$usingApache" ] ; then - if webroot_owner=$(_stat $_currentRoot) ; then + if [ ! "$usingApache" ]; then + if webroot_owner=$(_stat $_currentRoot); then _debug "Changing owner/group of .well-known to $webroot_owner" chown -R $webroot_owner "$_currentRoot/.well-known" else - _debug "not chaning owner/group of webroot"; + _debug "not chaning owner/group of webroot" fi fi - + fi - - elif [ "$vtype" = "$VTYPE_TLS" ] ; then + + elif [ "$vtype" = "$VTYPE_TLS" ]; then #create A #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )" #_debug2 _hash_A "$_hash_A" @@ -2747,21 +2716,21 @@ issue() { #_debug2 _y "$_y" #_SAN_A="$_x.$_y.token.acme.invalid" #_debug2 _SAN_A "$_SAN_A" - + #create B - _hash_B="$(printf "%s" $keyauthorization | _digest "sha256" "hex" )" + _hash_B="$(printf "%s" $keyauthorization | _digest "sha256" "hex")" _debug2 _hash_B "$_hash_B" _x="$(echo $_hash_B | cut -c 1-32)" _debug2 _x "$_x" _y="$(echo $_hash_B | cut -c 33-64)" _debug2 _y "$_y" - + #_SAN_B="$_x.$_y.ka.acme.invalid" - + _SAN_B="$_x.$_y.acme.invalid" _debug2 _SAN_B "$_SAN_B" - - _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex" )" + + _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" _ncIndex="$(_math $_ncIndex + 1)" if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then _err "Start tls server error." @@ -2771,43 +2740,43 @@ issue() { return 1 fi fi - - if ! _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" ; then + + if ! _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup _on_issue_err return 1 fi - - if [ ! -z "$code" ] && [ ! "$code" = '202' ] ; then + + if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then _err "$d:Challenge error: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup _on_issue_err return 1 fi - + waittimes=0 - if [ -z "$MAX_RETRY_TIMES" ] ; then + if [ -z "$MAX_RETRY_TIMES" ]; then MAX_RETRY_TIMES=30 fi - - while true ; do + + while true; do waittimes=$(_math $waittimes + 1) - if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ] ; then + if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then _err "$d:Timeout" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup _on_issue_err return 1 fi - + _debug "sleep 2 secs to verify" sleep 2 _debug "checking" response="$(_get $uri)" - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup @@ -2815,171 +2784,168 @@ issue() { return 1 fi _debug2 original "$response" - - response="$(echo "$response" | _normalizeJson )" + + response="$(echo "$response" | _normalizeJson)" _debug2 response "$response" - - status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') - if [ "$status" = "valid" ] ; then + + status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') + if [ "$status" = "valid" ]; then _info "Success" _stopserver $serverproc serverproc="" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - break; + break fi - - if [ "$status" = "invalid" ] ; then - error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*')" - _debug2 error "$error" - errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)" - _debug2 errordetail "$errordetail" - if [ "$errordetail" ] ; then - _err "$d:Verify error:$errordetail" - else - _err "$d:Verify error:$error" - fi - if [ "$DEBUG" ] ; then - if [ "$vtype" = "$VTYPE_HTTP" ] ; then - _debug "Debug: get token url." - _get "http://$d/.well-known/acme-challenge/$token" "" 1 - fi - fi + + if [ "$status" = "invalid" ]; then + error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*')" + _debug2 error "$error" + errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)" + _debug2 errordetail "$errordetail" + if [ "$errordetail" ]; then + _err "$d:Verify error:$errordetail" + else + _err "$d:Verify error:$error" + fi + if [ "$DEBUG" ]; then + if [ "$vtype" = "$VTYPE_HTTP" ]; then + _debug "Debug: get token url." + _get "http://$d/.well-known/acme-challenge/$token" "" 1 + fi + fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup _on_issue_err - return 1; + return 1 fi - - if [ "$status" = "pending" ] ; then + + if [ "$status" = "pending" ]; then _info "Pending" else - _err "$d:Verify error:$response" + _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup _on_issue_err return 1 fi - + done - + done _clearup _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)" - - if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" ; then + + if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err return 1 fi - + _rcert="$response" Le_LinkCert="$(grep -i '^Location.*$' $HTTP_HEADER | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" - _savedomainconf "Le_LinkCert" "$Le_LinkCert" + _savedomainconf "Le_LinkCert" "$Le_LinkCert" + + if [ "$Le_LinkCert" ]; then + echo "$BEGIN_CERT" >"$CERT_PATH" - if [ "$Le_LinkCert" ] ; then - echo "$BEGIN_CERT" > "$CERT_PATH" - #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then # _debug "Get cert failed. Let's try last response." # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" #fi - - if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" ; then + + if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then _debug "Try cert link." - _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" + _get "$Le_LinkCert" | _base64 "multiline" >>"$CERT_PATH" fi - echo "$END_CERT" >> "$CERT_PATH" + echo "$END_CERT" >>"$CERT_PATH" _info "$(__green "Cert success.")" cat "$CERT_PATH" - - _info "Your cert is in $( __green " $CERT_PATH ")" - if [ -f "$CERT_KEY_PATH" ] ; then - _info "Your cert key is in $( __green " $CERT_KEY_PATH ")" + _info "Your cert is in $(__green " $CERT_PATH ")" + + if [ -f "$CERT_KEY_PATH" ]; then + _info "Your cert key is in $(__green " $CERT_KEY_PATH ")" fi cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" - if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ] ; then + if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then USER_PATH="$PATH" _saveaccountconf "USER_PATH" "$USER_PATH" fi fi - - if [ -z "$Le_LinkCert" ] ; then - response="$(echo $response | _dbase64 "multiline" | _normalizeJson )" - _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" + if [ -z "$Le_LinkCert" ]; then + response="$(echo $response | _dbase64 "multiline" | _normalizeJson)" + _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" _on_issue_err return 1 fi - - _cleardomainconf "Le_Vlist" - - Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | _head_n 1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' ) - if ! _contains "$Le_LinkIssuer" ":" ; then + + _cleardomainconf "Le_Vlist" + + Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') + if ! _contains "$Le_LinkIssuer" ":"; then Le_LinkIssuer="$API$Le_LinkIssuer" fi - - _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" - - if [ "$Le_LinkIssuer" ] ; then - echo "$BEGIN_CERT" > "$CA_CERT_PATH" - _get "$Le_LinkIssuer" | _base64 "multiline" >> "$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 ")" + + _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" + + if [ "$Le_LinkIssuer" ]; then + echo "$BEGIN_CERT" >"$CA_CERT_PATH" + _get "$Le_LinkIssuer" | _base64 "multiline" >>"$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 ")" fi - + Le_CertCreateTime=$(_time) - _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" - - Le_CertCreateTimeStr=$(date -u ) - _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" - - if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ] ; then + _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" + + Le_CertCreateTimeStr=$(date -u) + _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" + + if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then Le_RenewalDays=$MAX_RENEW else - _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" + _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" fi - - if [ "$CA_BUNDLE" ] ; then + + if [ "$CA_BUNDLE" ]; then _saveaccountconf CA_BUNDLE "$CA_BUNDLE" else _clearaccountconf "CA_BUNDLE" fi - if [ "$HTTPS_INSECURE" ] ; then + if [ "$HTTPS_INSECURE" ]; then _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" else - _clearaccountconf "HTTPS_INSECURE" + _clearaccountconf "HTTPS_INSECURE" fi - if [ "$Le_Listen_V4" ] ; then - _savedomainconf "Le_Listen_V4" "$Le_Listen_V4" + if [ "$Le_Listen_V4" ]; then + _savedomainconf "Le_Listen_V4" "$Le_Listen_V4" _cleardomainconf Le_Listen_V6 - elif [ "$Le_Listen_V6" ] ; then - _savedomainconf "Le_Listen_V6" "$Le_Listen_V6" + elif [ "$Le_Listen_V6" ]; then + _savedomainconf "Le_Listen_V6" "$Le_Listen_V6" _cleardomainconf Le_Listen_V4 fi - + Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) - - - Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime ) - _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" - + + Le_NextRenewTimeStr=$(_time2str $Le_NextRenewTime) + _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" + Le_NextRenewTime=$(_math $Le_NextRenewTime - 86400) - _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" + _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - _on_issue_success - if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ] ; then + if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ]; then _installcert fi @@ -2988,7 +2954,7 @@ issue() { #domain [isEcc] renew() { Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then + if [ -z "$Le_Domain" ]; then _usage "Usage: $PROJECT_ENTRY --renew -d domain.com [--ecc]" return 1 fi @@ -2998,39 +2964,39 @@ renew() { _initpath $Le_Domain "$_isEcc" _info "$(__green "Renew: '$Le_Domain'")" - if [ ! -f "$DOMAIN_CONF" ] ; then + if [ ! -f "$DOMAIN_CONF" ]; then _info "'$Le_Domain' is not a issued domain, skip." - return 0; + return 0 fi - - if [ "$Le_RenewalDays" ] ; then + + if [ "$Le_RenewalDays" ]; then _savedomainconf Le_RenewalDays "$Le_RenewalDays" fi . "$DOMAIN_CONF" - - if [ "$Le_API" ] ; then + + if [ "$Le_API" ]; then API="$Le_API" fi - - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ] ; then + + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" _info "Add '$(__red '--force')' to force to renew." return $RENEW_SKIP fi - + IS_RENEW="1" issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" res=$? - if [ "$res" != "0" ] ; then + if [ "$res" != "0" ]; then return $res fi - - if [ "$Le_DeployHook" ] ; then + + if [ "$Le_DeployHook" ]; then deploy $Le_Domain "$Le_DeployHook" "$Le_Keylength" res=$? fi - + IS_RENEW="" return $res @@ -3043,10 +3009,10 @@ renewAll() { _debug "_stopRenewOnError" "$_stopRenewOnError" _ret="0" - for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do + for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$); do d=$(echo $d | cut -d '/' -f 1) ( - if _endswith $d "$ECC_SUFFIX" ; then + if _endswith $d "$ECC_SUFFIX"; then _isEcc=$(echo $d | cut -d "$ECC_SEP" -f 2) d=$(echo $d | cut -d "$ECC_SEP" -f 1) fi @@ -3054,10 +3020,10 @@ renewAll() { ) rc="$?" _debug "Return code: $rc" - if [ "$rc" != "0" ] ; then - if [ "$rc" = "$RENEW_SKIP" ] ; then + if [ "$rc" != "0" ]; then + if [ "$rc" = "$RENEW_SKIP" ]; then _info "Skipped $d" - elif [ "$_stopRenewOnError" ] ; then + elif [ "$_stopRenewOnError" ]; then _err "Error renew $d, stop now." return $rc else @@ -3069,9 +3035,8 @@ renewAll() { return $_ret } - #csr webroot -signcsr(){ +signcsr() { _csrfile="$1" _csrW="$2" if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then @@ -3082,50 +3047,49 @@ signcsr(){ _initpath _csrsubj=$(_readSubjectFromCSR "$_csrfile") - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Can not read subject from csr: $_csrfile" return 1 fi _debug _csrsubj "$_csrsubj" _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Can not read domain list from csr: $_csrfile" return 1 fi _debug "_csrdomainlist" "$_csrdomainlist" - - - if [ -z "$_csrsubj" ] ; then + + if [ -z "$_csrsubj" ]; then _csrsubj="$(_getfield "$_csrdomainlist" 1)" _debug _csrsubj "$_csrsubj" _csrdomainlist="$(echo "$_csrdomainlist" | cut -d , -f 2-)" _debug "_csrdomainlist" "$_csrdomainlist" fi - - if [ -z "$_csrsubj" ] ; then + + if [ -z "$_csrsubj" ]; then _err "Can not read subject from csr: $_csrfile" return 1 fi - + _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") - if [ "$?" != "0" ] || [ -z "$_csrkeylength" ] ; then + if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then _err "Can not read key length from csr: $_csrfile" return 1 fi - + _initpath "$_csrsubj" "$_csrkeylength" mkdir -p "$DOMAIN_PATH" - + _info "Copy csr to: $CSR_PATH" cp "$_csrfile" "$CSR_PATH" - + issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" - + } showcsr() { - _csrfile="$1" + _csrfile="$1" _csrd="$2" if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then _usage "Usage: $PROJECT_ENTRY --showcsr --csr mycsr.csr" @@ -3133,17 +3097,17 @@ showcsr() { fi _initpath - + _csrsubj=$(_readSubjectFromCSR "$_csrfile") - if [ "$?" != "0" ] || [ -z "$_csrsubj" ] ; then + if [ "$?" != "0" ] || [ -z "$_csrsubj" ]; then _err "Can not read subject from csr: $_csrfile" return 1 fi - + _info "Subject=$_csrsubj" _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Can not read domain list from csr: $_csrfile" return 1 fi @@ -3151,9 +3115,8 @@ showcsr() { _info "SubjectAltNames=$_csrdomainlist" - _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") - if [ "$?" != "0" ] || [ -z "$_csrkeylength" ] ; then + if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then _err "Can not read key length from csr: $_csrfile" return 1 fi @@ -3163,88 +3126,87 @@ showcsr() { list() { _raw="$1" _initpath - + _sep="|" - if [ "$_raw" ] ; then - printf "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew\n" - for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do + if [ "$_raw" ]; then + printf "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew\n" + for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$); do d=$(echo $d | cut -d '/' -f 1) ( - if _endswith $d "$ECC_SUFFIX" ; then + if _endswith $d "$ECC_SUFFIX"; then _isEcc=$(echo $d | cut -d "$ECC_SEP" -f 2) d=$(echo $d | cut -d "$ECC_SEP" -f 1) fi _initpath $d "$_isEcc" - if [ -f "$DOMAIN_CONF" ] ; then + if [ -f "$DOMAIN_CONF" ]; then . "$DOMAIN_CONF" printf "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr\n" fi ) done else - if _exists column ; then + if _exists column; then list "raw" | column -t -s "$_sep" else list "raw" | tr "$_sep" '\t' fi fi - } deploy() { Le_Domain="$1" Le_DeployHook="$2" _isEcc="$3" - if [ -z "$Le_DeployHook" ] ; then + if [ -z "$Le_DeployHook" ]; then _usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] " return 1 fi _initpath $Le_Domain "$_isEcc" - if [ ! -d "$DOMAIN_PATH" ] ; then + if [ ! -d "$DOMAIN_PATH" ]; then _err "Domain is not valid:'$Le_Domain'" return 1 fi _deployApi="$(_findHook $Le_Domain deploy $Le_DeployHook)" - if [ -z "$_deployApi" ] ; then + if [ -z "$_deployApi" ]; then _err "The deploy hook $Le_DeployHook is not found." return 1 fi _debug _deployApi "$_deployApi" - + _savedomainconf Le_DeployHook "$Le_DeployHook" - + if ! ( - if ! . $_deployApi ; then + if ! . $_deployApi; then _err "Load file $_deployApi error. Please check your api file and try again." return 1 fi - + d_command="${Le_DeployHook}_deploy" - if ! _exists $d_command ; then + if ! _exists $d_command; then _err "It seems that your api file is not correct, it must have a function named: $d_command" return 1 fi - - if ! $d_command $Le_Domain "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH" ; then + + if ! $d_command $Le_Domain "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then _err "Error deploy for domain:$Le_Domain" _on_issue_err return 1 fi - ) ; then + ); then _err "Deploy error." return 1 else _info "$(__green Success)" fi - + } installcert() { Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then + if [ -z "$Le_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]" return 1 fi @@ -3257,7 +3219,7 @@ installcert() { _isEcc="$7" _initpath $Le_Domain "$_isEcc" - if [ ! -d "$DOMAIN_PATH" ] ; then + if [ ! -d "$DOMAIN_PATH" ]; then _err "Domain is not valid:'$Le_Domain'" return 1 fi @@ -3265,90 +3227,87 @@ installcert() { _installcert } - _installcert() { - _savedomainconf "Le_RealCertPath" "$Le_RealCertPath" - _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath" - _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath" - _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd" - _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath" - - if [ "$Le_RealCertPath" = "$NO_VALUE" ] ; then + _savedomainconf "Le_RealCertPath" "$Le_RealCertPath" + _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath" + _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath" + _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd" + _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath" + + if [ "$Le_RealCertPath" = "$NO_VALUE" ]; then Le_RealCertPath="" fi - if [ "$Le_RealKeyPath" = "$NO_VALUE" ] ; then + if [ "$Le_RealKeyPath" = "$NO_VALUE" ]; then Le_RealKeyPath="" fi - if [ "$Le_RealCACertPath" = "$NO_VALUE" ] ; then + if [ "$Le_RealCACertPath" = "$NO_VALUE" ]; then Le_RealCACertPath="" fi - if [ "$Le_ReloadCmd" = "$NO_VALUE" ] ; then + if [ "$Le_ReloadCmd" = "$NO_VALUE" ]; then Le_ReloadCmd="" fi - if [ "$Le_RealFullChainPath" = "$NO_VALUE" ] ; then + if [ "$Le_RealFullChainPath" = "$NO_VALUE" ]; then Le_RealFullChainPath="" fi - + _installed="0" - if [ "$Le_RealCertPath" ] ; then + if [ "$Le_RealCertPath" ]; then _installed=1 _info "Installing cert to:$Le_RealCertPath" - if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ] ; then + if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then cp "$Le_RealCertPath" "$Le_RealCertPath".bak fi - cat "$CERT_PATH" > "$Le_RealCertPath" + cat "$CERT_PATH" >"$Le_RealCertPath" fi - - if [ "$Le_RealCACertPath" ] ; then + + if [ "$Le_RealCACertPath" ]; then _installed=1 _info "Installing CA to:$Le_RealCACertPath" - if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ] ; then - echo "" >> "$Le_RealCACertPath" - cat "$CA_CERT_PATH" >> "$Le_RealCACertPath" + if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ]; then + echo "" >>"$Le_RealCACertPath" + cat "$CA_CERT_PATH" >>"$Le_RealCACertPath" else - if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ] ; then + if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak fi - cat "$CA_CERT_PATH" > "$Le_RealCACertPath" + cat "$CA_CERT_PATH" >"$Le_RealCACertPath" fi fi - - if [ "$Le_RealKeyPath" ] ; then + if [ "$Le_RealKeyPath" ]; then _installed=1 _info "Installing key to:$Le_RealKeyPath" - if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ] ; then + if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak fi - cat "$CERT_KEY_PATH" > "$Le_RealKeyPath" + cat "$CERT_KEY_PATH" >"$Le_RealKeyPath" fi - - if [ "$Le_RealFullChainPath" ] ; then + + if [ "$Le_RealFullChainPath" ]; then _installed=1 _info "Installing full chain to:$Le_RealFullChainPath" - if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ] ; then + if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak fi - cat "$CERT_FULLCHAIN_PATH" > "$Le_RealFullChainPath" - fi + cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath" + fi - if [ "$Le_ReloadCmd" ] ; then + if [ "$Le_ReloadCmd" ]; then _installed=1 _info "Run Le_ReloadCmd: $Le_ReloadCmd" - if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") ; then + if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd"); then _info "$(__green "Reload success")" else _err "Reload error for :$Le_Domain" fi fi - } installcronjob() { _initpath - if ! _exists "crontab" ; then + if ! _exists "crontab"; then _err "crontab doesn't exist, so, we can not install cron jobs." _err "All your certs will not be renewed automatically." _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday." @@ -3356,20 +3315,26 @@ installcronjob() { fi _info "Installing cron job" - if ! crontab -l | grep "$PROJECT_ENTRY --cron" ; then - if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ] ; then + if ! crontab -l | grep "$PROJECT_ENTRY --cron"; then + if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" else _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi - if _exists uname && uname -a | grep solaris >/dev/null ; then - crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab -- + if _exists uname && uname -a | grep solaris >/dev/null; then + crontab -l | { + cat + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + } | crontab -- else - crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab - + crontab -l | { + cat + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + } | crontab - fi fi - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Install cron job failed. You need to manually renew your certs." _err "Or you can add cronjob by yourself:" _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" @@ -3378,78 +3343,78 @@ installcronjob() { } uninstallcronjob() { - if ! _exists "crontab" ; then + if ! _exists "crontab"; then return fi _info "Removing cron job" cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")" - if [ "$cr" ] ; then - if _exists uname && uname -a | grep solaris >/dev/null ; then + if [ "$cr" ]; then + if _exists uname && uname -a | grep solaris >/dev/null; then crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -- else crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab - fi LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" - fi + fi _initpath } revoke() { Le_Domain="$1" - if [ -z "$Le_Domain" ] ; then + if [ -z "$Le_Domain" ]; then _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com" return 1 fi - + _isEcc="$2" _initpath $Le_Domain "$_isEcc" - if [ ! -f "$DOMAIN_CONF" ] ; then + if [ ! -f "$DOMAIN_CONF" ]; then _err "$Le_Domain is not a issued domain, skip." - return 1; + return 1 fi - - if [ ! -f "$CERT_PATH" ] ; then + + if [ ! -f "$CERT_PATH" ]; then _err "Cert for $Le_Domain $CERT_PATH is not found, skip." return 1 fi - - cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}"| tr -d "\r\n" | _urlencode)" - if [ -z "$cert" ] ; then + cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _urlencode)" + + if [ -z "$cert" ]; then _err "Cert for $Le_Domain is empty found, skip." return 1 fi - + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" uri="$API/acme/revoke-cert" - if [ -f "$CERT_KEY_PATH" ] ; then + if [ -f "$CERT_KEY_PATH" ]; then _info "Try domain key first." if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then - if [ -z "$response" ] ; then + if [ -z "$response" ]; then _info "Revoke success." rm -f $CERT_PATH return 0 - else + else _err "Revoke error by domain key." _err "$response" fi fi - else + else _info "Domain key file doesn't exists." fi - + _info "Try account key." - if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH" ; then - if [ -z "$response" ] ; then + if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH"; then + if [ -z "$response" ]; then _info "Revoke success." rm -f $CERT_PATH return 0 - else + else _err "Revoke error." _debug "$response" fi @@ -3457,67 +3422,63 @@ revoke() { return 1 } - #domain vtype _deactivate() { _d_domain="$1" _d_type="$2" _initpath - + _d_i=0 _d_max_retry=9 - while [ "$_d_i" -lt "$_d_max_retry" ] ; - do + while [ "$_d_i" -lt "$_d_max_retry" ]; do _info "Deactivate: $_d_domain" _d_i="$(_math $_d_i + 1)" - - - if ! __get_domain_new_authz "$_d_domain" ; then + + if ! __get_domain_new_authz "$_d_domain"; then _err "Can not get domain new authz token." return 1 fi - + authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "authzUri" "$authzUri" - if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then + if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then _err "new-authz error: $response" return 1 fi - - entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"status":"valid","uri"[^\}]*')" + + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"status":"valid","uri"[^\}]*')" _debug entry "$entry" - - if [ -z "$entry" ] ; then + + if [ -z "$entry" ]; then _info "No more valid entry found." break fi - + _vtype="$(printf "%s\n" "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')" _debug _vtype $_vtype _info "Found $_vtype" - - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )" + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" _debug uri $uri - - if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ] ; then + + if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then _info "Skip $_vtype" continue fi - + _info "Deactivate: $_vtype" - - if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" ; then + + if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}"; then _err "Can not deactivate $_vtype." return 1 fi - + _info "Deactivate: $_vtype success." - + done _debug "$_d_i" - if [ "$_d_i" -lt "$_d_max_retry" ] ; then + if [ "$_d_i" -lt "$_d_max_retry" ]; then _info "Deactivated success!" else _err "Deactivate failed." @@ -3530,16 +3491,15 @@ deactivate() { _d_type="$2" _initpath _debug _d_domain_list "$_d_domain_list" - if [ -z "$(echo $_d_domain_list | cut -d , -f 1 )" ] ; then + if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" return 1 fi - for _d_dm in $(echo "$_d_domain_list" | tr ',' ' ' ) ; - do - if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ] ; then + for _d_dm in $(echo "$_d_domain_list" | tr ',' ' '); do + if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ]; then continue fi - if ! _deactivate "$_d_dm" $_d_type ; then + if ! _deactivate "$_d_dm" $_d_type; then return 1 fi done @@ -3547,7 +3507,7 @@ deactivate() { # Detect profile file if not specified as environment variable _detect_profile() { - if [ -n "$PROFILE" -a -f "$PROFILE" ] ; then + if [ -n "$PROFILE" -a -f "$PROFILE" ]; then echo "$PROFILE" return fi @@ -3555,36 +3515,36 @@ _detect_profile() { DETECTED_PROFILE='' SHELLTYPE="$(basename "/$SHELL")" - if [ "$SHELLTYPE" = "bash" ] ; then - if [ -f "$HOME/.bashrc" ] ; then + if [ "$SHELLTYPE" = "bash" ]; then + if [ -f "$HOME/.bashrc" ]; then DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ] ; then + elif [ -f "$HOME/.bash_profile" ]; then DETECTED_PROFILE="$HOME/.bash_profile" fi - elif [ "$SHELLTYPE" = "zsh" ] ; then + elif [ "$SHELLTYPE" = "zsh" ]; then DETECTED_PROFILE="$HOME/.zshrc" fi - if [ -z "$DETECTED_PROFILE" ] ; then - if [ -f "$HOME/.profile" ] ; then + if [ -z "$DETECTED_PROFILE" ]; then + if [ -f "$HOME/.profile" ]; then DETECTED_PROFILE="$HOME/.profile" - elif [ -f "$HOME/.bashrc" ] ; then + elif [ -f "$HOME/.bashrc" ]; then DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ] ; then + elif [ -f "$HOME/.bash_profile" ]; then DETECTED_PROFILE="$HOME/.bash_profile" - elif [ -f "$HOME/.zshrc" ] ; then + elif [ -f "$HOME/.zshrc" ]; then DETECTED_PROFILE="$HOME/.zshrc" fi fi - if [ ! -z "$DETECTED_PROFILE" ] ; then + if [ ! -z "$DETECTED_PROFILE" ]; then echo "$DETECTED_PROFILE" fi } _initconf() { _initpath - if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then + if [ ! -f "$ACCOUNT_CONF_PATH" ]; then echo "#ACCOUNT_CONF_PATH=xxxx #Account configurations: @@ -3644,75 +3604,75 @@ _initconf() { #PDNS_Token=\"0123456789ABCDEF\" #PDNS_Ttl=60 - " > $ACCOUNT_CONF_PATH + " >$ACCOUNT_CONF_PATH fi } # nocron _precheck() { _nocron="$1" - - if ! _exists "curl" && ! _exists "wget"; then + + if ! _exists "curl" && ! _exists "wget"; then _err "Please install curl or wget first, we need to access http resources." return 1 fi - - if [ -z "$_nocron" ] ; then - if ! _exists "crontab" ; then + + if [ -z "$_nocron" ]; then + if ! _exists "crontab"; then _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." _err "We need to set cron job to renew the certs automatically." _err "Otherwise, your certs will not be able to be renewed automatically." - if [ -z "$FORCE" ] ; then + if [ -z "$FORCE" ]; then _err "Please add '--force' and try install again to go without crontab." _err "./$PROJECT_ENTRY --install --force" return 1 fi fi fi - - if ! _exists "openssl" ; then + + if ! _exists "openssl"; then _err "Please install openssl first." _err "We need openssl to generate keys." return 1 fi - - if ! _exists "nc" ; then + + if ! _exists "nc"; then _err "It is recommended to install nc first, try to install 'nc' or 'netcat'." _err "We use nc for standalone server if you use standalone mode." _err "If you don't use standalone mode, just ignore this warning." fi - + return 0 } _setShebang() { _file="$1" _shebang="$2" - if [ -z "$_shebang" ] ; then + if [ -z "$_shebang" ]; then _usage "Usage: file shebang" return 1 fi cp "$_file" "$_file.tmp" - echo "$_shebang" > "$_file" - sed -n 2,99999p "$_file.tmp" >> "$_file" - rm -f "$_file.tmp" + echo "$_shebang" >"$_file" + sed -n 2,99999p "$_file.tmp" >>"$_file" + rm -f "$_file.tmp" } _installalias() { _initpath _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" - if [ "$_upgrading" ] && [ "$_upgrading" = "1" ] ; then - echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile" - echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile" - echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile" + if [ "$_upgrading" ] && [ "$_upgrading" = "1" ]; then + echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile" + echo "$(cat $_envfile)" | sed "s|^alias le.*$||" >"$_envfile" + echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" >"$_envfile" fi _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" _profile="$(_detect_profile)" - if [ "$_profile" ] ; then + if [ "$_profile" ]; then _debug "Found profile: $_profile" _info "Installing alias to '$_profile'" _setopt "$_profile" ". \"$_envfile\"" @@ -3720,25 +3680,24 @@ _installalias() { else _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" fi - #for csh _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh" _csh_profile="$HOME/.cshrc" - if [ -f "$_csh_profile" ] ; then + if [ -f "$_csh_profile" ]; then _info "Installing alias to '$_csh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" - _setopt "$_csh_profile" "source \"$_cshfile\"" + _setopt "$_csh_profile" "source \"$_cshfile\"" fi - + #for tcsh _tcsh_profile="$HOME/.tcshrc" - if [ -f "$_tcsh_profile" ] ; then + if [ -f "$_tcsh_profile" ]; then _info "Installing alias to '$_tcsh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" - _setopt "$_tcsh_profile" "source \"$_cshfile\"" + _setopt "$_tcsh_profile" "source \"$_cshfile\"" fi } @@ -3746,36 +3705,35 @@ _installalias() { # nocron install() { - if [ -z "$LE_WORKING_DIR" ] ; then + if [ -z "$LE_WORKING_DIR" ]; then LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" fi - + _nocron="$1" - if ! _initpath ; then + if ! _initpath; then _err "Install failed." return 1 fi - if [ "$_nocron" ] ; then + if [ "$_nocron" ]; then _debug "Skip install cron job" fi - - if ! _precheck "$_nocron" ; then + + if ! _precheck "$_nocron"; then _err "Pre-check failed, can not install." return 1 fi - + #convert from le - if [ -d "$HOME/.le" ] ; then - for envfile in "le.env" "le.sh.env" - do - if [ -f "$HOME/.le/$envfile" ] ; then - if grep "le.sh" "$HOME/.le/$envfile" >/dev/null ; then - _upgrading="1" - _info "You are upgrading from le.sh" - _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR" - mv "$HOME/.le" "$LE_WORKING_DIR" - mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env" - break; + if [ -d "$HOME/.le" ]; then + for envfile in "le.env" "le.sh.env"; do + if [ -f "$HOME/.le/$envfile" ]; then + if grep "le.sh" "$HOME/.le/$envfile" >/dev/null; then + _upgrading="1" + _info "You are upgrading from le.sh" + _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR" + mv "$HOME/.le" "$LE_WORKING_DIR" + mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env" + break fi fi done @@ -3783,16 +3741,16 @@ install() { _info "Installing to $LE_WORKING_DIR" - if ! mkdir -p "$LE_WORKING_DIR" ; then + if ! mkdir -p "$LE_WORKING_DIR"; then _err "Can not create working dir: $LE_WORKING_DIR" return 1 fi - + chmod 700 "$LE_WORKING_DIR" cp $PROJECT_ENTRY "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Install failed, can not copy $PROJECT_ENTRY" return 1 fi @@ -3801,43 +3759,42 @@ install() { _installalias - for subf in $_SUB_FOLDERS ; do - if [ -d "$subf" ] ; then + for subf in $_SUB_FOLDERS; do + if [ -d "$subf" ]; then mkdir -p $LE_WORKING_DIR/$subf - cp $subf/* $LE_WORKING_DIR/$subf/ + cp $subf/* $LE_WORKING_DIR/$subf/ fi done - - if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then + if [ ! -f "$ACCOUNT_CONF_PATH" ]; then _initconf fi - if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ] ; then + if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]; then _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" fi - if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ] ; then + if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]; then _saveaccountconf "CERT_HOME" "$CERT_HOME" fi - if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ] ; then + if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]; then _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH" fi - - if [ -z "$_nocron" ] ; then + + if [ -z "$_nocron" ]; then installcronjob fi - if [ -z "$NO_DETECT_SH" ] ; then + if [ -z "$NO_DETECT_SH" ]; then #Modify shebang - if _exists bash ; then + if _exists bash; then _info "Good, bash is found, so change the shebang to use bash as prefered." _shebang='#!/usr/bin/env bash' _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" - for subf in $_SUB_FOLDERS ; do - if [ -d "$LE_WORKING_DIR/$subf" ] ; then - for _apifile in "$LE_WORKING_DIR/$subf/"*.sh ; do + for subf in $_SUB_FOLDERS; do + if [ -d "$LE_WORKING_DIR/$subf" ]; then + for _apifile in "$LE_WORKING_DIR/$subf/"*.sh; do _setShebang "$_apifile" "$_shebang" done fi @@ -3851,13 +3808,13 @@ install() { # nocron uninstall() { _nocron="$1" - if [ -z "$_nocron" ] ; then + if [ -z "$_nocron" ]; then uninstallcronjob fi _initpath _uninstallalias - + rm -f $LE_WORKING_DIR/$PROJECT_ENTRY _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." @@ -3867,24 +3824,24 @@ _uninstallalias() { _initpath _profile="$(_detect_profile)" - if [ "$_profile" ] ; then + if [ "$_profile" ]; then _info "Uninstalling alias from: '$_profile'" text="$(cat $_profile)" - echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" > "$_profile" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" >"$_profile" fi _csh_profile="$HOME/.cshrc" - if [ -f "$_csh_profile" ] ; then + if [ -f "$_csh_profile" ]; then _info "Uninstalling alias from: '$_csh_profile'" text="$(cat $_csh_profile)" - echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_csh_profile" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_csh_profile" fi - + _tcsh_profile="$HOME/.tcshrc" - if [ -f "$_tcsh_profile" ] ; then + if [ -f "$_tcsh_profile" ]; then _info "Uninstalling alias from: '$_csh_profile'" text="$(cat $_tcsh_profile)" - echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_tcsh_profile" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_tcsh_profile" fi } @@ -3892,20 +3849,20 @@ _uninstallalias() { cron() { IN_CRON=1 _initpath - if [ "$AUTO_UPGRADE" = "1" ] ; then + if [ "$AUTO_UPGRADE" = "1" ]; then export LE_WORKING_DIR ( - if ! upgrade ; then - _err "Cron:Upgrade failed!" - return 1 - fi + if ! upgrade; then + _err "Cron:Upgrade failed!" + return 1 + fi ) . $LE_WORKING_DIR/$PROJECT_ENTRY >/dev/null - if [ -t 1 ] ; then + if [ -t 1 ]; then __INTERACTIVE="1" fi - + _info "Auto upgraded to: $VER" fi renewAll @@ -4008,31 +3965,31 @@ Parameters: _installOnline() { _info "Installing from online archive." _nocron="$1" - if [ ! "$BRANCH" ] ; then + if [ ! "$BRANCH" ]; then BRANCH="master" fi target="$PROJECT/archive/$BRANCH.tar.gz" _info "Downloading $target" localname="$BRANCH.tar.gz" - if ! _get "$target" > $localname ; then + if ! _get "$target" >$localname; then _err "Download error." return 1 fi ( - _info "Extracting $localname" - tar xzf $localname - - cd "$PROJECT_NAME-$BRANCH" - chmod +x $PROJECT_ENTRY - if ./$PROJECT_ENTRY install "$_nocron" ; then - _info "Install success!" - fi - - cd .. - - rm -rf "$PROJECT_NAME-$BRANCH" - rm -f "$localname" + _info "Extracting $localname" + tar xzf $localname + + cd "$PROJECT_NAME-$BRANCH" + chmod +x $PROJECT_ENTRY + if ./$PROJECT_ENTRY install "$_nocron"; then + _info "Install success!" + fi + + cd .. + + rm -rf "$PROJECT_NAME-$BRANCH" + rm -f "$localname" ) } @@ -4042,7 +3999,7 @@ upgrade() { export LE_WORKING_DIR cd "$LE_WORKING_DIR" _installOnline "nocron" - ) ; then + ); then _info "Upgrade success!" exit 0 else @@ -4052,24 +4009,24 @@ upgrade() { } _processAccountConf() { - if [ "$_useragent" ] ; then + if [ "$_useragent" ]; then _saveaccountconf "USER_AGENT" "$_useragent" - elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ] ; then + elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ]; then _saveaccountconf "USER_AGENT" "$USER_AGENT" fi - - if [ "$_accountemail" ] ; then + + if [ "$_accountemail" ]; then _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" - elif [ "$ACCOUNT_EMAIL" ] && [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ] ; then + elif [ "$ACCOUNT_EMAIL" ] && [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ]; then _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL" fi - - if [ "$_auto_upgrade" ] ; then + + if [ "$_auto_upgrade" ]; then _saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade" - elif [ "$AUTO_UPGRADE" ] ; then + elif [ "$AUTO_UPGRADE" ]; then _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" fi - + } _process() { @@ -4111,339 +4068,339 @@ _process() { _auto_upgrade="" _listen_v4="" _listen_v6="" - while [ ${#} -gt 0 ] ; do + while [ ${#} -gt 0 ]; do case "${1}" in - - --help|-h) + + --help | -h) showhelp return ;; - --version|-v) + --version | -v) version return ;; - --install) + --install) _CMD="install" ;; - --uninstall) + --uninstall) _CMD="uninstall" ;; - --upgrade) + --upgrade) _CMD="upgrade" ;; - --issue) + --issue) _CMD="issue" ;; - --deploy) + --deploy) _CMD="deploy" ;; - --signcsr) + --signcsr) _CMD="signcsr" ;; - --showcsr) + --showcsr) _CMD="showcsr" ;; - --installcert|-i) + --installcert | -i) _CMD="installcert" ;; - --renew|-r) + --renew | -r) _CMD="renew" ;; - --renewAll|--renewall) + --renewAll | --renewall) _CMD="renewAll" ;; - --revoke) + --revoke) _CMD="revoke" ;; - --list) + --list) _CMD="list" ;; - --installcronjob) + --installcronjob) _CMD="installcronjob" ;; - --uninstallcronjob) + --uninstallcronjob) _CMD="uninstallcronjob" ;; - --cron) + --cron) _CMD="cron" ;; - --toPkcs) + --toPkcs) _CMD="toPkcs" - ;; - --createAccountKey|--createaccountkey|-cak) + ;; + --createAccountKey | --createaccountkey | -cak) _CMD="createAccountKey" ;; - --createDomainKey|--createdomainkey|-cdk) + --createDomainKey | --createdomainkey | -cdk) _CMD="createDomainKey" ;; - --createCSR|--createcsr|-ccr) + --createCSR | --createcsr | -ccr) _CMD="createCSR" ;; - --deactivate) + --deactivate) _CMD="deactivate" ;; - --updateaccount) + --updateaccount) _CMD="updateaccount" ;; - --registeraccount) + --registeraccount) _CMD="registeraccount" ;; - --domain|-d) + --domain | -d) _dvalue="$2" - - if [ "$_dvalue" ] ; then - if _startswith "$_dvalue" "-" ; then + + if [ "$_dvalue" ]; then + if _startswith "$_dvalue" "-"; then _err "'$_dvalue' is not a valid domain for parameter '$1'" return 1 fi - if _is_idn "$_dvalue" && ! _exists idn ; then + if _is_idn "$_dvalue" && ! _exists idn; then _err "It seems that $_dvalue is an IDN( Internationalized Domain Names), please install 'idn' command first." return 1 fi - - if [ -z "$_domain" ] ; then + + if [ -z "$_domain" ]; then _domain="$_dvalue" else - if [ "$_altdomains" = "$NO_VALUE" ] ; then + if [ "$_altdomains" = "$NO_VALUE" ]; then _altdomains="$_dvalue" else _altdomains="$_altdomains,$_dvalue" fi fi fi - + shift ;; - --force|-f) + --force | -f) FORCE="1" ;; - --staging|--test) + --staging | --test) STAGE="1" ;; - --debug) - if [ -z "$2" ] || _startswith "$2" "-" ; then + --debug) + if [ -z "$2" ] || _startswith "$2" "-"; then DEBUG="1" else DEBUG="$2" shift - fi + fi ;; - --webroot|-w) + --webroot | -w) wvalue="$2" - if [ -z "$_webroot" ] ; then + if [ -z "$_webroot" ]; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" fi shift - ;; - --standalone) + ;; + --standalone) wvalue="$NO_VALUE" - if [ -z "$_webroot" ] ; then + if [ -z "$_webroot" ]; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" fi ;; - --local-address) + --local-address) lvalue="$2" _local_address="$_local_address$lvalue," shift ;; - --apache) + --apache) wvalue="apache" - if [ -z "$_webroot" ] ; then + if [ -z "$_webroot" ]; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" fi ;; - --tls) + --tls) wvalue="$W_TLS" - if [ -z "$_webroot" ] ; then + if [ -z "$_webroot" ]; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" fi ;; - --dns) + --dns) wvalue="dns" - if ! _startswith "$2" "-" ; then + if ! _startswith "$2" "-"; then wvalue="$2" shift fi - if [ -z "$_webroot" ] ; then + if [ -z "$_webroot" ]; then _webroot="$wvalue" else _webroot="$_webroot,$wvalue" fi ;; - --dnssleep) + --dnssleep) _dnssleep="$2" Le_DNSSleep="$_dnssleep" shift ;; - - --keylength|-k) + + --keylength | -k) _keylength="$2" shift ;; - --accountkeylength|-ak) + --accountkeylength | -ak) _accountkeylength="$2" shift ;; - --certpath) + --certpath) _certpath="$2" shift ;; - --keypath) + --keypath) _keypath="$2" shift ;; - --capath) + --capath) _capath="$2" shift ;; - --fullchainpath) + --fullchainpath) _fullchainpath="$2" shift ;; - --reloadcmd|--reloadCmd) + --reloadcmd | --reloadCmd) _reloadcmd="$2" shift ;; - --password) + --password) _password="$2" shift ;; - --accountconf) + --accountconf) _accountconf="$2" ACCOUNT_CONF_PATH="$_accountconf" shift ;; - --home) + --home) LE_WORKING_DIR="$2" shift ;; - --certhome) + --certhome) _certhome="$2" CERT_HOME="$_certhome" shift - ;; - --useragent) + ;; + --useragent) _useragent="$2" USER_AGENT="$_useragent" shift ;; - --accountemail ) + --accountemail) _accountemail="$2" ACCOUNT_EMAIL="$_accountemail" shift ;; - --accountkey ) + --accountkey) _accountkey="$2" ACCOUNT_KEY_PATH="$_accountkey" shift ;; - --days ) + --days) _days="$2" Le_RenewalDays="$_days" shift ;; - --httpport ) + --httpport) _httpport="$2" Le_HTTPPort="$_httpport" shift ;; - --tlsport ) + --tlsport) _tlsport="$2" Le_TLSPort="$_tlsport" shift ;; - - --listraw ) + + --listraw) _listraw="raw" - ;; - --stopRenewOnError|--stoprenewonerror|-se ) + ;; + --stopRenewOnError | --stoprenewonerror | -se) _stopRenewOnError="1" ;; - --insecure) + --insecure) _insecure="1" HTTPS_INSECURE="1" ;; - --ca-bundle) + --ca-bundle) _ca_bundle="$(readlink -f $2)" CA_BUNDLE="$_ca_bundle" shift ;; - --nocron) + --nocron) _nocron="1" ;; - --ecc) + --ecc) _ecc="isEcc" ;; - --csr) + --csr) _csr="$2" shift ;; - --pre-hook) + --pre-hook) _pre_hook="$2" shift ;; - --post-hook) + --post-hook) _post_hook="$2" shift ;; - --renew-hook) + --renew-hook) _renew_hook="$2" shift ;; - --deploy-hook) + --deploy-hook) _deploy_hook="$2" shift ;; - --ocsp-must-staple|--ocsp) + --ocsp-must-staple | --ocsp) Le_OCSP_Stable="1" ;; - --log|--logfile) + --log | --logfile) _log="1" _logfile="$2" - if _startswith "$_logfile" '-' ; then + if _startswith "$_logfile" '-'; then _logfile="" else shift fi LOG_FILE="$_logfile" - if [ -z "$LOG_LEVEL" ] ; then + if [ -z "$LOG_LEVEL" ]; then LOG_LEVEL="$DEFAULT_LOG_LEVEL" fi ;; - --log-level) + --log-level) _log_level="$2" LOG_LEVEL="$_log_level" shift ;; - --auto-upgrade) + --auto-upgrade) _auto_upgrade="$2" - if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-' ; then + if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then _auto_upgrade="1" else shift fi AUTO_UPGRADE="$_auto_upgrade" ;; - --listen-v4) + --listen-v4) _listen_v4="1" Le_Listen_V4="$_listen_v4" ;; - --listen-v6) + --listen-v6) _listen_v6="1" Le_Listen_V6="$_listen_v6" ;; - - *) + + *) _err "Unknown parameter : $1" return 1 ;; @@ -4452,29 +4409,29 @@ _process() { shift 1 done - if [ "${_CMD}" != "install" ] ; then + if [ "${_CMD}" != "install" ]; then __initHome if [ "$_log" ]; then - if [ -z "$_logfile" ] ; then + if [ -z "$_logfile" ]; then _logfile="$DEFAULT_LOG_FILE" fi fi - if [ "$_logfile" ] ; then + if [ "$_logfile" ]; then _saveaccountconf "LOG_FILE" "$_logfile" LOG_FILE="$_logfile" fi - if [ "$_log_level" ] ; then + if [ "$_log_level" ]; then _saveaccountconf "LOG_LEVEL" "$_log_level" LOG_LEVEL="$_log_level" fi - + _processAccountConf fi - + _debug2 LE_WORKING_DIR "$LE_WORKING_DIR" - - if [ "$DEBUG" ] ; then + + if [ "$DEBUG" ]; then version fi @@ -4483,7 +4440,7 @@ _process() { uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" ;; deploy) deploy "$_domain" "$_deploy_hook" "$_ecc" @@ -4497,63 +4454,63 @@ _process() { installcert) installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc" ;; - renew) + renew) renew "$_domain" "$_ecc" ;; - renewAll) + renewAll) renewAll "$_stopRenewOnError" ;; - revoke) + revoke) revoke "$_domain" "$_ecc" ;; - deactivate) + deactivate) deactivate "$_domain,$_altdomains" ;; - registeraccount) + registeraccount) registeraccount "$_accountkeylength" ;; - updateaccount) + updateaccount) updateaccount ;; - list) + list) list "$_listraw" ;; installcronjob) installcronjob ;; uninstallcronjob) uninstallcronjob ;; cron) cron ;; - toPkcs) + toPkcs) toPkcs "$_domain" "$_password" "$_ecc" ;; - createAccountKey) + createAccountKey) createAccountKey "$_accountkeylength" ;; - createDomainKey) + createDomainKey) createDomainKey "$_domain" "$_keylength" ;; - createCSR) + createCSR) createCSR "$_domain" "$_altdomains" "$_ecc" ;; *) _err "Invalid command: $_CMD" - showhelp; + showhelp return 1 - ;; + ;; esac _ret="$?" - if [ "$_ret" != "0" ] ; then + if [ "$_ret" != "0" ]; then return $_ret fi - - if [ "${_CMD}" = "install" ] ; then - if [ "$_log" ] ; then - if [ -z "$LOG_FILE" ] ; then + + if [ "${_CMD}" = "install" ]; then + if [ "$_log" ]; then + if [ -z "$LOG_FILE" ]; then LOG_FILE="$DEFAULT_LOG_FILE" fi _saveaccountconf "LOG_FILE" "$LOG_FILE" fi - - if [ "$_log_level" ] ; then + + if [ "$_log_level" ]; then _saveaccountconf "LOG_LEVEL" "$_log_level" fi _processAccountConf @@ -4561,24 +4518,15 @@ _process() { } - -if [ "$INSTALLONLINE" ] ; then +if [ "$INSTALLONLINE" ]; then INSTALLONLINE="" _installOnline $BRANCH exit fi - - - - main() { [ -z "$1" ] && showhelp && return - if _startswith "$1" '-' ; then _process "$@"; else "$@";fi + if _startswith "$1" '-'; then _process "$@"; else "$@"; fi } - main "$@" - - - diff --git a/deploy/myapi.sh b/deploy/myapi.sh index 52e313e7..5075fab8 100644 --- a/deploy/myapi.sh +++ b/deploy/myapi.sh @@ -6,8 +6,6 @@ #Which will be called by acme.sh to deploy the cert #returns 0 means success, otherwise error. - - ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -17,17 +15,14 @@ myapi_deploy() { _ccert="$3" _cca="$4" _cfullchain="$5" - + _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" _debug _ccert "$_ccert" _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - - + _err "Not implemented yet" return 1 } - - diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index b2dc7eb8..63acb28f 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -1,54 +1,52 @@ #!/usr/bin/env sh - # #CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" # #CF_Email="xxxx@sss.com" - CF_Api="https://api.cloudflare.com/client/v4" ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cf_add(){ +dns_cf_add() { fulldomain=$1 txtvalue=$2 - - if [ -z "$CF_Key" ] || [ -z "$CF_Email" ] ; then + + if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then _err "You don't specify cloudflare api key and email yet." _err "Please create you key and try again." return 1 fi - + #save the api key and email to the account conf file. _saveaccountconf CF_Key "$CF_Key" _saveaccountconf CF_Email "$CF_Email" - + _debug "First detect the root zone" - if ! _get_root $fulldomain ; then + 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" _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain" - - if ! printf "$response" | grep \"success\":true > /dev/null ; then + + if ! printf "$response" | grep \"success\":true >/dev/null; then _err "Error" return 1 fi - + count=$(printf "%s\n" "$response" | _egrep_o \"count\":[^,]* | cut -d : -f 2) _debug count "$count" - if [ "$count" = "0" ] ; then + 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 _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 _info "Added, sleeping 10 seconds" sleep 10 #todo: check if the record takes effect @@ -61,22 +59,21 @@ dns_cf_add(){ _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \"| head -n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \" | head -n 1) _debug "record_id" $record_id - - _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" + + _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" if [ "$?" = "0" ]; then _info "Updated, sleeping 10 seconds" sleep 10 #todo: check if the record takes effect - return 0; + return 0 fi _err "Update error" return 1 fi - -} +} #fulldomain dns_cf_rm() { @@ -84,7 +81,6 @@ dns_cf_rm() { } - #################### Private functions bellow ################################## #_acme-challenge.www.domain.com #returns @@ -95,20 +91,20 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ] ; do + while [ '1' ]; do h=$(printf $domain | cut -d . -f $i-100) - if [ -z "$h" ] ; then + if [ -z "$h" ]; then #not valid - return 1; + return 1 fi - - if ! _cf_rest GET "zones?name=$h" ; then + + if ! _cf_rest GET "zones?name=$h"; then return 1 fi - - if printf $response | grep \"name\":\"$h\" >/dev/null ; then + + if printf $response | grep \"name\":\"$h\" >/dev/null; then _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | head -n 1 | cut -d : -f 2 | tr -d \") - if [ "$_domain_id" ] ; then + if [ "$_domain_id" ]; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) _domain=$h return 0 @@ -126,24 +122,22 @@ _cf_rest() { ep="$2" data="$3" _debug $ep - + _H1="X-Auth-Email: $CF_Email" _H2="X-Auth-Key: $CF_Key" _H3="Content-Type: application/json" - - if [ "$data" ] ; then + + if [ "$data" ]; then _debug data "$data" response="$(_post "$data" "$CF_Api/$ep" "" $m)" else response="$(_get "$CF_Api/$ep")" fi - - if [ "$?" != "0" ] ; then + + if [ "$?" != "0" ]; then _err "error $ep" return 1 fi _debug2 response "$response" return 0 } - - diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index ae162d62..81eb896d 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -6,10 +6,8 @@ # #CX_Secret="sADDsdasdgdsf" - CX_Api="https://www.cloudxns.net/api2" - #REST_API ######## Public functions ##################### @@ -17,54 +15,50 @@ CX_Api="https://www.cloudxns.net/api2" dns_cx_add() { fulldomain=$1 txtvalue=$2 - - if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ] ; then + + if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then _err "You don't specify cloudxns.com api key or secret yet." _err "Please create you key and try again." return 1 fi - + REST_API=$CX_Api - + #save the api key and email to the account conf file. _saveaccountconf CX_Key "$CX_Key" _saveaccountconf CX_Secret "$CX_Secret" - - + _debug "First detect the root zone" - if ! _get_root $fulldomain ; then + if ! _get_root $fulldomain; then _err "invalid domain" return 1 fi - - existing_records $_domain $_sub_domain + + existing_records $_domain $_sub_domain _debug count "$count" - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Error get existing records." return 1 fi - if [ "$count" = "0" ] ; then + if [ "$count" = "0" ]; then add_record $_domain $_sub_domain $txtvalue else update_record $_domain $_sub_domain $txtvalue fi - - if [ "$?" = "0" ] ; then + + if [ "$?" = "0" ]; then return 0 fi return 1 } - - #fulldomain dns_cx_rm() { fulldomain=$1 } - #usage: root sub #return if the sub record already exists. #echos the existing records count. @@ -73,24 +67,24 @@ existing_records() { _debug "Getting txt records" root=$1 sub=$2 - - if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100" ; then + + if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then return 1 fi count=0 seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") _debug seg "$seg" - if [ -z "$seg" ] ; then + if [ -z "$seg" ]; then return 0 fi - if printf "$response" | grep '"type":"TXT"' > /dev/null ; then + if printf "$response" | grep '"type":"TXT"' >/dev/null; then count=1 record_id=$(printf "%s\n" "$seg" | _egrep_o \"record_id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug record_id "$record_id" - return 0 + return 0 fi - + } #add the txt record. @@ -100,13 +94,13 @@ add_record() { sub=$2 txtvalue=$3 fulldomain=$sub.$root - + _info "Adding record" - + if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then return 1 fi - + return 0 } @@ -117,19 +111,16 @@ update_record() { sub=$2 txtvalue=$3 fulldomain=$sub.$root - + _info "Updating record" - - if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}" ; then + + if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then return 0 fi - + return 1 } - - - #################### Private functions bellow ################################## #_acme-challenge.www.domain.com #returns @@ -140,25 +131,25 @@ _get_root() { domain=$1 i=2 p=1 - - if ! _rest GET "domain" ; then + + if ! _rest GET "domain"; then return 1 fi - - while [ '1' ] ; do + + while [ '1' ]; do h=$(printf $domain | cut -d . -f $i-100) _debug h "$h" - if [ -z "$h" ] ; then + if [ -z "$h" ]; then #not valid - return 1; + return 1 fi - if printf "$response" | grep "$h." >/dev/null ; then - seg=$(printf "%s" "$response" | _egrep_o "\{[^\{]*\"$h\.\"[^\}]*\}" ) + if printf "$response" | grep "$h." >/dev/null; then + seg=$(printf "%s" "$response" | _egrep_o "\{[^\{]*\"$h\.\"[^\}]*\}") _debug seg "$seg" _domain_id=$(printf "%s" "$seg" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" - if [ "$_domain_id" ] ; then + if [ "$_domain_id" ]; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) _debug _sub_domain $_sub_domain _domain=$h @@ -173,7 +164,6 @@ _get_root() { return 1 } - #Usage: method URI data _rest() { m=$1 @@ -181,38 +171,36 @@ _rest() { _debug $ep url="$REST_API/$ep" _debug url "$url" - - cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC") + + cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC") _debug cdate "$cdate" - + data="$3" _debug data "$data" - + sec="$CX_Key$url$data$cdate$CX_Secret" _debug sec "$sec" - hmac=$(printf "$sec"| openssl md5 |cut -d " " -f 2) + hmac=$(printf "$sec" | openssl md5 | cut -d " " -f 2) _debug hmac "$hmac" - + _H1="API-KEY: $CX_Key" _H2="API-REQUEST-DATE: $cdate" _H3="API-HMAC: $hmac" _H4="Content-Type: application/json" - if [ "$data" ] ; then + if [ "$data" ]; then response="$(_post "$data" "$url" "" $m)" else response="$(_get "$url")" fi - - if [ "$?" != "0" ] ; then + + if [ "$?" != "0" ]; then _err "error $ep" return 1 fi _debug2 response "$response" - if ! printf "$response" | grep '"message":"success"' > /dev/null ; then + if ! printf "$response" | grep '"message":"success"' >/dev/null; then return 1 fi return 0 } - - diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 898806bd..4ec8da69 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -18,7 +18,7 @@ dns_dp_add() { fulldomain=$1 txtvalue=$2 - if [ -z "$DP_Id" ] || [ -z "$DP_Key" ] ; then + if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then _err "You don't specify dnspod api key and key id yet." _err "Please create you key and try again." return 1 @@ -39,12 +39,12 @@ dns_dp_add() { existing_records $_domain $_sub_domain _debug count "$count" - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "Error get existing records." return 1 fi - if [ "$count" = "0" ] ; then + if [ "$count" = "0" ]; then add_record $_domain $_sub_domain $txtvalue else update_record $_domain $_sub_domain $txtvalue @@ -149,9 +149,9 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ] ; do + while [ '1' ]; do h=$(printf $domain | cut -d . -f $i-100) - if [ -z "$h" ] ; then + if [ -z "$h" ]; then #not valid return 1; fi @@ -163,7 +163,7 @@ _get_root() { if printf "$response" | grep "Action completed successful" >/dev/null ; then _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" - if [ "$_domain_id" ] ; then + if [ "$_domain_id" ]; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) _debug _sub_domain $_sub_domain _domain=$h @@ -189,14 +189,14 @@ _rest() { _debug url "$url" - if [ "$data" ] ; then + if [ "$data" ]; then _debug2 data "$data" response="$(_post $data "$url")" else response="$(_get "$url")" fi - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "error $ep" return 1 fi diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 0f399b41..51ca8db5 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -6,39 +6,37 @@ # #GD_Secret="asdfsdfsfsdfsdfdfsdf" - GD_Api="https://api.godaddy.com/v1" ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_gd_add(){ +dns_gd_add() { fulldomain=$1 txtvalue=$2 - - if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ] ; then + + if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then _err "You don't specify godaddy api key and secret yet." _err "Please create you key and try again." return 1 fi - + #save the api key and email to the account conf file. _saveaccountconf GD_Key "$GD_Key" _saveaccountconf GD_Secret "$GD_Secret" - + _debug "First detect the root zone" - if ! _get_root $fulldomain ; then + if ! _get_root $fulldomain; then _err "invalid domain" return 1 fi _debug _domain_id "$_domain_id" _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _info "Adding record" - if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then - if [ "$response" = "{}" ] ; then + if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then + if [ "$response" = "{}" ]; then _info "Added, sleeping 10 seconds" sleep 10 #todo: check if the record takes effect @@ -50,10 +48,8 @@ dns_gd_add(){ fi fi _err "Add txt record error." - -} - +} #fulldomain dns_gd_rm() { @@ -61,9 +57,6 @@ dns_gd_rm() { } - - - #################### Private functions bellow ################################## #_acme-challenge.www.domain.com #returns @@ -74,18 +67,18 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ] ; do + while [ '1' ]; do h=$(printf $domain | cut -d . -f $i-100) - if [ -z "$h" ] ; then + if [ -z "$h" ]; then #not valid - return 1; + return 1 fi - - if ! _gd_rest GET "domains/$h" ; then + + if ! _gd_rest GET "domains/$h"; then return 1 fi - - if printf "$response" | grep '"code":"NOT_FOUND"' >/dev/null ; then + + if printf "$response" | grep '"code":"NOT_FOUND"' >/dev/null; then _debug "$h not found" else _sub_domain=$(printf $domain | cut -d . -f 1-$p) @@ -103,23 +96,21 @@ _gd_rest() { ep="$2" data="$3" _debug $ep - + _H1="Authorization: sso-key $GD_Key:$GD_Secret" _H2="Content-Type: application/json" - - if [ "$data" ] ; then + + if [ "$data" ]; then _debug data "$data" response="$(_post "$data" "$GD_Api/$ep" "" $m)" else response="$(_get "$GD_Api/$ep")" fi - - if [ "$?" != "0" ] ; then + + if [ "$?" != "0" ]; then _err "error $ep" return 1 fi _debug2 response "$response" return 0 } - - diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 34f7637c..847b9999 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -13,15 +13,15 @@ wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" dns_lexicon_add() { fulldomain=$1 txtvalue=$2 - + domain=$(printf "$fulldomain" | cut -d . -f 2-999) - - if ! _exists $lexicon_cmd ; then + + if ! _exists $lexicon_cmd; then _err "Please install $lexicon_cmd first: $wiki" return 1 fi - - if [ -z "$PROVIDER" ] ; then + + if [ -z "$PROVIDER" ]; then _err "Please define env PROVIDER first: $wiki" return 1 fi @@ -29,34 +29,34 @@ dns_lexicon_add() { _savedomainconf PROVIDER "$PROVIDER" export PROVIDER - Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr [a-z] [A-Z]) + Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr [a-z] [A-Z]) eval Lx_name_v="\$$Lx_name" _debug "$Lx_name" "$Lx_name_v" - if [ "$Lx_name_v" ] ; then + if [ "$Lx_name_v" ]; then _saveaccountconf $Lx_name "$Lx_name_v" export "$Lx_name" fi - - Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr [a-z] [A-Z]) + + Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr [a-z] [A-Z]) eval Lx_token_v="\$$Lx_token" _debug "$Lx_token" "$Lx_token_v" - if [ "$Lx_token_v" ] ; then + if [ "$Lx_token_v" ]; then _saveaccountconf $Lx_token "$Lx_token_v" export "$Lx_token" fi - - Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr [a-z] [A-Z]) + + Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr [a-z] [A-Z]) eval Lx_password_v="\$$Lx_password" _debug "$Lx_password" "$Lx_password_v" - if [ "$Lx_password_v" ] ; then + if [ "$Lx_password_v" ]; then _saveaccountconf $Lx_password "$Lx_password_v" export "$Lx_password" fi - - Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr [a-z] [A-Z]) + + Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr [a-z] [A-Z]) eval Lx_domaintoken_v="\$$Lx_domaintoken" _debug "$Lx_domaintoken" "$Lx_domaintoken_v" - if [ "$Lx_domaintoken_v" ] ; then + if [ "$Lx_domaintoken_v" ]; then export "$Lx_domaintoken" _saveaccountconf $Lx_domaintoken "$Lx_domaintoken_v" fi @@ -65,14 +65,8 @@ dns_lexicon_add() { } - #fulldomain dns_lexicon_rm() { fulldomain=$1 } - - - - - diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index a59e0d0b..efd197c2 100644 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -16,40 +16,40 @@ LUA_auth=$(printf $LUA_Email:$LUA_Key | _base64) dns_lua_add() { fulldomain=$1 txtvalue=$2 - - if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ] ; then + + if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then _err "You don't specify luadns api key and email yet." _err "Please create you key and try again." return 1 fi - + #save the api key and email to the account conf file. _saveaccountconf LUA_Key "$LUA_Key" _saveaccountconf LUA_Email "$LUA_Email" - + _debug "First detect the root zone" - if ! _get_root $fulldomain ; then + 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" _LUA_rest GET "zones/${_domain_id}/records" - - if ! printf "$response" | grep \"id\": > /dev/null ; then + + if ! printf "$response" | grep \"id\": >/dev/null; then _err "Error" return 1 fi - + count=$(printf "%s\n" "$response" | _egrep_o \"name\":\"$fulldomain\" | wc -l) _debug count "$count" - if [ "$count" = "0" ] ; then + if [ "$count" = "0" ]; then _info "Adding record" - if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep $fulldomain > /dev/null ; then + if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep $fulldomain >/dev/null; then _info "Added" #todo: check if the record takes effect return 0 @@ -61,21 +61,20 @@ dns_lua_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\" | cut -d: -f2|cut -d, -f1 ) + record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\" | cut -d: -f2 | cut -d, -f1) _debug "record_id" $record_id - - _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" + + _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" if [ "$?" = "0" ]; then _info "Updated!" #todo: check if the record takes effect - return 0; + return 0 fi _err "Update error" return 1 fi - -} +} #fulldomain dns_lua_rm() { @@ -83,7 +82,6 @@ dns_lua_rm() { } - #################### Private functions bellow ################################## #_acme-challenge.www.domain.com #returns @@ -94,19 +92,19 @@ _get_root() { domain=$1 i=2 p=1 - if ! _LUA_rest GET "zones" ; then - return 1 - fi - while [ '1' ] ; do + if ! _LUA_rest GET "zones"; then + return 1 + fi + while [ '1' ]; do h=$(printf $domain | cut -d . -f $i-100) - if [ -z "$h" ] ; then + if [ -z "$h" ]; then #not valid - return 1; + return 1 fi - - if printf $response | grep \"name\":\"$h\" >/dev/null ; then + + if printf $response | grep \"name\":\"$h\" >/dev/null; then _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$h\" | cut -d : -f 2 | cut -d , -f 1) - if [ "$_domain_id" ] ; then + if [ "$_domain_id" ]; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) _domain=$h return 0 @@ -124,22 +122,20 @@ _LUA_rest() { ep="$2" data="$3" _debug $ep - + _H1="Accept: application/json" _H2="Authorization: Basic $LUA_auth" - if [ "$data" ] ; then + if [ "$data" ]; then _debug data "$data" response="$(_post "$data" "$LUA_Api/$ep" "" $m)" else response="$(_get "$LUA_Api/$ep")" fi - - if [ "$?" != "0" ] ; then + + if [ "$?" != "0" ]; then _err "error $ep" return 1 fi _debug2 response "$response" return 0 } - - diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index 73b1ea85..813a2ed1 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -6,8 +6,6 @@ #Which will be called by acme.sh to add the txt record to your api system. #returns 0 means success, otherwise error. - - ######## Public functions ##################### #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -15,21 +13,18 @@ dns_myapi_add() { fulldomain=$1 txtvalue=$2 _err "Not implemented!" - return 1; + return 1 } - - #fulldomain dns_myapi_rm() { fulldomain=$1 } - #################### Private functions bellow ################################## _info() { - if [ -z "$2" ] ; then + if [ -z "$2" ]; then echo "[$(date)] $1" else echo "[$(date)] $1='$2'" @@ -42,7 +37,7 @@ _err() { } _debug() { - if [ -z "$DEBUG" ] ; then + if [ -z "$DEBUG" ]; then return fi _err "$@" @@ -50,8 +45,8 @@ _debug() { } _debug2() { - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _debug "$@" fi return -} \ No newline at end of file +} diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index b31d02fc..782c0830 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -1,6 +1,5 @@ #!/usr/bin/env sh - #Applcation Key #OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" # @@ -10,10 +9,8 @@ #Consumer Key #OVH_CK="sdfsdfsdfsdfsdfdsf" - #OVH_END_POINT=ovh-eu - #'ovh-eu' OVH_EU='https://eu.api.ovh.com/1.0' @@ -35,121 +32,116 @@ SYS_CA='https://ca.api.soyoustart.com/1.0' #'runabove-ca' RAV_CA='https://api.runabove.com/1.0' - wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api" ovh_success="https://github.com/Neilpang/acme.sh/wiki/OVH-Success" - - _ovh_get_api() { _ogaep="$1" case "${_ogaep}" in - - ovh-eu|ovheu) - printf "%s" $OVH_EU - return - ;; - ovh-ca|ovhca) - printf "%s" $OVH_CA - return - ;; - kimsufi-eu|kimsufieu) - printf "%s" $KSF_EU - return - ;; - kimsufi-ca|kimsufica) - printf "%s" $KSF_CA - return - ;; - soyoustart-eu|soyoustarteu) - printf "%s" $SYS_EU - return - ;; - soyoustart-ca|soyoustartca) - printf "%s" $SYS_CA - return - ;; - runabove-ca|runaboveca) - printf "%s" $RAV_CA - return - ;; - - + + ovh-eu | ovheu) + printf "%s" $OVH_EU + return + ;; + ovh-ca | ovhca) + printf "%s" $OVH_CA + return + ;; + kimsufi-eu | kimsufieu) + printf "%s" $KSF_EU + return + ;; + kimsufi-ca | kimsufica) + printf "%s" $KSF_CA + return + ;; + soyoustart-eu | soyoustarteu) + printf "%s" $SYS_EU + return + ;; + soyoustart-ca | soyoustartca) + printf "%s" $SYS_CA + return + ;; + runabove-ca | runaboveca) + printf "%s" $RAV_CA + return + ;; + *) - _err "Unknown parameter : $1" - return 1 - ;; - esac + + _err "Unknown parameter : $1" + return 1 + ;; + esac } ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_ovh_add(){ +dns_ovh_add() { fulldomain=$1 txtvalue=$2 - - if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ] ; then + + if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then _err "You don't specify OVH application key and application secret yet." _err "Please create you key and try again." return 1 fi - + #save the api key and email to the account conf file. _saveaccountconf OVH_AK "$OVH_AK" _saveaccountconf OVH_AS "$OVH_AS" - - - if [ -z "$OVH_END_POINT" ] ; then + + if [ -z "$OVH_END_POINT" ]; then OVH_END_POINT="ovh-eu" fi _info "Using OVH endpoint: $OVH_END_POINT" - if [ "$OVH_END_POINT" != "ovh-eu" ] ; then - _saveaccountconf OVH_END_POINT "$OVH_END_POINT" + if [ "$OVH_END_POINT" != "ovh-eu" ]; then + _saveaccountconf OVH_END_POINT "$OVH_END_POINT" fi - - OVH_API="$(_ovh_get_api $OVH_END_POINT )" + + OVH_API="$(_ovh_get_api $OVH_END_POINT)" _debug OVH_API "$OVH_API" - if [ -z "$OVH_CK" ] ; then + if [ -z "$OVH_CK" ]; then _info "OVH consumer key is empty, Let's get one:" - if ! _ovh_authentication ; then + if ! _ovh_authentication; then _err "Can not get consumer key." fi #return and wait for retry. - return 1; + return 1 fi - - + _info "Checking authentication" - + 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 "Please retry to create a new one." - _clearaccountconf OVH_CK + _clearaccountconf OVH_CK return 1 fi _info "Consumer key is ok." - + _debug "First detect the root zone" - if ! _get_root $fulldomain ; then + 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" _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" - - if _contains "$response" '\[\]' || _contains "$response" "This service does not exist" ; then + + if _contains "$response" '\[\]' || _contains "$response" "This service does not exist"; then _info "Adding record" - if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then - if _contains "$response" "$txtvalue" ; then + if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then + if _contains "$response" "$txtvalue"; then _ovh_rest POST "domain/zone/$_domain/refresh" _debug "Refresh:$response" _info "Added, sleeping 10 seconds" @@ -161,27 +153,26 @@ dns_ovh_add(){ else _info "Updating record" record_id=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 1) - if [ -z "$record_id" ] ; then + if [ -z "$record_id" ]; then _err "Can not get record id." return 1 fi _debug "record_id" $record_id - if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}" ; then - if _contains "$response" "null" ; then + if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}"; then + if _contains "$response" "null"; then _ovh_rest POST "domain/zone/$_domain/refresh" _debug "Refresh:$response" _info "Updated, sleeping 10 seconds" sleep 10 - return 0; + return 0 fi fi _err "Update error" return 1 fi - -} +} #fulldomain dns_ovh_rm() { @@ -189,45 +180,43 @@ dns_ovh_rm() { } - #################### Private functions bellow ################################## _ovh_authentication() { - + _H1="X-Ovh-Application: $OVH_AK" _H2="Content-type: application/json" _H3="" _H4="" - + _ovhdata='{"accessRules": [{"method": "GET","path": "/*"},{"method": "POST","path": "/*"},{"method": "PUT","path": "/*"},{"method": "DELETE","path": "/*"}],"redirection":"'$ovh_success'"}' - + response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" _debug3 response "$response" validationUrl="$(echo "$response" | _egrep_o "validationUrl\":\"[^\"]*\"" | _egrep_o "http.*\"" | tr -d '"')" - if [ -z "$validationUrl" ] ; then + if [ -z "$validationUrl" ]; then _err "Unable to get validationUrl" return 1 fi _debug validationUrl "$validationUrl" - + consumerKey="$(echo "$response" | _egrep_o "consumerKey\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')" - if [ -z "$consumerKey" ] ; then + if [ -z "$consumerKey" ]; then _err "Unable to get consumerKey" return 1 fi _debug consumerKey "$consumerKey" - + OVH_CK="$consumerKey" _saveaccountconf OVH_CK "$OVH_CK" - - _info "Please open this link to do authentication: $(__green "$validationUrl" )" - _info "Here is a guide for you: $(__green "$wiki" )" + _info "Please open this link to do authentication: $(__green "$validationUrl")" + + _info "Here is a guide for you: $(__green "$wiki")" _info "Please retry after the authentication is done." } - #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www @@ -237,18 +226,18 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ] ; do + while [ '1' ]; do h=$(printf $domain | cut -d . -f $i-100) - if [ -z "$h" ] ; then + if [ -z "$h" ]; then #not valid - return 1; + return 1 fi - - if ! _ovh_rest GET "domain/zone/$h" ; then + + if ! _ovh_rest GET "domain/zone/$h"; then return 1 fi - - if ! _contains "$response" "This service does not exist" >/dev/null ; then + + if ! _contains "$response" "This service does not exist" >/dev/null; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) _domain=$h return 0 @@ -273,8 +262,7 @@ _ovh_rest() { ep="$2" data="$3" _debug $ep - - + _ovh_url="$OVH_API/$ep" _debug2 _ovh_url "$_ovh_url" _ovh_t="$(_ovh_timestamp)" @@ -283,7 +271,6 @@ _ovh_rest() { _debug _ovh_p "$_ovh_p" _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" _debug2 _ovh_hex "$_ovh_hex" - _H1="X-Ovh-Application: $OVH_AK" _H2="X-Ovh-Signature: \$1\$$_ovh_hex" @@ -291,19 +278,17 @@ _ovh_rest() { _H3="X-Ovh-Timestamp: $_ovh_t" _H4="X-Ovh-Consumer: $OVH_CK" _H5="Content-Type: application/json;charset=utf-8" - if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] ; then + if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then _debug data "$data" response="$(_post "$data" "$_ovh_url" "" $m)" else response="$(_get "$_ovh_url")" fi - - if [ "$?" != "0" ] ; then + + if [ "$?" != "0" ]; then _err "error $ep" return 1 fi _debug2 response "$response" return 0 } - - diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index aa7a2c45..ec82bfe8 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -16,25 +16,25 @@ dns_pdns_add() { fulldomain=$1 txtvalue=$2 - if [ -z "$PDNS_Url" ] ; then + if [ -z "$PDNS_Url" ]; then _err "You don't specify PowerDNS address." _err "Please set PDNS_Url and try again." return 1 fi - if [ -z "$PDNS_ServerId" ] ; then + if [ -z "$PDNS_ServerId" ]; then _err "You don't specify PowerDNS server id." _err "Please set you PDNS_ServerId and try again." return 1 fi - if [ -z "$PDNS_Token" ] ; then + if [ -z "$PDNS_Token" ]; then _err "You don't specify PowerDNS token." _err "Please create you PDNS_Token and try again." return 1 fi - if [ -z "$PDNS_Ttl" ] ; then + if [ -z "$PDNS_Ttl" ]; then PDNS_Ttl=$DEFAULT_PDNS_TTL fi @@ -42,44 +42,42 @@ dns_pdns_add() { _saveaccountconf PDNS_Url "$PDNS_Url" _saveaccountconf PDNS_ServerId "$PDNS_ServerId" _saveaccountconf PDNS_Token "$PDNS_Token" - - if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ] ; then + + if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ]; then _saveaccountconf PDNS_Ttl "$PDNS_Ttl" fi _debug "First detect the root zone" - if ! _get_root $fulldomain ; then + if ! _get_root $fulldomain; then _err "invalid domain" return 1 fi _debug _domain "$_domain" - if ! set_record "$_domain" "$fulldomain" "$txtvalue" ; then + if ! set_record "$_domain" "$fulldomain" "$txtvalue"; then return 1 fi return 0 } - #fulldomain dns_pdns_rm() { fulldomain=$1 } - set_record() { _info "Adding record" root=$1 full=$2 txtvalue=$3 - if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"name\": \"$full.\", \"changetype\": \"REPLACE\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}" ; then + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"name\": \"$full.\", \"changetype\": \"REPLACE\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then _err "Set txt record error." return 1 fi - if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify" ; then + if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify"; then _err "Notify servers error." return 1 fi @@ -95,17 +93,17 @@ _get_root() { i=1 p=1 - if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones" ; then + if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones"; then _zones_response=$response fi - while [ '1' ] ; do + while [ '1' ]; do h=$(printf $domain | cut -d . -f $i-100) - if [ -z "$h" ] ; then + if [ -z "$h" ]; then return 1 fi - if printf "$_zones_response" | grep "\"name\": \"$h.\"" >/dev/null ; then + if printf "$_zones_response" | grep "\"name\": \"$h.\"" >/dev/null; then _domain=$h return 0 fi @@ -124,18 +122,18 @@ _pdns_rest() { _H1="X-API-Key: $PDNS_Token" - if [ ! "$method" = "GET" ] ; then + if [ ! "$method" = "GET" ]; then _debug data "$data" response="$(_post "$data" "$PDNS_Url$ep" "" "$method")" else response="$(_get "$PDNS_Url$ep")" fi - if [ "$?" != "0" ] ; then + if [ "$?" != "0" ]; then _err "error $ep" return 1 fi _debug2 response "$response" return 0 -} \ No newline at end of file +} From 439580b91beb02635ce3d76895d44970ceadb083 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 9 Nov 2016 20:01:27 +0800 Subject: [PATCH 0426/1348] apply shfmt to dns_dp api. --- dnsapi/dns_dp.sh | 86 ++++++++++++++++++++--------------------------- dnsapi/dns_lua.sh | 0 2 files changed, 36 insertions(+), 50 deletions(-) mode change 100644 => 100755 dnsapi/dns_lua.sh diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 4ec8da69..8861bfcf 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -6,10 +6,8 @@ # #DP_Key="sADDsdasdgdsf" - DP_Api="https://dnsapi.cn" - #REST_API ######## Public functions ##################### @@ -17,27 +15,26 @@ DP_Api="https://dnsapi.cn" dns_dp_add() { fulldomain=$1 txtvalue=$2 - + if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then _err "You don't specify dnspod api key and key id yet." _err "Please create you key and try again." return 1 fi - + REST_API=$DP_Api - + #save the api key and email to the account conf file. _saveaccountconf DP_Id "$DP_Id" _saveaccountconf DP_Key "$DP_Key" - - + _debug "First detect the root zone" - if ! _get_root $fulldomain ; then + if ! _get_root $fulldomain; then _err "invalid domain" return 1 fi - - existing_records $_domain $_sub_domain + + existing_records $_domain $_sub_domain _debug count "$count" if [ "$?" != "0" ]; then _err "Error get existing records." @@ -51,15 +48,12 @@ dns_dp_add() { fi } - #fulldomain dns_dp_rm() { fulldomain=$1 } - - #usage: root sub #return if the sub record already exists. #echos the existing records count. @@ -68,26 +62,25 @@ existing_records() { _debug "Getting txt records" root=$1 sub=$2 - + if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&domain_id=$_domain_id&sub_domain=$_sub_domain"; then - return 1 + return 1 fi - - if printf "$response" | grep 'No records' ; then - count=0; - return 0 + + if printf "$response" | grep 'No records'; then + count=0 + return 0 fi - - if printf "$response" | grep "Action completed successful" >/dev/null ; then + + if printf "$response" | grep "Action completed successful" >/dev/null; then count=$(printf "$response" | grep 'TXT' | wc -l) record_id=$(printf "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) - return 0 + return 0 else _err "get existing records error." return 1 fi - - + count=0 } @@ -98,19 +91,18 @@ add_record() { sub=$2 txtvalue=$3 fulldomain=$sub.$root - + _info "Adding record" - + if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then return 1 fi - - if printf "$response" | grep "Action completed successful" ; then - + + if printf "$response" | grep "Action completed successful"; then + return 0 fi - - + return 1 #error } @@ -121,24 +113,21 @@ update_record() { sub=$2 txtvalue=$3 fulldomain=$sub.$root - + _info "Updating record" - + if ! _rest POST "Record.Modify" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认&record_id=$record_id"; then return 1 fi - - if printf "$response" | grep "Action completed successful" ; then - + + if printf "$response" | grep "Action completed successful"; then + return 0 fi - + return 1 #error } - - - #################### Private functions bellow ################################## #_acme-challenge.www.domain.com #returns @@ -153,14 +142,14 @@ _get_root() { h=$(printf $domain | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid - return 1; + return 1 fi - + if ! _rest POST "Domain.Info" "login_token=$DP_Id,$DP_Key&format=json&domain=$h"; then return 1 fi - - if printf "$response" | grep "Action completed successful" >/dev/null ; then + + if printf "$response" | grep "Action completed successful" >/dev/null; then _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then @@ -178,7 +167,6 @@ _get_root() { return 1 } - #Usage: method URI data _rest() { m=$1 @@ -186,16 +174,16 @@ _rest() { data="$3" _debug $ep url="$REST_API/$ep" - + _debug url "$url" - + if [ "$data" ]; then _debug2 data "$data" response="$(_post $data "$url")" else response="$(_get "$url")" fi - + if [ "$?" != "0" ]; then _err "error $ep" return 1 @@ -203,5 +191,3 @@ _rest() { _debug2 response "$response" return 0 } - - diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh old mode 100644 new mode 100755 From f530a5074be442512ff7181b0c4f4a6ead293d9a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 20:05:52 +0800 Subject: [PATCH 0427/1348] fix CI exit code --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6b71b4b8..f363dbef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,4 @@ script: - curl -sSL $SHFMT_URL -o ~/shfmt - chmod +x ~/shfmt - ~/shfmt -l -w -i 2 . - - git diff --exit-code || echo "Run shfmt to fix the formatting issues" + - git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) From 95e06de5ded62826ef503d05121eadf7f9cb6c66 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 20:45:57 +0800 Subject: [PATCH 0428/1348] fix for shellcheck --- acme.sh | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/acme.sh b/acme.sh index 47a4f6d0..cba4905b 100755 --- a/acme.sh +++ b/acme.sh @@ -119,7 +119,7 @@ _dlg_versions() { _log() { [ -z "$LOG_FILE" ] && return - _printargs "$@" >>$LOG_FILE + _printargs "$@" >>"$LOG_FILE" } _info() { @@ -229,12 +229,12 @@ _getfield() { _ffi=$_findex while [ "$_ffi" -gt "0" ]; do - _fv="$(echo "$_str" | cut -d $_sep -f $_ffi)" + _fv="$(echo "$_str" | cut -d $_sep -f "$_ffi")" if [ "$_fv" ]; then printf -- "%s" "$_fv" return 0 fi - _ffi="$(_math $_ffi - 1)" + _ffi="$(_math "$_ffi" - 1)" done printf -- "%s" "$_str" @@ -312,21 +312,21 @@ _h2b() { fi printf "\x$h" else - ic="$(printf $hex | cut -c $i)" - jc="$(printf $hex | cut -c $j)" + ic="$(printf "%s" "$hex" | cut -c $i)" + jc="$(printf "%s" "$hex" | cut -c $j)" if [ -z "$ic$jc" ]; then break fi ic="$(_h_char_2_dec "$ic")" jc="$(_h_char_2_dec "$jc")" - printf '\'"$(printf %o "$(_math $ic \* 16 + $jc)")" + printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")" fi if [ "$uselet" ]; then let "i+=2" >/dev/null let "j+=2" >/dev/null else - i="$(_math $i + 2)" - j="$(_math $j + 2)" + i="$(_math "$i" + 2)" + j="$(_math "$j" + 2)" fi done } @@ -419,9 +419,9 @@ _digest() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - openssl dgst -$alg -hex | cut -d = -f 2 | tr -d ' ' + openssl dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' else - openssl dgst -$alg -binary | _base64 + openssl dgst -"$alg" -binary | _base64 fi else _err "$alg is not supported yet" @@ -444,9 +444,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - openssl dgst -$alg -hmac "$hmac_sec" | cut -d = -f 2 | tr -d ' ' + openssl dgst -"$alg" -hmac "$hmac_sec" | cut -d = -f 2 | tr -d ' ' else - openssl dgst -$alg -hmac "$hmac_sec" -binary | _base64 + openssl dgst -"$alg" -hmac "$hmac_sec" -binary | _base64 fi else _err "$alg is not supported yet" @@ -516,7 +516,7 @@ _createkey() { f="$2" eccname="$length" if _startswith "$length" "ec-"; then - length=$(printf $length | cut -d '-' -f 2-100) + length=$(printf "$length" | cut -d '-' -f 2-100) if [ "$length" = "256" ]; then eccname="prime256v1" @@ -962,22 +962,22 @@ _calcjwk() { pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" - xlen="$(printf "$pubtext" | tr -d ':' | wc -c)" + xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" xlen=$(_math $xlen / 4) _debug3 xlen "$xlen" xend=$(_math "$xlen" + 1) - x="$(printf $pubtext | cut -d : -f 2-$xend)" + x="$(printf "%s" "$pubtext" | cut -d : -f 2-$xend)" _debug3 x "$x" - x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)" + x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _urlencode)" _debug3 x64 "$x64" xend=$(_math "$xend" + 1) - y="$(printf $pubtext | cut -d : -f $xend-10000)" + y="$(printf "%s" "$pubtext" | cut -d : -f $xend-10000)" _debug3 y "$y" - y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)" + y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _urlencode)" _debug3 y64 "$y64" jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' @@ -1240,7 +1240,7 @@ _send_signed_request() { protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" - protected64="$(printf "$protected" | _base64 | _urlencode)" + protected64="$(printf "%s" "$protected" | _base64 | _urlencode)" _debug3 protected64 "$protected64" if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then @@ -2392,7 +2392,7 @@ issue() { if [ -f "$DOMAIN_CONF" ]; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(_time) -lt $Le_NextRenewTime ]; then + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then _saved_domain=$(_readdomainconf Le_Domain) _debug _saved_domain "$_saved_domain" _saved_alt=$(_readdomainconf Le_Alt) @@ -2529,7 +2529,7 @@ issue() { keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" - if printf "$response" | grep '"status":"valid"' >/dev/null 2>&1; then + if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then _info "$d is already verified, skip." keyauthorization=$STATE_VERIFIED _debug keyauthorization "$keyauthorization" From f9a6988ece012b5291ae47374afb2bacadd1425a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 21:06:22 +0800 Subject: [PATCH 0429/1348] fix for shellcheck --- acme.sh | 57 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/acme.sh b/acme.sh index cba4905b..16fb1b04 100755 --- a/acme.sh +++ b/acme.sh @@ -306,7 +306,7 @@ _h2b() { _debug3 _URGLY_PRINTF "$_URGLY_PRINTF" while true; do if [ -z "$_URGLY_PRINTF" ]; then - h="$(printf $hex | cut -c $i-$j)" + h="$(printf "%s" "$hex" | cut -c $i-$j)" if [ -z "$h" ]; then break fi @@ -479,7 +479,7 @@ _sign() { if ! _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" - _err "Key content:$(cat "$keyfile" | wc -l) lises" + _err "Key content:$(wc -l <"$keyfile") lises" return 1 fi _debug3 "_signedECText" "$_signedECText" @@ -516,7 +516,7 @@ _createkey() { f="$2" eccname="$length" if _startswith "$length" "ec-"; then - length=$(printf "$length" | cut -d '-' -f 2-100) + length=$(printf "%s" "$length" | cut -d '-' -f 2-100) if [ "$length" = "256" ]; then eccname="prime256v1" @@ -608,10 +608,10 @@ _createcsr() { #single domain _info "Single domain" "$domain" else - domainlist="$(_idn $domainlist)" + domainlist="$(_idn "$domainlist")" _debug2 domainlist "$domainlist" if _contains "$domainlist" ","; then - alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" + alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" else alt="DNS:$domainlist" fi @@ -803,7 +803,7 @@ createDomainKey() { length="$DEFAULT_DOMAIN_KEY_LENGTH" fi - _initpath $domain "$length" + _initpath "$domain" "$length" if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then _createkey "$length" "$CERT_KEY_PATH" @@ -849,18 +849,17 @@ createCSR() { } _urlencode() { - __n=$(cat) - echo $__n | tr '/+' '_-' | tr -d '= ' + tr '/+' '_-' | tr -d '= ' } _time2str() { #BSD - if date -u -d@$1 2>/dev/null; then + if date -u -d@"$1" 2>/dev/null; then return fi #Linux - if date -u -r $1 2>/dev/null; then + if date -u -r "$1" 2>/dev/null; then return fi @@ -905,16 +904,16 @@ _calcjwk() { EC_SIGN="" if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "RSA key" - pub_exp=$(openssl rsa -in $keyfile -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) + pub_exp=$(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 pub_exp=0$pub_exp fi _debug3 pub_exp "$pub_exp" - e=$(echo $pub_exp | _h2b | _base64) + e=$(echo "$pub_exp" | _h2b | _base64) _debug3 e "$e" - modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2) + modulus=$(openssl rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' @@ -926,12 +925,12 @@ _calcjwk() { elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" EC_SIGN="1" - crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" - crv_oid="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv_oid="$(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" case "${crv_oid}" in "prime256v1") @@ -951,15 +950,15 @@ _calcjwk() { _debug3 crv "$crv" fi - pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + pubi="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math $pubi + 1) _debug3 pubi "$pubi" - pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + pubj="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math $pubj - 1) _debug3 pubj "$pubj" - pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + pubtext="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" @@ -967,14 +966,14 @@ _calcjwk() { _debug3 xlen "$xlen" xend=$(_math "$xlen" + 1) - x="$(printf "%s" "$pubtext" | cut -d : -f 2-$xend)" + x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")" _debug3 x "$x" x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _urlencode)" _debug3 x64 "$x64" xend=$(_math "$xend" + 1) - y="$(printf "%s" "$pubtext" | cut -d : -f $xend-10000)" + y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)" _debug3 y "$y" y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _urlencode)" @@ -1148,9 +1147,9 @@ _get() { fi _debug "_CURL" "$_CURL" if [ "$onlyheader" ]; then - $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url + $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" else - $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url + $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" fi ret=$? if [ "$ret" != "0" ]; then @@ -1167,9 +1166,9 @@ _get() { fi _debug "_WGET" "$_WGET" if [ "$onlyheader" ]; then - $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g' + $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' else - $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url + $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url" fi ret=$? if [ "$_ret" = "8" ]; then @@ -1192,9 +1191,9 @@ _head_n() { } _tail_n() { - if ! tail -n $1 2>/dev/null; then + if ! tail -n "$1" 2>/dev/null; then #fix for solaris - tail -$1 + tail -"$1" fi } @@ -1207,7 +1206,7 @@ _send_signed_request() { if [ -z "$keyfile" ]; then keyfile="$ACCOUNT_KEY_PATH" fi - _debug url $url + _debug url "$url" _debug payload "$payload" if ! _calcjwk "$keyfile"; then @@ -1215,7 +1214,7 @@ _send_signed_request() { fi payload64=$(printf "%s" "$payload" | _base64 | _urlencode) - _debug3 payload64 $payload64 + _debug3 payload64 "$payload64" if [ -z "$_CACHED_NONCE" ]; then _debug2 "Get nonce." @@ -1255,7 +1254,7 @@ _send_signed_request() { body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" _debug3 body "$body" - response="$(_post "$body" $url "$needbase64")" + response="$(_post "$body" "$url" "$needbase64")" _CACHED_NONCE="" if [ "$?" != "0" ]; then _err "Can not post to $url" From 79a267ab08c70912de7a9c040faa32554b5243ce Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 21:18:47 +0800 Subject: [PATCH 0430/1348] fix for shellcheck --- acme.sh | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/acme.sh b/acme.sh index 16fb1b04..71742fab 100755 --- a/acme.sh +++ b/acme.sh @@ -951,18 +951,18 @@ _calcjwk() { fi pubi="$(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" pubj="$(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" pubtext="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" - xlen=$(_math $xlen / 4) + xlen=$(_math "$xlen" / 4) _debug3 xlen "$xlen" xend=$(_math "$xlen" + 1) @@ -1135,7 +1135,7 @@ _get() { url="$1" onlyheader="$2" t="$3" - _debug url $url + _debug url "$url" _debug "timeout" "$t" _inithttp @@ -1187,7 +1187,7 @@ _get() { } _head_n() { - head -n $1 + head -n "$1" } _tail_n() { @@ -1219,7 +1219,7 @@ _send_signed_request() { if [ -z "$_CACHED_NONCE" ]; then _debug2 "Get nonce." nonceurl="$API/directory" - _headers="$(_get $nonceurl "onlyheader")" + _headers="$(_get "$nonceurl" "onlyheader")" if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." @@ -1268,8 +1268,8 @@ _send_signed_request() { _debug2 responseHeaders "$responseHeaders" _debug2 response "$response" - code="$(grep "^HTTP" $HTTP_HEADER | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" - _debug code $code + code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug code "$code" _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" @@ -1293,23 +1293,23 @@ _setopt() { if grep -n "^$__opt$__sep" "$__conf" >/dev/null; then _debug3 OK if _contains "$__val" "&"; then - __val="$(echo $__val | sed 's/&/\\&/g')" + __val="$(echo "$__val" | sed 's/&/\\&/g')" fi - text="$(cat $__conf)" + text="$(cat "$__conf")" echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then if _contains "$__val" "&"; then - __val="$(echo $__val | sed 's/&/\\&/g')" + __val="$(echo "$__val" | sed 's/&/\\&/g')" fi - text="$(cat $__conf)" + text="$(cat "$__conf")" echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" else _debug3 APP echo "$__opt$__sep$__val$__end" >>"$__conf" fi - _debug2 "$(grep -n "^$__opt$__sep" $__conf)" + _debug2 "$(grep -n "^$__opt$__sep" "$__conf")" } #_save_conf file key value @@ -1342,7 +1342,7 @@ _read_conf() { _sdkey="$2" if [ -f "$_r_c_f" ]; then ( - eval $(grep "^$_sdkey *=" "$_r_c_f") + eval "$(grep "^$_sdkey *=" "$_r_c_f")" eval "printf \"%s\" \"\$$_sdkey\"" ) else @@ -1493,7 +1493,7 @@ _sleep() { while [ "$_sleep_c" -ge "0" ]; do printf "\r \r" __green "$_sleep_c" - _sleep_c="$(_math $_sleep_c - 1)" + _sleep_c="$(_math "$_sleep_c" - 1)" sleep 1 done printf "\r" @@ -1816,7 +1816,7 @@ _apachePath() { if [ "$APACHE_HTTPD_CONF" ]; then _saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF" httpdconf="$APACHE_HTTPD_CONF" - httpdconfname="$(basename $httpdconfname)" + httpdconfname="$(basename "$httpdconfname")" else httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"')" _debug httpdconfname "$httpdconfname" @@ -1828,12 +1828,12 @@ _apachePath() { if _startswith "$httpdconfname" '/'; then httpdconf="$httpdconfname" - httpdconfname="$(basename $httpdconfname)" + httpdconfname="$(basename "$httpdconfname")" else httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"')" _debug httpdroot "$httpdroot" httpdconf="$httpdroot/$httpdconfname" - httpdconfname="$(basename $httpdconfname)" + httpdconfname="$(basename "$httpdconfname")" fi fi _debug httpdconf "$httpdconf" @@ -1974,10 +1974,10 @@ _clearupdns() { ventries=$(echo "$vlist" | tr ',' ' ') for ventry in $ventries; do - d=$(echo $ventry | cut -d $sep -f 1) - keyauthorization=$(echo $ventry | cut -d $sep -f 2) - vtype=$(echo $ventry | cut -d $sep -f 4) - _currentRoot=$(echo $ventry | cut -d $sep -f 5) + d=$(echo "$ventry" | cut -d $sep -f 1) + keyauthorization=$(echo "$ventry" | cut -d $sep -f 2) + vtype=$(echo "$ventry" | cut -d $sep -f 4) + _currentRoot=$(echo "$ventry" | cut -d $sep -f 5) if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." From 0c944a03fee3212e83ca3a6b9b9b1ffbd4c298c5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 21:26:35 +0800 Subject: [PATCH 0431/1348] fix shellcheck warnings --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 71742fab..9be912be 100755 --- a/acme.sh +++ b/acme.sh @@ -1429,11 +1429,11 @@ _startserver() { if _contains "$nchelp" "nmap.org"; then _debug "Using ncat: nmap.org" if [ "$DEBUG" ]; then - if printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort; then + if printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC $Le_HTTPPort; then return fi else - if printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort >/dev/null 2>&1; then + if printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC $Le_HTTPPort >/dev/null 2>&1; then return fi fi @@ -1442,12 +1442,12 @@ _startserver() { # while true ; do if [ "$DEBUG" ]; then - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort + if ! printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC -p $Le_HTTPPort; then + printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC $Le_HTTPPort fi else - if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort >/dev/null 2>&1; then - printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort >/dev/null 2>&1 + if ! printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC -p $Le_HTTPPort >/dev/null 2>&1; then + printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC $Le_HTTPPort >/dev/null 2>&1 fi fi if [ "$?" != "0" ]; then From d5ec5f80ffbdaa37a90c32d6613140b7d806db26 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 21:44:46 +0800 Subject: [PATCH 0432/1348] fix shellcheck warnings --- acme.sh | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/acme.sh b/acme.sh index 9be912be..17746db0 100755 --- a/acme.sh +++ b/acme.sh @@ -1429,11 +1429,11 @@ _startserver() { if _contains "$nchelp" "nmap.org"; then _debug "Using ncat: nmap.org" if [ "$DEBUG" ]; then - if printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC $Le_HTTPPort; then + if printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC "$Le_HTTPPort"; then return fi else - if printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC $Le_HTTPPort >/dev/null 2>&1; then + if printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC "$Le_HTTPPort" >/dev/null 2>&1; then return fi fi @@ -1442,12 +1442,12 @@ _startserver() { # while true ; do if [ "$DEBUG" ]; then - if ! printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC -p $Le_HTTPPort; then - printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC $Le_HTTPPort + if ! printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC -p "$Le_HTTPPort"; then + printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC "$Le_HTTPPort" fi else - if ! printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC -p $Le_HTTPPort >/dev/null 2>&1; then - printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC $Le_HTTPPort >/dev/null 2>&1 + if ! printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC -p "$Le_HTTPPort" >/dev/null 2>&1; then + printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC "$Le_HTTPPort" >/dev/null 2>&1 fi fi if [ "$?" != "0" ]; then @@ -1555,14 +1555,14 @@ _starttlsserver() { #start openssl _debug "$__S_OPENSSL" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | $__S_OPENSSL -tlsextdebug) & + (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) & else - (printf "HTTP/1.1 200 OK\r\n\r\n$content" | $__S_OPENSSL >/dev/null 2>&1) & + (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL >/dev/null 2>&1) & fi serverproc="$!" sleep 1 - _debug serverproc $serverproc + _debug serverproc "$serverproc" } #file @@ -1998,20 +1998,20 @@ _clearupdns() { fi ( - if ! . $d_api; then + if ! . "$d_api"; then _err "Load file $d_api error. Please check your api file and try again." return 1 fi rmcommand="${_currentRoot}_rm" - if ! _exists $rmcommand; then + if ! _exists "$rmcommand"; then _err "It seems that your api file doesn't define $rmcommand" return 1 fi txtdomain="_acme-challenge.$d" - if ! $rmcommand $txtdomain; then + if ! $rmcommand "$txtdomain"; then _err "Error removing txt for domain:$txtdomain" return 1 fi @@ -2067,7 +2067,7 @@ _on_before_issue() { _currentRoot="" _addrIndex=1 for d in $alldomains; do - _debug "Check for domain" $d + _debug "Check for domain" "$d" _currentRoot="$(_getfield "$Le_Webroot" $_index)" _debug "_currentRoot" "$_currentRoot" _index=$(_math $_index + 1) @@ -3128,7 +3128,7 @@ list() { _sep="|" if [ "$_raw" ]; then - printf "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew\n" + printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew" for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$); do d=$(echo $d | cut -d '/' -f 1) ( @@ -3139,7 +3139,7 @@ list() { _initpath $d "$_isEcc" if [ -f "$DOMAIN_CONF" ]; then . "$DOMAIN_CONF" - printf "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr\n" + printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr" fi ) done @@ -3603,7 +3603,7 @@ _initconf() { #PDNS_Token=\"0123456789ABCDEF\" #PDNS_Ttl=60 - " >$ACCOUNT_CONF_PATH + " >"$ACCOUNT_CONF_PATH" fi } @@ -3747,7 +3747,7 @@ install() { chmod 700 "$LE_WORKING_DIR" - cp $PROJECT_ENTRY "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" + cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" if [ "$?" != "0" ]; then _err "Install failed, can not copy $PROJECT_ENTRY" @@ -3760,8 +3760,8 @@ install() { for subf in $_SUB_FOLDERS; do if [ -d "$subf" ]; then - mkdir -p $LE_WORKING_DIR/$subf - cp $subf/* $LE_WORKING_DIR/$subf/ + mkdir -p "$LE_WORKING_DIR/$subf" + cp "$subf"/* "$LE_WORKING_DIR"/"$subf"/ fi done @@ -3814,7 +3814,7 @@ uninstall() { _uninstallalias - rm -f $LE_WORKING_DIR/$PROJECT_ENTRY + rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY" _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." } @@ -3825,21 +3825,21 @@ _uninstallalias() { _profile="$(_detect_profile)" if [ "$_profile" ]; then _info "Uninstalling alias from: '$_profile'" - text="$(cat $_profile)" + text="$(cat "$_profile")" echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" >"$_profile" fi _csh_profile="$HOME/.cshrc" if [ -f "$_csh_profile" ]; then _info "Uninstalling alias from: '$_csh_profile'" - text="$(cat $_csh_profile)" + text="$(cat "$_csh_profile")" echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_csh_profile" fi _tcsh_profile="$HOME/.tcshrc" if [ -f "$_tcsh_profile" ]; then _info "Uninstalling alias from: '$_csh_profile'" - text="$(cat $_tcsh_profile)" + text="$(cat "$_tcsh_profile")" echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_tcsh_profile" fi @@ -3856,7 +3856,7 @@ cron() { return 1 fi ) - . $LE_WORKING_DIR/$PROJECT_ENTRY >/dev/null + . "$LE_WORKING_DIR/$PROJECT_ENTRY" >/dev/null if [ -t 1 ]; then __INTERACTIVE="1" @@ -4330,7 +4330,7 @@ _process() { HTTPS_INSECURE="1" ;; --ca-bundle) - _ca_bundle="$(readlink -f $2)" + _ca_bundle="$(readlink -f "$2")" CA_BUNDLE="$_ca_bundle" shift ;; From ca7202eb0a6a416cc4a2c8c243e5d07c44005c7c Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 21:56:50 +0800 Subject: [PATCH 0433/1348] fix shellcheck warnings --- acme.sh | 60 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/acme.sh b/acme.sh index 17746db0..1285e541 100755 --- a/acme.sh +++ b/acme.sh @@ -2195,7 +2195,7 @@ registeraccount() { } __calcAccountKeyHash() { - [ -f "$ACCOUNT_KEY_PATH" ] && cat "$ACCOUNT_KEY_PATH" | _digest sha256 + [ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH" } #keylength @@ -2244,7 +2244,7 @@ _regAccount() { fi if [ "$code" = "" ] || [ "$code" = '201' ]; then - echo "$response" >$ACCOUNT_JSON_PATH + echo "$response" >"$ACCOUNT_JSON_PATH" _info "Registered" elif [ "$code" = '409' ]; then _info "Already registered" @@ -2384,7 +2384,7 @@ issue() { _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then - _initpath $Le_Domain "$Le_Keylength" + _initpath "$Le_Domain" "$Le_Keylength" mkdir -p "$DOMAIN_PATH" fi @@ -2455,7 +2455,7 @@ issue() { _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then - if ! createDomainKey $Le_Domain $Le_Keylength; then + if ! createDomainKey "$Le_Domain" "$Le_Keylength"; then _err "Create domain key error." _clearup _on_issue_err @@ -2482,7 +2482,7 @@ issue() { _index=1 _currentRoot="" for d in $alldomains; do - _info "Getting webroot for domain" $d + _info "Getting webroot for domain" "$d" _w="$(echo $Le_Webroot | cut -d , -f $_index)" _info _w "$_w" if [ "$_w" ]; then @@ -2520,17 +2520,17 @@ issue() { return 1 fi token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" - _debug token $token + _debug token "$token" uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" - _debug uri $uri + _debug uri "$uri" keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then _info "$d is already verified, skip." - keyauthorization=$STATE_VERIFIED + keyauthorization="$STATE_VERIFIED" _debug keyauthorization "$keyauthorization" fi @@ -2545,10 +2545,10 @@ issue() { dnsadded="" ventries=$(echo "$vlist" | tr ',' ' ') for ventry in $ventries; do - d=$(echo $ventry | cut -d $sep -f 1) - keyauthorization=$(echo $ventry | cut -d $sep -f 2) - vtype=$(echo $ventry | cut -d $sep -f 4) - _currentRoot=$(echo $ventry | cut -d $sep -f 5) + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." @@ -2578,18 +2578,18 @@ issue() { fi ( - if ! . $d_api; then + if ! . "$d_api"; then _err "Load file $d_api error. Please check your api file and try again." return 1 fi addcommand="${_currentRoot}_add" - if ! _exists $addcommand; then + if ! _exists "$addcommand"; then _err "It seems that your api file is not correct, it must have a function named: $addcommand" return 1 fi - if ! $addcommand $txtdomain $txt; then + if ! $addcommand "$txtdomain" "$txt"; then _err "Error add txt for domain:$txtdomain" return 1 fi @@ -2617,13 +2617,13 @@ issue() { if [ "$dnsadded" = '1' ]; then if [ -z "$Le_DNSSleep" ]; then - Le_DNSSleep=$DEFAULT_DNS_SLEEP + Le_DNSSleep="$DEFAULT_DNS_SLEEP" else _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" fi _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" - _sleep $Le_DNSSleep + _sleep "$Le_DNSSleep" fi _debug "ok, let's start to verify" @@ -2631,11 +2631,11 @@ issue() { _ncIndex=1 ventries=$(echo "$vlist" | tr ',' ' ') for ventry in $ventries; do - d=$(echo $ventry | cut -d $sep -f 1) - keyauthorization=$(echo $ventry | cut -d $sep -f 2) - uri=$(echo $ventry | cut -d $sep -f 3) - vtype=$(echo $ventry | cut -d $sep -f 4) - _currentRoot=$(echo $ventry | cut -d $sep -f 5) + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + uri=$(echo "$ventry" | cut -d "$sep" -f 3) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." @@ -2664,7 +2664,7 @@ issue() { fi serverproc="$!" sleep 1 - _debug serverproc $serverproc + _debug serverproc "$serverproc" else if [ "$_currentRoot" = "apache" ]; then @@ -2697,7 +2697,7 @@ issue() { if [ ! "$usingApache" ]; then if webroot_owner=$(_stat $_currentRoot); then _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R $webroot_owner "$_currentRoot/.well-known" + chown -R "$webroot_owner" "$_currentRoot/.well-known" else _debug "not chaning owner/group of webroot" fi @@ -2740,7 +2740,7 @@ issue() { fi fi - if ! _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then + if ! _send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup @@ -2790,7 +2790,7 @@ issue() { status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') if [ "$status" = "valid" ]; then _info "Success" - _stopserver $serverproc + _stopserver "$serverproc" serverproc="" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" break @@ -2909,7 +2909,7 @@ issue() { _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then - Le_RenewalDays=$MAX_RENEW + Le_RenewalDays="$MAX_RENEW" else _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" fi @@ -2934,12 +2934,12 @@ issue() { _cleardomainconf Le_Listen_V4 fi - Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60) + Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60) - Le_NextRenewTimeStr=$(_time2str $Le_NextRenewTime) + Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime") _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" - Le_NextRenewTime=$(_math $Le_NextRenewTime - 86400) + Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" _on_issue_success From 0c538f7527fdf8d9a8517c21ad02fd814f85df9a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 22:07:32 +0800 Subject: [PATCH 0434/1348] fix shellcheck warnings --- acme.sh | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/acme.sh b/acme.sh index 1285e541..1ea1cbf5 100755 --- a/acme.sh +++ b/acme.sh @@ -901,7 +901,6 @@ _calcjwk() { return 0 fi - EC_SIGN="" if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "RSA key" pub_exp=$(openssl rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) @@ -924,7 +923,6 @@ _calcjwk() { JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" - EC_SIGN="1" crv="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" @@ -1974,10 +1972,10 @@ _clearupdns() { ventries=$(echo "$vlist" | tr ',' ' ') for ventry in $ventries; do - d=$(echo "$ventry" | cut -d $sep -f 1) - keyauthorization=$(echo "$ventry" | cut -d $sep -f 2) - vtype=$(echo "$ventry" | cut -d $sep -f 4) - _currentRoot=$(echo "$ventry" | cut -d $sep -f 5) + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." @@ -1989,7 +1987,7 @@ _clearupdns() { continue fi - d_api="$(_findHook $d dnsapi $_currentRoot)" + d_api="$(_findHook "$d" dnsapi "$_currentRoot")" _debug d_api "$d_api" if [ -z "$d_api" ]; then @@ -2562,7 +2560,7 @@ issue() { txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)" _debug txt "$txt" - d_api="$(_findHook $d dnsapi $_currentRoot)" + d_api="$(_findHook "$d" dnsapi "$_currentRoot")" _debug d_api "$d_api" @@ -2570,8 +2568,8 @@ issue() { _info "Found domain api file: $d_api" else _err "Add the following TXT record:" - _err "Domain: '$(__green $txtdomain)'" - _err "TXT value: '$(__green $txt)'" + _err "Domain: '$(__green "$txtdomain")'" + _err "TXT value: '$(__green "$txt")'" _err "Please be aware that you prepend _acme-challenge. before your domain" _err "so the resulting subdomain will be: $txtdomain" continue @@ -2717,11 +2715,11 @@ issue() { #_debug2 _SAN_A "$_SAN_A" #create B - _hash_B="$(printf "%s" $keyauthorization | _digest "sha256" "hex")" + _hash_B="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")" _debug2 _hash_B "$_hash_B" - _x="$(echo $_hash_B | cut -c 1-32)" + _x="$(echo "$_hash_B" | cut -c 1-32)" _debug2 _x "$_x" - _y="$(echo $_hash_B | cut -c 33-64)" + _y="$(echo "$_hash_B" | cut -c 33-64)" _debug2 _y "$_y" #_SAN_B="$_x.$_y.ka.acme.invalid" @@ -2730,7 +2728,7 @@ issue() { _debug2 _SAN_B "$_SAN_B" _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" - _ncIndex="$(_math $_ncIndex + 1)" + _ncIndex="$(_math "$_ncIndex" + 1)" if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then _err "Start tls server error." _clearupwebbroot "$_currentRoot" "$removelevel" "$token" @@ -2762,7 +2760,7 @@ issue() { fi while true; do - waittimes=$(_math $waittimes + 1) + waittimes=$(_math "$waittimes" + 1) if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then _err "$d:Timeout" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" @@ -2843,7 +2841,7 @@ issue() { fi _rcert="$response" - Le_LinkCert="$(grep -i '^Location.*$' $HTTP_HEADER | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ "$Le_LinkCert" ]; then @@ -2878,7 +2876,7 @@ issue() { fi if [ -z "$Le_LinkCert" ]; then - response="$(echo $response | _dbase64 "multiline" | _normalizeJson)" + response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)" _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" _on_issue_err return 1 @@ -2886,7 +2884,7 @@ issue() { _cleardomainconf "Le_Vlist" - Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') + Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') if ! _contains "$Le_LinkIssuer" ":"; then Le_LinkIssuer="$API$Le_LinkIssuer" fi From e799ef2977a829a875851e54f5063bf43564e565 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 22:09:30 +0800 Subject: [PATCH 0435/1348] fix shellcheck warnings. --- acme.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 1ea1cbf5..f983ea77 100755 --- a/acme.sh +++ b/acme.sh @@ -2958,7 +2958,7 @@ renew() { _isEcc="$2" - _initpath $Le_Domain "$_isEcc" + _initpath "$Le_Domain" "$_isEcc" _info "$(__green "Renew: '$Le_Domain'")" if [ ! -f "$DOMAIN_CONF" ]; then @@ -2979,24 +2979,24 @@ renew() { if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" _info "Add '$(__red '--force')' to force to renew." - return $RENEW_SKIP + return "$RENEW_SKIP" fi IS_RENEW="1" issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" - res=$? + res="$?" if [ "$res" != "0" ]; then - return $res + return "$res" fi if [ "$Le_DeployHook" ]; then - deploy $Le_Domain "$Le_DeployHook" "$Le_Keylength" - res=$? + deploy "$Le_Domain" "$Le_DeployHook" "$Le_Keylength" + res="$?" fi IS_RENEW="" - return $res + return "$res" } #renewAll [stopRenewOnError] From 201aa24448531de8020334f4aa5320d975cd2ff8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 22:28:12 +0800 Subject: [PATCH 0436/1348] fix shellcheck warnings. --- acme.sh | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index f983ea77..b1e5ecbd 100755 --- a/acme.sh +++ b/acme.sh @@ -227,9 +227,9 @@ _getfield() { _sep="," fi - _ffi=$_findex + _ffi="$_findex" while [ "$_ffi" -gt "0" ]; do - _fv="$(echo "$_str" | cut -d $_sep -f "$_ffi")" + _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")" if [ "$_fv" ]; then printf -- "%s" "$_fv" return 0 @@ -3006,12 +3006,14 @@ renewAll() { _debug "_stopRenewOnError" "$_stopRenewOnError" _ret="0" - for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$); do - d=$(echo $d | cut -d '/' -f 1) + for d in "${CERT_HOME}"/*.*/; do + _debug d "$d" + d=$(basename "$d") + _debug d "$d" ( - if _endswith $d "$ECC_SUFFIX"; then - _isEcc=$(echo $d | cut -d "$ECC_SEP" -f 2) - d=$(echo $d | cut -d "$ECC_SEP" -f 1) + if _endswith "$d" "$ECC_SUFFIX"; then + _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2) + d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) fi renew "$d" "$_isEcc" ) @@ -3022,14 +3024,14 @@ renewAll() { _info "Skipped $d" elif [ "$_stopRenewOnError" ]; then _err "Error renew $d, stop now." - return $rc + return "$rc" else _ret="$rc" _err "Error renew $d, Go ahead to next one." fi fi done - return $_ret + return "$_ret" } #csr webroot @@ -3127,12 +3129,13 @@ list() { _sep="|" if [ "$_raw" ]; then printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew" - for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$); do - d=$(echo $d | cut -d '/' -f 1) + for d in "${CERT_HOME}"/*.*/; do + d=$(basename "$d") + _debug d "$d" ( - if _endswith $d "$ECC_SUFFIX"; then - _isEcc=$(echo $d | cut -d "$ECC_SEP" -f 2) - d=$(echo $d | cut -d "$ECC_SEP" -f 1) + if _endswith "$d" "$ECC_SUFFIX"; then + _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2) + d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) fi _initpath $d "$_isEcc" if [ -f "$DOMAIN_CONF" ]; then From 44edb2bd2ffa738bb98d31c53588693dd5ca341a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 22:35:30 +0800 Subject: [PATCH 0437/1348] fix shellcheck warnings --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index b1e5ecbd..e4c377dc 100755 --- a/acme.sh +++ b/acme.sh @@ -1878,7 +1878,7 @@ _setApache() { #test the conf first _info "Checking if there is an error in the apache config file before starting." - if ! _exec $_APACHECTL -t >/dev/null; then + if ! _exec "$_APACHECTL" -t >/dev/null; then _exec_err _err "The apache config file has error, please fix it first, then try again." _err "Don't worry, there is nothing changed to your system." @@ -1940,7 +1940,7 @@ Allow from all chmod 755 "$ACME_DIR" fi - if ! _exec $_APACHECTL graceful; then + if ! _exec "$_APACHECTL" graceful; then _exec_err _err "$_APACHECTL graceful error, please contact me." _restoreApache @@ -1951,7 +1951,7 @@ Allow from all } _clearup() { - _stopserver $serverproc + _stopserver "$serverproc" serverproc="" _restoreApache _clearupdns @@ -2693,7 +2693,7 @@ issue() { fi 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" chown -R "$webroot_owner" "$_currentRoot/.well-known" else @@ -2772,7 +2772,7 @@ issue() { _debug "sleep 2 secs to verify" sleep 2 _debug "checking" - response="$(_get $uri)" + response="$(_get "$uri")" if [ "$?" != "0" ]; then _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" @@ -3663,9 +3663,9 @@ _installalias() { _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" if [ "$_upgrading" ] && [ "$_upgrading" = "1" ]; then - echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile" - echo "$(cat $_envfile)" | sed "s|^alias le.*$||" >"$_envfile" - echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" >"$_envfile" + echo "$(cat "$_envfile")" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile" + echo "$(cat "$_envfile")" | sed "s|^alias le.*$||" >"$_envfile" + echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile" fi _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" From b9091e14b370db69747ec5538005fbe68dec2122 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 21:50:59 +0100 Subject: [PATCH 0438/1348] adding DNSMadeEasy API --- README.md | 1 + dnsapi/README.md | 19 ++++++ dnsapi/dns_me.sh | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100755 dnsapi/dns_me.sh diff --git a/README.md b/README.md index 79b5a52f..104532bf 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,7 @@ You don't have do anything manually! 8. 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.) 9. LuaDNS.com API +10. DNSMadeEasy.com API ##### More APIs are coming soon... diff --git a/dnsapi/README.md b/dnsapi/README.md index 19769111..7eff6de1 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -154,4 +154,23 @@ acme.sh --issue --dns dns_lua --dnssleep 3 -d example.com -d www.example.c The `LUA_Key` and `LUA_Email` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. +## Use DNSMadeEasy domain API + +Get your API credentials at https://cp.dnsmadeeasy.com/account/info + +``` +export ME_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" + +export ME_Secret="qdfqsdfkjdskfj" + +``` + +To issue a cert: +``` +acme.sh --issue --dns dns_me --dnssleep 3 -d example.com -d www.example.com +``` + +The `ME_Key` and `ME_Secret` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. + + diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh new file mode 100755 index 00000000..fffd8d49 --- /dev/null +++ b/dnsapi/dns_me.sh @@ -0,0 +1,148 @@ +#!/bin/sh + +# bug reports to dev@1e.ca + +# ME_Key=qmlkdjflmkqdjf +# ME_Secret=qmsdlkqmlksdvnnpae + +ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_me_add(){ + fulldomain=$1 + txtvalue=$2 + + if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ] ; then + _err "You didn't specify DNSMadeEasy api key and secret yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf ME_Key "$ME_Key" + _saveaccountconf ME_Secret "$ME_Secret" + + _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" + _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" + + if ! printf "$response" | grep \"totalRecords\": > /dev/null ; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o \"totalRecords\":[^,]* | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ] ; then + _info "Adding record" + if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep id: > /dev/null ; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | cut -d : -f 2 | head -n 1) + _debug "record_id" $record_id + + _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" + if [ "$?" = "0" ]; then + _info "Updated" + #todo: check if the record takes effect + return 0; + fi + _err "Update error" + return 1 + fi + +} + + +#fulldomain +dns_me_rm() { + fulldomain=$1 + +} + + +#################### Private functions bellow ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while [ '1' ] ; do + h=$(printf $domain | cut -d . -f $i-100) + if [ -z "$h" ] ; then + #not valid + return 1; + fi + + if ! _me_rest GET "name?domainname=$h" ; then + return 1 + fi + + if printf $response | grep \"name\":\"$h\" >/dev/null ; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | head -n 1 | cut -d : -f 2 ) + if [ "$_domain_id" ] ; then + _sub_domain=$(printf $domain | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(expr $i + 1) + done + return 1 +} + +_me_rest() { + m=$1 + ep="$2" + data="$3" + _debug $ep + + cdate=$(date -Ru) + hmac=$(printf "$cdate" | openssl dgst -sha1 -hmac $ME_Secret | cut -d = -f 2 | tr -d ' ') + + _H1="x-dnsme-apiKey: $ME_Key" + _H2="x-dnsme-requestDate: $cdate" + _H3="x-dnsme-hmac: $hmac" + + if [ "$data" ] ; then + _debug data "$data" + response="$(_post "$data" "$ME_Api/$ep" "" $m)" + else + response="$(_get "$ME_Api/$ep")" + fi + + if [ "$?" != "0" ] ; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + + From 3ec72fcee959954b6bcbf317ba015cd77ed9994f Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 22:16:00 +0100 Subject: [PATCH 0439/1348] bugfix --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index fffd8d49..4234ac9c 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -46,7 +46,7 @@ dns_me_add(){ if [ "$count" = "0" ] ; then _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep id: > /dev/null ; then + if [ "$?" = "0" ]; then _info "Added" #todo: check if the record takes effect return 0 From cd90062850161b943b01695379b003ed754f5c9b Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 22:16:53 +0100 Subject: [PATCH 0440/1348] better bugfix --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 4234ac9c..b379fe98 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -46,7 +46,7 @@ dns_me_add(){ if [ "$count" = "0" ] ; then _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if [ "$?" = "0" ]; then + if printf -- "%s" "$response" | grep \"id\": > /dev/null ; then _info "Added" #todo: check if the record takes effect return 0 From eb23549cd635cdf4c8231e709f45737aaa7a5697 Mon Sep 17 00:00:00 2001 From: nytral Date: Tue, 8 Nov 2016 14:13:05 +0100 Subject: [PATCH 0441/1348] s/bash/sh/ --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index b379fe98..d8dd7e45 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh # bug reports to dev@1e.ca From 2ea5b283a84c9efba1ac2171e477ea6968a878e0 Mon Sep 17 00:00:00 2001 From: nytral Date: Tue, 8 Nov 2016 15:56:46 +0100 Subject: [PATCH 0442/1348] _hmac use and generic date --- dnsapi/dns_me.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index d8dd7e45..3135718e 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -123,8 +123,8 @@ _me_rest() { data="$3" _debug $ep - cdate=$(date -Ru) - hmac=$(printf "$cdate" | openssl dgst -sha1 -hmac $ME_Secret | cut -d = -f 2 | tr -d ' ') + cdate=$(date -u +"%a, %d %b %Y %T %Z") + hmac=$(printf "$cdate" | _hmac sha1 "$ME_Secret" 1) _H1="x-dnsme-apiKey: $ME_Key" _H2="x-dnsme-requestDate: $cdate" From dec90f7e5eca1af818d6a7f59d4aca2df56f5d16 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 9 Nov 2016 23:15:08 +0800 Subject: [PATCH 0443/1348] format dns_me api --- dnsapi/dns_me.sh | 66 +++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 3135718e..abc17475 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -10,43 +10,43 @@ ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_me_add(){ +dns_me_add() { fulldomain=$1 txtvalue=$2 - - if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ] ; then + + if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ]; then _err "You didn't specify DNSMadeEasy api key and secret yet." _err "Please create you key and try again." return 1 fi - + #save the api key and email to the account conf file. _saveaccountconf ME_Key "$ME_Key" _saveaccountconf ME_Secret "$ME_Secret" - + _debug "First detect the root zone" - if ! _get_root $fulldomain ; then + 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" _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" - - if ! printf "$response" | grep \"totalRecords\": > /dev/null ; then + + if ! printf "$response" | grep \"totalRecords\": >/dev/null; then _err "Error" return 1 fi - + count=$(printf "%s\n" "$response" | _egrep_o \"totalRecords\":[^,]* | cut -d : -f 2) _debug count "$count" - if [ "$count" = "0" ] ; then + if [ "$count" = "0" ]; then _info "Adding record" - if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep \"id\": > /dev/null ; then + if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep \"id\": >/dev/null; then _info "Added" #todo: check if the record takes effect return 0 @@ -60,19 +60,18 @@ dns_me_add(){ _info "Updating record" record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | cut -d : -f 2 | head -n 1) _debug "record_id" $record_id - - _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" + + _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" if [ "$?" = "0" ]; then _info "Updated" #todo: check if the record takes effect - return 0; + return 0 fi _err "Update error" return 1 fi - -} +} #fulldomain dns_me_rm() { @@ -80,7 +79,6 @@ dns_me_rm() { } - #################### Private functions bellow ################################## #_acme-challenge.www.domain.com #returns @@ -91,20 +89,20 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ] ; do + while [ '1' ]; do h=$(printf $domain | cut -d . -f $i-100) - if [ -z "$h" ] ; then + if [ -z "$h" ]; then #not valid - return 1; + return 1 fi - - if ! _me_rest GET "name?domainname=$h" ; then + + if ! _me_rest GET "name?domainname=$h"; then return 1 fi - - if printf $response | grep \"name\":\"$h\" >/dev/null ; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | head -n 1 | cut -d : -f 2 ) - if [ "$_domain_id" ] ; then + + if printf $response | grep \"name\":\"$h\" >/dev/null; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | head -n 1 | cut -d : -f 2) + if [ "$_domain_id" ]; then _sub_domain=$(printf $domain | cut -d . -f 1-$p) _domain=$h return 0 @@ -124,25 +122,23 @@ _me_rest() { _debug $ep cdate=$(date -u +"%a, %d %b %Y %T %Z") - hmac=$(printf "$cdate" | _hmac sha1 "$ME_Secret" 1) + hmac=$(printf "$cdate" | _hmac sha1 "$ME_Secret" 1) _H1="x-dnsme-apiKey: $ME_Key" _H2="x-dnsme-requestDate: $cdate" _H3="x-dnsme-hmac: $hmac" - - if [ "$data" ] ; then + + if [ "$data" ]; then _debug data "$data" response="$(_post "$data" "$ME_Api/$ep" "" $m)" else response="$(_get "$ME_Api/$ep")" fi - - if [ "$?" != "0" ] ; then + + if [ "$?" != "0" ]; then _err "error $ep" return 1 fi _debug2 response "$response" return 0 } - - From a2e62f8e1d05fe200c079a832388ad2419b9eba6 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 9 Nov 2016 23:44:24 +0800 Subject: [PATCH 0444/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 104532bf..258cc027 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# An ACME Shell script: acme.sh +# An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) - An ACME protocol client written purely in Shell (Unix shell) language. - Fully ACME protocol implementation. - Simple, powerful and very easy to use. You only need 3 minutes to learn. From e591d5cfe4a9a990adbce3a194771a9b9ee113f5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 21:13:33 +0800 Subject: [PATCH 0445/1348] fix shellcheck warnings --- acme.sh | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/acme.sh b/acme.sh index e4c377dc..255c609b 100755 --- a/acme.sh +++ b/acme.sh @@ -27,7 +27,7 @@ STAGE_CA="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" VTYPE_TLS="tls-sni-01" -VTYPE_TLS2="tls-sni-02" +#VTYPE_TLS2="tls-sni-02" LOCAL_ANY_ADDRESS="0.0.0.0" @@ -247,10 +247,10 @@ _exists() { _usage "Usage: _exists cmd" return 1 fi - if type command >/dev/null 2>&1; then + if command >/dev/null 2>&1; then command -v "$cmd" >/dev/null 2>&1 - else - type "$cmd" >/dev/null 2>&1 + else which >/dev/null 2>&1; + which "$cmd" >/dev/null 2>&1 fi ret="$?" _debug3 "$cmd exists=$ret" @@ -259,7 +259,7 @@ _exists() { #a + b _math() { - expr "$@" + $(( "$@" )) } _h_char_2_dec() { @@ -299,10 +299,7 @@ _h2b() { hex=$(cat) i=1 j=2 - if _exists let; then - uselet="1" - fi - _debug3 uselet "$uselet" + _debug3 _URGLY_PRINTF "$_URGLY_PRINTF" while true; do if [ -z "$_URGLY_PRINTF" ]; then @@ -310,7 +307,7 @@ _h2b() { if [ -z "$h" ]; then break fi - printf "\x$h" + printf "\x$h%s" else ic="$(printf "%s" "$hex" | cut -c $i)" jc="$(printf "%s" "$hex" | cut -c $j)" @@ -321,13 +318,10 @@ _h2b() { jc="$(_h_char_2_dec "$jc")" printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")" fi - if [ "$uselet" ]; then - let "i+=2" >/dev/null - let "j+=2" >/dev/null - else - i="$(_math "$i" + 2)" - j="$(_math "$j" + 2)" - fi + + i="$(_math "$i" + 2)" + j="$(_math "$j" + 2)" + done } @@ -3006,9 +3000,9 @@ renewAll() { _debug "_stopRenewOnError" "$_stopRenewOnError" _ret="0" - for d in "${CERT_HOME}"/*.*/; do - _debug d "$d" - d=$(basename "$d") + for di in "${CERT_HOME}"/*.*/; do + _debug di "$di" + d=$(basename "$di") _debug d "$d" ( if _endswith "$d" "$ECC_SUFFIX"; then @@ -3129,15 +3123,15 @@ list() { _sep="|" if [ "$_raw" ]; then printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew" - for d in "${CERT_HOME}"/*.*/; do - d=$(basename "$d") + for di in "${CERT_HOME}"/*.*/; do + d=$(basename "$di") _debug d "$d" ( if _endswith "$d" "$ECC_SUFFIX"; then _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2) d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) fi - _initpath $d "$_isEcc" + _initpath "$d" "$_isEcc" if [ -f "$DOMAIN_CONF" ]; then . "$DOMAIN_CONF" printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr" @@ -3163,13 +3157,13 @@ deploy() { return 1 fi - _initpath $Le_Domain "$_isEcc" + _initpath "$Le_Domain" "$_isEcc" if [ ! -d "$DOMAIN_PATH" ]; then _err "Domain is not valid:'$Le_Domain'" return 1 fi - _deployApi="$(_findHook $Le_Domain deploy $Le_DeployHook)" + _deployApi="$(_findHook "$Le_Domain" deploy "$Le_DeployHook")" if [ -z "$_deployApi" ]; then _err "The deploy hook $Le_DeployHook is not found." return 1 @@ -3179,18 +3173,18 @@ deploy() { _savedomainconf Le_DeployHook "$Le_DeployHook" if ! ( - if ! . $_deployApi; then + if ! . "$_deployApi"; then _err "Load file $_deployApi error. Please check your api file and try again." return 1 fi d_command="${Le_DeployHook}_deploy" - if ! _exists $d_command; then + if ! _exists "$d_command"; then _err "It seems that your api file is not correct, it must have a function named: $d_command" return 1 fi - if ! $d_command $Le_Domain "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then + if ! $d_command "$Le_Domain" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then _err "Error deploy for domain:$Le_Domain" _on_issue_err return 1 From e3698edd1952b7777d7b2c438cd6ac6f3ee25fb5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 21:15:48 +0800 Subject: [PATCH 0446/1348] fix shellcheck warnings --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 255c609b..ed2bf90e 100755 --- a/acme.sh +++ b/acme.sh @@ -4046,7 +4046,7 @@ _process() { _dnssleep="" _listraw="" _stopRenewOnError="" - _insecure="" + #_insecure="" _ca_bundle="" _nocron="" _ecc="" @@ -4321,7 +4321,7 @@ _process() { _stopRenewOnError="1" ;; --insecure) - _insecure="1" + #_insecure="1" HTTPS_INSECURE="1" ;; --ca-bundle) From c4a375b3a5288b5abbb0ff73ad9b06d32f492565 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 21:22:48 +0800 Subject: [PATCH 0447/1348] fix shellcheck warnings. --- acme.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index ed2bf90e..79afb237 100755 --- a/acme.sh +++ b/acme.sh @@ -3364,7 +3364,7 @@ revoke() { _isEcc="$2" - _initpath $Le_Domain "$_isEcc" + _initpath "$Le_Domain" "$_isEcc" if [ ! -f "$DOMAIN_CONF" ]; then _err "$Le_Domain is not a issued domain, skip." return 1 @@ -3387,10 +3387,10 @@ revoke() { if [ -f "$CERT_KEY_PATH" ]; then _info "Try domain key first." - if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then + if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then if [ -z "$response" ]; then _info "Revoke success." - rm -f $CERT_PATH + rm -f "$CERT_PATH" return 0 else _err "Revoke error by domain key." @@ -3403,10 +3403,10 @@ revoke() { _info "Try account key." - if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH"; then + if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then if [ -z "$response" ]; then _info "Revoke success." - rm -f $CERT_PATH + rm -f "$CERT_PATH" return 0 else _err "Revoke error." @@ -3450,11 +3450,11 @@ _deactivate() { fi _vtype="$(printf "%s\n" "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')" - _debug _vtype $_vtype + _debug _vtype "$_vtype" _info "Found $_vtype" uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" - _debug uri $uri + _debug uri "$uri" if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then _info "Skip $_vtype" @@ -3493,7 +3493,7 @@ deactivate() { if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ]; then continue fi - if ! _deactivate "$_d_dm" $_d_type; then + if ! _deactivate "$_d_dm" "$_d_type"; then return 1 fi done @@ -3562,7 +3562,7 @@ _initconf() { #USER_AGENT=\"$USER_AGENT\" -#USER_PATH="" +#USER_PATH= #dns api ####################### From 7ff7a7c527ca9aa6c02d7722717ede9dd8e50b37 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 21:31:16 +0800 Subject: [PATCH 0448/1348] fix shellcheck warnning --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 79afb237..705f5a9b 100755 --- a/acme.sh +++ b/acme.sh @@ -259,7 +259,7 @@ _exists() { #a + b _math() { - $(( "$@" )) + printf "%s" "$(( $@ ))" } _h_char_2_dec() { From 4bd31f4967fcd637087cbc423b650f9d8eb3a557 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 21:47:24 +0800 Subject: [PATCH 0449/1348] fix shellcheck warnings --- acme.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 705f5a9b..d050738a 100755 --- a/acme.sh +++ b/acme.sh @@ -3212,7 +3212,7 @@ installcert() { Le_RealFullChainPath="$6" _isEcc="$7" - _initpath $Le_Domain "$_isEcc" + _initpath "$Le_Domain" "$_isEcc" if [ ! -d "$DOMAIN_PATH" ]; then _err "Domain is not valid:'$Le_Domain'" return 1 @@ -3245,9 +3245,9 @@ _installcert() { Le_RealFullChainPath="" fi - _installed="0" + if [ "$Le_RealCertPath" ]; then - _installed=1 + _info "Installing cert to:$Le_RealCertPath" if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then cp "$Le_RealCertPath" "$Le_RealCertPath".bak @@ -3256,7 +3256,7 @@ _installcert() { fi if [ "$Le_RealCACertPath" ]; then - _installed=1 + _info "Installing CA to:$Le_RealCACertPath" if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ]; then echo "" >>"$Le_RealCACertPath" @@ -3270,7 +3270,7 @@ _installcert() { fi if [ "$Le_RealKeyPath" ]; then - _installed=1 + _info "Installing key to:$Le_RealKeyPath" if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak @@ -3279,7 +3279,7 @@ _installcert() { fi if [ "$Le_RealFullChainPath" ]; then - _installed=1 + _info "Installing full chain to:$Le_RealFullChainPath" if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak @@ -3288,7 +3288,7 @@ _installcert() { fi if [ "$Le_ReloadCmd" ]; then - _installed=1 + _info "Run Le_ReloadCmd: $Le_ReloadCmd" if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd"); then _info "$(__green "Reload success")" From e51bef6d12c4d80babbd6d24fcaef8dca7b3bbf4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 22:00:15 +0800 Subject: [PATCH 0450/1348] fix shellcheck warnings. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d050738a..5a42595f 100755 --- a/acme.sh +++ b/acme.sh @@ -316,7 +316,7 @@ _h2b() { fi ic="$(_h_char_2_dec "$ic")" jc="$(_h_char_2_dec "$jc")" - printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")" + printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" fi i="$(_math "$i" + 2)" From b97e1403891ac9f38911bea9baf8c77f6d12c502 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 22:07:49 +0800 Subject: [PATCH 0451/1348] fix shfmt warnings --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 5a42595f..bd61d11e 100755 --- a/acme.sh +++ b/acme.sh @@ -249,7 +249,7 @@ _exists() { fi if command >/dev/null 2>&1; then command -v "$cmd" >/dev/null 2>&1 - else which >/dev/null 2>&1; + elif which >/dev/null 2>&1; which "$cmd" >/dev/null 2>&1 fi ret="$?" @@ -259,7 +259,7 @@ _exists() { #a + b _math() { - printf "%s" "$(( $@ ))" + printf "%s" "$(($@))" } _h_char_2_dec() { From a8b564fa648a0cafae32c7948ae7167a583e86a1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 22:10:14 +0800 Subject: [PATCH 0452/1348] typo --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bd61d11e..f861ace0 100755 --- a/acme.sh +++ b/acme.sh @@ -249,7 +249,7 @@ _exists() { fi if command >/dev/null 2>&1; then command -v "$cmd" >/dev/null 2>&1 - elif which >/dev/null 2>&1; + elif which >/dev/null 2>&1; then which "$cmd" >/dev/null 2>&1 fi ret="$?" From a988a91e2eb7e3d9ef81924bc14f7bd6ab36b186 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 22:14:21 +0800 Subject: [PATCH 0453/1348] fix shfmt warnings --- acme.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/acme.sh b/acme.sh index f861ace0..4a5b1118 100755 --- a/acme.sh +++ b/acme.sh @@ -3222,7 +3222,6 @@ installcert() { } _installcert() { - _savedomainconf "Le_RealCertPath" "$Le_RealCertPath" _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath" _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath" @@ -3245,7 +3244,6 @@ _installcert() { Le_RealFullChainPath="" fi - if [ "$Le_RealCertPath" ]; then _info "Installing cert to:$Le_RealCertPath" From 7af784adce32592a2758b3e72d1eebb89e1dd7ae Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 22:30:55 +0800 Subject: [PATCH 0454/1348] fix shellcheck warnings --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4a5b1118..c5e09264 100755 --- a/acme.sh +++ b/acme.sh @@ -548,7 +548,7 @@ _createkey() { _is_idn() { _is_idn_d="$1" _debug2 _is_idn_d "$_is_idn_d" - _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '[0-9]' | tr -d '[a-z]' | tr -d 'A-Z' | tr -d '.,-') + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-') _debug2 _idn_temp "$_idn_temp" [ "$_idn_temp" ] } From 796e2cc1562a856ba9909be018d5da8b8711a202 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 22:32:11 +0800 Subject: [PATCH 0455/1348] fix shellcheck warnings --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index c5e09264..29f08813 100755 --- a/acme.sh +++ b/acme.sh @@ -532,10 +532,10 @@ _createkey() { if _isEccKey "$length"; then _debug "Using ec name: $eccname" - openssl ecparam -name $eccname -genkey 2>/dev/null >"$f" + openssl ecparam -name "$eccname" -genkey 2>/dev/null >"$f" else _debug "Using RSA: $length" - openssl genrsa $length 2>/dev/null >"$f" + openssl genrsa "$length" 2>/dev/null >"$f" fi if [ "$?" != "0" ]; then From 031e885e4de0b684e6d0df5ef686540c5181c0d6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 22:36:16 +0800 Subject: [PATCH 0456/1348] fix shellcheck warnings --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 29f08813..f8c7e179 100755 --- a/acme.sh +++ b/acme.sh @@ -859,7 +859,8 @@ _time2str() { #Soaris if _exists adb; then - echo $(echo "0t${1}=Y" | adb) + _t_s_a=$(echo "0t${1}=Y" | adb) + echo "$_t_s_a" fi } From c7b16249b88f682fed44f84ef772625bb69b0eba Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 23:30:14 +0800 Subject: [PATCH 0457/1348] fix shellcheck warnings --- acme.sh | 10 ++++----- dnsapi/dns_cf.sh | 22 ++++++++++---------- dnsapi/dns_cx.sh | 40 ++++++++++++++++++------------------ dnsapi/dns_dp.sh | 48 +++++++++++++++++++++---------------------- dnsapi/dns_gd.sh | 14 ++++++------- dnsapi/dns_lexicon.sh | 12 +++++------ dnsapi/dns_lua.sh | 20 +++++++++--------- dnsapi/dns_me.sh | 22 ++++++++++---------- dnsapi/dns_ovh.sh | 12 +++++------ dnsapi/dns_pdns.sh | 16 +++++++-------- 10 files changed, 108 insertions(+), 108 deletions(-) diff --git a/acme.sh b/acme.sh index f8c7e179..195adee0 100755 --- a/acme.sh +++ b/acme.sh @@ -411,7 +411,7 @@ _digest() { outputhex="$2" - if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then + if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$outputhex" ]; then openssl dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' else @@ -2290,10 +2290,10 @@ _findHook() { _hookcat="$2" _hookname="$3" - if [ -f "$_SCRIPT_HOME/$_hookdomain/$_hookname" ]; then - d_api="$_SCRIPT_HOME/$_hookdomain/$_hookname" - elif [ -f "$_SCRIPT_HOME/$_hookdomain/$_hookname.sh" ]; then - d_api="$_SCRIPT_HOME/$_hookdomain/$_hookname.sh" + if [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname" ]; then + d_api="$_SCRIPT_HOME/$_hookcat/$_hookname" + elif [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname.sh" ]; then + d_api="$_SCRIPT_HOME/$_hookcat/$_hookname.sh" elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname" elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 63acb28f..edd48300 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -25,7 +25,7 @@ dns_cf_add() { _saveaccountconf CF_Email "$CF_Email" _debug "First detect the root zone" - if ! _get_root $fulldomain; then + if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi @@ -36,7 +36,7 @@ dns_cf_add() { _debug "Getting txt records" _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain" - if ! printf "$response" | grep \"success\":true >/dev/null; then + if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then _err "Error" return 1 fi @@ -46,7 +46,7 @@ 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 printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then _info "Added, sleeping 10 seconds" sleep 10 #todo: check if the record takes effect @@ -60,7 +60,7 @@ dns_cf_add() { else _info "Updating record" record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \" | head -n 1) - _debug "record_id" $record_id + _debug "record_id" "$record_id" _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" if [ "$?" = "0" ]; then @@ -91,8 +91,8 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ]; do - h=$(printf $domain | cut -d . -f $i-100) + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid return 1 @@ -102,17 +102,17 @@ _get_root() { return 1 fi - if printf $response | grep \"name\":\"$h\" >/dev/null; then + if printf "%s" "$response" | grep "\"name\":\"$h\"" >/dev/null; then _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | head -n 1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ]; then - _sub_domain=$(printf $domain | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h return 0 fi return 1 fi p=$i - i=$(expr $i + 1) + i=$(_math "$i" + 1) done return 1 } @@ -121,7 +121,7 @@ _cf_rest() { m=$1 ep="$2" data="$3" - _debug $ep + _debug "$ep" _H1="X-Auth-Email: $CF_Email" _H2="X-Auth-Key: $CF_Key" @@ -129,7 +129,7 @@ _cf_rest() { if [ "$data" ]; then _debug data "$data" - response="$(_post "$data" "$CF_Api/$ep" "" $m)" + response="$(_post "$data" "$CF_Api/$ep" "" "$m")" else response="$(_get "$CF_Api/$ep")" fi diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 81eb896d..c4d941da 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -22,19 +22,19 @@ dns_cx_add() { return 1 fi - REST_API=$CX_Api + REST_API="$CX_Api" #save the api key and email to the account conf file. _saveaccountconf CX_Key "$CX_Key" _saveaccountconf CX_Secret "$CX_Secret" _debug "First detect the root zone" - if ! _get_root $fulldomain; then + if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi - existing_records $_domain $_sub_domain + existing_records "$_domain" "$_sub_domain" _debug count "$count" if [ "$?" != "0" ]; then _err "Error get existing records." @@ -42,9 +42,9 @@ dns_cx_add() { fi if [ "$count" = "0" ]; then - add_record $_domain $_sub_domain $txtvalue + add_record "$_domain" "$_sub_domain" "$txtvalue" else - update_record $_domain $_sub_domain $txtvalue + update_record "$_domain" "$_sub_domain" "$txtvalue" fi if [ "$?" = "0" ]; then @@ -78,7 +78,7 @@ existing_records() { return 0 fi - if printf "$response" | grep '"type":"TXT"' >/dev/null; then + if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then count=1 record_id=$(printf "%s\n" "$seg" | _egrep_o \"record_id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug record_id "$record_id" @@ -93,7 +93,7 @@ add_record() { root=$1 sub=$2 txtvalue=$3 - fulldomain=$sub.$root + fulldomain="$sub.$root" _info "Adding record" @@ -110,7 +110,7 @@ update_record() { root=$1 sub=$2 txtvalue=$3 - fulldomain=$sub.$root + fulldomain="$sub.$root" _info "Updating record" @@ -136,30 +136,30 @@ _get_root() { return 1 fi - while [ '1' ]; do - h=$(printf $domain | cut -d . -f $i-100) + 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 printf "$response" | grep "$h." >/dev/null; then + if _contains "$response" "$h."; then seg=$(printf "%s" "$response" | _egrep_o "\{[^\{]*\"$h\.\"[^\}]*\}") _debug seg "$seg" _domain_id=$(printf "%s" "$seg" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then - _sub_domain=$(printf $domain | cut -d . -f 1-$p) - _debug _sub_domain $_sub_domain - _domain=$h - _debug _domain $_domain + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _sub_domain "$_sub_domain" + _domain="$h" + _debug _domain "$_domain" return 0 fi return 1 fi - p=$i - i=$(expr $i + 1) + p="$i" + i=$(_math "$i" + 1) done return 1 } @@ -168,7 +168,7 @@ _get_root() { _rest() { m=$1 ep="$2" - _debug $ep + _debug "$ep" url="$REST_API/$ep" _debug url "$url" @@ -180,7 +180,7 @@ _rest() { sec="$CX_Key$url$data$cdate$CX_Secret" _debug sec "$sec" - hmac=$(printf "$sec" | openssl md5 | cut -d " " -f 2) + hmac=$(printf "%s" "$sec" | _digest md5 hex) _debug hmac "$hmac" _H1="API-KEY: $CX_Key" @@ -199,7 +199,7 @@ _rest() { return 1 fi _debug2 response "$response" - if ! printf "$response" | grep '"message":"success"' >/dev/null; then + if ! _contains "$response" '"message":"success"'; then return 1 fi return 0 diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 8861bfcf..605c541d 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -22,19 +22,19 @@ dns_dp_add() { return 1 fi - REST_API=$DP_Api + REST_API="$DP_Api" #save the api key and email to the account conf file. _saveaccountconf DP_Id "$DP_Id" _saveaccountconf DP_Key "$DP_Key" _debug "First detect the root zone" - if ! _get_root $fulldomain; then + if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi - existing_records $_domain $_sub_domain + existing_records "$_domain" "$_sub_domain" _debug count "$count" if [ "$?" != "0" ]; then _err "Error get existing records." @@ -42,9 +42,9 @@ dns_dp_add() { fi if [ "$count" = "0" ]; then - add_record $_domain $_sub_domain $txtvalue + add_record "$_domain" "$_sub_domain" "$txtvalue" else - update_record $_domain $_sub_domain $txtvalue + update_record "$_domain" "$_sub_domain" "$txtvalue" fi } @@ -67,14 +67,14 @@ existing_records() { return 1 fi - if printf "$response" | grep 'No records'; then + if _contains "$response" 'No records'; then count=0 return 0 fi - if printf "$response" | grep "Action completed successful" >/dev/null; then - count=$(printf "$response" | grep 'TXT' | wc -l) - record_id=$(printf "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) + if _contains "$response" "Action completed successful"; then + count=$(printf "%s" "$response" | grep 'TXT' | wc -l) + record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) return 0 else _err "get existing records error." @@ -90,7 +90,7 @@ add_record() { root=$1 sub=$2 txtvalue=$3 - fulldomain=$sub.$root + fulldomain="$sub.$root" _info "Adding record" @@ -98,7 +98,7 @@ add_record() { return 1 fi - if printf "$response" | grep "Action completed successful"; then + if _contains "$response" "Action completed successful"; then return 0 fi @@ -112,7 +112,7 @@ update_record() { root=$1 sub=$2 txtvalue=$3 - fulldomain=$sub.$root + fulldomain="$sub.$root" _info "Updating record" @@ -120,7 +120,7 @@ update_record() { return 1 fi - if printf "$response" | grep "Action completed successful"; then + if _contains "$response" "Action completed successful"; then return 0 fi @@ -138,8 +138,8 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ]; do - h=$(printf $domain | cut -d . -f $i-100) + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid return 1 @@ -149,20 +149,20 @@ _get_root() { return 1 fi - if printf "$response" | grep "Action completed successful" >/dev/null; then + if _contains "$response" "Action completed successful"; then _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then - _sub_domain=$(printf $domain | cut -d . -f 1-$p) - _debug _sub_domain $_sub_domain - _domain=$h - _debug _domain $_domain + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _sub_domain "$_sub_domain" + _domain="$h" + _debug _domain "$_domain" return 0 fi return 1 fi - p=$i - i=$(expr $i + 1) + p="$i" + i=$(_math "$i" + 1) done return 1 } @@ -172,14 +172,14 @@ _rest() { m=$1 ep="$2" data="$3" - _debug $ep + _debug "$ep" url="$REST_API/$ep" _debug url "$url" if [ "$data" ]; then _debug2 data "$data" - response="$(_post $data "$url")" + response="$(_post "$data" "$url")" else response="$(_get "$url")" fi diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 51ca8db5..304d5d3e 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -26,7 +26,7 @@ dns_gd_add() { _saveaccountconf GD_Secret "$GD_Secret" _debug "First detect the root zone" - if ! _get_root $fulldomain; then + if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi @@ -67,8 +67,8 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ]; do - h=$(printf $domain | cut -d . -f $i-100) + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid return 1 @@ -78,11 +78,11 @@ _get_root() { return 1 fi - if printf "$response" | grep '"code":"NOT_FOUND"' >/dev/null; then + if _contains "$response" '"code":"NOT_FOUND"'; then _debug "$h not found" else - _sub_domain=$(printf $domain | cut -d . -f 1-$p) - _domain=$h + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" return 0 fi p=$i @@ -95,7 +95,7 @@ _gd_rest() { m=$1 ep="$2" data="$3" - _debug $ep + _debug "$ep" _H1="Authorization: sso-key $GD_Key:$GD_Secret" _H2="Content-Type: application/json" diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 847b9999..bceab8d5 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -14,9 +14,9 @@ dns_lexicon_add() { fulldomain=$1 txtvalue=$2 - domain=$(printf "$fulldomain" | cut -d . -f 2-999) + domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) - if ! _exists $lexicon_cmd; then + if ! _exists "$lexicon_cmd"; then _err "Please install $lexicon_cmd first: $wiki" return 1 fi @@ -33,7 +33,7 @@ dns_lexicon_add() { eval Lx_name_v="\$$Lx_name" _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then - _saveaccountconf $Lx_name "$Lx_name_v" + _saveaccountconf "$Lx_name" "$Lx_name_v" export "$Lx_name" fi @@ -41,7 +41,7 @@ dns_lexicon_add() { eval Lx_token_v="\$$Lx_token" _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then - _saveaccountconf $Lx_token "$Lx_token_v" + _saveaccountconf "$Lx_token" "$Lx_token_v" export "$Lx_token" fi @@ -49,7 +49,7 @@ dns_lexicon_add() { eval Lx_password_v="\$$Lx_password" _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then - _saveaccountconf $Lx_password "$Lx_password_v" + _saveaccountconf "$Lx_password" "$Lx_password_v" export "$Lx_password" fi @@ -58,7 +58,7 @@ dns_lexicon_add() { _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then export "$Lx_domaintoken" - _saveaccountconf $Lx_domaintoken "$Lx_domaintoken_v" + _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" fi $lexicon_cmd "$PROVIDER" create ${domain} TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index efd197c2..a6375e5b 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -28,7 +28,7 @@ dns_lua_add() { _saveaccountconf LUA_Email "$LUA_Email" _debug "First detect the root zone" - if ! _get_root $fulldomain; then + if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi @@ -49,7 +49,7 @@ dns_lua_add() { if [ "$count" = "0" ]; then _info "Adding record" if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep $fulldomain >/dev/null; then + if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then _info "Added" #todo: check if the record takes effect return 0 @@ -62,7 +62,7 @@ dns_lua_add() { else _info "Updating record" record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\" | cut -d: -f2 | cut -d, -f1) - _debug "record_id" $record_id + _debug "record_id" "$record_id" _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" if [ "$?" = "0" ]; then @@ -95,24 +95,24 @@ _get_root() { if ! _LUA_rest GET "zones"; then return 1 fi - while [ '1' ]; do - h=$(printf $domain | cut -d . -f $i-100) + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid return 1 fi - if printf $response | grep \"name\":\"$h\" >/dev/null; then + if _contains "$response" "\"name\":\"$h\""; then _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$h\" | cut -d : -f 2 | cut -d , -f 1) if [ "$_domain_id" ]; then - _sub_domain=$(printf $domain | cut -d . -f 1-$p) - _domain=$h + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" return 0 fi return 1 fi p=$i - i=$(expr $i + 1) + i=$(_math "$i" + 1) done return 1 } @@ -121,7 +121,7 @@ _LUA_rest() { m=$1 ep="$2" data="$3" - _debug $ep + _debug "$ep" _H1="Accept: application/json" _H2="Authorization: Basic $LUA_auth" diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index abc17475..db4f796a 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -25,7 +25,7 @@ dns_me_add() { _saveaccountconf ME_Secret "$ME_Secret" _debug "First detect the root zone" - if ! _get_root $fulldomain; then + if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi @@ -36,7 +36,7 @@ dns_me_add() { _debug "Getting txt records" _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" - if ! printf "$response" | grep \"totalRecords\": >/dev/null; then + if ! _contains "$response" "\"totalRecords\":"; then _err "Error" return 1 fi @@ -59,7 +59,7 @@ dns_me_add() { else _info "Updating record" record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | cut -d : -f 2 | head -n 1) - _debug "record_id" $record_id + _debug "record_id" "$record_id" _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" if [ "$?" = "0" ]; then @@ -89,8 +89,8 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ]; do - h=$(printf $domain | cut -d . -f $i-100) + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid return 1 @@ -100,17 +100,17 @@ _get_root() { return 1 fi - if printf $response | grep \"name\":\"$h\" >/dev/null; then + if _contains "$response" "\"name\":\"$h\""; then _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | head -n 1 | cut -d : -f 2) if [ "$_domain_id" ]; then - _sub_domain=$(printf $domain | cut -d . -f 1-$p) - _domain=$h + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" return 0 fi return 1 fi p=$i - i=$(expr $i + 1) + i=$(_math "$i" + 1) done return 1 } @@ -119,10 +119,10 @@ _me_rest() { m=$1 ep="$2" data="$3" - _debug $ep + _debug "$ep" cdate=$(date -u +"%a, %d %b %Y %T %Z") - hmac=$(printf "$cdate" | _hmac sha1 "$ME_Secret" 1) + hmac=$(printf "%s" "$cdate" | _hmac sha1 "$ME_Secret" 1) _H1="x-dnsme-apiKey: $ME_Key" _H2="x-dnsme-requestDate: $cdate" diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 782c0830..ace52225 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -226,8 +226,8 @@ _get_root() { domain=$1 i=2 p=1 - while [ '1' ]; do - h=$(printf $domain | cut -d . -f $i-100) + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid return 1 @@ -238,12 +238,12 @@ _get_root() { fi if ! _contains "$response" "This service does not exist" >/dev/null; then - _sub_domain=$(printf $domain | cut -d . -f 1-$p) - _domain=$h + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" return 0 fi p=$i - i=$(expr $i + 1) + i=$(_math "$i" + 1) done return 1 } @@ -261,7 +261,7 @@ _ovh_rest() { m=$1 ep="$2" data="$3" - _debug $ep + _debug "$ep" _ovh_url="$OVH_API/$ep" _debug2 _ovh_url "$_ovh_url" diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index ec82bfe8..7c994eb5 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -35,7 +35,7 @@ dns_pdns_add() { fi if [ -z "$PDNS_Ttl" ]; then - PDNS_Ttl=$DEFAULT_PDNS_TTL + PDNS_Ttl="$DEFAULT_PDNS_TTL" fi #save the api addr and key to the account conf file. @@ -48,7 +48,7 @@ dns_pdns_add() { fi _debug "First detect the root zone" - if ! _get_root $fulldomain; then + if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi @@ -94,22 +94,22 @@ _get_root() { p=1 if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones"; then - _zones_response=$response + _zones_response="$response" fi - while [ '1' ]; do - h=$(printf $domain | cut -d . -f $i-100) + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then return 1 fi - if printf "$_zones_response" | grep "\"name\": \"$h.\"" >/dev/null; then - _domain=$h + if _contains "$_zones_response" "\"name\": \"$h.\""; then + _domain="$h" return 0 fi p=$i - i=$(expr $i + 1) + i=$(_math $i + 1) done _debug "$domain not found" return 1 From a0636d5a87e216ecfb033eff320bd5a79a0489de Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 23:34:21 +0800 Subject: [PATCH 0458/1348] fix shellcheck warnings. --- dnsapi/dns_lexicon.sh | 8 ++++---- dnsapi/dns_lua.sh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index bceab8d5..4cec7cb7 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -29,7 +29,7 @@ dns_lexicon_add() { _savedomainconf PROVIDER "$PROVIDER" export PROVIDER - Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr [a-z] [A-Z]) + Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr 'a-z' 'A-Z') eval Lx_name_v="\$$Lx_name" _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then @@ -37,7 +37,7 @@ dns_lexicon_add() { export "$Lx_name" fi - Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr [a-z] [A-Z]) + Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr 'a-z' 'A-Z') eval Lx_token_v="\$$Lx_token" _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then @@ -45,7 +45,7 @@ dns_lexicon_add() { export "$Lx_token" fi - Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr [a-z] [A-Z]) + Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr 'a-z' 'A-Z') eval Lx_password_v="\$$Lx_password" _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then @@ -53,7 +53,7 @@ dns_lexicon_add() { export "$Lx_password" fi - Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr [a-z] [A-Z]) + Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr 'a-z' 'A-Z') eval Lx_domaintoken_v="\$$Lx_domaintoken" _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index a6375e5b..c03686ab 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -8,7 +8,7 @@ #LUA_Email="user@luadns.net" LUA_Api="https://api.luadns.com/v1" -LUA_auth=$(printf $LUA_Email:$LUA_Key | _base64) +LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) ######## Public functions ##################### @@ -39,7 +39,7 @@ dns_lua_add() { _debug "Getting txt records" _LUA_rest GET "zones/${_domain_id}/records" - if ! printf "$response" | grep \"id\": >/dev/null; then + if ! _contains "$response" "\"id\":"; then _err "Error" return 1 fi From c7b8f223ee3cd17c6c95e45bdde47c9129547648 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 23:48:27 +0800 Subject: [PATCH 0459/1348] fix for solaris tr --- acme.sh | 2 +- dnsapi/dns_lexicon.sh | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 195adee0..78a6ec6a 100755 --- a/acme.sh +++ b/acme.sh @@ -548,7 +548,7 @@ _createkey() { _is_idn() { _is_idn_d="$1" _debug2 _is_idn_d "$_is_idn_d" - _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-') + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '[0-9]' | tr -d '[a-z]' | tr -d '[A-Z]' | tr -d '.,-') _debug2 _idn_temp "$_idn_temp" [ "$_idn_temp" ] } diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 4cec7cb7..c3628a0f 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -29,7 +29,7 @@ dns_lexicon_add() { _savedomainconf PROVIDER "$PROVIDER" export PROVIDER - Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr 'a-z' 'A-Z') + Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr '[a-z]' '[A-Z]') eval Lx_name_v="\$$Lx_name" _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then @@ -37,7 +37,7 @@ dns_lexicon_add() { export "$Lx_name" fi - Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr 'a-z' 'A-Z') + Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr '[a-z]' '[A-Z]') eval Lx_token_v="\$$Lx_token" _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then @@ -45,7 +45,7 @@ dns_lexicon_add() { export "$Lx_token" fi - Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr 'a-z' 'A-Z') + Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr '[a-z]' '[A-Z]') eval Lx_password_v="\$$Lx_password" _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then @@ -53,7 +53,7 @@ dns_lexicon_add() { export "$Lx_password" fi - Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr 'a-z' 'A-Z') + Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr '[a-z]' '[A-Z]') eval Lx_domaintoken_v="\$$Lx_domaintoken" _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then From efd96153d840672d6893c448412eb24f2b763a09 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 11 Nov 2016 23:52:02 +0800 Subject: [PATCH 0460/1348] minor fix log message. --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 78a6ec6a..e49a253a 100755 --- a/acme.sh +++ b/acme.sh @@ -2319,7 +2319,7 @@ __get_domain_new_authz() { _Max_new_authz_retry_times=5 _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do - _info "Try new-authz for the $_authz_i time." + _debug "Try new-authz for the $_authz_i time." if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then _err "Can not get domain new authz." return 1 @@ -2334,7 +2334,7 @@ __get_domain_new_authz() { done if [ "$_authz_i" = "$_Max_new_authz_retry_times" ]; then - _debug "new-authz retry reach the max $_Max_new_authz_retry_times times." + _err "new-authz retry reach the max $_Max_new_authz_retry_times times." fi if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then From e9f9f515bdf707e704e33af001378e0bb256d053 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 00:06:34 +0800 Subject: [PATCH 0461/1348] fix shellcheck warnings. --- dnsapi/dns_gd.sh | 4 ++-- dnsapi/dns_lexicon.sh | 10 +++++----- dnsapi/dns_lua.sh | 8 ++++---- dnsapi/dns_me.sh | 2 +- dnsapi/dns_ovh.sh | 6 +++--- dnsapi/dns_pdns.sh | 2 -- 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 304d5d3e..dec80a9b 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -85,8 +85,8 @@ _get_root() { _domain="$h" return 0 fi - p=$i - i=$(expr $i + 1) + p="$i" + i=$(_math "$i" + 1) done return 1 } diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index c3628a0f..38b6a13c 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -29,7 +29,7 @@ dns_lexicon_add() { _savedomainconf PROVIDER "$PROVIDER" export PROVIDER - Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr '[a-z]' '[A-Z]') + Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr '[a-z]' '[A-Z]') eval Lx_name_v="\$$Lx_name" _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then @@ -37,7 +37,7 @@ dns_lexicon_add() { export "$Lx_name" fi - Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr '[a-z]' '[A-Z]') + Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr '[a-z]' '[A-Z]') eval Lx_token_v="\$$Lx_token" _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then @@ -45,7 +45,7 @@ dns_lexicon_add() { export "$Lx_token" fi - Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr '[a-z]' '[A-Z]') + Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr '[a-z]' '[A-Z]') eval Lx_password_v="\$$Lx_password" _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then @@ -53,7 +53,7 @@ dns_lexicon_add() { export "$Lx_password" fi - Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr '[a-z]' '[A-Z]') + Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr '[a-z]' '[A-Z]') eval Lx_domaintoken_v="\$$Lx_domaintoken" _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then @@ -61,7 +61,7 @@ dns_lexicon_add() { _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" fi - $lexicon_cmd "$PROVIDER" create ${domain} TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" + $lexicon_cmd "$PROVIDER" create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" } diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index c03686ab..e6b48724 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -44,7 +44,7 @@ dns_lua_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o \"name\":\"$fulldomain\" | wc -l) + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l) _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" @@ -61,7 +61,7 @@ dns_lua_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\" | cut -d: -f2 | cut -d, -f1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | cut -d: -f2 | cut -d, -f1) _debug "record_id" "$record_id" _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" @@ -103,7 +103,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]*,\"name\":\"$h\" | cut -d : -f 2 | cut -d , -f 1) + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" @@ -127,7 +127,7 @@ _LUA_rest() { _H2="Authorization: Basic $LUA_auth" if [ "$data" ]; then _debug data "$data" - response="$(_post "$data" "$LUA_Api/$ep" "" $m)" + response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" else response="$(_get "$LUA_Api/$ep")" fi diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index db4f796a..ba792474 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -130,7 +130,7 @@ _me_rest() { if [ "$data" ]; then _debug data "$data" - response="$(_post "$data" "$ME_Api/$ep" "" $m)" + response="$(_post "$data" "$ME_Api/$ep" "" "$m")" else response="$(_get "$ME_Api/$ep")" fi diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index ace52225..97730f7e 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -127,7 +127,7 @@ dns_ovh_add() { _info "Consumer key is ok." _debug "First detect the root zone" - if ! _get_root $fulldomain; then + if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi @@ -157,7 +157,7 @@ dns_ovh_add() { _err "Can not get record id." return 1 fi - _debug "record_id" $record_id + _debug "record_id" "$record_id" if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}"; then if _contains "$response" "null"; then @@ -280,7 +280,7 @@ _ovh_rest() { _H5="Content-Type: application/json;charset=utf-8" if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then _debug data "$data" - response="$(_post "$data" "$_ovh_url" "" $m)" + response="$(_post "$data" "$_ovh_url" "" "$m")" else response="$(_get "$_ovh_url")" fi diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 7c994eb5..0f6c59d5 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -91,7 +91,6 @@ set_record() { _get_root() { domain=$1 i=1 - p=1 if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones"; then _zones_response="$response" @@ -108,7 +107,6 @@ _get_root() { return 0 fi - p=$i i=$(_math $i + 1) done _debug "$domain not found" From 69925ce8230d98d7ea32a543d785a83391985ee9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 00:09:45 +0800 Subject: [PATCH 0462/1348] fix shellcheck warnings. --- dnsapi/dns_cx.sh | 2 +- dnsapi/dns_gd.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index c4d941da..45003745 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -189,7 +189,7 @@ _rest() { _H4="Content-Type: application/json" if [ "$data" ]; then - response="$(_post "$data" "$url" "" $m)" + response="$(_post "$data" "$url" "" "$m")" else response="$(_get "$url")" fi diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index dec80a9b..fed25d86 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -102,7 +102,7 @@ _gd_rest() { if [ "$data" ]; then _debug data "$data" - response="$(_post "$data" "$GD_Api/$ep" "" $m)" + response="$(_post "$data" "$GD_Api/$ep" "" "$m")" else response="$(_get "$GD_Api/$ep")" fi From 432771dfe3c46786a5eaf01f8fa37d811e923c1d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 00:19:59 +0800 Subject: [PATCH 0463/1348] add shellcheck to CI --- .travis.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f363dbef..3c4485bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,19 @@ -language: bash +language: shell env: global: - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 +addons: + apt: + sources: + - debian-sid # Grab shellcheck from the Debian repo (o_O) + packages: + - shellcheck + script: - curl -sSL $SHFMT_URL -o ~/shfmt - chmod +x ~/shfmt - - ~/shfmt -l -w -i 2 . - - git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) + - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) + - [ "$?" = "0" ] && shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" || false + From 9d6abcd9be975a0286125b1da4da02ccc85d5356 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 00:23:07 +0800 Subject: [PATCH 0464/1348] fix CI --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3c4485bc..15099797 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,6 @@ addons: script: - curl -sSL $SHFMT_URL -o ~/shfmt - chmod +x ~/shfmt - - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) - - [ "$?" = "0" ] && shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" || false + - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && exit 1) + - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" || exit 1 From 870274ad9db5f789f20f766326891bb4f51eb190 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 00:25:15 +0800 Subject: [PATCH 0465/1348] fix CI --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 15099797..cad5a20c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ addons: script: - curl -sSL $SHFMT_URL -o ~/shfmt - chmod +x ~/shfmt - - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && exit 1) - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" || exit 1 + - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && exit 1) + From 5766250288ffdf6c28a8b49069f5720d9b20cdd2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 00:31:24 +0800 Subject: [PATCH 0466/1348] fix CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cad5a20c..4c06c2d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ addons: script: - curl -sSL $SHFMT_URL -o ~/shfmt - chmod +x ~/shfmt + - shellcheck -V - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" || exit 1 - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && exit 1) From e440223b40998411c80be06286ff88336fbefc03 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 00:50:44 +0800 Subject: [PATCH 0467/1348] fix shellcheck warnings --- dnsapi/dns_cf.sh | 6 +++--- dnsapi/dns_cx.sh | 4 ++-- dnsapi/dns_dp.sh | 2 +- dnsapi/dns_gd.sh | 3 +-- dnsapi/dns_me.sh | 6 +++--- dnsapi/dns_ovh.sh | 3 +-- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index edd48300..20cb169e 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -41,7 +41,7 @@ dns_cf_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o \"count\":[^,]* | cut -d : -f 2) + count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" @@ -59,7 +59,7 @@ dns_cf_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \" | head -n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) _debug "record_id" "$record_id" _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" @@ -103,7 +103,7 @@ _get_root() { fi if printf "%s" "$response" | grep "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | head -n 1 | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$response" | _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 diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 45003745..38649f3e 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -80,7 +80,7 @@ existing_records() { if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then count=1 - record_id=$(printf "%s\n" "$seg" | _egrep_o \"record_id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") + record_id=$(printf "%s\n" "$seg" | _egrep_o "\"record_id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug record_id "$record_id" return 0 fi @@ -147,7 +147,7 @@ _get_root() { if _contains "$response" "$h."; then seg=$(printf "%s" "$response" | _egrep_o "\{[^\{]*\"$h\.\"[^\}]*\}") _debug seg "$seg" - _domain_id=$(printf "%s" "$seg" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 605c541d..a06f157b 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -150,7 +150,7 @@ _get_root() { fi if _contains "$response" "Action completed successful"; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index fed25d86..f96af937 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -30,7 +30,7 @@ dns_gd_add() { _err "invalid domain" return 1 fi - _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" @@ -62,7 +62,6 @@ dns_gd_rm() { #returns # _sub_domain=_acme-challenge.www # _domain=domain.com -# _domain_id=sdjkglgdfewsdfg _get_root() { domain=$1 i=2 diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index ba792474..f231f7ed 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -41,7 +41,7 @@ dns_me_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o \"totalRecords\":[^,]* | cut -d : -f 2) + count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" @@ -58,7 +58,7 @@ dns_me_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | cut -d : -f 2 | head -n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) _debug "record_id" "$record_id" _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" @@ -101,7 +101,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | head -n 1 | cut -d : -f 2) + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | head -n 1 | cut -d : -f 2) if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 97730f7e..ed8c42be 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -131,7 +131,7 @@ dns_ovh_add() { _err "invalid domain" return 1 fi - _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" @@ -221,7 +221,6 @@ _ovh_authentication() { #returns # _sub_domain=_acme-challenge.www # _domain=domain.com -# _domain_id=sdjkglgdfewsdfg _get_root() { domain=$1 i=2 From be68fbd4f5b65716a37a4a669e7a8ae960ebf07d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 10:58:20 +0800 Subject: [PATCH 0468/1348] fix for alpine --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e49a253a..b4f01380 100755 --- a/acme.sh +++ b/acme.sh @@ -259,7 +259,8 @@ _exists() { #a + b _math() { - printf "%s" "$(($@))" + _m_opts="$@" + printf "%s" "$(($_m_opts))" } _h_char_2_dec() { From 797cbb9b2064784a4a13d8d509863a3292c35739 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 11:05:05 +0800 Subject: [PATCH 0469/1348] fix shellcheck warnings --- dnsapi/dns_cf.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 20cb169e..cacb5b39 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -15,6 +15,8 @@ dns_cf_add() { txtvalue=$2 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 From 422e5026d60847c1df316539d3e7b91ef2fee2a6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 11:13:40 +0800 Subject: [PATCH 0470/1348] fix shellcheck warnings --- dnsapi/dns_cx.sh | 2 ++ dnsapi/dns_dp.sh | 2 ++ dnsapi/dns_gd.sh | 2 ++ dnsapi/dns_lexicon.sh | 1 + dnsapi/dns_me.sh | 2 ++ dnsapi/dns_ovh.sh | 2 ++ dnsapi/dns_pdns.sh | 3 +++ 7 files changed, 14 insertions(+) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 38649f3e..0caf0c02 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -17,6 +17,8 @@ dns_cx_add() { txtvalue=$2 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 "Please create you key and try again." return 1 diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index a06f157b..aa06d5fc 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -17,6 +17,8 @@ dns_dp_add() { txtvalue=$2 if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then + DP_Id="" + DP_Key="" _err "You don't specify dnspod api key and key id yet." _err "Please create you key and try again." return 1 diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index f96af937..9470ed22 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -16,6 +16,8 @@ dns_gd_add() { txtvalue=$2 if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then + GD_Key="" + GD_Secret="" _err "You don't specify godaddy api key and secret yet." _err "Please create you key and try again." return 1 diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 38b6a13c..a0f707a6 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -22,6 +22,7 @@ dns_lexicon_add() { fi if [ -z "$PROVIDER" ]; then + PROVIDER="" _err "Please define env PROVIDER first: $wiki" return 1 fi diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index f231f7ed..edd88d98 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -15,6 +15,8 @@ dns_me_add() { txtvalue=$2 if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ]; then + ME_Key="" + ME_Secret="" _err "You didn't specify DNSMadeEasy api key and secret yet." _err "Please create you key and try again." return 1 diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index ed8c42be..377b3de1 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -86,6 +86,8 @@ dns_ovh_add() { txtvalue=$2 if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then + OVH_AK="" + OVH_AS="" _err "You don't specify OVH application key and application secret yet." _err "Please create you key and try again." return 1 diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 0f6c59d5..5d6d99fd 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -17,18 +17,21 @@ dns_pdns_add() { txtvalue=$2 if [ -z "$PDNS_Url" ]; then + PDNS_Url="" _err "You don't specify PowerDNS address." _err "Please set PDNS_Url and try again." return 1 fi if [ -z "$PDNS_ServerId" ]; then + PDNS_ServerId="" _err "You don't specify PowerDNS server id." _err "Please set you PDNS_ServerId and try again." return 1 fi if [ -z "$PDNS_Token" ]; then + PDNS_Token="" _err "You don't specify PowerDNS token." _err "Please create you PDNS_Token and try again." return 1 From 158a628c0e53173686f127a25c41ca7d30c9490e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 11:16:40 +0800 Subject: [PATCH 0471/1348] fix CI --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4c06c2d5..7b68dfdf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ script: - curl -sSL $SHFMT_URL -o ~/shfmt - chmod +x ~/shfmt - shellcheck -V - - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" || exit 1 - - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && exit 1) + - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" + - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) From a0311b0134571d380715e63cd633db1e939bfa56 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 11:35:19 +0800 Subject: [PATCH 0472/1348] fix for shellcheck warnings --- dnsapi/dns_lexicon.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index a0f707a6..74954429 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -31,7 +31,7 @@ dns_lexicon_add() { export PROVIDER Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr '[a-z]' '[A-Z]') - eval Lx_name_v="\$$Lx_name" + Lx_name_v=$(eval "echo "\$$Lx_name"") _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then _saveaccountconf "$Lx_name" "$Lx_name_v" @@ -39,7 +39,7 @@ dns_lexicon_add() { fi Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr '[a-z]' '[A-Z]') - eval Lx_token_v="\$$Lx_token" + Lx_token_v=$(eval "echo "\$$Lx_token"") _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then _saveaccountconf "$Lx_token" "$Lx_token_v" @@ -47,7 +47,7 @@ dns_lexicon_add() { fi Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr '[a-z]' '[A-Z]') - eval Lx_password_v="\$$Lx_password" + Lx_password_v=$(eval "echo "\$$Lx_password"") _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then _saveaccountconf "$Lx_password" "$Lx_password_v" @@ -55,7 +55,7 @@ dns_lexicon_add() { fi Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr '[a-z]' '[A-Z]') - eval Lx_domaintoken_v="\$$Lx_domaintoken" + Lx_domaintoken_v=$(eval "echo "\$$Lx_domaintoken"") _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then export "$Lx_domaintoken" From 3de85700226a2f5fe0c9145259ca7864ae1093a5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 11:40:30 +0800 Subject: [PATCH 0473/1348] fix shellcheck warnings. --- dnsapi/dns_lexicon.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 74954429..d3bfc942 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -31,34 +31,34 @@ dns_lexicon_add() { export PROVIDER Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr '[a-z]' '[A-Z]') - Lx_name_v=$(eval "echo "\$$Lx_name"") + Lx_name_v=$(eval "echo "\$"$Lx_name""") _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then _saveaccountconf "$Lx_name" "$Lx_name_v" - export "$Lx_name" + eval export "$Lx_name" fi Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr '[a-z]' '[A-Z]') - Lx_token_v=$(eval "echo "\$$Lx_token"") + Lx_token_v=$(eval "echo "\$"$Lx_token""") _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then _saveaccountconf "$Lx_token" "$Lx_token_v" - export "$Lx_token" + eval export "$Lx_token" fi Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr '[a-z]' '[A-Z]') - Lx_password_v=$(eval "echo "\$$Lx_password"") + Lx_password_v=$(eval "echo "\$"$Lx_password""") _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then _saveaccountconf "$Lx_password" "$Lx_password_v" - export "$Lx_password" + eval export "$Lx_password" fi Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr '[a-z]' '[A-Z]') - Lx_domaintoken_v=$(eval "echo "\$$Lx_domaintoken"") + Lx_domaintoken_v=$(eval "echo "\$"$Lx_domaintoken""") _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then - export "$Lx_domaintoken" + eval export "$Lx_domaintoken" _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" fi From a8c61111978013d594d63cca7e6eadab1e865bad Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 11:45:30 +0800 Subject: [PATCH 0474/1348] fix shellcheck warnings --- dnsapi/dns_lexicon.sh | 8 ++++---- dnsapi/dns_lua.sh | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index d3bfc942..4ab65645 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -31,7 +31,7 @@ dns_lexicon_add() { export PROVIDER Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr '[a-z]' '[A-Z]') - Lx_name_v=$(eval "echo "\$"$Lx_name""") + Lx_name_v=$(eval echo \$"$Lx_name") _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then _saveaccountconf "$Lx_name" "$Lx_name_v" @@ -39,7 +39,7 @@ dns_lexicon_add() { fi Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr '[a-z]' '[A-Z]') - Lx_token_v=$(eval "echo "\$"$Lx_token""") + Lx_token_v=$(eval echo \$"$Lx_token") _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then _saveaccountconf "$Lx_token" "$Lx_token_v" @@ -47,7 +47,7 @@ dns_lexicon_add() { fi Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr '[a-z]' '[A-Z]') - Lx_password_v=$(eval "echo "\$"$Lx_password""") + Lx_password_v=$(eval echo \$"$Lx_password") _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then _saveaccountconf "$Lx_password" "$Lx_password_v" @@ -55,7 +55,7 @@ dns_lexicon_add() { fi Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr '[a-z]' '[A-Z]') - Lx_domaintoken_v=$(eval "echo "\$"$Lx_domaintoken""") + Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then eval export "$Lx_domaintoken" diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index e6b48724..2c7ec4b3 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -18,6 +18,8 @@ dns_lua_add() { txtvalue=$2 if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then + LUA_Key="" + LUA_Email="" _err "You don't specify luadns api key and email yet." _err "Please create you key and try again." return 1 From 8f9a1881a4d78c567e53eb84300933b2b18da278 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 18:28:17 +0800 Subject: [PATCH 0475/1348] v2.6.5, support shellcheck and shfmt --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index b4f01380..c2f76638 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.4 +VER=2.6.5 PROJECT_NAME="acme.sh" From 87edf71e9395caac3eef8fbb195fe0994b9de817 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 12 Nov 2016 18:39:26 +0800 Subject: [PATCH 0476/1348] fast_finish: true --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7b68dfdf..62feca32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,7 @@ script: - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) - +matrix: + fast_finish: true + + From 07af42476da0baf53b2d34474df1b7f08fa65951 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 13 Nov 2016 21:47:58 +0800 Subject: [PATCH 0477/1348] change default user agent --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index c2f76638..2ecf1225 100755 --- a/acme.sh +++ b/acme.sh @@ -16,7 +16,7 @@ _SUB_FOLDERS="dnsapi deploy" DEFAULT_CA="https://acme-v01.api.letsencrypt.org" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" -DEFAULT_USER_AGENT="$PROJECT_ENTRY client v$VER : $PROJECT" +DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" DEFAULT_ACCOUNT_KEY_LENGTH=2048 From 20ea85918322a19953fd8e4cff73b4b7d0337e1d Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 14 Nov 2016 17:47:22 +0800 Subject: [PATCH 0478/1348] fix 'sed -i' permissions on PVE --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2ecf1225..e5dabb3a 100755 --- a/acme.sh +++ b/acme.sh @@ -1324,7 +1324,8 @@ _clear_conf() { _c_c_f="$1" _sdkey="$2" if [ "$_c_c_f" ]; then - _sed_i "s/^$_sdkey.*$//" "$_c_c_f" + _conf_data="$(cat "$_c_c_f")" + echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" > "$_c_c_f" else _err "config file is empty, can not clear" fi From 243593cdaa716393283bb8f879517f2146d8b57b Mon Sep 17 00:00:00 2001 From: Philippe Kueck Date: Mon, 14 Nov 2016 14:06:30 +0100 Subject: [PATCH 0479/1348] fix warnings and remove unused ${tmp} variable --- dnsapi/dns_nsupdate.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 56023322..a024e314 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -13,16 +13,15 @@ dns_nsupdate_add() { _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" - nsupdate -k ${NSUPDATE_KEY} < Date: Mon, 14 Nov 2016 22:11:05 +0800 Subject: [PATCH 0480/1348] run acmetest in CI --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 62feca32..46f0dff4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,10 @@ script: - shellcheck -V - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) + - cd .. + - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" + - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest && ./letest.sh + matrix: fast_finish: true From 13ffa1704822911db362d1e85b163e54ff73a92b Mon Sep 17 00:00:00 2001 From: Philippe Kueck Date: Mon, 14 Nov 2016 15:56:07 +0100 Subject: [PATCH 0481/1348] add documentation for dns_nsupdate --- README.md | 1 + dnsapi/README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/README.md b/README.md index e86392ec..58cadc61 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,7 @@ You don't have do anything manually! 7. PowerDNS API 8. 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.) +9. nsupdate ##### More APIs are coming soon... diff --git a/dnsapi/README.md b/dnsapi/README.md index 94603154..a56f68b7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -112,10 +112,60 @@ acme.sh --issue --dns dns_pdns -d example.com -d www.example.com The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf`. + ## Use OVH/kimsufi/soyoustart/runabove API https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api +## Use nsupdate to automatically issue cert + +First, generate a key for updating the zone +``` +b=$(dnssec-keygen -a hmac-sha512 -b 512 -n USER -K /tmp foo) +cat > /etc/named/keys/update.key < Date: Tue, 15 Nov 2016 17:28:15 +0800 Subject: [PATCH 0482/1348] Update README.md --- dnsapi/README.md | 60 +++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 8f7df7b3..34be5070 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1,6 +1,6 @@ # How to use dns api -## Use CloudFlare domain api to automatically issue cert +## 1. Use CloudFlare domain api to automatically issue cert For now, we support clourflare integeration. @@ -22,7 +22,7 @@ The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf`, when ne -## Use Dnspod.cn domain api to automatically issue cert +## 2. Use Dnspod.cn domain api to automatically issue cert For now, we support dnspod.cn integeration. @@ -43,7 +43,7 @@ acme.sh --issue --dns dns_dp -d example.com -d www.example.com The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf`, when next time you use dnspod.cn api, it will reuse this key. -## Use Cloudxns.com domain api to automatically issue cert +## 3. Use Cloudxns.com domain api to automatically issue cert For now, we support Cloudxns.com integeration. @@ -64,7 +64,7 @@ acme.sh --issue --dns dns_cx -d example.com -d www.example.com The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. -## Use Godaddy.com domain api to automatically issue cert +## 4. Use Godaddy.com domain api to automatically issue cert We support Godaddy integration. @@ -89,7 +89,7 @@ acme.sh --issue --dns dns_gd -d example.com -d www.example.com The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. -## Use PowerDNS embedded api to automatically issue cert +## 5. Use PowerDNS embedded api to automatically issue cert We support PowerDNS embedded API integration. @@ -113,11 +113,11 @@ acme.sh --issue --dns dns_pdns -d example.com -d www.example.com The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf`. -## Use OVH/kimsufi/soyoustart/runabove API +## 6. Use OVH/kimsufi/soyoustart/runabove API https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api -## Use nsupdate to automatically issue cert +## 7. Use nsupdate to automatically issue cert First, generate a key for updating the zone ``` @@ -166,27 +166,7 @@ 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`. -# Use custom api - -If your api is not supported yet, you can write your own dns api. - -Let's assume you want to name it 'myapi', - -1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, -2. In the script, you must have a function named `dns_myapi_add()`. Which will be called by acme.sh to add dns records. -3. Then you can use your api to issue cert like: - -``` -acme.sh --issue --dns dns_myapi -d example.com -d www.example.com -``` - -For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) - -# Use lexicon dns api - -https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api - -## Use LuaDNS domain API +## 8. Use LuaDNS domain API Get your API token at https://api.luadns.com/settings @@ -204,7 +184,7 @@ acme.sh --issue --dns dns_lua --dnssleep 3 -d example.com -d www.example.c The `LUA_Key` and `LUA_Email` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. -## Use DNSMadeEasy domain API +## 9. Use DNSMadeEasy domain API Get your API credentials at https://cp.dnsmadeeasy.com/account/info @@ -222,5 +202,27 @@ acme.sh --issue --dns dns_me --dnssleep 3 -d example.com -d www.example.co The `ME_Key` and `ME_Secret` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. +# 10. Use custom api + +If your api is not supported yet, you can write your own dns api. + +Let's assume you want to name it 'myapi', + +1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, +2. In the script, you must have a function named `dns_myapi_add()`. Which will be called by acme.sh to add dns records. +3. Then you can use your api to issue cert like: + +``` +acme.sh --issue --dns dns_myapi -d example.com -d www.example.com +``` + +For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) + +# 11. Use lexicon dns api + +https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api + + + From b87503715004c8924d196ee017d33eeaf4f3a5eb Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 15 Nov 2016 17:38:35 +0800 Subject: [PATCH 0483/1348] check NGROK_BIN --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 46f0dff4..991e4ed4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ script: - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) - cd .. - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" + - $NGROK_BIN - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest && ./letest.sh From 15777732d3d4e595d6bb6e712c3381b1d84f1e7d Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 15 Nov 2016 19:20:41 +0800 Subject: [PATCH 0484/1348] test ngrok --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 991e4ed4..9ec5405d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ script: - cd .. - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - $NGROK_BIN + - $NGROK_BIN http 80 --log stdout --log-format logfmt --log-level debug - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest && ./letest.sh From a2801649b40a0f9e3716b525985f0e6e7bdfc85d Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 15 Nov 2016 19:24:08 +0800 Subject: [PATCH 0485/1348] test ngrok --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9ec5405d..62c86a29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ script: - cd .. - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - $NGROK_BIN + - $NGROK_BIN authtoken "$NGROK_TOKEN" - $NGROK_BIN http 80 --log stdout --log-format logfmt --log-level debug - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest && ./letest.sh From 1c02b85802f53f39bbf06f2cacc02f0e9ae9c020 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 15 Nov 2016 19:29:02 +0800 Subject: [PATCH 0486/1348] test ngrok --- .travis.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 62c86a29..3d368d7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,8 +21,13 @@ script: - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - $NGROK_BIN - $NGROK_BIN authtoken "$NGROK_TOKEN" - - $NGROK_BIN http 80 --log stdout --log-format logfmt --log-level debug - - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest && ./letest.sh + - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest + - $NGROK_BIN http 80 --log stdout --log-format logfmt --log-level debug > ngrok.tmp & + - echo "===========================" + - cat ngrok.tmp + - echo ============================== + - grep -o 'Hostname:[a-z0-9]+.ngrok.io' ngrok.tmp + - ./letest.sh matrix: From 7f944c2c8b532eaec65e3452150a4be6f2a69173 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 15 Nov 2016 19:38:28 +0800 Subject: [PATCH 0487/1348] test ngrok --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3d368d7e..0cc14b6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ script: - $NGROK_BIN authtoken "$NGROK_TOKEN" - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - $NGROK_BIN http 80 --log stdout --log-format logfmt --log-level debug > ngrok.tmp & + - sleep 5 - echo "===========================" - cat ngrok.tmp - echo ============================== From 09f1c58872f2b8fd297e1c3e6cd3d4807482e95f Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 15 Nov 2016 19:45:04 +0800 Subject: [PATCH 0488/1348] test ngrok --- .travis.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0cc14b6a..fe615d82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,15 +19,7 @@ script: - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) - cd .. - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - - $NGROK_BIN - - $NGROK_BIN authtoken "$NGROK_TOKEN" - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - $NGROK_BIN http 80 --log stdout --log-format logfmt --log-level debug > ngrok.tmp & - - sleep 5 - - echo "===========================" - - cat ngrok.tmp - - echo ============================== - - grep -o 'Hostname:[a-z0-9]+.ngrok.io' ngrok.tmp - ./letest.sh From 1bb902984bb600b32004f98521631071f6fb440d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 15 Nov 2016 14:13:58 +0100 Subject: [PATCH 0489/1348] Clean up readme. --- README.md | 210 +++++++++++++++++++++++++++++------------------------- 1 file changed, 112 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index bb5c7c55..e09ef89b 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,23 @@ # An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) - An ACME protocol client written purely in Shell (Unix shell) language. -- Fully ACME protocol implementation. -- Simple, powerful and very easy to use. You only need 3 minutes to learn. -- Bash, dash and sh compatible. +- Full ACME protocol implementation. +- Simple, powerful and very easy to use. You only need 3 minutes to learn it. +- Bash, dash and sh compatible. - Simplest shell script for Let's Encrypt free certificate client. -- Purely written in Shell with no dependencies on python or Let's Encrypt official client. -- Just one script, to issue, renew and install your certificates automatically. +- 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. - DOES NOT require `root/sudoer` access. It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. - Wiki: https://github.com/Neilpang/acme.sh/wiki + # [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) -#Tested OS + +# Tested OS + | NO | Status| Platform| |----|-------|---------| |1|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu @@ -38,41 +40,39 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris |19|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux -For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): +For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): https://github.com/Neilpang/acmetest -# Supported Mode -1. Webroot mode -2. Standalone mode -3. Apache mode -4. Dns mode +# Supported modes +- Webroot mode +- Standalone mode +- Apache mode +- DNS mode # 1. How to install -### 1. Install online: +### 1. Install online Check this project: https://github.com/Neilpang/get.acme.sh ```bash curl https://get.acme.sh | sh - ``` Or: ```bash wget -O - https://get.acme.sh | sh - ``` -### 2. Or, Install from git: +### 2. Or, Install from git -Clone this project: +Clone this project and launch installation: ```bash git clone https://github.com/Neilpang/acme.sh.git @@ -82,14 +82,14 @@ cd ./acme.sh You `don't have to be root` then, although `it is recommended`. -Advanced Installation: https://github.com/Neilpang/acme.sh/wiki/How-to-install +Advanced Installation: https://github.com/Neilpang/acme.sh/wiki/How-to-install The installer will perform 3 actions: -1. Create and copy `acme.sh` to your home dir (`$HOME`): `~/.acme.sh/`. -All certs will be placed in this folder. -2. Create alias for: `acme.sh=~/.acme.sh/acme.sh`. -3. Create everyday cron job to check and renew the cert if needed. +1. Create and copy `acme.sh` to your home dir (`$HOME`): `~/.acme.sh/`. +All certs will be placed in this folder too. +2. Create alias for: `acme.sh=~/.acme.sh/acme.sh`. +3. Create daily cron job to check and renew the certs if needed. Cron entry example: @@ -97,18 +97,17 @@ Cron entry example: 0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null ``` -After the installation, you must close current terminal and reopen again to make the alias take effect. +After the installation, you must close the current terminal and reopen it to make the alias take effect. + +Ok, you are ready to issue certs now. -Ok, you are ready to issue cert now. Show help message: ``` - root@v1:~# acme.sh -h - ``` - -# 2. Just issue a cert: + +# 2. Just issue a cert **Example 1:** Single domain. @@ -119,56 +118,57 @@ acme.sh --issue -d example.com -w /home/wwwroot/example.com **Example 2:** Multiple domains in the same cert. ```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. -Second argument **"example.com"** is the main domain you want to issue cert for. -You must have at least a domain there. +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 point and bind all the domains to the same webroot dir: `/home/wwwroot/example.com`. -Generate/issued certs will be placed in `~/.acme.sh/example.com/` +Generated/issued certs will be placed in `~/.acme.sh/example.com/` -The issued cert will be renewed every **60** days automatically. +The issued cert will be renewed automatically every **60** days. More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# 3. Install the issued cert to apache/nginx etc. +# 3. Install the issued cert to Apache/Nginx etc. -After you issue a cert, you probably want to install/copy the cert to your nginx/apache or other servers. -You **MUST** use this command to copy the certs to the target files, **Do NOT** use the certs files in **.acme.sh/** folder, they are for internal use only, the folder structure may change in future. +After you issue a cert, you probably want to install/copy the cert to your Apache/Nginx or other servers. +You **MUST** use this command to copy the certs to the target files, **DO NOT** use the certs files in **~/.acme.sh/** folder, they are for internal use only, the folder structure may change in the future. -**nginx** example +**Apache** example: ```bash acme.sh --installcert -d example.com \ ---keypath /path/to/keyfile/in/nginx/key.pem \ ---fullchainpath path/to/fullchain/nginx/cert.pem \ ---reloadcmd "service nginx restart" +--certpath /path/to/certfile/in/apache/cert.pem \ +--keypath /path/to/keyfile/in/apache/key.pem \ +--fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ +--reloadcmd "service apache2 restart" ``` -**apache** example +**Nginx** example: ```bash acme.sh --installcert -d example.com \ ---certpath /path/to/certfile/in/apache/cert.pem \ ---keypath /path/to/keyfile/in/apache/key.pem \ ---fullchainpath path/to/fullchain/certfile/apache/fullchain.pem \ ---reloadcmd "service apache2 restart" +--keypath /path/to/keyfile/in/nginx/key.pem \ +--fullchainpath /path/to/fullchain/nginx/cert.pem \ +--reloadcmd "service nginx restart" ``` Only the domain is required, all the other parameters are optional. -Install/copy the issued cert/key to the production apache or nginx path. +Install/copy the issued cert/key to the production Apache or Nginx path. + +The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the Apache/Nginx service will be restarted automatically by the command: `service apache2 restart` or `service nginx restart`. -The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`. # 4. Use Standalone server to issue cert -**(requires you be root/sudoer, or you have permission to listen tcp 80 port)** +**(requires you to be root/sudoer or have permission to listen on port 80 (TCP))** -The tcp `80` port **MUST** be free to listen, otherwise you will be prompted to free the `80` port and try again. +Port `80` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. ```bash acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com @@ -176,13 +176,14 @@ acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# 5. Use Standalone tls server to issue cert -**(requires you be root/sudoer, or you have permission to listen tcp 443 port)** +# 5. Use Standalone TLS server to issue cert + +**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))** acme.sh supports `tls-sni-01` validation. -The tcp `443` port **MUST** be free to listen, otherwise you will be prompted to free the `443` port and try again. +Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. ```bash acme.sh --issue --tls -d example.com -d www.example.com -d cp.example.com @@ -190,31 +191,33 @@ acme.sh --issue --tls -d example.com -d www.example.com -d cp.example.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + # 6. Use Apache mode -**(requires you be root/sudoer, since it is required to interact with apache server)** +**(requires you to be root/sudoer, since it is required to interact with Apache server)** -If you are running a web server, apache or nginx, it is recommended to use the `Webroot mode`. +If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`. -Particularly, if you are running an apache server, you should use apache mode instead. This mode doesn't write any files to your web root folder. +Particularly, if you are running an Apache server, you should use Apache mode instead. This mode doesn't write any files to your web root folder. -Just set string "apache" as the second argument, it will force use of apache plugin automatically. +Just set string "apache" as the second argument and it will force use of apache plugin automatically. ``` -acme.sh --issue --apache -d example.com -d www.example.com -d user.example.com +acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com ``` More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + # 7. Use DNS mode: Support the `dns-01` challenge. ```bash -acme.sh --issue --dns -d example.com -d www.example.com -d user.example.com +acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com ``` -You should get the output like below: +You should get an output like below: ``` Add the following txt record: @@ -226,7 +229,6 @@ Domain:_acme-challenge.www.example.com Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Please add those txt records to the domains. Waiting for the dns to take effect. - ``` Then just rerun with `renew` argument: @@ -237,53 +239,54 @@ acme.sh --renew -d example.com Ok, it's finished. + # 8. Automatic DNS API integration -If your DNS provider supports API access, we can use API to automatically issue the certs. +If your DNS provider supports API access, we can use that API to automatically issue the certs. -You don't have do anything manually! +You don't have to do anything manually! ### Currently acme.sh supports: -1. Cloudflare.com API -2. Dnspod.cn API -3. Cloudxns.com API -4. Godaddy.com API -5. OVH, kimsufi, soyoustart and runabove API -6. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 -7. PowerDNS API -8. 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.) -9. LuaDNS.com API -10. DNSMadeEasy.com API -11. nsupdate +- CloudFlare.com API +- DNSPod.cn API +- CloudXNS.com API +- GoDaddy.com API +- OVH, kimsufi, soyoustart and runabove API +- AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 +- PowerDNS.com API +- 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.) +- LuaDNS.com API +- DNSMadeEasy.com API + +**More APIs coming soon...** -##### More APIs are coming soon... +If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project. -If your DNS provider is not on the supported list above, you can write your own script API easily. If you do please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute to the project. +For more details: [How to use DNS API](dnsapi) -For more details: [How to use dns api](dnsapi) -# 9. Issue ECC certificate: +# 9. Issue ECC certificates -`Let's Encrypt` now can issue **ECDSA** certificates. +`Let's Encrypt` can now issue **ECDSA** certificates. -And we also support it. +And we support them too! Just set the `length` parameter with a prefix `ec-`. For example: -### Single domain ECC cerfiticate: +### Single domain ECC cerfiticate ```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 ``` -SAN multi domain ECC certificate: +### SAN multi domain ECC certificate ```bash -acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength ec-256 +acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength ec-256 ``` Please look at the last parameter above. @@ -295,40 +298,48 @@ Valid values are: 3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)** -# 10. How to renew the cert +# 10. How to renew the issued certs -No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. +No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. However, you can also force to renew any cert: ``` -acme.sh --renew -d example.com --force +acme.sh --renew -d example.com --force ``` or, for ECC cert: + ``` -acme.sh --renew -d example.com --force --ecc +acme.sh --renew -d example.com --force --ecc ``` + # 11. How to upgrade `acme.sh` -acme.sh is in developing, it's strongly recommended to use the latest code. + +acme.sh is in constant developement, so it's strongly recommended to use the latest code. You can update acme.sh to the latest code: + ``` acme.sh --upgrade ``` -You can enable auto upgrade: +You can also enable auto upgrade: + ``` -acme.sh --upgrade --auto-upgrade +acme.sh --upgrade --auto-upgrade ``` -Then **acme.sh** will keep up to date automatically. + +Then **acme.sh** will be kept up to date automatically. Disable auto upgrade: + ``` -acme.sh --upgrade --auto-upgrade 0 +acme.sh --upgrade --auto-upgrade 0 ``` + # 12. Issue a cert from an existing CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR @@ -340,22 +351,25 @@ Speak ACME language using shell, directly to "Let's Encrypt". TODO: -# Acknowledgment + +# Acknowledgments + 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme 3. Certbot: https://github.com/certbot/certbot + # License & Others License is GPLv3 Please Star and Fork me. -[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcomed. +[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome. # Donate -1. PayPal: donate@acme.sh -[Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) +1. PayPal: donate@acme.sh +[Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) From d20831e41a305fb34d52941ed67041d01969da7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 15 Nov 2016 14:24:07 +0100 Subject: [PATCH 0490/1348] Update DNS API readme --- dnsapi/README.md | 129 ++++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 75 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 34be5070..f1df726f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1,99 +1,80 @@ -# How to use dns api +# How to use DNS API -## 1. Use CloudFlare domain api to automatically issue cert +## 1. Use CloudFlare domain API to automatically issue cert -For now, we support clourflare integeration. - -First you need to login to your clourflare account to get your api key. +First you need to login to your CloudFlare account to get your API key. ``` export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" - export CF_Email="xxxx@sss.com" - ``` -Ok, let's issue cert now: +Ok, let's issue a cert now: ``` -acme.sh --issue --dns dns_cf -d example.com -d www.example.com +acme.sh --issue --dns dns_cf -d example.com -d www.example.com ``` -The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. - +The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 2. Use Dnspod.cn domain api to automatically issue cert +## 2. Use DNSPod.cn domain API to automatically issue cert -For now, we support dnspod.cn integeration. - -First you need to login to your dnspod.cn account to get your api key and key id. +First you need to login to your DNSPod account to get your API Key and ID. ``` export DP_Id="1234" - export DP_Key="sADDsdasdgdsf" - ``` -Ok, let's issue cert now: +Ok, let's issue a cert now: ``` -acme.sh --issue --dns dns_dp -d example.com -d www.example.com +acme.sh --issue --dns dns_dp -d example.com -d www.example.com ``` -The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf`, when next time you use dnspod.cn api, it will reuse this key. - +The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 3. Use Cloudxns.com domain api to automatically issue cert -For now, we support Cloudxns.com integeration. +## 3. Use CloudXNS.com domain API to automatically issue cert -First you need to login to your Cloudxns.com account to get your api key and key secret. +First you need to login to your CloudXNS account to get your API Key and Secret. ``` export CX_Key="1234" - export CX_Secret="sADDsdasdgdsf" - ``` -Ok, let's issue cert now: +Ok, let's issue a cert now: ``` -acme.sh --issue --dns dns_cx -d example.com -d www.example.com +acme.sh --issue --dns dns_cx -d example.com -d www.example.com ``` -The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use Cloudxns.com api, it will reuse this key. +The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 4. Use Godaddy.com domain api to automatically issue cert +## 4. Use GoDaddy.com domain API to automatically issue cert -We support Godaddy integration. - -First you need to login to your Godaddy account to get your api key and api secret. +First you need to login to your GoDaddy account to get your API Key and Secret. https://developer.godaddy.com/keys/ -Please Create a Production key, instead of a Test key. - +Please create a Production key, instead of a Test key. ``` export GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" - export GD_Secret="asdfsdafdsfdsfdsfdsfdsafd" - ``` -Ok, let's issue cert now: +Ok, let's issue a cert now: ``` -acme.sh --issue --dns dns_gd -d example.com -d www.example.com +acme.sh --issue --dns dns_gd -d example.com -d www.example.com ``` -The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key. +The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 5. Use PowerDNS embedded api to automatically issue cert -We support PowerDNS embedded API integration. +## 5. Use PowerDNS embedded API to automatically issue cert -First you need to enable api and set your api-token in PowerDNS configuration. +First you need to login to your PowerDNS account to enable the API and set your API-Token in the configuration. https://doc.powerdns.com/md/httpapi/README/ @@ -102,21 +83,21 @@ export PDNS_Url="http://ns.example.com:8081" export PDNS_ServerId="localhost" export PDNS_Token="0123456789ABCDEF" export PDNS_Ttl=60 - ``` -Ok, let's issue cert now: +Ok, let's issue a cert now: ``` -acme.sh --issue --dns dns_pdns -d example.com -d www.example.com +acme.sh --issue --dns dns_pdns -d example.com -d www.example.com ``` -The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf`. +The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 6. Use OVH/kimsufi/soyoustart/runabove API +## 6. Use OVH/kimsufi/soyoustart/runabove API to automatically issue cert https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api + ## 7. Use nsupdate to automatically issue cert First, generate a key for updating the zone @@ -137,6 +118,7 @@ include "/etc/named/keys/update.key"; ``` Next, configure your zone to allow dynamic updates. + Depending on your named version, use either ``` zone "example.com" { @@ -153,18 +135,21 @@ zone "example.com" { }; } ``` -Finally, make the dns server and update key available to `acme.sh` + +Finally, make the DNS server and update Key available to `acme.sh` + ``` -export NSUPDATE_SERVER=dns.example.com -export NSUPDATE_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa== +export NSUPDATE_SERVER="dns.example.com" +export NSUPDATE_KEY="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==" ``` -Ok, let's issue cert now: +Ok, let's issue a cert now: ``` -acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com +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`. +The `NSUPDATE_SERVER` and `NSUPDATE_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + ## 8. Use LuaDNS domain API @@ -172,17 +157,16 @@ Get your API token at https://api.luadns.com/settings ``` export LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" - export LUA_Email="xxxx@sss.com" - ``` To issue a cert: ``` -acme.sh --issue --dns dns_lua --dnssleep 3 -d example.com -d www.example.com +acme.sh --issue --dns dns_lua -d example.com -d www.example.com ``` -The `LUA_Key` and `LUA_Email` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. +The `LUA_Key` and `LUA_Email` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + ## 9. Use DNSMadeEasy domain API @@ -190,39 +174,34 @@ Get your API credentials at https://cp.dnsmadeeasy.com/account/info ``` export ME_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" - export ME_Secret="qdfqsdfkjdskfj" - ``` To issue a cert: ``` -acme.sh --issue --dns dns_me --dnssleep 3 -d example.com -d www.example.com +acme.sh --issue --dns dns_me -d example.com -d www.example.com ``` -The `ME_Key` and `ME_Secret` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. +The `ME_Key` and `ME_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + -# 10. Use custom api +# 10. 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. -Let's assume you want to name it 'myapi', +Let's assume you want to name it 'myapi': -1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, -2. In the script, you must have a function named `dns_myapi_add()`. Which will be called by acme.sh to add dns records. -3. Then you can use your api to issue cert like: +1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, +2. In the script you must have a function named `dns_myapi_add()` which will be called by acme.sh to add the DNS records. +3. Then you can use your API to issue cert like this: ``` -acme.sh --issue --dns dns_myapi -d example.com -d www.example.com +acme.sh --issue --dns dns_myapi -d example.com -d www.example.com ``` For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) -# 11. Use lexicon dns api - -https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api - - - +## 11. Use lexicon DNS API +https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api From c947322a69d62bb3780b07a80c066a2d6aac7f97 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 15 Nov 2016 21:49:35 +0800 Subject: [PATCH 0491/1348] sudo for travis --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fe615d82..f032890a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: shell +sudo: required env: global: @@ -20,7 +21,7 @@ script: - cd .. - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - ./letest.sh + - sudo ./letest.sh matrix: From 9c1747581f53d3dc0bb82e9cae83ff59008a67f5 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 16 Nov 2016 13:10:56 +0800 Subject: [PATCH 0492/1348] Update README.md --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e09ef89b..ca51c73d 100644 --- a/README.md +++ b/README.md @@ -248,17 +248,18 @@ You don't have to do anything manually! ### Currently acme.sh supports: -- CloudFlare.com API -- DNSPod.cn API -- CloudXNS.com API -- GoDaddy.com API -- OVH, kimsufi, soyoustart and runabove API -- AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 -- PowerDNS.com API -- lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api +1. CloudFlare.com API +1. DNSPod.cn API +1. CloudXNS.com API +1. GoDaddy.com API +1. OVH, kimsufi, soyoustart and runabove API +1. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 +1. PowerDNS.com API +1. 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.) -- LuaDNS.com API -- DNSMadeEasy.com API +1. LuaDNS.com API +1. DNSMadeEasy.com API +1. nsupdate API **More APIs coming soon...** From 54ae008dd76c8381b84a2e40d9030d8267255847 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 16 Nov 2016 19:45:00 +0800 Subject: [PATCH 0493/1348] minor, message typo --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 54e33730..a6a6e977 100755 --- a/acme.sh +++ b/acme.sh @@ -2132,7 +2132,7 @@ _on_issue_err() { if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" else - _err "Please use add '--debug' or '--log' to check more details." + _err "Please add '--debug' or '--log' to check more details." _err "See: $_DEBUG_WIKI" fi From 3e5b10244576c661d5cb3b960a55bff05aa9cb8a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 16 Nov 2016 22:20:47 +0800 Subject: [PATCH 0494/1348] fix error message for nc --- acme.sh | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/acme.sh b/acme.sh index a6a6e977..57420a85 100755 --- a/acme.sh +++ b/acme.sh @@ -1423,32 +1423,29 @@ _startserver() { #for centos ncat if _contains "$nchelp" "nmap.org"; then _debug "Using ncat: nmap.org" - if [ "$DEBUG" ]; then - if printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC "$Le_HTTPPort"; then - return - fi - else - if printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC "$Le_HTTPPort" >/dev/null 2>&1; then - return - fi + if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"; then + _exec_err + return 1 fi - _err "ncat listen error." + if [ "$DEBUG" ] ; then + _exec_err + fi + return fi # while true ; do - if [ "$DEBUG" ]; then - if ! printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC -p "$Le_HTTPPort"; then - printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC "$Le_HTTPPort" - fi - else - if ! printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC -p "$Le_HTTPPort" >/dev/null 2>&1; then - printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $_NC "$Le_HTTPPort" >/dev/null 2>&1 - fi + if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC -p \"$Le_HTTPPort\" >&2"; then + _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2" fi + if [ "$?" != "0" ]; then _err "nc listen error." + _exec_err exit 1 fi + if [ "$DEBUG" ] ; then + _exec_err + fi # done } @@ -1781,14 +1778,14 @@ _exec() { fi if [ "$_EXEC_TEMP_ERR" ]; then - "$@" 2>"$_EXEC_TEMP_ERR" + eval "$@ 2>>$_EXEC_TEMP_ERR" else - "$@" + eval "$@" fi } _exec_err() { - [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" + [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR" } _apachePath() { From 8f9034fc8b7146aa111a219cdcfd5dbaac275b24 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 16 Nov 2016 22:28:33 +0800 Subject: [PATCH 0495/1348] fix shfmt --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f032890a..a5e7a3b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ script: - chmod +x ~/shfmt - shellcheck -V - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" - - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code || (echo "Run shfmt to fix the formatting issues" && false) + - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code - cd .. - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest From 9a6e18ce80f72abbce3051d4853e9bd22fb9a619 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 16 Nov 2016 22:37:03 +0800 Subject: [PATCH 0496/1348] fix shfmt --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a5e7a3b6..e78787f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,8 @@ script: - chmod +x ~/shfmt - shellcheck -V - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" - - ~/shfmt -l -w -i 2 . && echo "shfmt OK" || git diff --exit-code + - ~/shfmt -l -w -i 2 . + - git diff --exit-code && echo "shfmt OK" - cd .. - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest From fa574fe833330a4e19395738627822ad87b1ae43 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 16 Nov 2016 22:44:39 +0800 Subject: [PATCH 0497/1348] fix shfmt --- .travis.yml | 4 ++-- acme.sh | 6 +++--- dnsapi/dns_nsupdate.sh | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index e78787f6..cf708c2f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,10 @@ addons: script: - curl -sSL $SHFMT_URL -o ~/shfmt - chmod +x ~/shfmt - - shellcheck -V - - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" - ~/shfmt -l -w -i 2 . - git diff --exit-code && echo "shfmt OK" + - shellcheck -V + - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" - cd .. - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest diff --git a/acme.sh b/acme.sh index 57420a85..ba4688cf 100755 --- a/acme.sh +++ b/acme.sh @@ -1325,7 +1325,7 @@ _clear_conf() { _sdkey="$2" if [ "$_c_c_f" ]; then _conf_data="$(cat "$_c_c_f")" - echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" > "$_c_c_f" + echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f" else _err "config file is empty, can not clear" fi @@ -1427,7 +1427,7 @@ _startserver() { _exec_err return 1 fi - if [ "$DEBUG" ] ; then + if [ "$DEBUG" ]; then _exec_err fi return @@ -1443,7 +1443,7 @@ _startserver() { _exec_err exit 1 fi - if [ "$DEBUG" ] ; then + if [ "$DEBUG" ]; then _exec_err fi # done diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index a024e314..5e7af831 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -1,6 +1,5 @@ #!/usr/bin/env sh - ######## Public functions ##################### #Usage: dns_nsupdate_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -22,7 +21,7 @@ EOF _err "error updating domain" return 1 fi - + return 0 } From ac26f841709e73fd56b3efa77911744b4b391cd1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 16 Nov 2016 22:53:59 +0800 Subject: [PATCH 0498/1348] fix shfmt --- dnsapi/dns_nsupdate.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 5e7af831..8067d2fe 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -44,7 +44,6 @@ EOF return 0 } - #################### Private functions bellow ################################## _checkKeyFile() { From 7575094cf34e6e218fbad9face68362360b2eedb Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 16 Nov 2016 23:53:32 +0800 Subject: [PATCH 0499/1348] fix _exists --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ba4688cf..280cb415 100755 --- a/acme.sh +++ b/acme.sh @@ -249,7 +249,7 @@ _exists() { fi if command >/dev/null 2>&1; then command -v "$cmd" >/dev/null 2>&1 - elif which >/dev/null 2>&1; then + elif which ls >/dev/null 2>&1; then which "$cmd" >/dev/null 2>&1 fi ret="$?" From 4a56b2406b7b44f0f791008e7f99bf339e25292f Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 17 Nov 2016 00:22:45 +0800 Subject: [PATCH 0500/1348] fix check email --- dnsapi/dns_cf.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index cacb5b39..7f2a0977 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -22,6 +22,12 @@ dns_cf_add() { return 1 fi + if ! _contains "$CF_Email" "@"; then + _err "It seems that the CF_Email=$CF_Email is not a valid email address." + _err "Please check and retry." + return 1 + fi + #save the api key and email to the account conf file. _saveaccountconf CF_Key "$CF_Key" _saveaccountconf CF_Email "$CF_Email" From ab45b7783f19447c7d7bd8a06e368a6461933b86 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 17 Nov 2016 00:25:40 +0800 Subject: [PATCH 0501/1348] fix format --- dnsapi/dns_cf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 7f2a0977..dd8c9143 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -27,7 +27,7 @@ dns_cf_add() { _err "Please check and retry." return 1 fi - + #save the api key and email to the account conf file. _saveaccountconf CF_Key "$CF_Key" _saveaccountconf CF_Email "$CF_Email" From 82dc2244c00b9de6636eebff2a0ec3dce3bcb174 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 17 Nov 2016 13:17:29 +0800 Subject: [PATCH 0502/1348] fix _exists for busybox --- acme.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 280cb415..a4a08392 100755 --- a/acme.sh +++ b/acme.sh @@ -247,9 +247,12 @@ _exists() { _usage "Usage: _exists cmd" return 1 fi - if command >/dev/null 2>&1; then + + if eval type type >/dev/null 2>&1; then + eval type "$cmd" >/dev/null 2>&1 + elif command >/dev/null 2>&1; then command -v "$cmd" >/dev/null 2>&1 - elif which ls >/dev/null 2>&1; then + elif which which >/dev/null 2>&1; then which "$cmd" >/dev/null 2>&1 fi ret="$?" From ce4be4e91eb5e2d34b4a3363fb2514e0088ae5ed Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 17 Nov 2016 13:20:20 +0800 Subject: [PATCH 0503/1348] fix _exists --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a4a08392..1397f870 100755 --- a/acme.sh +++ b/acme.sh @@ -252,7 +252,7 @@ _exists() { eval type "$cmd" >/dev/null 2>&1 elif command >/dev/null 2>&1; then command -v "$cmd" >/dev/null 2>&1 - elif which which >/dev/null 2>&1; then + else which "$cmd" >/dev/null 2>&1 fi ret="$?" From 2ce2a15fc6e5a77315db234483abe594bf8fe8c8 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 17 Nov 2016 13:40:10 +0800 Subject: [PATCH 0504/1348] add PULL_REQUEST_TEMPLATE template --- .github/PULL_REQUEST_TEMPLATE.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..2df6e9c4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ + \ No newline at end of file From d5c00071d33943876d31559c36f5ad6da767e9c1 Mon Sep 17 00:00:00 2001 From: magna-z Date: Thu, 17 Nov 2016 14:52:00 +0300 Subject: [PATCH 0505/1348] Add functional in method dns_pdns_rm() --- dnsapi/dns_pdns.sh | 50 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 5d6d99fd..a2c29075 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -12,6 +12,8 @@ DEFAULT_PDNS_TTL=60 ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" +#fulldomain +#txtvalue dns_pdns_add() { fulldomain=$1 txtvalue=$2 @@ -50,7 +52,7 @@ dns_pdns_add() { _saveaccountconf PDNS_Ttl "$PDNS_Ttl" fi - _debug "First detect the root zone" + _debug "Detect root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 @@ -68,6 +70,18 @@ dns_pdns_add() { dns_pdns_rm() { fulldomain=$1 + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain "$_domain" + + if ! rm_record "$_domain" "$fulldomain"; then + return 1 + fi + + return 0 } set_record() { @@ -76,14 +90,43 @@ set_record() { full=$2 txtvalue=$3 - if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"name\": \"$full.\", \"changetype\": \"REPLACE\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then _err "Set txt record error." return 1 fi + + if ! notify_slaves "$root"; then + return 1 + fi + + return 0 +} + +rm_record() { + _info "Remove record" + root=$1 + full=$2 + + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then + _err "Delete txt record error." + return 1 + fi + + if ! notify_slaves "$root"; then + return 1 + fi + + return 0 +} + +notify_slaves() { + root=$1 + if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify"; then - _err "Notify servers error." + _err "Notify slaves error." return 1 fi + return 0 } @@ -113,6 +156,7 @@ _get_root() { i=$(_math $i + 1) done _debug "$domain not found" + return 1 } From 3498a5856aed22ee696d70c1d269a03f7f96758f Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 18 Nov 2016 19:40:41 +0800 Subject: [PATCH 0506/1348] fix bug https://github.com/Neilpang/acme.sh/issues/401 --- acme.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index 1397f870..2b2386d0 100755 --- a/acme.sh +++ b/acme.sh @@ -1705,8 +1705,6 @@ _initpath() { return 0 fi - mkdir -p "$CA_DIR" - domain="$1" _ilength="$2" @@ -1726,13 +1724,6 @@ _initpath() { _debug DOMAIN_PATH "$DOMAIN_PATH" fi - if [ ! -d "$DOMAIN_PATH" ]; then - if ! mkdir -p "$DOMAIN_PATH"; then - _err "Can not create domain path: $DOMAIN_PATH" - return 1 - fi - fi - if [ -z "$DOMAIN_CONF" ]; then DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" fi @@ -3005,6 +2996,10 @@ renewAll() { for di in "${CERT_HOME}"/*.*/; do _debug di "$di" + if ! [ -d "$di" ] ; then + _debug "Not directory, skip: $di" + continue + fi d=$(basename "$di") _debug d "$d" ( @@ -3127,6 +3122,10 @@ list() { if [ "$_raw" ]; then printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew" for di in "${CERT_HOME}"/*.*/; do + if ! [ -d "$di" ] ; then + _debug "Not directory, skip: $di" + continue + fi d=$(basename "$di") _debug d "$d" ( From 44483dba218947d8e9900912d06aa68ddd012376 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 18 Nov 2016 19:44:43 +0800 Subject: [PATCH 0507/1348] fix format --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 2b2386d0..6f948f51 100755 --- a/acme.sh +++ b/acme.sh @@ -2996,7 +2996,7 @@ renewAll() { for di in "${CERT_HOME}"/*.*/; do _debug di "$di" - if ! [ -d "$di" ] ; then + if ! [ -d "$di" ]; then _debug "Not directory, skip: $di" continue fi @@ -3122,7 +3122,7 @@ list() { if [ "$_raw" ]; then printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew" for di in "${CERT_HOME}"/*.*/; do - if ! [ -d "$di" ] ; then + if ! [ -d "$di" ]; then _debug "Not directory, skip: $di" continue fi From a3c0c7546df4d4e8d8dc384b0642101572085fd3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 18 Nov 2016 20:14:08 +0800 Subject: [PATCH 0508/1348] fix egrep performance --- acme.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 6f948f51..e3f844ea 100755 --- a/acme.sh +++ b/acme.sh @@ -349,10 +349,8 @@ _sed_i() { } _egrep_o() { - if _contains "$(egrep -o 2>&1)" "egrep: illegal option -- o"; then + if ! egrep -o "$1" 2>/dev/null; then sed -n 's/.*\('"$1"'\).*/\1/p' - else - egrep -o "$1" fi } From 5a7b7b51c580898a101bf15ba51c532ef4fbde23 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 18 Nov 2016 21:40:03 +0800 Subject: [PATCH 0509/1348] fix ngrok --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cf708c2f..8829e472 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,6 @@ script: - shellcheck -V - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" - cd .. - - curl -sSL https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && export NGROK_BIN="$(pwd)/ngrok" - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - sudo ./letest.sh From e009ec8b935342c1d8cf3ff9fe55e88f0f7051a2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 20 Nov 2016 22:57:07 +0800 Subject: [PATCH 0510/1348] Support AWS Route53 api --- acme.sh | 24 +++-- dnsapi/dns_aws.sh | 220 ++++++++++++++++++++++++++++++++++++++++++++++ dnsapi/dns_me.sh | 2 +- 3 files changed, 239 insertions(+), 7 deletions(-) create mode 100644 dnsapi/dns_aws.sh diff --git a/acme.sh b/acme.sh index e3f844ea..36492cb8 100755 --- a/acme.sh +++ b/acme.sh @@ -329,6 +329,18 @@ _h2b() { done } +#hex string +_hex() { + _str="$1" + _str_len=${#_str} + _h_i=1 + while [ "$_h_i" -le "$_str_len" ]; do + _str_c="$(printf "%s" "$_str" | cut -c "$_h_i" )" + printf "%02x" "'$_str_c" + _h_i="$(_math "$_h_i" + 1)" + done +} + #options file _sed_i() { options="$1" @@ -426,23 +438,23 @@ _digest() { } -#Usage: hashalg secret [outputhex] -#Output Base64-encoded hmac +#Usage: hashalg secret_hex [outputhex] +#Output binary hmac _hmac() { alg="$1" - hmac_sec="$2" + secret_hex="$2" outputhex="$3" - if [ -z "$hmac_sec" ]; then + if [ -z "$secret_hex" ]; then _usage "Usage: _hmac hashalg secret [outputhex]" return 1 fi if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - openssl dgst -"$alg" -hmac "$hmac_sec" | cut -d = -f 2 | tr -d ' ' + openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" | cut -d = -f 2 | tr -d ' ' else - openssl dgst -"$alg" -hmac "$hmac_sec" -binary | _base64 + openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary fi else _err "$alg is not supported yet" diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh new file mode 100644 index 00000000..ecf1156c --- /dev/null +++ b/dnsapi/dns_aws.sh @@ -0,0 +1,220 @@ +#!/usr/bin/env sh + +# +#AWS_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#AWS_SECRET_ACCESS_KEY="xxxxxxx" + +#This is the Amazon Route53 api wrapper for acme.sh + +AWS_HOST="route53.amazonaws.com" +AWS_URL="https://$AWS_HOST" + +AWS_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-use-Amazon-Route53-API" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_aws_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then + AWS_ACCESS_KEY_ID="" + AWS_SECRET_ACCESS_KEY="" + _err "You don't specify aws route53 api key id and and api key secret yet." + _err "Please create you key and try again. see $(__green $AWS_WIKI)" + return 1 + fi + + _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" + _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_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" + + _aws_tmpl_xml="UPSERT$fulldomainTXT300\"$txtvalue\"" + + if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then + _info "txt record updated sucess." + return 0 + fi + + return 1; +} + + + +#fulldomain +dns_aws_rm() { + fulldomain=$1 + +} + + +#################### Private functions bellow ################################## + +_get_root() { + domain=$1 + i=2 + p=1 + + if aws_rest GET "2013-04-01/hostedzone"; then + _debug "response" "$response" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h."; then + hostedzone="$(echo "$response" | _egrep_o ".*$h..*")" + _debug hostedzone "$hostedzone" + if [ -z "$hostedzone" ]; then + _err "Error, can not get hostedzone." + return 1 + fi + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*" | head -n 1 | _egrep_o ">.*<" | 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 +aws_rest() { + mtd="$1" + ep="$2" + qsr="$3" + data="$4" + + _debug mtd "$mtd" + _debug ep "$ep" + _debug qsr "$qsr" + _debug data "$data" + + CanonicalURI="/$ep" + _debug2 CanonicalURI "$CanonicalURI" + + CanonicalQueryString="$qsr" + _debug2 CanonicalQueryString "$CanonicalQueryString" + + RequestDate="$(date -u +"%Y%m%dT%H%M%SZ")" + _debug2 RequestDate "$RequestDate" + + #RequestDate="20161120T141056Z" ############## + + _H1="x-amz-date: $RequestDate" + + aws_host="$AWS_HOST" + CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" + _debug2 CanonicalHeaders "$CanonicalHeaders" + + SignedHeaders="host;x-amz-date" + _debug2 SignedHeaders "$SignedHeaders" + + RequestPayload="$data" + _debug2 RequestPayload "$RequestPayload" + + Hash="sha256" + + CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$(printf "%s" "$RequestPayload" | _digest "$Hash" hex)" + _debug2 CanonicalRequest "$CanonicalRequest" + + HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex )" + _debug2 HashedCanonicalRequest "$HashedCanonicalRequest" + + Algorithm="AWS4-HMAC-SHA256" + _debug2 Algorithm "$Algorithm" + + RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8 )" + _debug2 RequestDateOnly "$RequestDateOnly" + + Region="us-east-1" + Service="route53" + + CredentialScope="$RequestDateOnly/$Region/$Service/aws4_request" + _debug2 CredentialScope "$CredentialScope" + + StringToSign="$Algorithm\n$RequestDate\n$CredentialScope\n$HashedCanonicalRequest" + + _debug2 StringToSign "$StringToSign" + + kSecret="AWS4$AWS_SECRET_ACCESS_KEY" + + #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################ + + _debug2 kSecret "$kSecret" + + kSecretH="$(_hex "$kSecret")" + _debug2 kSecretH "$kSecretH" + + kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" + _debug2 kDateH "$kDateH" + + kRegionH="$(printf "$Region%s" | _hmac "$Hash" "$kDateH" hex)" + _debug2 kRegionH "$kRegionH" + + kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" + _debug2 kServiceH "$kServiceH" + + kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)" + _debug2 kSigningH "$kSigningH" + + signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" + _debug2 signature "$signature" + + Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" + _debug2 Authorization "$Authorization" + + _H3="Authorization: $Authorization" + _debug _H3 "$_H3" + + url="$AWS_URL/$ep" + + if [ "$mtd" = "GET" ]; then + response="$(_get "$url")" + else + response="$(_post "$data" "$url")" + fi + + _ret="$?" + if [ "$_ret" = "0" ]; then + if _contains "$response" " Date: Sun, 20 Nov 2016 23:04:28 +0800 Subject: [PATCH 0511/1348] fix format --- acme.sh | 2 +- dnsapi/dns_aws.sh | 28 +++++----------------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/acme.sh b/acme.sh index 36492cb8..63ec7d44 100755 --- a/acme.sh +++ b/acme.sh @@ -335,7 +335,7 @@ _hex() { _str_len=${#_str} _h_i=1 while [ "$_h_i" -le "$_str_len" ]; do - _str_c="$(printf "%s" "$_str" | cut -c "$_h_i" )" + _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" printf "%02x" "'$_str_c" _h_i="$(_math "$_h_i" + 1)" done diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index ecf1156c..c0ab72df 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -40,31 +40,28 @@ dns_aws_add() { _debug _domain "$_domain" _aws_tmpl_xml="UPSERT$fulldomainTXT300\"$txtvalue\"" - + if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then _info "txt record updated sucess." return 0 fi - return 1; + return 1 } - - #fulldomain dns_aws_rm() { fulldomain=$1 } - #################### Private functions bellow ################################## _get_root() { domain=$1 i=2 p=1 - + if aws_rest GET "2013-04-01/hostedzone"; then _debug "response" "$response" while true; do @@ -96,7 +93,6 @@ _get_root() { return 1 } - #method uri qstr data aws_rest() { mtd="$1" @@ -137,13 +133,13 @@ aws_rest() { CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$(printf "%s" "$RequestPayload" | _digest "$Hash" hex)" _debug2 CanonicalRequest "$CanonicalRequest" - HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex )" + HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex)" _debug2 HashedCanonicalRequest "$HashedCanonicalRequest" Algorithm="AWS4-HMAC-SHA256" _debug2 Algorithm "$Algorithm" - RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8 )" + RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8)" _debug2 RequestDateOnly "$RequestDateOnly" Region="us-east-1" @@ -204,17 +200,3 @@ aws_rest() { return "$_ret" } - - - - - - - - - - - - - - From 2f1bc5864f03ce9b7b3c2e4cbf6f192fabb5f255 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 20 Nov 2016 23:09:57 +0800 Subject: [PATCH 0512/1348] fix format --- dnsapi/dns_aws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index c0ab72df..15bf7b14 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -132,7 +132,7 @@ aws_rest() { CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$(printf "%s" "$RequestPayload" | _digest "$Hash" hex)" _debug2 CanonicalRequest "$CanonicalRequest" - + HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex)" _debug2 HashedCanonicalRequest "$HashedCanonicalRequest" @@ -197,6 +197,6 @@ aws_rest() { return 1 fi fi - + return "$_ret" } From 5b771039fc705ed822a3331f5ee4761b5fab2346 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 20 Nov 2016 23:21:07 +0800 Subject: [PATCH 0513/1348] Support AWS Route53 api --- README.md | 2 +- acme.sh | 5 +++++ dnsapi/README.md | 20 ++++++++++++++++++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ca51c73d..69348bf9 100644 --- a/README.md +++ b/README.md @@ -253,7 +253,7 @@ You don't have to do anything manually! 1. CloudXNS.com API 1. GoDaddy.com API 1. OVH, kimsufi, soyoustart and runabove API -1. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65 +1. AWS Route 53 1. PowerDNS.com API 1. 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.) diff --git a/acme.sh b/acme.sh index 63ec7d44..7a305cf2 100755 --- a/acme.sh +++ b/acme.sh @@ -3613,6 +3613,11 @@ _initconf() { #PDNS_Token=\"0123456789ABCDEF\" #PDNS_Ttl=60 +####################### +#Amazon Route53: +#AWS_ACCESS_KEY_ID=XXXXXXXXXX +#AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX + " >"$ACCOUNT_CONF_PATH" fi } diff --git a/dnsapi/README.md b/dnsapi/README.md index f1df726f..9a8730c9 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -185,7 +185,23 @@ acme.sh --issue --dns dns_me -d example.com -d www.example.com The `ME_Key` and `ME_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -# 10. Use custom API +## 10. Use Amazon Route53 domain API + +https://github.com/Neilpang/acme.sh/wiki/How-to-use-Amazon-Route53-API + +``` +export AWS_ACCESS_KEY_ID=XXXXXXXXXX +export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX +``` + +To issue a cert: +``` +acme.sh --issue --dns dns_aws -d example.com -d www.example.com +``` + +The `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +# 11. Use custom API If your API is not supported yet, you can write your own DNS API. @@ -202,6 +218,6 @@ acme.sh --issue --dns dns_myapi -d example.com -d www.example.com For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) -## 11. Use lexicon DNS API +## 12. Use lexicon DNS API https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api From 7834c252534d6d24c8a307feec7aa7428c65e7e6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 21 Nov 2016 20:56:50 +0800 Subject: [PATCH 0514/1348] refactor HTTPS_INSECURE --- acme.sh | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index 7a305cf2..6b63c9ed 100755 --- a/acme.sh +++ b/acme.sh @@ -1049,9 +1049,6 @@ _inithttp() { _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " fi - if [ "$HTTPS_INSECURE" ]; then - _ACME_CURL="$_ACME_CURL --insecure " - fi fi if [ -z "$_ACME_WGET" ] && _exists "wget"; then @@ -1062,9 +1059,6 @@ _inithttp() { if [ "$CA_BUNDLE" ]; then _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " fi - if [ "$HTTPS_INSECURE" ]; then - _ACME_WGET="$_ACME_WGET --no-check-certificate " - fi fi __HTTP_INITIALIZED=1 @@ -1089,6 +1083,9 @@ _post() { if [ "$_ACME_CURL" ]; then _CURL="$_ACME_CURL" + if [ "$HTTPS_INSECURE" ]; then + _CURL="$_CURL --insecure " + fi _debug "_CURL" "$_CURL" if [ "$needbase64" ]; then response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" @@ -1104,18 +1101,22 @@ _post() { fi fi elif [ "$_ACME_WGET" ]; then - _debug "_ACME_WGET" "$_ACME_WGET" + _WGET="$_ACME_WGET" + if [ "$HTTPS_INSECURE" ]; then + _WGET="$_WGET --no-check-certificate " + fi + _debug "_WGET" "$_WGET" if [ "$needbase64" ]; then if [ "$httpmethod" = "POST" ]; then - response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" else - response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" fi else if [ "$httpmethod" = "POST" ]; then - response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" else - response="$($_ACME_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" fi fi _ret="$?" @@ -1149,6 +1150,9 @@ _get() { if [ "$_ACME_CURL" ]; then _CURL="$_ACME_CURL" + if [ "$HTTPS_INSECURE" ]; then + _CURL="$_CURL --insecure " + fi if [ "$t" ]; then _CURL="$_CURL --connect-timeout $t" fi @@ -1168,6 +1172,9 @@ _get() { fi elif [ "$_ACME_WGET" ]; then _WGET="$_ACME_WGET" + if [ "$HTTPS_INSECURE" ]; then + _WGET="$_WGET --no-check-certificate " + fi if [ "$t" ]; then _WGET="$_WGET --timeout=$t" fi From a746139c53b26052b6eec79c16fd100204d4e04c Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 21:43:42 +0800 Subject: [PATCH 0515/1348] support OPENSSL_BIN and "--openssl-bin" --- acme.sh | 85 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/acme.sh b/acme.sh index 6b63c9ed..674a428e 100755 --- a/acme.sh +++ b/acme.sh @@ -22,6 +22,8 @@ DEFAULT_ACCOUNT_EMAIL="" DEFAULT_ACCOUNT_KEY_LENGTH=2048 DEFAULT_DOMAIN_KEY_LENGTH=2048 +DEFAULT_OPENSSL_BIN="openssl" + STAGE_CA="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" @@ -95,11 +97,11 @@ _printargs() { _dlg_versions() { echo "Diagnosis versions: " - echo "openssl:" - if _exists openssl; then - openssl version 2>&1 + echo "openssl:$OPENSSL_BIN" + if _exists "$OPENSSL_BIN"; then + $OPENSSL_BIN version 2>&1 else - echo "openssl doesn't exists." + echo "$OPENSSL_BIN doesn't exists." fi echo "apache:" @@ -399,18 +401,18 @@ _getfile() { #Usage: multiline _base64() { if [ "$1" ]; then - openssl base64 -e + $OPENSSL_BIN base64 -e else - openssl base64 -e | tr -d '\r\n' + $OPENSSL_BIN base64 -e | tr -d '\r\n' fi } #Usage: multiline _dbase64() { if [ "$1" ]; then - openssl base64 -d -A + $OPENSSL_BIN base64 -d -A else - openssl base64 -d + $OPENSSL_BIN base64 -d fi } @@ -427,9 +429,9 @@ _digest() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$outputhex" ]; then - openssl dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' + $OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' else - openssl dgst -"$alg" -binary | _base64 + $OPENSSL_BIN dgst -"$alg" -binary | _base64 fi else _err "$alg is not supported yet" @@ -452,9 +454,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" | cut -d = -f 2 | tr -d ' ' + $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" | cut -d = -f 2 | tr -d ' ' else - openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary + $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary fi else _err "$alg is not supported yet" @@ -473,7 +475,7 @@ _sign() { return 1 fi - _sign_openssl="openssl dgst -sign $keyfile " + _sign_openssl="$OPENSSL_BIN dgst -sign $keyfile " if [ "$alg" = "sha256" ]; then _sign_openssl="$_sign_openssl -$alg" else @@ -484,7 +486,7 @@ _sign() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then $_sign_openssl | _base64 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - if ! _signedECText="$($_sign_openssl | openssl asn1parse -inform DER)"; then + if ! _signedECText="$($_sign_openssl | $OPENSSL_BIN asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" _err "Key content:$(wc -l <"$keyfile") lises" @@ -546,10 +548,10 @@ _createkey() { if _isEccKey "$length"; then _debug "Using ec name: $eccname" - openssl ecparam -name "$eccname" -genkey 2>/dev/null >"$f" + $OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" else _debug "Using RSA: $length" - openssl genrsa "$length" 2>/dev/null >"$f" + $OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" fi if [ "$?" != "0" ]; then @@ -634,7 +636,7 @@ _createcsr() { _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" - openssl req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" } #_signcsr key csr conf cert @@ -645,7 +647,7 @@ _signcsr() { cert="$4" _debug "_signcsr" - _msg="$(openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" + _msg="$($OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" _ret="$?" _debug "$_msg" return $_ret @@ -658,7 +660,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - openssl req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + $OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile @@ -673,7 +675,7 @@ _readSubjectAltNamesFromCSR() { _csrsubj="$(_readSubjectFromCSR "$_csrfile")" _debug _csrsubj "$_csrsubj" - _dnsAltnames="$(openssl req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" + _dnsAltnames="$($OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" _debug _dnsAltnames "$_dnsAltnames" if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then @@ -694,7 +696,7 @@ _readKeyLengthFromCSR() { return 1 fi - _outcsr="$(openssl req -noout -text -in "$_csrfile")" + _outcsr="$($OPENSSL_BIN req -noout -text -in "$_csrfile")" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' @@ -748,9 +750,9 @@ toPkcs() { _initpath "$domain" "$_isEcc" if [ "$pfxPassword" ]; then - openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" + $OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" else - openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" + $OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" fi if [ "$?" = "0" ]; then @@ -912,7 +914,7 @@ _calcjwk() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "RSA key" - pub_exp=$(openssl rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) + pub_exp=$($OPENSSL_BIN 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 pub_exp=0$pub_exp fi @@ -921,7 +923,7 @@ _calcjwk() { e=$(echo "$pub_exp" | _h2b | _base64) _debug3 e "$e" - modulus=$(openssl rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) + modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' @@ -932,12 +934,12 @@ _calcjwk() { JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" - crv="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" - crv_oid="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv_oid="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv_oid "$crv_oid" case "${crv_oid}" in "prime256v1") @@ -957,15 +959,15 @@ _calcjwk() { _debug3 crv "$crv" fi - pubi="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + pubi="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math "$pubi" + 1) _debug3 pubi "$pubi" - pubj="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + pubj="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math "$pubj" - 1) _debug3 pubj "$pubj" - pubtext="$(openssl ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + pubtext="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" @@ -1549,7 +1551,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="openssl s_server -cert $TLS_CERT -key $TLS_KEY " + __S_OPENSSL="$OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY " if [ "$opaddr" ]; then __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" else @@ -1564,7 +1566,6 @@ _starttlsserver() { __S_OPENSSL="$__S_OPENSSL -6" fi - #start openssl _debug "$__S_OPENSSL" if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) & @@ -1718,6 +1719,10 @@ _initpath() { CERT_HOME="$_DEFAULT_CERT_HOME" fi + if [ -z "$OPENSSL_BIN" ]; then + OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" + fi + if [ -z "$1" ]; then return 0 fi @@ -3576,6 +3581,7 @@ _initconf() { #FORCE=1 # Force to issue cert #DEBUG=1 # Debug mode +#OPENSSL_BIN=openssl #USER_AGENT=\"$USER_AGENT\" @@ -3651,7 +3657,7 @@ _precheck() { fi fi - if ! _exists "openssl"; then + if ! _exists "$OPENSSL_BIN"; then _err "Please install openssl first." _err "We need openssl to generate keys." return 1 @@ -3979,6 +3985,7 @@ Parameters: --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. --listen-v4 Force standalone/tls server to listen at ipv4. --listen-v6 Force standalone/tls server to listen at ipv6. + --openssl-bin Specifies a custom openssl bin location. " } @@ -4042,6 +4049,12 @@ _processAccountConf() { _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL" fi + if [ "$_openssl_bin" ]; then + _saveaccountconf "OPENSSL_BIN" "$_openssl_bin" + elif [ "$OPENSSL_BIN" ] && [ "$OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then + _saveaccountconf "OPENSSL_BIN" "$OPENSSL_BIN" + fi + if [ "$_auto_upgrade" ]; then _saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade" elif [ "$AUTO_UPGRADE" ]; then @@ -4089,6 +4102,7 @@ _process() { _auto_upgrade="" _listen_v4="" _listen_v6="" + _openssl_bin="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -4420,7 +4434,10 @@ _process() { _listen_v6="1" Le_Listen_V6="$_listen_v6" ;; - + --openssl-bin) + _openssl_bin="$2" + OPENSSL_BIN="$_openssl_bin" + ;; *) _err "Unknown parameter : $1" return 1 From 4441a6ff5953a2f2299331f060fa328787d92efd Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 21:59:40 +0800 Subject: [PATCH 0516/1348] support osx CI --- .travis.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8829e472..77017f3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,30 @@ language: shell sudo: required +os: + - linux + - osx + env: global: - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 addons: apt: - sources: - - debian-sid # Grab shellcheck from the Debian repo (o_O) packages: - shellcheck +before_install: + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then brew update ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install shellcheck; fi + script: - - curl -sSL $SHFMT_URL -o ~/shfmt - - chmod +x ~/shfmt - - ~/shfmt -l -w -i 2 . - - git diff --exit-code && echo "shfmt OK" - - shellcheck -V - - shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; chmod +x ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; ~/shfmt -l -w -i 2 . ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; git diff --exit-code && echo "shfmt OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; shellcheck -V ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - sudo ./letest.sh From 791c62ca645ef65c0fc00735dd425aa5ba0ef416 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 22:02:10 +0800 Subject: [PATCH 0517/1348] fix ci --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 77017f3e..2a319042 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ env: addons: apt: + sources: + - debian-sid # Grab shellcheck from the Debian repo (o_O) packages: - shellcheck From 1fadae82c79a1c7f52f1a1b03075459441f9fb96 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 22:03:59 +0800 Subject: [PATCH 0518/1348] fix ci --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2a319042..5c388ba9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,12 +21,12 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install shellcheck; fi script: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; chmod +x ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; ~/shfmt -l -w -i 2 . ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; git diff --exit-code && echo "shfmt OK" ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then then curl -sSL $SHFMT_URL -o ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - sudo ./letest.sh From bc18168662a34397a5ee45bbd57d70beb1c36434 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 22:06:19 +0800 Subject: [PATCH 0519/1348] fix ci --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c388ba9..90373171 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,9 @@ addons: packages: - shellcheck -before_install: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then brew update ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install shellcheck; fi +#before_install: +# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi +# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install shellcheck; fi script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then then curl -sSL $SHFMT_URL -o ~/shfmt ; fi From 41d804719f905bb7eaf7ee1cc6b748f9f92f126d Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 22:10:29 +0800 Subject: [PATCH 0520/1348] fix ci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 90373171..ed54fd6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ addons: # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install shellcheck; fi script: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then then curl -sSL $SHFMT_URL -o ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi From 28688488ff6c5841384bbe109b53c8fc4c734c20 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 22:21:51 +0800 Subject: [PATCH 0521/1348] fix ci --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index ed54fd6e..53f21b37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,8 @@ addons: # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install shellcheck; fi script: + - echo "TEST_LOCAL=$TEST_LOCAL" + - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi From 9eeae9ad7ea80dcb0e1f0d28e21b37c30891d0c9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 22:28:29 +0800 Subject: [PATCH 0522/1348] fix ch --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 53f21b37..8e00e251 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - sudo ./letest.sh + - sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh matrix: From fa6234e417297108008c6af06f89ba88d4b3be23 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 22:37:48 +0800 Subject: [PATCH 0523/1348] add NGROK_TOKEN_OSX --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8e00e251..e2b0a9d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,8 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" ./letest.sh ; fi matrix: From cfbb3e86b39db37fafec005fbbb6acb53949edc9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 22:52:08 +0800 Subject: [PATCH 0524/1348] fix ci --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e2b0a9d2..84184d1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,13 +16,14 @@ addons: packages: - shellcheck -#before_install: -# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi -# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install shellcheck; fi +before_install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl ; fi script: - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" + - openssl version - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi From d78c1f695e6f08a705b00f6e3349dc748f8d3a6c Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Nov 2016 23:10:41 +0800 Subject: [PATCH 0525/1348] fix ci --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 84184d1d..1482d2cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ addons: before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH=/usr/local/bin:$PATH ; fi script: - echo "TEST_LOCAL=$TEST_LOCAL" From e55b2f4f8de195bb86314f6b3f21b92ee11f3fa6 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Nov 2016 13:18:29 +0800 Subject: [PATCH 0526/1348] fix ci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1482d2cc..1d97bdb4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH=/usr/local/bin:$PATH ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew link openssl --force ; fi script: - echo "TEST_LOCAL=$TEST_LOCAL" From 11e0ccdc91bc4077f46f057ef4eaf48c4ebfe672 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Nov 2016 13:35:30 +0800 Subject: [PATCH 0527/1348] fix ci --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1d97bdb4..122474df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew link openssl --force ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export openssl="/usr/local/bin/openssl" ; fi script: - echo "TEST_LOCAL=$TEST_LOCAL" From 7fe19a030a84780e301f3b71d9f50c34928a2e57 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Nov 2016 13:39:27 +0800 Subject: [PATCH 0528/1348] fix osx ci --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 122474df..7294a28f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew link openssl --force ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export openssl="/usr/local/bin/openssl" ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export OPENSSL_BIN="/usr/local/bin/openssl" ; fi script: - echo "TEST_LOCAL=$TEST_LOCAL" @@ -35,7 +35,7 @@ script: - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" OPENSSL_BIN="/usr/local/bin/openssl" ./letest.sh ; fi matrix: From 340155e6a6bd7dc1d97d586f56f2a8dd101edfe6 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Nov 2016 13:51:01 +0800 Subject: [PATCH 0529/1348] fix ci --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7294a28f..f4b52227 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,15 +17,14 @@ addons: - shellcheck before_install: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew link openssl --force ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export OPENSSL_BIN="/usr/local/bin/openssl" ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew update && brew install openssl && brew link openssl --force + fi script: - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - - openssl version + - which openssl && openssl version - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi @@ -35,7 +34,7 @@ script: - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" OPENSSL_BIN="/usr/local/bin/openssl" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" ./letest.sh ; fi matrix: From 8dee328eae514bb55a1a373f17fd9f0bd11e982f Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Nov 2016 13:53:44 +0800 Subject: [PATCH 0530/1348] fix ci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f4b52227..1d61cc1f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew update && brew install openssl && brew link openssl --force + brew update && brew install openssl && brew link openssl --force; fi script: From fa6e1746514bd23e57bfe5287cb363edad3abbfc Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Nov 2016 13:59:15 +0800 Subject: [PATCH 0531/1348] fix ci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1d61cc1f..7afbc90d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ addons: packages: - shellcheck -before_install: +install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install openssl && brew link openssl --force; fi From 8a09dc1b9be9b252660a7b7f3781e0ce4b17fe37 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Nov 2016 18:50:34 +0800 Subject: [PATCH 0532/1348] fix ci --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 7afbc90d..e3063963 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,10 @@ addons: install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install openssl && brew link openssl --force; + #we must reload PATH to make the new openssl live + _old_path="$PATH"; + export PATH=; + export PATH="$_old_path"; fi script: From 7cbe31baad614d5098e58e5f036955a60bd0d527 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 23 Nov 2016 18:51:49 +0800 Subject: [PATCH 0533/1348] fix ci --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e3063963..811e59c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,6 @@ addons: install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install openssl && brew link openssl --force; - #we must reload PATH to make the new openssl live _old_path="$PATH"; export PATH=; export PATH="$_old_path"; From 10a6aec9982cc9326012f3de415410c51f1be93a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 23 Nov 2016 19:48:14 +0800 Subject: [PATCH 0534/1348] fix ci --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 811e59c5..38fb496a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,8 @@ install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install openssl && brew link openssl --force; _old_path="$PATH"; - export PATH=; + export PATH=""; + openssl version 2>&1 || true export PATH="$_old_path"; fi From 2ffab66d97ff6e5a0f7c23e1c6565d7acc923b07 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 23 Nov 2016 20:01:40 +0800 Subject: [PATCH 0535/1348] fix ci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 38fb496a..5cadb562 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ install: brew update && brew install openssl && brew link openssl --force; _old_path="$PATH"; export PATH=""; - openssl version 2>&1 || true + openssl version 2>&1 || true; export PATH="$_old_path"; fi From a205762bf092e107f5f00f2831be4a17dcef5006 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 23 Nov 2016 20:21:43 +0800 Subject: [PATCH 0536/1348] fix ci --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5cadb562..27847a19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,11 @@ addons: install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew update && brew install openssl && brew link openssl --force; + brew update && brew install openssl; + brew info openssl; + ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; + ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; + ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl openssl; _old_path="$PATH"; export PATH=""; openssl version 2>&1 || true; From 670cb9d223ace2baa0e73391873fc1fd1f24d52e Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 23 Nov 2016 20:35:47 +0800 Subject: [PATCH 0537/1348] fix ci --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 27847a19..40a2019f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,8 +22,9 @@ install: brew info openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl openssl; + ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; _old_path="$PATH"; + echo "PATH=$PATH" export PATH=""; openssl version 2>&1 || true; export PATH="$_old_path"; From d2aa3318388f7ed7900ea08845dbbc2c9beed395 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 23 Nov 2016 20:46:11 +0800 Subject: [PATCH 0538/1348] fix ci --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 40a2019f..8659ecd1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ install: _old_path="$PATH"; echo "PATH=$PATH" export PATH=""; - openssl version 2>&1 || true; + /usr/local/openssl version 2>&1 || true; export PATH="$_old_path"; fi @@ -43,7 +43,7 @@ script: - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" OPENSSL_BIN="/usr/local/Cellar/openssl/1.0.2j/bin/openssl" ./letest.sh ; fi matrix: From 41266f05e93ff945526ef336a67c921c2d2b3dfe Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 23 Nov 2016 21:01:47 +0800 Subject: [PATCH 0539/1348] fix CI --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8659ecd1..645032a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,8 @@ install: _old_path="$PATH"; echo "PATH=$PATH" export PATH=""; - /usr/local/openssl version 2>&1 || true; + export OPENSSL_BIN="/usr/local/openssl" + $OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; fi @@ -43,7 +44,7 @@ script: - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" OPENSSL_BIN="/usr/local/Cellar/openssl/1.0.2j/bin/openssl" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi matrix: From df86ff2191d01f34d32f5b3f593033836186b021 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 23 Nov 2016 21:17:51 +0800 Subject: [PATCH 0540/1348] fix ci --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 645032a3..7e901528 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,9 +24,10 @@ install: ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; _old_path="$PATH"; - echo "PATH=$PATH" + echo "PATH=$PATH"; export PATH=""; - export OPENSSL_BIN="/usr/local/openssl" + export OPENSSL_BIN="/usr/local/openssl"; + openssl version 2>&1 || true; $OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; fi From 74a7592b4b40468203451c0941086051b2113105 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 23 Nov 2016 22:07:24 +0800 Subject: [PATCH 0541/1348] fix ci, remove NGROK_TOKEN_OSX --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7e901528..d70b7e49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,7 +45,7 @@ script: - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN_OSX" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi matrix: From 79db8dadddee3f5ebbe5f8c989ec78ee10fd249d Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 24 Nov 2016 13:39:46 +0800 Subject: [PATCH 0542/1348] fix CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d70b7e49..efa4790f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ install: fi script: + - echo "TRAVIS_PULL_REQUEST_BRANCH=$TRAVIS_PULL_REQUEST_BRANCH" - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - which openssl && openssl version From 72349507c4a57106d6d2864436787e5f31c37056 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 24 Nov 2016 13:45:00 +0800 Subject: [PATCH 0543/1348] fix ci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index efa4790f..b7d92dac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ install: fi script: - - echo "TRAVIS_PULL_REQUEST_BRANCH=$TRAVIS_PULL_REQUEST_BRANCH" + - env - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - which openssl && openssl version From 9e04222ee63016ab6675cf78dd4614cc31a8c45c Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 24 Nov 2016 13:58:14 +0800 Subject: [PATCH 0544/1348] fix ci --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b7d92dac..94848c17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,6 @@ install: fi script: - - env - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - which openssl && openssl version @@ -45,8 +44,8 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi matrix: From 8b1fb3cb0cd9d9beab1496c815a6b07ace5bb234 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 24 Nov 2016 14:13:23 +0800 Subject: [PATCH 0545/1348] Dev (#419) * fix CI * fix ci * fix ci --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d70b7e49..94848c17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,8 +44,8 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi matrix: From be39ab32d1d1d4654a8bf053d0636b9737a271c1 Mon Sep 17 00:00:00 2001 From: baiyangliu Date: Thu, 24 Nov 2016 21:49:45 +0800 Subject: [PATCH 0546/1348] Add DNS API support for aliyun (#410) * Add DNS API support for aliyun * Update README.md * format * format * format * format... * format... * format * format * fix bug * fix bug * code format * code format * fix bug * just ok... * fix bug * fix bug * fix bug * change "echo" to "printf" * fix bug * code format * fix bug."head -c" in function _ali_nonce not supported by solaris * fix bug."head -c" in function _ali_nonce not supported by solaris * format * fix bug._ali_nonce not work on solaris * fix bug. _ali_nonce not work on solaris * fix bug. _ali_nonce not work on solaris * add aliyun.com to README.md --- README.md | 1 + dnsapi/README.md | 21 +++++- dnsapi/dns_ali.sh | 186 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 dnsapi/dns_ali.sh diff --git a/README.md b/README.md index 69348bf9..724f6eed 100644 --- a/README.md +++ b/README.md @@ -260,6 +260,7 @@ You don't have to do anything manually! 1. LuaDNS.com API 1. DNSMadeEasy.com API 1. nsupdate API +1. aliyun.com(阿里云) API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 9a8730c9..ca9b08d9 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -201,7 +201,24 @@ acme.sh --issue --dns dns_aws -d example.com -d www.example.com The `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -# 11. Use custom API +## 11. Use Aliyun domain API to automatically issue cert + +First you need to login to your Aliyun account to get your API key. +[https://ak-console.aliyun.com/#/accesskey](https://ak-console.aliyun.com/#/accesskey) + +``` +export Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +export Ali_Secret="jlsdflanljkljlfdsaklkjflsa" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_ali -d example.com -d www.example.com +``` + +The `Ali_Key` and `Ali_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +# 12. Use custom API If your API is not supported yet, you can write your own DNS API. @@ -218,6 +235,6 @@ acme.sh --issue --dns dns_myapi -d example.com -d www.example.com For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) -## 12. Use lexicon DNS API +## 13. Use lexicon DNS API https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh new file mode 100644 index 00000000..97b450a1 --- /dev/null +++ b/dnsapi/dns_ali.sh @@ -0,0 +1,186 @@ +#!/usr/bin/env sh + +Ali_API="https://alidns.aliyuncs.com/" + +#Ali_Key="LTqIA87hOKdjevsf5" +#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2" + +#Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ali_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then + Ali_Key="" + Ali_Secret="" + _err "You don't specify aliyun api key and secret yet." + return 1 + fi + + #save the api key and secret to the account conf file. + _saveaccountconf Ali_Key "$Ali_Key" + _saveaccountconf Ali_Secret "$Ali_Secret" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + return 1 + fi + + _add_record_query "$_domain" "$_sub_domain" "$txtvalue" && _ali_rest "Add record" +} + +dns_ali_rm() { + fulldomain=$1 + _clean +} + +#################### Private functions bellow ################################## + +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _describe_records_query "$h" + if ! _ali_rest "Get root" "ignore"; then + return 1 + fi + + if _contains "$response" "PageNumber"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _sub_domain "$_sub_domain" + _domain="$h" + _debug _domain "$_domain" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_ali_rest() { + signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(_hex "$Ali_Secret&")" | _base64) + signature=$(_ali_urlencode "$signature") + url="$Ali_API?$query&Signature=$signature" + + if ! response="$(_get "$url")"; then + _err "Error <$1>" + return 1 + fi + + if [ -z "$2" ]; then + message="$(printf "%s" "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + if [ -n "$message" ]; then + _err "$message" + return 1 + fi + fi + + _debug2 response "$response" + return 0 +} + +_ali_urlencode() { + _str="$1" + _str_len=${#_str} + _u_i=1 + while [ "$_u_i" -le "$_str_len" ]; do + _str_c="$(printf "%s" "$_str" | cut -c "$_u_i")" + case $_str_c in [a-zA-Z0-9.~_-]) + printf "%s" "$_str_c" + ;; + *) + printf "%%%02X" "'$_str_c" + ;; + esac + _u_i="$(_math "$_u_i" + 1)" + done +} + +_ali_nonce() { + #_head_n 1 Date: Thu, 24 Nov 2016 22:27:14 +0800 Subject: [PATCH 0547/1348] fix for aliyun api --- acme.sh | 2 +- dnsapi/dns_ali.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 674a428e..f695ded9 100755 --- a/acme.sh +++ b/acme.sh @@ -90,7 +90,7 @@ _printargs() { if [ -z "$2" ]; then printf -- "[$(date)] $1" else - printf -- "[$(date)] $1='$2'" + printf -- "%s" "[$(date)] $1='$2'" fi printf "\n" } diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 97b450a1..30867219 100644 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -26,6 +26,7 @@ dns_ali_add() { return 1 fi + _debug "Add record" _add_record_query "$_domain" "$_sub_domain" "$txtvalue" && _ali_rest "Add record" } From 93f3098aec5c47070236104d52d3a1f38f6b7a80 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 24 Nov 2016 22:36:21 +0800 Subject: [PATCH 0548/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index f695ded9..bcaa3014 100755 --- a/acme.sh +++ b/acme.sh @@ -2797,7 +2797,7 @@ issue() { status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') if [ "$status" = "valid" ]; then - _info "Success" + _info "$(__green Success)" _stopserver "$serverproc" serverproc="" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" From 192ede5e64a5b63752dcf7b4c750c616f920db37 Mon Sep 17 00:00:00 2001 From: sjau Date: Thu, 24 Nov 2016 16:00:32 +0100 Subject: [PATCH 0549/1348] Added ISPConfig DNS API --- README.md | 1 + dnsapi/README.md | 26 ++++++- dnsapi/dns_ispconfig.sh | 158 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 2 deletions(-) create mode 100755 dnsapi/dns_ispconfig.sh diff --git a/README.md b/README.md index 724f6eed..859e8fe3 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,7 @@ You don't have to do anything manually! 1. DNSMadeEasy.com API 1. nsupdate API 1. aliyun.com(阿里云) API +1. ISPConfig 3.1 API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index ca9b08d9..dbd27fce 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -218,7 +218,29 @@ acme.sh --issue --dns dns_ali -d example.com -d www.example.com The `Ali_Key` and `Ali_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -# 12. Use custom API +## 12. Use ISPConfig 3.1 API + +This only works for ISPConfig 3.1 (and newer). + +Create a Remote User in the ISPConfig Control Panel. The Remote User must have access to at least `DNS zone functions` and `DNS txt functions`. + +``` +export ISPC_User="xxx" +export ISPC_Password="xxx" +export ISPC_Api="https://ispc.domain.tld:8080/remote/json.php" +export ISPC_Api_Insecure=1 +``` +If you have installed ISPConfig on a different port, then alter the 8080 accordingly. +Leaver ISPC_Api_Insecure set to 1 if you have not a valid ssl cert for your installation. Change it to 0 if you have a valid ssl cert. + +To issue a cert: +``` +acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com +``` + +The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +# 13. Use custom API If your API is not supported yet, you can write your own DNS API. @@ -235,6 +257,6 @@ acme.sh --issue --dns dns_myapi -d example.com -d www.example.com For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) -## 13. Use lexicon DNS API +## 14. Use lexicon DNS API https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh new file mode 100755 index 00000000..eb55d356 --- /dev/null +++ b/dnsapi/dns_ispconfig.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env sh + +# ISPConfig 3.1 API +# User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to: +# - DNS zone Functions +# - DNS txt Functions + +# Report bugs to https://github.com/sjau/acme.sh + +# Values to export: +# export ISPC_User="remoteUser" +# export ISPC_Password="remotePasword" +# export ISPC_Api="https://ispc.domain.tld:8080/remote/json.php" +# export ISPC_Api_Insecure=1 # Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1) + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ispconfig_add() { + fulldomain="${1}" + txtvalue="${2}" + _ISPC_credentials && _ISPC_login && _ISPC_getZoneInfo && _ISPC_addTxt +} + +#Usage: dns_myapi_rm _acme-challenge.www.domain.com +dns_ispconfig_rm() { + fulldomain="${1}" + _ISPC_credentials && _ISPC_login && _ISPC_rmTxt +} + +#################### Private functions bellow ################################## + +_ISPC_credentials() { + if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then + ISPC_User="" + ISPC_Password="" + ISPC_Api="" + ISPC_Api_Insecure="" + _err "You haven't specified the ISPConfig Login data, URL and whether you want check the ISPC SSL cert. Please try again." + return 1 + else + _saveaccountconf ISPC_User "${ISPC_User}" + _saveaccountconf ISPC_Password "${ISPC_Password}" + _saveaccountconf ISPC_Api "${ISPC_Api}" + _saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}" + # Set whether curl should use secure or insecure mode + HTTPS_INSECURE="${ISPC_Api_Insecure}" + fi +} + +_ISPC_login() { + _info "Getting Session ID" + curData="{\"username\":\"${ISPC_User}\",\"password\":\"${ISPC_Password}\",\"client_login\":false}" + curResult="$(_post "${curData}" "${ISPC_Api}?login")" + if _contains "${curResult}" '"code":"ok"'; then + sessionID=$(echo "${curResult}" | _egrep_o "response.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _info "Retrieved Session ID." + else + _err "Couldn't retrieve the Session ID." + return 1 + fi +} + +_ISPC_getZoneInfo() { + _info "Getting Zoneinfo" + zoneEnd=false + curZone="${fulldomain}" + while [ "${zoneEnd}" = false ]; do + # we can strip the first part of the fulldomain, since it's just the _acme-challenge string + curZone="${curZone#*.}" + # suffix . needed for zone -> domain.tld. + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":[{\"origin\":\"${curZone}.\"}]}" + curResult="$(_post "${curData}" "${ISPC_Api}?dns_zone_get")" + if _contains "${curResult}" '"id":"'; then + zoneFound=true + zoneEnd=true + _info "Retrieved zone data." + fi + if [ "${curZone#*.}" != "$curZone" ]; then + _debug2 "$curZone still contains a '.' - so we can check next higher level" + else + zoneEnd=true + _err "Couldn't retrieve zone data." + return 1 + fi + done + if [ "${zoneFound}" ]; then + server_id=$(echo "${curResult}" | _egrep_o "server_id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + case "${server_id}" in + '' | *[!0-9]*) + _err "Server ID is not numeric." + return 1 + ;; + *) _info "Retrieved Server ID" ;; + esac + zone=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + case "${zone}" in + '' | *[!0-9]*) + _err "Zone ID is not numeric." + return 1 + ;; + *) _info "Retrieved Zone ID" ;; + esac + client_id=$(echo "${curResult}" | _egrep_o "sys_userid.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + case "${client_id}" in + '' | *[!0-9]*) + _err "Client ID is not numeric." + return 1 + ;; + *) _info "Retrieved Client ID." ;; + esac + zoneFound="" + zoneEnd="" + fi +} + +_ISPC_addTxt() { + curSerial="$(date +%s)" + curStamp="$(date +'%F %T')" + params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\"" + curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}}}" + curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" + record_id=$(echo "${curResult}" | _egrep_o "\"response.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + case "${record_id}" in + '' | *[!0-9]*) + _err "Couldn't add ACME Challenge TXT record to zone." + return 1 + ;; + *) _info "Added ACME Challenge TXT record to zone." ;; + esac +} + +_ISPC_rmTxt() { + # Need to get the record ID. + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"name\":\"${fulldomain}.\",\"type\":\"TXT\"}}" + curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_get")" + if _contains "${curResult}" '"code":"ok"'; then + record_id=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + case "${record_id}" in + '' | *[!0-9]*) + _err "Record ID is not numeric." + return 1 + ;; + *) + unset IFS + _info "Retrieved Record ID." + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\"}" + curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")" + if _contains "${curResult}" '"code":"ok"'; then + _info "Removed ACME Challenge TXT record from zone." + else + _err "Couldn't remove ACME Challenge TXT record from zone." + return 1 + fi + ;; + esac + fi +} From 983f1f28ca273d4b4461cd9fb5a4211335ed9904 Mon Sep 17 00:00:00 2001 From: sjau Date: Thu, 24 Nov 2016 18:02:42 +0100 Subject: [PATCH 0550/1348] Fixed wrong zone getting JSON and added lots of debug info --- dnsapi/dns_ispconfig.sh | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index eb55d356..315dd6ef 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash # ISPConfig 3.1 API # User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to: @@ -9,7 +9,7 @@ # Values to export: # export ISPC_User="remoteUser" -# export ISPC_Password="remotePasword" +# export ISPC_Password="remotePassword" # export ISPC_Api="https://ispc.domain.tld:8080/remote/json.php" # export ISPC_Api_Insecure=1 # Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1) @@ -19,12 +19,14 @@ dns_ispconfig_add() { fulldomain="${1}" txtvalue="${2}" + _debug "Calling: dns_ispconfig_add() '${fulldomain}' '${txtvalue}'" _ISPC_credentials && _ISPC_login && _ISPC_getZoneInfo && _ISPC_addTxt } #Usage: dns_myapi_rm _acme-challenge.www.domain.com dns_ispconfig_rm() { fulldomain="${1}" + _debug "Calling: dns_ispconfig_rm() '${fulldomain}'" _ISPC_credentials && _ISPC_login && _ISPC_rmTxt } @@ -52,9 +54,12 @@ _ISPC_login() { _info "Getting Session ID" curData="{\"username\":\"${ISPC_User}\",\"password\":\"${ISPC_Password}\",\"client_login\":false}" curResult="$(_post "${curData}" "${ISPC_Api}?login")" + _debug "Calling _ISPC_login: '${curData}' '${ISPC_Api}?login'" + _debug "Result of _ISPC_login: '$curResult'" if _contains "${curResult}" '"code":"ok"'; then sessionID=$(echo "${curResult}" | _egrep_o "response.*" | cut -d ':' -f 2 | cut -d '"' -f 2) _info "Retrieved Session ID." + _debug "Session ID: '${sessionID}'" else _err "Couldn't retrieve the Session ID." return 1 @@ -69,12 +74,15 @@ _ISPC_getZoneInfo() { # we can strip the first part of the fulldomain, since it's just the _acme-challenge string curZone="${curZone#*.}" # suffix . needed for zone -> domain.tld. - curData="{\"session_id\":\"${sessionID}\",\"primary_id\":[{\"origin\":\"${curZone}.\"}]}" + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"origin\":\"${curZone}.\"}}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_zone_get")" + _debug "Calling _ISPC_getZoneInfo: '${curData}' '${ISPC_Api}?login'" + _debug "Result of _ISPC_getZoneInfo: '$curResult'" if _contains "${curResult}" '"id":"'; then zoneFound=true zoneEnd=true _info "Retrieved zone data." + _debug "Zone data: '${curResult}'" fi if [ "${curZone#*.}" != "$curZone" ]; then _debug2 "$curZone still contains a '.' - so we can check next higher level" @@ -86,6 +94,7 @@ _ISPC_getZoneInfo() { done if [ "${zoneFound}" ]; then server_id=$(echo "${curResult}" | _egrep_o "server_id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Server ID: '${server_id}'" case "${server_id}" in '' | *[!0-9]*) _err "Server ID is not numeric." @@ -94,6 +103,7 @@ _ISPC_getZoneInfo() { *) _info "Retrieved Server ID" ;; esac zone=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Zone: '${zone}'" case "${zone}" in '' | *[!0-9]*) _err "Zone ID is not numeric." @@ -102,6 +112,7 @@ _ISPC_getZoneInfo() { *) _info "Retrieved Zone ID" ;; esac client_id=$(echo "${curResult}" | _egrep_o "sys_userid.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Client ID: '${client_id}'" case "${client_id}" in '' | *[!0-9]*) _err "Client ID is not numeric." @@ -120,7 +131,10 @@ _ISPC_addTxt() { params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\"" curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}}}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" + _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'" + _debug "Result of _ISPC_addTxt: '$curResult'" record_id=$(echo "${curResult}" | _egrep_o "\"response.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Record ID: '${record_id}'" case "${record_id}" in '' | *[!0-9]*) _err "Couldn't add ACME Challenge TXT record to zone." @@ -134,8 +148,11 @@ _ISPC_rmTxt() { # Need to get the record ID. curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"name\":\"${fulldomain}.\",\"type\":\"TXT\"}}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_get")" + _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_get'" + _debug "Result of _ISPC_rmTxt: '$curResult'" if _contains "${curResult}" '"code":"ok"'; then record_id=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Record ID: '${record_id}'" case "${record_id}" in '' | *[!0-9]*) _err "Record ID is not numeric." @@ -146,6 +163,8 @@ _ISPC_rmTxt() { _info "Retrieved Record ID." curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\"}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")" + _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'" + _debug "Result of _ISPC_rmTxt: '$curResult'" if _contains "${curResult}" '"code":"ok"'; then _info "Removed ACME Challenge TXT record from zone." else From 5eed02f7e927742facd9d938a6e692a771271377 Mon Sep 17 00:00:00 2001 From: sjau Date: Fri, 25 Nov 2016 04:50:05 +0100 Subject: [PATCH 0551/1348] Changing shebang back to sh --- dnsapi/dns_ispconfig.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index 315dd6ef..789b6267 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # ISPConfig 3.1 API # User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to: From 58bb94d7c73028441a3dfde7675a2150ae423685 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 25 Nov 2016 22:20:54 +0800 Subject: [PATCH 0552/1348] Update README.md --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index dbd27fce..c4245701 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -240,7 +240,7 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -# 13. Use custom API +# Use custom API If your API is not supported yet, you can write your own DNS API. @@ -257,6 +257,6 @@ acme.sh --issue --dns dns_myapi -d example.com -d www.example.com For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) -## 14. Use lexicon DNS API +# Use lexicon DNS API https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api From 569d6c557c789a9ac749c9fe1b45ee606528fb23 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 29 Nov 2016 00:11:02 +0800 Subject: [PATCH 0553/1348] fix https://github.com/Neilpang/acme.sh/issues/426 --- acme.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index bcaa3014..d886bfee 100755 --- a/acme.sh +++ b/acme.sh @@ -87,10 +87,13 @@ __red() { } _printargs() { + if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then + printf -- "%s" "[$(date)] " + fi if [ -z "$2" ]; then - printf -- "[$(date)] $1" + printf -- "%s" "$1" else - printf -- "%s" "[$(date)] $1='$2'" + printf -- "%s" "$1='$2'" fi printf "\n" } @@ -131,7 +134,9 @@ _info() { _err() { _log "$@" - printf -- "[$(date)] " >&2 + if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then + printf -- "%s" "[$(date)] " >&2 + fi if [ -z "$2" ]; then __red "$1" >&2 else @@ -3580,7 +3585,7 @@ _initconf() { #STAGE=1 # Use the staging api #FORCE=1 # Force to issue cert #DEBUG=1 # Debug mode - +#NO_TIMESTAMP=1 #OPENSSL_BIN=openssl #USER_AGENT=\"$USER_AGENT\" From b43416af97b3cc48625773a3635d694e2e923198 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 2 Dec 2016 20:24:12 +0800 Subject: [PATCH 0554/1348] do not use script home --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index d886bfee..c7c9f9f0 100755 --- a/acme.sh +++ b/acme.sh @@ -1612,14 +1612,14 @@ __initHome() { fi fi - if [ -z "$LE_WORKING_DIR" ]; then - if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then - _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" - LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" - else - LE_WORKING_DIR="$_SCRIPT_HOME" - fi - fi +# if [ -z "$LE_WORKING_DIR" ]; then +# if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then +# _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" +# LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" +# else +# LE_WORKING_DIR="$_SCRIPT_HOME" +# fi +# fi if [ -z "$LE_WORKING_DIR" ]; then _debug "Using default home:$DEFAULT_INSTALL_HOME" From 219e9115c03723d01dbb2eca6c26797875529842 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 2 Dec 2016 20:30:52 +0800 Subject: [PATCH 0555/1348] fix format --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index c7c9f9f0..a669aba1 100755 --- a/acme.sh +++ b/acme.sh @@ -1612,14 +1612,14 @@ __initHome() { fi fi -# if [ -z "$LE_WORKING_DIR" ]; then -# if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then -# _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" -# LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" -# else -# LE_WORKING_DIR="$_SCRIPT_HOME" -# fi -# fi + # if [ -z "$LE_WORKING_DIR" ]; then + # if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then + # _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" + # LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + # else + # LE_WORKING_DIR="$_SCRIPT_HOME" + # fi + # fi if [ -z "$LE_WORKING_DIR" ]; then _debug "Using default home:$DEFAULT_INSTALL_HOME" From 048e5210f751b88104fb4455644e6d09815b0d18 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 2 Dec 2016 21:12:20 +0800 Subject: [PATCH 0556/1348] do not use script home * do not use script home * fix format --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index d886bfee..a669aba1 100755 --- a/acme.sh +++ b/acme.sh @@ -1612,14 +1612,14 @@ __initHome() { fi fi - if [ -z "$LE_WORKING_DIR" ]; then - if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then - _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" - LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" - else - LE_WORKING_DIR="$_SCRIPT_HOME" - fi - fi + # if [ -z "$LE_WORKING_DIR" ]; then + # if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then + # _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" + # LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + # else + # LE_WORKING_DIR="$_SCRIPT_HOME" + # fi + # fi if [ -z "$LE_WORKING_DIR" ]; then _debug "Using default home:$DEFAULT_INSTALL_HOME" From d69f0289caf15b1b8b8516a92b18ea68087024bc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Dec 2016 12:22:36 +0800 Subject: [PATCH 0557/1348] fix issue when there is no one records in the domain. --- dnsapi/dns_cx.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 0caf0c02..91556c67 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -69,11 +69,11 @@ existing_records() { _debug "Getting txt records" root=$1 sub=$2 - + count=0 if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then return 1 fi - count=0 + seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") _debug seg "$seg" if [ -z "$seg" ]; then From c572ce946bdbd56572d36d73a266a163e4396b54 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 4 Dec 2016 13:46:07 +0800 Subject: [PATCH 0558/1348] Dev (#434) * do not use script home * fix format * fix issue when there is no one records in the domain. --- dnsapi/dns_cx.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 0caf0c02..91556c67 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -69,11 +69,11 @@ existing_records() { _debug "Getting txt records" root=$1 sub=$2 - + count=0 if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then return 1 fi - count=0 + seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") _debug seg "$seg" if [ -z "$seg" ]; then From 5be3f22d06cd62397395b0de4e76f3f1d3c27405 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Dec 2016 14:45:26 +0800 Subject: [PATCH 0559/1348] fix issue --- dnsapi/dns_cx.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 91556c67..ff1c943d 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -74,7 +74,7 @@ existing_records() { return 1 fi - seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") + seg=$(printf "%s\n" "$response" | _egrep_o '{[^{]*host":"'"$_sub_domain"'"[^}]*\}') _debug seg "$seg" if [ -z "$seg" ]; then return 0 @@ -82,7 +82,7 @@ existing_records() { if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then count=1 - record_id=$(printf "%s\n" "$seg" | _egrep_o "\"record_id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1) _debug record_id "$record_id" return 0 fi @@ -170,7 +170,7 @@ _get_root() { _rest() { m=$1 ep="$2" - _debug "$ep" + _debug ep "$ep" url="$REST_API/$ep" _debug url "$url" From e4468562d273863489558d4c89549b87e43c23eb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Dec 2016 21:24:38 +0800 Subject: [PATCH 0560/1348] fix cx --- dnsapi/dns_cx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 0c3d5c80..4117d29d 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -147,7 +147,7 @@ _get_root() { fi if _contains "$response" "$h."; then - seg=$(printf "%s" "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') + seg=$(echo "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') _debug seg "$seg" _domain_id=$(printf "%s" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" From a62706678e65f28deebe2ac58a7b19483089aaed Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Dec 2016 21:33:36 +0800 Subject: [PATCH 0561/1348] fix for solaris --- dnsapi/dns_cx.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 4117d29d..602a5012 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -147,9 +147,9 @@ _get_root() { fi if _contains "$response" "$h."; then - seg=$(echo "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') + seg=$(printf "%s\n" "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') _debug seg "$seg" - _domain_id=$(printf "%s" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) From 8379f015d7e2280b4861478a086672d89dcabb37 Mon Sep 17 00:00:00 2001 From: kookxiang Date: Sat, 3 Dec 2016 23:32:50 +0800 Subject: [PATCH 0562/1348] Finish dns_cx_rm() method --- dnsapi/dns_cx.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 602a5012..86a7b2d0 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -58,7 +58,15 @@ dns_cx_add() { #fulldomain dns_cx_rm() { fulldomain=$1 - + REST_API="$CX_Api" + if _get_root "$fulldomain"; then + record_id="" + existing_records "$_domain" "$_sub_domain" + if ! [ "$record_id" = "" ]; then + _rest DELETE "record/$record_id/$_domain_id" "{}" + _info "Deleted record ${fulldomain}" + fi + fi } #usage: root sub From c12be766e92ec7cd97048f6ffbb8559c6e730ac7 Mon Sep 17 00:00:00 2001 From: Marcello Barnaba Date: Sun, 4 Dec 2016 20:10:33 +0100 Subject: [PATCH 0563/1348] Fix Route53 API consumer Ignoring the Chthlulu argument :smiley:, Route53 returns its XML all on one line, making not possible to grep the hosted zone record with egrep/sed. This change splits the XML in multiple lines, so that parsing can succeed. --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 15bf7b14..2c58754d 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -72,7 +72,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | _egrep_o ".*$h..*")" + hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*$h..*")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." From eea52a5fa632eb87943cf1d84f880cf0043291a8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 13:55:06 +0800 Subject: [PATCH 0564/1348] update api template --- dnsapi/dns_myapi.sh | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index 813a2ed1..f3e275d9 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -5,48 +5,28 @@ #So, here must be a method dns_myapi_add() #Which will be called by acme.sh to add the txt record to your api system. #returns 0 means success, otherwise error. - +# +#Author: Neilpang +#Report Bugs here: https://github.com/Neilpang/acme.sh +# ######## Public functions ##################### #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_myapi_add() { fulldomain=$1 txtvalue=$2 + _info "Using myapi" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" _err "Not implemented!" return 1 } -#fulldomain +#Usage: fulldomain +#Remove the txt record afer validation. dns_myapi_rm() { fulldomain=$1 } #################### Private functions bellow ################################## -_info() { - if [ -z "$2" ]; then - echo "[$(date)] $1" - else - echo "[$(date)] $1='$2'" - fi -} - -_err() { - _info "$@" >&2 - return 1 -} - -_debug() { - if [ -z "$DEBUG" ]; then - return - fi - _err "$@" - return 0 -} - -_debug2() { - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _debug "$@" - fi - return -} From e2d494321cc7ca58d423f1862c078f2549117fbb Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 14:02:31 +0800 Subject: [PATCH 0565/1348] update template --- .github/PULL_REQUEST_TEMPLATE.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2df6e9c4..29ea4e42 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,14 +1,9 @@ \ No newline at end of file From 21f201e37148c7ef2385621ca7b994388e9ab8d3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 14:58:36 +0800 Subject: [PATCH 0566/1348] support cloudflare rm function --- acme.sh | 5 +++-- dnsapi/dns_cf.sh | 43 ++++++++++++++++++++++++++++++++++++++----- dnsapi/dns_myapi.sh | 7 +++++-- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index a669aba1..9e3ae4b5 100755 --- a/acme.sh +++ b/acme.sh @@ -1991,7 +1991,8 @@ _clearupdns() { keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) vtype=$(echo "$ventry" | cut -d "$sep" -f 4) _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - + txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)" + _debug txt "$txt" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." continue @@ -2024,7 +2025,7 @@ _clearupdns() { txtdomain="_acme-challenge.$d" - if ! $rmcommand "$txtdomain"; then + if ! $rmcommand "$txtdomain" "$txt"; then _err "Error removing txt for domain:$txtdomain" return 1 fi diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index dd8c9143..6c191ead 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -55,9 +55,7 @@ dns_cf_add() { _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 - _info "Added, sleeping 10 seconds" - sleep 10 - #todo: check if the record takes effect + _info "Added, OK" return 0 else _err "Add txt record error." @@ -83,9 +81,44 @@ dns_cf_add() { } -#fulldomain +#fulldomain txtvalue dns_cf_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" + _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue" + + if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _cf_rest DELETE "zones/$_domain_id/dns_records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '"success":true' + fi } @@ -135,7 +168,7 @@ _cf_rest() { _H2="X-Auth-Key: $CF_Key" _H3="Content-Type: application/json" - if [ "$data" ]; then + if [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$CF_Api/$ep" "" "$m")" else diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index f3e275d9..e5a98dd9 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -22,11 +22,14 @@ dns_myapi_add() { return 1 } -#Usage: fulldomain +#Usage: fulldomain txtvalue #Remove the txt record afer validation. dns_myapi_rm() { fulldomain=$1 - + txtvalue=$2 + _info "Using myapi" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" } #################### Private functions bellow ################################## From c0d0100ca8dd6c20abb29dded178fa41e8f449b9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 15:18:02 +0800 Subject: [PATCH 0567/1348] fix format --- dnsapi/dns_cf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 6c191ead..b8ff06c1 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -101,7 +101,7 @@ dns_cf_rm() { _err "Error" return 1 fi - + count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) _debug count "$count" if [ "$count" = "0" ]; then From f162ad193fb29a304b2ef2e74141404fb2b6d7e2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 15:46:22 +0800 Subject: [PATCH 0568/1348] support dnspod remove --- dnsapi/dns_dp.sh | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index aa06d5fc..c6dd1ba3 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -6,9 +6,8 @@ # #DP_Key="sADDsdasdgdsf" -DP_Api="https://dnsapi.cn" +REST_API="https://dnsapi.cn" -#REST_API ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -24,8 +23,6 @@ dns_dp_add() { return 1 fi - REST_API="$DP_Api" - #save the api key and email to the account conf file. _saveaccountconf DP_Id "$DP_Id" _saveaccountconf DP_Key "$DP_Key" @@ -50,9 +47,39 @@ dns_dp_add() { fi } -#fulldomain +#fulldomain txtvalue dns_dp_rm() { fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then + _err "Record.Lis error." + return 1 + fi + + if _contains "$response" 'No records'; then + _info "Don't need to remove." + return 0 + fi + + record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'$txtvalue'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id." + return 1 + fi + + if ! _rest POST "Record.Remove" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then + _err "Record.Remove error." + return 1 + fi + + _contains "$response" "Action completed successful" } From f1f30743068610c1967fcf36b765e7a57f457844 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 15:54:19 +0800 Subject: [PATCH 0569/1348] fix format --- dnsapi/dns_dp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index c6dd1ba3..155979af 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -67,7 +67,7 @@ dns_dp_rm() { return 0 fi - record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'$txtvalue'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") + record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") _debug record_id "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id." From dfbc244b00cadf6b937171bce45a95641fb548df Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 16:52:02 +0800 Subject: [PATCH 0570/1348] support aws remove --- dnsapi/dns_aws.sh | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 2c58754d..ca79326b 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -49,9 +49,28 @@ dns_aws_add() { return 1 } -#fulldomain +#fulldomain txtvalue dns_aws_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" + + _aws_tmpl_xml="DELETE\"$txtvalue\"$fulldomain.TXT300" + + if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then + _info "txt record deleted sucess." + return 0 + fi + + return 1 } From b9ece28f68bdf94018e9b40e921666dce653c565 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 19:02:46 +0800 Subject: [PATCH 0571/1348] add osx CI --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 859e8fe3..40dca816 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) |18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris |19|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux +|20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|OSX For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From b28a3db3d6931c690bfb9d4f57a550a3dd98ec50 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 19:03:59 +0800 Subject: [PATCH 0572/1348] Mac OSX --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40dca816..1e563795 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) |18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris |19|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux -|20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|OSX +|20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From 5efbaa48495d7380e170f575b805edfc8ad899b6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 20:50:33 +0800 Subject: [PATCH 0573/1348] minor, clear default confs --- acme.sh | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) diff --git a/acme.sh b/acme.sh index 9e3ae4b5..4c4a03f1 100755 --- a/acme.sh +++ b/acme.sh @@ -3569,23 +3569,16 @@ _initconf() { if [ ! -f "$ACCOUNT_CONF_PATH" ]; then echo "#ACCOUNT_CONF_PATH=xxxx -#Account configurations: -#Here are the supported macros, uncomment them to make them take effect. - #ACCOUNT_EMAIL=aaa@example.com # the account email used to register account. #ACCOUNT_KEY_PATH=\"/path/to/account.key\" #CERT_HOME=\"/path/to/cert/home\" - #LOG_FILE=\"$DEFAULT_LOG_FILE\" #LOG_LEVEL=1 #AUTO_UPGRADE=\"1\" -#STAGE=1 # Use the staging api -#FORCE=1 # Force to issue cert -#DEBUG=1 # Debug mode #NO_TIMESTAMP=1 #OPENSSL_BIN=openssl @@ -3593,49 +3586,6 @@ _initconf() { #USER_PATH= -#dns api -####################### -#Cloudflare: -#api key -#CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\" -#account email -#CF_Email=\"xxxx@sss.com\" - -####################### -#Dnspod.cn: -#api key id -#DP_Id=\"1234\" -#api key -#DP_Key=\"sADDsdasdgdsf\" - -####################### -#Cloudxns.com: -#CX_Key=\"1234\" -# -#CX_Secret=\"sADDsdasdgdsf\" - -####################### -#Godaddy.com: -#GD_Key=\"sdfdsgdgdfdasfds\" -# -#GD_Secret=\"sADDsdasdfsdfdssdgdsf\" - -####################### -#nsupdate: -#NSUPDATE_KEY=\"/path/to/update.key\" -#NSUPDATE_SERVER=\"192.168.0.1\" - -####################### -#PowerDNS: -#PDNS_Url=\"http://ns.example.com:8081\" -#PDNS_ServerId=\"localhost\" -#PDNS_Token=\"0123456789ABCDEF\" -#PDNS_Ttl=60 - -####################### -#Amazon Route53: -#AWS_ACCESS_KEY_ID=XXXXXXXXXX -#AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX " >"$ACCOUNT_CONF_PATH" fi From c7c57cfa0e7dc2ce77eaa542a342dc79fbab557a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 11:49:24 +0800 Subject: [PATCH 0574/1348] fix for solaris --- dnsapi/dns_cf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index b8ff06c1..79f3ae83 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -144,7 +144,7 @@ _get_root() { fi if printf "%s" "$response" | grep "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$response" | _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 From 122cc48c29be40b15122ae9ad2ddda026e0c2fa0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 11:51:15 +0800 Subject: [PATCH 0575/1348] minor --- dnsapi/dns_cf.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 79f3ae83..309eee51 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -70,9 +70,7 @@ dns_cf_add() { _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" if [ "$?" = "0" ]; then - _info "Updated, sleeping 10 seconds" - sleep 10 - #todo: check if the record takes effect + _info "Updated, OK" return 0 fi _err "Update error" From 39d1eeda2362837b5eebc96a0d591573f1f0c744 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 12:41:22 +0800 Subject: [PATCH 0576/1348] fix for solaris --- dnsapi/dns_aws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index ca79326b..63542ccb 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -91,13 +91,13 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*$h..*")" + hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*$h.<.Name>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." return 1 fi - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h From 7d1c5fca0b211168bc9e5f9cfe916f92c22f9fed Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 13:52:31 +0800 Subject: [PATCH 0577/1348] fix for solaris --- dnsapi/dns_dp.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 155979af..81edc225 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -102,7 +102,7 @@ existing_records() { fi if _contains "$response" "Action completed successful"; then - count=$(printf "%s" "$response" | grep 'TXT' | wc -l) + count=$(printf "%s" "$response" | grep 'TXT' | wc -l | tr -d ' ') record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) return 0 else @@ -208,9 +208,9 @@ _rest() { if [ "$data" ]; then _debug2 data "$data" - response="$(_post "$data" "$url")" + response="$(_post "$data" "$url" | tr -d '\r')" else - response="$(_get "$url")" + response="$(_get "$url" | tr -d '\r')" fi if [ "$?" != "0" ]; then From 2728170c01510e1c5ca5aaa9f06226f19819d5f3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 14:30:17 +0800 Subject: [PATCH 0578/1348] add debug info --- dnsapi/dns_dp.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 81edc225..e2952d71 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -104,6 +104,7 @@ existing_records() { if _contains "$response" "Action completed successful"; then count=$(printf "%s" "$response" | grep 'TXT' | wc -l | tr -d ' ') record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) + _debug record_id "$record_id" return 0 else _err "get existing records error." From 03d3f3afc39e688bb998f8e2f7d3c094a2aad1df Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 14:50:45 +0800 Subject: [PATCH 0579/1348] fix for solaris --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4c4a03f1..5e672a59 100755 --- a/acme.sh +++ b/acme.sh @@ -3469,7 +3469,7 @@ _deactivate() { return 1 fi - entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"status":"valid","uri"[^\}]*')" + entry="$(printf "%s\n" "$response" | _egrep_o '{"type":".*","status":"valid","uri"[^}]*')" _debug entry "$entry" if [ -z "$entry" ]; then From 947d14ffebe9ce35ccc5da9e61a0469cfb99efb8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 9 Dec 2016 22:20:38 +0800 Subject: [PATCH 0580/1348] fix deactivate function --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5e672a59..dc3ac7f0 100755 --- a/acme.sh +++ b/acme.sh @@ -3469,7 +3469,7 @@ _deactivate() { return 1 fi - entry="$(printf "%s\n" "$response" | _egrep_o '{"type":".*","status":"valid","uri"[^}]*')" + entry="$(printf "%s\n" "$response" | _egrep_o '{"type":"[^"]*","status":"valid","uri"[^}]*')" _debug entry "$entry" if [ -z "$entry" ]; then From c4236e58d1d8faf3491335e48b43e3fdc1112a9c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Dec 2016 21:32:47 +0800 Subject: [PATCH 0581/1348] fix renew for different CA --- acme.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/acme.sh b/acme.sh index dc3ac7f0..6803616a 100755 --- a/acme.sh +++ b/acme.sh @@ -529,6 +529,7 @@ _isEccKey() { _createkey() { length="$1" f="$2" + _debug2 "_createkey for file:$f" eccname="$length" if _startswith "$length" "ec-"; then length=$(printf "%s" "$length" | cut -d '-' -f 2-100) @@ -1685,6 +1686,7 @@ _initpath() { if [ -z "$CA_CONF" ]; then CA_CONF="$_DEFAULT_CA_CONF" fi + _debug3 CA_CONF "$CA_CONF" if [ -f "$CA_CONF" ]; then . "$CA_CONF" @@ -2990,6 +2992,12 @@ renew() { if [ "$Le_API" ]; then API="$Le_API" + #reload ca configs + ACCOUNT_KEY_PATH="" + ACCOUNT_JSON_PATH="" + CA_CONF="" + _debug3 "initpath again." + _initpath "$Le_Domain" "$_isEcc" fi if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then From 4d8b99a3073778fb387a2ffa02198db835912331 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Dec 2016 20:04:43 +0800 Subject: [PATCH 0582/1348] add more debug info --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 6803616a..436c3ef9 100755 --- a/acme.sh +++ b/acme.sh @@ -406,8 +406,10 @@ _getfile() { #Usage: multiline _base64() { if [ "$1" ]; then + _debug3 "base64 multiline:$1" $OPENSSL_BIN base64 -e else + _debug3 "base64 single line." $OPENSSL_BIN base64 -e | tr -d '\r\n' fi } @@ -932,6 +934,8 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" + _debug3 n "$n" + jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' _debug3 jwk "$jwk" From 24d2a8b9d52facff65e999a8a668c3720b2dbbb7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Dec 2016 20:27:49 +0800 Subject: [PATCH 0583/1348] add debug info --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 436c3ef9..33c0ed4a 100755 --- a/acme.sh +++ b/acme.sh @@ -406,7 +406,7 @@ _getfile() { #Usage: multiline _base64() { if [ "$1" ]; then - _debug3 "base64 multiline:$1" + _debug3 "base64 multiline:'$1'" $OPENSSL_BIN base64 -e else _debug3 "base64 single line." @@ -933,7 +933,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64| _urlencode)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' From 1f6ffa3e88c8b0719d26943aa3b065571c47140b Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Dec 2016 20:32:50 +0800 Subject: [PATCH 0584/1348] fix warnings --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 33c0ed4a..c6af629a 100755 --- a/acme.sh +++ b/acme.sh @@ -933,7 +933,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64| _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' From b171aff4189634387be9fefbff64f716582136a4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Dec 2016 20:42:36 +0800 Subject: [PATCH 0585/1348] fix for wrt https://github.com/Neilpang/acme.sh/issues/465 I know it's a stupid fix, but it works. I will check it later. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index c6af629a..3512b8d6 100755 --- a/acme.sh +++ b/acme.sh @@ -933,7 +933,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64 | tr -d '\r\n' | _urlencode)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' From 329174b6d93b04cd239878f3fda07458532f7b29 Mon Sep 17 00:00:00 2001 From: klemens Date: Wed, 14 Dec 2016 21:32:24 +0100 Subject: [PATCH 0586/1348] spelling fixes --- README.md | 2 +- acme.sh | 4 ++-- dnsapi/dns_ali.sh | 2 +- dnsapi/dns_aws.sh | 6 +++--- dnsapi/dns_cf.sh | 2 +- dnsapi/dns_cx.sh | 2 +- dnsapi/dns_dp.sh | 2 +- dnsapi/dns_gd.sh | 2 +- dnsapi/dns_ispconfig.sh | 2 +- dnsapi/dns_lua.sh | 2 +- dnsapi/dns_me.sh | 2 +- dnsapi/dns_myapi.sh | 4 ++-- dnsapi/dns_nsupdate.sh | 2 +- dnsapi/dns_ovh.sh | 2 +- dnsapi/dns_pdns.sh | 2 +- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 1e563795..a9d5d31d 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,7 @@ acme.sh --renew -d example.com --force --ecc # 11. How to upgrade `acme.sh` -acme.sh is in constant developement, so it's strongly recommended to use the latest code. +acme.sh is in constant development, so it's strongly recommended to use the latest code. You can update acme.sh to the latest code: diff --git a/acme.sh b/acme.sh index 6803616a..75d4be80 100755 --- a/acme.sh +++ b/acme.sh @@ -1913,7 +1913,7 @@ _setApache() { fi _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" _info "In case there is an error that can not be restored automatically, you may try restore it yourself." - _info "The backup file will be deleted on sucess, just forget it." + _info "The backup file will be deleted on success, just forget it." #add alias @@ -3780,7 +3780,7 @@ install() { if [ -z "$NO_DETECT_SH" ]; then #Modify shebang if _exists bash; then - _info "Good, bash is found, so change the shebang to use bash as prefered." + _info "Good, bash is found, so change the shebang to use bash as preferred." _shebang='#!/usr/bin/env bash' _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" for subf in $_SUB_FOLDERS; do diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 30867219..98c56f87 100644 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -35,7 +35,7 @@ dns_ali_rm() { _clean } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _get_root() { domain=$1 diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 63542ccb..86d4d044 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -42,7 +42,7 @@ dns_aws_add() { _aws_tmpl_xml="UPSERT$fulldomainTXT300\"$txtvalue\"" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then - _info "txt record updated sucess." + _info "txt record updated success." return 0 fi @@ -66,7 +66,7 @@ dns_aws_rm() { _aws_tmpl_xml="DELETE\"$txtvalue\"$fulldomain.TXT300" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then - _info "txt record deleted sucess." + _info "txt record deleted success." return 0 fi @@ -74,7 +74,7 @@ dns_aws_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _get_root() { domain=$1 diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 309eee51..e13e6d7e 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -120,7 +120,7 @@ dns_cf_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 86a7b2d0..f7f20812 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -131,7 +131,7 @@ update_record() { return 1 } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index e2952d71..06833b4b 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -158,7 +158,7 @@ update_record() { return 1 #error } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 9470ed22..81000561 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -59,7 +59,7 @@ dns_gd_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index 789b6267..a84d95d7 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -30,7 +30,7 @@ dns_ispconfig_rm() { _ISPC_credentials && _ISPC_login && _ISPC_rmTxt } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _ISPC_credentials() { if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 2c7ec4b3..bc06b3ef 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -84,7 +84,7 @@ dns_lua_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 2a03f533..d7a1b19f 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -81,7 +81,7 @@ dns_me_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index e5a98dd9..6bf62508 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -23,7 +23,7 @@ dns_myapi_add() { } #Usage: fulldomain txtvalue -#Remove the txt record afer validation. +#Remove the txt record after validation. dns_myapi_rm() { fulldomain=$1 txtvalue=$2 @@ -32,4 +32,4 @@ dns_myapi_rm() { _debug txtvalue "$txtvalue" } -#################### Private functions bellow ################################## +#################### Private functions below ################################## diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 8067d2fe..7acb2ef7 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -44,7 +44,7 @@ EOF return 0 } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _checkKeyFile() { if [ -z "${NSUPDATE_KEY}" ]; then diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 377b3de1..18b9c341 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -182,7 +182,7 @@ dns_ovh_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _ovh_authentication() { diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index a2c29075..06763d88 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -130,7 +130,7 @@ notify_slaves() { return 0 } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _domain=domain.com From a3a04b5f769f58514cce19933b44b73e798bbc5f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Dec 2016 20:51:00 +0800 Subject: [PATCH 0587/1348] revert last fix --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3512b8d6..c6af629a 100755 --- a/acme.sh +++ b/acme.sh @@ -933,7 +933,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | tr -d '\r\n' | _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' From 96db9362c565cd9245b0051af50ab08f1b195eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 18 Dec 2016 03:17:35 +0100 Subject: [PATCH 0588/1348] Fix typo. --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 81e0e0cc..acbcc023 100755 --- a/acme.sh +++ b/acme.sh @@ -637,8 +637,8 @@ _createcsr() { _info "Multi domain" "$alt" printf -- "\nsubjectAltName=$alt" >>"$csrconf" fi - if [ "$Le_OCSP_Stable" ]; then - _savedomainconf Le_OCSP_Stable "$Le_OCSP_Stable" + if [ "$Le_OCSP_Staple" ]; then + _savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple" printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" fi @@ -4365,7 +4365,7 @@ _process() { shift ;; --ocsp-must-staple | --ocsp) - Le_OCSP_Stable="1" + Le_OCSP_Staple="1" ;; --log | --logfile) _log="1" From 0a3b6c4813b9faa1b5f7404455a4876972b052b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 18 Dec 2016 05:29:27 +0100 Subject: [PATCH 0589/1348] Keep backwards compatible. --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index acbcc023..b67960d0 100755 --- a/acme.sh +++ b/acme.sh @@ -637,8 +637,9 @@ _createcsr() { _info "Multi domain" "$alt" printf -- "\nsubjectAltName=$alt" >>"$csrconf" fi - if [ "$Le_OCSP_Staple" ]; then + if [ "$Le_OCSP_Staple" ] || [ "$Le_OCSP_Stable" ]; then _savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple" + _cleardomainconf Le_OCSP_Stable printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" fi From 08b6cf023169788404ac05baf23e6017adaa7767 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Dec 2016 19:56:28 +0800 Subject: [PATCH 0590/1348] fix https://github.com/Neilpang/acme.sh/issues/478 --- acme.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acme.sh b/acme.sh index b67960d0..691eb7d8 100755 --- a/acme.sh +++ b/acme.sh @@ -2225,11 +2225,13 @@ _regAccount() { _reg_length="$1" if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" fi if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then + mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" fi From e2c939fb97da2dcd578e6aff0acec4b008afde11 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Dec 2016 20:19:57 +0800 Subject: [PATCH 0591/1348] fix https://github.com/Neilpang/acme.sh/issues/480 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 691eb7d8..a4375033 100755 --- a/acme.sh +++ b/acme.sh @@ -3359,7 +3359,7 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi - if _exists uname && uname -a | grep solaris >/dev/null; then + if _exists uname && uname -a | grep SunOS >/dev/null; then crontab -l | { cat echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" From 3a3b0dd5c1b5a8d9ec7c45f42194c5ae56a44cf8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Dec 2016 20:38:14 +0800 Subject: [PATCH 0592/1348] fix https://github.com/Neilpang/acme.sh/issues/481 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a4375033..aefc0155 100755 --- a/acme.sh +++ b/acme.sh @@ -3977,7 +3977,10 @@ _installOnline() { fi ( _info "Extracting $localname" - tar xzf $localname + if ! (tar xzf $localname || gtar xzf $localname); then + _err "Extraction error." + exit 1 + fi cd "$PROJECT_NAME-$BRANCH" chmod +x $PROJECT_ENTRY From 4743171b4f1f97c4054f4df6365f44630ee65753 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 22 Dec 2016 20:06:55 +0800 Subject: [PATCH 0593/1348] service nginx force-reload --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a9d5d31d..1a7766ef 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ acme.sh --installcert -d example.com \ --certpath /path/to/certfile/in/apache/cert.pem \ --keypath /path/to/keyfile/in/apache/key.pem \ --fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ ---reloadcmd "service apache2 restart" +--reloadcmd "service apache2 force-reload" ``` **Nginx** example: @@ -155,7 +155,7 @@ acme.sh --installcert -d example.com \ acme.sh --installcert -d example.com \ --keypath /path/to/keyfile/in/nginx/key.pem \ --fullchainpath /path/to/fullchain/nginx/cert.pem \ ---reloadcmd "service nginx restart" +--reloadcmd "service nginx force-reload" ``` Only the domain is required, all the other parameters are optional. From 8c71bd57e750ee1ad827d706c02bfa3052d18076 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Dec 2016 20:19:22 +0800 Subject: [PATCH 0594/1348] fix https://github.com/Neilpang/acme.sh/issues/491 --- dnsapi/dns_cx.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index f7f20812..dfc838ae 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -82,7 +82,7 @@ existing_records() { return 1 fi - seg=$(printf "%s\n" "$response" | _egrep_o '{[^{]*host":"'"$_sub_domain"'"[^}]*\}') + seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*host":"'"$_sub_domain"'"[^}]*\}') _debug seg "$seg" if [ -z "$seg" ]; then return 0 @@ -155,7 +155,7 @@ _get_root() { fi if _contains "$response" "$h."; then - seg=$(printf "%s\n" "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') + seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*"'"$h"'."[^}]*}') _debug seg "$seg" _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" From 15af89d51cdd7c64705471550dc8ade17713eec8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Dec 2016 20:40:52 +0800 Subject: [PATCH 0595/1348] fix https://github.com/Neilpang/acme.sh/issues/490 --- dnsapi/dns_cf.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index e13e6d7e..0b817d36 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -132,6 +132,7 @@ _get_root() { 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 @@ -141,8 +142,8 @@ _get_root() { return 1 fi - if printf "%s" "$response" | grep "\"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 "$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 [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h From 20444bf253841de76fedc80de824665aa0eafa61 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Dec 2016 20:53:57 +0800 Subject: [PATCH 0596/1348] fix https://github.com/Neilpang/acme.sh/issues/465 --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index aefc0155..4c096534 100755 --- a/acme.sh +++ b/acme.sh @@ -405,6 +405,7 @@ _getfile() { #Usage: multiline _base64() { + [ "" ];#urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" $OPENSSL_BIN base64 -e From ec9975c3d9a521ebcf3573841810adfaa58a08c4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Dec 2016 21:29:44 +0800 Subject: [PATCH 0597/1348] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4c096534..5199a820 100755 --- a/acme.sh +++ b/acme.sh @@ -405,7 +405,7 @@ _getfile() { #Usage: multiline _base64() { - [ "" ];#urgly + [ "" ] #urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" $OPENSSL_BIN base64 -e From fe600441c9a121e0b6bdf125296f316d2b44d67c Mon Sep 17 00:00:00 2001 From: Georg Lutz Date: Thu, 29 Dec 2016 11:12:26 +0100 Subject: [PATCH 0598/1348] Add note about permissions of installed files --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1a7766ef..dde2eeae 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,8 @@ acme.sh --installcert -d example.com \ Only the domain is required, all the other parameters are optional. +The ownership and permission info of existing files are preserved. You may want to precreate the files to have defined ownership and permission. + Install/copy the issued cert/key to the production Apache or Nginx path. The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the Apache/Nginx service will be restarted automatically by the command: `service apache2 restart` or `service nginx restart`. From e5079b9dad0b8e12d4d043daacd5da93e8422d4a Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Mon, 2 Jan 2017 23:39:00 +0000 Subject: [PATCH 0599/1348] Add Alwaysdata DNS API. --- dnsapi/dns_ad.sh | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 dnsapi/dns_ad.sh diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh new file mode 100644 index 00000000..158ea951 --- /dev/null +++ b/dnsapi/dns_ad.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env sh + +# +#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" + +#This is the Alwaysdata api wrapper for acme.sh + +AD_HOST="api.alwaysdata.com" +AD_URL="https://$AD_API_KEY:@$AD_HOST" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ad_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$AD_API_KEY" ]; then + AD_API_KEY="" + _err "You didn't specify the AD api key yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf AD_API_KEY "$AD_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" + + _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" + + if ad_rest POST "record/" "" "$_ad_tmpl_json" && [ -z "$response" ]; then + _info "txt record updated success." + return 0 + fi + + return 1 +} + +#fulldomain txtvalue +dns_ad_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" + + if ad_rest DELETE "record/" "domain=$_domain_id&name=$_sub_domain" "" && [ -z "$response" ]; then + _info "txt record deleted success." + return 0 + fi + _debug response "$response" + + return 1 +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=2 + p=1 + + if ad_rest GET "domain/"; then + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + hostedzone="$(echo "$response" | tr -d "\n" | sed 's//\n&/g' | _egrep_o ".*$h<.name>.*<.object>")" + if [ -z "$hostedzone" ]; then + _err "Error, can not get domain record." + return 1 + fi + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.id>" | head -n 1 | _egrep_o ">.*<" | 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 +ad_rest() { + mtd="$1" + ep="$2" + qsr="$3" + data="$4" + + _debug mtd "$mtd" + _debug ep "$ep" + _debug qsr "$qsr" + _debug data "$data" + + _H1="Accept: application/xml" + + url="$AD_URL/v1/$ep?$qsr" + + if [ "$mtd" = "GET" ]; then + response="$(_get "$url")" + elif [ "$mtd" = "DELETE" ]; then + response="$(_delete "$url")" + else + response="$(_post "$data" "$url")" + fi + + _ret="$?" + if [ "$_ret" = "0" ]; then + # Errors usually 404, otherwise just empty response. How to detect 404? + if _contains "$response" " Date: Tue, 3 Jan 2017 19:31:11 +0800 Subject: [PATCH 0600/1348] run pre-hook first --- acme.sh | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 5199a820..06b14ef6 100755 --- a/acme.sh +++ b/acme.sh @@ -2075,6 +2075,17 @@ _clearupwebbroot() { _on_before_issue() { _debug _on_before_issue + #run pre hook + if [ "$Le_PreHook" ]; then + _info "Run pre hook:'$Le_PreHook'" + if ! ( + cd "$DOMAIN_PATH" && eval "$Le_PreHook" + ); then + _err "Error when run pre hook." + return 1 + fi + fi + if _hasfield "$Le_Webroot" "$NO_VALUE"; then if ! _exists "nc"; then _err "Please install netcat(nc) tools first." @@ -2142,16 +2153,6 @@ _on_before_issue() { usingApache="" fi - #run pre hook - if [ "$Le_PreHook" ]; then - _info "Run pre hook:'$Le_PreHook'" - if ! ( - cd "$DOMAIN_PATH" && eval "$Le_PreHook" - ); then - _err "Error when run pre hook." - return 1 - fi - fi } _on_issue_err() { From 331b599a8184234f3f007acfca570ce43b26e31c Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 11:41:11 +0000 Subject: [PATCH 0601/1348] Use _post for DELETE and switch to JSON API (Alwaysdata default). --- dnsapi/dns_ad.sh | 81 +++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 158ea951..379b51f9 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -5,8 +5,7 @@ #This is the Alwaysdata api wrapper for acme.sh -AD_HOST="api.alwaysdata.com" -AD_URL="https://$AD_API_KEY:@$AD_HOST" +AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" ######## Public functions ##################### @@ -35,7 +34,7 @@ dns_ad_add() { _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" - if ad_rest POST "record/" "" "$_ad_tmpl_json" && [ -z "$response" ]; then + if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then _info "txt record updated success." return 0 fi @@ -57,37 +56,51 @@ dns_ad_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - if ad_rest DELETE "record/" "domain=$_domain_id&name=$_sub_domain" "" && [ -z "$response" ]; then - _info "txt record deleted success." - return 0 + _debug "Getting txt records" + _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" + + if [ -n "$response" ]; then + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d \ | head -n 1) + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if _ad_rest DELETE "record/$record_id/" && [ -z "$response" ]; then + _info "txt record deleted success." + return 0 + fi + _debug response "$response" + return 1 fi - _debug response "$response" 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 ad_rest GET "domain/"; then + if _ad_rest GET "domain/"; 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 - if _contains "$response" "$h"; then - hostedzone="$(echo "$response" | tr -d "\n" | sed 's//\n&/g' | _egrep_o ".*$h<.name>.*<.object>")" - if [ -z "$hostedzone" ]; then - _err "Error, can not get domain record." - return 1 - fi - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") + 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 @@ -103,37 +116,29 @@ _get_root() { } #method uri qstr data -ad_rest() { +_ad_rest() { mtd="$1" ep="$2" - qsr="$3" - data="$4" + data="$3" _debug mtd "$mtd" _debug ep "$ep" - _debug qsr "$qsr" - _debug data "$data" - _H1="Accept: application/xml" + _H1="Accept: application/json" + _H2="Content-Type: application/json" - url="$AD_URL/v1/$ep?$qsr" - - if [ "$mtd" = "GET" ]; then - response="$(_get "$url")" - elif [ "$mtd" = "DELETE" ]; then - response="$(_delete "$url")" + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$AD_API_URL/$ep" "" "$mtd")" else - response="$(_post "$data" "$url")" + response="$(_get "$AD_API_URL/$ep")" fi - _ret="$?" - if [ "$_ret" = "0" ]; then - # Errors usually 404, otherwise just empty response. How to detect 404? - if _contains "$response" " Date: Tue, 3 Jan 2017 12:09:57 +0000 Subject: [PATCH 0602/1348] Merge suggested improvements. * Use `_head_n`. * Add link to GitHub repo for bug reporting. --- dnsapi/dns_ad.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 379b51f9..81c20e09 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -4,6 +4,9 @@ #AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" #This is the Alwaysdata api wrapper for acme.sh +# +#Author: Paul Koppen +#Report Bugs here: https://github.com/wpk-/acme.sh AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" @@ -60,7 +63,7 @@ dns_ad_rm() { _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" if [ -n "$response" ]; then - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d \ | head -n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d \ | _head_n 1) _debug record_id "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." @@ -100,7 +103,7 @@ _get_root() { 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 \ ) + _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 From b2686e5b6da57b51f2ddb55e8ca06e69777c8cab Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 12:13:27 +0000 Subject: [PATCH 0603/1348] Add Alwaysdata.com to list of supported API's. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dde2eeae..9b5891c9 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,7 @@ You don't have to do anything manually! 1. nsupdate API 1. aliyun.com(阿里云) API 1. ISPConfig 3.1 API +1. Alwaysdata.com API **More APIs coming soon...** From 180f05f6f08bdfbec46d53c6b1b4bdcc7538e527 Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 12:16:22 +0000 Subject: [PATCH 0604/1348] Add instructions for the Alwaysdata API. --- dnsapi/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index c4245701..e32b4655 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -240,6 +240,23 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 13. Use Alwaysdata domain API + +First you need to login to your Alwaysdata account to get your API Key. + +```sh +export AD_API_KEY="myalwaysdataapikey" +``` + +Ok, let's issue a cert now: + +```sh +acme.sh --issue --dns dns_ad -d example.com -d www.example.com +``` + +The `AD_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused +when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. From b90917a52951e85cb5eda4ae51d6daedd921fbf7 Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 12:33:10 +0000 Subject: [PATCH 0605/1348] Improve legibility. --- dnsapi/dns_ad.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 81c20e09..cbec6c9b 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -63,7 +63,7 @@ dns_ad_rm() { _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" if [ -n "$response" ]; then - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d \ | _head_n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) _debug record_id "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." From 7b4be7be4094176098d889d7a37feab0dd45ace9 Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 12:35:10 +0000 Subject: [PATCH 0606/1348] Remove spaces from blank lines. --- dnsapi/dns_ad.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index cbec6c9b..1c7e85f9 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -36,12 +36,12 @@ dns_ad_add() { _debug _domain "$_domain" _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" - + if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then _info "txt record updated success." return 0 fi - + return 1 } @@ -61,7 +61,7 @@ dns_ad_rm() { _debug "Getting txt records" _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" - + if [ -n "$response" ]; then record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) _debug record_id "$record_id" @@ -129,7 +129,7 @@ _ad_rest() { _H1="Accept: application/json" _H2="Content-Type: application/json" - + if [ "$mtd" != "GET" ]; then # both POST and DELETE. _debug data "$data" From 058e5d5f4b9b67f49527da71f9c0a3fbfbecc8c4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 5 Jan 2017 22:32:26 +0800 Subject: [PATCH 0607/1348] LF --- .travis.yml | 108 ++++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/.travis.yml b/.travis.yml index 94848c17..0667919d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,54 +1,54 @@ -language: shell -sudo: required - -os: - - linux - - osx - -env: - global: - - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 - -addons: - apt: - sources: - - debian-sid # Grab shellcheck from the Debian repo (o_O) - packages: - - shellcheck - -install: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew update && brew install openssl; - brew info openssl; - ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; - _old_path="$PATH"; - echo "PATH=$PATH"; - export PATH=""; - export OPENSSL_BIN="/usr/local/openssl"; - openssl version 2>&1 || true; - $OPENSSL_BIN version 2>&1 || true; - export PATH="$_old_path"; - fi - -script: - - echo "TEST_LOCAL=$TEST_LOCAL" - - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - - which openssl && openssl version - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - - cd .. - - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi - - -matrix: - fast_finish: true - - +language: shell +sudo: required + +os: + - linux + - osx + +env: + global: + - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 + +addons: + apt: + sources: + - debian-sid # Grab shellcheck from the Debian repo (o_O) + packages: + - shellcheck + +install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew update && brew install openssl; + brew info openssl; + ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; + ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; + ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; + _old_path="$PATH"; + echo "PATH=$PATH"; + export PATH=""; + export OPENSSL_BIN="/usr/local/openssl"; + openssl version 2>&1 || true; + $OPENSSL_BIN version 2>&1 || true; + export PATH="$_old_path"; + fi + +script: + - echo "TEST_LOCAL=$TEST_LOCAL" + - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" + - which openssl && openssl version + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi + - cd .. + - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest + - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + + +matrix: + fast_finish: true + + From 5415381cf42f005953392267b75936db5199ddb9 Mon Sep 17 00:00:00 2001 From: Karsten Sperling Date: Fri, 6 Jan 2017 15:27:55 +1300 Subject: [PATCH 0608/1348] Add support for AWS_SESSION_TOKEN and fix bug when multiple hosted zones exist --- dnsapi/dns_aws.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 86d4d044..38b03cd4 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -27,8 +27,10 @@ dns_aws_add() { return 1 fi - _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" - _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" + if [ -z "$AWS_SESSION_TOKEN" ]; then + _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" + _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" + fi _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -91,7 +93,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*$h.<.Name>.*<.HostedZone>")" + hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*?$h.<.Name>.*?<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." @@ -139,9 +141,13 @@ aws_rest() { aws_host="$AWS_HOST" CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" - _debug2 CanonicalHeaders "$CanonicalHeaders" - SignedHeaders="host;x-amz-date" + if [ -n "$AWS_SESSION_TOKEN" ]; then + _H2="x-amz-security-token: $AWS_SESSION_TOKEN" + CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" + SignedHeaders="${SignedHeaders};x-amz-security-token" + fi + _debug2 CanonicalHeaders "$CanonicalHeaders" _debug2 SignedHeaders "$SignedHeaders" RequestPayload="$data" From 3cf85634ebb955ecee7616e88f4e1cef4458df41 Mon Sep 17 00:00:00 2001 From: Kevin Kaland Date: Sun, 8 Jan 2017 00:09:21 +0100 Subject: [PATCH 0609/1348] Trim potential closing curly brace. Fixes GH-517. --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index d7a1b19f..c94a3c90 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -103,7 +103,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | head -n 1 | cut -d : -f 2) + _domain_id=$(printf "%s\n" "$response" | _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" From 800f02ba381cb526860b12ffdf5c3f9577e93553 Mon Sep 17 00:00:00 2001 From: Bastian Bittorf Date: Mon, 9 Jan 2017 12:19:18 +0100 Subject: [PATCH 0610/1348] dnsapi/dns_lexicon.sh: shellcheck: fix 4 occurences of SC2021: "Don't use [] around ranges in tr, it replaces literal square brackets." this introduces another warning: "Use '[:lower:]' to support accents and foreign alphabets." This is more a style thingy because we really want to only catch A-Z. work around this by using a shellcheck-directive and a comment that the [:lower:] will not work with e.g. busybox-ash. if we later really want to use [:lower:], we should use 'sed' for that. --- .travis.yml | 2 +- dnsapi/dns_lexicon.sh | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0667919d..fd4ee25c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 4ab65645..0398bd2e 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -30,7 +30,9 @@ dns_lexicon_add() { _savedomainconf PROVIDER "$PROVIDER" export PROVIDER - Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr '[a-z]' '[A-Z]') + # e.g. busybox-ash does not know [:upper:] + # shellcheck disable=SC2018,SC2019 + Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') Lx_name_v=$(eval echo \$"$Lx_name") _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then @@ -38,7 +40,8 @@ dns_lexicon_add() { eval export "$Lx_name" fi - Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr '[a-z]' '[A-Z]') + # shellcheck disable=SC2018,SC2019 + Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') Lx_token_v=$(eval echo \$"$Lx_token") _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then @@ -46,7 +49,8 @@ dns_lexicon_add() { eval export "$Lx_token" fi - Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr '[a-z]' '[A-Z]') + # shellcheck disable=SC2018,SC2019 + Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') Lx_password_v=$(eval echo \$"$Lx_password") _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then @@ -54,7 +58,8 @@ dns_lexicon_add() { eval export "$Lx_password" fi - Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr '[a-z]' '[A-Z]') + # shellcheck disable=SC2018,SC2019 + Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then From d11d476126a6958211d9813ebf34c1e33f25055a Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 9 Jan 2017 20:26:07 +0800 Subject: [PATCH 0611/1348] "Don't use [] around ranges in tr, it replaces literal square brackets." --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 06b14ef6..d0f97b1a 100755 --- a/acme.sh +++ b/acme.sh @@ -573,7 +573,7 @@ _createkey() { _is_idn() { _is_idn_d="$1" _debug2 _is_idn_d "$_is_idn_d" - _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '[0-9]' | tr -d '[a-z]' | tr -d '[A-Z]' | tr -d '.,-') + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-') _debug2 _idn_temp "$_idn_temp" [ "$_idn_temp" ] } From 671a69947219a745cb3882b33d4b60a312b5cb60 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 9 Jan 2017 22:01:48 +0800 Subject: [PATCH 0612/1348] minor, fix shellcheck warning --- dnsapi/dns_dp.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 06833b4b..3691be06 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -199,7 +199,7 @@ _get_root() { #Usage: method URI data _rest() { - m=$1 + m="$1" ep="$2" data="$3" _debug "$ep" @@ -207,11 +207,11 @@ _rest() { _debug url "$url" - if [ "$data" ]; then + if [ "$m" = "GET" ]; then + response="$(_get "$url" | tr -d '\r')" + else _debug2 data "$data" response="$(_post "$data" "$url" | tr -d '\r')" - else - response="$(_get "$url" | tr -d '\r')" fi if [ "$?" != "0" ]; then From 3b67cf4378c5dfc141dce4e66639d4fa7d2b462b Mon Sep 17 00:00:00 2001 From: Bastian Bittorf Date: Mon, 9 Jan 2017 15:08:41 +0100 Subject: [PATCH 0613/1348] dnsapi/dns_dp.sh: shellcheck: fix 1 occurence of SC2126 shellcheck message was: "Consider using grep -c instead of grep | wc" --- .travis.yml | 2 +- dnsapi/dns_dp.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fd4ee25c..1924f82a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 3691be06..301a1f6c 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -102,7 +102,7 @@ existing_records() { fi if _contains "$response" "Action completed successful"; then - count=$(printf "%s" "$response" | grep 'TXT' | wc -l | tr -d ' ') + count=$(printf "%s" "$response" | grep -c 'TXT' | tr -d ' ') record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) _debug record_id "$record_id" return 0 From 5413bf8753bce20471a3023559e176db6e9c1977 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 10 Jan 2017 10:36:47 +0800 Subject: [PATCH 0614/1348] minor, clear account key cache if new-authz error. --- acme.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/acme.sh b/acme.sh index d0f97b1a..bd3a51b5 100755 --- a/acme.sh +++ b/acme.sh @@ -2356,6 +2356,12 @@ __get_domain_new_authz() { _err "Can not get domain new authz." return 1 fi + if _contains "$response" "No registration exists matching provided key"; then + _err "It seems there is an error, but it's recovered now, please try again." + _err "If you see this message for a second time, please report bug: $(__green "$PROJECT")" + _clearcaconf "CA_KEY_HASH" + break + fi if ! _contains "$response" "An error occurred while processing your request"; then _info "The new-authz request is ok." break From 1699e94f0ffdd056cd58891dd43a4386b2246471 Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 14:09:58 +0100 Subject: [PATCH 0615/1348] Adding kong deploy script (https://getkong.org) --- deploy/kong.sh | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 deploy/kong.sh diff --git a/deploy/kong.sh b/deploy/kong.sh new file mode 100644 index 00000000..cd9de10c --- /dev/null +++ b/deploy/kong.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env sh + +# This deploy hook will deploy ssl cert on kong proxy engine based on api request_host parameter. +# Note that ssl plugin should be available on Kong instance +# 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 + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +kong.sh_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _info "Deploying certificate on Kong instance" + if [ -z "$KONG_URL" ] + then + _debug "KONG_URL Not set, using default http://localhost:8001" + KONG_URL="http://localhost:8001" + fi + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + #Get 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}' ) + if [ "$uuid" = "" ] + then + _err "Unable to get Kong uuid for domain $_cdomain" + _err "Make sure that KONG_URL is correctly configured" + _err "Make sure that a Kong api request_host match the domain" + _err "Kong url: $KONG_URL" + return 1 + fi + #Save kong url if it's succesful (First run case) + _saveaccountconf KONG_URL "$KONG_URL" + #Generate DEIM + delim="-----MultipartDelimeter$(date "+%s%N")" + nl=$( printf "\\r\\n" ) + #Set Header + _H1="Content-Type: multipart/form-data; boundary=$delim" + #Generate data for request (Multipart/form-data with mixed content) + #set name to ssl + content="--$delim${nl}Content-Disposition: form-data; name=\"name\"${nl}${nl}ssl" + #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")" + #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")" + #Close multipart + content="$content${nl}--$delim--${nl}" + #DEBUG + _debug header "$_H1" + _debug content "$content" + #Check if ssl plugins is aready enabled (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 [ "$ssl_uuid" = "" ] + then + #Post certificate to Kong + response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST" ) + else + #patch + response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH" ) + fi + if ! [ "$( echo "$response" | _egrep_o "ssl" )" = "ssl" ] + then + _err "An error occured with cert upload. Check response:" + _err "$response" + return 1 + fi + _debug response "$response" + _info "Certificate successfully deployed" +} From 07feb87deeab89fe55af42a532b463f1e3cc3ae8 Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 14:52:52 +0100 Subject: [PATCH 0616/1348] Travis fix --- deploy/kong.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index cd9de10c..0fa726a3 100644 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -20,8 +20,7 @@ kong.sh_deploy() { _cca="$4" _cfullchain="$5" _info "Deploying certificate on Kong instance" - if [ -z "$KONG_URL" ] - then + if [ -z "$KONG_URL" ]; then _debug "KONG_URL Not set, using default http://localhost:8001" KONG_URL="http://localhost:8001" fi @@ -33,9 +32,8 @@ kong.sh_deploy() { _debug _cfullchain "$_cfullchain" #Get 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}' ) - if [ "$uuid" = "" ] - then + 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}') + if [ "$uuid" = "" ]; then _err "Unable to get Kong uuid for domain $_cdomain" _err "Make sure that KONG_URL is correctly configured" _err "Make sure that a Kong api request_host match the domain" @@ -46,7 +44,7 @@ kong.sh_deploy() { _saveaccountconf KONG_URL "$KONG_URL" #Generate DEIM delim="-----MultipartDelimeter$(date "+%s%N")" - nl=$( printf "\\r\\n" ) + nl=$(printf "\\r\\n") #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) @@ -62,18 +60,17 @@ kong.sh_deploy() { _debug header "$_H1" _debug content "$content" #Check if ssl plugins is aready enabled (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}' ) + 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 [ "$ssl_uuid" = "" ] then #Post certificate to Kong - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST" ) + response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") else #patch - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH" ) + response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") fi - if ! [ "$( echo "$response" | _egrep_o "ssl" )" = "ssl" ] - then + if ! [ "$( echo "$response" | _egrep_o "ssl" )" = "ssl" ]; then _err "An error occured with cert upload. Check response:" _err "$response" return 1 From e2cc350fbc90c18e5574361d15ce57f600eaa42c Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 14:54:52 +0100 Subject: [PATCH 0617/1348] Fix function name --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 0fa726a3..86a1835b 100644 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -13,7 +13,7 @@ ######## Public functions ##################### #domain keyfile certfile cafile fullchain -kong.sh_deploy() { +kong_deploy() { _cdomain="$1" _ckey="$2" _ccert="$3" From 753d0e7df77b9dcf261da4547c679fec49df0961 Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 15:05:26 +0100 Subject: [PATCH 0618/1348] Syntax fix part 2 --- deploy/kong.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 86a1835b..2eab3d4e 100644 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -21,8 +21,8 @@ kong_deploy() { _cfullchain="$5" _info "Deploying certificate on Kong instance" if [ -z "$KONG_URL" ]; then - _debug "KONG_URL Not set, using default http://localhost:8001" - KONG_URL="http://localhost:8001" + _debug "KONG_URL Not set, using default http://localhost:8001" + KONG_URL="http://localhost:8001" fi _debug _cdomain "$_cdomain" @@ -32,7 +32,7 @@ kong_deploy() { _debug _cfullchain "$_cfullchain" #Get 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}') + 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}') if [ "$uuid" = "" ]; then _err "Unable to get Kong uuid for domain $_cdomain" _err "Make sure that KONG_URL is correctly configured" @@ -62,15 +62,14 @@ kong_deploy() { #Check if ssl plugins is aready enabled (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 [ "$ssl_uuid" = "" ] - then + if [ "$ssl_uuid" = "" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") else #patch response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") fi - if ! [ "$( echo "$response" | _egrep_o "ssl" )" = "ssl" ]; then + if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then _err "An error occured with cert upload. Check response:" _err "$response" return 1 From 5fe91d65770d84e6de633384f94fcdcd5a9e6039 Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 16:17:16 +0100 Subject: [PATCH 0619/1348] Correction of test from comment of Neilpang + Correction of CRLF with sh not working correctly --- deploy/kong.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 2eab3d4e..3b9c5c79 100644 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -33,7 +33,7 @@ kong_deploy() { #Get 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}') - if [ "$uuid" = "" ]; then + if [ -z "$uuid" ]; then _err "Unable to get Kong uuid for domain $_cdomain" _err "Make sure that KONG_URL is correctly configured" _err "Make sure that a Kong api request_host match the domain" @@ -44,7 +44,7 @@ kong_deploy() { _saveaccountconf KONG_URL "$KONG_URL" #Generate DEIM delim="-----MultipartDelimeter$(date "+%s%N")" - nl=$(printf "\\r\\n") + nl="\015\012" #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) @@ -56,13 +56,15 @@ kong_deploy() { 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")" #Close multipart content="$content${nl}--$delim--${nl}" + #Convert CRLF + content=$(printf %b "$content") #DEBUG _debug header "$_H1" _debug content "$content" #Check if ssl plugins is aready enabled (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 [ "$ssl_uuid" = "" ]; then + if [ -z "$ssl_uuid" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") else From 2fbf39915652975f0b15a4090919ac22ccc5c374 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 13 Jan 2017 20:49:58 +0800 Subject: [PATCH 0620/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bd3a51b5..6eace3fd 100755 --- a/acme.sh +++ b/acme.sh @@ -4540,7 +4540,7 @@ _process() { if [ "$INSTALLONLINE" ]; then INSTALLONLINE="" - _installOnline $BRANCH + _installOnline exit fi From 3ca93f4a4c679b93361f3ae411fd0eceda813f3c Mon Sep 17 00:00:00 2001 From: Bastian Bittorf Date: Mon, 9 Jan 2017 17:04:09 +0100 Subject: [PATCH 0621/1348] shellcheck: fix several occurences of SC2034 message: SC2034: $VARNAME appears unused. Verify it or export it. most of these are related to the style: we generate global vars, which are used in other functions. the var "lexical_url" was really unused (left it as comment) the travis-check now does not need anymore special flags. Signed-off-by: Bastian Bittorf --- .travis.yml | 2 +- dnsapi/dns_ad.sh | 4 ++-- dnsapi/dns_aws.sh | 4 ++-- dnsapi/dns_cf.sh | 6 +++--- dnsapi/dns_cx.sh | 8 ++++---- dnsapi/dns_gd.sh | 4 ++-- dnsapi/dns_ispconfig.sh | 2 +- dnsapi/dns_lexicon.sh | 2 +- dnsapi/dns_lua.sh | 4 ++-- dnsapi/dns_me.sh | 6 +++--- dnsapi/dns_ovh.sh | 10 +++++----- dnsapi/dns_pdns.sh | 2 +- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1924f82a..1fff02e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2034 **/*.sh && echo "shellcheck OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 1c7e85f9..fc4a664b 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -127,8 +127,8 @@ _ad_rest() { _debug mtd "$mtd" _debug ep "$ep" - _H1="Accept: application/json" - _H2="Content-Type: application/json" + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" if [ "$mtd" != "GET" ]; then # both POST and DELETE. diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 38b03cd4..59ef6181 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -137,13 +137,13 @@ aws_rest() { #RequestDate="20161120T141056Z" ############## - _H1="x-amz-date: $RequestDate" + export _H1="x-amz-date: $RequestDate" aws_host="$AWS_HOST" CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" SignedHeaders="host;x-amz-date" if [ -n "$AWS_SESSION_TOKEN" ]; then - _H2="x-amz-security-token: $AWS_SESSION_TOKEN" + export _H2="x-amz-security-token: $AWS_SESSION_TOKEN" CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" SignedHeaders="${SignedHeaders};x-amz-security-token" fi diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 0b817d36..3718f9db 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -163,9 +163,9 @@ _cf_rest() { data="$3" _debug "$ep" - _H1="X-Auth-Email: $CF_Email" - _H2="X-Auth-Key: $CF_Key" - _H3="Content-Type: application/json" + export _H1="X-Auth-Email: $CF_Email" + export _H2="X-Auth-Key: $CF_Key" + export _H3="Content-Type: application/json" if [ "$m" != "GET" ]; then _debug data "$data" diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index dfc838ae..9c032fd7 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -193,10 +193,10 @@ _rest() { hmac=$(printf "%s" "$sec" | _digest md5 hex) _debug hmac "$hmac" - _H1="API-KEY: $CX_Key" - _H2="API-REQUEST-DATE: $cdate" - _H3="API-HMAC: $hmac" - _H4="Content-Type: application/json" + export _H1="API-KEY: $CX_Key" + export _H2="API-REQUEST-DATE: $cdate" + export _H3="API-HMAC: $hmac" + export _H4="Content-Type: application/json" if [ "$data" ]; then response="$(_post "$data" "$url" "" "$m")" diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 81000561..1abeeacf 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -98,8 +98,8 @@ _gd_rest() { data="$3" _debug "$ep" - _H1="Authorization: sso-key $GD_Key:$GD_Secret" - _H2="Content-Type: application/json" + export _H1="Authorization: sso-key $GD_Key:$GD_Secret" + export _H2="Content-Type: application/json" if [ "$data" ]; then _debug data "$data" diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index a84d95d7..6d1f34c5 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -46,7 +46,7 @@ _ISPC_credentials() { _saveaccountconf ISPC_Api "${ISPC_Api}" _saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}" # Set whether curl should use secure or insecure mode - HTTPS_INSECURE="${ISPC_Api_Insecure}" + export HTTPS_INSECURE="${ISPC_Api_Insecure}" fi } diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 0398bd2e..c38ff3e3 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -2,7 +2,7 @@ # dns api wrapper of lexicon for acme.sh -lexicon_url="https://github.com/AnalogJ/lexicon" +# https://github.com/AnalogJ/lexicon lexicon_cmd="lexicon" wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index bc06b3ef..47f4497a 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -125,8 +125,8 @@ _LUA_rest() { data="$3" _debug "$ep" - _H1="Accept: application/json" - _H2="Authorization: Basic $LUA_auth" + export _H1="Accept: application/json" + export _H2="Authorization: Basic $LUA_auth" if [ "$data" ]; then _debug data "$data" response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index c94a3c90..9fe6baf8 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -126,9 +126,9 @@ _me_rest() { cdate=$(date -u +"%a, %d %b %Y %T %Z") hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(_hex "$ME_Secret")" hex) - _H1="x-dnsme-apiKey: $ME_Key" - _H2="x-dnsme-requestDate: $cdate" - _H3="x-dnsme-hmac: $hmac" + export _H1="x-dnsme-apiKey: $ME_Key" + export _H2="x-dnsme-requestDate: $cdate" + export _H3="x-dnsme-hmac: $hmac" if [ "$data" ]; then _debug data "$data" diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 18b9c341..8833c0a1 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -273,12 +273,12 @@ _ovh_rest() { _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" _debug2 _ovh_hex "$_ovh_hex" - _H1="X-Ovh-Application: $OVH_AK" - _H2="X-Ovh-Signature: \$1\$$_ovh_hex" + export _H1="X-Ovh-Application: $OVH_AK" + export _H2="X-Ovh-Signature: \$1\$$_ovh_hex" _debug2 _H2 "$_H2" - _H3="X-Ovh-Timestamp: $_ovh_t" - _H4="X-Ovh-Consumer: $OVH_CK" - _H5="Content-Type: application/json;charset=utf-8" + export _H3="X-Ovh-Timestamp: $_ovh_t" + export _H4="X-Ovh-Consumer: $OVH_CK" + export _H5="Content-Type: application/json;charset=utf-8" if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then _debug data "$data" response="$(_post "$data" "$_ovh_url" "" "$m")" diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 06763d88..ebc02949 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -165,7 +165,7 @@ _pdns_rest() { ep=$2 data=$3 - _H1="X-API-Key: $PDNS_Token" + export _H1="X-API-Key: $PDNS_Token" if [ ! "$method" = "GET" ]; then _debug data "$data" From 2f4b84c0743cb81d2a2f5a868da9e237777d7022 Mon Sep 17 00:00:00 2001 From: Bastian Bittorf Date: Fri, 13 Jan 2017 15:31:10 +0100 Subject: [PATCH 0622/1348] travis: use only POSIX constructs here, avoid bashisms e.g. [[ ]] -> [ ] and 'which' -> command -V Although this is not strictly needed, it keeps the project uniformly POSIX. Signed-off-by: Bastian Bittorf --- .travis.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1fff02e5..8d6d30ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ addons: - shellcheck install: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then brew update && brew install openssl; brew info openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; @@ -35,17 +35,17 @@ install: script: - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - - which openssl && openssl version - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi + - command -V openssl && openssl version + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then chmod +x ~/shfmt ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi matrix: From 38f2334360301396cd2baa6dd3eb899fd01cb00a Mon Sep 17 00:00:00 2001 From: Philipp Grosswiler Date: Mon, 16 Jan 2017 15:42:17 +0700 Subject: [PATCH 0623/1348] Added support for Linode DNS API. --- README.md | 1 + dnsapi/README.md | 19 ++++++++++++++ dnsapi/dns_linode.sh | 60 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100755 dnsapi/dns_linode.sh diff --git a/README.md b/README.md index 9b5891c9..ea0e0de7 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,7 @@ You don't have to do anything manually! 1. aliyun.com(阿里云) API 1. ISPConfig 3.1 API 1. Alwaysdata.com API +1. Linode.com API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index e32b4655..1895d376 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -257,6 +257,25 @@ acme.sh --issue --dns dns_ad -d example.com -d www.example.com The `AD_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 14. Use Linode domain API + +You will need to install the Linode CLI and set it up accordingly. + +[https://www.linode.com/docs/platform/linode-cli](https://www.linode.com/docs/platform/linode-cli) + +Follow the installation instructions appropriate for your platform and then run the configuration. + +```linode configure +``` + +Make sure Linode CLI is working correctly before proceeding. + +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. + +```sh +acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh new file mode 100755 index 00000000..0af1ad7c --- /dev/null +++ b/dnsapi/dns_linode.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +linode_cmd="/usr/bin/linode" + +######## Public functions ##################### + +#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_linode_add() { + fulldomain="${1}" + txtvalue="${2}" + + _info "Using Linode" + _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" + + domain=$(printf "%s" "${fulldomain}" | cut -d . -f 3-999) + name=$(printf "%s" "${fulldomain}" | cut -d . -f 1-2) + _debug name "${name}" + _debug domain "${domain}" + + _Linode_CLI && _Linode_addTXT +} + +#Usage: dns_linode_rm _acme-challenge.www.domain.com +dns_linode_rm() { + fulldomain="${1}" + + _info "Using Linode" + _debug "Calling: dns_linode_rm() '${fulldomain}'" + + domain=$(printf "%s" "${fulldomain}" | cut -d . -f 3-999) + name=$(printf "%s" "${fulldomain}" | cut -d . -f 1-2) + _debug name "${name}" + _debug domain "${domain}" + + _Linode_CLI && _Linode_rmTXT +} + +#################### Private functions below ################################## + +_Linode_CLI() { + if [ ! -f "${linode_cmd}" ]; then + _err "Please install the Linode CLI package and set it up accordingly before using this DNS API." + return 1 + fi +} + +_Linode_addTXT() { + _debug "$linode_cmd domain record-update ${domain} TXT ${name} --target ${txtvalue}" + $linode_cmd domain record-update ${domain} TXT ${name} --target ${txtvalue} + + if [ $? -ne 0 ]; then + _debug "$linode_cmd domain record-create ${domain} TXT ${name} ${txtvalue}" + $linode_cmd domain record-create ${domain} TXT ${name} ${txtvalue} + fi +} + +_Linode_rmTXT() { + _debug "$linode_cmd domain record-delete ${domain} TXT ${name}" + $linode_cmd domain record-delete ${domain} TXT ${name} +} From 27dbe77fad0e59ad9bce55df8d165ca512be0c65 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 16 Jan 2017 22:31:24 +0800 Subject: [PATCH 0624/1348] add "--config-home" --- acme.sh | 110 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 36 deletions(-) diff --git a/acme.sh b/acme.sh index 6eace3fd..0cbae7ba 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.5 +VER=2.6.6 PROJECT_NAME="acme.sh" @@ -1634,7 +1634,11 @@ __initHome() { fi export LE_WORKING_DIR - _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" + if [ -z "$CONFIG_HOME" ]; then + CONFIG_HOME="$LE_WORKING_DIR" + fi + + _DEFAULT_ACCOUNT_CONF_PATH="$CONFIG_HOME/account.conf" if [ -z "$ACCOUNT_CONF_PATH" ]; then if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then @@ -1646,12 +1650,12 @@ __initHome() { ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi - DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log" + DEFAULT_LOG_FILE="$CONFIG_HOME/$PROJECT_NAME.log" - DEFAULT_CA_HOME="$LE_WORKING_DIR/ca" + DEFAULT_CA_HOME="$CONFIG_HOME/ca" if [ -z "$LE_TEMP_DIR" ]; then - LE_TEMP_DIR="$LE_WORKING_DIR/tmp" + LE_TEMP_DIR="$CONFIG_HOME/tmp" fi } @@ -1703,7 +1707,7 @@ _initpath() { fi if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then - APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR" + APACHE_CONF_BACKUP_DIR="$CONFIG_HOME" fi if [ -z "$USER_AGENT" ]; then @@ -1711,7 +1715,7 @@ _initpath() { fi if [ -z "$HTTP_HEADER" ]; then - HTTP_HEADER="$LE_WORKING_DIR/http.header" + HTTP_HEADER="$CONFIG_HOME/http.header" fi _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" @@ -1727,7 +1731,7 @@ _initpath() { ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" fi - _DEFAULT_CERT_HOME="$LE_WORKING_DIR" + _DEFAULT_CERT_HOME="$CONFIG_HOME" if [ -z "$CERT_HOME" ]; then CERT_HOME="$_DEFAULT_CERT_HOME" fi @@ -3350,7 +3354,9 @@ _installcert() { } +#confighome installcronjob() { + _c_home="$1" _initpath if ! _exists "crontab"; then _err "crontab doesn't exist, so, we can not install cron jobs." @@ -3367,15 +3373,20 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi + + if [ "$_c_home" ]; then + _c_entry="--config-home \"$_c_home\"" + fi + if _exists uname && uname -a | grep SunOS >/dev/null; then crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry > /dev/null" } | crontab -- else crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry > /dev/null" } | crontab - fi fi @@ -3401,6 +3412,10 @@ uninstallcronjob() { fi LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" + if _contains "$cr" "--config-home"; then + CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" + _debug CONFIG_HOME "$CONFIG_HOME" + fi fi _initpath @@ -3664,7 +3679,9 @@ _setShebang() { rm -f "$_file.tmp" } +#confighome _installalias() { + _c_home="$1" _initpath _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" @@ -3674,8 +3691,12 @@ _installalias() { echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile" fi + if [ "$_c_home" ]; then + _c_entry="--config-home '$_c_home'" + fi + _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" - _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _profile="$(_detect_profile)" if [ "$_profile" ]; then @@ -3693,7 +3714,7 @@ _installalias() { if [ -f "$_csh_profile" ]; then _info "Installing alias to '$_csh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _setopt "$_csh_profile" "source \"$_cshfile\"" fi @@ -3702,13 +3723,13 @@ _installalias() { if [ -f "$_tcsh_profile" ]; then _info "Installing alias to '$_tcsh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _setopt "$_tcsh_profile" "source \"$_cshfile\"" fi } -# nocron +# nocron confighome install() { if [ -z "$LE_WORKING_DIR" ]; then @@ -3716,6 +3737,7 @@ install() { fi _nocron="$1" + _c_home="$2" if ! _initpath; then _err "Install failed." return 1 @@ -3754,6 +3776,13 @@ install() { chmod 700 "$LE_WORKING_DIR" + if ! mkdir -p "$CONFIG_HOME"; then + _err "Can not create config dir: $CONFIG_HOME" + return 1 + fi + + chmod 700 "$CONFIG_HOME" + cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" if [ "$?" != "0" ]; then @@ -3763,7 +3792,7 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" - _installalias + _installalias "$_c_home" for subf in $_SUB_FOLDERS; do if [ -d "$subf" ]; then @@ -3789,7 +3818,7 @@ install() { fi if [ -z "$_nocron" ]; then - installcronjob + installcronjob "$_c_home" fi if [ -z "$NO_DETECT_SH" ]; then @@ -3822,7 +3851,7 @@ uninstall() { _uninstallalias rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY" - _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." + _info "The keys and certs are in \"$(__green "$CONFIG_HOME")\", you can remove them by yourself." } @@ -3895,18 +3924,18 @@ Commands: --issue Issue a cert. --signcsr Issue a cert from an existing csr. --deploy Deploy the cert to your server. - --installcert Install the issued cert to apache/nginx or any other server. + --install-cert Install the issued cert to apache/nginx or any other server. --renew, -r Renew a cert. - --renewAll Renew all the certs. + --renew-all Renew all the certs. --revoke Revoke a cert. --list List all the certs. --showcsr Show the content of a csr. - --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. - --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically. + --install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. + --uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically. --cron Run cron job to renew all the certs. --toPkcs Export the certificate and key to a pfx file. - --updateaccount Update account info. - --registeraccount Register account key. + --update-account Update account info. + --register-account Register account key. --createAccountKey, -cak Create an account private key, professional use. --createDomainKey, -cdk Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. @@ -3941,7 +3970,8 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME . - --certhome Specifies the home dir to save all the certs, only valid for '--install' command. + --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. + --config-home Specifies the home dir to save all the configurations. --useragent Specifies the user agent string. it will be saved for future use too. --accountemail Specifies the account email for registering, Only valid for the '--install' command. --accountkey Specifies the account key path, Only valid for the '--install' command. @@ -3950,11 +3980,11 @@ Parameters: --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 '--renewall' 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. --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate. --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 '--installcert', '--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. --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. @@ -4063,6 +4093,7 @@ _process() { _accountemail="" _accountkey="" _certhome="" + _confighome="" _httpport="" _tlsport="" _dnssleep="" @@ -4117,13 +4148,13 @@ _process() { --showcsr) _CMD="showcsr" ;; - --installcert | -i) + --installcert | -i|--install-cert) _CMD="installcert" ;; --renew | -r) _CMD="renew" ;; - --renewAll | --renewall) + --renewAll | --renewall|--renew-all) _CMD="renewAll" ;; --revoke) @@ -4132,10 +4163,10 @@ _process() { --list) _CMD="list" ;; - --installcronjob) + --installcronjob|--install-cronjob) _CMD="installcronjob" ;; - --uninstallcronjob) + --uninstallcronjob|--install-cronjob) _CMD="uninstallcronjob" ;; --cron) @@ -4156,10 +4187,10 @@ _process() { --deactivate) _CMD="deactivate" ;; - --updateaccount) + --updateaccount|--update-account) _CMD="updateaccount" ;; - --registeraccount) + --registeraccount|--register-account) _CMD="registeraccount" ;; --domain | -d) @@ -4301,11 +4332,16 @@ _process() { LE_WORKING_DIR="$2" shift ;; - --certhome) + --certhome|--cert-home) _certhome="$2" CERT_HOME="$_certhome" shift ;; + --config-home) + _confighome="$2" + CONFIG_HOME="$_confighome" + shift + ;; --useragent) _useragent="$2" USER_AGENT="$_useragent" @@ -4456,7 +4492,7 @@ _process() { fi case "${_CMD}" in - install) install "$_nocron" ;; + install) install "$_nocron" "$_confighome" ;; uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) @@ -4495,7 +4531,7 @@ _process() { list) list "$_listraw" ;; - installcronjob) installcronjob ;; + installcronjob) installcronjob "$_confighome" ;; uninstallcronjob) uninstallcronjob ;; cron) cron ;; toPkcs) @@ -4512,7 +4548,9 @@ _process() { ;; *) - _err "Invalid command: $_CMD" + if [ "$_CMD" ]; then + _err "Invalid command: $_CMD" + fi showhelp return 1 ;; From 80941f84137c45014da23d7e3db17e3d267305c9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 16 Jan 2017 22:36:13 +0800 Subject: [PATCH 0625/1348] minor --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 0cbae7ba..07500eed 100755 --- a/acme.sh +++ b/acme.sh @@ -3375,18 +3375,18 @@ installcronjob() { fi if [ "$_c_home" ]; then - _c_entry="--config-home \"$_c_home\"" + _c_entry="--config-home \"$_c_home\" " fi if _exists uname && uname -a | grep SunOS >/dev/null; then crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry > /dev/null" + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" } | crontab -- else crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry > /dev/null" + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" } | crontab - fi fi From ee20015d4460b2b9bd5647f9e3d4e5f9bd1dbc6d Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 17 Jan 2017 13:04:02 +0800 Subject: [PATCH 0626/1348] fix format --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 07500eed..b58a3f47 100755 --- a/acme.sh +++ b/acme.sh @@ -4148,7 +4148,7 @@ _process() { --showcsr) _CMD="showcsr" ;; - --installcert | -i|--install-cert) + --installcert | -i| --install-cert) _CMD="installcert" ;; --renew | -r) @@ -4163,10 +4163,10 @@ _process() { --list) _CMD="list" ;; - --installcronjob|--install-cronjob) + --installcronjob | --install-cronjob) _CMD="installcronjob" ;; - --uninstallcronjob|--install-cronjob) + --uninstallcronjob|--uninstall-cronjob) _CMD="uninstallcronjob" ;; --cron) @@ -4187,10 +4187,10 @@ _process() { --deactivate) _CMD="deactivate" ;; - --updateaccount|--update-account) + --updateaccount | --update-account) _CMD="updateaccount" ;; - --registeraccount|--register-account) + --registeraccount | --register-account) _CMD="registeraccount" ;; --domain | -d) @@ -4332,7 +4332,7 @@ _process() { LE_WORKING_DIR="$2" shift ;; - --certhome|--cert-home) + --certhome | --cert-home) _certhome="$2" CERT_HOME="$_certhome" shift From db7e4bf9405c55e2361a8f2140c60b092c6c1d3c Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 17 Jan 2017 13:06:44 +0800 Subject: [PATCH 0627/1348] fix format --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b58a3f47..c24b019d 100755 --- a/acme.sh +++ b/acme.sh @@ -4148,13 +4148,13 @@ _process() { --showcsr) _CMD="showcsr" ;; - --installcert | -i| --install-cert) + --installcert | -i | --install-cert) _CMD="installcert" ;; --renew | -r) _CMD="renew" ;; - --renewAll | --renewall|--renew-all) + --renewAll | --renewall | --renew-all) _CMD="renewAll" ;; --revoke) @@ -4166,7 +4166,7 @@ _process() { --installcronjob | --install-cronjob) _CMD="installcronjob" ;; - --uninstallcronjob|--uninstall-cronjob) + --uninstallcronjob | --uninstall-cronjob) _CMD="uninstallcronjob" ;; --cron) From 2aff36e74b4cf406bbd74ecf80dca64a0aef8d10 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 17 Jan 2017 20:13:15 +0800 Subject: [PATCH 0628/1348] fix comma in domain --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 6eace3fd..66abd882 100755 --- a/acme.sh +++ b/acme.sh @@ -2391,6 +2391,10 @@ issue() { Le_Webroot="$1" Le_Domain="$2" Le_Alt="$3" + if _contains "$Le_Domain" ","; then + Le_Domain=$(echo "$2,$3" | cut -d , -f 1) + Le_Alt=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") + fi Le_Keylength="$4" Le_RealCertPath="$5" Le_RealKeyPath="$6" From 32b3717c32196dea163e87b40d428774fded5c25 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 17 Jan 2017 21:49:02 +0800 Subject: [PATCH 0629/1348] random minute --- acme.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 66abd882..49f3c3fd 100755 --- a/acme.sh +++ b/acme.sh @@ -3371,15 +3371,18 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi + + _t=$(_time) + random_minute=$(_math $_t % 60) if _exists uname && uname -a | grep SunOS >/dev/null; then crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" } | crontab -- else crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" } | crontab - fi fi From 0f21537f148e0522d305713b66677de387d95b28 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 17 Jan 2017 22:01:36 +0800 Subject: [PATCH 0630/1348] format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 49f3c3fd..0ee1eeee 100755 --- a/acme.sh +++ b/acme.sh @@ -3371,7 +3371,7 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi - + _t=$(_time) random_minute=$(_math $_t % 60) if _exists uname && uname -a | grep SunOS >/dev/null; then From f5b546b3c8c437b2e43406ac15df575e34210a9b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Jan 2017 11:28:10 +0800 Subject: [PATCH 0631/1348] rename to LE_CONFIG_HOME --- acme.sh | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/acme.sh b/acme.sh index b9da2f46..33fd6201 100755 --- a/acme.sh +++ b/acme.sh @@ -1634,11 +1634,13 @@ __initHome() { fi export LE_WORKING_DIR - if [ -z "$CONFIG_HOME" ]; then - CONFIG_HOME="$LE_WORKING_DIR" + if [ -z "$LE_CONFIG_HOME" ]; then + LE_CONFIG_HOME="$LE_WORKING_DIR" fi + _debug "Using config home:$LE_CONFIG_HOME" + export LE_CONFIG_HOME - _DEFAULT_ACCOUNT_CONF_PATH="$CONFIG_HOME/account.conf" + _DEFAULT_ACCOUNT_CONF_PATH="$LE_CONFIG_HOME/account.conf" if [ -z "$ACCOUNT_CONF_PATH" ]; then if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then @@ -1650,12 +1652,12 @@ __initHome() { ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi - DEFAULT_LOG_FILE="$CONFIG_HOME/$PROJECT_NAME.log" + DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log" - DEFAULT_CA_HOME="$CONFIG_HOME/ca" + DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca" if [ -z "$LE_TEMP_DIR" ]; then - LE_TEMP_DIR="$CONFIG_HOME/tmp" + LE_TEMP_DIR="$LE_CONFIG_HOME/tmp" fi } @@ -1707,7 +1709,7 @@ _initpath() { fi if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then - APACHE_CONF_BACKUP_DIR="$CONFIG_HOME" + APACHE_CONF_BACKUP_DIR="$LE_CONFIG_HOME" fi if [ -z "$USER_AGENT" ]; then @@ -1715,7 +1717,7 @@ _initpath() { fi if [ -z "$HTTP_HEADER" ]; then - HTTP_HEADER="$CONFIG_HOME/http.header" + HTTP_HEADER="$LE_CONFIG_HOME/http.header" fi _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" @@ -1731,7 +1733,7 @@ _initpath() { ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" fi - _DEFAULT_CERT_HOME="$CONFIG_HOME" + _DEFAULT_CERT_HOME="$LE_CONFIG_HOME" if [ -z "$CERT_HOME" ]; then CERT_HOME="$_DEFAULT_CERT_HOME" fi @@ -3418,8 +3420,8 @@ uninstallcronjob() { LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" if _contains "$cr" "--config-home"; then - CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" - _debug CONFIG_HOME "$CONFIG_HOME" + LE_CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" + _debug LE_CONFIG_HOME "$LE_CONFIG_HOME" fi fi _initpath @@ -3701,6 +3703,9 @@ _installalias() { fi _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" + fi _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _profile="$(_detect_profile)" @@ -3719,6 +3724,9 @@ _installalias() { if [ -f "$_csh_profile" ]; then _info "Installing alias to '$_csh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" + fi _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _setopt "$_csh_profile" "source \"$_cshfile\"" fi @@ -3728,6 +3736,9 @@ _installalias() { if [ -f "$_tcsh_profile" ]; then _info "Installing alias to '$_tcsh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" + fi _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _setopt "$_tcsh_profile" "source \"$_cshfile\"" fi @@ -3781,12 +3792,12 @@ install() { chmod 700 "$LE_WORKING_DIR" - if ! mkdir -p "$CONFIG_HOME"; then - _err "Can not create config dir: $CONFIG_HOME" + if ! mkdir -p "$LE_CONFIG_HOME"; then + _err "Can not create config dir: $LE_CONFIG_HOME" return 1 fi - chmod 700 "$CONFIG_HOME" + chmod 700 "$LE_CONFIG_HOME" cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" @@ -3856,7 +3867,7 @@ uninstall() { _uninstallalias rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY" - _info "The keys and certs are in \"$(__green "$CONFIG_HOME")\", you can remove them by yourself." + _info "The keys and certs are in \"$(__green "$LE_CONFIG_HOME")\", you can remove them by yourself." } @@ -4344,7 +4355,7 @@ _process() { ;; --config-home) _confighome="$2" - CONFIG_HOME="$_confighome" + LE_CONFIG_HOME="$_confighome" shift ;; --useragent) From be83a6a37ac7cfba048db5e06b04b9486ebf1fd5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Jan 2017 12:40:43 +0800 Subject: [PATCH 0632/1348] minor, fix alias --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 33fd6201..d9cd0228 100755 --- a/acme.sh +++ b/acme.sh @@ -3699,14 +3699,14 @@ _installalias() { fi if [ "$_c_home" ]; then - _c_entry="--config-home '$_c_home'" + _c_entry=" --config-home '$_c_home'" fi _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" if [ "$_c_home" ]; then _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" fi - _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" + _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" _profile="$(_detect_profile)" if [ "$_profile" ]; then @@ -3727,7 +3727,7 @@ _installalias() { if [ "$_c_home" ]; then _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" fi - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" _setopt "$_csh_profile" "source \"$_cshfile\"" fi @@ -3739,7 +3739,7 @@ _installalias() { if [ "$_c_home" ]; then _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" fi - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" _setopt "$_tcsh_profile" "source \"$_cshfile\"" fi From 78f0201dfafede2ef68a5776ab5f80a6d196d3af Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Jan 2017 13:32:12 +0800 Subject: [PATCH 0633/1348] add --remove --- acme.sh | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d9cd0228..2dc16e5a 100755 --- a/acme.sh +++ b/acme.sh @@ -3431,7 +3431,7 @@ uninstallcronjob() { revoke() { Le_Domain="$1" if [ -z "$Le_Domain" ]; then - _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com" + _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com [--ecc]" return 1 fi @@ -3489,6 +3489,37 @@ revoke() { return 1 } +#domain ecc +remove() { + Le_Domain="$1" + if [ -z "$Le_Domain" ]; then + _usage "Usage: $PROJECT_ENTRY --remove -d domain.com [--ecc]" + return 1 + fi + + _isEcc="$2" + + _initpath "$Le_Domain" "$_isEcc" + _removed_conf="$DOMAIN_CONF.removed" + if [ ! -f "$DOMAIN_CONF" ]; then + if [ -f "$_removed_conf" ]; then + _err "$Le_Domain is already removed, You can remove the folder by yourself: $DOMAIN_PATH" + else + _err "$Le_Domain is not a issued domain, skip." + fi + return 1 + fi + + if mv "$DOMAIN_CONF" "$_removed_conf"; then + _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH )" + _info "You can remove them by yourself." + return 0 + else + _err "Remove $Le_Domain failed." + return 1 + fi +} + #domain vtype _deactivate() { _d_domain="$1" @@ -3944,6 +3975,7 @@ Commands: --renew, -r Renew a cert. --renew-all Renew all the certs. --revoke Revoke a cert. + --remove Remove the cert from $PROJECT --list List all the certs. --showcsr Show the content of a csr. --install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. @@ -4176,6 +4208,9 @@ _process() { --revoke) _CMD="revoke" ;; + --remove) + _CMD="remove" + ;; --list) _CMD="list" ;; @@ -4535,6 +4570,9 @@ _process() { revoke) revoke "$_domain" "$_ecc" ;; + remove) + remove "$_domain" "$_ecc" + ;; deactivate) deactivate "$_domain,$_altdomains" ;; From 68aea3af9e87d40df689dca19c5a97cd4c5b25bc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Jan 2017 14:19:01 +0800 Subject: [PATCH 0634/1348] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2dc16e5a..35b0cc7a 100755 --- a/acme.sh +++ b/acme.sh @@ -3511,7 +3511,7 @@ remove() { fi if mv "$DOMAIN_CONF" "$_removed_conf"; then - _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH )" + _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH)" _info "You can remove them by yourself." return 0 else From 25555b8c3ead26d7fb58ac8519f73efc61b786f6 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 22 Jan 2017 18:11:32 +0800 Subject: [PATCH 0635/1348] pass the paths to reload cmd --- acme.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 35b0cc7a..33599448 100755 --- a/acme.sh +++ b/acme.sh @@ -3349,9 +3349,14 @@ _installcert() { fi if [ "$Le_ReloadCmd" ]; then - _info "Run Le_ReloadCmd: $Le_ReloadCmd" - if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd"); then + if ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" + ); then _info "$(__green "Reload success")" else _err "Reload error for :$Le_Domain" From 839bf0e2c9ccf97e6acc8a6cccc0c3d5b2e5600f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 22 Jan 2017 18:48:21 +0800 Subject: [PATCH 0636/1348] fix format --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 33599448..7ec84e6f 100755 --- a/acme.sh +++ b/acme.sh @@ -3351,12 +3351,12 @@ _installcert() { if [ "$Le_ReloadCmd" ]; then _info "Run Le_ReloadCmd: $Le_ReloadCmd" if ( - export CERT_PATH - export CERT_KEY_PATH - export CA_CERT_PATH - export CERT_FULLCHAIN_PATH - cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" - ); then + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" + ); then _info "$(__green "Reload success")" else _err "Reload error for :$Le_Domain" From 11927a768eca90138dd123391d7a55cece468b85 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 29 Jan 2017 11:47:04 +0800 Subject: [PATCH 0637/1348] minor, rename --- acme.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 7ec84e6f..eb3164f1 100755 --- a/acme.sh +++ b/acme.sh @@ -868,7 +868,7 @@ createCSR() { } -_urlencode() { +_url_replace() { tr '/+' '_-' | tr -d '= ' } @@ -935,7 +935,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' @@ -990,14 +990,14 @@ _calcjwk() { x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")" _debug3 x "$x" - x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _urlencode)" + x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _url_replace)" _debug3 x64 "$x64" xend=$(_math "$xend" + 1) y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)" _debug3 y "$y" - y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _urlencode)" + y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)" _debug3 y64 "$y64" jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' @@ -1241,7 +1241,7 @@ _send_signed_request() { return 1 fi - payload64=$(printf "%s" "$payload" | _base64 | _urlencode) + payload64=$(printf "%s" "$payload" | _base64 | _url_replace) _debug3 payload64 "$payload64" if [ -z "$_CACHED_NONCE" ]; then @@ -1267,7 +1267,7 @@ _send_signed_request() { protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" - protected64="$(printf "%s" "$protected" | _base64 | _urlencode)" + protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" _debug3 protected64 "$protected64" if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then @@ -1276,7 +1276,7 @@ _send_signed_request() { fi _debug3 _sig_t "$_sig_t" - sig="$(printf "%s" "$_sig_t" | _urlencode)" + sig="$(printf "%s" "$_sig_t" | _url_replace)" _debug3 sig "$sig" body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" @@ -2005,7 +2005,7 @@ _clearupdns() { keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) vtype=$(echo "$ventry" | cut -d "$sep" -f 4) _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)" + txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." @@ -2549,7 +2549,7 @@ issue() { if [ -z "$thumbprint" ]; then accountkey_json=$(printf "%s" "$jwk" | tr -d ' ') - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) + thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _url_replace) fi entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" @@ -2600,7 +2600,7 @@ issue() { dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" - txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)" + txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" d_api="$(_findHook "$d" dnsapi "$_currentRoot")" @@ -2875,7 +2875,7 @@ issue() { _clearup _info "Verify finished, start to sign." - der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)" + der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." @@ -3453,7 +3453,7 @@ revoke() { return 1 fi - cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _urlencode)" + cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)" if [ -z "$cert" ]; then _err "Cert for $Le_Domain is empty found, skip." From 542d7977db1479f9383561ae1657dcfb2ecfcb2c Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 30 Jan 2017 12:07:50 +0800 Subject: [PATCH 0638/1348] add new _url_encode --- acme.sh | 248 ++++++++++++++++++++++++++++++++++++++++++++-- dnsapi/dns_ali.sh | 2 +- dnsapi/dns_aws.sh | 2 +- dnsapi/dns_me.sh | 2 +- 4 files changed, 242 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index eb3164f1..22d49351 100755 --- a/acme.sh +++ b/acme.sh @@ -336,15 +336,245 @@ _h2b() { done } -#hex string -_hex() { - _str="$1" - _str_len=${#_str} - _h_i=1 - while [ "$_h_i" -le "$_str_len" ]; do - _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" - printf "%02x" "'$_str_c" - _h_i="$(_math "$_h_i" + 1)" +_is_solaris() { + _contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS" +} + +#stdin output hexstr splited by one space +#input:"abc" +#output: " 61 62 63" +_hex_dump() { + if _is_solaris; then + od -A n -v -t x1 | tr -d "\r\n\t" | tr -s " " | tr -d "\n" + else + od -A n -v -t x1 | tr -d "\r\n\t" | tr -s " " | sed "s/ $//" | tr -d "\n" + fi +} + +#url encode, no-preserved chars +#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a + +#a b c d e f g h i j k l m n o p q r s t u v w x y z +#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a + +#0 1 2 3 4 5 6 7 8 9 - _ . ~ +#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e + +#stdin stdout +_url_encode() { + _hex_str=$(_hex_dump) + _debug3 "_url_encode" + _debug3 "_hex_str" "$_hex_str" + for _hex_code in $_hex_str; do + #upper case + case "${_hex_code}" in + "41" ) + printf "%s" "A" + ;; + "42" ) + printf "%s" "B" + ;; + "43" ) + printf "%s" "C" + ;; + "44" ) + printf "%s" "D" + ;; + "45" ) + printf "%s" "E" + ;; + "46" ) + printf "%s" "F" + ;; + "47" ) + printf "%s" "G" + ;; + "48" ) + printf "%s" "H" + ;; + "49" ) + printf "%s" "I" + ;; + "4a" ) + printf "%s" "J" + ;; + "4b" ) + printf "%s" "K" + ;; + "4c" ) + printf "%s" "L" + ;; + "4d" ) + printf "%s" "M" + ;; + "4e" ) + printf "%s" "N" + ;; + "4f" ) + printf "%s" "O" + ;; + "50" ) + printf "%s" "P" + ;; + "51" ) + printf "%s" "Q" + ;; + "52" ) + printf "%s" "R" + ;; + "53" ) + printf "%s" "S" + ;; + "54" ) + printf "%s" "T" + ;; + "55" ) + printf "%s" "U" + ;; + "56" ) + printf "%s" "V" + ;; + "57" ) + printf "%s" "W" + ;; + "58" ) + printf "%s" "X" + ;; + "59" ) + printf "%s" "Y" + ;; + "5a" ) + printf "%s" "Z" + ;; + + #lower case + "61" ) + printf "%s" "a" + ;; + "62" ) + printf "%s" "b" + ;; + "63" ) + printf "%s" "c" + ;; + "64" ) + printf "%s" "d" + ;; + "65" ) + printf "%s" "e" + ;; + "66" ) + printf "%s" "f" + ;; + "67" ) + printf "%s" "g" + ;; + "68" ) + printf "%s" "h" + ;; + "69" ) + printf "%s" "i" + ;; + "6a" ) + printf "%s" "j" + ;; + "6b" ) + printf "%s" "k" + ;; + "6c" ) + printf "%s" "l" + ;; + "6d" ) + printf "%s" "m" + ;; + "6e" ) + printf "%s" "n" + ;; + "6f" ) + printf "%s" "o" + ;; + "70" ) + printf "%s" "p" + ;; + "71" ) + printf "%s" "q" + ;; + "72" ) + printf "%s" "r" + ;; + "73" ) + printf "%s" "s" + ;; + "74" ) + printf "%s" "t" + ;; + "75" ) + printf "%s" "u" + ;; + "76" ) + printf "%s" "v" + ;; + "77" ) + printf "%s" "w" + ;; + "78" ) + printf "%s" "x" + ;; + "79" ) + printf "%s" "y" + ;; + "7a" ) + printf "%s" "z" + ;; + #numbers + "30" ) + printf "%s" "0" + ;; + "31" ) + printf "%s" "1" + ;; + "32" ) + printf "%s" "2" + ;; + "33" ) + printf "%s" "3" + ;; + "34" ) + printf "%s" "4" + ;; + "35" ) + printf "%s" "5" + ;; + "36" ) + printf "%s" "6" + ;; + "37" ) + printf "%s" "7" + ;; + "38" ) + printf "%s" "8" + ;; + "39" ) + printf "%s" "9" + ;; + "2d" ) + printf "%s" "-" + ;; + "5f" ) + printf "%s" "_" + ;; + "2e" ) + printf "%s" "." + ;; + "7e" ) + printf "%s" "~" + ;; + #other hex + *) + printf '%%%s' "$_hex_code" + ;; + esac done } diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 98c56f87..9b6f85c8 100644 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -67,7 +67,7 @@ _get_root() { } _ali_rest() { - signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(_hex "$Ali_Secret&")" | _base64) + signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | sed "s/ //g")" | _base64) signature=$(_ali_urlencode "$signature") url="$Ali_API?$query&Signature=$signature" diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 59ef6181..5e7b34f5 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -183,7 +183,7 @@ aws_rest() { _debug2 kSecret "$kSecret" - kSecretH="$(_hex "$kSecret")" + kSecretH="$(printf "%s" "$kSecret" | _hex_dump | sed "s/ //g")" _debug2 kSecretH "$kSecretH" kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 9fe6baf8..c6bec70d 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -124,7 +124,7 @@ _me_rest() { _debug "$ep" cdate=$(date -u +"%a, %d %b %Y %T %Z") - hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(_hex "$ME_Secret")" hex) + hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | sed "s/ //g")" hex) export _H1="x-dnsme-apiKey: $ME_Key" export _H2="x-dnsme-requestDate: $cdate" From c3b1eb0837cd5585709d32f8b337158d18bc38eb Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 30 Jan 2017 12:25:56 +0800 Subject: [PATCH 0639/1348] fix format --- acme.sh | 406 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/acme.sh b/acme.sh index 22d49351..cf82153a 100755 --- a/acme.sh +++ b/acme.sh @@ -369,211 +369,211 @@ _url_encode() { for _hex_code in $_hex_str; do #upper case case "${_hex_code}" in - "41" ) - printf "%s" "A" - ;; - "42" ) - printf "%s" "B" - ;; - "43" ) - printf "%s" "C" - ;; - "44" ) - printf "%s" "D" - ;; - "45" ) - printf "%s" "E" - ;; - "46" ) - printf "%s" "F" - ;; - "47" ) - printf "%s" "G" - ;; - "48" ) - printf "%s" "H" - ;; - "49" ) - printf "%s" "I" - ;; - "4a" ) - printf "%s" "J" - ;; - "4b" ) - printf "%s" "K" - ;; - "4c" ) - printf "%s" "L" - ;; - "4d" ) - printf "%s" "M" - ;; - "4e" ) - printf "%s" "N" - ;; - "4f" ) - printf "%s" "O" - ;; - "50" ) - printf "%s" "P" - ;; - "51" ) - printf "%s" "Q" - ;; - "52" ) - printf "%s" "R" - ;; - "53" ) - printf "%s" "S" - ;; - "54" ) - printf "%s" "T" - ;; - "55" ) - printf "%s" "U" - ;; - "56" ) - printf "%s" "V" - ;; - "57" ) - printf "%s" "W" - ;; - "58" ) - printf "%s" "X" - ;; - "59" ) - printf "%s" "Y" - ;; - "5a" ) - printf "%s" "Z" - ;; + "41") + printf "%s" "A" + ;; + "42") + printf "%s" "B" + ;; + "43") + printf "%s" "C" + ;; + "44") + printf "%s" "D" + ;; + "45") + printf "%s" "E" + ;; + "46") + printf "%s" "F" + ;; + "47") + printf "%s" "G" + ;; + "48") + printf "%s" "H" + ;; + "49") + printf "%s" "I" + ;; + "4a") + printf "%s" "J" + ;; + "4b") + printf "%s" "K" + ;; + "4c") + printf "%s" "L" + ;; + "4d") + printf "%s" "M" + ;; + "4e") + printf "%s" "N" + ;; + "4f") + printf "%s" "O" + ;; + "50") + printf "%s" "P" + ;; + "51") + printf "%s" "Q" + ;; + "52") + printf "%s" "R" + ;; + "53") + printf "%s" "S" + ;; + "54") + printf "%s" "T" + ;; + "55") + printf "%s" "U" + ;; + "56") + printf "%s" "V" + ;; + "57") + printf "%s" "W" + ;; + "58") + printf "%s" "X" + ;; + "59") + printf "%s" "Y" + ;; + "5a") + printf "%s" "Z" + ;; - #lower case - "61" ) - printf "%s" "a" - ;; - "62" ) - printf "%s" "b" - ;; - "63" ) - printf "%s" "c" - ;; - "64" ) - printf "%s" "d" - ;; - "65" ) - printf "%s" "e" - ;; - "66" ) - printf "%s" "f" - ;; - "67" ) - printf "%s" "g" - ;; - "68" ) - printf "%s" "h" - ;; - "69" ) - printf "%s" "i" - ;; - "6a" ) - printf "%s" "j" - ;; - "6b" ) - printf "%s" "k" - ;; - "6c" ) - printf "%s" "l" - ;; - "6d" ) - printf "%s" "m" - ;; - "6e" ) - printf "%s" "n" - ;; - "6f" ) - printf "%s" "o" - ;; - "70" ) - printf "%s" "p" - ;; - "71" ) - printf "%s" "q" - ;; - "72" ) - printf "%s" "r" - ;; - "73" ) - printf "%s" "s" - ;; - "74" ) - printf "%s" "t" - ;; - "75" ) - printf "%s" "u" - ;; - "76" ) - printf "%s" "v" - ;; - "77" ) - printf "%s" "w" - ;; - "78" ) - printf "%s" "x" - ;; - "79" ) - printf "%s" "y" - ;; - "7a" ) - printf "%s" "z" - ;; - #numbers - "30" ) - printf "%s" "0" - ;; - "31" ) - printf "%s" "1" - ;; - "32" ) - printf "%s" "2" - ;; - "33" ) - printf "%s" "3" - ;; - "34" ) - printf "%s" "4" - ;; - "35" ) - printf "%s" "5" - ;; - "36" ) - printf "%s" "6" - ;; - "37" ) - printf "%s" "7" - ;; - "38" ) - printf "%s" "8" - ;; - "39" ) - printf "%s" "9" - ;; - "2d" ) - printf "%s" "-" - ;; - "5f" ) - printf "%s" "_" - ;; - "2e" ) - printf "%s" "." - ;; - "7e" ) - printf "%s" "~" - ;; - #other hex + #lower case + "61") + printf "%s" "a" + ;; + "62") + printf "%s" "b" + ;; + "63") + printf "%s" "c" + ;; + "64") + printf "%s" "d" + ;; + "65") + printf "%s" "e" + ;; + "66") + printf "%s" "f" + ;; + "67") + printf "%s" "g" + ;; + "68") + printf "%s" "h" + ;; + "69") + printf "%s" "i" + ;; + "6a") + printf "%s" "j" + ;; + "6b") + printf "%s" "k" + ;; + "6c") + printf "%s" "l" + ;; + "6d") + printf "%s" "m" + ;; + "6e") + printf "%s" "n" + ;; + "6f") + printf "%s" "o" + ;; + "70") + printf "%s" "p" + ;; + "71") + printf "%s" "q" + ;; + "72") + printf "%s" "r" + ;; + "73") + printf "%s" "s" + ;; + "74") + printf "%s" "t" + ;; + "75") + printf "%s" "u" + ;; + "76") + printf "%s" "v" + ;; + "77") + printf "%s" "w" + ;; + "78") + printf "%s" "x" + ;; + "79") + printf "%s" "y" + ;; + "7a") + printf "%s" "z" + ;; + #numbers + "30") + printf "%s" "0" + ;; + "31") + printf "%s" "1" + ;; + "32") + printf "%s" "2" + ;; + "33") + printf "%s" "3" + ;; + "34") + printf "%s" "4" + ;; + "35") + printf "%s" "5" + ;; + "36") + printf "%s" "6" + ;; + "37") + printf "%s" "7" + ;; + "38") + printf "%s" "8" + ;; + "39") + printf "%s" "9" + ;; + "2d") + printf "%s" "-" + ;; + "5f") + printf "%s" "_" + ;; + "2e") + printf "%s" "." + ;; + "7e") + printf "%s" "~" + ;; + #other hex *) - printf '%%%s' "$_hex_code" - ;; + printf '%%%s' "$_hex_code" + ;; esac done } From 0899803294d2bbebda8e098b5022d3fd808049bb Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 30 Jan 2017 14:29:40 +0800 Subject: [PATCH 0640/1348] add my twitter --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9b5891c9..7b9d0025 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ It's probably the `easiest&smallest&smartest` shell script to automatically issu Wiki: https://github.com/Neilpang/acme.sh/wiki +Twitter: [@neilpangxa](https://twitter.com/neilpangxa) + + # [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) From 59182dbc97dbbf017441a46c53f6dcac837431e6 Mon Sep 17 00:00:00 2001 From: Philipp Grosswiler Date: Tue, 31 Jan 2017 10:43:30 +0700 Subject: [PATCH 0641/1348] Removed Linode CLI dependency. --- dnsapi/dns_linode.sh | 176 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 152 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 0af1ad7c..e1c32204 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -1,6 +1,13 @@ #!/usr/bin/env bash -linode_cmd="/usr/bin/linode" +#Author: Philipp Grosswiler + +#How to create the Linode API key: +#Sign into your Linode account and go to this page: https://manager.linode.com/profile/api +#Then add an API key with label ACME and copy the new key. +#export LINODE_API_KEY="..." + +LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" ######## Public functions ##################### @@ -9,52 +16,173 @@ dns_linode_add() { fulldomain="${1}" txtvalue="${2}" + if ! _Linode_API; then + return 1 + fi + _info "Using Linode" _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" - domain=$(printf "%s" "${fulldomain}" | cut -d . -f 3-999) - name=$(printf "%s" "${fulldomain}" | cut -d . -f 1-2) - _debug name "${name}" - _debug domain "${domain}" + _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" + + _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue" + + if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\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 - _Linode_CLI && _Linode_addTXT + _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}'" - domain=$(printf "%s" "${fulldomain}" | cut -d . -f 3-999) - name=$(printf "%s" "${fulldomain}" | cut -d . -f 1-2) - _debug name "${name}" - _debug domain "${domain}" + _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" + + _parameters="&DomainID=$_domain_id" + + if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + + resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" + if [ "$resource" ]; then + _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_resource_id" ]; then + _debug _resource_id "$_resource_id" - _Linode_CLI && _Linode_rmTXT + _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id" + + if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _resource_id "$_resource_id" + + if [ -z "$_resource_id" ]; then + _err "Error deleting the domain resource." + return 1 + fi + + _info "Domain resource successfully deleted." + return 0 + fi + fi + + return 1 + fi + + return 0 + fi + + return 1 } #################### Private functions below ################################## -_Linode_CLI() { - if [ ! -f "${linode_cmd}" ]; then - _err "Please install the Linode CLI package and set it up accordingly before using this DNS API." +_Linode_API() { + if [ -z "$LINODE_API_KEY" ]; then + LINODE_API_KEY="" + + _err "You didn't specify the Linode API key yet." + _err "Please create your key and try again." + return 1 fi + + _saveaccountconf LINODE_API_KEY "$LINODE_API_KEY" } -_Linode_addTXT() { - _debug "$linode_cmd domain record-update ${domain} TXT ${name} --target ${txtvalue}" - $linode_cmd domain record-update ${domain} TXT ${name} --target ${txtvalue} +#################### 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 "domain.list"; 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 - if [ $? -ne 0 ]; then - _debug "$linode_cmd domain record-create ${domain} TXT ${name} ${txtvalue}" - $linode_cmd domain record-create ${domain} TXT ${name} ${txtvalue} + hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\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 } -_Linode_rmTXT() { - _debug "$linode_cmd domain record-delete ${domain} TXT ${name}" - $linode_cmd domain record-delete ${domain} TXT ${name} -} +#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" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")" + else + response="$(_get "$LINODE_API_URL$ep$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} \ No newline at end of file From dd17ac5045a8dc7832d90644271937f4550e793e Mon Sep 17 00:00:00 2001 From: Philipp Grosswiler Date: Tue, 31 Jan 2017 10:56:34 +0700 Subject: [PATCH 0642/1348] Added instructions on how to get the Linode API key. --- dnsapi/README.md | 16 +++++++++------- dnsapi/dns_linode.sh | 7 +------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 1895d376..df728acc 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -259,23 +259,25 @@ when needed. ## 14. Use Linode domain API -You will need to install the Linode CLI and set it up accordingly. +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) -[https://www.linode.com/docs/platform/linode-cli](https://www.linode.com/docs/platform/linode-cli) +Then add an API key with label *ACME* and copy the new key. -Follow the installation instructions appropriate for your platform and then run the configuration. - -```linode configure +```sh +export LINODE_API_KEY="..." ``` -Make sure Linode CLI is working correctly before proceeding. - 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 --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. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index e1c32204..501a51af 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -1,12 +1,7 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh #Author: Philipp Grosswiler -#How to create the Linode API key: -#Sign into your Linode account and go to this page: https://manager.linode.com/profile/api -#Then add an API key with label ACME and copy the new key. -#export LINODE_API_KEY="..." - LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" ######## Public functions ##################### From bcf96608d123d2cfd0f810b0c1138e0f37a4efea Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 12:38:37 +0800 Subject: [PATCH 0643/1348] fix for solaris --- dnsapi/dns_cx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 9c032fd7..fa821f76 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -155,7 +155,7 @@ _get_root() { fi if _contains "$response" "$h."; then - seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*"'"$h"'."[^}]*}') + seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}') _debug seg "$seg" _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" From 646c0bfcb9290a98a8b835897114860e14376560 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 12:51:59 +0800 Subject: [PATCH 0644/1348] fix for solaris --- dnsapi/dns_cx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index fa821f76..2b6d5691 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -82,7 +82,7 @@ existing_records() { return 1 fi - seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*host":"'"$_sub_domain"'"[^}]*\}') + seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}') _debug seg "$seg" if [ -z "$seg" ]; then return 0 From 1c22c2f76a0a7c0b3c03c40aaba0d0c6fd7723f3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 14:04:40 +0800 Subject: [PATCH 0645/1348] fix for solaris --- dnsapi/dns_ali.sh | 2 +- dnsapi/dns_aws.sh | 2 +- dnsapi/dns_me.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 9b6f85c8..f796f076 100644 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -67,7 +67,7 @@ _get_root() { } _ali_rest() { - signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | sed "s/ //g")" | _base64) + signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64) signature=$(_ali_urlencode "$signature") url="$Ali_API?$query&Signature=$signature" diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 5e7b34f5..1308c507 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -183,7 +183,7 @@ aws_rest() { _debug2 kSecret "$kSecret" - kSecretH="$(printf "%s" "$kSecret" | _hex_dump | sed "s/ //g")" + kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" _debug2 kSecretH "$kSecretH" kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index c6bec70d..f63621d9 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -124,7 +124,7 @@ _me_rest() { _debug "$ep" cdate=$(date -u +"%a, %d %b %Y %T %Z") - hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | sed "s/ //g")" hex) + hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex) export _H1="x-dnsme-apiKey: $ME_Key" export _H2="x-dnsme-requestDate: $cdate" From c070407ab2dfd784f57188a2a34322aed020fc1b Mon Sep 17 00:00:00 2001 From: Philipp Grosswiler Date: Tue, 31 Jan 2017 13:38:16 +0700 Subject: [PATCH 0646/1348] Fixed Travis CI complaining about missing newline at end of file. --- dnsapi/dns_linode.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 501a51af..6d54e6c1 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -180,4 +180,4 @@ _rest() { fi _debug2 response "$response" return 0 -} \ No newline at end of file +} From bb6326f4d423b9fe6b6677ffb058711724376fcb Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 15:57:43 +0800 Subject: [PATCH 0647/1348] fix for solaris --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 1308c507..555bd70b 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -93,7 +93,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*?$h.<.Name>.*?<.HostedZone>")" + hostedzone="$(echo "$response" | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." From 5d833336d33ca82eb3f1634d83e21b8d805bf88b Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 18:41:32 +0800 Subject: [PATCH 0648/1348] minor --- dnsapi/dns_lua.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 47f4497a..9506929c 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -46,12 +46,12 @@ dns_lua_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l) + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l | tr -s " ") _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" if _LUA_rest POST "zones/$_domain_id/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" #todo: check if the record takes effect return 0 @@ -99,6 +99,7 @@ _get_root() { fi while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" if [ -z "$h" ]; then #not valid return 1 @@ -106,6 +107,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\""; then _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) + _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" From 05cf405cb53a2ea1bc55d29535beefaffd8dbe97 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 18:46:24 +0800 Subject: [PATCH 0649/1348] minor --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 9506929c..be77b9d9 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -46,7 +46,7 @@ dns_lua_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l | tr -s " ") + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l | tr -d " ") _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" From 53fa16d39f314a43e60b47c923cd5d854742e539 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 18:59:00 +0800 Subject: [PATCH 0650/1348] minor --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index be77b9d9..211dbb04 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -46,7 +46,7 @@ dns_lua_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l | tr -d " ") + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" From ab5c1b0a3a6843954ee959c4700f8e422c5b8002 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 19:03:29 +0800 Subject: [PATCH 0651/1348] minor --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 211dbb04..0dd97fc3 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -63,7 +63,7 @@ dns_lua_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | cut -d: -f2 | cut -d, -f1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) _debug "record_id" "$record_id" _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" From d78ba322bfbbaf93659c8b905b50431b3a7d14f4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 19:22:14 +0800 Subject: [PATCH 0652/1348] fix update --- dnsapi/dns_lua.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 0dd97fc3..42d55e84 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -66,8 +66,8 @@ dns_lua_add() { record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) _debug "record_id" "$record_id" - _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" - if [ "$?" = "0" ]; then + _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}" + if [ "$?" = "0" ] && _contains "$response" "updated_at" ; then _info "Updated!" #todo: check if the record takes effect return 0 From 5f8daeeb6d987687ac896c128c327c2096b02009 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 20:03:41 +0800 Subject: [PATCH 0653/1348] minor, a better hex_dump --- acme.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index cf82153a..e5728b3c 100755 --- a/acme.sh +++ b/acme.sh @@ -344,11 +344,7 @@ _is_solaris() { #input:"abc" #output: " 61 62 63" _hex_dump() { - if _is_solaris; then - od -A n -v -t x1 | tr -d "\r\n\t" | tr -s " " | tr -d "\n" - else - od -A n -v -t x1 | tr -d "\r\n\t" | tr -s " " | sed "s/ $//" | tr -d "\n" - fi + od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" } #url encode, no-preserved chars From 600a23514029477e794f356f4158ba36b3311a8f Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 31 Jan 2017 23:16:04 -0500 Subject: [PATCH 0654/1348] Add FreeDNS plugin --- dnsapi/dns_freedns.sh | 371 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100755 dnsapi/dns_freedns.sh diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh new file mode 100755 index 00000000..ad3f9da3 --- /dev/null +++ b/dnsapi/dns_freedns.sh @@ -0,0 +1,371 @@ +#!/usr/bin/env sh + +#This file name is "dns_freedns.sh" +#So, here must be a method dns_freedns_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. +# +#Author: David Kerr +#Report Bugs here: https://github.com/dkerr64/acme.sh +# +######## Public functions ##################### + +# Export FreeDNS userid and password in folowing variables... +# FREEDNS_User=username +# FREEDNS_Password=password +# login cookie is saved in acme account config file so userid / pw +# need to be set only when changed. + +#Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_freedns_add() { + fulldomain="$1" + txtvalue="$2" + + _info "Add TXT record using FreeDNS" + _debug "fulldomain: $fulldomain" + _debug "txtvalue: $txtvalue" + + if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then + FREEDNS_User="" + FREEDNS_Password="" + if [ -z "$FREEDNS_COOKIE" ]; then + _err "You did not specify the FreeDNS username and password yet." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + return 1 + fi + using_cached_cookies="true" + else + FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")" + if [ -z "$FREEDNS_COOKIE" ]; then + return 1 + fi + using_cached_cookies="false" + fi + + _debug "FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)" + + _saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE" + + # split our full domain name into two parts... + i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" + i="$(_math "$i" - 1)" + top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)" + i="$(_math "$i" - 1)" + sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" + + # Sometimes FreeDNS does not reurn the subdomain page but rather + # returns a page regarding becoming a premium member. This usually + # happens after a period of inactivity. Immediately trying again + # returns the correct subdomain page. So, we will try twice to + # load the page and obtain our domain ID + attempts=2 + while [ "$attempts" -gt "0" ]; do + attempts="$(_math "$attempts" - 1)" + + htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" + if [ "$?" != "0" ]; then + if [ "$using_cached_cookies" = "true" ]; then + _err "Has your FreeDNS username and password channged? If so..." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + fi + return 1 + fi + + # Now convert the tables in the HTML to CSV. This litte gem from + # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv + subdomain_csv="$(echo "$htmlpage" \ + | grep -i -e ']*>/\n/Ig' \ + | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ + | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ + | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ + | grep 'edit.php?' \ + | grep "$top_domain")" + # The above beauty ends with striping out rows that do not have an + # href to edit.php and do not have the top domain we are looking for. + # So all we should be left with is CSV of table of subdomains we are + # interested in. + + # Now we have to read through this table and extract the data we need + lines="$(echo "$subdomain_csv" | wc -l)" + nl=' +' + i=0 + found=0 + while [ "$i" -lt "$lines" ]; do + i="$(_math "$i" + 1)" + line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" + tmp="$(echo "$line" | cut -d ',' -f 1)" + if [ $found = 0 ] && _startswith "$tmp" "$top_domain"; then + # this line will contain DNSdomainid for the top_domain + DNSdomainid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')" + found=1 + else + # lines contain DNS records for all subdomains + DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" + DNStype="$(echo "$line" | cut -d ',' -f 3)" + if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then + DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" + # Now get current value for the TXT record. This method may + # not produce accurate results as the value field is truncated + # on this webpage. To get full value we would need to load + # another page. However we don't really need this so long as + # there is only one TXT record for the acme chalenge subdomain. + DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" + if [ $found != 0 ]; then + break + # we are breaking out of the loop at the first match of DNS name + # and DNS type (if we are past finding the domainid). This assumes + # that there is only ever one TXT record for the LetsEncrypt/acme + # challenge subdomain. This seems to be a reasonable assumption + # as the acme client deletes the TXT record on successful validation. + fi + else + DNSname="" + DNStype="" + fi + fi + done + + _debug "DNSname: $DNSname DNStype: $DNStype DNSdomainid: $DNSdomainid DNSdataid: $DNSdataid" + _debug "DNSvalue: $DNSvalue" + + if [ -z "$DNSdomainid" ]; then + # If domain ID is empty then something went wrong (top level + # domain not found at FreeDNS). + if [ "$attempts" = "0" ]; then + # exhausted maximum retry attempts + _debug "$htmlpage" + _debug "$subdomain_csv" + _err "Domain $top_domain not found at FreeDNS" + return 1 + fi + else + # break out of the 'retry' loop... we have found our domain ID + break + fi + _info "Domain $top_domain not found at FreeDNS" + _info "Retry loading subdomain page ($attempts attempts remaining)" + done + + if [ -z "$DNSdataid" ]; then + # If data ID is empty then specific subdomain does not exist yet, need + # to create it this should always be the case as the acme client + # deletes the entry after domain is validated. + _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" + return $? + else + if [ "$txtvalue" = "$DNSvalue" ]; then + # if value in TXT record matches value requested then DNS record + # does not need to be updated. But... + # Testing value match fails. Website is truncating the value field. + # So for now we will always go down the else path. Though in theory + # should never come here anyway as the acme client deletes + # the TXT record on successful validation, so we should not even + # have found a TXT record !! + _info "No update necessary for $fulldomain at FreeDNS" + return 0 + else + # Delete the old TXT record (with the wrong value) + _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" + if [ "$?" = "0" ]; then + # And add in new TXT record with the value provided + _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" + fi + return $? + fi + fi + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_freedns_rm() { + fulldomain="$1" + txtvalue="$2" + + _info "Delete TXT record using FreeDNS" + _debug "fulldomain: $fulldomain" + _debug "txtvalue: $txtvalue" + + # Need to read cookie from conf file again in case new value set + # during login to FreeDNS when TXT record was created. + # acme.sh does not have a _readaccountconf() fuction + FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" + _debug "FreeDNS login cookies: $FREEDNS_COOKIE" + + # Sometimes FreeDNS does not reurn the subdomain page but rather + # returns a page regarding becoming a premium member. This usually + # happens after a period of inactivity. Immediately trying again + # returns the correct subdomain page. So, we will try twice to + # load the page and obtain our TXT record. + attempts=2 + while [ "$attempts" -gt "0" ]; do + attempts="$(_math "$attempts" - 1)" + + htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" + if [ "$?" != "0" ]; then + return 1 + fi + + # Now convert the tables in the HTML to CSV. This litte gem from + # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv + subdomain_csv="$(echo "$htmlpage" \ + | grep -i -e ']*>/\n/Ig' \ + | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ + | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ + | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ + | grep 'edit.php?' \ + | grep "$fulldomain")" + # The above beauty ends with striping out rows that do not have an + # href to edit.php and do not have the domain name we are looking for. + # So all we should be left with is CSV of table of subdomains we are + # interested in. + + # Now we have to read through this table and extract the data we need + lines="$(echo "$subdomain_csv" | wc -l)" + nl=' +' + i=0 + found=0 + while [ "$i" -lt "$lines" ]; do + i="$(_math "$i" + 1)" + line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" + DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" + DNStype="$(echo "$line" | cut -d ',' -f 3)" + if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then + DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" + DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" + _debug "DNSvalue: $DNSvalue" + # if [ "$DNSvalue" = "$txtvalue" ]; then + # Testing value match fails. Website is truncating the value + # field. So for now we will assume that there is only one TXT + # field for the sub domain and just delete it. Currently this + # is a safe assumption. + _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" + return $? + # fi + fi + done + done + + # If we get this far we did not find a match (after two attempts) + # Not necessarily an error, but log anyway. + _debug2 "$subdomain_csv" + _info "Cannot delete TXT record for $fulldomain/$txtvalue. Does not exist at FreeDNS" + return 0 +} + +#################### Private functions below ################################## + +# usage: _freedns_login username password +# print string "cookie=value" etc. +# returns 0 success +_freedns_login() { + username="$1" + password="$2" + url="https://freedns.afraid.org/zc.php?step=2" + + _debug "Login to FreeDNS as user $username" + + htmlpage="$(_post "username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS login failed for user $username bad RC from _post" + return 1 + fi + + cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + + # if cookies is not empty then logon successful + if [ -z "$cookies" ]; then + _debug "$htmlpage" + _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file" + return 1 + fi + + printf "%s" "$cookies" + return 0 +} + +# usage _freedns_retrieve_subdomain_page login_cookies +# echo page retrieved (html) +# returns 0 success +_freedns_retrieve_subdomain_page() { + export _H1="Cookie:$1" + url="https://freedns.afraid.org/subdomain/" + + _debug "Retrieve subdmoain page from FreeDNS" + + htmlpage="$(_get "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS retrieve subdomins failed bad RC from _get" + return 1 + fi + + if [ -z "$htmlpage" ]; then + _err "FreeDNS returned empty subdomain page" + return 1 + fi + + _debug2 "$htmlpage" + + printf "%s" "$htmlpage" + return 0 +} + +# usage _freedns_add_txt_record login_cookies domain_id subdomain value +# returns 0 success +_freedns_add_txt_record() { + export _H1="Cookie:$1" + domain_id="$2" + subdomain="$3" + value="$(printf '%s' "$4" | _url_encode)" + url="http://freedns.afraid.org/subdomain/save.php?step=2" + + htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" + return 1 + fi + + if ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then + _debug "$htmlpage" + _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" + return 1 + fi + _info "Added acme challenge TXT record for $fulldomain at FreeDNS" + return 0 +} + +# usage _freedns_delete_txt_record login_cookies data_id +# returns 0 success +_freedns_delete_txt_record() { + export _H1="Cookie:$1" + data_id="$2" + url="https://freedns.afraid.org/subdomain/delete2.php" + + htmlheader="$(_get "$url?data_id%5B%5D=$data_id&submit=delete+selected" "onlyheader")" + + if [ "$?" != "0" ]; then + _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" + return 1 + fi + + if ! _contains "$htmlheader" "200 OK"; then + _debug "$htmlheader" + _err "FreeDNS failed to delete TXT record $data_id" + return 1 + fi + + _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS" + return 0 +} + From 1476a9ecf144b3c5a033adc533b429fe1365e9a7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 1 Feb 2017 16:12:43 +0800 Subject: [PATCH 0655/1348] fix format --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 42d55e84..828e8012 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -67,7 +67,7 @@ dns_lua_add() { _debug "record_id" "$record_id" _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}" - if [ "$?" = "0" ] && _contains "$response" "updated_at" ; then + if [ "$?" = "0" ] && _contains "$response" "updated_at"; then _info "Updated!" #todo: check if the record takes effect return 0 From 70b63a5ed442efe28587b8107c216db9e2965f70 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 1 Feb 2017 23:18:37 +0800 Subject: [PATCH 0656/1348] Create README.md --- deploy/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 deploy/README.md diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 00000000..580eaac8 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1 @@ +#Using deploy api From 0aed065a75dc3be7c906a156ebad1b30344d09ba Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 1 Feb 2017 17:08:26 -0500 Subject: [PATCH 0657/1348] Updates to README.md --- README.md | 1 + dnsapi/README.md | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/README.md b/README.md index 90a64ee0..067e9b50 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,7 @@ You don't have to do anything manually! 1. ISPConfig 3.1 API 1. Alwaysdata.com API 1. Linode.com API +1. FreeDNS **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index df728acc..9f06483e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -278,6 +278,32 @@ acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.co The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +# 15. Use FreeDNS + +FreeDNS (https://freedns.afraid.org/) does not provide an API to update DNS records (other than IPv4 and IPv6 +dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging +into the FreeDNS website to read the HTML and posting updates as HTTP. The plugin needs to know your +userid and password for the FreeDNS website. + +```sh +export FREEDNS_User="..." +export FREEDNS_Password="..." +``` + +You need only provide this the first time you run the acme.sh client with FreeDNS validation and then again +whenever you change your password at the FreeDNS site. The acme.sh FreeDNS plugin does not store your userid +or password but rather saves an authentication token returned by FreeDNS in `~/.acme.sh/account.conf` and +reuses that when needed. + +Now you can issue a certificate. + +```sh +acme.sh --issue --dns dns_freedns --dnssleep 30 -d example.com -d www.example.com +``` + +FreeDNS updates records quite quickly so it is possible to reduce the dnssleep time, in the above example +to 30 seconds. + # Use custom API If your API is not supported yet, you can write your own DNS API. From 40e6ba1100e2ed61508131873fa99225748aded4 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 1 Feb 2017 17:12:52 -0500 Subject: [PATCH 0658/1348] fix heading level to match others. --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9f06483e..65acb7d9 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -278,7 +278,7 @@ acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.co The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -# 15. Use FreeDNS +## 15. Use FreeDNS FreeDNS (https://freedns.afraid.org/) does not provide an API to update DNS records (other than IPv4 and IPv6 dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging From 6c4cc357b5ba12c5bd5682750647b198d40a8cdc Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 3 Feb 2017 11:13:38 +0800 Subject: [PATCH 0659/1348] _readlink --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 7ec84e6f..d4cbe1fd 100755 --- a/acme.sh +++ b/acme.sh @@ -1594,14 +1594,18 @@ _starttlsserver() { _readlink() { _rf="$1" if ! readlink -f "$_rf" 2>/dev/null; then - if _startswith "$_rf" "\./$PROJECT_ENTRY"; then - printf -- "%s" "$(pwd)/$PROJECT_ENTRY" + if _startswith "$_rf" "/"; then + echo "$_rf" return 0 fi - readlink "$_rf" + echo "$(pwd)/$_rf" | _conapath fi } +_conapath() { + sed "s#/\./#/#g" +} + __initHome() { if [ -z "$_SCRIPT_HOME" ]; then if _exists readlink && _exists dirname; then @@ -4440,7 +4444,7 @@ _process() { HTTPS_INSECURE="1" ;; --ca-bundle) - _ca_bundle="$(readlink -f "$2")" + _ca_bundle="$(_readlink -f "$2")" CA_BUNDLE="$_ca_bundle" shift ;; From 50a9680f17f0719450f3f1874d723d0db2c4a1fb Mon Sep 17 00:00:00 2001 From: David Kerr Date: Fri, 3 Feb 2017 11:13:12 -0500 Subject: [PATCH 0660/1348] Travis error... remove blank line at end of file. --- dnsapi/dns_freedns.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index ad3f9da3..28aaa77a 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -368,4 +368,3 @@ _freedns_delete_txt_record() { _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS" return 0 } - From e6b940e24754ede06e8b2618d50347bf8f39185b Mon Sep 17 00:00:00 2001 From: David Kerr Date: Fri, 3 Feb 2017 22:59:22 -0500 Subject: [PATCH 0661/1348] Minor edits to FreeDNS documentation --- README.md | 2 +- dnsapi/README.md | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 067e9b50..c6362ed7 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ You don't have to do anything manually! 1. ISPConfig 3.1 API 1. Alwaysdata.com API 1. Linode.com API -1. FreeDNS +1. FreeDNS (https://freedns.afraid.org/) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 65acb7d9..fc613e2a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -278,7 +278,7 @@ acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.co The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 15. Use FreeDNS +## 15. Use FreeDNS FreeDNS (https://freedns.afraid.org/) does not provide an API to update DNS records (other than IPv4 and IPv6 dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging @@ -298,12 +298,9 @@ reuses that when needed. Now you can issue a certificate. ```sh -acme.sh --issue --dns dns_freedns --dnssleep 30 -d example.com -d www.example.com +acme.sh --issue --dns dns_freedns -d example.com -d www.example.com ``` -FreeDNS updates records quite quickly so it is possible to reduce the dnssleep time, in the above example -to 30 seconds. - # Use custom API If your API is not supported yet, you can write your own DNS API. From f78b656f5f6c20bde86c10b1bfb40bf2f210d899 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 4 Feb 2017 10:21:58 -0500 Subject: [PATCH 0662/1348] Add error message if fails to add TXT record for missing security code (probably a FreeDNS public domain) --- dnsapi/README.md | 4 ++++ dnsapi/dns_freedns.sh | 19 ++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index fc613e2a..6a86bf4c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -301,6 +301,10 @@ Now you can issue a certificate. 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 +you create under a FreeDNS public domain. You must own the top level domain in order to automaitcally +validate with acme.sh at FreeDNS. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 28aaa77a..8d519fd5 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -307,9 +307,7 @@ _freedns_retrieve_subdomain_page() { if [ "$?" != "0" ]; then _err "FreeDNS retrieve subdomins failed bad RC from _get" return 1 - fi - - if [ -z "$htmlpage" ]; then + elif [ -z "$htmlpage" ]; then _err "FreeDNS returned empty subdomain page" return 1 fi @@ -334,13 +332,18 @@ _freedns_add_txt_record() { if [ "$?" != "0" ]; then _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" return 1 - fi - - if ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then + elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then _debug "$htmlpage" _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" return 1 + elif _contains "$htmlpage" "security code was incorrect"; then + _debug "$htmlpage" + _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested seurity code" + _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" + return 1 fi + + _debug2 "$htmlpage" _info "Added acme challenge TXT record for $fulldomain at FreeDNS" return 0 } @@ -357,9 +360,7 @@ _freedns_delete_txt_record() { if [ "$?" != "0" ]; then _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" return 1 - fi - - if ! _contains "$htmlheader" "200 OK"; then + elif ! _contains "$htmlheader" "200 OK"; then _debug "$htmlheader" _err "FreeDNS failed to delete TXT record $data_id" return 1 From 87f5ec5be52208c2daaf040c646bee69fdcb7771 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 4 Feb 2017 10:36:51 -0500 Subject: [PATCH 0663/1348] Add Accept-Language:en-US to HTTP header as precaution against future multi-lingual FreeDNS pages. --- dnsapi/dns_freedns.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 8d519fd5..f30c8958 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -267,6 +267,7 @@ dns_freedns_rm() { # print string "cookie=value" etc. # returns 0 success _freedns_login() { + export _H1="Accept-Language:en-US" username="$1" password="$2" url="https://freedns.afraid.org/zc.php?step=2" @@ -298,6 +299,7 @@ _freedns_login() { # returns 0 success _freedns_retrieve_subdomain_page() { export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" url="https://freedns.afraid.org/subdomain/" _debug "Retrieve subdmoain page from FreeDNS" @@ -322,6 +324,7 @@ _freedns_retrieve_subdomain_page() { # returns 0 success _freedns_add_txt_record() { export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" domain_id="$2" subdomain="$3" value="$(printf '%s' "$4" | _url_encode)" @@ -352,6 +355,7 @@ _freedns_add_txt_record() { # returns 0 success _freedns_delete_txt_record() { export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" data_id="$2" url="https://freedns.afraid.org/subdomain/delete2.php" From 989651c23be6f8fbf2d507aaae76ec5c774f2644 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 4 Feb 2017 23:17:24 -0500 Subject: [PATCH 0664/1348] Initial version --- deploy/sshdeploy.sh | 128 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 deploy/sshdeploy.sh diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh new file mode 100644 index 00000000..d33aad7a --- /dev/null +++ b/deploy/sshdeploy.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env sh + +#Here is a script to deploy certificates to remote server by ssh +#This file name is "sshdeploy.sh" +#So, here must be a method sshdeploy_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + +# The following variables exported from environment will be used. +# If not set then values previously saved in domain.conf file are used. +# +# export ACME_DEPLOY_SSH_URL="admin@qnap" +# export ACME_DEPLOY_SSH_SERVICE_STOP="/etc/init.d/stunnel.sh stop" +# export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +# export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +# export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +# export ACME_DEPLOY_SSH_FULLCHAIN="" +# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +# export ACME_DEPLOY_SSH_SERVICE_START="/etc/init.d/stunnel.sh stop" + +. "$DOMAIN_CONF" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +sshdeploy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _cmdstr="{" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if [ -z "$ACME_DEPLOY_SSH_URL" ]; then + if [ -z "$Le_Deploy_ssh_url" ]; then + _err "ACME_DEPLOY_SSH_URL not defined." + return 1 + fi + else + Le_Deploy_ssh_url="$ACME_DEPLOY_SSH_URL" + _savedomainconf Le_Deploy_ssh_url "$Le_Deploy_ssh_url" + fi + + _info "Deploy certificates to remote server $Le_Deploy_ssh_url" + + if [ -n "$ACME_DEPLOY_SSH_SERVICE_STOP" ]; then + Le_Deploy_ssh_service_stop="$ACME_DEPLOY_SSH_SERVICE_STOP" + _savedomainconf Le_Deploy_ssh_service_stop "$Le_Deploy_ssh_service_stop" + fi + if [ -n "$Le_Deploy_ssh_service_stop" ]; then + _cmdstr="$_cmdstr $Le_Deploy_ssh_service_stop ;" + _info "Will stop remote service with command $Le_Deploy_ssh_service_stop" + fi + + if [ -n "$ACME_DEPLOY_SSH_KEYFILE" ]; then + Le_Deploy_ssh_keyfile="$ACME_DEPLOY_SSH_KEYFILE" + _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" + fi + if [ -n "$Le_Deploy_ssh_keyfile" ]; then + _cmdstr="$_cmdstr echo \"$(cat $_ckey)\" > $Le_Deploy_ssh_keyfile ;" + _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" + fi + + if [ -n "$ACME_DEPLOY_SSH_CERTFILE" ]; then + Le_Deploy_ssh_certfile="$ACME_DEPLOY_SSH_CERTFILE" + _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" + fi + if [ -n "$Le_Deploy_ssh_certfile" ]; then + if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then + _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" >> $Le_Deploy_ssh_certfile ;" + _info "will append certificate to same file" + else + _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" > $Le_Deploy_ssh_certfile ;" + _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" + fi + fi + + if [ -n "$ACME_DEPLOY_SSH_CAFILE" ]; then + Le_Deploy_ssh_cafile="$ACME_DEPLOY_SSH_CAFILE" + _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" + fi + if [ -n "$Le_Deploy_ssh_cafile" ]; then + _cmdstr="$_cmdstr echo \"$(cat $_cca)\" > $Le_Deploy_ssh_cafile ;" + _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" + fi + + if [ -n "$ACME_DEPLOY_SSH_FULLCHAIN" ]; then + Le_Deploy_ssh_fullchain="$ACME_DEPLOY_SSH_FULLCHAIN" + _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" + fi + if [ -n "$Le_Deploy_ssh_fullchain" ]; then + _cmdstr="$_cmdstr echo \"$(cat $_cfullchain)\" > $Le_Deploy_ssh_fullchain ;" + _info "will copy full chain to remote file $Le_Deploy_ssh_fullchain" + fi + + if [ -n "$ACME_DEPLOY_SSH_REMOTE_CMD" ]; then + Le_Deploy_ssh_remote_cmd="$ACME_DEPLOY_SSH_REMOTE_CMD" + _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" + fi + if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then + _cmdstr="$_cmdstr sleep 2 ; $Le_Deploy_ssh_remote_cmd ;" + _info "Will sleep 2 seconds then execute remote command $Le_Deploy_ssh_remote_cmd" + fi + + if [ -n "$ACME_DEPLOY_SSH_SERVICE_START" ]; then + Le_Deploy_ssh_service_start="$ACME_DEPLOY_SSH_SERVICE_START" + _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" + fi + if [ -n "$Le_Deploy_ssh_service_start" ]; then + _cmdstr="$_cmdstr sleep 2 ; $Le_Deploy_ssh_service_start ;" + _info "Will sleep 2 seconds then start remote service with command $Le_Deploy_ssh_remote_cmd" + fi + + _cmdstr="$_cmdstr }" + + _debug "Remote command to execute: $_cmdstr" + + _info "Submitting sequence of commands to remote server by ssh" + ssh -T "$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" + + return 0 +} From 9bdb799b412bf86cddbe62d630e94a023fcc532d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Feb 2017 13:16:51 +0800 Subject: [PATCH 0665/1348] fix bug when the od command is missing --- acme.sh | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bc211522..df4a0b4a 100755 --- a/acme.sh +++ b/acme.sh @@ -340,11 +340,29 @@ _is_solaris() { _contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS" } +#_ascii_hex str +#this can only process ascii chars, should only be used when od command is missing as a backup way. +_ascii_hex() { + _debug2 "Using _ascii_hex" + _str="$1" + _str_len=${#_str} + _h_i=1 + while [ "$_h_i" -le "$_str_len" ]; do + _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" + printf " %02x" "'$_str_c" + _h_i="$(_math "$_h_i" + 1)" + done +} + #stdin output hexstr splited by one space #input:"abc" #output: " 61 62 63" _hex_dump() { - od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" + #in wired some system, the od command is missing. + if ! od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" 2>/dev/null; then + str=$(cat) + _ascii_hex "$str" + fi } #url encode, no-preserved chars From b22b085b508c745030b9ecd4ce931fca19f43455 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Feb 2017 22:08:52 +0800 Subject: [PATCH 0666/1348] fix https://github.com/Neilpang/acme.sh/issues/578 support openssl 1.1.0 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index df4a0b4a..ec41b60f 100755 --- a/acme.sh +++ b/acme.sh @@ -914,7 +914,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - $OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + $OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile From 562a4c056ea208e85e6f0551a188d55cee8050d5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Feb 2017 23:06:06 +0800 Subject: [PATCH 0667/1348] add note info if netcat-openbsd is required. --- acme.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/acme.sh b/acme.sh index ec41b60f..b22b2e69 100755 --- a/acme.sh +++ b/acme.sh @@ -61,6 +61,8 @@ DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" _DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh" +_PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations" + __INTERACTIVE="" if [ -t 1 ]; then __INTERACTIVE="1" @@ -1684,6 +1686,14 @@ _startserver() { _NC="$_NC -6" fi + if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then + if ! _contains "$nchelp" "OpenBSD"; then + _err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again." + _err "See $(__green $_PREPARE_LINK)" + return 1 + fi + fi + if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then _NC="$_NC -q 1 -l $ncaddr" else From b4325026b17374efdbcc7726369085e4373f23ef Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Feb 2017 23:14:25 +0800 Subject: [PATCH 0668/1348] exe --- deploy/kong.sh | 0 deploy/myapi.sh | 0 dnsapi/dns_ad.sh | 0 dnsapi/dns_ali.sh | 0 dnsapi/dns_aws.sh | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 deploy/kong.sh mode change 100644 => 100755 deploy/myapi.sh mode change 100644 => 100755 dnsapi/dns_ad.sh mode change 100644 => 100755 dnsapi/dns_ali.sh mode change 100644 => 100755 dnsapi/dns_aws.sh diff --git a/deploy/kong.sh b/deploy/kong.sh old mode 100644 new mode 100755 diff --git a/deploy/myapi.sh b/deploy/myapi.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh old mode 100644 new mode 100755 From 7d75ad4c56a97ae7576bcc89eb41610df1d856b5 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 14:35:05 -0500 Subject: [PATCH 0669/1348] Backup old certificates before overwriting. Add userid export parameter. And generate error if nothing to do at remote server. --- deploy/sshdeploy.sh | 104 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 22 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index d33aad7a..aa924136 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -1,22 +1,26 @@ #!/usr/bin/env sh -#Here is a script to deploy certificates to remote server by ssh -#This file name is "sshdeploy.sh" -#So, here must be a method sshdeploy_deploy() -#Which will be called by acme.sh to deploy the cert -#returns 0 means success, otherwise error. - +# Script to deploy certificates to remote server by SSH +# Note that SSH must be able to login to remote host without a password... +# SSH Keys must have been exchanged with the remote host. Validate and +# test that you can login to USER@URL from the host running acme.sh before +# using this script. +# # The following variables exported from environment will be used. # If not set then values previously saved in domain.conf file are used. # -# export ACME_DEPLOY_SSH_URL="admin@qnap" -# export ACME_DEPLOY_SSH_SERVICE_STOP="/etc/init.d/stunnel.sh stop" +# Only a username is required. All others are optional. +# +# The following examples are for QNAP NAS running QTS 4.2 +# export ACME_DEPLOY_SSH_USER="admin" +# export ACME_DEPLOY_SSH_URL="qnap" +# export ACME_DEPLOY_SSH_SERVICE_STOP="" # export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" # export ACME_DEPLOY_SSH_FULLCHAIN="" # export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -# export ACME_DEPLOY_SSH_SERVICE_START="/etc/init.d/stunnel.sh stop" +# export ACME_DEPLOY_SSH_SERVICE_START="" . "$DOMAIN_CONF" @@ -29,7 +33,9 @@ sshdeploy_deploy() { _ccert="$3" _cca="$4" _cfullchain="$5" - _cmdstr="{" + _cmdstr="" + _homedir="~/.acme_ssh_deploy" + _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" @@ -37,18 +43,29 @@ sshdeploy_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - if [ -z "$ACME_DEPLOY_SSH_URL" ]; then - if [ -z "$Le_Deploy_ssh_url" ]; then - _err "ACME_DEPLOY_SSH_URL not defined." + # USER is required to login by SSH to remote host. + if [ -z "$ACME_DEPLOY_SSH_USER" ]; then + if [ -z "$Le_Deploy_ssh_user" ]; then + _err "ACME_DEPLOY_SSH_USER not defined." return 1 fi else + Le_Deploy_ssh_user="$ACME_DEPLOY_SSH_USER" + _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user" + fi + + # URL is optional. If not provided then use _cdomain + if [ -n "$ACME_DEPLOY_SSH_URL" ]; then Le_Deploy_ssh_url="$ACME_DEPLOY_SSH_URL" _savedomainconf Le_Deploy_ssh_url "$Le_Deploy_ssh_url" + elif [ -z "$Le_Deploy_ssh_url" ]; then + Le_Deploy_ssh_url="$_cdomain" fi - _info "Deploy certificates to remote server $Le_Deploy_ssh_url" + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_url" + # SERVICE_STOP is optional. + # If provided then this command will be executed on remote host. if [ -n "$ACME_DEPLOY_SSH_SERVICE_STOP" ]; then Le_Deploy_ssh_service_stop="$ACME_DEPLOY_SSH_SERVICE_STOP" _savedomainconf Le_Deploy_ssh_service_stop "$Le_Deploy_ssh_service_stop" @@ -58,71 +75,114 @@ sshdeploy_deploy() { _info "Will stop remote service with command $Le_Deploy_ssh_service_stop" fi + # KEYFILE is optional. + # If provided then private key will be copied to provided filename. if [ -n "$ACME_DEPLOY_SSH_KEYFILE" ]; then Le_Deploy_ssh_keyfile="$ACME_DEPLOY_SSH_KEYFILE" _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" fi if [ -n "$Le_Deploy_ssh_keyfile" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" + # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat $_ckey)\" > $Le_Deploy_ssh_keyfile ;" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" fi + # CERTFILE is optional. + # If provided then private key will be copied or appended to provided filename. if [ -n "$ACME_DEPLOY_SSH_CERTFILE" ]; then Le_Deploy_ssh_certfile="$ACME_DEPLOY_SSH_CERTFILE" _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" fi if [ -n "$Le_Deploy_ssh_certfile" ]; then if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then + # if filename is same as that provided for private key then append. _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" >> $Le_Deploy_ssh_certfile ;" _info "will append certificate to same file" else + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" + # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" > $Le_Deploy_ssh_certfile ;" _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" fi fi + # CAFILE is optional. + # If provided then CA intermediate certificate will be copied to provided filename. if [ -n "$ACME_DEPLOY_SSH_CAFILE" ]; then Le_Deploy_ssh_cafile="$ACME_DEPLOY_SSH_CAFILE" _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" fi if [ -n "$Le_Deploy_ssh_cafile" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" + # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat $_cca)\" > $Le_Deploy_ssh_cafile ;" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" fi + # FULLCHAIN is optional. + # If provided then fullchain certificate will be copied to provided filename. if [ -n "$ACME_DEPLOY_SSH_FULLCHAIN" ]; then Le_Deploy_ssh_fullchain="$ACME_DEPLOY_SSH_FULLCHAIN" _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" fi if [ -n "$Le_Deploy_ssh_fullchain" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" + # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat $_cfullchain)\" > $Le_Deploy_ssh_fullchain ;" _info "will copy full chain to remote file $Le_Deploy_ssh_fullchain" fi + # REMOTE_CMD is optional. + # If provided then this command will be executed on remote host. + # A 2 second delay is inserted to allow system to stabalize after + # executing a service stop. if [ -n "$ACME_DEPLOY_SSH_REMOTE_CMD" ]; then Le_Deploy_ssh_remote_cmd="$ACME_DEPLOY_SSH_REMOTE_CMD" _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - _cmdstr="$_cmdstr sleep 2 ; $Le_Deploy_ssh_remote_cmd ;" - _info "Will sleep 2 seconds then execute remote command $Le_Deploy_ssh_remote_cmd" + if [ -n "$Le_Deploy_ssh_service_stop" ]; then + _cmdstr="$_cmdstr sleep 2 ;" + fi + _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd ;" + _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" fi + # SERVICE_START is optional. + # If provided then this command will be executed on remote host. + # A 2 second delay is inserted to allow system to stabalize after + # executing a service stop or previous command. if [ -n "$ACME_DEPLOY_SSH_SERVICE_START" ]; then Le_Deploy_ssh_service_start="$ACME_DEPLOY_SSH_SERVICE_START" _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" fi if [ -n "$Le_Deploy_ssh_service_start" ]; then - _cmdstr="$_cmdstr sleep 2 ; $Le_Deploy_ssh_service_start ;" - _info "Will sleep 2 seconds then start remote service with command $Le_Deploy_ssh_remote_cmd" + if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ] ; then + _cmdstr="$_cmdstr sleep 2 ;" + fi + _cmdstr="$_cmdstr $Le_Deploy_ssh_service_start ;" + _info "Will start remote service with command $Le_Deploy_ssh_remote_cmd" fi - _cmdstr="$_cmdstr }" - - _debug "Remote command to execute: $_cmdstr" + if [ -z "$_cmdstr" ]; then + _err "No remote commands to excute. Failed to deploy certificates to remote server" + return 1 + else + # something to execute. + # run cleanup on the backup directory, erase all older than 180 days. + _cmdstr="find $_homedir/* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" + # Create our backup directory for overwritten cert files. + _cmdstr="mkdir -p $_backupdir ; $_cmdstr" + fi + _debug "Remote commands to execute: $_cmdstr" _info "Submitting sequence of commands to remote server by ssh" - ssh -T "$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" + ssh -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" return 0 } From 5d3de4b670fefbc4f0fc54b390e0c196ea8583a7 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 14:39:25 -0500 Subject: [PATCH 0670/1348] Additional info messages for backup management --- deploy/sshdeploy.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index aa924136..e34371a1 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -178,6 +178,8 @@ sshdeploy_deploy() { _cmdstr="find $_homedir/* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" # Create our backup directory for overwritten cert files. _cmdstr="mkdir -p $_backupdir ; $_cmdstr" + _info "Backup of old certificate files will be placed in remote directory $_backupdir" + _info "Backup directories erased after 180 days." fi _debug "Remote commands to execute: $_cmdstr" From 62e7d904b40af35884bfb1dd59d9a0486c993207 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:02:59 -0500 Subject: [PATCH 0671/1348] Travis errors --- deploy/sshdeploy.sh | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index e34371a1..949bc1d3 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -22,8 +22,6 @@ # export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" # export ACME_DEPLOY_SSH_SERVICE_START="" -. "$DOMAIN_CONF" - ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -34,9 +32,12 @@ sshdeploy_deploy() { _cca="$4" _cfullchain="$5" _cmdstr="" - _homedir="~/.acme_ssh_deploy" + _homedir='~' + _homedir="$_homedir/.acme_ssh_deploy" _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" + . "$DOMAIN_CONF" + _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" _debug _ccert "$_ccert" @@ -61,7 +62,7 @@ sshdeploy_deploy() { elif [ -z "$Le_Deploy_ssh_url" ]; then Le_Deploy_ssh_url="$_cdomain" fi - + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_url" # SERVICE_STOP is optional. @@ -146,9 +147,9 @@ sshdeploy_deploy() { _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ]; then - _cmdstr="$_cmdstr sleep 2 ;" - fi + if [ -n "$Le_Deploy_ssh_service_stop" ]; then + _cmdstr="$_cmdstr sleep 2 ;" + fi _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd ;" _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" fi @@ -162,9 +163,9 @@ sshdeploy_deploy() { _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" fi if [ -n "$Le_Deploy_ssh_service_start" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ] ; then - _cmdstr="$_cmdstr sleep 2 ;" - fi + if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ] ; then + _cmdstr="$_cmdstr sleep 2 ;" + fi _cmdstr="$_cmdstr $Le_Deploy_ssh_service_start ;" _info "Will start remote service with command $Le_Deploy_ssh_remote_cmd" fi From ff60dc4d24b27998fe2e435c94135e1494dd2cc8 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:12:23 -0500 Subject: [PATCH 0672/1348] More Travis issues !!! --- deploy/sshdeploy.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 949bc1d3..672b25cd 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -36,8 +36,16 @@ sshdeploy_deploy() { _homedir="$_homedir/.acme_ssh_deploy" _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" + if [ -z "$DOMAIN_CONF" ]; then + DOMAIN_CONF="" + fi + if [ ! -f "$DOMAIN_CONF" ]; then + _err "$DOMAIN_CONF does not exist." + return 1 + fi + . "$DOMAIN_CONF" - + _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" _debug _ccert "$_ccert" @@ -163,7 +171,7 @@ sshdeploy_deploy() { _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" fi if [ -n "$Le_Deploy_ssh_service_start" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ] ; then + if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ]; then _cmdstr="$_cmdstr sleep 2 ;" fi _cmdstr="$_cmdstr $Le_Deploy_ssh_service_start ;" From 9ab6353d73c4ac747e1063ec8d2e40017222b6ba Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:16:05 -0500 Subject: [PATCH 0673/1348] Trying again. --- deploy/sshdeploy.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 672b25cd..63d72fb8 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -36,15 +36,9 @@ sshdeploy_deploy() { _homedir="$_homedir/.acme_ssh_deploy" _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" - if [ -z "$DOMAIN_CONF" ]; then - DOMAIN_CONF="" + if [ -f "$DOMAIN_CONF" ]; then + . "$DOMAIN_CONF" fi - if [ ! -f "$DOMAIN_CONF" ]; then - _err "$DOMAIN_CONF does not exist." - return 1 - fi - - . "$DOMAIN_CONF" _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" From 6c1561f415c18d66f8d7294c479ef3c47a443702 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:20:06 -0500 Subject: [PATCH 0674/1348] Grasping at straws now !! --- deploy/sshdeploy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 63d72fb8..39819ba9 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -37,6 +37,7 @@ sshdeploy_deploy() { _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" if [ -f "$DOMAIN_CONF" ]; then + # shellcheck disable=SC1090 . "$DOMAIN_CONF" fi From 3812b275e9995ada19604da863f2d2d6dd31d5d2 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:26:55 -0500 Subject: [PATCH 0675/1348] Moving on to the next batch of travis errors. --- deploy/sshdeploy.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 39819ba9..96eabc74 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -89,7 +89,7 @@ sshdeploy_deploy() { # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat $_ckey)\" > $Le_Deploy_ssh_keyfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile ;" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" fi @@ -102,13 +102,13 @@ sshdeploy_deploy() { if [ -n "$Le_Deploy_ssh_certfile" ]; then if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then # if filename is same as that provided for private key then append. - _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" >> $Le_Deploy_ssh_certfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" >> $Le_Deploy_ssh_certfile ;" _info "will append certificate to same file" else # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat $_ccert)\" > $Le_Deploy_ssh_certfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" > $Le_Deploy_ssh_certfile ;" _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" fi fi @@ -123,7 +123,7 @@ sshdeploy_deploy() { # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat $_cca)\" > $Le_Deploy_ssh_cafile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" > $Le_Deploy_ssh_cafile ;" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" fi @@ -137,7 +137,7 @@ sshdeploy_deploy() { # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat $_cfullchain)\" > $Le_Deploy_ssh_fullchain ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" > $Le_Deploy_ssh_fullchain ;" _info "will copy full chain to remote file $Le_Deploy_ssh_fullchain" fi @@ -188,6 +188,8 @@ sshdeploy_deploy() { _debug "Remote commands to execute: $_cmdstr" _info "Submitting sequence of commands to remote server by ssh" + # quotations in bash cmd below intended. Squash travis spellcheck error + # shellcheck disable=SC2029 ssh -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" return 0 From 9507b121acfe49b922683809d853f27c2f229ecd Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 15:34:03 -0500 Subject: [PATCH 0676/1348] More selective pruning of certificate backup directories. --- deploy/sshdeploy.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 96eabc74..55d248ca 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -33,8 +33,8 @@ sshdeploy_deploy() { _cfullchain="$5" _cmdstr="" _homedir='~' - _homedir="$_homedir/.acme_ssh_deploy" - _backupdir="$_homedir/certs-backup-$(date +%Y%m%d%H%M%S)" + _backupprefix="$_homedir/.acme_ssh_deploy/certs-backup" + _backupdir="$_backupprefix-$(date +%Y%m%d%H%M%S)" if [ -f "$DOMAIN_CONF" ]; then # shellcheck disable=SC1090 @@ -179,7 +179,7 @@ sshdeploy_deploy() { else # something to execute. # run cleanup on the backup directory, erase all older than 180 days. - _cmdstr="find $_homedir/* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" + _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" # Create our backup directory for overwritten cert files. _cmdstr="mkdir -p $_backupdir ; $_cmdstr" _info "Backup of old certificate files will be placed in remote directory $_backupdir" From 0ca5b7996cddab0e471efcb25313c3d6301cdfb1 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 6 Feb 2017 09:28:30 +0800 Subject: [PATCH 0677/1348] minor clear account conf --- acme.sh | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index b22b2e69..08e06fbd 100755 --- a/acme.sh +++ b/acme.sh @@ -3906,12 +3906,7 @@ _detect_profile() { _initconf() { _initpath if [ ! -f "$ACCOUNT_CONF_PATH" ]; then - echo "#ACCOUNT_CONF_PATH=xxxx - -#ACCOUNT_EMAIL=aaa@example.com # the account email used to register account. -#ACCOUNT_KEY_PATH=\"/path/to/account.key\" -#CERT_HOME=\"/path/to/cert/home\" - + echo " #LOG_FILE=\"$DEFAULT_LOG_FILE\" #LOG_LEVEL=1 @@ -3919,12 +3914,6 @@ _initconf() { #AUTO_UPGRADE=\"1\" #NO_TIMESTAMP=1 -#OPENSSL_BIN=openssl - -#USER_AGENT=\"$USER_AGENT\" - -#USER_PATH= - " >"$ACCOUNT_CONF_PATH" fi From dba26c3240efaa6cdd9c6f163f8294242c2bdbfd Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 6 Feb 2017 13:27:58 +0800 Subject: [PATCH 0678/1348] fix check for Mac nc command, it doesn't contain "openbsd", but it works. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 08e06fbd..d3d46b59 100755 --- a/acme.sh +++ b/acme.sh @@ -1687,7 +1687,7 @@ _startserver() { fi if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then - if ! _contains "$nchelp" "OpenBSD"; then + if ! _contains "$nchelp" "-4"; then _err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again." _err "See $(__green $_PREPARE_LINK)" return 1 From d6edff3182e3e3fe672652aa02324590e7f2057d Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 6 Feb 2017 14:20:37 +0800 Subject: [PATCH 0679/1348] fix ci --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8d6d30ad..1d54faed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,6 @@ install: fi script: - - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - command -V openssl && openssl version - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi @@ -44,8 +43,8 @@ script: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi matrix: From 5d2c5b01a80c2cdc555673926e7b865e33297ddd Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 6 Feb 2017 19:30:53 +0800 Subject: [PATCH 0680/1348] add _utc_date function --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index d3d46b59..0b234953 100755 --- a/acme.sh +++ b/acme.sh @@ -1265,6 +1265,10 @@ _time() { date -u "+%s" } +_utc_date() { + date -u "+%Y-%m-%d %H:%M:%S" +} + _mktemp() { if _exists mktemp; then if mktemp 2>/dev/null; then From 339a8ad61041591d6cc2bb3af77ed855e13e735d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 6 Feb 2017 19:53:12 +0800 Subject: [PATCH 0681/1348] minor, output thumbprint --- acme.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 0b234953..7ad5897d 100755 --- a/acme.sh +++ b/acme.sh @@ -2489,6 +2489,10 @@ __calcAccountKeyHash() { [ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH" } +__calc_account_thumbprint() { + printf "%s" "$jwk" | tr -d ' ' | _digest "sha256" | _url_replace +} + #keylength _regAccount() { _initpath @@ -2579,6 +2583,8 @@ _regAccount() { return 1 fi fi + ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" + _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" return 0 done @@ -2810,8 +2816,7 @@ issue() { fi if [ -z "$thumbprint" ]; then - accountkey_json=$(printf "%s" "$jwk" | tr -d ' ') - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _url_replace) + thumbprint="$(__calc_account_thumbprint)" fi entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" From 0e44f587a5052ece05ad09674c0384809c95dd7e Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 6 Feb 2017 20:42:54 +0800 Subject: [PATCH 0682/1348] add stateless mode --- acme.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7ad5897d..cb99b5ab 100755 --- a/acme.sh +++ b/acme.sh @@ -41,6 +41,8 @@ NO_VALUE="no" W_TLS="tls" +MODE_STATELESS="stateless" + STATE_VERIFIED="verified_ok" BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" @@ -63,6 +65,8 @@ _DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh" _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations" +_STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode" + __INTERACTIVE="" if [ -t 1 ]; then __INTERACTIVE="1" @@ -2973,7 +2977,9 @@ issue() { serverproc="$!" sleep 1 _debug serverproc "$serverproc" - + elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then + _info "Stateless mode for domain:$d" + _sleep 1 else if [ "$_currentRoot" = "apache" ]; then wellknown_path="$ACME_DIR" @@ -4258,6 +4264,7 @@ Parameters: --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --standalone Use standalone mode. + --stateless Use stateless mode, see: $_STATELESS_WIKI --tls Use standalone tls mode. --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. @@ -4563,6 +4570,14 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; + --stateless) + wvalue="$MODE_STATELESS" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; --local-address) lvalue="$2" _local_address="$_local_address$lvalue," From 7c488b5913f47aecfcc61d8e6d329a4b374387c3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 6 Feb 2017 21:37:21 +0800 Subject: [PATCH 0683/1348] doc for stateless mode --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c6362ed7..2dd178d8 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ https://github.com/Neilpang/acmetest - Standalone mode - Apache mode - DNS mode +- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) # 1. How to install From f158caa2ebba77a343ca7badddba8395e822a609 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Mon, 6 Feb 2017 21:49:20 -0500 Subject: [PATCH 0684/1348] Updates from code review --- deploy/sshdeploy.sh | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/deploy/sshdeploy.sh b/deploy/sshdeploy.sh index 55d248ca..e7ca78a8 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/sshdeploy.sh @@ -3,7 +3,7 @@ # Script to deploy certificates to remote server by SSH # Note that SSH must be able to login to remote host without a password... # SSH Keys must have been exchanged with the remote host. Validate and -# test that you can login to USER@URL from the host running acme.sh before +# test that you can login to USER@SERVER from the host running acme.sh before # using this script. # # The following variables exported from environment will be used. @@ -13,7 +13,8 @@ # # The following examples are for QNAP NAS running QTS 4.2 # export ACME_DEPLOY_SSH_USER="admin" -# export ACME_DEPLOY_SSH_URL="qnap" +# export ACME_DEPLOY_SSH_SERVER="qnap" +# export ACME_DEPLOY_SSH_PORT="22" # export ACME_DEPLOY_SSH_SERVICE_STOP="" # export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" @@ -34,7 +35,7 @@ sshdeploy_deploy() { _cmdstr="" _homedir='~' _backupprefix="$_homedir/.acme_ssh_deploy/certs-backup" - _backupdir="$_backupprefix-$(date +%Y%m%d%H%M%S)" + _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')" if [ -f "$DOMAIN_CONF" ]; then # shellcheck disable=SC1090 @@ -58,15 +59,23 @@ sshdeploy_deploy() { _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user" fi - # URL is optional. If not provided then use _cdomain - if [ -n "$ACME_DEPLOY_SSH_URL" ]; then - Le_Deploy_ssh_url="$ACME_DEPLOY_SSH_URL" - _savedomainconf Le_Deploy_ssh_url "$Le_Deploy_ssh_url" - elif [ -z "$Le_Deploy_ssh_url" ]; then - Le_Deploy_ssh_url="$_cdomain" + # SERVER is optional. If not provided then use _cdomain + if [ -n "$ACME_DEPLOY_SSH_SERVER" ]; then + Le_Deploy_ssh_server="$ACME_DEPLOY_SSH_SERVER" + _savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server" + elif [ -z "$Le_Deploy_ssh_server" ]; then + Le_Deploy_ssh_server="$_cdomain" fi - _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_url" + # PORT is optional. If not provided then use port 22 + if [ -n "$ACME_DEPLOY_SSH_PORT" ]; then + Le_Deploy_ssh_port="$ACME_DEPLOY_SSH_PORT" + _savedomainconf Le_Deploy_ssh_port "$Le_Deploy_ssh_port" + elif [ -z "$Le_Deploy_ssh_port" ]; then + Le_Deploy_ssh_port="22" + fi + + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server on port $Le_Deploy_ssh_port" # SERVICE_STOP is optional. # If provided then this command will be executed on remote host. @@ -190,7 +199,7 @@ sshdeploy_deploy() { _info "Submitting sequence of commands to remote server by ssh" # quotations in bash cmd below intended. Squash travis spellcheck error # shellcheck disable=SC2029 - ssh -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_url" bash -c "'$_cmdstr'" + ssh -T -p "$Le_Deploy_ssh_port" "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmdstr'" - return 0 + return $? } From 3be5a68e12bd366ab80c93c8d8f353d1ebda268a Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 7 Feb 2017 13:05:22 -0500 Subject: [PATCH 0685/1348] Rename sshdeploy.sh to ssh.sh --- deploy/{sshdeploy.sh => ssh.sh} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename deploy/{sshdeploy.sh => ssh.sh} (99%) diff --git a/deploy/sshdeploy.sh b/deploy/ssh.sh similarity index 99% rename from deploy/sshdeploy.sh rename to deploy/ssh.sh index e7ca78a8..c3b89448 100644 --- a/deploy/sshdeploy.sh +++ b/deploy/ssh.sh @@ -26,7 +26,7 @@ ######## Public functions ##################### #domain keyfile certfile cafile fullchain -sshdeploy_deploy() { +ssh_deploy() { _cdomain="$1" _ckey="$2" _ccert="$3" From 3365df77789b97c8e2b54eae02afd581d5714636 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 8 Feb 2017 10:15:39 -0500 Subject: [PATCH 0686/1348] Make certificate domain name part of the backup directory name. --- deploy/ssh.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/ssh.sh b/deploy/ssh.sh index c3b89448..6d628436 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -34,7 +34,7 @@ ssh_deploy() { _cfullchain="$5" _cmdstr="" _homedir='~' - _backupprefix="$_homedir/.acme_ssh_deploy/certs-backup" + _backupprefix="$_homedir/.acme_ssh_deploy/$_cdomain-backup" _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')" if [ -f "$DOMAIN_CONF" ]; then From 1a5989350fad48a824dda39c7d83703d6ae490f1 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 8 Feb 2017 21:02:00 -0500 Subject: [PATCH 0687/1348] Some documentation in README --- deploy/README.md | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 580eaac8..8096073d 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1 +1,92 @@ #Using deploy api + +#Using the ssh deploy plugin + +The ssh deploy plugin allows you to deploy certificates to a remote host +using SSH command to connect to the remote server. The ssh plugin is invoked +with the following command... + +```bash +acme.sh --deploy -d example.com --deploy-hook ssh +``` +Prior to running this for the first time you must tell the plugin where +and how to deploy the certificates. This is done by exporting the following +environment variables. + +This is not required for subsequent runs as the +values are stored by acme.sh in the domain configuration files. + +Required... +```bash +export ACME_DEPLOY_SSH_USER="admin" +``` +Optional... +```bash +export ACME_DEPLOY_SSH_SERVER="qnap" +export ACME_DEPLOY_SSH_PORT="22" +export ACME_DEPLOY_SSH_SERVICE_STOP="" +export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +export ACME_DEPLOY_SSH_FULLCHAIN="" +export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +export ACME_DEPLOY_SSH_SERVICE_START="" +``` +The values used above are illustrative only and represent those used +to deploy certificates to a QNAP NAS device running QTS 4.2 + +###ACME_DEPLOY_SSH_USER +Username at the remote host that SSH will login with. Note that +SSH must be able to login to remote host without a password... SSH Keys +must have been exchanged with the remote host. Validate and test that you +can login to USER@URL from the host running acme.sh before using this script. + +The USER@URL at the remote server must also have has permissions to write to +the target location of the certificate files and to execute any commands +(e.g. to stop/start services). + +###ACME_DEPLOY_SSH_SERVER +URL or IP Address of the remote server. If not provided then the domain +name provided on the acme.sh --deploy command line is used. + +###ACME_DEPLOY_SSH_PORT +Port number that SSH will attempt to connect to at the remote server. If +not specified then defaults to 22. + +###ACME_DEPLOY_SSH_SERVICE_STOP +Command to execute on the remote server prior to copying any certificates. This +would typically be used to stop the service for which the certificates are +being deployed. + +###ACME_DEPLOY_SSH_KEYFILE +###ACME_DEPLOY_SSH_CERTFILE +###ACME_DEPLOY_SSH_CAFILE +###ACME_DEPLOY_SSH_FULLCHAIN +These four variables identify the target location for the respective +certificates issued by LetsEncrypt. Directory path and filenames are those +on the remote server and the SSH user must have write permissions. + +###ACME_DEPLOY_SSH_REMOTE_CMD +Command to execute on the remote server after copying any certificates. This +could be any additional command required prior to starting the service again, +or could be a all-inclusive restart (stop and start of service). If +ACME_DEPLOY_SSH_SERVICE_STOP value was provided then a 2 second sleep is +inserted prior to calling this command to allow the system to stabalize. + +###ACME_DEPLOY_SSH_SERVICE_START +Command to execute on the remote server after copying any certificates. This +would typically be used to stop the service for which the certificates are +being deployed. If ACME_DEPLOY_SSH_SERVICE_STOP or ACME_DEPLOY_SSH_REMOTE_CMD +value were provided then a 2 second sleep is inserted prior to calling +this command to allow the system to stabalize. + +##Backups +Before writing a certificate file to the remote server the existing +certificate will be copied to a backup directory on the remote server. +These are placed in a hidden directory in the home directory of the SSH +user +```bash +~/.acme_ssh_deploy/[domain name]-backup-[timestamp] +``` +Any backups older than 180 days will be deleted when new certificates +are deployed. From e3feac3fd87db1bbd0838c3e851c8724d17a2fe1 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 8 Feb 2017 21:13:00 -0500 Subject: [PATCH 0688/1348] Documentation updates --- deploy/README.md | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 8096073d..2e490a17 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -11,9 +11,7 @@ acme.sh --deploy -d example.com --deploy-hook ssh ``` Prior to running this for the first time you must tell the plugin where and how to deploy the certificates. This is done by exporting the following -environment variables. - -This is not required for subsequent runs as the +environment variables. This is not required for subsequent runs as the values are stored by acme.sh in the domain configuration files. Required... @@ -32,8 +30,8 @@ export ACME_DEPLOY_SSH_FULLCHAIN="" export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" export ACME_DEPLOY_SSH_SERVICE_START="" ``` -The values used above are illustrative only and represent those used -to deploy certificates to a QNAP NAS device running QTS 4.2 +The values used above are illustrative only and represent those that could +be used to deploy certificates to a QNAP NAS device running QTS 4.2 ###ACME_DEPLOY_SSH_USER Username at the remote host that SSH will login with. Note that @@ -44,40 +42,37 @@ can login to USER@URL from the host running acme.sh before using this script. The USER@URL at the remote server must also have has permissions to write to the target location of the certificate files and to execute any commands (e.g. to stop/start services). - ###ACME_DEPLOY_SSH_SERVER URL or IP Address of the remote server. If not provided then the domain name provided on the acme.sh --deploy command line is used. - ###ACME_DEPLOY_SSH_PORT Port number that SSH will attempt to connect to at the remote server. If -not specified then defaults to 22. - +not provided then defaults to 22. ###ACME_DEPLOY_SSH_SERVICE_STOP Command to execute on the remote server prior to copying any certificates. This would typically be used to stop the service for which the certificates are being deployed. - ###ACME_DEPLOY_SSH_KEYFILE +Target filename for the private key issued by LetsEncrypt. ###ACME_DEPLOY_SSH_CERTFILE +Target filename for the certificate issued by LetsEncrypt. If this filename +is the same as that provided for ACME_DEPLOY_SSH_KEYFILE then this certificate +is appended to the same file as the private key. ###ACME_DEPLOY_SSH_CAFILE +Target filename for the CA intermediate certificate issued by LetsEncrypt. ###ACME_DEPLOY_SSH_FULLCHAIN -These four variables identify the target location for the respective -certificates issued by LetsEncrypt. Directory path and filenames are those -on the remote server and the SSH user must have write permissions. - +Target filename for the fullchain certificate issued by LetsEncrypt. ###ACME_DEPLOY_SSH_REMOTE_CMD Command to execute on the remote server after copying any certificates. This could be any additional command required prior to starting the service again, or could be a all-inclusive restart (stop and start of service). If ACME_DEPLOY_SSH_SERVICE_STOP value was provided then a 2 second sleep is inserted prior to calling this command to allow the system to stabalize. - ###ACME_DEPLOY_SSH_SERVICE_START Command to execute on the remote server after copying any certificates. This would typically be used to stop the service for which the certificates are being deployed. If ACME_DEPLOY_SSH_SERVICE_STOP or ACME_DEPLOY_SSH_REMOTE_CMD -value were provided then a 2 second sleep is inserted prior to calling +values were provided then a 2 second sleep is inserted prior to calling this command to allow the system to stabalize. ##Backups From c9d7daab70476e7c5f60a4e0aea06c671d91cb3d Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 10 Feb 2017 13:34:34 +0800 Subject: [PATCH 0689/1348] fix https://github.com/Neilpang/acme.sh/issues/593 --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 555bd70b..29d7a2cd 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -93,7 +93,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" + hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." From 34f25fa590ba9917ecfd8f70887635ed5d2c467d Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 10 Feb 2017 18:20:15 +0800 Subject: [PATCH 0690/1348] support mingw/git-bash --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index cb99b5ab..4279ddfc 100755 --- a/acme.sh +++ b/acme.sh @@ -896,7 +896,11 @@ _createcsr() { _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" - $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + if _contains "$(uname -a)" "MINGW"; then + $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" + else + $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + fi } #_signcsr key csr conf cert From d8beaf727f84ac8149e290b5695dc35634e195e2 Mon Sep 17 00:00:00 2001 From: hebbet Date: Fri, 10 Feb 2017 13:26:17 +0100 Subject: [PATCH 0691/1348] remove extra space remove extra space from help --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4279ddfc..8eb52d3e 100755 --- a/acme.sh +++ b/acme.sh @@ -4238,7 +4238,7 @@ Commands: --version, -v Show version info. --install Install $PROJECT_NAME to your system. --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job. - --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT . + --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT. --issue Issue a cert. --signcsr Issue a cert from an existing csr. --deploy Deploy the cert to your server. From 4e4a6d83973fa0580ef8b2f1d7d0312fdd671543 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 10 Feb 2017 20:55:25 +0800 Subject: [PATCH 0692/1348] better hexdump fix https://github.com/Neilpang/acme.sh/issues/595 --- acme.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 4279ddfc..b544f531 100755 --- a/acme.sh +++ b/acme.sh @@ -364,8 +364,16 @@ _ascii_hex() { #input:"abc" #output: " 61 62 63" _hex_dump() { - #in wired some system, the od command is missing. - if ! od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" 2>/dev/null; then + if _exists od; then + od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n" + elif _exists hexdump; then + _debug3 "using hexdump" + hexdump -v -e '/1 ""' -e '/1 " %02x" ""' + elif _exists xxd; then + _debug3 "using xxd" + xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " " + else + _debug3 "using _ascii_hex" str=$(cat) _ascii_hex "$str" fi From 04e0f87c0387e81b100f94de9a511e47f0b49f75 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 13:24:00 +0800 Subject: [PATCH 0693/1348] add doc --- deploy/README.md | 31 ++++++++++++++++++++++++++++++- deploy/cpanel.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 deploy/cpanel.sh diff --git a/deploy/README.md b/deploy/README.md index 580eaac8..fcdf8019 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1 +1,30 @@ -#Using deploy api +# Using deploy api + +Here are the scripts to deploy the certs/key to the server/services. + +## 1. Deploy the certs to your cpanel host. + +(cpanel deploy hook is not finished yet, this is just an example.) + +Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). + +Then you can deploy now: + +```sh +export DEPLOY_CPANEL_USER=myusername +export DEPLOY_CPANEL_PASSWORD=PASSWORD +acme.sh --deploy -d example.com --deploy --deploy-hook cpanel +``` + +## 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). + +(TODO) + +## 3. Deploy the cert to remote server through SSH access. + +(TODO) + + + diff --git a/deploy/cpanel.sh b/deploy/cpanel.sh new file mode 100644 index 00000000..bf1332ff --- /dev/null +++ b/deploy/cpanel.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env sh + +#Here is the script to deploy the cert to your cpanel account by the cpanel APIs. + +#returns 0 means success, otherwise error. + +#export DEPLOY_CPANEL_USER=myusername +#export DEPLOY_CPANEL_PASSWORD=PASSWORD + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +cpanel_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Not implemented yet" + return 1 + +} From 0984585d58cc87a8b49ee93ad8d5c6924c88a79d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 13:36:52 +0800 Subject: [PATCH 0694/1348] minor, rename command --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 04bf55ad..67c72068 100755 --- a/acme.sh +++ b/acme.sh @@ -4263,8 +4263,8 @@ Commands: --toPkcs Export the certificate and key to a pfx file. --update-account Update account info. --register-account Register account key. - --createAccountKey, -cak Create an account private key, professional use. - --createDomainKey, -cdk Create an domain private key, professional use. + --create-account-key Create an account private key, professional use. + --create-domain-key Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. --deactivate Deactivate the domain authz, professional use. @@ -4506,10 +4506,10 @@ _process() { --toPkcs) _CMD="toPkcs" ;; - --createAccountKey | --createaccountkey | -cak) + --createAccountKey | --createaccountkey | -cak | --create-account-key) _CMD="createAccountKey" ;; - --createDomainKey | --createdomainkey | -cdk) + --createDomainKey | --createdomainkey | -cdk | --create-domain-key) _CMD="createDomainKey" ;; --createCSR | --createcsr | -ccr) From d47c5eaf604743867ae0ca2fdeda0d2108747c4e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 20:13:21 +0800 Subject: [PATCH 0695/1348] update issue template --- .github/ISSUE_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4abbb7ab..f7d4d1d7 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,4 +1,6 @@ Steps to reproduce ------------------ - Debug log ----------------- From e2edf2083384f6ceae71d89e569052b1ba3b827d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 21:15:36 +0800 Subject: [PATCH 0696/1348] support syslog --- acme.sh | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 67c72068..9929dfad 100755 --- a/acme.sh +++ b/acme.sh @@ -61,6 +61,10 @@ LOG_LEVEL_2=2 LOG_LEVEL_3=3 DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" +SYSLOG_INFO="user.info" +SYSLOG_ERROR="user.error" +SYSLOG_DEBUG="user.debug" + _DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh" _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations" @@ -128,18 +132,30 @@ _dlg_versions() { fi } +#class +_syslog() { + if [ -z "$SYS_LOG" ] || [ "$SYS_LOG" = "0" ]; then + return + fi + _logclass="$1" + shift + logger -i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 +} + _log() { + _syslog "$@" [ -z "$LOG_FILE" ] && return + shift _printargs "$@" >>"$LOG_FILE" } _info() { - _log "$@" + _log "$SYSLOG_INFO" "$@" _printargs "$@" } _err() { - _log "$@" + _log "$SYSLOG_ERROR" "$@" if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then printf -- "%s" "[$(date)] " >&2 fi @@ -159,7 +175,7 @@ _usage() { _debug() { if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ]; then - _log "$@" + _log "$SYSLOG_DEBUG" "$@" fi if [ -z "$DEBUG" ]; then return @@ -169,19 +185,19 @@ _debug() { _debug2() { if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ]; then - _log "$@" + _log "$SYSLOG_DEBUG" "$@" fi if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _debug "$@" + _printargs "$@" >&2 fi } _debug3() { if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ]; then - _log "$@" + _log "$SYSLOG_DEBUG" "$@" fi if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ]; then - _debug "$@" + _printargs "$@" >&2 fi } @@ -4286,6 +4302,7 @@ Parameters: --accountkeylength, -ak [2048] Specifies the account key length. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. --log-level 1|2 Specifies the log level, default is 1. + --syslog [1|0] Enable/Disable syslog. These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: @@ -4444,6 +4461,7 @@ _process() { _listen_v4="" _listen_v6="" _openssl_bin="" + _syslog="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -4774,6 +4792,15 @@ _process() { LOG_LEVEL="$_log_level" shift ;; + --syslog) + if ! _startswith "$2" '-'; then + _syslog="$2" + shift + fi + if [ -z "$_syslog" ]; then + _syslog="1" + fi + ;; --auto-upgrade) _auto_upgrade="$2" if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then @@ -4821,6 +4848,21 @@ _process() { LOG_LEVEL="$_log_level" fi + if [ "$_syslog" ]; then + if _exists logger; then + if [ "$_syslog" = "0" ]; then + _clearaccountconf "SYS_LOG" + else + _saveaccountconf "SYS_LOG" "$_syslog" + fi + SYS_LOG="$_syslog" + else + _err "The 'logger' command is not found, can not enable syslog." + _clearaccountconf "SYS_LOG" + SYS_LOG="" + fi + fi + _processAccountConf fi @@ -4913,6 +4955,21 @@ _process() { if [ "$_log_level" ]; then _saveaccountconf "LOG_LEVEL" "$_log_level" fi + + if [ "$_syslog" ]; then + if _exists logger; then + if [ "$_syslog" = "0" ]; then + _clearaccountconf "SYS_LOG" + else + _saveaccountconf "SYS_LOG" "$_syslog" + fi + else + _err "The 'logger' command is not found, can not enable syslog." + _clearaccountconf "SYS_LOG" + SYS_LOG="" + fi + fi + _processAccountConf fi From cd9c3a79e556c6221d3fe15aaa4dc3f50689bc98 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 21:29:36 +0800 Subject: [PATCH 0697/1348] update doc --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2dd178d8..f1c74806 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT** **Apache** example: ```bash -acme.sh --installcert -d example.com \ +acme.sh --install-cert -d example.com \ --certpath /path/to/certfile/in/apache/cert.pem \ --keypath /path/to/keyfile/in/apache/key.pem \ --fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ @@ -156,7 +156,7 @@ acme.sh --installcert -d example.com \ **Nginx** example: ```bash -acme.sh --installcert -d example.com \ +acme.sh --install-cert -d example.com \ --keypath /path/to/keyfile/in/nginx/key.pem \ --fullchainpath /path/to/fullchain/nginx/cert.pem \ --reloadcmd "service nginx force-reload" From 68d708e56da391e86bd13ea8900d015048d7f279 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 11 Feb 2017 16:11:27 -0500 Subject: [PATCH 0698/1348] Reduce and simplify number of exported variables. Also allow any cert file to append to previous file. --- deploy/README.md | 33 ++++++--------- deploy/ssh.sh | 106 ++++++++++++++++++++--------------------------- 2 files changed, 58 insertions(+), 81 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 15b7ae1d..95f31d45 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -42,15 +42,13 @@ export ACME_DEPLOY_SSH_USER="admin" ``` Optional... ```bash +export ACME_DEPLOY_SSH_CMD="" export ACME_DEPLOY_SSH_SERVER="qnap" -export ACME_DEPLOY_SSH_PORT="22" -export ACME_DEPLOY_SSH_SERVICE_STOP="" export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" export ACME_DEPLOY_SSH_FULLCHAIN="" export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -export ACME_DEPLOY_SSH_SERVICE_START="" ``` The values used above are illustrative only and represent those that could be used to deploy certificates to a QNAP NAS device running QTS 4.2 @@ -64,16 +62,13 @@ can login to USER@URL from the host running acme.sh before using this script. The USER@URL at the remote server must also have has permissions to write to the target location of the certificate files and to execute any commands (e.g. to stop/start services). +###ACME_DEPLOY_SSH_CMD +You can customize the ssh command used to connect to the remote host. For example +if you need to connect to a specific port at the remote server you can set this +to, for example, "ssh -p 22" ###ACME_DEPLOY_SSH_SERVER URL or IP Address of the remote server. If not provided then the domain name provided on the acme.sh --deploy command line is used. -###ACME_DEPLOY_SSH_PORT -Port number that SSH will attempt to connect to at the remote server. If -not provided then defaults to 22. -###ACME_DEPLOY_SSH_SERVICE_STOP -Command to execute on the remote server prior to copying any certificates. This -would typically be used to stop the service for which the certificates are -being deployed. ###ACME_DEPLOY_SSH_KEYFILE Target filename for the private key issued by LetsEncrypt. ###ACME_DEPLOY_SSH_CERTFILE @@ -82,22 +77,18 @@ is the same as that provided for ACME_DEPLOY_SSH_KEYFILE then this certificate is appended to the same file as the private key. ###ACME_DEPLOY_SSH_CAFILE Target filename for the CA intermediate certificate issued by LetsEncrypt. +If this is the same as a previous filename then it is appended to the same +file ###ACME_DEPLOY_SSH_FULLCHAIN Target filename for the fullchain certificate issued by LetsEncrypt. +If this is the same as a previous filename then it is appended to the same +file ###ACME_DEPLOY_SSH_REMOTE_CMD Command to execute on the remote server after copying any certificates. This -could be any additional command required prior to starting the service again, -or could be a all-inclusive restart (stop and start of service). If -ACME_DEPLOY_SSH_SERVICE_STOP value was provided then a 2 second sleep is -inserted prior to calling this command to allow the system to stabalize. -###ACME_DEPLOY_SSH_SERVICE_START -Command to execute on the remote server after copying any certificates. This -would typically be used to stop the service for which the certificates are -being deployed. If ACME_DEPLOY_SSH_SERVICE_STOP or ACME_DEPLOY_SSH_REMOTE_CMD -values were provided then a 2 second sleep is inserted prior to calling -this command to allow the system to stabalize. +could be any additional command required for example to stop and restart +the service. -##Backups +###Backups Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH diff --git a/deploy/ssh.sh b/deploy/ssh.sh index 6d628436..0adeba89 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -12,16 +12,14 @@ # Only a username is required. All others are optional. # # The following examples are for QNAP NAS running QTS 4.2 +# export ACME_DEPLOY_SSH_CMD="" # export ACME_DEPLOY_SSH_USER="admin" # export ACME_DEPLOY_SSH_SERVER="qnap" -# export ACME_DEPLOY_SSH_PORT="22" -# export ACME_DEPLOY_SSH_SERVICE_STOP="" # export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" # export ACME_DEPLOY_SSH_FULLCHAIN="" -# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -# export ACME_DEPLOY_SSH_SERVICE_START="" +# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" ######## Public functions ##################### @@ -67,26 +65,15 @@ ssh_deploy() { Le_Deploy_ssh_server="$_cdomain" fi - # PORT is optional. If not provided then use port 22 - if [ -n "$ACME_DEPLOY_SSH_PORT" ]; then - Le_Deploy_ssh_port="$ACME_DEPLOY_SSH_PORT" - _savedomainconf Le_Deploy_ssh_port "$Le_Deploy_ssh_port" - elif [ -z "$Le_Deploy_ssh_port" ]; then - Le_Deploy_ssh_port="22" + # CMD is optional. If not provided then use ssh + if [ -n "$ACME_DEPLOY_SSH_CMD" ]; then + Le_Deploy_ssh_cmd="$ACME_DEPLOY_SSH_CMD" + _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd" + elif [ -z "$Le_Deploy_ssh_cmd" ]; then + Le_Deploy_ssh_cmd="ssh" fi - _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server on port $Le_Deploy_ssh_port" - - # SERVICE_STOP is optional. - # If provided then this command will be executed on remote host. - if [ -n "$ACME_DEPLOY_SSH_SERVICE_STOP" ]; then - Le_Deploy_ssh_service_stop="$ACME_DEPLOY_SSH_SERVICE_STOP" - _savedomainconf Le_Deploy_ssh_service_stop "$Le_Deploy_ssh_service_stop" - fi - if [ -n "$Le_Deploy_ssh_service_stop" ]; then - _cmdstr="$_cmdstr $Le_Deploy_ssh_service_stop ;" - _info "Will stop remote service with command $Le_Deploy_ssh_service_stop" - fi + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server" # KEYFILE is optional. # If provided then private key will be copied to provided filename. @@ -110,78 +97,72 @@ ssh_deploy() { fi if [ -n "$Le_Deploy_ssh_certfile" ]; then if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then - # if filename is same as that provided for private key then append. - _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" >> $Le_Deploy_ssh_certfile ;" - _info "will append certificate to same file" + # if filename is same as previous file then append. + _pipe=">>" else # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" - # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" > $Le_Deploy_ssh_certfile ;" - _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" + _pipe=">" fi + # copy new certificate into file. + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile ;" + _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" fi # CAFILE is optional. - # If provided then CA intermediate certificate will be copied to provided filename. + # If provided then CA intermediate certificate will be copied or appended to provided filename. if [ -n "$ACME_DEPLOY_SSH_CAFILE" ]; then Le_Deploy_ssh_cafile="$ACME_DEPLOY_SSH_CAFILE" _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" fi if [ -n "$Le_Deploy_ssh_cafile" ]; then - # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" + if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] || + [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then + # if filename is same as previous file then append. + _pipe=">>" + else + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" + _pipe=">" + fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" > $Le_Deploy_ssh_cafile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile ;" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" fi # FULLCHAIN is optional. - # If provided then fullchain certificate will be copied to provided filename. + # If provided then fullchain certificate will be copied or appended to provided filename. if [ -n "$ACME_DEPLOY_SSH_FULLCHAIN" ]; then Le_Deploy_ssh_fullchain="$ACME_DEPLOY_SSH_FULLCHAIN" _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" fi if [ -n "$Le_Deploy_ssh_fullchain" ]; then - # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" + if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] || + [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] || + [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then + # if filename is same as previous file then append. + _pipe=">>" + else + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" + _pipe=">" + fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" > $Le_Deploy_ssh_fullchain ;" - _info "will copy full chain to remote file $Le_Deploy_ssh_fullchain" + _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain ;" + _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain" fi # REMOTE_CMD is optional. # If provided then this command will be executed on remote host. - # A 2 second delay is inserted to allow system to stabalize after - # executing a service stop. if [ -n "$ACME_DEPLOY_SSH_REMOTE_CMD" ]; then Le_Deploy_ssh_remote_cmd="$ACME_DEPLOY_SSH_REMOTE_CMD" _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ]; then - _cmdstr="$_cmdstr sleep 2 ;" - fi _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd ;" _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" fi - # SERVICE_START is optional. - # If provided then this command will be executed on remote host. - # A 2 second delay is inserted to allow system to stabalize after - # executing a service stop or previous command. - if [ -n "$ACME_DEPLOY_SSH_SERVICE_START" ]; then - Le_Deploy_ssh_service_start="$ACME_DEPLOY_SSH_SERVICE_START" - _savedomainconf Le_Deploy_ssh_service_start "$Le_Deploy_ssh_service_start" - fi - if [ -n "$Le_Deploy_ssh_service_start" ]; then - if [ -n "$Le_Deploy_ssh_service_stop" ] || [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - _cmdstr="$_cmdstr sleep 2 ;" - fi - _cmdstr="$_cmdstr $Le_Deploy_ssh_service_start ;" - _info "Will start remote service with command $Le_Deploy_ssh_remote_cmd" - fi - if [ -z "$_cmdstr" ]; then _err "No remote commands to excute. Failed to deploy certificates to remote server" return 1 @@ -199,7 +180,12 @@ ssh_deploy() { _info "Submitting sequence of commands to remote server by ssh" # quotations in bash cmd below intended. Squash travis spellcheck error # shellcheck disable=SC2029 - ssh -T -p "$Le_Deploy_ssh_port" "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmdstr'" + $Le_Deploy_ssh_cmd -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmdstr'" + _ret="$?" + + if [ "$_ret" != "0" ]; then + _err "Error code $_ret returned from $Le_Deploy_ssh_cmd" + fi - return $? + return $_ret } From a4b2cebef61e6add91c423aa146ab7313d7ab740 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 11 Feb 2017 16:42:44 -0500 Subject: [PATCH 0699/1348] Make backup of certs on remote server optional. Defaults to yes. --- deploy/README.md | 6 +++--- deploy/ssh.sh | 50 +++++++++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 95f31d45..01705838 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -49,6 +49,7 @@ export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" export ACME_DEPLOY_SSH_FULLCHAIN="" export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +export ACME_DEPLOY_SSH_BACKUP="" ``` The values used above are illustrative only and represent those that could be used to deploy certificates to a QNAP NAS device running QTS 4.2 @@ -87,8 +88,7 @@ file Command to execute on the remote server after copying any certificates. This could be any additional command required for example to stop and restart the service. - -###Backups +###ACME_DEPLOY_SSH_BACKUP Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH @@ -97,4 +97,4 @@ user ~/.acme_ssh_deploy/[domain name]-backup-[timestamp] ``` Any backups older than 180 days will be deleted when new certificates -are deployed. +are deployed. This defaults to "yes" set to "no" to disable backup. diff --git a/deploy/ssh.sh b/deploy/ssh.sh index 0adeba89..26963ed5 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -12,15 +12,16 @@ # Only a username is required. All others are optional. # # The following examples are for QNAP NAS running QTS 4.2 -# export ACME_DEPLOY_SSH_CMD="" -# export ACME_DEPLOY_SSH_USER="admin" -# export ACME_DEPLOY_SSH_SERVER="qnap" +# export ACME_DEPLOY_SSH_CMD="" # defaults to ssh +# export ACME_DEPLOY_SSH_USER="admin" # required +# export ACME_DEPLOY_SSH_SERVER="qnap" # defaults to domain name # export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" # export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" # export ACME_DEPLOY_SSH_FULLCHAIN="" -# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" - +# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +# export ACME_DEPLOY_SSH_BACKUP="" # yes or no, default to yes +# ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -73,6 +74,14 @@ ssh_deploy() { Le_Deploy_ssh_cmd="ssh" fi + # BACKUP is optional. If not provided then default to yes + if [ "$ACME_DEPLOY_SSH_BACKUP" = "no"]; then + Le_Deploy_ssh_backup="no" + elif [ -z "$Le_Deploy_ssh_backup" ]; then + Le_Deploy_ssh_backup="yes" + fi + _savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup" + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server" # KEYFILE is optional. @@ -82,8 +91,10 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" fi if [ -n "$Le_Deploy_ssh_keyfile" ]; then - # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" + if [ "$Le_Deploy_ssh_backup" = "yes" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" + fi # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile ;" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" @@ -96,13 +107,13 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" fi if [ -n "$Le_Deploy_ssh_certfile" ]; then + _pipe=">" if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then # if filename is same as previous file then append. _pipe=">>" - else + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" - _pipe=">" fi # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile ;" @@ -116,14 +127,14 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" fi if [ -n "$Le_Deploy_ssh_cafile" ]; then - if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] || - [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then + _pipe=">" + if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] \ + || [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then # if filename is same as previous file then append. _pipe=">>" - else + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" - _pipe=">" fi # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile ;" @@ -137,15 +148,15 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" fi if [ -n "$Le_Deploy_ssh_fullchain" ]; then - if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] || - [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] || - [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then + _pipe=">" + if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] \ + || [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] \ + || [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then # if filename is same as previous file then append. _pipe=">>" - else + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" - _pipe=">" fi # copy new certificate into file. _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain ;" @@ -166,8 +177,7 @@ ssh_deploy() { if [ -z "$_cmdstr" ]; then _err "No remote commands to excute. Failed to deploy certificates to remote server" return 1 - else - # something to execute. + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # run cleanup on the backup directory, erase all older than 180 days. _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" # Create our backup directory for overwritten cert files. From 18a90734d94f77ab90e45aa6e32bf065567e2cc2 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 11 Feb 2017 17:55:05 -0500 Subject: [PATCH 0700/1348] Alternate backup cleanup after 180 days method. --- deploy/ssh.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/deploy/ssh.sh b/deploy/ssh.sh index 26963ed5..eb3690a6 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -75,7 +75,7 @@ ssh_deploy() { fi # BACKUP is optional. If not provided then default to yes - if [ "$ACME_DEPLOY_SSH_BACKUP" = "no"]; then + if [ "$ACME_DEPLOY_SSH_BACKUP" = "no" ]; then Le_Deploy_ssh_backup="no" elif [ -z "$Le_Deploy_ssh_backup" ]; then Le_Deploy_ssh_backup="yes" @@ -178,8 +178,12 @@ ssh_deploy() { _err "No remote commands to excute. Failed to deploy certificates to remote server" return 1 elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then - # run cleanup on the backup directory, erase all older than 180 days. - _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" + # run cleanup on the backup directory, erase all older + # than 180 days (15552000 seconds). + _cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \ +do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \ +then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr" + # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" # Create our backup directory for overwritten cert files. _cmdstr="mkdir -p $_backupdir ; $_cmdstr" _info "Backup of old certificate files will be placed in remote directory $_backupdir" From fd72cced13e37c3a5f877e14825bac2d6c455a2a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 12 Feb 2017 10:10:53 +0800 Subject: [PATCH 0701/1348] move the backup file to acme home fix https://github.com/Neilpang/acme.sh/issues/488 --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 9929dfad..5ce5b803 100755 --- a/acme.sh +++ b/acme.sh @@ -2059,6 +2059,10 @@ _initpath() { _debug DOMAIN_PATH "$DOMAIN_PATH" fi + if [ -z "$DOMAIN_BACKUP_PATH" ]; then + DOMAIN_BACKUP_PATH="$DOMAIN_PATH" + fi + if [ -z "$DOMAIN_CONF" ]; then DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" fi @@ -3612,7 +3616,7 @@ _installcert() { _info "Installing cert to:$Le_RealCertPath" if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then - cp "$Le_RealCertPath" "$Le_RealCertPath".bak + cp "$Le_RealCertPath" "$DOMAIN_BACKUP_PATH/cert.bak" fi cat "$CERT_PATH" >"$Le_RealCertPath" fi @@ -3625,7 +3629,7 @@ _installcert() { cat "$CA_CERT_PATH" >>"$Le_RealCACertPath" else if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then - cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak + cp "$Le_RealCACertPath" "$DOMAIN_BACKUP_PATH/ca.bak" fi cat "$CA_CERT_PATH" >"$Le_RealCACertPath" fi @@ -3635,7 +3639,7 @@ _installcert() { _info "Installing key to:$Le_RealKeyPath" if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then - cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak + cp "$Le_RealKeyPath" "$DOMAIN_BACKUP_PATH/key.bak" fi cat "$CERT_KEY_PATH" >"$Le_RealKeyPath" fi @@ -3644,7 +3648,7 @@ _installcert() { _info "Installing full chain to:$Le_RealFullChainPath" if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then - cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak + cp "$Le_RealFullChainPath" "$DOMAIN_BACKUP_PATH/fullchain.bak" fi cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath" fi From d88f8e862bc33d4d989be7acb1e1f05049e0163f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 12 Feb 2017 10:20:50 +0800 Subject: [PATCH 0702/1348] move backup to sub folder. --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5ce5b803..f03501b4 100755 --- a/acme.sh +++ b/acme.sh @@ -2060,7 +2060,7 @@ _initpath() { fi if [ -z "$DOMAIN_BACKUP_PATH" ]; then - DOMAIN_BACKUP_PATH="$DOMAIN_PATH" + DOMAIN_BACKUP_PATH="$DOMAIN_PATH/backup" fi if [ -z "$DOMAIN_CONF" ]; then @@ -3616,6 +3616,7 @@ _installcert() { _info "Installing cert to:$Le_RealCertPath" if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then + mkdir -p "$DOMAIN_BACKUP_PATH" cp "$Le_RealCertPath" "$DOMAIN_BACKUP_PATH/cert.bak" fi cat "$CERT_PATH" >"$Le_RealCertPath" @@ -3629,6 +3630,7 @@ _installcert() { cat "$CA_CERT_PATH" >>"$Le_RealCACertPath" else if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then + mkdir -p "$DOMAIN_BACKUP_PATH" cp "$Le_RealCACertPath" "$DOMAIN_BACKUP_PATH/ca.bak" fi cat "$CA_CERT_PATH" >"$Le_RealCACertPath" @@ -3639,6 +3641,7 @@ _installcert() { _info "Installing key to:$Le_RealKeyPath" if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then + mkdir -p "$DOMAIN_BACKUP_PATH" cp "$Le_RealKeyPath" "$DOMAIN_BACKUP_PATH/key.bak" fi cat "$CERT_KEY_PATH" >"$Le_RealKeyPath" @@ -3648,6 +3651,7 @@ _installcert() { _info "Installing full chain to:$Le_RealFullChainPath" if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then + mkdir -p "$DOMAIN_BACKUP_PATH" cp "$Le_RealFullChainPath" "$DOMAIN_BACKUP_PATH/fullchain.bak" fi cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath" From 0ec9b9823f3ff32108bab78f5e2b5f1c0750adf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 00:24:26 +0100 Subject: [PATCH 0703/1348] Add DNS API for cyon.ch --- dnsapi/dns_cyon.sh | 355 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 dnsapi/dns_cyon.sh diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh new file mode 100644 index 00000000..95e690bb --- /dev/null +++ b/dnsapi/dns_cyon.sh @@ -0,0 +1,355 @@ +#!/usr/bin/env sh + +######## +# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/Neilpang/acme.sh) +# +# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com +# +# Dependencies: +# ------------- +# - jq (get it here: https://stedolan.github.io/jq/download) +# - oathtool (When using 2 Factor Authentication) +# +# Author: Armando Lüscher +######## + +######## +# Define cyon.ch login credentials: +# +# Either set them here: (uncomment these lines) +# +# cyon_username='your_cyon_username' +# cyon_password='your_cyon_password' +# cyon_otp_secret='your_otp_secret' # Only required if using 2FA +# +# ...or export them as environment variables in your shell: +# +# $ export cyon_username='your_cyon_username' +# $ export cyon_password='your_cyon_password' +# $ export cyon_otp_secret='your_otp_secret' # Only required if using 2FA +# +# *Note:* +# After the first run, the credentials are saved in the "account.conf" +# file, so any hard-coded or environment variables can then be removed. +######## + +dns_cyon_add() { + if ! _exists jq; then + _fail "Please install jq to use cyon.ch DNS API." + fi + + _load_credentials + _load_parameters "$@" + + _info_header "add" + _login + _domain_env + _add_txt + _cleanup + + return 0 +} + +dns_cyon_rm() { + _load_credentials + _load_parameters "$@" + + _info_header "delete" + _login + _domain_env + _delete_txt + _cleanup + + return 0 +} + +######################### +### PRIVATE FUNCTIONS ### +######################### + +_load_credentials() { + # Convert loaded password to/from base64 as needed. + if [ "${cyon_password_b64}" ] ; then + cyon_password="$(echo "${cyon_password_b64}" | _dbase64)" + elif [ "${cyon_password}" ] ; then + cyon_password_b64="$(echo "${cyon_password}" | _base64)" + fi + + if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ] ; then + _err "" + _err "You haven't set your cyon.ch login credentials yet." + _err "Please set the required cyon environment variables." + _err "" + exit 1 + fi + + # Save the login credentials to the account.conf file. + _debug "Save credentials to account.conf" + _saveaccountconf cyon_username "${cyon_username}" + _saveaccountconf cyon_password_b64 "$cyon_password_b64" + if [ ! -z "${cyon_otp_secret}" ] ; then + _saveaccountconf cyon_otp_secret "$cyon_otp_secret" + fi +} + +_is_idn() { + _idn_temp=$(printf "%s" "$1" | tr -d "[0-9a-zA-Z.,-]") + _idn_temp2="$(printf "%s" "$1" | grep -o "xn--")" + [ "$_idn_temp" ] || [ "$_idn_temp2" ] +} + +_load_parameters() { + # Read the required parameters to add the TXT entry. + fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" + fulldomain_idn="${fulldomain}" + + # Special case for IDNs, as cyon needs a domain environment change, + # which uses the "pretty" instead of the punycode version. + if _is_idn "$1" ; then + if ! _exists idn; then + _fail "Please install idn to process IDN names." + fi + + fulldomain="$(idn -u "${fulldomain}")" + fulldomain_idn="$(idn -a "${fulldomain}")" + fi + + _debug fulldomain "$fulldomain" + _debug fulldomain_idn "$fulldomain_idn" + + txtvalue="$2" + _debug txtvalue "$txtvalue" + + # Cookiejar required for login session, as cyon.ch has no official API (yet). + cookiejar=$(tempfile) + _debug cookiejar "$cookiejar" +} + +_info_header() { + if [ "$1" = "add" ]; then + _info "" + _info "+---------------------------------------------+" + _info "| Adding DNS TXT entry to your cyon.ch domain |" + _info "+---------------------------------------------+" + _info "" + _info " * Full Domain: ${fulldomain}" + _info " * TXT Value: ${txtvalue}" + _info " * Cookie Jar: ${cookiejar}" + _info "" + elif [ "$1" = "delete" ]; then + _info "" + _info "+-------------------------------------------------+" + _info "| Deleting DNS TXT entry from your cyon.ch domain |" + _info "+-------------------------------------------------+" + _info "" + _info " * Full Domain: ${fulldomain}" + _info " * Cookie Jar: ${cookiejar}" + _info "" + fi +} + +_login() { + _info " - Logging in..." + login_response=$(curl \ + "https://my.cyon.ch/auth/index/dologin-async" \ + -s \ + -c "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest" \ + --data-urlencode "username=${cyon_username}" \ + --data-urlencode "password=${cyon_password}" \ + --data-urlencode "pathname=/") + + _debug login_response "${login_response}" + + # Bail if login fails. + if [ "$(echo "${login_response}" | jq -r '.onSuccess')" != "success" ]; then + _fail " $(echo "${login_response}" | jq -r '.message')" + fi + + _info " success" + + + # NECESSARY!! Load the main page after login, before the OTP check. + curl "https://my.cyon.ch/" -s --compressed -b "${cookiejar}" >/dev/null + + + # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. + + + # 2FA authentication with OTP? + if [ ! -z "${cyon_otp_secret}" ] ; then + _info " - Authorising with OTP code..." + + if ! _exists oathtool; then + _fail "Please install oathtool to use 2 Factor Authentication." + fi + + # Get OTP code with the defined secret. + otp_code=$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null) + + otp_response=$(curl \ + "https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" \ + -s \ + --compressed \ + -b "${cookiejar}" \ + -c "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest" \ + -d "totpcode=${otp_code}&pathname=%2F&rememberme=0") + + _debug otp_response "${otp_response}" + + # Bail if OTP authentication fails. + if [ "$(echo "${otp_response}" | jq -r '.onSuccess')" != "success" ]; then + _fail " $(echo "${otp_response}" | jq -r '.message')" + fi + + _info " success" + fi + + _info "" +} + +_domain_env() { + _info " - Changing domain environment..." + + # Get the "example.com" part of the full domain name. + domain_env=$(echo "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/') + _debug "Changing domain environment to ${domain_env}" + + domain_env_response=$(curl \ + "https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" \ + -s \ + --compressed \ + -b "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest") + + _debug domain_env_response "${domain_env_response}" + + _check_2fa_miss "${domain_env_response}" + + domain_env_success=$(echo "${domain_env_response}" | jq -r '.authenticated') + + # Bail if domain environment change fails. + if [ "${domain_env_success}" != "true" ]; then + _fail " $(echo "${domain_env_response}" | jq -r '.message')" + fi + + _info " success" + _info "" +} + +_add_txt() { + _info " - Adding DNS TXT entry..." + addtxt_response=$(curl \ + "https://my.cyon.ch/domain/dnseditor/add-record-async" \ + -s \ + --compressed \ + -b "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest" \ + -d "zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}") + + _debug addtxt_response "${addtxt_response}" + + _check_2fa_miss "${addtxt_response}" + + addtxt_message=$(echo "${addtxt_response}" | jq -r '.message') + addtxt_status=$(echo "${addtxt_response}" | jq -r '.status') + + # Bail if adding TXT entry fails. + if [ "${addtxt_status}" != "true" ]; then + if [ "${addtxt_status}" = "null" ]; then + addtxt_message=$(echo "${addtxt_response}" | jq -r '.error.message') + fi + _fail " ${addtxt_message}" + fi + + _info " success" + _info "" +} + +_delete_txt() { + _info " - Deleting DNS TXT entry..." + + list_txt_response=$(curl \ + "https://my.cyon.ch/domain/dnseditor/list-async" \ + -s \ + -b "${cookiejar}" \ + --compressed \ + -H "X-Requested-With: XMLHttpRequest") + + _debug list_txt_response "${list_txt_response}" + + _check_2fa_miss "${list_txt_response}" + + # Find and delete all acme challenge entries for the $fulldomain. + _dns_entries=$(echo "$list_txt_response" | jq -r --arg fulldomain_idn "${fulldomain_idn}." ' + .rows[] | + label $out| + if .[0] != $fulldomain_idn then + break $out + else + .[4]| + capture("data-hash=\"(?[^\"]*)\" data-identifier=\"(?[^\"]*)\"";"g")| + .hash + " " + .identifier + end') + _dns_entries_cnt=$(echo "${_dns_entries}" | wc -l | grep -o '\d') + + _info " (entries found: ${_dns_entries_cnt})" + + _dns_entry_num=0 + + echo "${_dns_entries}" | while read -r _hash _identifier + do + ((_dns_entry_num++)) + + delete_txt_response=$(curl \ + "https://my.cyon.ch/domain/dnseditor/delete-record-async" \ + -s \ + --compressed \ + -b "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest" \ + --data-urlencode "hash=${_hash}" \ + --data-urlencode "identifier=${_identifier}") + + _debug delete_txt_response "${delete_txt_response}" + + _check_2fa_miss "${delete_txt_response}" + + delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.message') + delete_txt_status=$(echo "${delete_txt_response}" | jq -r '.status') + + # Skip if deleting TXT entry fails. + if [ "${delete_txt_status}" != "true" ]; then + if [ "${delete_txt_status}" = "null" ]; then + delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.error.message') + fi + _err " [${_dns_entry_num}/${_dns_entries_cnt}] ${delete_txt_message} (${_identifier})" + else + _info " [${_dns_entry_num}/${_dns_entries_cnt}] success (${_identifier})" + fi + done + + _info " done" + _info "" +} + +_check_2fa_miss() { + # Did we miss the 2FA? + if [[ "$1" =~ "multi_factor_form" ]] ; then + _fail " Missed OTP authentication!" + fi +} + +_fail() { + _err "$1" + _err "" + _cleanup + exit 1 +} + +_cleanup() { + _info " - Cleanup." + _debug "Remove cookie jar: ${cookiejar}" + rm "${cookiejar}" 2>/dev/null + _info "" +} From c90fa3bcfc71f298cdbb1f2207df981ffc126c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 00:45:56 +0100 Subject: [PATCH 0704/1348] Fix problems found by travis. --- dnsapi/dns_cyon.sh | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 95e690bb..3ebd3099 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -69,13 +69,16 @@ dns_cyon_rm() { _load_credentials() { # Convert loaded password to/from base64 as needed. - if [ "${cyon_password_b64}" ] ; then + if [ "${cyon_password_b64}" ]; then cyon_password="$(echo "${cyon_password_b64}" | _dbase64)" - elif [ "${cyon_password}" ] ; then + elif [ "${cyon_password}" ]; then cyon_password_b64="$(echo "${cyon_password}" | _base64)" fi - if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ] ; then + if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then + cyon_username="" + cyon_password="" + cyon_otp_secret="" _err "" _err "You haven't set your cyon.ch login credentials yet." _err "Please set the required cyon environment variables." @@ -87,7 +90,7 @@ _load_credentials() { _debug "Save credentials to account.conf" _saveaccountconf cyon_username "${cyon_username}" _saveaccountconf cyon_password_b64 "$cyon_password_b64" - if [ ! -z "${cyon_otp_secret}" ] ; then + if [ ! -z "${cyon_otp_secret}" ]; then _saveaccountconf cyon_otp_secret "$cyon_otp_secret" fi } @@ -105,7 +108,7 @@ _load_parameters() { # Special case for IDNs, as cyon needs a domain environment change, # which uses the "pretty" instead of the punycode version. - if _is_idn "$1" ; then + if _is_idn "$1"; then if ! _exists idn; then _fail "Please install idn to process IDN names." fi @@ -168,16 +171,13 @@ _login() { _info " success" - # NECESSARY!! Load the main page after login, before the OTP check. curl "https://my.cyon.ch/" -s --compressed -b "${cookiejar}" >/dev/null - # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. - # 2FA authentication with OTP? - if [ ! -z "${cyon_otp_secret}" ] ; then + if [ ! -z "${cyon_otp_secret}" ]; then _info " - Authorising with OTP code..." if ! _exists oathtool; then @@ -298,9 +298,8 @@ _delete_txt() { _dns_entry_num=0 - echo "${_dns_entries}" | while read -r _hash _identifier - do - ((_dns_entry_num++)) + echo "${_dns_entries}" | while read -r _hash _identifier; do + _dns_entry_num=$((_dns_entry_num + 1)) delete_txt_response=$(curl \ "https://my.cyon.ch/domain/dnseditor/delete-record-async" \ @@ -335,7 +334,7 @@ _delete_txt() { _check_2fa_miss() { # Did we miss the 2FA? - if [[ "$1" =~ "multi_factor_form" ]] ; then + if test "${1#*multi_factor_form}" != "$1"; then _fail " Missed OTP authentication!" fi } From 0085e6f83bbf78bffd8f34681be6e6d6865a19a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 15:21:04 +0100 Subject: [PATCH 0705/1348] Don't use jq to fetch list of DNS entries to be deleted. --- dnsapi/dns_cyon.sh | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 3ebd3099..605585e6 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -275,31 +275,23 @@ _delete_txt() { -s \ -b "${cookiejar}" \ --compressed \ - -H "X-Requested-With: XMLHttpRequest") + -H "X-Requested-With: XMLHttpRequest" | \ + sed -e 's/data-hash/\\ndata-hash/g') _debug list_txt_response "${list_txt_response}" _check_2fa_miss "${list_txt_response}" # Find and delete all acme challenge entries for the $fulldomain. - _dns_entries=$(echo "$list_txt_response" | jq -r --arg fulldomain_idn "${fulldomain_idn}." ' - .rows[] | - label $out| - if .[0] != $fulldomain_idn then - break $out - else - .[4]| - capture("data-hash=\"(?[^\"]*)\" data-identifier=\"(?[^\"]*)\"";"g")| - .hash + " " + .identifier - end') - _dns_entries_cnt=$(echo "${_dns_entries}" | wc -l | grep -o '\d') - - _info " (entries found: ${_dns_entries_cnt})" - - _dns_entry_num=0 + _dns_entries=$(echo -e "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p') echo "${_dns_entries}" | while read -r _hash _identifier; do - _dns_entry_num=$((_dns_entry_num + 1)) + dns_type="$(echo "$_identifier" | cut -d'|' -f1)" + dns_domain="$(echo "$_identifier" | cut -d'|' -f2)" + + if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then + continue + fi delete_txt_response=$(curl \ "https://my.cyon.ch/domain/dnseditor/delete-record-async" \ @@ -322,9 +314,9 @@ _delete_txt() { if [ "${delete_txt_status}" = "null" ]; then delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.error.message') fi - _err " [${_dns_entry_num}/${_dns_entries_cnt}] ${delete_txt_message} (${_identifier})" + _err " ${delete_txt_message} (${_identifier})" else - _info " [${_dns_entry_num}/${_dns_entries_cnt}] success (${_identifier})" + _info " success (${_identifier})" fi done From e7ee3a7dd55dc505b0cfb959b15161fb35704272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 18:06:16 +0100 Subject: [PATCH 0706/1348] Remove jq completely to not require it as a dependency. --- dnsapi/dns_cyon.sh | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 605585e6..af5a225b 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -7,7 +7,6 @@ # # Dependencies: # ------------- -# - jq (get it here: https://stedolan.github.io/jq/download) # - oathtool (When using 2 Factor Authentication) # # Author: Armando Lüscher @@ -34,10 +33,6 @@ ######## dns_cyon_add() { - if ! _exists jq; then - _fail "Please install jq to use cyon.ch DNS API." - fi - _load_credentials _load_parameters "$@" @@ -165,8 +160,8 @@ _login() { _debug login_response "${login_response}" # Bail if login fails. - if [ "$(echo "${login_response}" | jq -r '.onSuccess')" != "success" ]; then - _fail " $(echo "${login_response}" | jq -r '.message')" + if [ "$(echo "${login_response}" | _get_response_success)" != "success" ]; then + _fail " $(echo "${login_response}" | _get_response_message)" fi _info " success" @@ -199,8 +194,8 @@ _login() { _debug otp_response "${otp_response}" # Bail if OTP authentication fails. - if [ "$(echo "${otp_response}" | jq -r '.onSuccess')" != "success" ]; then - _fail " $(echo "${otp_response}" | jq -r '.message')" + if [ "$(echo "${otp_response}" | _get_response_success)" != "success" ]; then + _fail " $(echo "${otp_response}" | _get_response_message)" fi _info " success" @@ -227,11 +222,11 @@ _domain_env() { _check_2fa_miss "${domain_env_response}" - domain_env_success=$(echo "${domain_env_response}" | jq -r '.authenticated') + domain_env_success=$(echo "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2) # Bail if domain environment change fails. if [ "${domain_env_success}" != "true" ]; then - _fail " $(echo "${domain_env_response}" | jq -r '.message')" + _fail " $(echo "${domain_env_response}" | _get_response_message)" fi _info " success" @@ -252,14 +247,11 @@ _add_txt() { _check_2fa_miss "${addtxt_response}" - addtxt_message=$(echo "${addtxt_response}" | jq -r '.message') - addtxt_status=$(echo "${addtxt_response}" | jq -r '.status') + addtxt_message=$(echo "${addtxt_response}" | _get_response_message) + addtxt_status=$(echo "${addtxt_response}" | _get_response_status) # Bail if adding TXT entry fails. if [ "${addtxt_status}" != "true" ]; then - if [ "${addtxt_status}" = "null" ]; then - addtxt_message=$(echo "${addtxt_response}" | jq -r '.error.message') - fi _fail " ${addtxt_message}" fi @@ -306,14 +298,11 @@ _delete_txt() { _check_2fa_miss "${delete_txt_response}" - delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.message') - delete_txt_status=$(echo "${delete_txt_response}" | jq -r '.status') + delete_txt_message=$(echo "${delete_txt_response}" | _get_response_message) + delete_txt_status=$(echo "${delete_txt_response}" | _get_response_status) # Skip if deleting TXT entry fails. if [ "${delete_txt_status}" != "true" ]; then - if [ "${delete_txt_status}" = "null" ]; then - delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.error.message') - fi _err " ${delete_txt_message} (${_identifier})" else _info " success (${_identifier})" @@ -324,6 +313,18 @@ _delete_txt() { _info "" } +_get_response_message() { + _egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"' +} + +_get_response_status() { + _egrep_o '"status":\w*' | cut -d : -f 2 +} + +_get_response_success() { + _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' +} + _check_2fa_miss() { # Did we miss the 2FA? if test "${1#*multi_factor_form}" != "$1"; then From 46b2ee3bae604619e3d191085581846853e25ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 18:31:38 +0100 Subject: [PATCH 0707/1348] Replace all echos with printf. --- dnsapi/dns_cyon.sh | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index af5a225b..28cb9e6e 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -65,9 +65,9 @@ dns_cyon_rm() { _load_credentials() { # Convert loaded password to/from base64 as needed. if [ "${cyon_password_b64}" ]; then - cyon_password="$(echo "${cyon_password_b64}" | _dbase64)" + cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64)" elif [ "${cyon_password}" ]; then - cyon_password_b64="$(echo "${cyon_password}" | _base64)" + cyon_password_b64="$(printf "%s" "${cyon_password}" | _base64)" fi if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then @@ -98,7 +98,7 @@ _is_idn() { _load_parameters() { # Read the required parameters to add the TXT entry. - fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" + fulldomain="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, @@ -160,8 +160,8 @@ _login() { _debug login_response "${login_response}" # Bail if login fails. - if [ "$(echo "${login_response}" | _get_response_success)" != "success" ]; then - _fail " $(echo "${login_response}" | _get_response_message)" + if [ "$(printf "%s" "${login_response}" | _get_response_success)" != "success" ]; then + _fail " $(printf "%s" "${login_response}" | _get_response_message)" fi _info " success" @@ -194,8 +194,8 @@ _login() { _debug otp_response "${otp_response}" # Bail if OTP authentication fails. - if [ "$(echo "${otp_response}" | _get_response_success)" != "success" ]; then - _fail " $(echo "${otp_response}" | _get_response_message)" + if [ "$(printf "%s" "${otp_response}" | _get_response_success)" != "success" ]; then + _fail " $(printf "%s" "${otp_response}" | _get_response_message)" fi _info " success" @@ -208,7 +208,7 @@ _domain_env() { _info " - Changing domain environment..." # Get the "example.com" part of the full domain name. - domain_env=$(echo "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/') + domain_env=$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/') _debug "Changing domain environment to ${domain_env}" domain_env_response=$(curl \ @@ -222,11 +222,11 @@ _domain_env() { _check_2fa_miss "${domain_env_response}" - domain_env_success=$(echo "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2) + domain_env_success=$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2) # Bail if domain environment change fails. if [ "${domain_env_success}" != "true" ]; then - _fail " $(echo "${domain_env_response}" | _get_response_message)" + _fail " $(printf "%s" "${domain_env_response}" | _get_response_message)" fi _info " success" @@ -247,8 +247,8 @@ _add_txt() { _check_2fa_miss "${addtxt_response}" - addtxt_message=$(echo "${addtxt_response}" | _get_response_message) - addtxt_status=$(echo "${addtxt_response}" | _get_response_status) + addtxt_message=$(printf "%s" "${addtxt_response}" | _get_response_message) + addtxt_status=$(printf "%s" "${addtxt_response}" | _get_response_status) # Bail if adding TXT entry fails. if [ "${addtxt_status}" != "true" ]; then @@ -267,19 +267,19 @@ _delete_txt() { -s \ -b "${cookiejar}" \ --compressed \ - -H "X-Requested-With: XMLHttpRequest" | \ - sed -e 's/data-hash/\\ndata-hash/g') + -H "X-Requested-With: XMLHttpRequest" \ + | sed -e 's/data-hash/\\ndata-hash/g') _debug list_txt_response "${list_txt_response}" _check_2fa_miss "${list_txt_response}" # Find and delete all acme challenge entries for the $fulldomain. - _dns_entries=$(echo -e "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p') + _dns_entries=$(printf "%s" "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p') - echo "${_dns_entries}" | while read -r _hash _identifier; do - dns_type="$(echo "$_identifier" | cut -d'|' -f1)" - dns_domain="$(echo "$_identifier" | cut -d'|' -f2)" + printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do + dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)" + dns_domain="$(printf "%s" "$_identifier" | cut -d'|' -f2)" if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then continue @@ -298,8 +298,8 @@ _delete_txt() { _check_2fa_miss "${delete_txt_response}" - delete_txt_message=$(echo "${delete_txt_response}" | _get_response_message) - delete_txt_status=$(echo "${delete_txt_response}" | _get_response_status) + delete_txt_message=$(printf "%s" "${delete_txt_response}" | _get_response_message) + delete_txt_status=$(printf "%s" "${delete_txt_response}" | _get_response_status) # Skip if deleting TXT entry fails. if [ "${delete_txt_status}" != "true" ]; then From 2698ef6c5f7795703c49c49e8225d6e99e94dc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 23 Nov 2016 11:16:51 +0100 Subject: [PATCH 0708/1348] Return instead of exit. Clear OTP secret if environment variable is set to empty. This is for when the 2FA is disabled. Rename `_is_idn` function to `_is_idn_cyon`. Remove usage of curl (except for URL encoding of data). Instead of cleaning up the cookie jar, get rid of it completely and logout of cyon instead. --- dnsapi/dns_cyon.sh | 242 ++++++++++++++++++++++----------------------- 1 file changed, 118 insertions(+), 124 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 28cb9e6e..05079351 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -33,29 +33,23 @@ ######## dns_cyon_add() { - _load_credentials - _load_parameters "$@" - - _info_header "add" - _login - _domain_env - _add_txt - _cleanup - - return 0 + _load_credentials \ + && _load_parameters "$@" \ + && _info_header "add" \ + && _login \ + && _domain_env \ + && _add_txt \ + && _logout } dns_cyon_rm() { - _load_credentials - _load_parameters "$@" - - _info_header "delete" - _login - _domain_env - _delete_txt - _cleanup - - return 0 + _load_credentials \ + && _load_parameters "$@" \ + && _info_header "delete" \ + && _login \ + && _domain_env \ + && _delete_txt \ + && _logout } ######################### @@ -65,20 +59,22 @@ dns_cyon_rm() { _load_credentials() { # Convert loaded password to/from base64 as needed. if [ "${cyon_password_b64}" ]; then - cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64)" + cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64 "multiline")" elif [ "${cyon_password}" ]; then cyon_password_b64="$(printf "%s" "${cyon_password}" | _base64)" fi if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then + # Dummy entries to satify script checker. cyon_username="" cyon_password="" cyon_otp_secret="" + _err "" _err "You haven't set your cyon.ch login credentials yet." _err "Please set the required cyon environment variables." _err "" - exit 1 + return 1 fi # Save the login credentials to the account.conf file. @@ -87,44 +83,52 @@ _load_credentials() { _saveaccountconf cyon_password_b64 "$cyon_password_b64" if [ ! -z "${cyon_otp_secret}" ]; then _saveaccountconf cyon_otp_secret "$cyon_otp_secret" + else + _clearaccountconf cyon_otp_secret fi } -_is_idn() { - _idn_temp=$(printf "%s" "$1" | tr -d "[0-9a-zA-Z.,-]") - _idn_temp2="$(printf "%s" "$1" | grep -o "xn--")" +_is_idn_cyon() { + _idn_temp="$(printf "%s" "${1}" | tr -d "[0-9a-zA-Z.,-_]")" + _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" [ "$_idn_temp" ] || [ "$_idn_temp2" ] } +# comment on https://stackoverflow.com/a/10797966 +_urlencode_cyon() { + curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3- +} + _load_parameters() { # Read the required parameters to add the TXT entry. - fulldomain="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')" + fulldomain="$(printf "%s" "${1}" | tr '[:upper:]' '[:lower:]')" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, # which uses the "pretty" instead of the punycode version. - if _is_idn "$1"; then + if _is_idn_cyon "${fulldomain}"; then if ! _exists idn; then - _fail "Please install idn to process IDN names." + _err "Please install idn to process IDN names." + _err "" + return 1 fi fulldomain="$(idn -u "${fulldomain}")" fulldomain_idn="$(idn -a "${fulldomain}")" fi - _debug fulldomain "$fulldomain" - _debug fulldomain_idn "$fulldomain_idn" + _debug fulldomain "${fulldomain}" + _debug fulldomain_idn "${fulldomain_idn}" - txtvalue="$2" - _debug txtvalue "$txtvalue" + txtvalue="${2}" + _debug txtvalue "${txtvalue}" - # Cookiejar required for login session, as cyon.ch has no official API (yet). - cookiejar=$(tempfile) - _debug cookiejar "$cookiejar" + # This header is required for curl calls. + _H1="X-Requested-With: XMLHttpRequest" } _info_header() { - if [ "$1" = "add" ]; then + if [ "${1}" = "add" ]; then _info "" _info "+---------------------------------------------+" _info "| Adding DNS TXT entry to your cyon.ch domain |" @@ -132,42 +136,46 @@ _info_header() { _info "" _info " * Full Domain: ${fulldomain}" _info " * TXT Value: ${txtvalue}" - _info " * Cookie Jar: ${cookiejar}" _info "" - elif [ "$1" = "delete" ]; then + elif [ "${1}" = "delete" ]; then _info "" _info "+-------------------------------------------------+" _info "| Deleting DNS TXT entry from your cyon.ch domain |" _info "+-------------------------------------------------+" _info "" _info " * Full Domain: ${fulldomain}" - _info " * Cookie Jar: ${cookiejar}" _info "" fi } +_get_cookie_header() { + printf "%s" "$(sed -n 's/Set-\(Cookie:.*cyon=[^;]*\).*/\1/p' "$HTTP_HEADER" | _tail_n 1)" +} + _login() { _info " - Logging in..." - login_response=$(curl \ - "https://my.cyon.ch/auth/index/dologin-async" \ - -s \ - -c "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest" \ - --data-urlencode "username=${cyon_username}" \ - --data-urlencode "password=${cyon_password}" \ - --data-urlencode "pathname=/") + username_encoded="$(printf "%s" "${cyon_username}" | _urlencode_cyon)" + password_encoded="$(printf "%s" "${cyon_password}" | _urlencode_cyon)" + + login_url="https://my.cyon.ch/auth/index/dologin-async" + login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" + + login_response="$(_post "$login_data" "$login_url")" _debug login_response "${login_response}" # Bail if login fails. if [ "$(printf "%s" "${login_response}" | _get_response_success)" != "success" ]; then - _fail " $(printf "%s" "${login_response}" | _get_response_message)" + _err " $(printf "%s" "${login_response}" | _get_response_message)" + _err "" + return 1 fi _info " success" - # NECESSARY!! Load the main page after login, before the OTP check. - curl "https://my.cyon.ch/" -s --compressed -b "${cookiejar}" >/dev/null + # NECESSARY!! Load the main page after login, to get the new cookie. + _H2="$(_get_cookie_header)" + _get "https://my.cyon.ch/" > /dev/null # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. @@ -176,26 +184,25 @@ _login() { _info " - Authorising with OTP code..." if ! _exists oathtool; then - _fail "Please install oathtool to use 2 Factor Authentication." + _err "Please install oathtool to use 2 Factor Authentication." + _err "" + return 1 fi # Get OTP code with the defined secret. - otp_code=$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null) + otp_code="$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null)" - otp_response=$(curl \ - "https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" \ - -s \ - --compressed \ - -b "${cookiejar}" \ - -c "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest" \ - -d "totpcode=${otp_code}&pathname=%2F&rememberme=0") + login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" + login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0" - _debug otp_response "${otp_response}" + login_otp_response="$(_post "$login_otp_data" "$login_otp_url")" + _debug login_otp_response "${login_otp_response}" # Bail if OTP authentication fails. - if [ "$(printf "%s" "${otp_response}" | _get_response_success)" != "success" ]; then - _fail " $(printf "%s" "${otp_response}" | _get_response_message)" + if [ "$(printf "%s" "${login_otp_response}" | _get_response_success)" != "success" ]; then + _err " $(printf "%s" "${login_otp_response}" | _get_response_message)" + _err "" + return 1 fi _info " success" @@ -204,29 +211,36 @@ _login() { _info "" } +_logout() { + _info " - Logging out..." + + _get "https://my.cyon.ch/auth/index/dologout" > /dev/null + + _info " success" + _info "" +} + _domain_env() { _info " - Changing domain environment..." # Get the "example.com" part of the full domain name. - domain_env=$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/') + domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')" _debug "Changing domain environment to ${domain_env}" - domain_env_response=$(curl \ - "https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" \ - -s \ - --compressed \ - -b "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest") + domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" + domain_env_response="$(_get "${domain_env_url}")" _debug domain_env_response "${domain_env_response}" - _check_2fa_miss "${domain_env_response}" + if ! _check_if_2fa_missed "${domain_env_response}"; then return 1; fi - domain_env_success=$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2) + domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)" # Bail if domain environment change fails. if [ "${domain_env_success}" != "true" ]; then - _fail " $(printf "%s" "${domain_env_response}" | _get_response_message)" + _err " $(printf "%s" "${domain_env_response}" | _get_response_message)" + _err "" + return 1 fi _info " success" @@ -235,47 +249,41 @@ _domain_env() { _add_txt() { _info " - Adding DNS TXT entry..." - addtxt_response=$(curl \ - "https://my.cyon.ch/domain/dnseditor/add-record-async" \ - -s \ - --compressed \ - -b "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest" \ - -d "zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}") - _debug addtxt_response "${addtxt_response}" + add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async" + add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}" - _check_2fa_miss "${addtxt_response}" + add_txt_response="$(_post "$add_txt_data" "$add_txt_url")" + _debug add_txt_response "${add_txt_response}" - addtxt_message=$(printf "%s" "${addtxt_response}" | _get_response_message) - addtxt_status=$(printf "%s" "${addtxt_response}" | _get_response_status) + if ! _check_if_2fa_missed "${add_txt_response}"; then return 1; fi + + add_txt_message="$(printf "%s" "${add_txt_response}" | _get_response_message)" + add_txt_status="$(printf "%s" "${add_txt_response}" | _get_response_status)" # Bail if adding TXT entry fails. - if [ "${addtxt_status}" != "true" ]; then - _fail " ${addtxt_message}" + if [ "${add_txt_status}" != "true" ]; then + _err " ${add_txt_message}" + _err "" + return 1 fi - _info " success" + _info " success (TXT|${fulldomain_idn}.|${txtvalue})" _info "" } _delete_txt() { _info " - Deleting DNS TXT entry..." - list_txt_response=$(curl \ - "https://my.cyon.ch/domain/dnseditor/list-async" \ - -s \ - -b "${cookiejar}" \ - --compressed \ - -H "X-Requested-With: XMLHttpRequest" \ - | sed -e 's/data-hash/\\ndata-hash/g') + list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async" + list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')" _debug list_txt_response "${list_txt_response}" - _check_2fa_miss "${list_txt_response}" + if ! _check_if_2fa_missed "${list_txt_response}"; then return 1; fi # Find and delete all acme challenge entries for the $fulldomain. - _dns_entries=$(printf "%s" "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p') + _dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')" printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)" @@ -285,21 +293,19 @@ _delete_txt() { continue fi - delete_txt_response=$(curl \ - "https://my.cyon.ch/domain/dnseditor/delete-record-async" \ - -s \ - --compressed \ - -b "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest" \ - --data-urlencode "hash=${_hash}" \ - --data-urlencode "identifier=${_identifier}") + hash_encoded="$(printf "%s" "${_hash}" | _urlencode_cyon)" + identifier_encoded="$(printf "%s" "${_identifier}" | _urlencode_cyon)" + + delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" + delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" + delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")" _debug delete_txt_response "${delete_txt_response}" - _check_2fa_miss "${delete_txt_response}" + if ! _check_if_2fa_missed "${delete_txt_response}"; then return 1; fi - delete_txt_message=$(printf "%s" "${delete_txt_response}" | _get_response_message) - delete_txt_status=$(printf "%s" "${delete_txt_response}" | _get_response_status) + delete_txt_message="$(printf "%s" "${delete_txt_response}" | _get_response_message)" + delete_txt_status="$(printf "%s" "${delete_txt_response}" | _get_response_status)" # Skip if deleting TXT entry fails. if [ "${delete_txt_status}" != "true" ]; then @@ -325,23 +331,11 @@ _get_response_success() { _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' } -_check_2fa_miss() { +_check_if_2fa_missed() { # Did we miss the 2FA? - if test "${1#*multi_factor_form}" != "$1"; then - _fail " Missed OTP authentication!" - fi -} - -_fail() { - _err "$1" + if test "${1#*multi_factor_form}" != "${1}"; then + _err " Missed OTP authentication!" _err "" - _cleanup - exit 1 -} - -_cleanup() { - _info " - Cleanup." - _debug "Remove cookie jar: ${cookiejar}" - rm "${cookiejar}" 2>/dev/null - _info "" + return 1 + fi } From 98b3dcbf37fd462609b92e72080542e4b01b48c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 16 Dec 2016 03:44:48 +0100 Subject: [PATCH 0709/1348] Prefix all private functions with `_cyon`. Satisfy shellcheck. --- dnsapi/dns_cyon.sh | 106 ++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 05079351..3a441aaf 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -33,30 +33,30 @@ ######## dns_cyon_add() { - _load_credentials \ - && _load_parameters "$@" \ - && _info_header "add" \ - && _login \ - && _domain_env \ - && _add_txt \ - && _logout + _cyon_load_credentials \ + && _cyon_load_parameters "$@" \ + && _cyon_print_header "add" \ + && _cyon_login \ + && _cyon_change_domain_env \ + && _cyon_add_txt \ + && _cyon_logout } dns_cyon_rm() { - _load_credentials \ - && _load_parameters "$@" \ - && _info_header "delete" \ - && _login \ - && _domain_env \ - && _delete_txt \ - && _logout + _cyon_load_credentials \ + && _cyon_load_parameters "$@" \ + && _cyon_print_header "delete" \ + && _cyon_login \ + && _cyon_change_domain_env \ + && _cyon_delete_txt \ + && _cyon_logout } ######################### ### PRIVATE FUNCTIONS ### ######################### -_load_credentials() { +_cyon_load_credentials() { # Convert loaded password to/from base64 as needed. if [ "${cyon_password_b64}" ]; then cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64 "multiline")" @@ -88,25 +88,25 @@ _load_credentials() { fi } -_is_idn_cyon() { +_cyon_is_idn() { _idn_temp="$(printf "%s" "${1}" | tr -d "[0-9a-zA-Z.,-_]")" _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" [ "$_idn_temp" ] || [ "$_idn_temp2" ] } # comment on https://stackoverflow.com/a/10797966 -_urlencode_cyon() { - curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3- +_cyon_urlencode() { + curl -Gso /dev/null -w "%{url_effective}" --data-urlencode @- "" | cut -c 3- } -_load_parameters() { +_cyon_load_parameters() { # Read the required parameters to add the TXT entry. fulldomain="$(printf "%s" "${1}" | tr '[:upper:]' '[:lower:]')" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, # which uses the "pretty" instead of the punycode version. - if _is_idn_cyon "${fulldomain}"; then + if _cyon_is_idn "${fulldomain}"; then if ! _exists idn; then _err "Please install idn to process IDN names." _err "" @@ -127,7 +127,7 @@ _load_parameters() { _H1="X-Requested-With: XMLHttpRequest" } -_info_header() { +_cyon_print_header() { if [ "${1}" = "add" ]; then _info "" _info "+---------------------------------------------+" @@ -148,15 +148,15 @@ _info_header() { fi } -_get_cookie_header() { +_cyon_get_cookie_header() { printf "%s" "$(sed -n 's/Set-\(Cookie:.*cyon=[^;]*\).*/\1/p' "$HTTP_HEADER" | _tail_n 1)" } -_login() { +_cyon_login() { _info " - Logging in..." - username_encoded="$(printf "%s" "${cyon_username}" | _urlencode_cyon)" - password_encoded="$(printf "%s" "${cyon_password}" | _urlencode_cyon)" + username_encoded="$(printf "%s" "${cyon_username}" | _cyon_urlencode)" + password_encoded="$(printf "%s" "${cyon_password}" | _cyon_urlencode)" login_url="https://my.cyon.ch/auth/index/dologin-async" login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" @@ -165,8 +165,8 @@ _login() { _debug login_response "${login_response}" # Bail if login fails. - if [ "$(printf "%s" "${login_response}" | _get_response_success)" != "success" ]; then - _err " $(printf "%s" "${login_response}" | _get_response_message)" + if [ "$(printf "%s" "${login_response}" | _cyon_get_response_success)" != "success" ]; then + _err " $(printf "%s" "${login_response}" | _cyon_get_response_message)" _err "" return 1 fi @@ -174,8 +174,8 @@ _login() { _info " success" # NECESSARY!! Load the main page after login, to get the new cookie. - _H2="$(_get_cookie_header)" - _get "https://my.cyon.ch/" > /dev/null + _H2="$(_cyon_get_cookie_header)" + _get "https://my.cyon.ch/" >/dev/null # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. @@ -199,8 +199,8 @@ _login() { _debug login_otp_response "${login_otp_response}" # Bail if OTP authentication fails. - if [ "$(printf "%s" "${login_otp_response}" | _get_response_success)" != "success" ]; then - _err " $(printf "%s" "${login_otp_response}" | _get_response_message)" + if [ "$(printf "%s" "${login_otp_response}" | _cyon_get_response_success)" != "success" ]; then + _err " $(printf "%s" "${login_otp_response}" | _cyon_get_response_message)" _err "" return 1 fi @@ -211,16 +211,16 @@ _login() { _info "" } -_logout() { +_cyon_logout() { _info " - Logging out..." - _get "https://my.cyon.ch/auth/index/dologout" > /dev/null + _get "https://my.cyon.ch/auth/index/dologout" >/dev/null _info " success" _info "" } -_domain_env() { +_cyon_change_domain_env() { _info " - Changing domain environment..." # Get the "example.com" part of the full domain name. @@ -232,13 +232,13 @@ _domain_env() { domain_env_response="$(_get "${domain_env_url}")" _debug domain_env_response "${domain_env_response}" - if ! _check_if_2fa_missed "${domain_env_response}"; then return 1; fi + if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)" # Bail if domain environment change fails. if [ "${domain_env_success}" != "true" ]; then - _err " $(printf "%s" "${domain_env_response}" | _get_response_message)" + _err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)" _err "" return 1 fi @@ -247,7 +247,7 @@ _domain_env() { _info "" } -_add_txt() { +_cyon_add_txt() { _info " - Adding DNS TXT entry..." add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async" @@ -256,10 +256,10 @@ _add_txt() { add_txt_response="$(_post "$add_txt_data" "$add_txt_url")" _debug add_txt_response "${add_txt_response}" - if ! _check_if_2fa_missed "${add_txt_response}"; then return 1; fi + if ! _cyon_check_if_2fa_missed "${add_txt_response}"; then return 1; fi - add_txt_message="$(printf "%s" "${add_txt_response}" | _get_response_message)" - add_txt_status="$(printf "%s" "${add_txt_response}" | _get_response_status)" + add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)" + add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)" # Bail if adding TXT entry fails. if [ "${add_txt_status}" != "true" ]; then @@ -272,7 +272,7 @@ _add_txt() { _info "" } -_delete_txt() { +_cyon_delete_txt() { _info " - Deleting DNS TXT entry..." list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async" @@ -280,7 +280,7 @@ _delete_txt() { list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')" _debug list_txt_response "${list_txt_response}" - if ! _check_if_2fa_missed "${list_txt_response}"; then return 1; fi + if ! _cyon_check_if_2fa_missed "${list_txt_response}"; then return 1; fi # Find and delete all acme challenge entries for the $fulldomain. _dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')" @@ -293,8 +293,8 @@ _delete_txt() { continue fi - hash_encoded="$(printf "%s" "${_hash}" | _urlencode_cyon)" - identifier_encoded="$(printf "%s" "${_identifier}" | _urlencode_cyon)" + hash_encoded="$(printf "%s" "${_hash}" | _cyon_urlencode)" + identifier_encoded="$(printf "%s" "${_identifier}" | _cyon_urlencode)" delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" @@ -302,10 +302,10 @@ _delete_txt() { delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")" _debug delete_txt_response "${delete_txt_response}" - if ! _check_if_2fa_missed "${delete_txt_response}"; then return 1; fi + if ! _cyon_check_if_2fa_missed "${delete_txt_response}"; then return 1; fi - delete_txt_message="$(printf "%s" "${delete_txt_response}" | _get_response_message)" - delete_txt_status="$(printf "%s" "${delete_txt_response}" | _get_response_status)" + delete_txt_message="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_message)" + delete_txt_status="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_status)" # Skip if deleting TXT entry fails. if [ "${delete_txt_status}" != "true" ]; then @@ -319,23 +319,23 @@ _delete_txt() { _info "" } -_get_response_message() { +_cyon_get_response_message() { _egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"' } -_get_response_status() { +_cyon_get_response_status() { _egrep_o '"status":\w*' | cut -d : -f 2 } -_get_response_success() { +_cyon_get_response_success() { _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' } -_check_if_2fa_missed() { +_cyon_check_if_2fa_missed() { # Did we miss the 2FA? if test "${1#*multi_factor_form}" != "${1}"; then _err " Missed OTP authentication!" - _err "" - return 1 + _err "" + return 1 fi } From edfefb6763e6e2ecc523aac762e4db4d247bf72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 27 Dec 2016 00:56:05 +0100 Subject: [PATCH 0710/1348] Add usage instructions and repo link to post issues. --- README.md | 1 + dnsapi/README.md | 18 ++++++++++++++++++ dnsapi/dns_cyon.sh | 25 +++++-------------------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index f1c74806..5f82effb 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,7 @@ You don't have to do anything manually! 1. Alwaysdata.com API 1. Linode.com API 1. FreeDNS (https://freedns.afraid.org/) +1. cyon.ch **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 6a86bf4c..70af17e7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -305,6 +305,24 @@ Note that you cannot use acme.sh automatic DNS validation for FreeDNS public dom you create under a FreeDNS public domain. You must own the top level domain in order to automaitcally validate with acme.sh at FreeDNS. +## 16. Use cyon.ch + +You only need to set your cyon.ch login credentials. +If you also have 2 Factor Authentication (OTP) enabled, you need to set your secret token too and have `oathtool` installed. + +``` +export cyon_username="your_cyon_username" +export cyon_password="your_cyon_password" +export cyon_otp_secret="your_otp_secret" # Only required if using 2FA +``` + +To issue a cert: +``` +acme.sh --issue --dns dns_cyon -d example.com -d www.example.com +``` + +The `cyon_username`, `cyon_password` and `cyon_otp_secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 3a441aaf..6c9c5c5d 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -9,27 +9,12 @@ # ------------- # - oathtool (When using 2 Factor Authentication) # -# Author: Armando Lüscher -######## - -######## -# Define cyon.ch login credentials: -# -# Either set them here: (uncomment these lines) +# Issues: +# ------- +# Any issues / questions / suggestions can be posted here: +# https://github.com/noplanman/cyon-api/issues # -# cyon_username='your_cyon_username' -# cyon_password='your_cyon_password' -# cyon_otp_secret='your_otp_secret' # Only required if using 2FA -# -# ...or export them as environment variables in your shell: -# -# $ export cyon_username='your_cyon_username' -# $ export cyon_password='your_cyon_password' -# $ export cyon_otp_secret='your_otp_secret' # Only required if using 2FA -# -# *Note:* -# After the first run, the credentials are saved in the "account.conf" -# file, so any hard-coded or environment variables can then be removed. +# Author: Armando Lüscher ######## dns_cyon_add() { From 09eccf6fc075c8f39ff0ec9ee1d7d20aa9826b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 28 Dec 2016 13:37:24 +0100 Subject: [PATCH 0711/1348] Use more flexible version of uppercase to lowercase conversion. --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 6c9c5c5d..ab8a38e5 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -86,7 +86,7 @@ _cyon_urlencode() { _cyon_load_parameters() { # Read the required parameters to add the TXT entry. - fulldomain="$(printf "%s" "${1}" | tr '[:upper:]' '[:lower:]')" + fulldomain="$(printf "%s" "${1}" | tr '[A-Z]' '[a-z]')" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, From afa3fc8bf921209476329cf9ebc6f58415dc0907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 28 Dec 2016 14:51:39 +0100 Subject: [PATCH 0712/1348] Adapt to use general naming rule for account variables. --- dnsapi/README.md | 8 ++++---- dnsapi/dns_cyon.sh | 34 +++++++++++++++++----------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 70af17e7..fd88d579 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -311,9 +311,9 @@ You only need to set your cyon.ch login credentials. If you also have 2 Factor Authentication (OTP) enabled, you need to set your secret token too and have `oathtool` installed. ``` -export cyon_username="your_cyon_username" -export cyon_password="your_cyon_password" -export cyon_otp_secret="your_otp_secret" # Only required if using 2FA +export CY_Username="your_cyon_username" +export CY_Password="your_cyon_password" +export CY_OTP_Secret="your_otp_secret" # Only required if using 2FA ``` To issue a cert: @@ -321,7 +321,7 @@ To issue a cert: acme.sh --issue --dns dns_cyon -d example.com -d www.example.com ``` -The `cyon_username`, `cyon_password` and `cyon_otp_secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index ab8a38e5..ca952db4 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -43,17 +43,17 @@ dns_cyon_rm() { _cyon_load_credentials() { # Convert loaded password to/from base64 as needed. - if [ "${cyon_password_b64}" ]; then - cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64 "multiline")" - elif [ "${cyon_password}" ]; then - cyon_password_b64="$(printf "%s" "${cyon_password}" | _base64)" + if [ "${CY_Password_B64}" ]; then + CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")" + elif [ "${CY_Password}" ]; then + CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)" fi - if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then + if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then # Dummy entries to satify script checker. - cyon_username="" - cyon_password="" - cyon_otp_secret="" + CY_Username="" + CY_Password="" + CY_OTP_Secret="" _err "" _err "You haven't set your cyon.ch login credentials yet." @@ -64,12 +64,12 @@ _cyon_load_credentials() { # Save the login credentials to the account.conf file. _debug "Save credentials to account.conf" - _saveaccountconf cyon_username "${cyon_username}" - _saveaccountconf cyon_password_b64 "$cyon_password_b64" - if [ ! -z "${cyon_otp_secret}" ]; then - _saveaccountconf cyon_otp_secret "$cyon_otp_secret" + _saveaccountconf CY_Username "${CY_Username}" + _saveaccountconf CY_Password_B64 "$CY_Password_B64" + if [ ! -z "${CY_OTP_Secret}" ]; then + _saveaccountconf CY_OTP_Secret "$CY_OTP_Secret" else - _clearaccountconf cyon_otp_secret + _clearaccountconf CY_OTP_Secret fi } @@ -140,8 +140,8 @@ _cyon_get_cookie_header() { _cyon_login() { _info " - Logging in..." - username_encoded="$(printf "%s" "${cyon_username}" | _cyon_urlencode)" - password_encoded="$(printf "%s" "${cyon_password}" | _cyon_urlencode)" + username_encoded="$(printf "%s" "${CY_Username}" | _cyon_urlencode)" + password_encoded="$(printf "%s" "${CY_Password}" | _cyon_urlencode)" login_url="https://my.cyon.ch/auth/index/dologin-async" login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" @@ -165,7 +165,7 @@ _cyon_login() { # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. # 2FA authentication with OTP? - if [ ! -z "${cyon_otp_secret}" ]; then + if [ ! -z "${CY_OTP_Secret}" ]; then _info " - Authorising with OTP code..." if ! _exists oathtool; then @@ -175,7 +175,7 @@ _cyon_login() { fi # Get OTP code with the defined secret. - otp_code="$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null)" + otp_code="$(oathtool --base32 --totp "${CY_OTP_Secret}" 2>/dev/null)" login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0" From ce9fae82bd7a31c52514e5f0f7d6f6a0f5854117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Thu, 29 Dec 2016 16:12:42 +0100 Subject: [PATCH 0713/1348] Update cookie retrieval using _egrep_o (thanks @Neilpang) --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index ca952db4..0390592a 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -134,7 +134,7 @@ _cyon_print_header() { } _cyon_get_cookie_header() { - printf "%s" "$(sed -n 's/Set-\(Cookie:.*cyon=[^;]*\).*/\1/p' "$HTTP_HEADER" | _tail_n 1)" + printf "Cookie: %s" "$(cat "$HTTP_HEADER" | grep "cyon=" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" } _cyon_login() { From 6e8dcdce7834938db893f85955aef27e1d71ca9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 4 Jan 2017 03:19:58 +0100 Subject: [PATCH 0714/1348] Satisfy shellcheck. --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 0390592a..54162198 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -134,7 +134,7 @@ _cyon_print_header() { } _cyon_get_cookie_header() { - printf "Cookie: %s" "$(cat "$HTTP_HEADER" | grep "cyon=" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" + printf "Cookie: %s" "$(grep "cyon=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" } _cyon_login() { From 9499a1142bfdaf0c3fb9f729421fd8ae853705ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Mon, 30 Jan 2017 16:36:49 +0100 Subject: [PATCH 0715/1348] Remove custom URL encoding and use library's implementation. --- dnsapi/dns_cyon.sh | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 54162198..d225138b 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -79,11 +79,6 @@ _cyon_is_idn() { [ "$_idn_temp" ] || [ "$_idn_temp2" ] } -# comment on https://stackoverflow.com/a/10797966 -_cyon_urlencode() { - curl -Gso /dev/null -w "%{url_effective}" --data-urlencode @- "" | cut -c 3- -} - _cyon_load_parameters() { # Read the required parameters to add the TXT entry. fulldomain="$(printf "%s" "${1}" | tr '[A-Z]' '[a-z]')" @@ -140,8 +135,8 @@ _cyon_get_cookie_header() { _cyon_login() { _info " - Logging in..." - username_encoded="$(printf "%s" "${CY_Username}" | _cyon_urlencode)" - password_encoded="$(printf "%s" "${CY_Password}" | _cyon_urlencode)" + username_encoded="$(printf "%s" "${CY_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${CY_Password}" | _url_encode)" login_url="https://my.cyon.ch/auth/index/dologin-async" login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" @@ -278,8 +273,8 @@ _cyon_delete_txt() { continue fi - hash_encoded="$(printf "%s" "${_hash}" | _cyon_urlencode)" - identifier_encoded="$(printf "%s" "${_identifier}" | _cyon_urlencode)" + hash_encoded="$(printf "%s" "${_hash}" | _url_encode)" + identifier_encoded="$(printf "%s" "${_identifier}" | _url_encode)" delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" From 884f70fb399cd73c1004c9eb5c11a582e9e35c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 31 Jan 2017 15:23:40 +0100 Subject: [PATCH 0716/1348] Remove square brackets from ranges. Export curl header variables. --- dnsapi/dns_cyon.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index d225138b..85ff028c 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -74,14 +74,14 @@ _cyon_load_credentials() { } _cyon_is_idn() { - _idn_temp="$(printf "%s" "${1}" | tr -d "[0-9a-zA-Z.,-_]")" + _idn_temp="$(printf "%s" "${1}" | tr -d "0-9a-zA-Z.,-_")" _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" [ "$_idn_temp" ] || [ "$_idn_temp2" ] } _cyon_load_parameters() { # Read the required parameters to add the TXT entry. - fulldomain="$(printf "%s" "${1}" | tr '[A-Z]' '[a-z]')" + fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, @@ -105,6 +105,7 @@ _cyon_load_parameters() { # This header is required for curl calls. _H1="X-Requested-With: XMLHttpRequest" + export _H1 } _cyon_print_header() { @@ -155,6 +156,8 @@ _cyon_login() { # NECESSARY!! Load the main page after login, to get the new cookie. _H2="$(_cyon_get_cookie_header)" + export _H2 + _get "https://my.cyon.ch/" >/dev/null # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. From 3e1418d662a3dc15a8359c2441397d63688d596e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 12 Feb 2017 12:30:06 +0100 Subject: [PATCH 0717/1348] Use gloo item key for environment change, to support different account types. (this isn't working 100% yet, still looking for a solution) --- dnsapi/dns_cyon.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 85ff028c..0ced4217 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -210,7 +210,10 @@ _cyon_change_domain_env() { domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')" _debug "Changing domain environment to ${domain_env}" - domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" + gloo_item_key="$(_get "https://my.cyon.ch/domain/" | tr '\n' ' ' | sed -E -e "s/.*data-domain=\"${domain_env}\"[^<]*data-itemkey=\"([^\"]*).*/\1/")" + _debug gloo_item_key "${gloo_item_key}" + + domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/${gloo_item_key}" domain_env_response="$(_get "${domain_env_url}")" _debug domain_env_response "${domain_env_response}" From 3a77a6eded17122416ecec87babe59b8492ef927 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 11:17:23 -0500 Subject: [PATCH 0718/1348] cleanup documentation and suppress some remote messages. --- deploy/README.md | 104 ++++++++++++++++++++++++++++++++++------------- deploy/ssh.sh | 22 +++++----- 2 files changed, 87 insertions(+), 39 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 01705838..8f386056 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -38,23 +38,21 @@ values are stored by acme.sh in the domain configuration files. Required... ```bash -export ACME_DEPLOY_SSH_USER="admin" +export ACME_DEPLOY_SSH_USER=username ``` Optional... ```bash -export ACME_DEPLOY_SSH_CMD="" -export ACME_DEPLOY_SSH_SERVER="qnap" -export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" -export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" -export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" -export ACME_DEPLOY_SSH_FULLCHAIN="" -export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -export ACME_DEPLOY_SSH_BACKUP="" +export ACME_DEPLOY_SSH_CMD=custom ssh command +export ACME_DEPLOY_SSH_SERVER=url or ip address of remote host +export ACME_DEPLOY_SSH_KEYFILE=filename for private key +export ACME_DEPLOY_SSH_CERTFILE=filename for certificate file +export ACME_DEPLOY_SSH_CAFILE=filename for intermediate CA file +export ACME_DEPLOY_SSH_FULLCHAIN=filename forfullchain file +export ACME_DEPLOY_SSH_REMOTE_CMD=command to execute on remote host +export ACME_DEPLOY_SSH_BACKUP=yes or no ``` -The values used above are illustrative only and represent those that could -be used to deploy certificates to a QNAP NAS device running QTS 4.2 -###ACME_DEPLOY_SSH_USER +**ACME_DEPLOY_SSH_USER** Username at the remote host that SSH will login with. Note that SSH must be able to login to remote host without a password... SSH Keys must have been exchanged with the remote host. Validate and test that you @@ -63,32 +61,42 @@ can login to USER@URL from the host running acme.sh before using this script. The USER@URL at the remote server must also have has permissions to write to the target location of the certificate files and to execute any commands (e.g. to stop/start services). -###ACME_DEPLOY_SSH_CMD + +**ACME_DEPLOY_SSH_CMD** You can customize the ssh command used to connect to the remote host. For example if you need to connect to a specific port at the remote server you can set this -to, for example, "ssh -p 22" -###ACME_DEPLOY_SSH_SERVER +to, for example, "ssh -p 22" or to use `sshpass` to provide password inline +instead of exchanging ssh keys (this is not recommended, using keys is +more secure). + +**ACME_DEPLOY_SSH_SERVER** URL or IP Address of the remote server. If not provided then the domain name provided on the acme.sh --deploy command line is used. -###ACME_DEPLOY_SSH_KEYFILE + +**ACME_DEPLOY_SSH_KEYFILE** Target filename for the private key issued by LetsEncrypt. -###ACME_DEPLOY_SSH_CERTFILE -Target filename for the certificate issued by LetsEncrypt. If this filename -is the same as that provided for ACME_DEPLOY_SSH_KEYFILE then this certificate -is appended to the same file as the private key. -###ACME_DEPLOY_SSH_CAFILE + +**ACME_DEPLOY_SSH_CERTFILE** +Target filename for the certificate issued by LetsEncrypt. +If this is the same as the previous filename (for keyfile) then it is +appended to the same file. + +**ACME_DEPLOY_SSH_CAFILE** Target filename for the CA intermediate certificate issued by LetsEncrypt. -If this is the same as a previous filename then it is appended to the same -file -###ACME_DEPLOY_SSH_FULLCHAIN +If this is the same as a previous filename (for keyfile or certfile) then +it is appended to the same file. + +**ACME_DEPLOY_SSH_FULLCHAIN** Target filename for the fullchain certificate issued by LetsEncrypt. -If this is the same as a previous filename then it is appended to the same -file -###ACME_DEPLOY_SSH_REMOTE_CMD +If this is the same as a previous filename (for keyfile, certfile or +cafile) then it is appended to the same file. + +**ACME_DEPLOY_SSH_REMOTE_CMD** Command to execute on the remote server after copying any certificates. This could be any additional command required for example to stop and restart the service. -###ACME_DEPLOY_SSH_BACKUP + +**ACME_DEPLOY_SSH_BACKUP** Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH @@ -98,3 +106,43 @@ user ``` Any backups older than 180 days will be deleted when new certificates are deployed. This defaults to "yes" set to "no" to disable backup. + + +###Eamples using SSH deploy +The following example illustrates deploying certifcates to a QNAP NAS +running QTS 4.2 + +```bash +export ACME_DEPLOY_SSH_USER="admin" +export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" + +acme.sh --deploy -d qnap.example.com --deploy-hook ssh +``` + +The next example illustates deploying certificates to a Unifi +Contolller (tested with version 5.4.11). + +```bash +export ACME_DEPLOY_SSH_USER="root" +export ACME_DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" +export ACME_DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" +export ACME_DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ + -inkey /var/lib/unifi/unifi.example.com.key \ + -in /var/lib/unifi/unifi.example.com.cer \ + -out /var/lib/unifi/unifi.example.com.p12 \ + -name ubnt -password pass:temppass \ + && keytool -importkeystore -deststorepass aircontrolenterprise \ + -destkeypass aircontrolenterprise -destkeystore /var/lib/unifi/keystore \ + -srckeystore /var/lib/unifi/unifi.example.com.p12 \ + -srcstoretype PKCS12 -srcstorepass temppass -alias ubnt -noprompt \ + && service unifi restart" + +acme.sh --deploy -d qnap.example.com --deploy-hook ssh +``` +Note how in this exmple we execute several commands on the remote host +after the certificate files have been copied... to generate a pkcs12 file +compatible with Unifi, to import it into the Unifi keystore and then finaly +to restart the service. diff --git a/deploy/ssh.sh b/deploy/ssh.sh index eb3690a6..a8ed6a10 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -93,10 +93,10 @@ ssh_deploy() { if [ -n "$Le_Deploy_ssh_keyfile" ]; then if [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir ;" + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;" fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" fi @@ -113,10 +113,10 @@ ssh_deploy() { _pipe=">>" elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir ;" + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;" fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;" _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" fi @@ -134,10 +134,10 @@ ssh_deploy() { _pipe=">>" elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir ;" + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;" fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" fi @@ -156,10 +156,10 @@ ssh_deploy() { _pipe=">>" elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then # backup file we are about to overwrite. - _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir ;" + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;" fi # copy new certificate into file. - _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain ;" + _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;" _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain" fi @@ -170,7 +170,7 @@ ssh_deploy() { _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then - _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd ;" + _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;" _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" fi @@ -183,9 +183,9 @@ ssh_deploy() { _cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \ do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr" - # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf ; $_cmdstr" + # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr" # Create our backup directory for overwritten cert files. - _cmdstr="mkdir -p $_backupdir ; $_cmdstr" + _cmdstr="mkdir -p $_backupdir; $_cmdstr" _info "Backup of old certificate files will be placed in remote directory $_backupdir" _info "Backup directories erased after 180 days." fi From e35e31324078803cd1db2c398d070ce2cc184252 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 11:20:16 -0500 Subject: [PATCH 0719/1348] Fix error in Unifi example --- deploy/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 8f386056..8cc40cd3 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -135,12 +135,13 @@ export ACME_DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ -out /var/lib/unifi/unifi.example.com.p12 \ -name ubnt -password pass:temppass \ && keytool -importkeystore -deststorepass aircontrolenterprise \ - -destkeypass aircontrolenterprise -destkeystore /var/lib/unifi/keystore \ + -destkeypass aircontrolenterprise \ + -destkeystore /var/lib/unifi/keystore \ -srckeystore /var/lib/unifi/unifi.example.com.p12 \ -srcstoretype PKCS12 -srcstorepass temppass -alias ubnt -noprompt \ && service unifi restart" -acme.sh --deploy -d qnap.example.com --deploy-hook ssh +acme.sh --deploy -d unifi.example.com --deploy-hook ssh ``` Note how in this exmple we execute several commands on the remote host after the certificate files have been copied... to generate a pkcs12 file From 6f4abe95cb8be54272f080a98a3991e7ab9ee2ec Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 11:24:00 -0500 Subject: [PATCH 0720/1348] update markdown examples. --- deploy/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 8cc40cd3..9c22e80b 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -28,7 +28,7 @@ The ssh deploy plugin allows you to deploy certificates to a remote host using SSH command to connect to the remote server. The ssh plugin is invoked with the following command... -```bash +```sh acme.sh --deploy -d example.com --deploy-hook ssh ``` Prior to running this for the first time you must tell the plugin where @@ -37,17 +37,17 @@ environment variables. This is not required for subsequent runs as the values are stored by acme.sh in the domain configuration files. Required... -```bash +``` export ACME_DEPLOY_SSH_USER=username ``` Optional... -```bash +``` export ACME_DEPLOY_SSH_CMD=custom ssh command export ACME_DEPLOY_SSH_SERVER=url or ip address of remote host export ACME_DEPLOY_SSH_KEYFILE=filename for private key export ACME_DEPLOY_SSH_CERTFILE=filename for certificate file export ACME_DEPLOY_SSH_CAFILE=filename for intermediate CA file -export ACME_DEPLOY_SSH_FULLCHAIN=filename forfullchain file +export ACME_DEPLOY_SSH_FULLCHAIN=filename for fullchain file export ACME_DEPLOY_SSH_REMOTE_CMD=command to execute on remote host export ACME_DEPLOY_SSH_BACKUP=yes or no ``` @@ -101,7 +101,7 @@ Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH user -```bash +```sh ~/.acme_ssh_deploy/[domain name]-backup-[timestamp] ``` Any backups older than 180 days will be deleted when new certificates @@ -112,7 +112,7 @@ are deployed. This defaults to "yes" set to "no" to disable backup. The following example illustrates deploying certifcates to a QNAP NAS running QTS 4.2 -```bash +```sh export ACME_DEPLOY_SSH_USER="admin" export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" @@ -125,7 +125,7 @@ acme.sh --deploy -d qnap.example.com --deploy-hook ssh The next example illustates deploying certificates to a Unifi Contolller (tested with version 5.4.11). -```bash +```sh export ACME_DEPLOY_SSH_USER="root" export ACME_DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" export ACME_DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" From 76c1ed6628009d8752a8135e80c2614a28bb5e18 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 18:08:17 -0500 Subject: [PATCH 0721/1348] Additional documentation for the unifi example. --- deploy/README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 9c22e80b..10f355d6 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -143,7 +143,21 @@ export ACME_DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ acme.sh --deploy -d unifi.example.com --deploy-hook ssh ``` -Note how in this exmple we execute several commands on the remote host +In this exmple we execute several commands on the remote host after the certificate files have been copied... to generate a pkcs12 file compatible with Unifi, to import it into the Unifi keystore and then finaly to restart the service. + +Note also that once the certificate is imported +into the keystore the individual certificate files are no longer +required. We could if we desired delete those files immediately. If we +do that then we should disable backup at the remote host (as there are +no files to backup -- they were erased during deployment). For example... +```sh +export ACME_DEPLOY_SSH_BACKUP=no +# modify the end of the remte command... +&& rm /var/lib/unifi/unifi.example.com.key \ + /var/lib/unifi/unifi.example.com.cer \ + /var/lib/unifi/unifi.example.com.p12 \ +&& service unifi restart +``` From d04ccb7a3ff71fbf114ace288aea5a49faf9db1a Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 18:20:43 -0500 Subject: [PATCH 0722/1348] fix spelling error in readme --- deploy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 10f355d6..df0cdf0a 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -155,7 +155,7 @@ do that then we should disable backup at the remote host (as there are no files to backup -- they were erased during deployment). For example... ```sh export ACME_DEPLOY_SSH_BACKUP=no -# modify the end of the remte command... +# modify the end of the remote command... && rm /var/lib/unifi/unifi.example.com.key \ /var/lib/unifi/unifi.example.com.cer \ /var/lib/unifi/unifi.example.com.p12 \ From 9d725af60221519a8ac4cc976a0af49ff0be2e26 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 13 Feb 2017 23:29:37 +0800 Subject: [PATCH 0723/1348] support nginx mode --- README.md | 32 ++++++-- acme.sh | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 235 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f1c74806..edc4555c 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ https://github.com/Neilpang/acmetest - Webroot mode - Standalone mode - Apache mode +- Nginx mode - DNS mode - [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) @@ -215,8 +216,27 @@ acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert +# 7. Use Nginx mode -# 7. Use DNS mode: +**(requires you to be root/sudoer, since it is required to interact with Nginx server)** + +If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`. + +Particularly, if you are running an nginx server, you can use nginx mode instead. This mode doesn't write any files to your web root folder. + +Just set string "nginx" as the second argument. + +It will configure nginx server automatically to verify the domain and then restore the nginx config to the original version. + +So, the config is not changed. + +``` +acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com +``` + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + +# 8. Use DNS mode: Support the `dns-01` challenge. @@ -247,7 +267,7 @@ acme.sh --renew -d example.com Ok, it's finished. -# 8. Automatic DNS API integration +# 9. Automatic DNS API integration If your DNS provider supports API access, we can use that API to automatically issue the certs. @@ -280,7 +300,7 @@ If your DNS provider is not on the supported list above, you can write your own For more details: [How to use DNS API](dnsapi) -# 9. Issue ECC certificates +# 10. Issue ECC certificates `Let's Encrypt` can now issue **ECDSA** certificates. @@ -311,7 +331,7 @@ Valid values are: 3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)** -# 10. How to renew the issued certs +# 11. How to renew the issued certs No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. @@ -328,7 +348,7 @@ acme.sh --renew -d example.com --force --ecc ``` -# 11. How to upgrade `acme.sh` +# 12. How to upgrade `acme.sh` acme.sh is in constant development, so it's strongly recommended to use the latest code. @@ -353,7 +373,7 @@ acme.sh --upgrade --auto-upgrade 0 ``` -# 12. Issue a cert from an existing CSR +# 13. Issue a cert from an existing CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR diff --git a/acme.sh b/acme.sh index f03501b4..612c2094 100755 --- a/acme.sh +++ b/acme.sh @@ -45,6 +45,8 @@ MODE_STATELESS="stateless" STATE_VERIFIED="verified_ok" +NGINX="nginx:" + BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" END_CSR="-----END CERTIFICATE REQUEST-----" @@ -2277,10 +2279,186 @@ Allow from all return 0 } +#find the real nginx conf file +#backup +#set the nginx conf +#returns the real nginx conf file +_setNginx() { + _d="$1" + _croot="$2" + _thumbpt="$3" + if ! _exists "nginx"; then + _err "nginx command is not found." + return 1 + fi + FOUND_REAL_NGINX_CONF="" + BACKUP_NGINX_CONF="" + _debug _croot "$_croot" + _start_f="$(echo "$_croot" | cut -d : -f 2)" + _debug _start_f "$_start_f" + if [ -z "$_start_f" ]; then + _debug "find start conf from nginx command" + if [ -z "$NGINX_CONF" ]; then + NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")" + _debug NGINX_CONF "$NGINX_CONF" + NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)" + _debug NGINX_CONF "$NGINX_CONF" + if [ ! -f "$NGINX_CONF" ]; then + _err "'$NGINX_CONF' doesn't exist." + NGINX_CONF="" + return 1 + fi + _debug "Found nginx conf file:$NGINX_CONF" + fi + _start_f="$NGINX_CONF" + fi + _info "Start detect nginx conf for $_d from:$_start_f" + if ! _checkConf "$_d" "$_start_f"; then + "Can not find conf file for domain $d" + return 1 + fi + _info "Found conf file: $FOUND_REAL_NGINX_CONF" + + mkdir -p "$DOMAIN_BACKUP_PATH" + _backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf" + _debug _backup_conf "$_backup_conf" + BACKUP_NGINX_CONF="$_backup_conf" + _info "Backup $FOUND_REAL_NGINX_CONF to $_backup_conf" + if ! cp "$FOUND_REAL_NGINX_CONF" "$_backup_conf"; then + _err "backup error." + FOUND_REAL_NGINX_CONF="" + return 1 + fi + + _info "Check the nginx conf before setting up." + if ! _exec "nginx -t" >/dev/null; then + _exec_err + return 1 + fi + + _info "OK, Set up nginx config file" + _ln=$(grep -n "^ *server_name.* $_d" "$_backup_conf" | cut -d : -f 1 | tr -d "\n") + _debug "_ln" "$_ln" + + if ! sed -n "1,${_ln}p" "$_backup_conf" > "$FOUND_REAL_NGINX_CONF"; then + cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + _err "write nginx conf error, but don't worry, the file is restored to the original version." + return 1 + fi + + echo " +location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { + default_type text/plain; + return 200 \"\$1.$_thumbpt\"; +} +" >> "$FOUND_REAL_NGINX_CONF" + + _ln=$(_math $_ln + 1) + if ! sed -n "${_ln},99999p" "$_backup_conf" >> "$FOUND_REAL_NGINX_CONF"; then + cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + _err "write nginx conf error, but don't worry, the file is restored." + return 1 + fi + + _info "nginx conf is done, let's check it again." + if ! _exec "nginx -t" >/dev/null; then + _exec_err + _err "It seems that nginx conf was broken, let's restore." + cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + return 1 + fi + + _info "Reload nginx" + if ! _exec "nginx -s reload" >/dev/null; then + _exec_err + _err "It seems that nginx reload error, let's restore." + cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + return 1 + fi + + return 0 +} + +#d , conf +_checkConf() { + _d="$1" + _c_file="$2" + _debug "Start _checkConf from:$_c_file" + if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then + _debug "wildcard" + for _w_f in $2; do + if _checkConf "$1" "$_w_f"; then + return 0 + fi + done + #not found + return 1 + elif [ -f "$2" ]; then + _debug "single" + if _isRealNginxConf "$1" "$2"; then + _debug "$2 is found." + FOUND_REAL_NGINX_CONF="$2" + return 0 + fi + if grep "^ *include *.*;" "$2" >/dev/null; then + _debug "Try include files" + for included in $(grep "^ *include *.*;" "$2"| sed "s/include //" | tr -d " ;" ); do + _debug "check included $included" + if _checkConf "$1" "$included"; then + return 0 + fi + done + fi + return 1 + else + _debug "$2 not found." + return 1 + fi + return 1 +} + +#d , conf +_isRealNginxConf() { + _debug "_isRealNginxConf $1 $2" + if [ -f "$2" ] && grep "^ *server_name " "$2" | grep " $1" >/dev/null; then + return 0 + else + return 1 + fi +} + +#restore all the nginx conf +_restoreNginx() { + if [ -z "$NGINX_VLIST" ]; then + _debug "No need to restore nginx, skip." + return + fi + _debug "_restoreNginx" + _debug "NGINX_VLIST" "$NGINX_VLIST" + + for ng_entry in $(echo "$NGINX_VLIST" | tr "$dvsep" ' '); do + _debug "ng_entry" "$ng_entry" + _nd=$(echo "$ng_entry" | cut -d "$sep" -f 1) + _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) + _ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3) + _info "Restoring from $_ngbackupconf to $_ngconf" + cat "$_ngbackupconf" > "$_ngconf" + done + + _info "Reload nginx" + if ! _exec "nginx -s reload" >/dev/null; then + _exec_err + _err "It seems that nginx reload error, please report bug." + return 1 + fi + return 0 +} + _clearup() { _stopserver "$serverproc" serverproc="" _restoreApache + _restoreNginx _clearupdns if [ -z "$DEBUG" ]; then rm -f "$TLS_CONF" @@ -2822,6 +3000,7 @@ issue() { _info "Getting domain auth token for each domain" sep='#' + dvsep=',' if [ -z "$vlist" ]; then alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') _index=1 @@ -2829,7 +3008,7 @@ issue() { for d in $alldomains; do _info "Getting webroot for domain" "$d" _w="$(echo $Le_Webroot | cut -d , -f $_index)" - _info _w "$_w" + _debug _w "$_w" if [ "$_w" ]; then _currentRoot="$_w" fi @@ -2881,13 +3060,13 @@ issue() { dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" _debug dvlist "$dvlist" - vlist="$vlist$dvlist," + vlist="$vlist$dvlist$dvsep" done - + _debug vlist "$vlist" #add entry dnsadded="" - ventries=$(echo "$vlist" | tr ',' ' ') + ventries=$(echo "$vlist" | tr "$dvsep" ' ') for ventry in $ventries; do d=$(echo "$ventry" | cut -d "$sep" -f 1) keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) @@ -2970,10 +3149,11 @@ issue() { _sleep "$Le_DNSSleep" fi + NGINX_VLIST="" _debug "ok, let's start to verify" _ncIndex=1 - ventries=$(echo "$vlist" | tr ',' ' ') + ventries=$(echo "$vlist" | tr "$dvsep" ' ') for ventry in $ventries; do d=$(echo "$ventry" | cut -d "$sep" -f 1) keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) @@ -3012,6 +3192,22 @@ issue() { elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then _info "Stateless mode for domain:$d" _sleep 1 + elif _startswith "$_currentRoot" "$NGINX"; then + _info "Nginx mode for domain:$d" + #set up nginx server + FOUND_REAL_NGINX_CONF="" + BACKUP_NGINX_CONF="" + if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then + _clearup + _on_issue_err + return 1 + else + _realConf="$FOUND_REAL_NGINX_CONF" + _backup="$BACKUP_NGINX_CONF" + _debug _realConf "$_realConf" + NGINX_VLIST="$NGINX_VLIST$d$sep$_realConf$sep$_backup$dvsep" + fi + _sleep 1 else if [ "$_currentRoot" = "apache" ]; then wellknown_path="$ACME_DIR" @@ -4629,6 +4825,14 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; + --nginx) + wvalue="$NGINX" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; --tls) wvalue="$W_TLS" if [ -z "$_webroot" ]; then From 68a35155e4c2ab8ecd13c60a6e723fb0bdd8eaf3 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Mon, 13 Feb 2017 20:32:12 -0500 Subject: [PATCH 0724/1348] Improve documentation in readme --- deploy/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index df0cdf0a..ab38f275 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -110,7 +110,7 @@ are deployed. This defaults to "yes" set to "no" to disable backup. ###Eamples using SSH deploy The following example illustrates deploying certifcates to a QNAP NAS -running QTS 4.2 +(tested with QTS version 4.2.3) ```sh export ACME_DEPLOY_SSH_USER="admin" @@ -121,6 +121,10 @@ export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" acme.sh --deploy -d qnap.example.com --deploy-hook ssh ``` +Note how in this example both the private key and certificate point to +the same file. This will result in the certificate being appended +to the same file as the private key... a common requirement of several +services. The next example illustates deploying certificates to a Unifi Contolller (tested with version 5.4.11). From 03f8d6e946d642c529927668c078df2025f7aa22 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 14 Feb 2017 22:03:48 +0800 Subject: [PATCH 0725/1348] fix https://github.com/Neilpang/acme.sh/issues/615 --- acme.sh | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 612c2094..349e1b39 100755 --- a/acme.sh +++ b/acme.sh @@ -46,6 +46,8 @@ MODE_STATELESS="stateless" STATE_VERIFIED="verified_ok" NGINX="nginx:" +NGINX_START="#ACME_NGINX_START" +NGINX_END="#ACME_NGINX_END" BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" END_CSR="-----END CERTIFICATE REQUEST-----" @@ -2312,13 +2314,26 @@ _setNginx() { fi _start_f="$NGINX_CONF" fi - _info "Start detect nginx conf for $_d from:$_start_f" + _debug "Start detect nginx conf for $_d from:$_start_f" if ! _checkConf "$_d" "$_start_f"; then "Can not find conf file for domain $d" return 1 fi _info "Found conf file: $FOUND_REAL_NGINX_CONF" + _ln=$(grep -n "^ *server_name.* $_d" "$FOUND_REAL_NGINX_CONF" | cut -d : -f 1 | tr -d "\n") + _debug "_ln" "$_ln" + + _lnn=$(_math $_ln + 1) + _debug _lnn "$_lnn" + _start_tag="$(sed -n "$_lnn,${_lnn}p" "$FOUND_REAL_NGINX_CONF")" + _debug "_start_tag" "$_start_tag" + if [ "$_start_tag" = "$NGINX_START" ]; then + _info "The domain $_d is already configured, skip" + FOUND_REAL_NGINX_CONF="" + return 0 + fi + mkdir -p "$DOMAIN_BACKUP_PATH" _backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf" _debug _backup_conf "$_backup_conf" @@ -2337,25 +2352,23 @@ _setNginx() { fi _info "OK, Set up nginx config file" - _ln=$(grep -n "^ *server_name.* $_d" "$_backup_conf" | cut -d : -f 1 | tr -d "\n") - _debug "_ln" "$_ln" if ! sed -n "1,${_ln}p" "$_backup_conf" > "$FOUND_REAL_NGINX_CONF"; then - cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" _err "write nginx conf error, but don't worry, the file is restored to the original version." return 1 fi - echo " + echo "$NGINX_START location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { default_type text/plain; return 200 \"\$1.$_thumbpt\"; } -" >> "$FOUND_REAL_NGINX_CONF" +#NGINX_START +" >>"$FOUND_REAL_NGINX_CONF" - _ln=$(_math $_ln + 1) - if ! sed -n "${_ln},99999p" "$_backup_conf" >> "$FOUND_REAL_NGINX_CONF"; then - cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + if ! sed -n "${_lnn},99999p" "$_backup_conf" >>"$FOUND_REAL_NGINX_CONF"; then + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" _err "write nginx conf error, but don't worry, the file is restored." return 1 fi @@ -2364,7 +2377,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { if ! _exec "nginx -t" >/dev/null; then _exec_err _err "It seems that nginx conf was broken, let's restore." - cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" return 1 fi @@ -2372,7 +2385,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { if ! _exec "nginx -s reload" >/dev/null; then _exec_err _err "It seems that nginx reload error, let's restore." - cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" return 1 fi @@ -3201,7 +3214,9 @@ issue() { _clearup _on_issue_err return 1 - else + fi + + if [ "$FOUND_REAL_NGINX_CONF" ]; then _realConf="$FOUND_REAL_NGINX_CONF" _backup="$BACKUP_NGINX_CONF" _debug _realConf "$_realConf" From 5d943a35f8341660c0429e11ea5299bfb008689d Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 14 Feb 2017 22:12:58 +0800 Subject: [PATCH 0726/1348] fix https://github.com/Neilpang/acme.sh/issues/616 --- acme.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 349e1b39..6234500e 100755 --- a/acme.sh +++ b/acme.sh @@ -2442,14 +2442,14 @@ _isRealNginxConf() { #restore all the nginx conf _restoreNginx() { - if [ -z "$NGINX_VLIST" ]; then + if [ -z "$NGINX_RESTORE_VLIST" ]; then _debug "No need to restore nginx, skip." return fi _debug "_restoreNginx" - _debug "NGINX_VLIST" "$NGINX_VLIST" + _debug "NGINX_RESTORE_VLIST" "$NGINX_RESTORE_VLIST" - for ng_entry in $(echo "$NGINX_VLIST" | tr "$dvsep" ' '); do + for ng_entry in $(echo "$NGINX_RESTORE_VLIST" | tr "$dvsep" ' '); do _debug "ng_entry" "$ng_entry" _nd=$(echo "$ng_entry" | cut -d "$sep" -f 1) _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) @@ -3162,7 +3162,7 @@ issue() { _sleep "$Le_DNSSleep" fi - NGINX_VLIST="" + NGINX_RESTORE_VLIST="" _debug "ok, let's start to verify" _ncIndex=1 @@ -3220,7 +3220,7 @@ issue() { _realConf="$FOUND_REAL_NGINX_CONF" _backup="$BACKUP_NGINX_CONF" _debug _realConf "$_realConf" - NGINX_VLIST="$NGINX_VLIST$d$sep$_realConf$sep$_backup$dvsep" + NGINX_RESTORE_VLIST="$d$sep$_realConf$sep$_backup$dvsep$NGINX_RESTORE_VLIST" fi _sleep 1 else From 302c41edc9c8696f8f266352449eb7e8e2c79533 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 14 Feb 2017 22:41:34 +0800 Subject: [PATCH 0727/1348] fix format --- acme.sh | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index 6234500e..6121224f 100755 --- a/acme.sh +++ b/acme.sh @@ -2353,7 +2353,7 @@ _setNginx() { _info "OK, Set up nginx config file" - if ! sed -n "1,${_ln}p" "$_backup_conf" > "$FOUND_REAL_NGINX_CONF"; then + if ! sed -n "1,${_ln}p" "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"; then cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" _err "write nginx conf error, but don't worry, the file is restored to the original version." return 1 @@ -2377,7 +2377,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { if ! _exec "nginx -t" >/dev/null; then _exec_err _err "It seems that nginx conf was broken, let's restore." - cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" return 1 fi @@ -2385,7 +2385,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { if ! _exec "nginx -s reload" >/dev/null; then _exec_err _err "It seems that nginx reload error, let's restore." - cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" return 1 fi @@ -2415,7 +2415,7 @@ _checkConf() { fi if grep "^ *include *.*;" "$2" >/dev/null; then _debug "Try include files" - for included in $(grep "^ *include *.*;" "$2"| sed "s/include //" | tr -d " ;" ); do + for included in $(grep "^ *include *.*;" "$2" | sed "s/include //" | tr -d " ;"); do _debug "check included $included" if _checkConf "$1" "$included"; then return 0 @@ -2433,11 +2433,17 @@ _checkConf() { #d , conf _isRealNginxConf() { _debug "_isRealNginxConf $1 $2" - if [ -f "$2" ] && grep "^ *server_name " "$2" | grep " $1" >/dev/null; then + if [ -f "$2" ]; then + for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do + _debug _fln "$_fln" + if [ "$_fln" ]; then + _listen=$(cat "$2" | _head_n "$_fln" | grep "^ *listen .*" | _tail_n 1) + fi + done return 0 - else - return 1 fi + + return 1 } #restore all the nginx conf @@ -2455,7 +2461,7 @@ _restoreNginx() { _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) _ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3) _info "Restoring from $_ngbackupconf to $_ngconf" - cat "$_ngbackupconf" > "$_ngconf" + cat "$_ngbackupconf" >"$_ngconf" done _info "Reload nginx" @@ -3215,7 +3221,7 @@ issue() { _on_issue_err return 1 fi - + if [ "$FOUND_REAL_NGINX_CONF" ]; then _realConf="$FOUND_REAL_NGINX_CONF" _backup="$BACKUP_NGINX_CONF" From 9f90618a707750475604f5ad8bf726f62f281c67 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 14 Feb 2017 23:57:00 +0800 Subject: [PATCH 0728/1348] fix https://github.com/Neilpang/acme.sh/issues/617 --- acme.sh | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 6121224f..a846b97a 100755 --- a/acme.sh +++ b/acme.sh @@ -2294,6 +2294,7 @@ _setNginx() { return 1 fi FOUND_REAL_NGINX_CONF="" + FOUND_REAL_NGINX_CONF_LN="" BACKUP_NGINX_CONF="" _debug _croot "$_croot" _start_f="$(echo "$_croot" | cut -d : -f 2)" @@ -2321,7 +2322,7 @@ _setNginx() { fi _info "Found conf file: $FOUND_REAL_NGINX_CONF" - _ln=$(grep -n "^ *server_name.* $_d" "$FOUND_REAL_NGINX_CONF" | cut -d : -f 1 | tr -d "\n") + _ln=$FOUND_REAL_NGINX_CONF_LN _debug "_ln" "$_ln" _lnn=$(_math $_ln + 1) @@ -2437,12 +2438,36 @@ _isRealNginxConf() { for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do _debug _fln "$_fln" if [ "$_fln" ]; then - _listen=$(cat "$2" | _head_n "$_fln" | grep "^ *listen .*" | _tail_n 1) + _start=$(cat "$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) + _debug "_start" "$_start" + _start_n=$(echo "$_start" | cut -d : -f 1) + _start_nn=$(_math $_start_n + 1) + _debug "_start_n" "$_start_n" + _debug "_start_nn" "$_start_nn" + + _left="$(sed -n "${_start_nn},99999p" "$2")" + _debug2 _left "$_left" + if echo "$_left" | grep -n "^ *server *{" >/dev/null; then + _end=$(echo "$_left" | grep -n "^ *server *{" | _head_n 1) + _debug "_end" "$_end" + _end_n=$(echo "$_end" | cut -d : -f 1) + _debug "_end_n" "$_end_n" + _seg_n=$(echo "$_left" | sed -n "1,${_end_n}p") + else + _seg_n="$_left" + fi + + _debug "_seg_n" "$_seg_n" + + if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ]; then + _debug "ssl on, skip" + return 1 + fi + FOUND_REAL_NGINX_CONF_LN=$_fln + return 0 fi done - return 0 fi - return 1 } From 6921211461a1c4d7d24c21643ead5d56d15ea532 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Feb 2017 20:24:24 +0800 Subject: [PATCH 0729/1348] fix debug message --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index a846b97a..5e84eeaa 100755 --- a/acme.sh +++ b/acme.sh @@ -2528,7 +2528,7 @@ _clearupdns() { txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then - _info "$d is already verified, skip $vtype." + _debug "$d is already verified, skip $vtype." continue fi @@ -3096,7 +3096,7 @@ issue() { _debug keyauthorization "$keyauthorization" if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then - _info "$d is already verified, skip." + _debug "$d is already verified, skip." keyauthorization="$STATE_VERIFIED" _debug keyauthorization "$keyauthorization" fi @@ -3118,7 +3118,7 @@ issue() { _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then - _info "$d is already verified, skip $vtype." + _debug "$d is already verified, skip $vtype." continue fi From 7db28745c89b168d55b26ab68d696b069d091c23 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Feb 2017 20:28:50 +0800 Subject: [PATCH 0730/1348] start v2.6.7 --- README.md | 2 +- acme.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index edc4555c..2624690a 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ https://github.com/Neilpang/acmetest - Webroot mode - Standalone mode - Apache mode -- Nginx mode +- Nginx mode ( Beta ) - DNS mode - [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) diff --git a/acme.sh b/acme.sh index 5e84eeaa..7a229eb6 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.6 +VER=2.6.7 PROJECT_NAME="acme.sh" From 72af092cc1ac37908954366edf3abf05d7fae4be Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Feb 2017 21:09:01 +0800 Subject: [PATCH 0731/1348] fix https://github.com/Neilpang/acme.sh/issues/614 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7a229eb6..36443e39 100755 --- a/acme.sh +++ b/acme.sh @@ -994,7 +994,7 @@ _readKeyLengthFromCSR() { echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | _egrep_o "^ *Public-Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + echo "$_outcsr" | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 fi } From ad153ae041f40c4c4d730f35d9e58700ccd25906 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 16 Feb 2017 22:29:08 +0800 Subject: [PATCH 0732/1348] fix https://github.com/Neilpang/acme.sh/issues/622 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 36443e39..cf9d8501 100755 --- a/acme.sh +++ b/acme.sh @@ -1610,14 +1610,14 @@ _setopt() { __val="$(echo "$__val" | sed 's/&/\\&/g')" fi text="$(cat "$__conf")" - echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + printf -- "%s" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then if _contains "$__val" "&"; then __val="$(echo "$__val" | sed 's/&/\\&/g')" fi text="$(cat "$__conf")" - echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + printf -- "%s" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" else _debug3 APP From 52f8b787c981ffc761694ad979d58b86390ca9f5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 16 Feb 2017 22:37:32 +0800 Subject: [PATCH 0733/1348] fix https://github.com/Neilpang/acme.sh/issues/622 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index cf9d8501..a590d10e 100755 --- a/acme.sh +++ b/acme.sh @@ -1610,14 +1610,14 @@ _setopt() { __val="$(echo "$__val" | sed 's/&/\\&/g')" fi text="$(cat "$__conf")" - printf -- "%s" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + printf -- "%s\n" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then if _contains "$__val" "&"; then __val="$(echo "$__val" | sed 's/&/\\&/g')" fi text="$(cat "$__conf")" - printf -- "%s" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + printf -- "%s\n" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" else _debug3 APP From 0bc745f68fa9ca0dbb5350bf51ea65f3865824a9 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Feb 2017 13:51:17 +0800 Subject: [PATCH 0734/1348] retry if nonce is invalid fix https://github.com/Neilpang/acme.sh/issues/627 --- acme.sh | 99 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/acme.sh b/acme.sh index a590d10e..d3d3d507 100755 --- a/acme.sh +++ b/acme.sh @@ -1530,62 +1530,75 @@ _send_signed_request() { payload64=$(printf "%s" "$payload" | _base64 | _url_replace) _debug3 payload64 "$payload64" - if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce." - nonceurl="$API/directory" - _headers="$(_get "$nonceurl" "onlyheader")" + MAX_REQUEST_RETRY_TIMES=5 + _request_retry_times=0 + while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do + _debug3 _request_retry_times "$_request_retry_times" + if [ -z "$_CACHED_NONCE" ]; then + _debug2 "Get nonce." + nonceurl="$API/directory" + _headers="$(_get "$nonceurl" "onlyheader")" - if [ "$?" != "0" ]; then - _err "Can not connect to $nonceurl to get nonce." - return 1 - fi + if [ "$?" != "0" ]; then + _err "Can not connect to $nonceurl to get nonce." + return 1 + fi - _debug2 _headers "$_headers" + _debug2 _headers "$_headers" - _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - _debug2 _CACHED_NONCE "$_CACHED_NONCE" - else - _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" - fi - nonce="$_CACHED_NONCE" - _debug2 nonce "$nonce" + _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + _debug2 _CACHED_NONCE "$_CACHED_NONCE" + else + _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" + fi + nonce="$_CACHED_NONCE" + _debug2 nonce "$nonce" - protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" - _debug3 protected "$protected" + protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" + _debug3 protected "$protected" - protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" - _debug3 protected64 "$protected64" + protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" + _debug3 protected64 "$protected64" - if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then - _err "Sign request failed." - return 1 - fi - _debug3 _sig_t "$_sig_t" + if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then + _err "Sign request failed." + return 1 + fi + _debug3 _sig_t "$_sig_t" - sig="$(printf "%s" "$_sig_t" | _url_replace)" - _debug3 sig "$sig" + sig="$(printf "%s" "$_sig_t" | _url_replace)" + _debug3 sig "$sig" - body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - _debug3 body "$body" + body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + _debug3 body "$body" - response="$(_post "$body" "$url" "$needbase64")" - _CACHED_NONCE="" - if [ "$?" != "0" ]; then - _err "Can not post to $url" - return 1 - fi - _debug2 original "$response" + response="$(_post "$body" "$url" "$needbase64")" + _CACHED_NONCE="" + + if [ "$?" != "0" ]; then + _err "Can not post to $url" + return 1 + fi + _debug2 original "$response" + response="$(echo "$response" | _normalizeJson)" - response="$(echo "$response" | _normalizeJson)" + responseHeaders="$(< "$HTTP_HEADER")" - responseHeaders="$(cat "$HTTP_HEADER")" + _debug2 responseHeaders "$responseHeaders" + _debug2 response "$response" + code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug code "$code" - _debug2 responseHeaders "$responseHeaders" - _debug2 response "$response" - code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" - _debug code "$code" + _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + if _contains "$response" "JWS has invalid anti-replay nonce"; then + _info "It seems the CA server is busy now, let's wait and retry." + _request_retry_times=$(_math "$_request_retry_times" + 1) + _sleep 5 + continue + fi + break; + done } From b7924ce58b09927c606615b7a485d6870073d0b0 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Feb 2017 14:40:58 +0800 Subject: [PATCH 0735/1348] fix format --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index d3d3d507..7eee2909 100755 --- a/acme.sh +++ b/acme.sh @@ -1533,7 +1533,7 @@ _send_signed_request() { MAX_REQUEST_RETRY_TIMES=5 _request_retry_times=0 while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do - _debug3 _request_retry_times "$_request_retry_times" + _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then _debug2 "Get nonce." nonceurl="$API/directory" @@ -1582,7 +1582,7 @@ _send_signed_request() { _debug2 original "$response" response="$(echo "$response" | _normalizeJson)" - responseHeaders="$(< "$HTTP_HEADER")" + responseHeaders="$(<"$HTTP_HEADER")" _debug2 responseHeaders "$responseHeaders" _debug2 response "$response" @@ -1597,7 +1597,7 @@ _send_signed_request() { _sleep 5 continue fi - break; + break done } From c70432996a70c82bdb4af526496bbc9b33408ab3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 17 Feb 2017 23:06:39 +0800 Subject: [PATCH 0736/1348] compatible to openssl 0.9 for hmac function --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7eee2909..d36df7f7 100755 --- a/acme.sh +++ b/acme.sh @@ -740,9 +740,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" | cut -d = -f 2 | tr -d ' ' + ($OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' else - $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary + $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary fi else _err "$alg is not supported yet" From 64802502217e4a4f8694b5e851d83c804b2a2688 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 18 Feb 2017 10:31:18 +0800 Subject: [PATCH 0737/1348] fix for freebsd --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d36df7f7..aaf966cb 100755 --- a/acme.sh +++ b/acme.sh @@ -1582,7 +1582,7 @@ _send_signed_request() { _debug2 original "$response" response="$(echo "$response" | _normalizeJson)" - responseHeaders="$(<"$HTTP_HEADER")" + responseHeaders="$(cat "$HTTP_HEADER")" _debug2 responseHeaders "$responseHeaders" _debug2 response "$response" From db5046292075d0988031f33105a062d055c84182 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 18 Feb 2017 12:03:21 +0800 Subject: [PATCH 0738/1348] minor use interactive _sleep --- dnsapi/dns_gd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 1abeeacf..f2dd1fd5 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -40,7 +40,7 @@ dns_gd_add() { if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then if [ "$response" = "{}" ]; then _info "Added, sleeping 10 seconds" - sleep 10 + _sleep 10 #todo: check if the record takes effect return 0 else From fc6cf4d9635544a8f8e6d6d1a6c33254cf16c537 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 12:13:18 +0800 Subject: [PATCH 0739/1348] fix syslog --- acme.sh | 69 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index aaf966cb..34ca1d9d 100755 --- a/acme.sh +++ b/acme.sh @@ -65,10 +65,31 @@ LOG_LEVEL_2=2 LOG_LEVEL_3=3 DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" -SYSLOG_INFO="user.info" +DEBUG_LEVEL_1=1 +DEBUG_LEVEL_2=2 +DEBUG_LEVEL_3=3 +DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 +DEBUG_LEVEL_NONE=0 + SYSLOG_ERROR="user.error" +SYSLOG_INFO="user.info" SYSLOG_DEBUG="user.debug" +#error +SYSLOG_LEVEL_1=1 +#info +SYSLOG_LEVEL_2=2 +#debug +SYSLOG_LEVEL_3=3 +#debug2 +SYSLOG_LEVEL_4=4 +#debug3 +SYSLOG_LEVEL_5=5 + +SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_1 +#none +SYSLOG_LEVEL_NONE=0 + _DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh" _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations" @@ -138,7 +159,7 @@ _dlg_versions() { #class _syslog() { - if [ -z "$SYS_LOG" ] || [ "$SYS_LOG" = "0" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then return fi _logclass="$1" @@ -147,19 +168,21 @@ _syslog() { } _log() { - _syslog "$@" [ -z "$LOG_FILE" ] && return - shift _printargs "$@" >>"$LOG_FILE" } _info() { - _log "$SYSLOG_INFO" "$@" + _log "$@" + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_2" ]; then + _syslog "$SYSLOG_INFO" "$@" + fi _printargs "$@" } _err() { - _log "$SYSLOG_ERROR" "$@" + _syslog "$SYSLOG_ERROR" "$@" + _log "$@" if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then printf -- "%s" "[$(date)] " >&2 fi @@ -178,29 +201,37 @@ _usage() { } _debug() { - if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ]; then - _log "$SYSLOG_DEBUG" "$@" + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then + _log "$@" fi - if [ -z "$DEBUG" ]; then - return + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_3" ]; then + _syslog "$SYSLOG_DEBUG" "$@" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then + _printargs "$@" >&2 fi - _printargs "$@" >&2 } _debug2() { - if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ]; then - _log "$SYSLOG_DEBUG" "$@" + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then + _log "$@" fi - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_4" ]; then + _syslog "$SYSLOG_DEBUG" "$@" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then _printargs "$@" >&2 fi } _debug3() { - if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ]; then - _log "$SYSLOG_DEBUG" "$@" + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then + _log "$@" + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_5" ]; then + _syslog "$SYSLOG_DEBUG" "$@" fi - if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ]; then + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then _printargs "$@" >&2 fi } @@ -4840,7 +4871,7 @@ _process() { ;; --debug) if [ -z "$2" ] || _startswith "$2" "-"; then - DEBUG="1" + DEBUG="$DEBUG_LEVEL_DEFAULT" else DEBUG="$2" shift @@ -5069,7 +5100,7 @@ _process() { shift fi if [ -z "$_syslog" ]; then - _syslog="1" + _syslog="$SYSLOG_LEVEL_DEFAULT" fi ;; --auto-upgrade) From 113089be5d5310e4d8acce352fcbe592a1c5220f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 12:42:37 +0800 Subject: [PATCH 0740/1348] fix syslog level --- acme.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 34ca1d9d..f4ee89c9 100755 --- a/acme.sh +++ b/acme.sh @@ -76,17 +76,17 @@ SYSLOG_INFO="user.info" SYSLOG_DEBUG="user.debug" #error -SYSLOG_LEVEL_1=1 +SYSLOG_LEVEL_ERROR=3 #info -SYSLOG_LEVEL_2=2 +SYSLOG_LEVEL_INFO=6 #debug -SYSLOG_LEVEL_3=3 +SYSLOG_LEVEL_DEBUG=7 #debug2 -SYSLOG_LEVEL_4=4 +SYSLOG_LEVEL_DEBUG_2=8 #debug3 -SYSLOG_LEVEL_5=5 +SYSLOG_LEVEL_DEBUG_3=9 -SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_1 +SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR #none SYSLOG_LEVEL_NONE=0 @@ -174,7 +174,7 @@ _log() { _info() { _log "$@" - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_2" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_INFO" ]; then _syslog "$SYSLOG_INFO" "$@" fi _printargs "$@" @@ -204,7 +204,7 @@ _debug() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then _log "$@" fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_3" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then @@ -216,7 +216,7 @@ _debug2() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then _log "$@" fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_4" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then @@ -228,7 +228,7 @@ _debug3() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then _log "$@" fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_5" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then From 52765466c12aaeaff6d7c9c9eab1e18f8cb84042 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 12:55:05 +0800 Subject: [PATCH 0741/1348] fix syslog doc --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index f4ee89c9..aa9d24b0 100755 --- a/acme.sh +++ b/acme.sh @@ -4596,7 +4596,7 @@ Parameters: --accountkeylength, -ak [2048] Specifies the account key length. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. --log-level 1|2 Specifies the log level, default is 1. - --syslog [1|0] Enable/Disable syslog. + --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: From e6e85b0c556a5458177fd2a4d31cf3d019d6f727 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 13:24:00 +0800 Subject: [PATCH 0742/1348] secure debug message --- acme.sh | 68 ++++++++++++++++++++++++++++++++++++++++++- dnsapi/dns_aws.sh | 4 +-- dnsapi/dns_lexicon.sh | 8 ++--- dnsapi/dns_ovh.sh | 4 +-- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index aa9d24b0..a8b0790b 100755 --- a/acme.sh +++ b/acme.sh @@ -71,6 +71,8 @@ DEBUG_LEVEL_3=3 DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 DEBUG_LEVEL_NONE=0 +HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)" + SYSLOG_ERROR="user.error" SYSLOG_INFO="user.info" SYSLOG_DEBUG="user.debug" @@ -212,6 +214,27 @@ _debug() { fi } +#output the sensitive messages +_secure_debug() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + _debug2() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then _log "$@" @@ -224,6 +247,26 @@ _debug2() { fi } +_secure_debug2() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + _debug3() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then _log "$@" @@ -236,6 +279,26 @@ _debug3() { fi } +_secure_debug3() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + _startswith() { _str="$1" _sub="$2" @@ -4583,7 +4646,7 @@ Parameters: --force, -f Used to force to install or force to renew a cert immediately. --staging, --test Use staging server, just for test. --debug Output debug info. - + --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. --stateless Use stateless mode, see: $_STATELESS_WIKI @@ -4877,6 +4940,9 @@ _process() { shift fi ;; + --output-insecure) + export OUTPUT_INSECURE=1 + ;; --webroot | -w) wvalue="$2" if [ -z "$_webroot" ]; then diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 29d7a2cd..84aa28d3 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -181,10 +181,10 @@ aws_rest() { #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################ - _debug2 kSecret "$kSecret" + _secure_debug2 kSecret "$kSecret" kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" - _debug2 kSecretH "$kSecretH" + _secure_debug2 kSecretH "$kSecretH" kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" _debug2 kDateH "$kDateH" diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index c38ff3e3..c09f16fd 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -34,7 +34,7 @@ dns_lexicon_add() { # shellcheck disable=SC2018,SC2019 Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') Lx_name_v=$(eval echo \$"$Lx_name") - _debug "$Lx_name" "$Lx_name_v" + _secure_debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then _saveaccountconf "$Lx_name" "$Lx_name_v" eval export "$Lx_name" @@ -43,7 +43,7 @@ dns_lexicon_add() { # shellcheck disable=SC2018,SC2019 Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') Lx_token_v=$(eval echo \$"$Lx_token") - _debug "$Lx_token" "$Lx_token_v" + _secure_debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then _saveaccountconf "$Lx_token" "$Lx_token_v" eval export "$Lx_token" @@ -52,7 +52,7 @@ dns_lexicon_add() { # shellcheck disable=SC2018,SC2019 Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') Lx_password_v=$(eval echo \$"$Lx_password") - _debug "$Lx_password" "$Lx_password_v" + _secure_debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then _saveaccountconf "$Lx_password" "$Lx_password_v" eval export "$Lx_password" @@ -61,7 +61,7 @@ dns_lexicon_add() { # shellcheck disable=SC2018,SC2019 Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") - _debug "$Lx_domaintoken" "$Lx_domaintoken_v" + _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then eval export "$Lx_domaintoken" _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 8833c0a1..faf5b42b 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -207,7 +207,7 @@ _ovh_authentication() { _err "Unable to get consumerKey" return 1 fi - _debug consumerKey "$consumerKey" + _secure_debug consumerKey "$consumerKey" OVH_CK="$consumerKey" _saveaccountconf OVH_CK "$OVH_CK" @@ -269,7 +269,7 @@ _ovh_rest() { _ovh_t="$(_ovh_timestamp)" _debug2 _ovh_t "$_ovh_t" _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t" - _debug _ovh_p "$_ovh_p" + _secure_debug _ovh_p "$_ovh_p" _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" _debug2 _ovh_hex "$_ovh_hex" From 43d3b51bdee418732e54d0779da491e9369b836f Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 19 Feb 2017 18:16:12 +0800 Subject: [PATCH 0743/1348] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2624690a..716abe20 100644 --- a/README.md +++ b/README.md @@ -403,6 +403,6 @@ Please Star and Fork me. # Donate -1. PayPal: donate@acme.sh - +1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) + [Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) From cb6f62295748a415c55316cb90865a2f3a9bc9e9 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 19 Feb 2017 18:19:24 +0800 Subject: [PATCH 0744/1348] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 716abe20..a297b998 100644 --- a/README.md +++ b/README.md @@ -378,21 +378,21 @@ acme.sh --upgrade --auto-upgrade 0 https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR -# Under the Hood +# 14. Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". TODO: -# Acknowledgments +# 15. Acknowledgments 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme 3. Certbot: https://github.com/certbot/certbot -# License & Others +# 16. License & Others License is GPLv3 @@ -401,7 +401,8 @@ Please Star and Fork me. [Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome. -# Donate +# 17. Donate +Your donation makes **acme.sh** better: 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) From 93bce1b24cd1f3af6740ed6a8070a2cd176f8201 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 20:15:00 +0800 Subject: [PATCH 0745/1348] support multiple deploy hook fix https://github.com/Neilpang/acme.sh/issues/508 --- acme.sh | 90 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/acme.sh b/acme.sh index a8b0790b..2086ccc2 100755 --- a/acme.sh +++ b/acme.sh @@ -3693,7 +3693,7 @@ renew() { fi if [ "$Le_DeployHook" ]; then - deploy "$Le_Domain" "$Le_DeployHook" "$Le_Keylength" + _deploy "$Le_Domain" "$Le_DeployHook" res="$?" fi @@ -3865,54 +3865,64 @@ list() { } +_deploy() { + _d="$1" + _hooks="$2" + + for _d_api in $(echo "$_hooks" | tr ',' " "); do + _deployApi="$(_findHook "$_d" deploy "$_d_api")" + if [ -z "$_deployApi" ]; then + _err "The deploy hook $_d_api is not found." + return 1 + fi + _debug _deployApi "$_deployApi" + + if ! ( + if ! . "$_deployApi"; then + _err "Load file $_deployApi error. Please check your api file and try again." + return 1 + fi + + d_command="${_d_api}_deploy" + if ! _exists "$d_command"; then + _err "It seems that your api file is not correct, it must have a function named: $d_command" + return 1 + fi + + if ! $d_command "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then + _err "Error deploy for domain:$_d" + return 1 + fi + ); then + _err "Deploy error." + return 1 + else + _info "$(__green Success)" + fi + done +} + +#domain hooks deploy() { - Le_Domain="$1" - Le_DeployHook="$2" + _d="$1" + _hooks="$2" _isEcc="$3" - if [ -z "$Le_DeployHook" ]; then + if [ -z "$_hooks" ]; then _usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] " return 1 fi - _initpath "$Le_Domain" "$_isEcc" + _initpath "$_d" "$_isEcc" if [ ! -d "$DOMAIN_PATH" ]; then - _err "Domain is not valid:'$Le_Domain'" - return 1 - fi - - _deployApi="$(_findHook "$Le_Domain" deploy "$Le_DeployHook")" - if [ -z "$_deployApi" ]; then - _err "The deploy hook $Le_DeployHook is not found." + _err "Domain is not valid:'$_d'" return 1 fi - _debug _deployApi "$_deployApi" - - _savedomainconf Le_DeployHook "$Le_DeployHook" - if ! ( - if ! . "$_deployApi"; then - _err "Load file $_deployApi error. Please check your api file and try again." - return 1 - fi - - d_command="${Le_DeployHook}_deploy" - if ! _exists "$d_command"; then - _err "It seems that your api file is not correct, it must have a function named: $d_command" - return 1 - fi + . "$DOMAIN_CONF" - if ! $d_command "$Le_Domain" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then - _err "Error deploy for domain:$Le_Domain" - _on_issue_err - return 1 - fi - ); then - _err "Deploy error." - return 1 - else - _info "$(__green Success)" - fi + _savedomainconf Le_DeployHook "$_hooks" + _deploy "$_d" "$_hooks" } installcert() { @@ -5136,7 +5146,11 @@ _process() { shift ;; --deploy-hook) - _deploy_hook="$2" + if [ -z "$2" ] || _startswith "$2" "-"; then + _usage "Please specify a value for '--deploy-hook'" + return 1 + fi + _deploy_hook="$_deploy_hook$2," shift ;; --ocsp-must-staple | --ocsp) From a6d2e3a1e6b34c1fbf0675401672b76e8925809b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 19 Feb 2017 13:26:32 +0100 Subject: [PATCH 0746/1348] Suppress shellcheck warnings. --- dnsapi/dns_cyon.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 0ced4217..c096d8b0 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -81,6 +81,7 @@ _cyon_is_idn() { _cyon_load_parameters() { # Read the required parameters to add the TXT entry. + # shellcheck disable=SC2018,SC2019 fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")" fulldomain_idn="${fulldomain}" From 3a1bd3114b3c965d9718ee5bb039ced856136a65 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 20:35:32 +0800 Subject: [PATCH 0747/1348] add hooks, not implemented yet. --- deploy/apache.sh | 26 ++++++++++++++++++++++++++ deploy/dovecot.sh | 26 ++++++++++++++++++++++++++ deploy/exim4.sh | 26 ++++++++++++++++++++++++++ deploy/haproxy.sh | 26 ++++++++++++++++++++++++++ deploy/mysqld.sh | 26 ++++++++++++++++++++++++++ deploy/nginx.sh | 26 ++++++++++++++++++++++++++ deploy/opensshd.sh | 26 ++++++++++++++++++++++++++ deploy/pureftpd.sh | 26 ++++++++++++++++++++++++++ deploy/vsftpd.sh | 26 ++++++++++++++++++++++++++ 9 files changed, 234 insertions(+) create mode 100644 deploy/apache.sh create mode 100644 deploy/dovecot.sh create mode 100644 deploy/exim4.sh create mode 100644 deploy/haproxy.sh create mode 100644 deploy/mysqld.sh create mode 100644 deploy/nginx.sh create mode 100644 deploy/opensshd.sh create mode 100644 deploy/pureftpd.sh create mode 100644 deploy/vsftpd.sh diff --git a/deploy/apache.sh b/deploy/apache.sh new file mode 100644 index 00000000..42de93f4 --- /dev/null +++ b/deploy/apache.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +apache_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Deploy cert to apache server, Not implemented yet" + return 1 + +} diff --git a/deploy/dovecot.sh b/deploy/dovecot.sh new file mode 100644 index 00000000..99a17d51 --- /dev/null +++ b/deploy/dovecot.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +dovecot_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Not implemented yet" + return 1 + +} diff --git a/deploy/exim4.sh b/deploy/exim4.sh new file mode 100644 index 00000000..cc53e344 --- /dev/null +++ b/deploy/exim4.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to exim4 server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +exim4_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to exim4 server, Not implemented yet" + return 1 + +} diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh new file mode 100644 index 00000000..e7fa5b09 --- /dev/null +++ b/deploy/haproxy.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to haproxy server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +haproxy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to haproxy server, Not implemented yet" + return 1 + +} diff --git a/deploy/mysqld.sh b/deploy/mysqld.sh new file mode 100644 index 00000000..6fb178d7 --- /dev/null +++ b/deploy/mysqld.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to mysqld server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +mysqld_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to mysqld server, Not implemented yet" + return 1 + +} diff --git a/deploy/nginx.sh b/deploy/nginx.sh new file mode 100644 index 00000000..2fb127fd --- /dev/null +++ b/deploy/nginx.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to nginx server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +nginx_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to nginx server, Not implemented yet" + return 1 + +} diff --git a/deploy/opensshd.sh b/deploy/opensshd.sh new file mode 100644 index 00000000..01fbc3f1 --- /dev/null +++ b/deploy/opensshd.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to opensshd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +opensshd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to opensshd server, Not implemented yet" + return 1 + +} diff --git a/deploy/pureftpd.sh b/deploy/pureftpd.sh new file mode 100644 index 00000000..28643204 --- /dev/null +++ b/deploy/pureftpd.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to pureftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +pureftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to pureftpd server, Not implemented yet" + return 1 + +} diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh new file mode 100644 index 00000000..7ff1a58a --- /dev/null +++ b/deploy/vsftpd.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to vsftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +vsftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to vsftpd server, Not implemented yet" + return 1 + +} From f845b371ceb95c4712405704928d90813d67c591 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 20:40:53 +0800 Subject: [PATCH 0748/1348] fix format --- deploy/apache.sh | 52 +++++++++++++++++++++++----------------------- deploy/dovecot.sh | 52 +++++++++++++++++++++++----------------------- deploy/exim4.sh | 52 +++++++++++++++++++++++----------------------- deploy/haproxy.sh | 52 +++++++++++++++++++++++----------------------- deploy/mysqld.sh | 52 +++++++++++++++++++++++----------------------- deploy/nginx.sh | 52 +++++++++++++++++++++++----------------------- deploy/opensshd.sh | 52 +++++++++++++++++++++++----------------------- deploy/pureftpd.sh | 52 +++++++++++++++++++++++----------------------- deploy/vsftpd.sh | 52 +++++++++++++++++++++++----------------------- 9 files changed, 234 insertions(+), 234 deletions(-) diff --git a/deploy/apache.sh b/deploy/apache.sh index 42de93f4..b6c1fbc2 100644 --- a/deploy/apache.sh +++ b/deploy/apache.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to dovecot server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -apache_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "Deploy cert to apache server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +apache_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Deploy cert to apache server, Not implemented yet" + return 1 + +} diff --git a/deploy/dovecot.sh b/deploy/dovecot.sh index 99a17d51..3baf23d9 100644 --- a/deploy/dovecot.sh +++ b/deploy/dovecot.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to dovecot server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -dovecot_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +dovecot_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Not implemented yet" + return 1 + +} diff --git a/deploy/exim4.sh b/deploy/exim4.sh index cc53e344..b53f58ec 100644 --- a/deploy/exim4.sh +++ b/deploy/exim4.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to exim4 server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -exim4_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to exim4 server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to exim4 server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +exim4_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to exim4 server, Not implemented yet" + return 1 + +} diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index e7fa5b09..34efbb1f 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to haproxy server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -haproxy_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to haproxy server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to haproxy server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +haproxy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to haproxy server, Not implemented yet" + return 1 + +} diff --git a/deploy/mysqld.sh b/deploy/mysqld.sh index 6fb178d7..8778843e 100644 --- a/deploy/mysqld.sh +++ b/deploy/mysqld.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to mysqld server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -mysqld_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to mysqld server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to mysqld server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +mysqld_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to mysqld server, Not implemented yet" + return 1 + +} diff --git a/deploy/nginx.sh b/deploy/nginx.sh index 2fb127fd..952b27f3 100644 --- a/deploy/nginx.sh +++ b/deploy/nginx.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to nginx server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -nginx_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to nginx server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to nginx server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +nginx_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to nginx server, Not implemented yet" + return 1 + +} diff --git a/deploy/opensshd.sh b/deploy/opensshd.sh index 01fbc3f1..9001b97c 100644 --- a/deploy/opensshd.sh +++ b/deploy/opensshd.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to opensshd server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -opensshd_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to opensshd server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to opensshd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +opensshd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to opensshd server, Not implemented yet" + return 1 + +} diff --git a/deploy/pureftpd.sh b/deploy/pureftpd.sh index 28643204..3d803601 100644 --- a/deploy/pureftpd.sh +++ b/deploy/pureftpd.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to pureftpd server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -pureftpd_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to pureftpd server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to pureftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +pureftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to pureftpd server, Not implemented yet" + return 1 + +} diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index 7ff1a58a..5e89ea95 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to vsftpd server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -vsftpd_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to vsftpd server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to vsftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +vsftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to vsftpd server, Not implemented yet" + return 1 + +} From af1cc3b3317d7a8ed2f4c65d8b57cb2cf7e75602 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 21:13:00 +0800 Subject: [PATCH 0749/1348] refactor params --- acme.sh | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/acme.sh b/acme.sh index 2086ccc2..d2910ab3 100755 --- a/acme.sh +++ b/acme.sh @@ -2707,6 +2707,7 @@ _clearupwebbroot() { } _on_before_issue() { + _chk_web_roots="$1" _debug _on_before_issue #run pre hook if [ "$Le_PreHook" ]; then @@ -2719,7 +2720,7 @@ _on_before_issue() { fi fi - if _hasfield "$Le_Webroot" "$NO_VALUE"; then + if _hasfield "$_chk_web_roots" "$NO_VALUE"; then if ! _exists "nc"; then _err "Please install netcat(nc) tools first." return 1 @@ -2734,7 +2735,7 @@ _on_before_issue() { _addrIndex=1 for d in $alldomains; do _debug "Check for domain" "$d" - _currentRoot="$(_getfield "$Le_Webroot" $_index)" + _currentRoot="$(_getfield "$_chk_web_roots" $_index)" _debug "_currentRoot" "$_currentRoot" _index=$(_math $_index + 1) _checkport="" @@ -2777,7 +2778,7 @@ _on_before_issue() { fi done - if _hasfield "$Le_Webroot" "apache"; then + if _hasfield "$_chk_web_roots" "apache"; then if ! _setApache; then _err "set up apache error. Report error to me." return 1 @@ -3027,11 +3028,11 @@ issue() { _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " return 1 fi - Le_Webroot="$1" - Le_Domain="$2" + _web_roots="$1" + _main_domain="$2" Le_Alt="$3" - if _contains "$Le_Domain" ","; then - Le_Domain=$(echo "$2,$3" | cut -d , -f 1) + if _contains "$_main_domain" ","; then + _main_domain=$(echo "$2,$3" | cut -d , -f 1) Le_Alt=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi Le_Keylength="$4" @@ -3046,19 +3047,19 @@ issue() { Le_LocalAddress="${13}" #remove these later. - if [ "$Le_Webroot" = "dns-cf" ]; then - Le_Webroot="dns_cf" + if [ "$_web_roots" = "dns-cf" ]; then + _web_roots="dns_cf" fi - if [ "$Le_Webroot" = "dns-dp" ]; then - Le_Webroot="dns_dp" + if [ "$_web_roots" = "dns-dp" ]; then + _web_roots="dns_dp" fi - if [ "$Le_Webroot" = "dns-cx" ]; then - Le_Webroot="dns_cx" + if [ "$_web_roots" = "dns-cx" ]; then + _web_roots="dns_cx" fi _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then - _initpath "$Le_Domain" "$Le_Keylength" + _initpath "$_main_domain" "$Le_Keylength" mkdir -p "$DOMAIN_PATH" fi @@ -3070,7 +3071,7 @@ issue() { _debug _saved_domain "$_saved_domain" _saved_alt=$(_readdomainconf Le_Alt) _debug _saved_alt "$_saved_alt" - if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ]; then + if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$Le_Alt" ]; then _info "Domains not changed." _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" _info "Add '$(__red '--force')' to force to renew." @@ -3081,9 +3082,9 @@ issue() { fi fi - _savedomainconf "Le_Domain" "$Le_Domain" + _savedomainconf "Le_Domain" "$_main_domain" _savedomainconf "Le_Alt" "$Le_Alt" - _savedomainconf "Le_Webroot" "$Le_Webroot" + _savedomainconf "Le_Webroot" "$_web_roots" _savedomainconf "Le_PreHook" "$Le_PreHook" _savedomainconf "Le_PostHook" "$Le_PostHook" @@ -3106,7 +3107,7 @@ issue() { Le_Keylength="" fi - if ! _on_before_issue; then + if ! _on_before_issue "$_web_roots"; then _err "_on_before_issue." return 1 fi @@ -3129,7 +3130,7 @@ issue() { _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then - if ! createDomainKey "$Le_Domain" "$Le_Keylength"; then + if ! createDomainKey "$_main_domain" "$Le_Keylength"; then _err "Create domain key error." _clearup _on_issue_err @@ -3137,7 +3138,7 @@ issue() { fi fi - if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then + if ! _createcsr "$_main_domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then _err "Create CSR error." _clearup _on_issue_err @@ -3153,12 +3154,12 @@ issue() { sep='#' dvsep=',' if [ -z "$vlist" ]; then - alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') + alldomains=$(echo "$_main_domain,$Le_Alt" | tr ',' ' ') _index=1 _currentRoot="" for d in $alldomains; do _info "Getting webroot for domain" "$d" - _w="$(echo $Le_Webroot | cut -d , -f $_index)" + _w="$(echo $_web_roots | cut -d , -f $_index)" _debug _w "$_w" if [ "$_w" ]; then _currentRoot="$_w" From 02140ce763c2f254674def89ee63ab9b5bbc4feb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 21:18:00 +0800 Subject: [PATCH 0750/1348] refactor alt domains --- acme.sh | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index d2910ab3..30bb0585 100755 --- a/acme.sh +++ b/acme.sh @@ -2708,6 +2708,8 @@ _clearupwebbroot() { _on_before_issue() { _chk_web_roots="$1" + _chk_main_domain="$2" + _chk_alt_domains="$3" _debug _on_before_issue #run pre hook if [ "$Le_PreHook" ]; then @@ -2729,7 +2731,7 @@ _on_before_issue() { _debug Le_LocalAddress "$Le_LocalAddress" - alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') + alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ') _index=1 _currentRoot="" _addrIndex=1 @@ -3030,10 +3032,10 @@ issue() { fi _web_roots="$1" _main_domain="$2" - Le_Alt="$3" + _alt_domains="$3" if _contains "$_main_domain" ","; then _main_domain=$(echo "$2,$3" | cut -d , -f 1) - Le_Alt=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") + _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi Le_Keylength="$4" Le_RealCertPath="$5" @@ -3071,7 +3073,7 @@ issue() { _debug _saved_domain "$_saved_domain" _saved_alt=$(_readdomainconf Le_Alt) _debug _saved_alt "$_saved_alt" - if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$Le_Alt" ]; then + if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then _info "Domains not changed." _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" _info "Add '$(__red '--force')' to force to renew." @@ -3083,7 +3085,7 @@ issue() { fi _savedomainconf "Le_Domain" "$_main_domain" - _savedomainconf "Le_Alt" "$Le_Alt" + _savedomainconf "Le_Alt" "$_alt_domains" _savedomainconf "Le_Webroot" "$_web_roots" _savedomainconf "Le_PreHook" "$Le_PreHook" @@ -3099,15 +3101,15 @@ issue() { Le_API="$API" _savedomainconf "Le_API" "$Le_API" - if [ "$Le_Alt" = "$NO_VALUE" ]; then - Le_Alt="" + if [ "$_alt_domains" = "$NO_VALUE" ]; then + _alt_domains="" fi if [ "$Le_Keylength" = "$NO_VALUE" ]; then Le_Keylength="" fi - if ! _on_before_issue "$_web_roots"; then + if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains"; then _err "_on_before_issue." return 1 fi @@ -3138,7 +3140,7 @@ issue() { fi fi - if ! _createcsr "$_main_domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then + if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then _err "Create CSR error." _clearup _on_issue_err @@ -3154,7 +3156,7 @@ issue() { sep='#' dvsep=',' if [ -z "$vlist" ]; then - alldomains=$(echo "$_main_domain,$Le_Alt" | tr ',' ' ') + alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ') _index=1 _currentRoot="" for d in $alldomains; do From d9c9114b3b897dcedd4c6a77f5dd03a346caec06 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 21:21:11 +0800 Subject: [PATCH 0751/1348] refactor key length --- acme.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 30bb0585..a9f9e72c 100755 --- a/acme.sh +++ b/acme.sh @@ -3037,7 +3037,7 @@ issue() { _main_domain=$(echo "$2,$3" | cut -d , -f 1) _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi - Le_Keylength="$4" + _key_length="$4" Le_RealCertPath="$5" Le_RealKeyPath="$6" Le_RealCACertPath="$7" @@ -3061,7 +3061,7 @@ issue() { _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then - _initpath "$_main_domain" "$Le_Keylength" + _initpath "$_main_domain" "$_key_length" mkdir -p "$DOMAIN_PATH" fi @@ -3105,8 +3105,8 @@ issue() { _alt_domains="" fi - if [ "$Le_Keylength" = "$NO_VALUE" ]; then - Le_Keylength="" + if [ "$_key_length" = "$NO_VALUE" ]; then + _key_length="" fi if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains"; then @@ -3131,8 +3131,8 @@ issue() { else _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" - if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then - if ! createDomainKey "$_main_domain" "$Le_Keylength"; then + if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ]; then + if ! createDomainKey "$_main_domain" "$_key_length"; then _err "Create domain key error." _clearup _on_issue_err @@ -3148,7 +3148,7 @@ issue() { fi fi - _savedomainconf "Le_Keylength" "$Le_Keylength" + _savedomainconf "Le_Keylength" "$_key_length" vlist="$Le_Vlist" From 85e1f4ea13f2fa5a754bf6c65795c03da84f2584 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 22:09:22 +0800 Subject: [PATCH 0752/1348] refactor parameters --- acme.sh | 227 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 120 insertions(+), 107 deletions(-) diff --git a/acme.sh b/acme.sh index a9f9e72c..db77c226 100755 --- a/acme.sh +++ b/acme.sh @@ -2710,12 +2710,14 @@ _on_before_issue() { _chk_web_roots="$1" _chk_main_domain="$2" _chk_alt_domains="$3" + _chk_pre_hook="$4" + _chk_local_addr="$5" _debug _on_before_issue #run pre hook - if [ "$Le_PreHook" ]; then - _info "Run pre hook:'$Le_PreHook'" + if [ "$_chk_pre_hook" ]; then + _info "Run pre hook:'$_chk_pre_hook'" if ! ( - cd "$DOMAIN_PATH" && eval "$Le_PreHook" + cd "$DOMAIN_PATH" && eval "$_chk_pre_hook" ); then _err "Error when run pre hook." return 1 @@ -2729,7 +2731,7 @@ _on_before_issue() { fi fi - _debug Le_LocalAddress "$Le_LocalAddress" + _debug Le_LocalAddress "$_chk_local_addr" alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ') _index=1 @@ -2761,7 +2763,7 @@ _on_before_issue() { if [ "$_checkport" ]; then _debug _checkport "$_checkport" - _checkaddr="$(_getfield "$Le_LocalAddress" $_addrIndex)" + _checkaddr="$(_getfield "$_chk_local_addr" $_addrIndex)" _debug _checkaddr "$_checkaddr" _addrIndex="$(_math $_addrIndex + 1)" @@ -2792,6 +2794,7 @@ _on_before_issue() { } _on_issue_err() { + _chk_post_hook="$1" _debug _on_issue_err if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" @@ -2805,10 +2808,10 @@ _on_issue_err() { fi #run the post hook - if [ "$Le_PostHook" ]; then - _info "Run post hook:'$Le_PostHook'" + if [ "$_chk_post_hook" ]; then + _info "Run post hook:'$_chk_post_hook'" if ! ( - cd "$DOMAIN_PATH" && eval "$Le_PostHook" + cd "$DOMAIN_PATH" && eval "$_chk_post_hook" ); then _err "Error when run post hook." return 1 @@ -2817,12 +2820,14 @@ _on_issue_err() { } _on_issue_success() { + _chk_post_hook="$1" + _chk_renew_hook="$2" _debug _on_issue_success #run the post hook - if [ "$Le_PostHook" ]; then - _info "Run post hook:'$Le_PostHook'" + if [ "$_chk_post_hook" ]; then + _info "Run post hook:'$_chk_post_hook'" if ! ( - cd "$DOMAIN_PATH" && eval "$Le_PostHook" + cd "$DOMAIN_PATH" && eval "$_chk_post_hook" ); then _err "Error when run post hook." return 1 @@ -2830,10 +2835,10 @@ _on_issue_success() { fi #run renew hook - if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ]; then - _info "Run renew hook:'$Le_RenewHook'" + if [ "$IS_RENEW" ] && [ "$_chk_renew_hook" ]; then + _info "Run renew hook:'$_chk_renew_hook'" if ! ( - cd "$DOMAIN_PATH" && eval "$Le_RenewHook" + cd "$DOMAIN_PATH" && eval "$_chk_renew_hook" ); then _err "Error when run renew hook." return 1 @@ -3038,15 +3043,15 @@ issue() { _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi _key_length="$4" - Le_RealCertPath="$5" - Le_RealKeyPath="$6" - Le_RealCACertPath="$7" - Le_ReloadCmd="$8" - Le_RealFullChainPath="$9" - Le_PreHook="${10}" - Le_PostHook="${11}" - Le_RenewHook="${12}" - Le_LocalAddress="${13}" + _real_cert="$5" + _real_key="$6" + _real_ca="$7" + _reload_cmd="$8" + _real_fullchain="$9" + _pre_hook="${10}" + _post_hook="${11}" + _renew_hook="${12}" + _local_addr="${13}" #remove these later. if [ "$_web_roots" = "dns-cf" ]; then @@ -3088,12 +3093,12 @@ issue() { _savedomainconf "Le_Alt" "$_alt_domains" _savedomainconf "Le_Webroot" "$_web_roots" - _savedomainconf "Le_PreHook" "$Le_PreHook" - _savedomainconf "Le_PostHook" "$Le_PostHook" - _savedomainconf "Le_RenewHook" "$Le_RenewHook" + _savedomainconf "Le_PreHook" "$_pre_hook" + _savedomainconf "Le_PostHook" "$_post_hook" + _savedomainconf "Le_RenewHook" "$_renew_hook" - if [ "$Le_LocalAddress" ]; then - _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" + if [ "$_local_addr" ]; then + _savedomainconf "Le_LocalAddress" "$_local_addr" else _cleardomainconf "Le_LocalAddress" fi @@ -3109,7 +3114,7 @@ issue() { _key_length="" fi - if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains"; then + if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then _err "_on_before_issue." return 1 fi @@ -3119,7 +3124,7 @@ issue() { if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then if ! _regAccount "$_accountkeylength"; then - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi else @@ -3135,7 +3140,7 @@ issue() { if ! createDomainKey "$_main_domain" "$_key_length"; then _err "Create domain key error." _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi fi @@ -3143,7 +3148,7 @@ issue() { if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then _err "Create CSR error." _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi fi @@ -3180,7 +3185,7 @@ issue() { if ! __get_domain_new_authz "$d"; then _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3193,7 +3198,7 @@ issue() { if [ -z "$entry" ]; then _err "Error, can not get domain token $d" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" @@ -3274,7 +3279,7 @@ issue() { if [ "$?" != "0" ]; then _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi dnsadded='1' @@ -3286,7 +3291,7 @@ issue() { _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3332,12 +3337,12 @@ issue() { if [ "$vtype" = "$VTYPE_HTTP" ]; then if [ "$_currentRoot" = "$NO_VALUE" ]; then _info "Standalone mode server" - _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" + _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" _ncIndex="$(_math $_ncIndex + 1)" _startserver "$keyauthorization" "$_ncaddr" & if [ "$?" != "0" ]; then _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi serverproc="$!" @@ -3353,7 +3358,7 @@ issue() { BACKUP_NGINX_CONF="" if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3388,7 +3393,7 @@ issue() { _err "$d:Can not write token to file : $wellknown_path/$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3427,13 +3432,13 @@ issue() { _SAN_B="$_x.$_y.acme.invalid" _debug2 _SAN_B "$_SAN_B" - _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" + _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" _ncIndex="$(_math "$_ncIndex" + 1)" if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then _err "Start tls server error." _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi fi @@ -3442,7 +3447,7 @@ issue() { _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3450,7 +3455,7 @@ issue() { _err "$d:Challenge error: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3477,7 +3482,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi _debug2 original "$response" @@ -3512,7 +3517,7 @@ issue() { fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3522,7 +3527,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3536,7 +3541,7 @@ issue() { if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3578,7 +3583,7 @@ issue() { if [ -z "$Le_LinkCert" ]; then response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)" _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3640,10 +3645,15 @@ issue() { Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - _on_issue_success + _on_issue_success "$_post_hook" "$_renew_hook" - if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ]; then - _installcert + if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then + _savedomainconf "Le_RealCertPath" "$_real_cert" + _savedomainconf "Le_RealCACertPath" "$_real_ca" + _savedomainconf "Le_RealKeyPath" "$_real_key" + _savedomainconf "Le_ReloadCmd" "$_reload_cmd" + _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" fi } @@ -3929,104 +3939,107 @@ deploy() { } installcert() { - Le_Domain="$1" - if [ -z "$Le_Domain" ]; then + _main_domain="$1" + 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]" return 1 fi - Le_RealCertPath="$2" - Le_RealKeyPath="$3" - Le_RealCACertPath="$4" - Le_ReloadCmd="$5" - Le_RealFullChainPath="$6" + _real_cert="$2" + _real_key="$3" + _real_ca="$4" + _reload_cmd="$5" + _real_fullchain="$6" _isEcc="$7" - _initpath "$Le_Domain" "$_isEcc" + _initpath "$_main_domain" "$_isEcc" if [ ! -d "$DOMAIN_PATH" ]; then - _err "Domain is not valid:'$Le_Domain'" + _err "Domain is not valid:'$_main_domain'" return 1 fi - _installcert + _savedomainconf "Le_RealCertPath" "$_real_cert" + _savedomainconf "Le_RealCACertPath" "$_real_ca" + _savedomainconf "Le_RealKeyPath" "$_real_key" + _savedomainconf "Le_ReloadCmd" "$_reload_cmd" + _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" + + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" } _installcert() { - _savedomainconf "Le_RealCertPath" "$Le_RealCertPath" - _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath" - _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath" - _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd" - _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath" + _main_domain="$1" + _real_cert="$2" + _real_key="$3" + _real_ca="$4" + _reload_cmd="$5" + _real_fullchain="$6" - if [ "$Le_RealCertPath" = "$NO_VALUE" ]; then - Le_RealCertPath="" + if [ "$_real_cert" = "$NO_VALUE" ]; then + _real_cert="" fi - if [ "$Le_RealKeyPath" = "$NO_VALUE" ]; then - Le_RealKeyPath="" + if [ "$_real_key" = "$NO_VALUE" ]; then + _real_key="" fi - if [ "$Le_RealCACertPath" = "$NO_VALUE" ]; then - Le_RealCACertPath="" + if [ "$_real_ca" = "$NO_VALUE" ]; then + _real_ca="" fi - if [ "$Le_ReloadCmd" = "$NO_VALUE" ]; then - Le_ReloadCmd="" + if [ "$_reload_cmd" = "$NO_VALUE" ]; then + _reload_cmd="" fi - if [ "$Le_RealFullChainPath" = "$NO_VALUE" ]; then - Le_RealFullChainPath="" + if [ "$_real_fullchain" = "$NO_VALUE" ]; then + _real_fullchain="" fi - if [ "$Le_RealCertPath" ]; then - - _info "Installing cert to:$Le_RealCertPath" - if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then + if [ "$_real_cert" ]; then + _info "Installing cert to:$_real_cert" + if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$Le_RealCertPath" "$DOMAIN_BACKUP_PATH/cert.bak" + cp "$_real_cert" "$DOMAIN_BACKUP_PATH/cert.bak" fi - cat "$CERT_PATH" >"$Le_RealCertPath" + cat "$CERT_PATH" >"$_real_cert" fi - if [ "$Le_RealCACertPath" ]; then - - _info "Installing CA to:$Le_RealCACertPath" - if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ]; then - echo "" >>"$Le_RealCACertPath" - cat "$CA_CERT_PATH" >>"$Le_RealCACertPath" + if [ "$_real_ca" ]; then + _info "Installing CA to:$_real_ca" + if [ "$_real_ca" = "$_real_cert" ]; then + echo "" >>"$_real_ca" + cat "$CA_CERT_PATH" >>"$_real_ca" else - if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then + if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$Le_RealCACertPath" "$DOMAIN_BACKUP_PATH/ca.bak" + cp "$_real_ca" "$DOMAIN_BACKUP_PATH/ca.bak" fi - cat "$CA_CERT_PATH" >"$Le_RealCACertPath" + cat "$CA_CERT_PATH" >"$_real_ca" fi fi - if [ "$Le_RealKeyPath" ]; then - - _info "Installing key to:$Le_RealKeyPath" - if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then + if [ "$_real_key" ]; then + _info "Installing key to:$_real_key" + if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$Le_RealKeyPath" "$DOMAIN_BACKUP_PATH/key.bak" + cp "$_real_key" "$DOMAIN_BACKUP_PATH/key.bak" fi - cat "$CERT_KEY_PATH" >"$Le_RealKeyPath" + cat "$CERT_KEY_PATH" >"$_real_key" fi - if [ "$Le_RealFullChainPath" ]; then - - _info "Installing full chain to:$Le_RealFullChainPath" - if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then + if [ "$_real_fullchain" ]; then + _info "Installing full chain to:$_real_fullchain" + if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$Le_RealFullChainPath" "$DOMAIN_BACKUP_PATH/fullchain.bak" + cp "$_real_fullchain" "$DOMAIN_BACKUP_PATH/fullchain.bak" fi - cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath" + cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" fi - if [ "$Le_ReloadCmd" ]; then - _info "Run Le_ReloadCmd: $Le_ReloadCmd" + if [ "$_reload_cmd" ]; then + _info "Run reload cmd: $_reload_cmd" if ( export CERT_PATH export CERT_KEY_PATH export CA_CERT_PATH export CERT_FULLCHAIN_PATH - cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" + cd "$DOMAIN_PATH" && eval "$_reload_cmd" ); then _info "$(__green "Reload success")" else From 8796adfd6393257177f96e2b5ab8bf0dfd0d2a47 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 20 Feb 2017 18:03:16 +0800 Subject: [PATCH 0753/1348] fix https://github.com/Neilpang/acme.sh/issues/614 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index db77c226..1bd955bc 100755 --- a/acme.sh +++ b/acme.sh @@ -1088,7 +1088,7 @@ _readKeyLengthFromCSR() { echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + echo "$_outcsr" | _egrep_o "(^ *|^RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 fi } From 1efb2085e98859261f9b697b1358a4478d5bb5cf Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 20 Feb 2017 20:18:58 +0800 Subject: [PATCH 0754/1348] fix debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 1bd955bc..43f87e98 100755 --- a/acme.sh +++ b/acme.sh @@ -1730,7 +1730,7 @@ _setopt() { _debug3 APP echo "$__opt$__sep$__val$__end" >>"$__conf" fi - _debug2 "$(grep -n "^$__opt$__sep" "$__conf")" + _debug3 "$(grep -n "^$__opt$__sep" "$__conf")" } #_save_conf file key value From 044da37c953003e284c2307624c858a4fecbba0c Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 21 Feb 2017 21:34:43 +0800 Subject: [PATCH 0755/1348] change installcert parameter order --- acme.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 43f87e98..e24d4d9a 100755 --- a/acme.sh +++ b/acme.sh @@ -3653,7 +3653,7 @@ issue() { _savedomainconf "Le_RealKeyPath" "$_real_key" _savedomainconf "Le_ReloadCmd" "$_reload_cmd" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" - _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" fi } @@ -3964,16 +3964,18 @@ installcert() { _savedomainconf "Le_ReloadCmd" "$_reload_cmd" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" - _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" } +#domain cert key ca fullchain reloadcmd backup-prefix _installcert() { _main_domain="$1" _real_cert="$2" _real_key="$3" _real_ca="$4" - _reload_cmd="$5" - _real_fullchain="$6" + _real_fullchain="$5" + _reload_cmd="$6" + _backup_prefix="$7" if [ "$_real_cert" = "$NO_VALUE" ]; then _real_cert="" @@ -3991,11 +3993,13 @@ _installcert() { _real_fullchain="" fi + _backup_path="$DOMAIN_BACKUP_PATH/$_backup_prefix" + mkdir -p "$_backup_path" + if [ "$_real_cert" ]; then _info "Installing cert to:$_real_cert" if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then - mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$_real_cert" "$DOMAIN_BACKUP_PATH/cert.bak" + cp "$_real_cert" "$_backup_path/cert.bak" fi cat "$CERT_PATH" >"$_real_cert" fi @@ -4007,8 +4011,7 @@ _installcert() { cat "$CA_CERT_PATH" >>"$_real_ca" else if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then - mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$_real_ca" "$DOMAIN_BACKUP_PATH/ca.bak" + cp "$_real_ca" "$_backup_path/ca.bak" fi cat "$CA_CERT_PATH" >"$_real_ca" fi @@ -4017,8 +4020,7 @@ _installcert() { if [ "$_real_key" ]; then _info "Installing key to:$_real_key" if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then - mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$_real_key" "$DOMAIN_BACKUP_PATH/key.bak" + cp "$_real_key" "$_backup_path/key.bak" fi cat "$CERT_KEY_PATH" >"$_real_key" fi @@ -4026,8 +4028,7 @@ _installcert() { if [ "$_real_fullchain" ]; then _info "Installing full chain to:$_real_fullchain" if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then - mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$_real_fullchain" "$DOMAIN_BACKUP_PATH/fullchain.bak" + cp "$_real_fullchain" "$_backup_path/fullchain.bak" fi cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" fi From 6dfc8fe0ea0f0d0889946d3cc54bd5ec21f7e59d Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 21 Feb 2017 23:18:11 +0800 Subject: [PATCH 0756/1348] support vsftpd hook --- deploy/README.md | 20 +++++++++++++ deploy/vsftpd.sh | 75 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index fcdf8019..cb500311 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -26,5 +26,25 @@ Before you can deploy your cert, you must [issue the cert first](https://github. (TODO) +## 4. Deploy the cert to local vsftpd server. +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd +``` + +The default vsftpd conf file is `/etc/vsftpd.conf`, if your vsftpd conf is not in the default location, you can specify one: + +```sh +export DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" + +acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd +``` + +The default command to restart vsftpd server is `service vsftpd restart`, if it doesn't work, you can specify one: + +```sh +export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart" + +acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd +``` diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index 5e89ea95..d2d8aa16 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -4,6 +4,9 @@ #returns 0 means success, otherwise error. +#DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" +#DEPLOY_VSFTPD_RELOAD="service vsftpd restart" + ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -20,7 +23,75 @@ vsftpd_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _err "deploy cert to vsftpd server, Not implemented yet" - return 1 + _ssl_path="/etc/acme.sh/vsftpd" + if ! mkdir -p "$_ssl_path"; then + _err "Can not create folder:$_ssl_path" + return 1 + fi + + DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" + _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" + if [ ! -f "$_vsftpd_conf" ]; then + if [ -z "$DEPLOY_VSFTPD_CONF" ]; then + _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" + return 1 + else + _err "It seems that the specified vsftpd conf is not valid, please check." + return 1 + fi + fi + + if [ ! -w "$_vsftpd_conf" ]; then + _err "The file $_vsftpd_conf is not writable, please change the permission." + return 1 + fi + + _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" + _info "Backup $_vsftpd_conf to $_backup_conf" + cp "$_vsftpd_conf" "$_backup_conf" + + _info "Copying key and cert" + _real_key="$_ssl_path/vsftpd.key" + if ! cat "$_ckey" >"$_real_key"; then + _err "Error: write key file to: $_real_key" + return 1 + fi + _real_fullchain="$_ssl_path/vsftpd.chain.pem" + if ! cat "$_cfullchain" >"$_real_fullchain"; then + _err "Error: write key file to: $_real_fullchain" + return 1 + fi + _info "Modify vsftpd conf: $_vsftpd_conf" + + DEFAULT_VSFTPD_RELOAD="service vsftpd restart" + _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" + if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ + && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \ + && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES" \ + && eval "$_reload"; then + _info "Deploy success!" + if [ "$DEPLOY_VSFTPD_CONF" ]; then + _savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF" + else + _cleardomainconf DEPLOY_VSFTPD_CONF + fi + if [ "$DEPLOY_VSFTPD_RELOAD" ]; then + _savedomainconf DEPLOY_VSFTPD_RELOAD "$DEPLOY_VSFTPD_RELOAD" + else + _cleardomainconf DEPLOY_VSFTPD_RELOAD + fi + return 0 + else + _err "Config vsftpd server error, please report bug to us." + _info "Restoring vsftpd conf" + if cat "$_backup_conf" >"$_vsftpd_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Opps, error restore vsftpd conf, please report bug to us." + fi + return 1 + fi + return 1 } From 45d6e00ff14a48f4ebd9a4a5a5a06cecad6b41d2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Feb 2017 20:17:36 +0800 Subject: [PATCH 0757/1348] fix format --- deploy/vsftpd.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index d2d8aa16..cc57f990 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -39,7 +39,7 @@ vsftpd_deploy() { else _err "It seems that the specified vsftpd conf is not valid, please check." return 1 - fi + fi fi if [ ! -w "$_vsftpd_conf" ]; then @@ -50,7 +50,7 @@ vsftpd_deploy() { _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" _info "Backup $_vsftpd_conf to $_backup_conf" cp "$_vsftpd_conf" "$_backup_conf" - + _info "Copying key and cert" _real_key="$_ssl_path/vsftpd.key" if ! cat "$_ckey" >"$_real_key"; then @@ -63,7 +63,7 @@ vsftpd_deploy() { return 1 fi _info "Modify vsftpd conf: $_vsftpd_conf" - + DEFAULT_VSFTPD_RELOAD="service vsftpd restart" _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ From ddf293bbcda2196ea9e7ec18d97d9f5a9a45d4c5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Feb 2017 20:40:33 +0800 Subject: [PATCH 0758/1348] reload only for renewal --- deploy/vsftpd.sh | 75 ++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index cc57f990..1c6410a6 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -29,28 +29,6 @@ vsftpd_deploy() { return 1 fi - DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" - _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" - - if [ ! -f "$_vsftpd_conf" ]; then - if [ -z "$DEPLOY_VSFTPD_CONF" ]; then - _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" - return 1 - else - _err "It seems that the specified vsftpd conf is not valid, please check." - return 1 - fi - fi - - if [ ! -w "$_vsftpd_conf" ]; then - _err "The file $_vsftpd_conf is not writable, please change the permission." - return 1 - fi - - _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" - _info "Backup $_vsftpd_conf to $_backup_conf" - cp "$_vsftpd_conf" "$_backup_conf" - _info "Copying key and cert" _real_key="$_ssl_path/vsftpd.key" if ! cat "$_ckey" >"$_real_key"; then @@ -62,15 +40,51 @@ vsftpd_deploy() { _err "Error: write key file to: $_real_fullchain" return 1 fi - _info "Modify vsftpd conf: $_vsftpd_conf" DEFAULT_VSFTPD_RELOAD="service vsftpd restart" _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" - if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ - && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \ - && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES" \ - && eval "$_reload"; then - _info "Deploy success!" + + if [ -z "$IS_RENEW" ]; then + DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" + _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" + if [ ! -f "$_vsftpd_conf" ]; then + if [ -z "$DEPLOY_VSFTPD_CONF" ]; then + _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" + return 1 + else + _err "It seems that the specified vsftpd conf is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_vsftpd_conf" ]; then + _err "The file $_vsftpd_conf is not writable, please change the permission." + return 1 + fi + _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" + _info "Backup $_vsftpd_conf to $_backup_conf" + cp "$_vsftpd_conf" "$_backup_conf" + + _info "Modify vsftpd conf: $_vsftpd_conf" + if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ + && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \ + && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then + _info "Set config success!" + else + _err "Config vsftpd server error, please report bug to us." + _info "Restoring vsftpd conf" + if cat "$_backup_conf" >"$_vsftpd_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Opps, error restore vsftpd conf, please report bug to us." + fi + return 1 + fi + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" if [ "$DEPLOY_VSFTPD_CONF" ]; then _savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF" else @@ -83,8 +97,7 @@ vsftpd_deploy() { fi return 0 else - _err "Config vsftpd server error, please report bug to us." - _info "Restoring vsftpd conf" + _err "Reload error, restoring" if cat "$_backup_conf" >"$_vsftpd_conf"; then _info "Restore conf success" eval "$_reload" @@ -93,5 +106,5 @@ vsftpd_deploy() { fi return 1 fi - return 1 + return 0 } From 35ca729cb939fb3a2e4798992fc51eb5b1ddda88 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 23 Feb 2017 19:01:48 +0800 Subject: [PATCH 0759/1348] fix doc --- deploy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index cb500311..40800401 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -13,7 +13,7 @@ Then you can deploy now: ```sh export DEPLOY_CPANEL_USER=myusername export DEPLOY_CPANEL_PASSWORD=PASSWORD -acme.sh --deploy -d example.com --deploy --deploy-hook cpanel +acme.sh --deploy -d example.com --deploy-hook cpanel ``` ## 2. Deploy ssl cert on kong proxy engine based on api. From a239a9efd508aa45d7299df6bb24e216b113251e Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 23 Feb 2017 19:04:08 +0800 Subject: [PATCH 0760/1348] fix doc --- deploy/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 40800401..a4e9136f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,12 +1,14 @@ # Using deploy 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). + Here are the scripts to deploy the certs/key to the server/services. ## 1. Deploy the certs to your cpanel host. (cpanel deploy hook is not finished yet, this is just an example.) -Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). + Then you can deploy now: From 1965035166a6259641d3f0c43de930ebb8d8b878 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 23 Feb 2017 20:03:03 +0800 Subject: [PATCH 0761/1348] support exim4 deploy --- deploy/README.md | 22 ++++++++++++ deploy/exim4.sh | 92 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index a4e9136f..4a13e096 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -50,3 +50,25 @@ export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart" acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd ``` +## 5. Deploy the cert to local exim4 server. + +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook exim4 +``` + +The default exim4 conf file is `/etc/exim/exim.conf`, if your exim4 conf is not in the default location, you can specify one: + +```sh +export DEPLOY_EXIM4_CONF="/etc/exim4/exim4.conf.template" + +acme.sh --deploy -d ftp.example.com --deploy-hook exim4 +``` + +The default command to restart exim4 server is `service exim4 restart`, if it doesn't work, you can specify one: + +```sh +export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart" + +acme.sh --deploy -d ftp.example.com --deploy-hook exim4 +``` + diff --git a/deploy/exim4.sh b/deploy/exim4.sh index b53f58ec..bf92b438 100644 --- a/deploy/exim4.sh +++ b/deploy/exim4.sh @@ -4,6 +4,9 @@ #returns 0 means success, otherwise error. +#DEPLOY_EXIM4_CONF="/etc/exim/exim.conf" +#DEPLOY_EXIM4_RELOAD="service exim4 restart" + ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -20,7 +23,92 @@ exim4_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _err "deploy cert to exim4 server, Not implemented yet" - return 1 + _ssl_path="/etc/acme.sh/exim4" + if ! mkdir -p "$_ssl_path"; then + _err "Can not create folder:$_ssl_path" + return 1 + fi + + _info "Copying key and cert" + _real_key="$_ssl_path/exim4.key" + if ! cat "$_ckey" >"$_real_key"; then + _err "Error: write key file to: $_real_key" + return 1 + fi + _real_fullchain="$_ssl_path/exim4.pem" + if ! cat "$_cfullchain" >"$_real_fullchain"; then + _err "Error: write key file to: $_real_fullchain" + return 1 + fi + + DEFAULT_EXIM4_RELOAD="service exim4 restart" + _reload="${DEPLOY_EXIM4_RELOAD:-$DEFAULT_EXIM4_RELOAD}" + + if [ -z "$IS_RENEW" ]; then + DEFAULT_EXIM4_CONF="/etc/exim/exim.conf" + if [ ! -f "$DEFAULT_EXIM4_CONF" ]; then + DEFAULT_EXIM4_CONF="/etc/exim4/exim4.conf.template" + fi + _exim4_conf="${DEPLOY_EXIM4_CONF:-$DEFAULT_EXIM4_CONF}" + _debug _exim4_conf "$_exim4_conf" + if [ ! -f "$_exim4_conf" ]; then + if [ -z "$DEPLOY_EXIM4_CONF" ]; then + _err "exim4 conf is not found, please define DEPLOY_EXIM4_CONF" + return 1 + else + _err "It seems that the specified exim4 conf is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_exim4_conf" ]; then + _err "The file $_exim4_conf is not writable, please change the permission." + return 1 + fi + _backup_conf="$DOMAIN_BACKUP_PATH/exim4.conf.bak" + _info "Backup $_exim4_conf to $_backup_conf" + cp "$_exim4_conf" "$_backup_conf" + + _info "Modify exim4 conf: $_exim4_conf" + if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" \ + && _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then + _info "Set config success!" + else + _err "Config exim4 server error, please report bug to us." + _info "Restoring exim4 conf" + if cat "$_backup_conf" >"$_exim4_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Opps, error restore exim4 conf, please report bug to us." + fi + return 1 + fi + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + if [ "$DEPLOY_EXIM4_CONF" ]; then + _savedomainconf DEPLOY_EXIM4_CONF "$DEPLOY_EXIM4_CONF" + else + _cleardomainconf DEPLOY_EXIM4_CONF + fi + if [ "$DEPLOY_EXIM4_RELOAD" ]; then + _savedomainconf DEPLOY_EXIM4_RELOAD "$DEPLOY_EXIM4_RELOAD" + else + _cleardomainconf DEPLOY_EXIM4_RELOAD + fi + return 0 + else + _err "Reload error, restoring" + if cat "$_backup_conf" >"$_exim4_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Opps, error restore exim4 conf, please report bug to us." + fi + return 1 + fi + return 0 } From 7b2fa1edb41a3b8a447cc590d0450a4a60c4029f Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Fri, 2 Dec 2016 20:10:13 +0000 Subject: [PATCH 0762/1348] add API for www.do.de/www.resellerinterface.de --- dnsapi/dns_do.sh | 167 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100755 dnsapi/dns_do.sh diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh new file mode 100755 index 00000000..43ce678f --- /dev/null +++ b/dnsapi/dns_do.sh @@ -0,0 +1,167 @@ +#!/usr/bin/env sh + +# DNS API for Domain-Offensive / Resellerinterface / Domainrobot + +# DO_PID="KD-1234567" +# DO_PW="cdfkjl3n2" + +DO_URL="https://soap.resellerinterface.de/" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_do_add() { + fulldomain=$1 + txtvalue=$2 + _cookiejar="$(_mktemp)" + if _dns_do_authenticate; then + _info "Adding TXT record to ${_domain} as ${fulldomain}" + _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300 + if _contains "${response}" '>success<'; then + return 0 + fi + _err "Could not create resource record, check logs" + fi + return 1 +} + +#fulldomain +dns_do_rm() { + fulldomain=$1 + _cookiejar="$(_mktemp)" + if _dns_do_authenticate; then + if _dns_do_list_rrs; then + for _rrid in ${_rr_list}; do + _info "Deleting resource record $_rrid for $_domain" + _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}" + if ! _contains "${response}" '>success<'; then + _err "Could not delete resource record for ${_domain}, id ${_rrid}" + fi + done + return 0 + fi + fi + return 1 +} + +#################### Private functions below ################################## +_dns_do_authenticate() { + _info "Authenticating as ${DO_PID}" + _dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}" + if _contains "${response}" '>success<'; then + _get_root "$fulldomain" + _debug "_domain $_domain" + return 0 + else + _err "Authentication failed, check logs" + fi + return 1 +} + +_dns_do_list_rrs() { + _dns_do_soap getRRList origin "${_domain}" + if ! _contains "${response}" 'SOAP-ENC:Array'; then + _err "getRRList origin ${_domain} failed" + return 1 + fi + _rr_list="$(echo "${response}" \ + | tr -d "\n\r\t" \ + | sed -e 's//\n/g' \ + | grep -F ">${fulldomain}" \ + | sed -e 's//\n\0/g' \ + | grep -F '>id' \ + | sed -re 's/.*]*>([^<]+)<\/value>.*/\1/')" + [ "${_rr_list}" ] +} + +_dns_do_soap() { + func="$1" + shift + # put the parameters to xml + body="" + while [ "$1" ] ; do + _k="$1" + shift + _v="$1" + shift + body="$body<$_k>$_v" + done + body="$body" + _debug2 "SOAP request ${body}" + + # build SOAP XML + _xml=' + + '"$body"' +' + + # set SOAP headers + _H1="SOAPAction: ${DO_URL}#${func}" + # add cookie header if present + [ -s "${_cookiejar}" ] && _H2="$(cat "${_cookiejar}")" + + if ! response="$(_post "${_xml}" "${DO_URL}")"; then + _err "Error <$1>" + return 1 + fi + _debug2 "SOAP response $response" + + # retrieve cookie header + grep -F 'Set-Cookie:' "$HTTP_HEADER" | sed -re 's/^Set-(Cookie: [^;]+).*/\1/' | head -1 > "${_cookiejar}" + + return 0 +} + +_get_root() { + domain=$1 + i=1 + + _all_domains="$(_mktemp)" + _dns_do_soap getDomainList + echo "${response}" | tr -d "\n\r\t " | grep -Eo 'domain]+>[^<]+' | sed -re 's/^domain<\/key>]+>//g' > "${_all_domains}" + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + return 1 + fi + + if grep -qF "$h" "${_all_domains}"; then + _domain="$h" + return 0 + fi + + i=$(_math $i + 1) + done + _debug "$domain not found" + + return 1 +} + +_info() { + if [ -z "$2" ]; then + echo "[$(date)] $1" + else + echo "[$(date)] $1='$2'" + fi +} + +_err() { + _info "$@" >&2 + return 1 +} + +_debug() { + if [ -z "$DEBUG" ]; then + return + fi + _err "$@" + return 0 +} + +_debug2() { + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _debug "$@" + fi + return +} From 76a3371b402b3006ee2f26872debffc8b6dca103 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sat, 3 Dec 2016 10:07:13 +0000 Subject: [PATCH 0763/1348] remove non-POSIX sed -r and use built-in functions --- dnsapi/dns_do.sh | 43 ++++++++----------------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 43ce678f..cea1beb3 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -67,10 +67,11 @@ _dns_do_list_rrs() { _rr_list="$(echo "${response}" \ | tr -d "\n\r\t" \ | sed -e 's//\n/g' \ - | grep -F ">${fulldomain}" \ - | sed -e 's//\n\0/g' \ - | grep -F '>id' \ - | sed -re 's/.*]*>([^<]+)<\/value>.*/\1/')" + | fgrep ">${fulldomain}" \ + | sed -e 's/<\/item>/\n/g' \ + | grep '>id[0-9]{1,16}<' \ + | tr -d '><')" [ "${_rr_list}" ] } @@ -107,7 +108,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - grep -F 'Set-Cookie:' "$HTTP_HEADER" | sed -re 's/^Set-(Cookie: [^;]+).*/\1/' | head -1 > "${_cookiejar}" + cat "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]+' | head -1 > "${_cookiejar}" return 0 } @@ -118,7 +119,7 @@ _get_root() { _all_domains="$(_mktemp)" _dns_do_soap getDomainList - echo "${response}" | tr -d "\n\r\t " | grep -Eo 'domain]+>[^<]+' | sed -re 's/^domain<\/key>]+>//g' > "${_all_domains}" + echo "${response}" | tr -d "\n\r\t " | _egrep_o 'domain]+>[^<]+' | sed -e 's/^domain<\/key>]+>//g' > "${_all_domains}" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) @@ -126,7 +127,7 @@ _get_root() { return 1 fi - if grep -qF "$h" "${_all_domains}"; then + if fgrep -q "$h" "${_all_domains}"; then _domain="$h" return 0 fi @@ -137,31 +138,3 @@ _get_root() { return 1 } - -_info() { - if [ -z "$2" ]; then - echo "[$(date)] $1" - else - echo "[$(date)] $1='$2'" - fi -} - -_err() { - _info "$@" >&2 - return 1 -} - -_debug() { - if [ -z "$DEBUG" ]; then - return - fi - _err "$@" - return 0 -} - -_debug2() { - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _debug "$@" - fi - return -} From 88ed5e506a9c1f862fc99d4c681bf47b2b97f253 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sat, 3 Dec 2016 19:04:31 +0000 Subject: [PATCH 0764/1348] fix whitespace and UUOC --- dnsapi/dns_do.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index cea1beb3..034e6aa6 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -80,7 +80,7 @@ _dns_do_soap() { shift # put the parameters to xml body="" - while [ "$1" ] ; do + while [ "$1" ]; do _k="$1" shift _v="$1" @@ -108,7 +108,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - cat "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]+' | head -1 > "${_cookiejar}" + _egrep_o 'Cookie: [^;]+' < "$HTTP_HEADER" | head -1 >"${_cookiejar}" return 0 } @@ -119,7 +119,7 @@ _get_root() { _all_domains="$(_mktemp)" _dns_do_soap getDomainList - echo "${response}" | tr -d "\n\r\t " | _egrep_o 'domain]+>[^<]+' | sed -e 's/^domain<\/key>]+>//g' > "${_all_domains}" + echo "${response}" | tr -d "\n\r\t " | _egrep_o 'domain]+>[^<]+' | sed -e 's/^domain<\/key>]+>//g' >"${_all_domains}" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) From 0d4035e99662c737ab4160e6a77e8071f620c4c4 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sat, 3 Dec 2016 19:24:42 +0000 Subject: [PATCH 0765/1348] remove fgrep, escape regex chars instead --- dnsapi/dns_do.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 034e6aa6..075cb3b0 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -67,7 +67,7 @@ _dns_do_list_rrs() { _rr_list="$(echo "${response}" \ | tr -d "\n\r\t" \ | sed -e 's//\n/g' \ - | fgrep ">${fulldomain}" \ + | grep ">$(_regexcape "$fulldomain")" \ | sed -e 's/<\/item>/\n/g' \ | grep '>id[0-9]{1,16}<' \ @@ -127,7 +127,7 @@ _get_root() { return 1 fi - if fgrep -q "$h" "${_all_domains}"; then + if grep -q "$(_regexcape "$h")" "${_all_domains}"; then _domain="$h" return 0 fi @@ -138,3 +138,7 @@ _get_root() { return 1 } + +_regexcape() { + echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g' +} From 3ebbeb103c195737b5d234a60c73056a9a5bb88f Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sat, 3 Dec 2016 19:27:46 +0000 Subject: [PATCH 0766/1348] old habits --- dnsapi/dns_do.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 075cb3b0..cc8f339e 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -108,7 +108,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - _egrep_o 'Cookie: [^;]+' < "$HTTP_HEADER" | head -1 >"${_cookiejar}" + _egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | head -1 >"${_cookiejar}" return 0 } From b95a99e0c2c8aa0e31b44df39fbe46119864dd55 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Mon, 5 Dec 2016 20:35:31 +0000 Subject: [PATCH 0767/1348] remove cookiejar temp file --- dnsapi/dns_do.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index cc8f339e..17ab23d7 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -98,8 +98,6 @@ _dns_do_soap() { # set SOAP headers _H1="SOAPAction: ${DO_URL}#${func}" - # add cookie header if present - [ -s "${_cookiejar}" ] && _H2="$(cat "${_cookiejar}")" if ! response="$(_post "${_xml}" "${DO_URL}")"; then _err "Error <$1>" @@ -108,7 +106,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - _egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | head -1 >"${_cookiejar}" + _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | head -1)" return 0 } From 743f821f1ee9e4827e95a4b1c4088949cbfc78ac Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Mon, 5 Dec 2016 20:49:46 +0000 Subject: [PATCH 0768/1348] improve error message on failed authentication --- dnsapi/dns_do.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 17ab23d7..7576092b 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -53,7 +53,7 @@ _dns_do_authenticate() { _debug "_domain $_domain" return 0 else - _err "Authentication failed, check logs" + _err "Authentication failed, are DO_PID and DO_PW set correctly?" fi return 1 } From d1d2f6f4518cc7332b92ef856471b1a76a6c03e8 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Mon, 5 Dec 2016 20:56:38 +0000 Subject: [PATCH 0769/1348] avoid temp file for domain list --- dnsapi/dns_do.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 7576092b..1a9458f8 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -115,9 +115,11 @@ _get_root() { domain=$1 i=1 - _all_domains="$(_mktemp)" _dns_do_soap getDomainList - echo "${response}" | tr -d "\n\r\t " | _egrep_o 'domain]+>[^<]+' | sed -e 's/^domain<\/key>]+>//g' >"${_all_domains}" + _all_domains="/$(echo "${response}" \ + | tr -d "\n\r\t " \ + | _egrep_o 'domain]+>[^<]+' \ + | sed -e 's/^domain<\/key>]*>//g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) @@ -125,7 +127,7 @@ _get_root() { return 1 fi - if grep -q "$(_regexcape "$h")" "${_all_domains}"; then + if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then _domain="$h" return 0 fi From 1cb6e9e7d0653b2920fb6eac0bc11d3abdfa5190 Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Wed, 7 Dec 2016 11:36:22 +0100 Subject: [PATCH 0770/1348] remove cookiejar file d'oh --- dnsapi/dns_do.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 1a9458f8..edcf4559 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -13,7 +13,6 @@ DO_URL="https://soap.resellerinterface.de/" dns_do_add() { fulldomain=$1 txtvalue=$2 - _cookiejar="$(_mktemp)" if _dns_do_authenticate; then _info "Adding TXT record to ${_domain} as ${fulldomain}" _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300 From cdec38ba12a3779f257f321fd8a84b02fee0dbec Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Wed, 7 Dec 2016 11:39:10 +0100 Subject: [PATCH 0771/1348] return error if any removal failed --- dnsapi/dns_do.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index edcf4559..1450ee5a 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -30,14 +30,16 @@ dns_do_rm() { _cookiejar="$(_mktemp)" if _dns_do_authenticate; then if _dns_do_list_rrs; then + _dns_do_had_error=0 for _rrid in ${_rr_list}; do _info "Deleting resource record $_rrid for $_domain" _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}" if ! _contains "${response}" '>success<'; then + _dns_do_had_error=1 _err "Could not delete resource record for ${_domain}, id ${_rrid}" fi done - return 0 + return _dns_do_had_error fi fi return 1 From e55605dbe9b91702f9b93ac0c0a84736fb8e0145 Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Wed, 7 Dec 2016 11:41:32 +0100 Subject: [PATCH 0772/1348] remove _all_ mktemp --- dnsapi/dns_do.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 1450ee5a..43a73b97 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -27,7 +27,6 @@ dns_do_add() { #fulldomain dns_do_rm() { fulldomain=$1 - _cookiejar="$(_mktemp)" if _dns_do_authenticate; then if _dns_do_list_rrs; then _dns_do_had_error=0 From 1633d14547ad6d1e5521af0ce814373cd840fc14 Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Wed, 7 Dec 2016 12:07:40 +0100 Subject: [PATCH 0773/1348] forgot dollar sign --- dnsapi/dns_do.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 43a73b97..bbf86bac 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -38,7 +38,7 @@ dns_do_rm() { _err "Could not delete resource record for ${_domain}, id ${_rrid}" fi done - return _dns_do_had_error + return $_dns_do_had_error fi fi return 1 From bf8ffade29daca74e15e53cf40cf1b1ba451272f Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Thu, 8 Dec 2016 08:43:29 +0100 Subject: [PATCH 0774/1348] replace head -1, add link to GitHub --- dnsapi/dns_do.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index bbf86bac..b718cd41 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -2,6 +2,9 @@ # DNS API for Domain-Offensive / Resellerinterface / Domainrobot +# Report bugs at https://github.com/seidler2547/acme.sh/issues + +# set these environment variables to match your customer ID and password: # DO_PID="KD-1234567" # DO_PW="cdfkjl3n2" @@ -106,7 +109,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | head -1)" + _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" return 0 } From 383fa8401d1dffb6d9a325b8df1c3324aba8f3b8 Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Thu, 19 Jan 2017 09:35:47 +0100 Subject: [PATCH 0775/1348] Remove stray characater fixes issue where the first listed domain would not work --- dnsapi/dns_do.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index b718cd41..b08e6f1e 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -119,7 +119,7 @@ _get_root() { i=1 _dns_do_soap getDomainList - _all_domains="/$(echo "${response}" \ + _all_domains="$(echo "${response}" \ | tr -d "\n\r\t " \ | _egrep_o 'domain]+>[^<]+' \ | sed -e 's/^domain<\/key>]*>//g')" From 9efd40a3662d64c54eeb98858ddbd9bfc589ba2c Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Sun, 19 Feb 2017 21:26:25 +0000 Subject: [PATCH 0776/1348] use export for headers --- dnsapi/dns_do.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index b08e6f1e..06a86b28 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -100,7 +100,7 @@ _dns_do_soap() { ' # set SOAP headers - _H1="SOAPAction: ${DO_URL}#${func}" + export _H1="SOAPAction: ${DO_URL}#${func}" if ! response="$(_post "${_xml}" "${DO_URL}")"; then _err "Error <$1>" @@ -109,7 +109,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" + export _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" return 0 } From 3d6a125bdc08e4419697a1913d00d68e0715b5e8 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sun, 19 Feb 2017 21:34:10 +0000 Subject: [PATCH 0777/1348] add documentation --- README.md | 1 + dnsapi/README.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index b33f8636..c8aeeb0f 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,7 @@ You don't have to do anything manually! 1. Linode.com API 1. FreeDNS (https://freedns.afraid.org/) 1. cyon.ch +1. Domain-Offensive/Resellerinterface/Domainrobot API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index fd88d579..3be5a7fe 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -240,6 +240,7 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +<<<<<<< HEAD ## 13. Use Alwaysdata domain API First you need to login to your Alwaysdata account to get your API Key. @@ -323,6 +324,19 @@ acme.sh --issue --dns dns_cyon -d example.com -d www.example.com The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API + +You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`: +``` +export DO_PID="KD-1234567" +export DO_PW="cdfkjl3n2" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_do -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. From 2b2b65fe1877725f4c7d400da28847bb31a09fbc Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Sun, 19 Feb 2017 21:42:55 +0000 Subject: [PATCH 0778/1348] Declare and assign separately to avoid masking return values --- dnsapi/dns_do.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 06a86b28..3a2f8f49 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -109,7 +109,8 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - export _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" + _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" + export _H2 return 0 } From abf4278d0911be6ff199380c66542b93ecca9824 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sun, 19 Feb 2017 21:46:33 +0000 Subject: [PATCH 0779/1348] resolve conflicts --- dnsapi/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 3be5a7fe..7df7142a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -240,7 +240,6 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -<<<<<<< HEAD ## 13. Use Alwaysdata domain API First you need to login to your Alwaysdata account to get your API Key. From e6cd596dc90bf51e3237b420b1715b000b64c3a6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 18:02:23 +0800 Subject: [PATCH 0780/1348] add debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e24d4d9a..b989d246 100755 --- a/acme.sh +++ b/acme.sh @@ -4369,7 +4369,7 @@ _precheck() { fi if ! _exists "$OPENSSL_BIN"; then - _err "Please install openssl first." + _err "Please install openssl first. OPENSSL_BIN=$OPENSSL_BIN" _err "We need openssl to generate keys." return 1 fi From 851fedf7512216c1926f3f64e899167ed6f06f56 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 19:08:00 +0800 Subject: [PATCH 0781/1348] rename OPENSSL_BIN to ACME_OPENSSL_BIN --- acme.sh | 80 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/acme.sh b/acme.sh index b989d246..937da149 100755 --- a/acme.sh +++ b/acme.sh @@ -137,11 +137,11 @@ _printargs() { _dlg_versions() { echo "Diagnosis versions: " - echo "openssl:$OPENSSL_BIN" - if _exists "$OPENSSL_BIN"; then - $OPENSSL_BIN version 2>&1 + echo "openssl:$ACME_OPENSSL_BIN" + if _exists "$ACME_OPENSSL_BIN"; then + $ACME_OPENSSL_BIN version 2>&1 else - echo "$OPENSSL_BIN doesn't exists." + echo "$ACME_OPENSSL_BIN doesn't exists." fi echo "apache:" @@ -780,19 +780,19 @@ _base64() { [ "" ] #urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" - $OPENSSL_BIN base64 -e + $ACME_OPENSSL_BIN base64 -e else _debug3 "base64 single line." - $OPENSSL_BIN base64 -e | tr -d '\r\n' + $ACME_OPENSSL_BIN base64 -e | tr -d '\r\n' fi } #Usage: multiline _dbase64() { if [ "$1" ]; then - $OPENSSL_BIN base64 -d -A + $ACME_OPENSSL_BIN base64 -d -A else - $OPENSSL_BIN base64 -d + $ACME_OPENSSL_BIN base64 -d fi } @@ -809,9 +809,9 @@ _digest() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$outputhex" ]; then - $OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' + $ACME_OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' else - $OPENSSL_BIN dgst -"$alg" -binary | _base64 + $ACME_OPENSSL_BIN dgst -"$alg" -binary | _base64 fi else _err "$alg is not supported yet" @@ -834,9 +834,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - ($OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' + ($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 ' ' else - $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary + $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 fi else _err "$alg is not supported yet" @@ -855,7 +855,7 @@ _sign() { return 1 fi - _sign_openssl="$OPENSSL_BIN dgst -sign $keyfile " + _sign_openssl="$ACME_OPENSSL_BIN dgst -sign $keyfile " if [ "$alg" = "sha256" ]; then _sign_openssl="$_sign_openssl -$alg" else @@ -866,7 +866,7 @@ _sign() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then $_sign_openssl | _base64 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - if ! _signedECText="$($_sign_openssl | $OPENSSL_BIN asn1parse -inform DER)"; then + if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" _err "Key content:$(wc -l <"$keyfile") lises" @@ -929,10 +929,10 @@ _createkey() { if _isEccKey "$length"; then _debug "Using ec name: $eccname" - $OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" + $ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" else _debug "Using RSA: $length" - $OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" + $ACME_OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" fi if [ "$?" != "0" ]; then @@ -1019,9 +1019,9 @@ _createcsr() { _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" if _contains "$(uname -a)" "MINGW"; then - $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" + $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" else - $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" fi } @@ -1033,7 +1033,7 @@ _signcsr() { cert="$4" _debug "_signcsr" - _msg="$($OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" + _msg="$($ACME_OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" _ret="$?" _debug "$_msg" return $_ret @@ -1046,7 +1046,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - $OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + $ACME_OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile @@ -1061,7 +1061,7 @@ _readSubjectAltNamesFromCSR() { _csrsubj="$(_readSubjectFromCSR "$_csrfile")" _debug _csrsubj "$_csrsubj" - _dnsAltnames="$($OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" + _dnsAltnames="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" _debug _dnsAltnames "$_dnsAltnames" if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then @@ -1082,7 +1082,7 @@ _readKeyLengthFromCSR() { return 1 fi - _outcsr="$($OPENSSL_BIN req -noout -text -in "$_csrfile")" + _outcsr="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile")" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' @@ -1136,9 +1136,9 @@ toPkcs() { _initpath "$domain" "$_isEcc" if [ "$pfxPassword" ]; then - $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 pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" else - $OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" + $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" fi if [ "$?" = "0" ]; then @@ -1300,7 +1300,7 @@ _calcjwk() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "RSA key" - pub_exp=$($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 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 pub_exp=0$pub_exp fi @@ -1309,7 +1309,7 @@ _calcjwk() { e=$(echo "$pub_exp" | _h2b | _base64) _debug3 e "$e" - modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) + modulus=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" _debug3 n "$n" @@ -1322,12 +1322,12 @@ _calcjwk() { JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" - crv="$($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 ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" - crv_oid="$($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 ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv_oid "$crv_oid" case "${crv_oid}" in "prime256v1") @@ -1347,15 +1347,15 @@ _calcjwk() { _debug3 crv "$crv" fi - pubi="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + pubi="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math "$pubi" + 1) _debug3 pubi "$pubi" - pubj="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + pubj="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math "$pubj" - 1) _debug3 pubj "$pubj" - pubtext="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + pubtext="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" @@ -1964,7 +1964,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="$OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY " + __S_OPENSSL="$ACME_OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY " if [ "$opaddr" ]; then __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" else @@ -2143,8 +2143,8 @@ _initpath() { CERT_HOME="$_DEFAULT_CERT_HOME" fi - if [ -z "$OPENSSL_BIN" ]; then - OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" + if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ] ; then + ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" fi if [ -z "$1" ]; then @@ -4368,8 +4368,8 @@ _precheck() { fi fi - if ! _exists "$OPENSSL_BIN"; then - _err "Please install openssl first. OPENSSL_BIN=$OPENSSL_BIN" + if ! _exists "$ACME_OPENSSL_BIN"; then + _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" _err "We need openssl to generate keys." return 1 fi @@ -4791,9 +4791,9 @@ _processAccountConf() { fi if [ "$_openssl_bin" ]; then - _saveaccountconf "OPENSSL_BIN" "$_openssl_bin" - elif [ "$OPENSSL_BIN" ] && [ "$OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then - _saveaccountconf "OPENSSL_BIN" "$OPENSSL_BIN" + _saveaccountconf "ACME_OPENSSL_BIN" "$_openssl_bin" + elif [ "$ACME_OPENSSL_BIN" ] && [ "$ACME_OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then + _saveaccountconf "ACME_OPENSSL_BIN" "$ACME_OPENSSL_BIN" fi if [ "$_auto_upgrade" ]; then @@ -5219,7 +5219,7 @@ _process() { ;; --openssl-bin) _openssl_bin="$2" - OPENSSL_BIN="$_openssl_bin" + ACME_OPENSSL_BIN="$_openssl_bin" ;; *) _err "Unknown parameter : $1" From 77f1ea40cd02024568b36daebdce55b2f41f565d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 19:12:20 +0800 Subject: [PATCH 0782/1348] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 937da149..d9f5a34e 100755 --- a/acme.sh +++ b/acme.sh @@ -2143,7 +2143,7 @@ _initpath() { CERT_HOME="$_DEFAULT_CERT_HOME" fi - if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ] ; then + if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ]; then ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" fi From 4410226db1bf51e543ea46d84cdb9d567a93d92a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 19:31:52 +0800 Subject: [PATCH 0783/1348] add --toPkcs8 command fix https://github.com/Neilpang/acme.sh/issues/664 --- acme.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/acme.sh b/acme.sh index d9f5a34e..e55265d0 100755 --- a/acme.sh +++ b/acme.sh @@ -1147,6 +1147,27 @@ toPkcs() { } +#domain [isEcc] +toPkcs8() { + domain="$1" + + if [ -z "$domain" ]; then + _usage "Usage: $PROJECT_ENTRY --toPkcs8 -d domain [--ecc]" + return 1 + fi + + _isEcc="$2" + + _initpath "$domain" "$_isEcc" + + $ACME_OPENSSL_BIN pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" + + if [ "$?" = "0" ]; then + _info "Success, $CERT_PKCS8_PATH" + fi + +} + #[2048] createAccountKey() { _info "Creating account key" @@ -2200,6 +2221,9 @@ _initpath() { if [ -z "$CERT_PFX_PATH" ]; then CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx" fi + if [ -z "$CERT_PKCS8_PATH" ]; then + CERT_PKCS8_PATH="$DOMAIN_PATH/$domain.pkcs8" + fi if [ -z "$TLS_CONF" ]; then TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" @@ -4661,6 +4685,7 @@ Commands: --uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically. --cron Run cron job to renew all the certs. --toPkcs Export the certificate and key to a pfx file. + --toPkcs8 Convert to pkcs8 format. --update-account Update account info. --register-account Register account key. --create-account-key Create an account private key, professional use. @@ -4908,6 +4933,9 @@ _process() { --toPkcs) _CMD="toPkcs" ;; + --toPkcs8) + _CMD="toPkcs8" + ;; --createAccountKey | --createaccountkey | -cak | --create-account-key) _CMD="createAccountKey" ;; @@ -5320,6 +5348,9 @@ _process() { toPkcs) toPkcs "$_domain" "$_password" "$_ecc" ;; + toPkcs8) + toPkcs8 "$_domain" "$_ecc" + ;; createAccountKey) createAccountKey "$_accountkeylength" ;; From 342128a457a5d1124b084d419653dd4957c7c2c8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 21:09:06 +0800 Subject: [PATCH 0784/1348] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e55265d0..3def82a0 100755 --- a/acme.sh +++ b/acme.sh @@ -4935,7 +4935,7 @@ _process() { ;; --toPkcs8) _CMD="toPkcs8" - ;; + ;; --createAccountKey | --createaccountkey | -cak | --create-account-key) _CMD="createAccountKey" ;; From 4fd63f4e302c381cd167f9e3ed1c4bdc3ba0da2e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 21:22:56 +0800 Subject: [PATCH 0785/1348] fix ci --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d54faed..7f7e120c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,9 @@ install: _old_path="$PATH"; echo "PATH=$PATH"; export PATH=""; - export OPENSSL_BIN="/usr/local/openssl"; + export ACME_OPENSSL_BIN="/usr/local/openssl"; openssl version 2>&1 || true; - $OPENSSL_BIN version 2>&1 || true; + $ACME_OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; fi @@ -44,7 +44,7 @@ script: - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi matrix: From 58e4d337e4eaa93de9ca0fdeb661df5ecdb1e50e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 26 Feb 2017 12:07:06 +0800 Subject: [PATCH 0786/1348] clear the pending authz when issue error fix bug https://github.com/Neilpang/acme.sh/issues/663 --- acme.sh | 59 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/acme.sh b/acme.sh index 3def82a0..f11f1f07 100755 --- a/acme.sh +++ b/acme.sh @@ -2819,6 +2819,7 @@ _on_before_issue() { _on_issue_err() { _chk_post_hook="$1" + _chk_vlist="$2" _debug _on_issue_err if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" @@ -2827,10 +2828,6 @@ _on_issue_err() { _err "See: $_DEBUG_WIKI" fi - if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then - _debug "$(_dlg_versions)" - fi - #run the post hook if [ "$_chk_post_hook" ]; then _info "Run post hook:'$_chk_post_hook'" @@ -2841,6 +2838,28 @@ _on_issue_err() { return 1 fi fi + + #trigger the validation to flush the pending authz + if [ "$_chk_vlist" ]; then + ( + _debug2 "_chk_vlist" "$_chk_vlist" + _debug2 "start to deactivate authz" + ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') + for ventry in $ventries; do + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + uri=$(echo "$ventry" | cut -d "$sep" -f 3) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) + __trigger_validaton "$uri" "$keyauthorization" + done + ) + fi + + if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then + _debug "$(_dlg_versions)" + fi + } _on_issue_success() { @@ -3053,6 +3072,16 @@ __get_domain_new_authz() { } +#uri keyAuthorization +__trigger_validaton() { + _debug2 "tigger domain validation." + _t_url="$1" + _debug2 _t_url "$_t_url" + _t_key_authz="$2" + _debug2 _t_key_authz "$_t_key_authz" + _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" +} + #webroot, domain domainlist keylength issue() { if [ -z "$2" ]; then @@ -3366,7 +3395,7 @@ issue() { _startserver "$keyauthorization" "$_ncaddr" & if [ "$?" != "0" ]; then _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi serverproc="$!" @@ -3382,7 +3411,7 @@ issue() { BACKUP_NGINX_CONF="" if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3417,7 +3446,7 @@ issue() { _err "$d:Can not write token to file : $wellknown_path/$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3462,16 +3491,16 @@ issue() { _err "Start tls server error." _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi fi - if ! _send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then + if ! __trigger_validaton "$uri" "$keyauthorization"; then _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3479,7 +3508,7 @@ issue() { _err "$d:Challenge error: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3494,7 +3523,7 @@ issue() { _err "$d:Timeout" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3506,7 +3535,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi _debug2 original "$response" @@ -3541,7 +3570,7 @@ issue() { fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3551,7 +3580,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi From c719a61ea70ad1a19337fe0cbb61c1cc0e80540b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 26 Feb 2017 12:15:39 +0800 Subject: [PATCH 0787/1348] fix format --- acme.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index f11f1f07..ecc6cb24 100755 --- a/acme.sh +++ b/acme.sh @@ -2842,17 +2842,17 @@ _on_issue_err() { #trigger the validation to flush the pending authz if [ "$_chk_vlist" ]; then ( - _debug2 "_chk_vlist" "$_chk_vlist" - _debug2 "start to deactivate authz" - ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') - for ventry in $ventries; do - d=$(echo "$ventry" | cut -d "$sep" -f 1) - keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) - uri=$(echo "$ventry" | cut -d "$sep" -f 3) - vtype=$(echo "$ventry" | cut -d "$sep" -f 4) - _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - __trigger_validaton "$uri" "$keyauthorization" - done + _debug2 "_chk_vlist" "$_chk_vlist" + _debug2 "start to deactivate authz" + ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') + for ventry in $ventries; do + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + uri=$(echo "$ventry" | cut -d "$sep" -f 3) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) + __trigger_validaton "$uri" "$keyauthorization" + done ) fi From 7c2e87549496e18c57253428252f8ff67ed73d53 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 26 Feb 2017 22:20:08 +0800 Subject: [PATCH 0788/1348] fix https://github.com/Neilpang/acme.sh/issues/675 --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index ecc6cb24..724f0e97 100755 --- a/acme.sh +++ b/acme.sh @@ -5277,6 +5277,7 @@ _process() { --openssl-bin) _openssl_bin="$2" ACME_OPENSSL_BIN="$_openssl_bin" + shift ;; *) _err "Unknown parameter : $1" From 81532f375ea6f9b55e19b07bbe1c106f3d164b19 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 27 Feb 2017 13:38:29 +0800 Subject: [PATCH 0789/1348] fix https://github.com/Neilpang/acme.sh/issues/667#issuecomment-282629936 --- acme.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/acme.sh b/acme.sh index 724f0e97..d2bb6c53 100755 --- a/acme.sh +++ b/acme.sh @@ -927,6 +927,15 @@ _createkey() { _debug "Use length $length" + if ! touch "$f" >/dev/null 2>&1; then + _f_path="$(dirname "$f")" + _debug _f_path "$_f_path" + if ! mkdir -p "$_f_path"; then + _err "Can not create path: $_f_path" + return 1 + fi + fi + if _isEccKey "$length"; then _debug "Using ec name: $eccname" $ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" From 9b124070286abde59d5afcffe67a6773c3135a78 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 27 Feb 2017 20:48:48 +0800 Subject: [PATCH 0790/1348] Wget (#678) * --use-wget force to use wget * fix force wget --- acme.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d2bb6c53..3e9e4d15 100755 --- a/acme.sh +++ b/acme.sh @@ -1505,7 +1505,7 @@ _post() { _inithttp - if [ "$_ACME_CURL" ]; then + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then _CURL="$_ACME_CURL" if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " @@ -1572,7 +1572,7 @@ _get() { _inithttp - if [ "$_ACME_CURL" ]; then + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then _CURL="$_ACME_CURL" if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " @@ -4787,6 +4787,7 @@ Parameters: --listen-v4 Force standalone/tls server to listen at ipv4. --listen-v6 Force standalone/tls server to listen at ipv6. --openssl-bin Specifies a custom openssl bin location. + --use-wget Force to use wget, if you have both curl and wget installed. " } @@ -4865,6 +4866,12 @@ _processAccountConf() { _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" fi + if [ "$_use_wget" ]; then + _saveaccountconf "ACME_USE_WGET" "$_use_wget" + elif [ "$ACME_USE_WGET" ]; then + _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" + fi + } _process() { @@ -4909,6 +4916,7 @@ _process() { _listen_v6="" _openssl_bin="" _syslog="" + _use_wget="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5288,6 +5296,10 @@ _process() { ACME_OPENSSL_BIN="$_openssl_bin" shift ;; + --use-wget) + _use_wget="1" + ACME_USE_WGET="1" + ;; *) _err "Unknown parameter : $1" return 1 From 59f7a2f6efb93fd81098146a0f8fe8367c155eb8 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 27 Feb 2017 20:54:38 +0800 Subject: [PATCH 0791/1348] Wget (#678) (#679) * --use-wget force to use wget * fix force wget --- acme.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d2bb6c53..3e9e4d15 100755 --- a/acme.sh +++ b/acme.sh @@ -1505,7 +1505,7 @@ _post() { _inithttp - if [ "$_ACME_CURL" ]; then + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then _CURL="$_ACME_CURL" if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " @@ -1572,7 +1572,7 @@ _get() { _inithttp - if [ "$_ACME_CURL" ]; then + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then _CURL="$_ACME_CURL" if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " @@ -4787,6 +4787,7 @@ Parameters: --listen-v4 Force standalone/tls server to listen at ipv4. --listen-v6 Force standalone/tls server to listen at ipv6. --openssl-bin Specifies a custom openssl bin location. + --use-wget Force to use wget, if you have both curl and wget installed. " } @@ -4865,6 +4866,12 @@ _processAccountConf() { _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" fi + if [ "$_use_wget" ]; then + _saveaccountconf "ACME_USE_WGET" "$_use_wget" + elif [ "$ACME_USE_WGET" ]; then + _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" + fi + } _process() { @@ -4909,6 +4916,7 @@ _process() { _listen_v6="" _openssl_bin="" _syslog="" + _use_wget="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5288,6 +5296,10 @@ _process() { ACME_OPENSSL_BIN="$_openssl_bin" shift ;; + --use-wget) + _use_wget="1" + ACME_USE_WGET="1" + ;; *) _err "Unknown parameter : $1" return 1 From fab2d9dc6ada42e2ac15abda2bd2f2ea73cf8bfc Mon Sep 17 00:00:00 2001 From: Frederic Crozat Date: Tue, 28 Feb 2017 12:58:04 +0100 Subject: [PATCH 0792/1348] add API for Gandi LiveDNS (#680) * add API for Gandi LiveDNS * ensure Gandi API key is saved for renewing certificate. * gandi_livedns: use PUT instead of POST for creating DNS record * gandi_livedns: fix formatting * dns_gandi_livedns: fix shellcheck errors --- README.md | 1 + dnsapi/README.md | 12 ++++ dnsapi/dns_gandi_livedns.sh | 120 ++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100755 dnsapi/dns_gandi_livedns.sh diff --git a/README.md b/README.md index c8aeeb0f..fd867015 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,7 @@ You don't have to do anything manually! 1. FreeDNS (https://freedns.afraid.org/) 1. cyon.ch 1. Domain-Offensive/Resellerinterface/Domainrobot API +1. Gandi LiveDNS API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 7df7142a..7607257d 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -336,6 +336,18 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_do -d example.com -d www.example.com ``` +## 18. Use Gandi LiveDNS API + +You will need your Gandi API key (on your Account preferences, go to Security and generate your API key) and export it before you run `acme.sh`: +``` +export GANDI_LIVEDNS_KEY="fdmlfsdklmfdkmqsdfk" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh new file mode 100755 index 00000000..9a170b8b --- /dev/null +++ b/dnsapi/dns_gandi_livedns.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env sh + +# Gandi LiveDNS v5 API +# http://doc.livedns.gandi.net/ +# currently under beta +# +# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable +# +#Author: Frédéric Crozat +#Report Bugs here: https://github.com/fcrozat/acme.sh +# +######## Public functions ##################### + +GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5" + +#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gandi_livedns_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$GANDI_LIVEDNS_KEY" ]; then + _err "No API key specifed for Gandi LiveDNS." + _err "Create your key and export it as GANDI_LIVEDNS_KEY" + return 1 + fi + + _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY" + + _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" + + _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" + + return $? +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_gandi_livedns_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" "" + + return $? +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _gandi_livedns_rest GET "domains/$h"; then + return 1 + fi + + if _contains "$response" '"code": 404'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_gandi_livedns_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Content-Type: application/json" + export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY" + + if [ "$data" ] || [ "$m" = "DELETE" ]; then + _debug data "$data" + response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")" + else + response="$(_get "$GANDI_LIVEDNS_API/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 9683ffe13a08ffee278c74b7059a190e4084f417 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 20:39:23 +0800 Subject: [PATCH 0793/1348] minor fix error message --- dnsapi/README.md | 3 ++- dnsapi/dns_gandi_livedns.sh | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 7607257d..18c1ca9f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -338,7 +338,8 @@ acme.sh --issue --dns dns_do -d example.com -d www.example.com ## 18. Use Gandi LiveDNS API -You will need your Gandi API key (on your Account preferences, go to Security and generate your API key) and export it before you run `acme.sh`: +You must enable the new Gandi LiveDNS API first and the create your api key, See: http://doc.livedns.gandi.net/ + ``` export GANDI_LIVEDNS_KEY="fdmlfsdklmfdkmqsdfk" ``` diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 9a170b8b..76c4c8a9 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -38,7 +38,6 @@ dns_gandi_livedns_add() { _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" - return $? } #Usage: fulldomain txtvalue @@ -59,7 +58,6 @@ dns_gandi_livedns_rm() { _gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" "" - return $? } #################### Private functions below ################################## @@ -82,7 +80,10 @@ _get_root() { return 1 fi - if _contains "$response" '"code": 404'; then + if _contains "$response" '"code": 401'; then + _err "$response" + return 1 + elif _contains "$response" '"code": 404'; then _debug "$h not found" else _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) @@ -104,11 +105,11 @@ _gandi_livedns_rest() { export _H1="Content-Type: application/json" export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY" - if [ "$data" ] || [ "$m" = "DELETE" ]; then + if [ "$m" = "GET" ]; then + response="$(_get "$GANDI_LIVEDNS_API/$ep")" + else _debug data "$data" response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")" - else - response="$(_get "$GANDI_LIVEDNS_API/$ep")" fi if [ "$?" != "0" ]; then From d24a87caf189dbcfaa066645f4076d755afb2a87 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 20:56:11 +0800 Subject: [PATCH 0794/1348] minor --- dnsapi/dns_gandi_livedns.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 76c4c8a9..d2521941 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -37,7 +37,7 @@ dns_gandi_livedns_add() { _debug sub_domain "$_sub_domain" _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" - + _contains "$response" '{"message": "Zone Record Created"}' } #Usage: fulldomain txtvalue @@ -71,6 +71,7 @@ _get_root() { 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 From 39a1f1ef644cef0daeb8fffa94cc8d844e207639 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 21:04:33 +0800 Subject: [PATCH 0795/1348] fix 404 for wget --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3e9e4d15..a8b3e038 100755 --- a/acme.sh +++ b/acme.sh @@ -1610,7 +1610,7 @@ _get() { fi ret=$? if [ "$_ret" = "8" ]; then - _ret=0 + ret=0 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." fi if [ "$ret" != "0" ]; then From f731a4c7041416612ffdf593f9d5763a850c09ac Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 21:06:02 +0800 Subject: [PATCH 0796/1348] fix 404 for wget --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a8b3e038..b87df6d6 100755 --- a/acme.sh +++ b/acme.sh @@ -1609,7 +1609,7 @@ _get() { $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url" fi ret=$? - if [ "$_ret" = "8" ]; then + if [ "$ret" = "8" ]; then ret=0 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." fi From 810c129ca970b7ae26e1e648f90670b8d91d2beb Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 21:08:20 +0800 Subject: [PATCH 0797/1348] minor fix error message --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index b87df6d6..a18be6f4 100755 --- a/acme.sh +++ b/acme.sh @@ -1546,7 +1546,7 @@ _post() { _ret="$?" if [ "$_ret" = "8" ]; then _ret=0 - _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." + _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." fi if [ "$_ret" != "0" ]; then _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" @@ -1611,7 +1611,7 @@ _get() { ret=$? if [ "$ret" = "8" ]; then ret=0 - _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." + _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." fi if [ "$ret" != "0" ]; then _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" From 177b57e1c007f185c87e9791c6f31b68ba0b302e Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 21:35:20 +0800 Subject: [PATCH 0798/1348] fix wget content on 404 error --- acme.sh | 5 +++++ dnsapi/dns_gandi_livedns.sh | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index a18be6f4..7c2875fd 100755 --- a/acme.sh +++ b/acme.sh @@ -1485,6 +1485,11 @@ _inithttp() { fi fi + #from wget 1.14: do not skip body on 404 error + if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help)" "--content-on-error"; then + _ACME_WGET="$_ACME_WGET --content-on-error " + fi + __HTTP_INITIALIZED=1 } diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index d2521941..55218a20 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -36,8 +36,9 @@ dns_gandi_livedns_add() { _debug domain "$_domain" _debug sub_domain "$_sub_domain" - _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" - _contains "$response" '{"message": "Zone Record Created"}' + _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ + && _contains "$response" '{"message": "Zone Record Created"}' \ + && _info "Add $(__green "success")" } #Usage: fulldomain txtvalue From 58ef6d83852f5bffc6ad00311a139f5f60ec4a2b Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 1 Mar 2017 13:12:29 +0800 Subject: [PATCH 0799/1348] fix wget error message --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7c2875fd..0313e0e1 100755 --- a/acme.sh +++ b/acme.sh @@ -1486,7 +1486,7 @@ _inithttp() { fi #from wget 1.14: do not skip body on 404 error - if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help)" "--content-on-error"; then + if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then _ACME_WGET="$_ACME_WGET --content-on-error " fi From 839f18d052c0dff1d6e38c098087e68832788f39 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 1 Mar 2017 19:17:20 +0800 Subject: [PATCH 0800/1348] fix format --- dnsapi/dns_gandi_livedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 55218a20..41f42980 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -37,8 +37,8 @@ dns_gandi_livedns_add() { _debug sub_domain "$_sub_domain" _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ - && _contains "$response" '{"message": "Zone Record Created"}' \ - && _info "Add $(__green "success")" + && _contains "$response" '{"message": "Zone Record Created"}' \ + && _info "Add $(__green "success")" } #Usage: fulldomain txtvalue From 29992f54a35394a9c4d75bb52e75b3c702b2b5b9 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 1 Mar 2017 18:28:39 +0100 Subject: [PATCH 0801/1348] delete support for dns_me --- dnsapi/dns_me.sh | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index f63621d9..59e9cec7 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -78,7 +78,41 @@ dns_me_add() { #fulldomain dns_me_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" + _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" + + if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _me_rest DELETE "$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '"success":true' + fi } #################### Private functions below ################################## @@ -130,7 +164,7 @@ _me_rest() { export _H2="x-dnsme-requestDate: $cdate" export _H3="x-dnsme-hmac: $hmac" - if [ "$data" ]; then + if [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$ME_Api/$ep" "" "$m")" else From a1e1bfc71b24ee04856230e2a28e27b746652cd6 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 1 Mar 2017 19:20:16 +0100 Subject: [PATCH 0802/1348] removed useless code --- dnsapi/dns_me.sh | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 59e9cec7..7c4a2ae3 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -91,11 +91,6 @@ dns_me_rm() { _debug "Getting txt records" _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" - if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then - _err "Error" - return 1 - fi - count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) _debug count "$count" if [ "$count" = "0" ]; then @@ -107,10 +102,7 @@ dns_me_rm() { _err "Can not get record id to remove." return 1 fi - if ! _me_rest DELETE "$_domain_id/records/$record_id"; then - _err "Delete record error." - return 1 - fi + _me_rest DELETE "$_domain_id/records/$record_id" _contains "$response" '"success":true' fi } From 8d53ec53530cb204bd873e2984df6300e4cb2392 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 1 Mar 2017 19:38:02 +0100 Subject: [PATCH 0803/1348] fixed validation, added LUA while I'm at it --- dnsapi/dns_lua.sh | 31 ++++++++++++++++++++++++++++++- dnsapi/dns_me.sh | 7 +++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 828e8012..00c54430 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -81,7 +81,36 @@ dns_lua_add() { #fulldomain dns_lua_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" + _LUA_rest GET "zones/${_domain_id}/records" + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _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 ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "$record_id" + fi } #################### Private functions below ################################## @@ -129,7 +158,7 @@ _LUA_rest() { export _H1="Accept: application/json" export _H2="Authorization: Basic $LUA_auth" - if [ "$data" ]; then + if [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" else diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 7c4a2ae3..3393fb75 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -102,8 +102,11 @@ dns_me_rm() { _err "Can not get record id to remove." return 1 fi - _me_rest DELETE "$_domain_id/records/$record_id" - _contains "$response" '"success":true' + if ! _me_rest DELETE "$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '' fi } From 51f8bec81b7db02217d118c9b6a82b45a2aabcb1 Mon Sep 17 00:00:00 2001 From: Felix Wolfsteller Date: Thu, 2 Mar 2017 08:38:25 +0100 Subject: [PATCH 0804/1348] deploy apache script: fix comment (dovecot/apache) --- deploy/apache.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/apache.sh b/deploy/apache.sh index b6c1fbc2..7b34bd5f 100644 --- a/deploy/apache.sh +++ b/deploy/apache.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#Here is a script to deploy cert to dovecot server. +#Here is a script to deploy cert to apache server. #returns 0 means success, otherwise error. From 5288c54aade8f54e4b4ec50f7c44513bc32cc11b Mon Sep 17 00:00:00 2001 From: Felix Wolfsteller Date: Thu, 2 Mar 2017 08:38:25 +0100 Subject: [PATCH 0805/1348] deploy apache script: fix comment (dovecot/apache) Closes #690 . --- deploy/apache.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/apache.sh b/deploy/apache.sh index b6c1fbc2..7b34bd5f 100644 --- a/deploy/apache.sh +++ b/deploy/apache.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#Here is a script to deploy cert to dovecot server. +#Here is a script to deploy cert to apache server. #returns 0 means success, otherwise error. From e735d8d4e5a0dd7810dd6cc937fec93c8fdbaad2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 3 Mar 2017 22:03:19 +0800 Subject: [PATCH 0806/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 0313e0e1..38bed5f6 100755 --- a/acme.sh +++ b/acme.sh @@ -146,7 +146,7 @@ _dlg_versions() { echo "apache:" if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then - _APACHECTL -V 2>&1 + $_APACHECTL -V 2>&1 else echo "apache doesn't exists." fi From 6fb2a1ed39c263407c2d1bb6d8b2e8a0cd9a7d07 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Mar 2017 19:56:06 +0800 Subject: [PATCH 0807/1348] minor fix comments --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 38bed5f6..d6ed13a4 100755 --- a/acme.sh +++ b/acme.sh @@ -1279,12 +1279,12 @@ _url_replace() { } _time2str() { - #BSD + #Linux if date -u -d@"$1" 2>/dev/null; then return fi - #Linux + #BSD if date -u -r "$1" 2>/dev/null; then return fi From 9c87a5890dec74d7f0c7f0edac9b72699e7aa116 Mon Sep 17 00:00:00 2001 From: csmk Date: Sun, 5 Mar 2017 22:18:31 +0900 Subject: [PATCH 0808/1348] Add support for Knot DNS API The script is actually an adapted version of the `dns_nsupdate.sh` script, as the `knsupdate` utility is quite similar to `nsupdate`. --- README.md | 1 + dnsapi/README.md | 45 ++++++++++++++++++++++ dnsapi/dns_knot.sh | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 dnsapi/dns_knot.sh diff --git a/README.md b/README.md index fd867015..3a03e703 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,7 @@ You don't have to do anything manually! 1. cyon.ch 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API +1. Knot DNS API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 18c1ca9f..5b71e89f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -349,6 +349,51 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com ``` +## 19. Use Knot (knsupdate) DNS API to automatically issue cert + +First, generate a TSIG key for updating the zone. + +``` +keymgr tsig generate acme_key algorithm hmac-sha512 > /etc/knot/acme.key +``` + +Include this key in your knot configuration file. + +``` +include: /etc/knot/acme.key +``` + +Next, configure your zone to allow dynamic updates. + +Dynamic updates for the zone are allowed via proper ACL rule with the `update` action. For in-depth instructions, please see [Knot DNS's documentation](https://www.knot-dns.cz/documentation/). + +``` +acl: + - id: acme_acl + address: 192.168.1.0/24 + key: acme_key + action: update + +zone: + - domain: example.com + file: example.com.zone + acl: acme_acl +``` + +Finally, make the DNS server and TSIG Key available to `acme.sh` + +``` +export KNOT_SERVER="dns.example.com" +export KNOT_KEY=`grep \# /etc/knot/acme.key | cut -d' ' -f2` +``` + +Ok, let's issue a cert now: +``` +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. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_knot.sh b/dnsapi/dns_knot.sh new file mode 100644 index 00000000..b6d1e0b6 --- /dev/null +++ b/dnsapi/dns_knot.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env sh + +######## Public functions ##################### + +#Usage: dns_knot_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_knot_add() { + fulldomain=$1 + txtvalue=$2 + _checkKey || return 1 + [ -n "${KNOT_SERVER}" ] || KNOT_SERVER="localhost" + # save the dns server and key to the account.conf file. + _saveaccountconf KNOT_SERVER "${KNOT_SERVER}" + _saveaccountconf KNOT_KEY "${KNOT_KEY}" + + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + + _info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\"" + + knsupdate -y "${KNOT_KEY}" < Date: Mon, 6 Mar 2017 11:09:12 +0900 Subject: [PATCH 0809/1348] deploy for OSX Keychain --- deploy/keychain.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 deploy/keychain.sh diff --git a/deploy/keychain.sh b/deploy/keychain.sh new file mode 100644 index 00000000..a99ed465 --- /dev/null +++ b/deploy/keychain.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env sh + +#Here is a sample custom api script. +#This file name is "myapi.sh" +#So, here must be a method myapi_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +keychain_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + /usr/bin/security import "$_ckey" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_ccert" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_cca" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_cfullchain" -k "/Library/Keychains/System.keychain" + + return 0 +} From f589a1d2458556fbbd8dfc8cff758b2f666d7f38 Mon Sep 17 00:00:00 2001 From: csmk Date: Tue, 7 Mar 2017 22:21:22 +0900 Subject: [PATCH 0810/1348] Fix format: use double quote to prevent globbing and word splitting --- dnsapi/dns_knot.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_knot.sh b/dnsapi/dns_knot.sh index b6d1e0b6..094a6981 100644 --- a/dnsapi/dns_knot.sh +++ b/dnsapi/dns_knot.sh @@ -73,10 +73,10 @@ EOF _get_root() { domain=$1 i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" - i=$(_math $i - 1) + i=$(_math "$i" - 1) 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 return 1 fi From 06492067966ef03344c92892d19b6fccee1cb86e Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 7 Mar 2017 11:57:03 -0500 Subject: [PATCH 0811/1348] remove _ACME prefix from all exported variables. --- deploy/README.md | 56 ++++++++++++++++++++++++------------------------ deploy/ssh.sh | 54 +++++++++++++++++++++++----------------------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index ab38f275..22b8e8d2 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -38,21 +38,21 @@ values are stored by acme.sh in the domain configuration files. Required... ``` -export ACME_DEPLOY_SSH_USER=username +export DEPLOY_SSH_USER=username ``` Optional... ``` -export ACME_DEPLOY_SSH_CMD=custom ssh command -export ACME_DEPLOY_SSH_SERVER=url or ip address of remote host -export ACME_DEPLOY_SSH_KEYFILE=filename for private key -export ACME_DEPLOY_SSH_CERTFILE=filename for certificate file -export ACME_DEPLOY_SSH_CAFILE=filename for intermediate CA file -export ACME_DEPLOY_SSH_FULLCHAIN=filename for fullchain file -export ACME_DEPLOY_SSH_REMOTE_CMD=command to execute on remote host -export ACME_DEPLOY_SSH_BACKUP=yes or no +export DEPLOY_SSH_CMD=custom ssh command +export DEPLOY_SSH_SERVER=url or ip address of remote host +export DEPLOY_SSH_KEYFILE=filename for private key +export DEPLOY_SSH_CERTFILE=filename for certificate file +export DEPLOY_SSH_CAFILE=filename for intermediate CA file +export DEPLOY_SSH_FULLCHAIN=filename for fullchain file +export DEPLOY_SSH_REMOTE_CMD=command to execute on remote host +export DEPLOY_SSH_BACKUP=yes or no ``` -**ACME_DEPLOY_SSH_USER** +**DEPLOY_SSH_USER** Username at the remote host that SSH will login with. Note that SSH must be able to login to remote host without a password... SSH Keys must have been exchanged with the remote host. Validate and test that you @@ -62,41 +62,41 @@ The USER@URL at the remote server must also have has permissions to write to the target location of the certificate files and to execute any commands (e.g. to stop/start services). -**ACME_DEPLOY_SSH_CMD** +**DEPLOY_SSH_CMD** You can customize the ssh command used to connect to the remote host. For example if you need to connect to a specific port at the remote server you can set this to, for example, "ssh -p 22" or to use `sshpass` to provide password inline instead of exchanging ssh keys (this is not recommended, using keys is more secure). -**ACME_DEPLOY_SSH_SERVER** +**DEPLOY_SSH_SERVER** URL or IP Address of the remote server. If not provided then the domain name provided on the acme.sh --deploy command line is used. -**ACME_DEPLOY_SSH_KEYFILE** +**DEPLOY_SSH_KEYFILE** Target filename for the private key issued by LetsEncrypt. -**ACME_DEPLOY_SSH_CERTFILE** +**DEPLOY_SSH_CERTFILE** Target filename for the certificate issued by LetsEncrypt. If this is the same as the previous filename (for keyfile) then it is appended to the same file. -**ACME_DEPLOY_SSH_CAFILE** +**DEPLOY_SSH_CAFILE** Target filename for the CA intermediate certificate issued by LetsEncrypt. If this is the same as a previous filename (for keyfile or certfile) then it is appended to the same file. -**ACME_DEPLOY_SSH_FULLCHAIN** +**DEPLOY_SSH_FULLCHAIN** Target filename for the fullchain certificate issued by LetsEncrypt. If this is the same as a previous filename (for keyfile, certfile or cafile) then it is appended to the same file. -**ACME_DEPLOY_SSH_REMOTE_CMD** +**DEPLOY_SSH_REMOTE_CMD** Command to execute on the remote server after copying any certificates. This could be any additional command required for example to stop and restart the service. -**ACME_DEPLOY_SSH_BACKUP** +**DEPLOY_SSH_BACKUP** Before writing a certificate file to the remote server the existing certificate will be copied to a backup directory on the remote server. These are placed in a hidden directory in the home directory of the SSH @@ -113,11 +113,11 @@ The following example illustrates deploying certifcates to a QNAP NAS (tested with QTS version 4.2.3) ```sh -export ACME_DEPLOY_SSH_USER="admin" -export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" -export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" -export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" -export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +export DEPLOY_SSH_USER="admin" +export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" acme.sh --deploy -d qnap.example.com --deploy-hook ssh ``` @@ -130,10 +130,10 @@ The next example illustates deploying certificates to a Unifi Contolller (tested with version 5.4.11). ```sh -export ACME_DEPLOY_SSH_USER="root" -export ACME_DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" -export ACME_DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" -export ACME_DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ +export DEPLOY_SSH_USER="root" +export DEPLOY_SSH_KEYFILE="/var/lib/unifi/unifi.example.com.key" +export DEPLOY_SSH_FULLCHAIN="/var/lib/unifi/unifi.example.com.cer" +export DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ -inkey /var/lib/unifi/unifi.example.com.key \ -in /var/lib/unifi/unifi.example.com.cer \ -out /var/lib/unifi/unifi.example.com.p12 \ @@ -158,7 +158,7 @@ required. We could if we desired delete those files immediately. If we do that then we should disable backup at the remote host (as there are no files to backup -- they were erased during deployment). For example... ```sh -export ACME_DEPLOY_SSH_BACKUP=no +export DEPLOY_SSH_BACKUP=no # modify the end of the remote command... && rm /var/lib/unifi/unifi.example.com.key \ /var/lib/unifi/unifi.example.com.cer \ diff --git a/deploy/ssh.sh b/deploy/ssh.sh index a8ed6a10..a68da356 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -12,15 +12,15 @@ # Only a username is required. All others are optional. # # The following examples are for QNAP NAS running QTS 4.2 -# export ACME_DEPLOY_SSH_CMD="" # defaults to ssh -# export ACME_DEPLOY_SSH_USER="admin" # required -# export ACME_DEPLOY_SSH_SERVER="qnap" # defaults to domain name -# export ACME_DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" -# export ACME_DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" -# export ACME_DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" -# export ACME_DEPLOY_SSH_FULLCHAIN="" -# export ACME_DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" -# export ACME_DEPLOY_SSH_BACKUP="" # yes or no, default to yes +# export DEPLOY_SSH_CMD="" # defaults to ssh +# export DEPLOY_SSH_USER="admin" # required +# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name +# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +# export DEPLOY_SSH_FULLCHAIN="" +# export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes # ######## Public functions ##################### @@ -48,34 +48,34 @@ ssh_deploy() { _debug _cfullchain "$_cfullchain" # USER is required to login by SSH to remote host. - if [ -z "$ACME_DEPLOY_SSH_USER" ]; then + if [ -z "$DEPLOY_SSH_USER" ]; then if [ -z "$Le_Deploy_ssh_user" ]; then - _err "ACME_DEPLOY_SSH_USER not defined." + _err "DEPLOY_SSH_USER not defined." return 1 fi else - Le_Deploy_ssh_user="$ACME_DEPLOY_SSH_USER" + Le_Deploy_ssh_user="$DEPLOY_SSH_USER" _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user" fi # SERVER is optional. If not provided then use _cdomain - if [ -n "$ACME_DEPLOY_SSH_SERVER" ]; then - Le_Deploy_ssh_server="$ACME_DEPLOY_SSH_SERVER" + if [ -n "$DEPLOY_SSH_SERVER" ]; then + Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER" _savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server" elif [ -z "$Le_Deploy_ssh_server" ]; then Le_Deploy_ssh_server="$_cdomain" fi # CMD is optional. If not provided then use ssh - if [ -n "$ACME_DEPLOY_SSH_CMD" ]; then - Le_Deploy_ssh_cmd="$ACME_DEPLOY_SSH_CMD" + if [ -n "$DEPLOY_SSH_CMD" ]; then + Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD" _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd" elif [ -z "$Le_Deploy_ssh_cmd" ]; then Le_Deploy_ssh_cmd="ssh" fi # BACKUP is optional. If not provided then default to yes - if [ "$ACME_DEPLOY_SSH_BACKUP" = "no" ]; then + if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then Le_Deploy_ssh_backup="no" elif [ -z "$Le_Deploy_ssh_backup" ]; then Le_Deploy_ssh_backup="yes" @@ -86,8 +86,8 @@ ssh_deploy() { # KEYFILE is optional. # If provided then private key will be copied to provided filename. - if [ -n "$ACME_DEPLOY_SSH_KEYFILE" ]; then - Le_Deploy_ssh_keyfile="$ACME_DEPLOY_SSH_KEYFILE" + if [ -n "$DEPLOY_SSH_KEYFILE" ]; then + Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE" _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" fi if [ -n "$Le_Deploy_ssh_keyfile" ]; then @@ -102,8 +102,8 @@ ssh_deploy() { # CERTFILE is optional. # If provided then private key will be copied or appended to provided filename. - if [ -n "$ACME_DEPLOY_SSH_CERTFILE" ]; then - Le_Deploy_ssh_certfile="$ACME_DEPLOY_SSH_CERTFILE" + if [ -n "$DEPLOY_SSH_CERTFILE" ]; then + Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE" _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" fi if [ -n "$Le_Deploy_ssh_certfile" ]; then @@ -122,8 +122,8 @@ ssh_deploy() { # CAFILE is optional. # If provided then CA intermediate certificate will be copied or appended to provided filename. - if [ -n "$ACME_DEPLOY_SSH_CAFILE" ]; then - Le_Deploy_ssh_cafile="$ACME_DEPLOY_SSH_CAFILE" + if [ -n "$DEPLOY_SSH_CAFILE" ]; then + Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE" _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" fi if [ -n "$Le_Deploy_ssh_cafile" ]; then @@ -143,8 +143,8 @@ ssh_deploy() { # FULLCHAIN is optional. # If provided then fullchain certificate will be copied or appended to provided filename. - if [ -n "$ACME_DEPLOY_SSH_FULLCHAIN" ]; then - Le_Deploy_ssh_fullchain="$ACME_DEPLOY_SSH_FULLCHAIN" + if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then + Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN" _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" fi if [ -n "$Le_Deploy_ssh_fullchain" ]; then @@ -165,8 +165,8 @@ ssh_deploy() { # REMOTE_CMD is optional. # If provided then this command will be executed on remote host. - if [ -n "$ACME_DEPLOY_SSH_REMOTE_CMD" ]; then - Le_Deploy_ssh_remote_cmd="$ACME_DEPLOY_SSH_REMOTE_CMD" + if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then + Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD" _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" fi if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then From 158abf5c6ca5c6de5a015569196403e4dad43395 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 7 Mar 2017 12:09:07 -0500 Subject: [PATCH 0812/1348] Remove line from README.md that I mistakenly added during merge with master. --- deploy/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 4008f64a..60ab34ae 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -26,8 +26,6 @@ Before you can deploy your cert, you must [issue the cert first](https://github. ## 3. Deploy the cert to remote server through SSH access. -Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). - The ssh deploy plugin allows you to deploy certificates to a remote host using SSH command to connect to the remote server. The ssh plugin is invoked with the following command... From bce11af09ae31284afc0d07e6205113f5390b207 Mon Sep 17 00:00:00 2001 From: hiska Date: Wed, 8 Mar 2017 08:00:17 +0900 Subject: [PATCH 0813/1348] Update README.md for OSX Keychain --- deploy/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 4a13e096..d8c2f57c 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -72,3 +72,8 @@ export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart" acme.sh --deploy -d ftp.example.com --deploy-hook exim4 ``` +## 6. Deploy the cert to OSX Keychain + +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook keychain +``` From 5378d9ca2655543cdf765065d0f3434b5e5ded0f Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 8 Mar 2017 13:55:01 +0800 Subject: [PATCH 0814/1348] fix nginx mode --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d6ed13a4..4edc1ecf 100755 --- a/acme.sh +++ b/acme.sh @@ -2462,7 +2462,7 @@ _setNginx() { fi _debug "Start detect nginx conf for $_d from:$_start_f" if ! _checkConf "$_d" "$_start_f"; then - "Can not find conf file for domain $d" + _err "Can not find conf file for domain $d" return 1 fi _info "Found conf file: $FOUND_REAL_NGINX_CONF" @@ -2559,7 +2559,7 @@ _checkConf() { FOUND_REAL_NGINX_CONF="$2" return 0 fi - if grep "^ *include *.*;" "$2" >/dev/null; then + if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then _debug "Try include files" for included in $(grep "^ *include *.*;" "$2" | sed "s/include //" | tr -d " ;"); do _debug "check included $included" From f08a79d3724b8c374131a28862b954738a8085b4 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 8 Mar 2017 16:01:14 +0800 Subject: [PATCH 0815/1348] fix nginx mode --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 4edc1ecf..eb1a8969 100755 --- a/acme.sh +++ b/acme.sh @@ -2546,7 +2546,7 @@ _checkConf() { if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then _debug "wildcard" for _w_f in $2; do - if _checkConf "$1" "$_w_f"; then + if [ -f "$_w_f"] && _checkConf "$1" "$_w_f"; then return 0 fi done @@ -2559,9 +2559,9 @@ _checkConf() { FOUND_REAL_NGINX_CONF="$2" return 0 fi - if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then + if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then _debug "Try include files" - for included in $(grep "^ *include *.*;" "$2" | sed "s/include //" | tr -d " ;"); do + for included in $(cat "$2" | tr "\t" " " | grep "^ *include *.*;" | sed "s/include //" | tr -d " ;"); do _debug "check included $included" if _checkConf "$1" "$included"; then return 0 From 6f1c72f5b46f7f0ee114c873886496a8ccb6139b Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 Mar 2017 21:21:15 +0800 Subject: [PATCH 0816/1348] add links --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index fd867015..e851fb93 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,18 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) # [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) +# Who are using **acme.sh** +- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/) +- [ruby-china.org](https://ruby-china.org/topics/31983) +- [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer)) +- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89) +- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt) +- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty) +- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709) +- [Centminmod](http://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/) +- [more and more](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS From 63ec05a66c71cef8ea71e8e6c6c152acb8c1ae2a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 Mar 2017 21:23:12 +0800 Subject: [PATCH 0817/1348] fix links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e851fb93..450de49a 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [Centminmod](http://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/) -- [more and more](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) +- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS From c4bf5eef73aa749393101f50683e4391ac8e46d2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 Mar 2017 21:51:25 +0800 Subject: [PATCH 0818/1348] add _upper_case and _lower_case --- acme.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/acme.sh b/acme.sh index eb1a8969..699ea268 100755 --- a/acme.sh +++ b/acme.sh @@ -299,6 +299,16 @@ _secure_debug3() { fi } +_upper_case() { + # shellcheck disable=SC2018,SC2019 + tr 'a-z' 'A-Z' +} + +_lower_case() { + # shellcheck disable=SC2018,SC2019 + tr 'A-Z' 'a-z' +} + _startswith() { _str="$1" _sub="$2" From 7d0452c7e330c53dd810964c7590876348642c75 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 8 Mar 2017 22:12:37 +0100 Subject: [PATCH 0819/1348] added NS1. support --- README.md | 1 + dnsapi/README.md | 11 +++ dnsapi/dns_nsone.sh | 159 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 dnsapi/dns_nsone.sh diff --git a/README.md b/README.md index 7d5ab846..5d1ddc5b 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,7 @@ You don't have to do anything manually! 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API 1. Knot DNS API +1. NS1. API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 5b71e89f..c1e98a6a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -394,6 +394,17 @@ 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. +## 20. Use NS1. API + +``` +export NS1_Key="fdmlfsdklmfdkmqsdfk" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_nsone -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh new file mode 100644 index 00000000..6a7d6001 --- /dev/null +++ b/dnsapi/dns_nsone.sh @@ -0,0 +1,159 @@ +#!/usr/bin/env sh + +# bug reports to dev@1e.ca + +# +#NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#NS1_Email="user@luadns.net" + +NS1_Api="https://api.nsone.net/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nsone_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$NS1_Key" ]; then + NS1_Key="" + _err "You didn't specify nsone dns api key yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf NS1_Key "$NS1_Key" + + _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" + _nsone_rest GET "zones/${_domain}" + + if ! _contains "$response" "\"records\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Adding record" + + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then + if _contains "$response" "$fulldomain"; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1) + _debug "record_id" "$record_id" + + _nsone_rest POST "zones/$_domain_/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" + if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi + +} + +#fulldomain +dns_nsone_rm() { + fulldomain=$1 + txtvalue=$2 + _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" + _nsone_rest GET "zones/${_domain}/$fulldomain/TXT" + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "" + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + if ! _nsone_rest GET "zones"; then + return 1 + fi + 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" "\"zone\":\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_nsone_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Accept: application/json" + export _H2="X-NSONE-Key: $NS1_Key" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NS1_Api/$ep" "" "$m")" + else + response="$(_get "$NS1_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 17361df66b9f8a4a4aabc7b1ab789d7d3ef5bb47 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 8 Mar 2017 22:15:07 +0100 Subject: [PATCH 0820/1348] cleanup --- dnsapi/dns_nsone.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 6a7d6001..898319b4 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -5,7 +5,6 @@ # #NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" # -#NS1_Email="user@luadns.net" NS1_Api="https://api.nsone.net/v1" From d3c4cd8270d2ee84e2dd20976156b7bdfdce42df Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 8 Mar 2017 22:21:25 +0100 Subject: [PATCH 0821/1348] bugfix --- dnsapi/dns_nsone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 898319b4..a5ea05fe 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -41,7 +41,7 @@ dns_nsone_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" From 1e5e03cc4603a65d4bb0b0d2c3932cbe070e5b96 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 8 Mar 2017 22:22:48 +0100 Subject: [PATCH 0822/1348] typo... --- dnsapi/dns_nsone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index a5ea05fe..0f6e441a 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -62,7 +62,7 @@ dns_nsone_add() { record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1) _debug "record_id" "$record_id" - _nsone_rest POST "zones/$_domain_/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" + _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then _info "Updated!" #todo: check if the record takes effect From ac690fceaf5a1fcba7632d340e709258f4fdbc3f Mon Sep 17 00:00:00 2001 From: thewer Date: Thu, 9 Mar 2017 22:28:30 +1000 Subject: [PATCH 0823/1348] Added DigitalOcean (native) API that requires only a read/write API key for DigitalOcean, updated 2 reads files. --- README.md | 1 + dnsapi/README.md | 13 +++ dnsapi/dns_dgon.sh | 205 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100755 dnsapi/dns_dgon.sh diff --git a/README.md b/README.md index 7d5ab846..52231d0f 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,7 @@ You don't have to do anything manually! 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API 1. Knot DNS API +1. DigitalOcean API (native) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 5b71e89f..fe243cb5 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -394,6 +394,19 @@ 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. +## 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 +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh new file mode 100755 index 00000000..9ceede44 --- /dev/null +++ b/dnsapi/dns_dgon.sh @@ -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: 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 requres 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 +} From 04683338a21bda18da6d3dafce6167de1fb699f2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Mar 2017 10:06:40 +0800 Subject: [PATCH 0824/1348] fix cloudxns api https://github.com/Neilpang/acme.sh/issues/717 --- dnsapi/dns_cx.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 2b6d5691..e2f0f099 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -209,8 +209,7 @@ _rest() { return 1 fi _debug2 response "$response" - if ! _contains "$response" '"message":"success"'; then - return 1 - fi - return 0 + + _contains "$response" '"code":1' + } From 4dd646a424a0f91267f3c198437319548dfb66be Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 13 Mar 2017 11:18:04 +0800 Subject: [PATCH 0825/1348] fix https://github.com/Neilpang/acme.sh/issues/719 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 699ea268..7906aa4c 100755 --- a/acme.sh +++ b/acme.sh @@ -4628,7 +4628,7 @@ install() { #Modify shebang if _exists bash; then _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" for subf in $_SUB_FOLDERS; do if [ -d "$LE_WORKING_DIR/$subf" ]; then From 3b7fbcd0c322b152d566dc65a6bca97cc483d4d5 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 13:24:09 +0200 Subject: [PATCH 0826/1348] Add DNS API support for ClouDNS --- dnsapi/README.md | 14 ++++ dnsapi/dns_cloudns.sh | 158 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100755 dnsapi/dns_cloudns.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index fe243cb5..702efc1c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -407,6 +407,20 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_dgon -d example.com -d www.example.com ``` +## 21. Use ClouDNS 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 +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh new file mode 100755 index 00000000..9b93b1ca --- /dev/null +++ b/dnsapi/dns_cloudns.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env 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=" + 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 + + 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 + # missing zone + 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=$(expr $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 | awk 'BEGIN { FS="\"" } {print $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" + + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + + response="$(_get "$CLOUDNS_API/$method?$data")" + + _debug response "$response" + + return 1; +} \ No newline at end of file From c7257e0a3c6b4883a1ccde8dbcf4338483d26f48 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:20:58 +0200 Subject: [PATCH 0827/1348] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 9b93b1ca..39d8c3a6 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -7,20 +7,20 @@ CLOUDNS_API="https://api.cloudns.net" ######## Public functions ##################### #Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_add() { +dns_cloudns_add () { _info "Using cloudns" if ! _dns_cloudns_init_check; then - return 1 + 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 + _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\$//")" + host="$(echo $1 | sed "s/\.$zone\$//")" record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") @@ -52,14 +52,14 @@ dns_cloudns_add() { } #Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_rm() { +dns_cloudns_rm () { _info "Using cloudns" if ! _dns_cloudns_init_check; then return 1 fi - if [ -z $zone]; then + 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." @@ -89,8 +89,8 @@ dns_cloudns_rm() { } #################### Private functions below ################################## -_dns_cloudns_init_check() { - if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED]; then +_dns_cloudns_init_check () { + if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED ]; then return 0 fi @@ -109,14 +109,13 @@ _dns_cloudns_init_check() { return 0 } -_dns_cloudns_get_zone_name() { +_dns_cloudns_get_zone_name () { i=2 while true; do zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) if [ -z "$zoneForCheck" ]; then - # missing zone - return 1; + return 1 fi _debug zoneForCheck $zoneForCheck @@ -125,15 +124,15 @@ _dns_cloudns_get_zone_name() { if ! _contains "$response" "\"status\":\"Failed\""; then echo $zoneForCheck - return 0; + return 0 fi i=$(expr $i + 1) done - return 1; + return 1 } -_dns_cloudns_get_record_id() { +_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 | awk 'BEGIN { FS="\"" } {print $2}' @@ -154,5 +153,5 @@ _dns_cloudns_http_api_call () { _debug response "$response" - return 1; + return 1 } \ No newline at end of file From 0dd6377fe666ded6d0919acd6e8fb8adc0d497ea Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:25:50 +0200 Subject: [PATCH 0828/1348] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 39d8c3a6..1726b81a 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -7,7 +7,7 @@ CLOUDNS_API="https://api.cloudns.net" ######## Public functions ##################### #Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_add () { +dns_cloudns_add() { _info "Using cloudns" if ! _dns_cloudns_init_check; then @@ -20,8 +20,8 @@ dns_cloudns_add () { return 1 fi - host="$(echo $1 | sed "s/\.$zone\$//")" - record=$2 + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") _debug zone "$zone" @@ -52,14 +52,14 @@ dns_cloudns_add () { } #Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_rm () { +dns_cloudns_rm() { _info "Using cloudns" if ! _dns_cloudns_init_check; then - return 1 + return 1 fi - if [ -z $zone ]; then + 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." @@ -67,8 +67,8 @@ dns_cloudns_rm () { fi fi - host="$(echo $1|sed "s/\.$zone\$//")" - record=$2 + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") _debug zone "$zone" @@ -89,8 +89,8 @@ dns_cloudns_rm () { } #################### Private functions below ################################## -_dns_cloudns_init_check () { - if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED ]; then +_dns_cloudns_init_check() { + if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then return 0 fi @@ -109,7 +109,7 @@ _dns_cloudns_init_check () { return 0 } -_dns_cloudns_get_zone_name () { +_dns_cloudns_get_zone_name() { i=2 while true; do zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) @@ -123,7 +123,7 @@ _dns_cloudns_get_zone_name () { _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" if ! _contains "$response" "\"status\":\"Failed\""; then - echo $zoneForCheck + echo "$zoneForCheck" return 0 fi @@ -132,16 +132,16 @@ _dns_cloudns_get_zone_name () { return 1 } -_dns_cloudns_get_record_id () { +_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 | awk 'BEGIN { FS="\"" } {print $2}' + echo "$response" | awk 'BEGIN { FS="\"" } {print $2}' return 0 fi return 1 } -_dns_cloudns_http_api_call () { +_dns_cloudns_http_api_call() { method=$1 _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" From a15f87ae39d33e0d35838e4dc5c810bd934fc232 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:26:57 +0200 Subject: [PATCH 0829/1348] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 1726b81a..3eb10b33 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -127,7 +127,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(expr $i + 1) + i=$(expr "$i" + 1) done return 1 } From 5df2ca3ef301fe8bbcf0c7e11c5ef9a1c0484aca Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:38:02 +0200 Subject: [PATCH 0830/1348] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 3eb10b33..cd83619f 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -14,7 +14,7 @@ dns_cloudns_add() { return 1 fi - zone="$(_dns_cloudns_get_zone_name $1)" + 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 @@ -28,7 +28,6 @@ dns_cloudns_add() { _debug host "$host" _debug record "$record" _debug record_id "$record_id" - if [ -z "$record_id" ]; then _info "Adding the TXT record for $1" @@ -60,7 +59,7 @@ dns_cloudns_rm() { fi if [ -z "$zone" ]; then - zone="$(_dns_cloudns_get_zone_name $1)" + 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 @@ -118,7 +117,7 @@ _dns_cloudns_get_zone_name() { return 1 fi - _debug zoneForCheck $zoneForCheck + _debug zoneForCheck "$zoneForCheck" _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" @@ -127,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(expr "$i" + 1) + i=$(($i+1)) done return 1 } From f881d6c44ff6f5043399ae3b379c158aa2ec69e8 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:40:18 +0200 Subject: [PATCH 0831/1348] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index cd83619f..698cc26e 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -153,4 +153,4 @@ _dns_cloudns_http_api_call() { _debug response "$response" return 1 -} \ No newline at end of file +} From 55a5da2102c2bfe9e41e2d32e7e29c7eb301e9ce Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:42:51 +0200 Subject: [PATCH 0832/1348] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 698cc26e..efa7ce7e 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(($i+1)) + i=$(($i + 1)) done return 1 } From 3d8598654c82128ac8e6be44f9f6127f9c778f09 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:43:43 +0200 Subject: [PATCH 0833/1348] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index efa7ce7e..d12db033 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(($i + 1)) + i=$((${i} + 1)) done return 1 } From ac11ba3d60534bc52478c6016e6025d4be8e93ad Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 15:12:02 +0200 Subject: [PATCH 0834/1348] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index d12db033..d000d6a2 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -28,7 +28,7 @@ dns_cloudns_add() { _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" @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$((${i} + 1)) + i=$((i + 1)) done return 1 } From be972fc0b5dc13171380fe0c88ac371539d45ef9 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 10:00:21 +0200 Subject: [PATCH 0835/1348] fixes for the comments in #723 --- dnsapi/dns_cloudns.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index d000d6a2..a9615c58 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$((i + 1)) + i=$(_math "$i" + 1) done return 1 } @@ -150,7 +150,7 @@ _dns_cloudns_http_api_call() { response="$(_get "$CLOUDNS_API/$method?$data")" - _debug response "$response" + _debug2 response "$response" - return 1 + return 0 } From f063dd195e44c099c0c65322049745af5cbb063a Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:49:14 +0200 Subject: [PATCH 0836/1348] some additional fixes and removed awk --- dnsapi/dns_cloudns.sh | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index a9615c58..9f6f1679 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -77,7 +77,7 @@ dns_cloudns_rm() { 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=" + _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 @@ -103,6 +103,13 @@ _dns_cloudns_init_check() { 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 @@ -134,7 +141,7 @@ _dns_cloudns_get_zone_name() { _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" | awk 'BEGIN { FS="\"" } {print $2}' + echo "$response" | cut -d '"' -f 2 return 0 fi return 1 @@ -146,7 +153,11 @@ _dns_cloudns_http_api_call() { _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + 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")" From 136d1b04b5379401ab721dc0939f9b0aa24507cb Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:52:05 +0200 Subject: [PATCH 0837/1348] some additional fixes and removed awk --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 9f6f1679..4bb2c267 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -153,7 +153,7 @@ _dns_cloudns_http_api_call() { _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - if [ -z $2 ]; then + 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" From c0b20275885437ff540c747b4f936510215a74ce Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:58:04 +0200 Subject: [PATCH 0838/1348] add ClouDNS to the list in the main README file --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 52231d0f..1cf29746 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,7 @@ You don't have to do anything manually! 1. Gandi LiveDNS API 1. Knot DNS API 1. DigitalOcean API (native) +1. ClouDNS API **More APIs coming soon...** From 819d2bc560e260e09a41b1124794f8348b899f2d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Mar 2017 22:52:57 +0800 Subject: [PATCH 0839/1348] fix for wget. fix https://github.com/Neilpang/acme.sh/issues/724#issuecomment-286761682 --- dnsapi/dns_aws.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 84aa28d3..d5d52de0 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -143,7 +143,7 @@ aws_rest() { CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" SignedHeaders="host;x-amz-date" 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" SignedHeaders="${SignedHeaders};x-amz-security-token" fi @@ -204,8 +204,8 @@ aws_rest() { Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" _debug2 Authorization "$Authorization" - _H3="Authorization: $Authorization" - _debug _H3 "$_H3" + _H2="Authorization: $Authorization" + _debug _H2 "$_H2" url="$AWS_URL/$ep" From 5ffca2d1383c017f07897dd8c77c34beb15153c2 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 17:16:54 +0200 Subject: [PATCH 0840/1348] Update cotnact details --- dnsapi/dns_cloudns.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 4bb2c267..f48a8052 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -1,5 +1,8 @@ #!/usr/bin/env sh +# Author: Boyan Peychev +# Repository: https://github.com/ClouDNS/acme.sh/ + #CLOUDNS_AUTH_ID=XXXXX #CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" CLOUDNS_API="https://api.cloudns.net" From 3e9478b58dda04923a2c1eeae9ad9613a04cc079 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 17:25:01 +0200 Subject: [PATCH 0841/1348] Update README information for ClouDNS --- README.md | 2 +- dnsapi/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1cf29746..5c1ddd80 100644 --- a/README.md +++ b/README.md @@ -309,7 +309,7 @@ You don't have to do anything manually! 1. Gandi LiveDNS API 1. Knot DNS API 1. DigitalOcean API (native) -1. ClouDNS API +1. ClouDNS.net API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 702efc1c..d419d5ed 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -407,7 +407,7 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_dgon -d example.com -d www.example.com ``` -## 21. Use ClouDNS API +## 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/ From 7044236824af45431413297c6224e11dcc785733 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Wed, 15 Mar 2017 11:40:32 -0700 Subject: [PATCH 0842/1348] Create dns_dynu.sh Add DNS API support for Dynu. --- dnsapi/dns_dynu.sh | 135 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 dnsapi/dns_dynu.sh diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh new file mode 100644 index 00000000..963bdd2f --- /dev/null +++ b/dnsapi/dns_dynu.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env sh + +my_dir="$(dirname "$0")" +source "$my_dir/acme.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" + +######## 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 +} + +#fulldomain +dns_dynu_rm() { + fulldomain=$1 +} + +######## 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 +} + +_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 + echo "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() { + export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + 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 +} From c87cd0de73f263ad2ce9892213a912b3ad691d07 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 16 Mar 2017 18:02:36 +0800 Subject: [PATCH 0843/1348] fix https://github.com/Neilpang/acme.sh/issues/729 https://github.com/Neilpang/acme.sh/issues/721 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7906aa4c..671b0d33 100755 --- a/acme.sh +++ b/acme.sh @@ -3477,7 +3477,10 @@ issue() { if [ ! "$usingApache" ]; then if webroot_owner=$(_stat "$_currentRoot"); then _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 _debug "not chaning owner/group of webroot" fi From 5c78e0a462178ea5424b241b486252c331c2bd53 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 16 Mar 2017 13:42:30 -0700 Subject: [PATCH 0844/1348] removed source acme.sh --- dnsapi/dns_dynu.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 963bdd2f..b12b0bbb 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -1,8 +1,5 @@ #!/usr/bin/env sh -my_dir="$(dirname "$0")" -source "$my_dir/acme.sh" - #Client ID Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" # From 2aa75f034ff1730bc576737b28b8002c7100129b Mon Sep 17 00:00:00 2001 From: jtbr Date: Sun, 19 Mar 2017 16:10:09 +0100 Subject: [PATCH 0845/1348] Adds support for --ca-path option for using non-default curl/wget CA certs --- acme.sh | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 671b0d33..68a3799a 100755 --- a/acme.sh +++ b/acme.sh @@ -1479,7 +1479,9 @@ _inithttp() { _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " 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 " fi @@ -1490,8 +1492,10 @@ _inithttp() { if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _ACME_WGET="$_ACME_WGET -d " fi - if [ "$CA_BUNDLE" ]; then - _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " + if [ "$CA_PATH" ]; then + _ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH " + elif [ "$CA_BUNDLE" ]; then + _ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE " fi fi @@ -3702,6 +3706,12 @@ issue() { else _clearaccountconf "CA_BUNDLE" fi + + if [ "$CA_PATH" ]; then + _saveaccountconf CA_PATH "$CA_PATH" + else + _clearaccountconf "CA_PATH" + fi if [ "$HTTPS_INSECURE" ]; then _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" @@ -4918,6 +4928,7 @@ _process() { _stopRenewOnError="" #_insecure="" _ca_bundle="" + _ca_path="" _nocron="" _ecc="" _csr="" @@ -5232,6 +5243,11 @@ _process() { CA_BUNDLE="$_ca_bundle" shift ;; + --ca-path) + _ca_path="$2" + CA_PATH="$_ca_path" + shift + ;; --nocron) _nocron="1" ;; From f21dd9117dc470f47668439ede249916d0a8cd2c Mon Sep 17 00:00:00 2001 From: jtbr Date: Sun, 19 Mar 2017 17:55:26 +0100 Subject: [PATCH 0846/1348] Handle case of busybox netstat, with no pid support --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 671b0d33..d5d9f313 100755 --- a/acme.sh +++ b/acme.sh @@ -1131,8 +1131,12 @@ _ss() { elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then #for solaris 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 " + else + #for busybox (embedded linux; no pid support) + netstat -ntl 2>/dev/null | grep ":$_port " fi fi return 0 From f19f21007c081074a47baba06582d53acfd8586a Mon Sep 17 00:00:00 2001 From: jtbr Date: Mon, 20 Mar 2017 18:51:45 +0100 Subject: [PATCH 0847/1348] formatting --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d5d9f313..043308e9 100755 --- a/acme.sh +++ b/acme.sh @@ -1131,7 +1131,7 @@ _ss() { elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then #for solaris netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" - elif netstat -help 2>&1 | grep "\-p" > /dev/null; then + elif netstat -help 2>&1 | grep "\-p" >/dev/null; then #for full linux netstat -ntpl | grep ":$_port " else From 4bdab73dd51f9bad4c823ab199b5c85ff0808fe4 Mon Sep 17 00:00:00 2001 From: jtbr Date: Mon, 20 Mar 2017 18:53:08 +0100 Subject: [PATCH 0848/1348] formatting --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 68a3799a..67b52cfe 100755 --- a/acme.sh +++ b/acme.sh @@ -3706,7 +3706,7 @@ issue() { else _clearaccountconf "CA_BUNDLE" fi - + if [ "$CA_PATH" ]; then _saveaccountconf CA_PATH "$CA_PATH" else From 5c539af7d7645723b928389bc93da526f0dcfa60 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Mar 2017 21:20:35 +0800 Subject: [PATCH 0849/1348] rename parameters --- README.md | 10 +++++----- acme.sh | 38 +++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 5c1ddd80..64609067 100644 --- a/README.md +++ b/README.md @@ -161,17 +161,17 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT** **Apache** example: ```bash acme.sh --install-cert -d example.com \ ---certpath /path/to/certfile/in/apache/cert.pem \ ---keypath /path/to/keyfile/in/apache/key.pem \ ---fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ +--cert-file /path/to/certfile/in/apache/cert.pem \ +--key-file /path/to/keyfile/in/apache/key.pem \ +--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \ --reloadcmd "service apache2 force-reload" ``` **Nginx** example: ```bash acme.sh --install-cert -d example.com \ ---keypath /path/to/keyfile/in/nginx/key.pem \ ---fullchainpath /path/to/fullchain/nginx/cert.pem \ +--key-file /path/to/keyfile/in/nginx/key.pem \ +--fullchain-file /path/to/fullchain/nginx/cert.pem \ --reloadcmd "service nginx force-reload" ``` diff --git a/acme.sh b/acme.sh index f8a1c49d..15257687 100755 --- a/acme.sh +++ b/acme.sh @@ -4035,7 +4035,7 @@ deploy() { installcert() { _main_domain="$1" 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 fi @@ -4785,10 +4785,10 @@ Parameters: 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. - --keypath /path/to/real/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. - --fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. + --cert-file /path/to/real/cert/file After issue/renew, the cert will be copied to this path. + --key-file /path/to/real/key/file After issue/renew, the key will be copied to this path. + --ca-file /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. + --fullchain-file /path/to/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. @@ -4913,10 +4913,10 @@ _process() { _webroot="" _keylength="" _accountkeylength="" - _certpath="" - _keypath="" - _capath="" - _fullchainpath="" + _cert_file="" + _key_file="" + _ca_file="" + _fullchain_file="" _reloadcmd="" _password="" _accountconf="" @@ -5158,20 +5158,20 @@ _process() { shift ;; - --certpath) - _certpath="$2" + --cert-file | --certpath) + _cert_file="$2" shift ;; - --keypath) - _keypath="$2" + --key-file | --keypath) + _key_file="$2" shift ;; - --capath) - _capath="$2" + --ca-file | --capath) + _ca_file="$2" shift ;; - --fullchainpath) - _fullchainpath="$2" + --fullchain-file | --fullchainpath) + _fullchain_file="$2" shift ;; --reloadcmd | --reloadCmd) @@ -5393,7 +5393,7 @@ _process() { uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; 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 "$_domain" "$_deploy_hook" "$_ecc" @@ -5405,7 +5405,7 @@ _process() { showcsr "$_csr" "$_domain" ;; installcert) - installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc" + installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc" ;; renew) renew "$_domain" "$_ecc" From 13fe54c938e964caefe74a9bb46087b6fbc4121f Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Mar 2017 22:58:03 +0800 Subject: [PATCH 0850/1348] update doc --- acme.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 15257687..244f72e3 100755 --- a/acme.sh +++ b/acme.sh @@ -4785,10 +4785,10 @@ Parameters: These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: - --cert-file /path/to/real/cert/file After issue/renew, the cert will be copied to this path. - --key-file /path/to/real/key/file After issue/renew, the key will be copied to this path. - --ca-file /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. - --fullchain-file /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. + --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. + --ca-file After issue/renew, the intermediate 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. @@ -4807,6 +4807,7 @@ Parameters: --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. --ca-bundle Specifices 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. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. From 4ddafb8e84cc2c647f788a58f0ba148433dfa7e3 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:14:28 -0500 Subject: [PATCH 0851/1348] Added Infoblox reference --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 64609067..014f0db3 100644 --- a/README.md +++ b/README.md @@ -310,6 +310,7 @@ You don't have to do anything manually! 1. Knot DNS API 1. DigitalOcean API (native) 1. ClouDNS.net API +1. Infoblox NIOS API (https://www.infoblox.com/) **More APIs coming soon...** From d03929507058c13ce81a925a77b2320fcb9bb147 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:15:17 -0500 Subject: [PATCH 0852/1348] Added Infoblox references --- dnsapi/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index d419d5ed..4543d9b4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -421,6 +421,23 @@ 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. + # Use custom API If your API is not supported yet, you can write your own DNS API. From b0561058c6a19e700d19ec9233d8d656f7cbed46 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:16:31 -0500 Subject: [PATCH 0853/1348] Infoblox API --- dnsapi/dns_infoblox.sh | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 dnsapi/dns_infoblox.sh diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh new file mode 100644 index 00000000..e71c90c9 --- /dev/null +++ b/dnsapi/dns_infoblox.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env 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 "$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 "$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=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + 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 ################################## From b1e4a7c61570137cf04901f3f92e3f4c8449b023 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:34:29 -0500 Subject: [PATCH 0854/1348] Fixed (hopefully) TravisCI errors --- dnsapi/dns_infoblox.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index e71c90c9..347c69e7 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -25,7 +25,7 @@ dns_infoblox_add() { _saveaccountconf Infoblox_Server "$Infoblox_Server" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -57,7 +57,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## 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=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + objRef=$(_egrep_o 'record:txt/.*:.*/default' <<< $result) objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") From 2c37d946111034eacf23b20a38a511ab131b2f3c Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:40:09 -0500 Subject: [PATCH 0855/1348] More bs --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 347c69e7..975dc771 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## 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=$(_egrep_o 'record:txt/.*:.*/default' <<< $result) + objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") From 7dc548b4b8764f8d8f36898a9f19db1ba2adb92e Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 15:06:37 -0500 Subject: [PATCH 0856/1348] MORE bs --- dnsapi/dns_infoblox.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 975dc771..8b9f9370 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -25,7 +25,7 @@ dns_infoblox_add() { _saveaccountconf Infoblox_Server "$Infoblox_Server" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -57,7 +57,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## 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=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + 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") From 1424e8a2de3f43947045a4861f3c3f9634d19748 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 20:20:04 -0500 Subject: [PATCH 0857/1348] Added attribution --- dnsapi/dns_infoblox.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 8b9f9370..3846e62e 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,5 +1,9 @@ #!/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 From 8afd31902fdff51ee3ce66fe124892d8cb232b3e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:26 +0000 Subject: [PATCH 0858/1348] spelling: application --- dnsapi/dns_ovh.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index faf5b42b..71642bd4 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#Applcation Key +#Application Key #OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" # #Application Secret From 3d22708f670ebcf56325631d25ca3e769f9cf8ef Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:38 +0000 Subject: [PATCH 0859/1348] spelling: automatically --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 4543d9b4..9eb77915 100644 --- a/dnsapi/README.md +++ b/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 -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. ## 16. Use cyon.ch From bcbecff6f6d4fed138a63255ae344bb70610d907 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:52 +0000 Subject: [PATCH 0860/1348] spelling: certificate --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 014f0db3..7a79bed4 100644 --- a/README.md +++ b/README.md @@ -329,7 +329,7 @@ Just set the `length` parameter with a prefix `ec-`. For example: -### Single domain ECC cerfiticate +### Single domain ECC certificate ```bash acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256 From 291c97dc81aeabacd40f14eda71d98bfa3f7a112 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:04 +0000 Subject: [PATCH 0861/1348] spelling: challenge --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index f30c8958..14622ad1 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -112,7 +112,7 @@ dns_freedns_add() { # not produce accurate results as the value field is truncated # on this webpage. To get full value we would need to load # 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>.*//')" if [ $found != 0 ]; then break From 9b2aa974ba57d9953a18ee218468c253770a34a0 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:31 +0000 Subject: [PATCH 0862/1348] spelling: changed --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 14622ad1..7c1f009e 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -65,7 +65,7 @@ dns_freedns_add() { htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" if [ "$?" != "0" ]; 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." fi return 1 From b54ce3107897f60d784da78c29c8e2faf75df703 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:23 +0000 Subject: [PATCH 0863/1348] spelling: changing --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 244f72e3..bbefb6bc 100755 --- a/acme.sh +++ b/acme.sh @@ -3490,7 +3490,7 @@ issue() { _exec_err >/dev/null 2>&1 fi else - _debug "not chaning owner/group of webroot" + _debug "not changing owner/group of webroot" fi fi From 4cedbf80df52aeb39489caeb4646a9625f17ea8a Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:20 +0000 Subject: [PATCH 0864/1348] spelling: delimiter --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 3b9c5c79..80a4b02d 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -43,7 +43,7 @@ kong_deploy() { #Save kong url if it's succesful (First run case) _saveaccountconf KONG_URL "$KONG_URL" #Generate DEIM - delim="-----MultipartDelimeter$(date "+%s%N")" + delim="-----MultipartDelimiter$(date "+%s%N")" nl="\015\012" #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" From 506f36b26ddc0dae35a5bf11316ae0fbe53c4fda Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:43 +0000 Subject: [PATCH 0865/1348] spelling: embedded --- dnsapi/dns_pdns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index ebc02949..7d807c81 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#PowerDNS Emdedded API +#PowerDNS Embedded API #https://doc.powerdns.com/md/httpapi/api_spec/ # #PDNS_Url="http://ns.example.com:8081" From 39f3239682b98a9ac9a83a646110dd24f7aba728 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:55 +0000 Subject: [PATCH 0866/1348] spelling: following --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 7c1f009e..6383c589 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -10,7 +10,7 @@ # ######## Public functions ##################### -# Export FreeDNS userid and password in folowing variables... +# Export FreeDNS userid and password in following variables... # FREEDNS_User=username # FREEDNS_Password=password # login cookie is saved in acme account config file so userid / pw From d39b1082746f3b7672dfe34311704163ffbe62f1 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:27:04 +0000 Subject: [PATCH 0867/1348] spelling: function --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 6383c589..aebbc68c 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -192,7 +192,7 @@ dns_freedns_rm() { # Need to read cookie from conf file again in case new value set # 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")" _debug "FreeDNS login cookies: $FREEDNS_COOKIE" From 357b514bc903e2e2c8acf500f760a8c7027df3ec Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:04 +0000 Subject: [PATCH 0868/1348] spelling: lines --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bbefb6bc..22cd412c 100755 --- a/acme.sh +++ b/acme.sh @@ -879,7 +879,7 @@ _sign() { if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" - _err "Key content:$(wc -l <"$keyfile") lises" + _err "Key content:$(wc -l <"$keyfile") lines" return 1 fi _debug3 "_signedECText" "$_signedECText" From 84a6730b1a05edd91f74cd96ad902c88b8e373b7 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:37 +0000 Subject: [PATCH 0869/1348] spelling: obtain --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 22cd412c..d686834a 100755 --- a/acme.sh +++ b/acme.sh @@ -4812,7 +4812,7 @@ Parameters: --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. --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. --deploy-hook The hook file to deploy cert --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. From 00b34eb2a4adafde6dd338ceb03bc551b3519f73 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:57 +0000 Subject: [PATCH 0870/1348] spelling: occurred --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 80a4b02d..e1873f35 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -72,7 +72,7 @@ kong_deploy() { response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") fi if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then - _err "An error occured with cert upload. Check response:" + _err "An error occurred with cert upload. Check response:" _err "$response" return 1 fi From df14085ec8ab262020c35d235d29c8aeda4e5af5 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:29:11 +0000 Subject: [PATCH 0871/1348] spelling: oops --- deploy/exim4.sh | 4 ++-- deploy/vsftpd.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/exim4.sh b/deploy/exim4.sh index bf92b438..573f762b 100644 --- a/deploy/exim4.sh +++ b/deploy/exim4.sh @@ -79,7 +79,7 @@ exim4_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore exim4 conf, please report bug to us." + _err "Oops, error restore exim4 conf, please report bug to us." fi return 1 fi @@ -105,7 +105,7 @@ exim4_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore exim4 conf, please report bug to us." + _err "Oops, error restore exim4 conf, please report bug to us." fi return 1 fi diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index 1c6410a6..ed44e709 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -76,7 +76,7 @@ vsftpd_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore vsftpd conf, please report bug to us." + _err "Oops, error restore vsftpd conf, please report bug to us." fi return 1 fi @@ -102,7 +102,7 @@ vsftpd_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore vsftpd conf, please report bug to us." + _err "Oops, error restore vsftpd conf, please report bug to us." fi return 1 fi From 61a48a5b9f775c1f7eaa56aefcb116881f458b85 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:29:30 +0000 Subject: [PATCH 0872/1348] spelling: please --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d686834a..91919e76 100755 --- a/acme.sh +++ b/acme.sh @@ -2385,7 +2385,7 @@ _setApache() { _debug "Backup apache config file" "$httpdconf" 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 "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 fi _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" From 849bed4bef08cbf303f7a97129bea804424af3da Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:03 +0000 Subject: [PATCH 0873/1348] spelling: requires --- dnsapi/dns_dgon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index 9ceede44..7e1f1fec 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -158,7 +158,7 @@ _get_base_domain() { 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 requres manual requests with DO) + ## 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!) From 997c517ba270727c7fa220e67a8680245c7b1b48 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:15 +0000 Subject: [PATCH 0874/1348] spelling: return --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index aebbc68c..6c8f95a9 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,7 +53,7 @@ dns_freedns_add() { i="$(_math "$i" - 1)" 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 # happens after a period of inactivity. Immediately trying again # returns the correct subdomain page. So, we will try twice to @@ -196,7 +196,7 @@ dns_freedns_rm() { FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "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 # happens after a period of inactivity. Immediately trying again # returns the correct subdomain page. So, we will try twice to From 0d6ce9f97773fce4ed811e7bfe2993fde48b739f Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:26 +0000 Subject: [PATCH 0875/1348] spelling: satisfy --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index c096d8b0..d7ad712c 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -50,7 +50,7 @@ _cyon_load_credentials() { fi if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then - # Dummy entries to satify script checker. + # Dummy entries to satisfy script checker. CY_Username="" CY_Password="" CY_OTP_Secret="" From 00777a10ae38de2b3d59c94be3f9ebed098a9cd4 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:43 +0000 Subject: [PATCH 0876/1348] spelling: security --- dnsapi/dns_freedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 6c8f95a9..77e4322c 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -341,7 +341,7 @@ _freedns_add_txt_record() { return 1 elif _contains "$htmlpage" "security code was incorrect"; then _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" return 1 fi From f3c984281c927cf37cb61a556670ffb36dd0e7a0 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:58 +0000 Subject: [PATCH 0877/1348] spelling: specified --- dnsapi/dns_gandi_livedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 41f42980..28b8f99d 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -19,7 +19,7 @@ dns_gandi_livedns_add() { txtvalue=$2 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" return 1 fi From 8f73e241755a3ad419245e705bcbb597e9d33c3e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:31:12 +0000 Subject: [PATCH 0878/1348] spelling: specifies --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 91919e76..28c0721f 100755 --- a/acme.sh +++ b/acme.sh @@ -4806,7 +4806,7 @@ Parameters: --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. --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. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' From 7f32488b781b5b1910839839606c71a5e3a6f69e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:31:35 +0000 Subject: [PATCH 0879/1348] spelling: subdomain --- dnsapi/dns_freedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 77e4322c..272a1243 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -302,12 +302,12 @@ _freedns_retrieve_subdomain_page() { export _H2="Accept-Language:en-US" url="https://freedns.afraid.org/subdomain/" - _debug "Retrieve subdmoain page from FreeDNS" + _debug "Retrieve subdomain page from FreeDNS" htmlpage="$(_get "$url")" if [ "$?" != "0" ]; then - _err "FreeDNS retrieve subdomins failed bad RC from _get" + _err "FreeDNS retrieve subdomains failed bad RC from _get" return 1 elif [ -z "$htmlpage" ]; then _err "FreeDNS returned empty subdomain page" From f94433e504c7787b93751755f3347455c61dc629 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:32:29 +0000 Subject: [PATCH 0880/1348] spelling: validation --- acme.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 28c0721f..ce5b1dbd 100755 --- a/acme.sh +++ b/acme.sh @@ -2258,16 +2258,16 @@ _initpath() { fi if [ -z "$TLS_CONF" ]; then - TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" + TLS_CONF="$DOMAIN_PATH/tls.validation.conf" fi if [ -z "$TLS_CERT" ]; then - TLS_CERT="$DOMAIN_PATH/tls.valdation.cert" + TLS_CERT="$DOMAIN_PATH/tls.validation.cert" fi if [ -z "$TLS_KEY" ]; then - TLS_KEY="$DOMAIN_PATH/tls.valdation.key" + TLS_KEY="$DOMAIN_PATH/tls.validation.key" fi if [ -z "$TLS_CSR" ]; then - TLS_CSR="$DOMAIN_PATH/tls.valdation.csr" + TLS_CSR="$DOMAIN_PATH/tls.validation.csr" fi } @@ -2883,7 +2883,7 @@ _on_issue_err() { uri=$(echo "$ventry" | cut -d "$sep" -f 3) vtype=$(echo "$ventry" | cut -d "$sep" -f 4) _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - __trigger_validaton "$uri" "$keyauthorization" + __trigger_validation "$uri" "$keyauthorization" done ) fi @@ -3105,7 +3105,7 @@ __get_domain_new_authz() { } #uri keyAuthorization -__trigger_validaton() { +__trigger_validation() { _debug2 "tigger domain validation." _t_url="$1" _debug2 _t_url "$_t_url" @@ -3531,7 +3531,7 @@ issue() { fi fi - if ! __trigger_validaton "$uri" "$keyauthorization"; then + if ! __trigger_validation "$uri" "$keyauthorization"; then _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup From d0300d4443caf45f0619cba436b40128e09dc71d Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 12:27:21 -0700 Subject: [PATCH 0881/1348] Changes as requested per Commit 9c90b21 In dnsapi/dns_dynu.sh line 115: export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" ^-- SC2155: Declare and assign separately to avoid masking return values. --- dnsapi/dns_dynu.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index b12b0bbb..c50c7a18 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,9 @@ _dynu_rest() { } _dynu_authentication() { - export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + 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")" From cd8fcbf9c63a9a60726fb2bc3a889df55fdf87dd Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 12:38:12 -0700 Subject: [PATCH 0882/1348] Spaces in assignment removed. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index c50c7a18..19a24471 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,7 @@ _dynu_rest() { } _dynu_authentication() { - realm = "$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" export _H1="Authorization: Basic $realm" export _H2="Content-Type: application/json" From b7b934913ef0375700e3808801db5565b36ed193 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 13:39:31 -0700 Subject: [PATCH 0883/1348] Removed unnecessary spaces --- dnsapi/dns_dynu.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 19a24471..b81840d0 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -42,7 +42,7 @@ dns_dynu_add() { if ! _get_root "$fulldomain"; then _err "Invalid domain" return 1 - fi + fi _debug _node "$_node" _debug _domain_name "$_domain_name" @@ -83,7 +83,7 @@ _get_root() { _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 + return 0 } _dynu_rest() { @@ -113,7 +113,7 @@ _dynu_rest() { _dynu_authentication() { realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" - + export _H1="Authorization: Basic $realm" export _H2="Content-Type: application/json" @@ -128,7 +128,7 @@ _dynu_authentication() { if _contains "$Dynu_Token" "null"; then Dynu_Token="" fi - + _debug2 response "$response" return 0 } From e137792efdb0986192b0b96cf728e670c4719c1b Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 28 Mar 2017 08:11:04 -0700 Subject: [PATCH 0884/1348] Commented out Dynu_ClientId and Dynu_Secret --- dnsapi/dns_dynu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index b81840d0..03a45c1a 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -1,10 +1,10 @@ #!/usr/bin/env sh #Client ID -Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" +#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" # #Secret -Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" +#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" # #Token Dynu_Token="" From 58d4c74b0bc09e4f6480ad2845a81df8b882da61 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 29 Mar 2017 09:10:42 +0800 Subject: [PATCH 0885/1348] export Le_Domain for reloadcmd fix https://github.com/Neilpang/acme.sh/issues/558#issuecomment-289926193 --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index ce5b1dbd..28344c6d 100755 --- a/acme.sh +++ b/acme.sh @@ -4134,6 +4134,7 @@ _installcert() { export CERT_KEY_PATH export CA_CERT_PATH export CERT_FULLCHAIN_PATH + export Le_Domain cd "$DOMAIN_PATH" && eval "$_reload_cmd" ); then _info "$(__green "Reload success")" From 6cf7be4b7e8899e4ca1658027af535b40485afd3 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 29 Mar 2017 09:16:22 +0800 Subject: [PATCH 0886/1348] fix https://github.com/Neilpang/acme.sh/issues/751 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 28344c6d..7cb36afb 100755 --- a/acme.sh +++ b/acme.sh @@ -340,7 +340,7 @@ _hasfield() { _sep="," fi - for f in $(echo "$_str" | tr ',' ' '); do + for f in $(echo "$_str" | tr "$_sep" ' '); do if [ "$f" = "$_field" ]; then _debug2 "'$_str' contains '$_field'" return 0 #contains ok From d8ba26e664242338b4e10ae5c50320ef0122922d Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 30 Mar 2017 21:16:25 +0800 Subject: [PATCH 0887/1348] add retry for issuer cert --- acme.sh | 99 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/acme.sh b/acme.sh index 7cb36afb..3bd9b024 100755 --- a/acme.sh +++ b/acme.sh @@ -138,8 +138,8 @@ _printargs() { _dlg_versions() { echo "Diagnosis versions: " echo "openssl:$ACME_OPENSSL_BIN" - if _exists "$ACME_OPENSSL_BIN"; then - $ACME_OPENSSL_BIN version 2>&1 + if _exists "${ACME_OPENSSL_BIN:-openssl}"; then + ${ACME_OPENSSL_BIN:-openssl} version 2>&1 else echo "$ACME_OPENSSL_BIN doesn't exists." fi @@ -790,19 +790,19 @@ _base64() { [ "" ] #urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" - $ACME_OPENSSL_BIN base64 -e + ${ACME_OPENSSL_BIN:-openssl} base64 -e else _debug3 "base64 single line." - $ACME_OPENSSL_BIN base64 -e | tr -d '\r\n' + ${ACME_OPENSSL_BIN:-openssl} base64 -e | tr -d '\r\n' fi } #Usage: multiline _dbase64() { if [ "$1" ]; then - $ACME_OPENSSL_BIN base64 -d -A + ${ACME_OPENSSL_BIN:-openssl} base64 -d -A else - $ACME_OPENSSL_BIN base64 -d + ${ACME_OPENSSL_BIN:-openssl} base64 -d fi } @@ -819,9 +819,9 @@ _digest() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; 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 - $ACME_OPENSSL_BIN dgst -"$alg" -binary | _base64 + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -binary | _base64 fi else _err "$alg is not supported yet" @@ -844,9 +844,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; 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 - $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 else _err "$alg is not supported yet" @@ -865,7 +865,7 @@ _sign() { return 1 fi - _sign_openssl="$ACME_OPENSSL_BIN dgst -sign $keyfile " + _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " if [ "$alg" = "sha256" ]; then _sign_openssl="$_sign_openssl -$alg" else @@ -876,7 +876,7 @@ _sign() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then $_sign_openssl | _base64 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 "Key file: $keyfile" _err "Key content:$(wc -l <"$keyfile") lines" @@ -948,10 +948,10 @@ _createkey() { if _isEccKey "$length"; then _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 _debug "Using RSA: $length" - $ACME_OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" + ${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null >"$f" fi if [ "$?" != "0" ]; then @@ -1038,9 +1038,9 @@ _createcsr() { _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" 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 - $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 } @@ -1052,7 +1052,7 @@ _signcsr() { cert="$4" _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="$?" _debug "$_msg" return $_ret @@ -1065,7 +1065,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 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 @@ -1080,7 +1080,7 @@ _readSubjectAltNamesFromCSR() { _csrsubj="$(_readSubjectFromCSR "$_csrfile")" _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" if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then @@ -1101,7 +1101,7 @@ _readKeyLengthFromCSR() { return 1 fi - _outcsr="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile")" + _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' @@ -1159,9 +1159,9 @@ toPkcs() { _initpath "$domain" "$_isEcc" 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 - $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 if [ "$?" = "0" ]; then @@ -1183,7 +1183,7 @@ toPkcs8() { _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 _info "Success, $CERT_PKCS8_PATH" @@ -1344,7 +1344,7 @@ _calcjwk() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _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 pub_exp=0$pub_exp fi @@ -1353,7 +1353,7 @@ _calcjwk() { e=$(echo "$pub_exp" | _h2b | _base64) _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" n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" _debug3 n "$n" @@ -1366,12 +1366,12 @@ _calcjwk() { JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _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" if [ -z "$crv" ]; then _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" case "${crv_oid}" in "prime256v1") @@ -1391,15 +1391,15 @@ _calcjwk() { _debug3 crv "$crv" 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) _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) _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" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" @@ -2017,7 +2017,7 @@ _starttlsserver() { return 1 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 __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" else @@ -3635,6 +3635,7 @@ issue() { _rcert="$response" 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" if [ "$Le_LinkCert" ]; then @@ -3681,16 +3682,34 @@ issue() { if ! _contains "$Le_LinkIssuer" ":"; then Le_LinkIssuer="$API$Le_LinkIssuer" fi - + _debug Le_LinkIssuer "$Le_LinkIssuer" _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ]; then - echo "$BEGIN_CERT" >"$CA_CERT_PATH" - _get "$Le_LinkIssuer" | _base64 "multiline" >>"$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 ")" + _link_issuer_retry=0; + _MAX_ISSUER_RETRY=5; + while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do + _debug _link_issuer_retry "$_link_issuer_retry" + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then + echo "$BEGIN_CERT" >"$CA_CERT_PATH" + _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" + echo "$END_CERT" >>"$CA_CERT_PATH" + + _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" + cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" + _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" + + rm -f "$CA_CERT_PATH.der" + break + fi + _link_issuer_retry=$(_math $_link_issuer_retry + 1) + _sleep "$_link_issuer_retry" + done + if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then + _err "Max retry for issuer ca cert is reached." + fi + else + _debug "No Le_LinkIssuer header found." fi Le_CertCreateTime=$(_time) @@ -4463,7 +4482,7 @@ _precheck() { 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 "We need openssl to generate keys." return 1 @@ -4705,6 +4724,7 @@ _uninstallalias() { cron() { IN_CRON=1 _initpath + _info "$(__green "===Starting cron===")" if [ "$AUTO_UPGRADE" = "1" ]; then export LE_WORKING_DIR ( @@ -4724,6 +4744,7 @@ cron() { renewAll _ret="$?" IN_CRON="" + _info "$(__green "===End cron===")" exit $_ret } From 232c7361a94cd0959abe175ccb7d5fdab43aefce Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 30 Mar 2017 21:34:15 +0800 Subject: [PATCH 0888/1348] fix format --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 3bd9b024..99525459 100755 --- a/acme.sh +++ b/acme.sh @@ -3686,8 +3686,8 @@ issue() { _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ]; then - _link_issuer_retry=0; - _MAX_ISSUER_RETRY=5; + _link_issuer_retry=0 + _MAX_ISSUER_RETRY=5 while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do _debug _link_issuer_retry "$_link_issuer_retry" if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then From f3b434397b9928e36c7303ffaa9bbb8cf711bfc2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 3 Apr 2017 12:08:38 +0800 Subject: [PATCH 0889/1348] v2.6.8 support Docker --- Dockerfile | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 ++ acme.sh | 2 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..8d0f6185 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,52 @@ +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 + +ENTRYPOINT ["/root/.acme.sh/acme.sh", "--config-home", "/acme.sh"] +CMD ["--help"] diff --git a/README.md b/README.md index 7a79bed4..e0c1e7d6 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,13 @@ - 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. - 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. 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) diff --git a/acme.sh b/acme.sh index 99525459..e2bc928f 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.7 +VER=2.6.8 PROJECT_NAME="acme.sh" From 1f4e64f81d7650e7811153cf73e527b94fc252c1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 00:21:39 +0800 Subject: [PATCH 0890/1348] Truncated request for more than 100 domains. --- dnsapi/dns_aws.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index d5d52de0..6fffd093 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -88,6 +88,19 @@ _get_root() { while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then + if _contains "$response" "true" && _contains "$response" ""; then + _debug "IsTruncated" + _nextMarker="$(echo "$response" | _egrep_o ".*" | 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 return 1 fi From 66e38ae69e4487155cbc555f1230ac641e2b5f5a Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 13:46:39 -0700 Subject: [PATCH 0891/1348] Updated Readme.md file (1 of 2) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e0c1e7d6..567ec5ba 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) +1. Dynu API (https://www.dynu.com) **More APIs coming soon...** From afb67d375facf5065326362f2046452ee039bc94 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 14:01:40 -0700 Subject: [PATCH 0892/1348] Updated README.md (2 of 2) --- dnsapi/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9eb77915..e8c263b0 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,6 +438,22 @@ 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 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. + # Use custom API If your API is not supported yet, you can write your own DNS API. From fc9649dbc48bc89626d0f80fd7db20442cb17f0e Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 10:02:45 +0800 Subject: [PATCH 0893/1348] fix aws --- dnsapi/dns_aws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 6fffd093..137af895 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -92,7 +92,7 @@ _get_root() { _debug "IsTruncated" _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug "NextMarker" "$_nextMarker" - if aws_rest GET "2013-04-01/hostedzone?marker=$_nextMarker"; then + if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then _debug "Truncated request OK" i=2 p=1 @@ -220,7 +220,7 @@ aws_rest() { _H2="Authorization: $Authorization" _debug _H2 "$_H2" - url="$AWS_URL/$ep" + url="$AWS_URL/$ep?$qsr" if [ "$mtd" = "GET" ]; then response="$(_get "$url")" From 695482ded7248b25ecaa23e00571dd32d04f4ad4 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 21:21:50 -0700 Subject: [PATCH 0894/1348] Added author name and link to report bugs --- dnsapi/dns_dynu.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 03a45c1a..9bf2c064 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -11,7 +11,10 @@ Dynu_Token="" # #Endpoint Dynu_EndPoint="https://api.dynu.com/v1" - +# +#Author: David Kerr +#Report Bugs here: https://github.com/dkerr64/acme.sh +# ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" From 6d7f6750e94bc969fed6469bff6402be538987a8 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 21:22:58 -0700 Subject: [PATCH 0895/1348] Updated author name and link to report bugs --- dnsapi/dns_dynu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 9bf2c064..63992ed4 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -12,8 +12,8 @@ Dynu_Token="" #Endpoint Dynu_EndPoint="https://api.dynu.com/v1" # -#Author: David Kerr -#Report Bugs here: https://github.com/dkerr64/acme.sh +#Author: Dynu Systems, Inc. +#Report Bugs here: https://github.com/shar0119/acme.sh # ######## Public functions ##################### From fd77e463a150e2253aa7ca6658c17bddb62fef79 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 14:34:23 +0800 Subject: [PATCH 0896/1348] fix aws --- dnsapi/dns_aws.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 137af895..6a723537 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -220,7 +220,10 @@ aws_rest() { _H2="Authorization: $Authorization" _debug _H2 "$_H2" - url="$AWS_URL/$ep?$qsr" + url="$AWS_URL/$ep" + if [ "$qsr" ]; then + url="$AWS_URL/$ep?$qsr" + fi if [ "$mtd" = "GET" ]; then response="$(_get "$url")" From f7217c5f2629d541a4584039a7d9c9313afdda7f Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 15:54:45 +0800 Subject: [PATCH 0897/1348] fix format --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 6a723537..21e86686 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -88,7 +88,7 @@ _get_root() { while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then - if _contains "$response" "true" && _contains "$response" ""; then + if _contains "$response" "true" && _contains "$response" ""; then _debug "IsTruncated" _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug "NextMarker" "$_nextMarker" From 7df062b7d7d9ff95f6a3b58f005431ccd3cd4ec8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 22:33:26 +0800 Subject: [PATCH 0898/1348] add more debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index e2bc928f..8f47f8cc 100755 --- a/acme.sh +++ b/acme.sh @@ -1102,6 +1102,7 @@ _readKeyLengthFromCSR() { fi _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" + _debug2 _outcsr "$_outcsr" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' From 49d75a0cd4ba5112ca947a2b54ba72719ac4f73b Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 5 Apr 2017 20:46:17 +0800 Subject: [PATCH 0899/1348] minor, add more error message --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 8f47f8cc..850ac4b1 100755 --- a/acme.sh +++ b/acme.sh @@ -3121,6 +3121,10 @@ issue() { _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " return 1 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" _main_domain="$2" _alt_domains="$3" From 3576754c217c643d9b66cba0e91d858ada5781bf Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 5 Apr 2017 20:54:53 +0800 Subject: [PATCH 0900/1348] fix https://github.com/Neilpang/acme.sh/issues/549 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 850ac4b1..b6b0c842 100755 --- a/acme.sh +++ b/acme.sh @@ -107,7 +107,7 @@ __green() { if [ "$__INTERACTIVE" ]; then printf '\033[1;31;32m' fi - printf -- "$1" + printf -- "%b" "$1" if [ "$__INTERACTIVE" ]; then printf '\033[0m' fi @@ -117,7 +117,7 @@ __red() { if [ "$__INTERACTIVE" ]; then printf '\033[1;31;40m' fi - printf -- "$1" + printf -- "%b" "$1" if [ "$__INTERACTIVE" ]; then printf '\033[0m' fi From 482cb737025d691c730594abf8084c0bd1936bc6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 6 Apr 2017 19:29:09 +0800 Subject: [PATCH 0901/1348] fix https://github.com/Neilpang/acme.sh/issues/758 --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b6b0c842..11a30fa9 100755 --- a/acme.sh +++ b/acme.sh @@ -1105,10 +1105,10 @@ _readKeyLengthFromCSR() { _debug2 _outcsr "$_outcsr" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _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 _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 } @@ -3865,7 +3865,7 @@ renewAll() { return "$rc" else _ret="$rc" - _err "Error renew $d, Go ahead to next one." + _err "Error renew $d." fi fi done From 7f618e7ecc698f171135558b34b6980219b902d7 Mon Sep 17 00:00:00 2001 From: Kok Suan Lim Date: Sat, 8 Apr 2017 14:50:39 +0800 Subject: [PATCH 0902/1348] fix missing space bug on if statement --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 11a30fa9..f434f685 100755 --- a/acme.sh +++ b/acme.sh @@ -2565,7 +2565,7 @@ _checkConf() { if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then _debug "wildcard" 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 fi done From fcdf41ba293658060e82c45b3c3ec368db270385 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 11 Apr 2017 21:37:56 +0800 Subject: [PATCH 0903/1348] support change account conf from env --- acme.sh | 20 +++++++++++++++++++- dnsapi/dns_cf.sh | 6 ++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index f434f685..3498fe75 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.8 +VER=2.6.9 PROJECT_NAME="acme.sh" @@ -1847,6 +1847,24 @@ _saveaccountconf() { _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() { _clear_conf "$ACCOUNT_CONF_PATH" "$1" diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 3718f9db..0442fbe0 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -14,6 +14,8 @@ dns_cf_add() { fulldomain=$1 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="" @@ -29,8 +31,8 @@ dns_cf_add() { fi #save the api key and email to the account conf file. - _saveaccountconf CF_Key "$CF_Key" - _saveaccountconf CF_Email "$CF_Email" + _saveaccountconf_mutable CF_Key "$CF_Key" + _saveaccountconf_mutable CF_Email "$CF_Email" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then From eb0fc67461c07ed5eeae8605d616e88ec9b985dc Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 11 Apr 2017 22:29:49 +0800 Subject: [PATCH 0904/1348] fix format --- dnsapi/dns_cf.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 0442fbe0..228caa82 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -14,8 +14,8 @@ dns_cf_add() { fulldomain=$1 txtvalue=$2 - CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key )}" - CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email )}" + 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="" From 9a61d6293d14a401f57fed793b9b829788c5b134 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 13 Apr 2017 20:48:39 -0700 Subject: [PATCH 0905/1348] Implemented dns_dynu_rm() Implemented dns_dynu_rm() method. --- dnsapi/dns_dynu.sh | 93 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 63992ed4..a3a604ba 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -35,7 +35,7 @@ dns_dynu_add() { _saveaccountconf Dynu_Secret "$Dynu_Secret" if [ -z "$Dynu_Token" ]; then - _info "Getting Dynu token" + _info "Getting Dynu token." if ! _dynu_authentication; then _err "Can not get token." fi @@ -43,29 +43,76 @@ dns_dynu_add() { _debug "Detect root zone" if ! _get_root "$fulldomain"; then - _err "Invalid domain" + _err "Invalid domain." return 1 fi _debug _node "$_node" _debug _domain_name "$_domain_name" - _info "Creating TXT record" + _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" + _err "Could not add TXT record." return 1 fi return 0 } -#fulldomain +#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 ################################## @@ -80,7 +127,7 @@ _get_root() { fi if ! _contains "$response" "domain_name"; then - _debug "Domain name not found" + _debug "Domain name not found." return 1 fi @@ -89,6 +136,38 @@ _get_root() { 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" grep -o -e "{[^}]*}" | grep '"text_data":"This is another TXT record."' | grep -o -e ",[^,]*," | 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" @@ -102,7 +181,7 @@ _dynu_rest() { _debug data "$data" response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" else - echo "Getting $Dynu_EndPoint/$ep" + _info "Getting $Dynu_EndPoint/$ep" response="$(_get "$Dynu_EndPoint/$ep")" fi From 394b1002b344db16ef8568f2933b162d9e87c9c5 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 13 Apr 2017 20:54:57 -0700 Subject: [PATCH 0906/1348] Corrected formatting error. Part of dns_dynu_rm() impementation. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index a3a604ba..e784c3b8 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,7 @@ dns_dynu_rm() { _err "Could not remove TXT record $_dns_record_id." fi - return 0 + return 0 } ######## Private functions below ################################## From 8470c60e067b522e3322f90bca980313ac110729 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Fri, 14 Apr 2017 12:46:00 -0700 Subject: [PATCH 0907/1348] Using _egrep_o() instead of grep -o -e Modified code to use egrep instead of grep -o -e. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index e784c3b8..19e7fc7b 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -149,7 +149,7 @@ _get_recordid() { return 0 fi - _dns_record_id=$(printf "%s" "$response" grep -o -e "{[^}]*}" | grep '"text_data":"This is another TXT record."' | grep -o -e ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) + _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | grep -Po '"id":\K[0-9]+') return 0 } From cd98951001ca5f9bbd79a6e35bca3653b1b1e0d8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 16 Apr 2017 09:36:59 +0800 Subject: [PATCH 0908/1348] fix https://github.com/Neilpang/acme.sh/issues/794#issuecomment-294314606 --- dnsapi/dns_cf.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 228caa82..57a2e884 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -85,6 +85,17 @@ dns_cf_add() { dns_cf_rm() { fulldomain=$1 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" if ! _get_root "$fulldomain"; then _err "invalid domain" From 7883cc58912418d96cf4f2eff5dac8e15015aa4d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 16 Apr 2017 11:16:48 +0800 Subject: [PATCH 0909/1348] fix docker cronjob --- Dockerfile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8d0f6185..feb89b0d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,5 +48,12 @@ RUN for verb in help \ 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 -ENTRYPOINT ["/root/.acme.sh/acme.sh", "--config-home", "/acme.sh"] +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"] From 3c07f57aade6d3995f16faa5f3ed3fac8d962d01 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 17 Apr 2017 19:08:34 +0800 Subject: [PATCH 0910/1348] minor remove spaces --- acme.sh | 26 +++++++++++++------------- dnsapi/dns_freedns.sh | 6 +++--- dnsapi/dns_ovh.sh | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/acme.sh b/acme.sh index 3498fe75..27bc4fb3 100755 --- a/acme.sh +++ b/acme.sh @@ -347,7 +347,7 @@ _hasfield() { fi done _debug2 "'$_str' does not contain '$_field'" - return 1 #not contains + return 1 #not contains } _getfield() { @@ -722,7 +722,7 @@ _url_encode() { "7e") printf "%s" "~" ;; - #other hex + #other hex *) printf '%%%s' "$_hex_code" ;; @@ -1025,7 +1025,7 @@ _createcsr() { else alt="DNS:$domainlist" fi - #multi + #multi _info "Multi domain" "$alt" printf -- "\nsubjectAltName=$alt" >>"$csrconf" fi @@ -1093,7 +1093,7 @@ _readSubjectAltNamesFromCSR() { printf "%s" "$_dnsAltnames" | sed "s/DNS://g" } -#_csrfile +#_csrfile _readKeyLengthFromCSR() { _csrfile="$1" if [ -z "$_csrfile" ]; then @@ -1192,7 +1192,7 @@ toPkcs8() { } -#[2048] +#[2048] createAccountKey() { _info "Creating account key" if [ -z "$1" ]; then @@ -2546,7 +2546,7 @@ _setNginx() { location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { default_type text/plain; return 200 \"\$1.$_thumbpt\"; -} +} #NGINX_START " >>"$FOUND_REAL_NGINX_CONF" @@ -3133,7 +3133,7 @@ __trigger_validation() { _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" } -#webroot, domain domainlist keylength +#webroot, domain domainlist keylength issue() { if [ -z "$2" ]; then _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " @@ -3666,7 +3666,7 @@ issue() { #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then # _debug "Get cert failed. Let's try last response." - # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" + # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" #fi if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then @@ -4807,7 +4807,7 @@ Commands: --create-domain-key Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. --deactivate Deactivate the domain authz, professional use. - + Parameters: --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. --force, -f Used to force to install or force to renew a cert immediately. @@ -4821,20 +4821,20 @@ Parameters: --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. --dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds. - + --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. --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: - + --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. --ca-file After issue/renew, the intermediate 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. --accountconf Specifies a customized account config file. diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 272a1243..53da4118 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,7 +53,7 @@ dns_freedns_add() { i="$(_math "$i" - 1)" sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" - # Sometimes FreeDNS does not return 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 # happens after a period of inactivity. Immediately trying again # returns the correct subdomain page. So, we will try twice to @@ -72,7 +72,7 @@ dns_freedns_add() { fi # Now convert the tables in the HTML to CSV. This litte gem from - # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv + # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv subdomain_csv="$(echo "$htmlpage" \ | grep -i -e ' Date: Wed, 19 Apr 2017 23:12:37 +0800 Subject: [PATCH 0911/1348] update doc --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e0c1e7d6..cf825625 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - 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 @@ -31,6 +31,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [Centminmod](http://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/) +- [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) # Tested OS From 27a05ff27112a29e98aa51661040ef3176c07531 Mon Sep 17 00:00:00 2001 From: LAV45 Date: Sat, 15 Apr 2017 14:34:37 +0300 Subject: [PATCH 0912/1348] Add dns_vscale.sh --- README.md | 1 + dnsapi/README.md | 15 +++++ dnsapi/dns_vscale.sh | 149 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100755 dnsapi/dns_vscale.sh diff --git a/README.md b/README.md index e0c1e7d6..47ea0126 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) +1. VSCALE (https://vscale.io/) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 9eb77915..896dfcb7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,6 +438,21 @@ 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. + +## 22. 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 vscale -d example.com -d www.example.com +``` + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh new file mode 100755 index 00000000..e50b7d8b --- /dev/null +++ b/dnsapi/dns_vscale.sh @@ -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 +} From dbe68684a054a11a6232803bafd0ba952380bc54 Mon Sep 17 00:00:00 2001 From: Aleksey Loban Date: Fri, 21 Apr 2017 12:30:01 +0300 Subject: [PATCH 0913/1348] Fix readme 'Use VSCALE API' [skip ci] --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 896dfcb7..82b47648 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -449,7 +449,7 @@ VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" Ok, let's issue a cert now: ``` -acme.sh --issue --dns vscale -d example.com -d www.example.com +acme.sh --issue --dns dns_vscale -d example.com -d www.example.com ``` From 020f9cd2a640a5347e46a650fdc4a3e059868ddc Mon Sep 17 00:00:00 2001 From: Aleksey Loban Date: Fri, 21 Apr 2017 13:15:39 +0300 Subject: [PATCH 0914/1348] small Fix readme [skip ci] --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 82b47648..d9f5c271 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -439,7 +439,7 @@ 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. -## 22. Use VSCALE API +## 23. Use VSCALE API First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). From a6e5876d964373c9fb68a16283f1097fb8b330c6 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 25 Apr 2017 19:33:54 -0700 Subject: [PATCH 0915/1348] Resolved conflict. Resolved conflict. --- dnsapi/README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index e8c263b0..41cc80a8 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,7 +438,21 @@ 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 Dynu API + +## 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 From 9cf65e31cd599e567498d2d7972d858857d629b8 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 25 Apr 2017 19:37:56 -0700 Subject: [PATCH 0916/1348] Resolved conflict. Resolved conflict. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 567ec5ba..cdcd40c3 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - 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 @@ -31,6 +31,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [Centminmod](http://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/) +- [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) # Tested OS @@ -313,6 +314,7 @@ You don't have to do anything manually! 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...** From 0138e167e91164bffc86eee29b4f140a1d03c93e Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 18:23:43 +0800 Subject: [PATCH 0917/1348] Update to support Kong-v0.10.x The previous one is for Kong-v0.9.x only. This change will allow it to work with v0.10.x. More info at: https://github.com/Mashape/kong/blob/4f960abe33fe3d45510944f062e571d63dc3a673/UPGRADE.md#upgrade-to-010x https://getkong.org/docs/0.10.x/admin-api/#add-certificate --- deploy/kong.sh | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index e1873f35..67eef693 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -31,14 +31,15 @@ kong_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - #Get 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}') - if [ -z "$uuid" ]; then - _err "Unable to get Kong uuid for domain $_cdomain" - _err "Make sure that KONG_URL is correctly configured" - _err "Make sure that a Kong api request_host match the domain" - _err "Kong url: $KONG_URL" - return 1 + #Get ssl_uuid linked to the domain + 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 "$ssl_uuid" ]; then + _debug "Unable to get Kong ssl_uuid for domain $_cdomain" + _debug "Make sure that KONG_URL is correctly configured" + _debug "Make sure that a Kong certificate match the sni" + _debug "Kong url: $KONG_URL" + _info "No existing certificate, creating..." + #return 1 fi #Save kong url if it's succesful (First run case) _saveaccountconf KONG_URL "$KONG_URL" @@ -48,12 +49,15 @@ kong_deploy() { #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) - #set name to ssl - content="--$delim${nl}Content-Disposition: form-data; name=\"name\"${nl}${nl}ssl" + content="--$delim${nl}" + if [ -z "$ssl_uuid" ]; then + #set sni to domain + content="$content{nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" + fi #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 - 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 content="$content${nl}--$delim--${nl}" #Convert CRLF @@ -61,17 +65,16 @@ kong_deploy() { #DEBUG _debug header "$_H1" _debug content "$content" - #Check if ssl plugins is aready enabled (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" + #Check if sslcreated (if not => POST else => PATCH) + if [ -z "$ssl_uuid" ]; then #Post certificate to Kong - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") + response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else #patch - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") + response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH") fi - if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then + if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then _err "An error occurred with cert upload. Check response:" _err "$response" return 1 From 3f1a76d9e4e8cb1ab79816db81df73dd663cca1a Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 27 Apr 2017 18:29:29 +0800 Subject: [PATCH 0918/1348] fix https://github.com/Neilpang/acme.sh/issues/808 --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 27bc4fb3..3506bdb9 100755 --- a/acme.sh +++ b/acme.sh @@ -2617,10 +2617,10 @@ _checkConf() { _isRealNginxConf() { _debug "_isRealNginxConf $1 $2" 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" 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" _start_n=$(echo "$_start" | cut -d : -f 1) _start_nn=$(_math $_start_n + 1) @@ -2629,8 +2629,8 @@ _isRealNginxConf() { _left="$(sed -n "${_start_nn},99999p" "$2")" _debug2 _left "$_left" - if echo "$_left" | grep -n "^ *server *{" >/dev/null; then - _end=$(echo "$_left" | grep -n "^ *server *{" | _head_n 1) + if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" >/dev/null; then + _end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" | _head_n 1) _debug "_end" "$_end" _end_n=$(echo "$_end" | cut -d : -f 1) _debug "_end_n" "$_end_n" From de3bac53bfb99e1b192bed48a1c5dcf694e2a606 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:06:47 +0800 Subject: [PATCH 0919/1348] update README --- deploy/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index d8c2f57c..232fdb4a 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -21,8 +21,11 @@ acme.sh --deploy -d example.com --deploy-hook cpanel ## 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). +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. From 4b02ee5b468814b2a19e9dd783b458264acbe776 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:38:08 +0800 Subject: [PATCH 0920/1348] Typo fix --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 67eef693..79dc3916 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -67,7 +67,7 @@ kong_deploy() { _debug content "$content" #Check if sslcreated (if not => POST else => PATCH) - if [ -z "$ssl_uuid" ]; then + if [ ! -z "$ssl_uuid" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else From c140fe9bae8926e3724545330505edc3e1355833 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:39:53 +0800 Subject: [PATCH 0921/1348] Typo Fix --- deploy/kong.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 79dc3916..9d1f40a7 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,6 +1,3 @@ -#!/usr/bin/env sh - -# This deploy hook will deploy ssl cert on kong proxy engine based on api request_host parameter. # Note that ssl plugin should be available on Kong instance # The hook will match cdomain to request_host, in case of multiple domain it will always take the first # one (acme.sh behaviour). @@ -49,10 +46,9 @@ kong_deploy() { #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) - content="--$delim${nl}" if [ -z "$ssl_uuid" ]; then #set sni to domain - content="$content{nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" + content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" fi #add key content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" @@ -67,7 +63,7 @@ kong_deploy() { _debug content "$content" #Check if sslcreated (if not => POST else => PATCH) - if [ ! -z "$ssl_uuid" ]; then + if [ -z "$ssl_uuid" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else From 148f869becd09518d015881763ab3f2ba98bfa2c Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 27 Apr 2017 22:21:59 +0800 Subject: [PATCH 0922/1348] fix https://github.com/Neilpang/acme.sh/issues/805 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3506bdb9..56e1ea49 100755 --- a/acme.sh +++ b/acme.sh @@ -1108,7 +1108,7 @@ _readKeyLengthFromCSR() { echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | tr "\t" " " | _egrep_o "(^ *|RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + echo "$_outcsr" | tr "\t" " " | (_egrep_o "^ *Public.Key:.*" || _egrep_o "RSA Public.Key:.*") | cut -d '(' -f 2 | cut -d ' ' -f 1 fi } From 824ffa24f497a69bd4b0cb0cf10520b27d326514 Mon Sep 17 00:00:00 2001 From: Andre Cantero Date: Fri, 28 Apr 2017 00:21:21 +0800 Subject: [PATCH 0923/1348] Add shebang --- deploy/kong.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/kong.sh b/deploy/kong.sh index 9d1f40a7..dce92096 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,3 +1,4 @@ +#!/usr/bin/env sh # Note that ssl plugin should be available on Kong instance # The hook will match cdomain to request_host, in case of multiple domain it will always take the first # one (acme.sh behaviour). From 1231b71245588f107bc9667c16925afeac0f4e4e Mon Sep 17 00:00:00 2001 From: Andre Cantero Date: Fri, 28 Apr 2017 00:25:30 +0800 Subject: [PATCH 0924/1348] Update the notes --- deploy/kong.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index dce92096..d3a6bc47 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,11 +1,7 @@ #!/usr/bin/env sh -# Note that ssl plugin should be available on Kong instance -# 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 +# If certificate already exist it will update only cert and key not touching other parameter +# If certificate doesn't exist it will only upload cert and key and not set other parameter +# Note that we deploy full chain # Written by Geoffroi Genot ######## Public functions ##################### From 5b3e3d9cf444e3c9e969244baedc18338f5b4ccc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 30 Apr 2017 16:29:20 +0800 Subject: [PATCH 0925/1348] fix https://github.com/Neilpang/acme.sh/issues/812 --- acme.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3506bdb9..7ce947ea 100755 --- a/acme.sh +++ b/acme.sh @@ -166,7 +166,14 @@ _syslog() { fi _logclass="$1" 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() { From 2310a9bbc0d043cc3340af8a933a0679004874ae Mon Sep 17 00:00:00 2001 From: shar0119 Date: Sun, 30 Apr 2017 10:32:56 -0700 Subject: [PATCH 0926/1348] Removed grep -Po Removed usage of grep -Po. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 19e7fc7b..f6eabde2 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -149,7 +149,7 @@ _get_recordid() { return 0 fi - _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | grep -Po '"id":\K[0-9]+') + _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) return 0 } From f5c381d5b466094f7c26573341deb517df5456b9 Mon Sep 17 00:00:00 2001 From: ka2er Date: Tue, 2 May 2017 00:45:29 +0200 Subject: [PATCH 0927/1348] less permissive permission on OVH API restrict authorization request to OVH /domain API and not whole OVH API. Not perfect due to some limitations in regex with *, but better security as the token don't give full access to the API. --- dnsapi/dns_ovh.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 18f9c7dc..6c1edb4d 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -119,7 +119,7 @@ dns_ovh_add() { _info "Checking authentication" - response="$(_ovh_rest GET "domain/")" + response="$(_ovh_rest GET "domain")" if _contains "$response" "INVALID_CREDENTIAL"; then _err "The consumer key is invalid: $OVH_CK" _err "Please retry to create a new one." @@ -191,7 +191,7 @@ _ovh_authentication() { _H3="" _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")" _debug3 response "$response" From 1994c6828ecaaefa50beb8fb5616ed51a3b98c48 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 5 Dec 2016 21:53:02 -0600 Subject: [PATCH 0928/1348] include dnsimple api Even though DNSimple is technically covered with lexicon not all systems can install python pip's easily. For these systems it is useful to have pure shell script API interactions. --- README.md | 1 + dnsapi/README.md | 36 +++++++-- dnsapi/dns_dnsimple.sh | 163 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 dnsapi/dns_dnsimple.sh diff --git a/README.md b/README.md index 0a320369..34b9243a 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,7 @@ You don't have to do anything manually! 1. CloudFlare.com API 1. DNSPod.cn API +1. DNSimple API 1. CloudXNS.com API 1. GoDaddy.com API 1. OVH, kimsufi, soyoustart and runabove API diff --git a/dnsapi/README.md b/dnsapi/README.md index 12d76bef..ad03ea79 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -422,31 +422,31 @@ 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 @@ -468,6 +468,28 @@ 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. # Use custom API diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh new file mode 100644 index 00000000..d714d36c --- /dev/null +++ b/dnsapi/dns_dnsimple.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env sh + +# DNSimple domain api +# +# 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//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" + + _debug "Retrive account ID" + if ! _get_account_id; then + _err "failed to retrive account id" + return 1 + fi + _debug _account_id "$_account_id" + + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + + _debug "Getting txt records" + _dnsimple_rest GET "$_account_id/zones/$_domain/records?per_page=100" + + if ! _contains "$response" "\"id\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$_sub_domain\"" | wc -l | _egrep_o "[0-9]+") + _debug count "$count" + + if [ "$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 "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) + _debug "record_id" "$record_id" + + _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" + if [ "$?" = "0" ]; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi +} + +# fulldomain +dns_dnsimple_rm() { + fulldomain=$1 + +} + +#################### Private functions bellow ################################## +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=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-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_get_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) + return 0 +} + +_dnsimple_rest() { + method=$1 + path="$2" + data="$3" + request_url="$DNSimple_API/$path" + _debug "$path" + + _H1="Accept: application/json" + _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + if [ "$data" ]; then + _H1="Content-Type: application/json" + _debug data "$data" + response="$(_post "$data" "$request_url" "" "$method")" + else + response="$(_get "$request_url")" + fi + + if [ "$?" != "0" ]; then + _err "error $request_url" + return 1 + fi + _debug2 response "$response" + return 0 +} From 2b092539618fc4ca627f9aa2b7b021488e222397 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Tue, 6 Dec 2016 08:32:14 -0600 Subject: [PATCH 0929/1348] link to contributor repo for support issues relating to the dnsimple API integration --- dnsapi/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index ad03ea79..f53d8ad4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -491,6 +491,9 @@ 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 If your API is not supported yet, you can write your own DNS API. From f4e81953ce59731c3c46f7dc6937417851bd6e88 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:07:05 -0600 Subject: [PATCH 0930/1348] provide a more general purpose request function This allows for more flexibility in the future. Most importantly being able to do more than just GET requests but any HTTP method. Specifically needed for DELETE requests. --- acme.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7ce947ea..3ccd8dc4 100755 --- a/acme.sh +++ b/acme.sh @@ -1592,12 +1592,17 @@ _post() { return $_ret } -# url getheader timeout _get() { - _debug GET + _request "$1" "$2" "$3" GET +} + +# url getheader timeout +_request() { url="$1" onlyheader="$2" t="$3" + method="$4" + _debug method $method _debug url "$url" _debug "timeout" "$t" @@ -1611,6 +1616,9 @@ _get() { if [ "$t" ]; then _CURL="$_CURL --connect-timeout $t" fi + if [ "$method" ]; then + _CURL="$_CURL -X $method" + fi _debug "_CURL" "$_CURL" if [ "$onlyheader" ]; then $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" @@ -1633,6 +1641,9 @@ _get() { if [ "$t" ]; then _WGET="$_WGET --timeout=$t" fi + if [ "$method" ]; then + _WGET="$_WGET --method=$method" + fi _debug "_WGET" "$_WGET" if [ "$onlyheader" ]; then $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' From f9b419d1e40c6056675891e846841158f36dc01a Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:08:32 -0600 Subject: [PATCH 0931/1348] cleanup dns in dnsimple api integration Implement the `_rm()` method for the DNSimple integration. This also required some changes and cleanup to DRY up the code. --- dnsapi/dns_dnsimple.sh | 96 +++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index d714d36c..dde6638e 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -26,49 +26,35 @@ dns_dnsimple_add() { # save the oauth token for later _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN" - _debug "Retrive account ID" if ! _get_account_id; then _err "failed to retrive account id" return 1 fi - _debug _account_id "$_account_id" if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi - _debug _domain "$_domain" - _debug _sub_domain "$_sub_domain" - - _debug "Getting txt records" - _dnsimple_rest GET "$_account_id/zones/$_domain/records?per_page=100" - - if ! _contains "$response" "\"id\":"; then - _err "Error" - return 1 - fi - count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$_sub_domain\"" | wc -l | _egrep_o "[0-9]+") - _debug count "$count" + _get_records $_account_id $_domain $_sub_domain - if [ "$count" = "0" ]; then + 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 "Add txt record error." + _err "Unexpected response while adding text record." return 1 fi fi _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) - _debug "record_id" "$record_id" + _extract_record_id $_records $_sub_domain - _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" + _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$_record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" if [ "$?" = "0" ]; then _info "Updated!" #todo: check if the record takes effect @@ -83,6 +69,31 @@ dns_dnsimple_add() { 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 + _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id" + + if [ "$?" = "0" ]; then + _info "removed record" "$_record_id" + return 0 + fi + fi + + _err "failed to remove record" "$_record_id" + return 1 + } #################### Private functions bellow ################################## @@ -93,7 +104,7 @@ dns_dnsimple_rm() { _get_root() { domain=$1 i=2 - p=1 + previous=1 while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then @@ -108,17 +119,24 @@ _get_root() { if _contains "$response" 'not found'; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous) _domain="$h" + + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + return 0 fi - p="$i" + + 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 @@ -129,14 +147,44 @@ _get_account_id() { fi if _contains "$response" "timeout"; then - _err "timeout retrieving account_id" + _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" @@ -151,7 +199,7 @@ _dnsimple_rest() { _debug data "$data" response="$(_post "$data" "$request_url" "" "$method")" else - response="$(_get "$request_url")" + response="$(_request "$request_url" "" "" "$method")" fi if [ "$?" != "0" ]; then From 326ac485b35e2783365f5ab660caec28fc64d794 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:15:37 -0600 Subject: [PATCH 0932/1348] link to repo for dnsimple integration support --- dnsapi/dns_dnsimple.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index dde6638e..f1c841dc 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -1,6 +1,7 @@ #!/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. From 2f4111a2e2ed01c27e070b375fa3f0179d0b46d3 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 13 Feb 2017 11:37:34 -0600 Subject: [PATCH 0933/1348] fixup shellcheck style issues --- dnsapi/dns_dnsimple.sh | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index f1c841dc..d92c6137 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -37,7 +37,7 @@ dns_dnsimple_add() { return 1 fi - _get_records $_account_id $_domain $_sub_domain + _get_records "$_account_id" "$_domain" "$_sub_domain" if [ "$_records_count" = "0" ]; then _info "Adding record" @@ -53,14 +53,17 @@ dns_dnsimple_add() { _err "Add txt record error." else _info "Updating record" - _extract_record_id $_records $_sub_domain + _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 - _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$_record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" - if [ "$?" = "0" ]; then _info "Updated!" - #todo: check if the record takes effect return 0 fi + _err "Update error" return 1 fi @@ -80,13 +83,12 @@ dns_dnsimple_rm() { return 1 fi - _get_records $_account_id $_domain $_sub_domain - _extract_record_id $_records $_sub_domain + _get_records "$_account_id" "$_domain" "$_sub_domain" + _extract_record_id "$_records" "$_sub_domain" if [ "$_record_id" ]; then - _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id" - if [ "$?" = "0" ]; then + if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then _info "removed record" "$_record_id" return 0 fi @@ -193,8 +195,9 @@ _dnsimple_rest() { request_url="$DNSimple_API/$path" _debug "$path" - _H1="Accept: application/json" - _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + export _H1="Accept: application/json" + export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + if [ "$data" ]; then _H1="Content-Type: application/json" _debug data "$data" From 5b21cbe0de81f858e29a5abf3e3c0c35ae6a18d3 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 1 May 2017 20:56:04 -0500 Subject: [PATCH 0934/1348] Revert "provide a more general purpose request function" This reverts commit aa86652db8d3132fb7fe0c0253dded7deb7dce2c. This is not actually necessary and can be accomplished with the post function. --- acme.sh | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/acme.sh b/acme.sh index 3ccd8dc4..7ce947ea 100755 --- a/acme.sh +++ b/acme.sh @@ -1592,17 +1592,12 @@ _post() { return $_ret } -_get() { - _request "$1" "$2" "$3" GET -} - # url getheader timeout -_request() { +_get() { + _debug GET url="$1" onlyheader="$2" t="$3" - method="$4" - _debug method $method _debug url "$url" _debug "timeout" "$t" @@ -1616,9 +1611,6 @@ _request() { if [ "$t" ]; then _CURL="$_CURL --connect-timeout $t" fi - if [ "$method" ]; then - _CURL="$_CURL -X $method" - fi _debug "_CURL" "$_CURL" if [ "$onlyheader" ]; then $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" @@ -1641,9 +1633,6 @@ _request() { if [ "$t" ]; then _WGET="$_WGET --timeout=$t" fi - if [ "$method" ]; then - _WGET="$_WGET --method=$method" - fi _debug "_WGET" "$_WGET" if [ "$onlyheader" ]; then $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' From 533238712536e3a11c2b09b4d0d480891cfd3d9f Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Tue, 2 May 2017 08:51:43 -0500 Subject: [PATCH 0935/1348] Use _post to send a DELETE request for DNSimple record removal. --- dnsapi/dns_dnsimple.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index d92c6137..0bfe2b99 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -198,12 +198,12 @@ _dnsimple_rest() { export _H1="Accept: application/json" export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" - if [ "$data" ]; then + if [ "$data" ] || [ "$method" = "DELETE" ]; then _H1="Content-Type: application/json" _debug data "$data" response="$(_post "$data" "$request_url" "" "$method")" else - response="$(_request "$request_url" "" "" "$method")" + response="$(_get "$request_url" "" "" "$method")" fi if [ "$?" != "0" ]; then From 4c38fec3b57e23d5aece5dfd92ac1f50abc6b150 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 3 May 2017 23:07:30 +0800 Subject: [PATCH 0936/1348] update doc --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 34b9243a..0cb800eb 100644 --- a/README.md +++ b/README.md @@ -136,13 +136,25 @@ root@v1:~# acme.sh -h 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. ```bash 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. You must have at least one domain there. From cc1d3b20b60a9f729bbd0f61f6563d2fe34772d4 Mon Sep 17 00:00:00 2001 From: wizard1024 Date: Fri, 5 May 2017 14:55:51 +0300 Subject: [PATCH 0937/1348] Update dns_aws.sh to work only with public zones --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 21e86686..800c3d09 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -106,7 +106,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" + hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*false<.PrivateZone>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." From 5e3a5f627a94efea26d18d7eebb022a99a6149dd Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 8 May 2017 15:51:01 +0200 Subject: [PATCH 0938/1348] last but not least --- README.md | 1 + dnsapi/README.md | 11 +++ dnsapi/dns_nsone.sh | 158 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 dnsapi/dns_nsone.sh diff --git a/README.md b/README.md index 0cb800eb..b816ec7f 100644 --- a/README.md +++ b/README.md @@ -329,6 +329,7 @@ You don't have to do anything manually! 1. Infoblox NIOS API (https://www.infoblox.com/) 1. VSCALE (https://vscale.io/) 1. Dynu API (https://www.dynu.com) +1. NS1.com API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index f53d8ad4..dff62399 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -494,6 +494,17 @@ be reused when needed. If you have any issues with this integration please report them to https://github.com/pho3nixf1re/acme.sh/issues. +## 26. Use NS1.com API + +``` +export NS1_Key="fdmlfsdklmfdkmqsdfk" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_nsone -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh new file mode 100644 index 00000000..48e4397f --- /dev/null +++ b/dnsapi/dns_nsone.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +# bug reports to dev@1e.ca + +# +#NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# + +NS1_Api="https://api.nsone.net/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nsone_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$NS1_Key" ]; then + NS1_Key="" + _err "You didn't specify nsone dns api key yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf NS1_Key "$NS1_Key" + + _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" + _nsone_rest GET "zones/${_domain}" + + if ! _contains "$response" "\"records\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Adding record" + + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then + if _contains "$response" "$fulldomain"; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1) + _debug "record_id" "$record_id" + + _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" + if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi + +} + +#fulldomain +dns_nsone_rm() { + fulldomain=$1 + txtvalue=$2 + _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" + _nsone_rest GET "zones/${_domain}/$fulldomain/TXT" + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "" + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + if ! _nsone_rest GET "zones"; then + return 1 + fi + 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" "\"zone\":\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_nsone_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Accept: application/json" + export _H2="X-NSONE-Key: $NS1_Key" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NS1_Api/$ep" "" "$m")" + else + response="$(_get "$NS1_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From dff641a665bffab928ebf0121ff15e86a608de96 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 8 May 2017 16:07:45 +0200 Subject: [PATCH 0939/1348] I can do it... just discovered vmdiff --- README.md | 1 - dnsapi/README.md | 5 +---- dnsapi/dns_nsone.sh | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index a67a9061..b816ec7f 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,6 @@ You don't have to do anything manually! 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API 1. Knot DNS API -1. NS1.com API 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) diff --git a/dnsapi/README.md b/dnsapi/README.md index 25ba1c34..dff62399 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -494,8 +494,7 @@ be reused when needed. If you have any issues with this integration please report them to https://github.com/pho3nixf1re/acme.sh/issues. -<<<<<<< HEAD -## 28. Use NS1.com API +## 26. Use NS1.com API ``` export NS1_Key="fdmlfsdklmfdkmqsdfk" @@ -505,8 +504,6 @@ Ok, let's issue a cert now: ``` acme.sh --issue --dns dns_nsone -d example.com -d www.example.com ``` -======= ->>>>>>> 9201e0a5b905812da1157efa075dd1ab52362c09 # Use custom API diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index ced65ac0..0f6e441a 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -1,6 +1,4 @@ -<<<<<<< HEAD #!/usr/bin/env sh ->>>>>>> 9201e0a5b905812da1157efa075dd1ab52362c09 # bug reports to dev@1e.ca From 9bc5f686ebb7e866bb8d0bf7299989d86a1c8d63 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 8 May 2017 22:25:06 +0800 Subject: [PATCH 0940/1348] fix list order --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b816ec7f..7e6b1227 100644 --- a/README.md +++ b/README.md @@ -304,17 +304,14 @@ You don't have to do anything manually! 1. CloudFlare.com API 1. DNSPod.cn API -1. DNSimple API 1. CloudXNS.com API 1. GoDaddy.com API -1. OVH, kimsufi, soyoustart and runabove API -1. AWS Route 53 1. PowerDNS.com API -1. 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.) +1. OVH, kimsufi, soyoustart and runabove API +1. nsupdate API 1. LuaDNS.com API 1. DNSMadeEasy.com API -1. nsupdate API +1. AWS Route 53 1. aliyun.com(阿里云) API 1. ISPConfig 3.1 API 1. Alwaysdata.com API @@ -329,9 +326,18 @@ You don't have to do anything manually! 1. Infoblox NIOS API (https://www.infoblox.com/) 1. VSCALE (https://vscale.io/) 1. Dynu API (https://www.dynu.com) +1. DNSimple API 1. NS1.com API + +And: + +1. 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.) + + + **More APIs coming soon...** If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project. From 5da1d3b73bdbec8fb5db9283d2755106c23847e0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 8 May 2017 22:55:21 +0800 Subject: [PATCH 0941/1348] minor fix format --- dnsapi/dns_nsone.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 0f6e441a..7af0f81d 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -45,7 +45,7 @@ dns_nsone_add() { _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" - + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then if _contains "$response" "$fulldomain"; then _info "Added" @@ -124,9 +124,9 @@ _get_root() { fi if _contains "$response" "\"zone\":\"$h\""; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$h" - return 0 + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 fi p=$i i=$(_math "$i" + 1) From a20707cd731f98b820f56dbd92bad0477c91ea1c Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 8 May 2017 22:57:23 +0800 Subject: [PATCH 0942/1348] fix format --- dnsapi/dns_nsone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 7af0f81d..adf1f422 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -45,7 +45,7 @@ dns_nsone_add() { _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" - + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then if _contains "$response" "$fulldomain"; then _info "Added" From 0f48b15695d5c04e98e6a36d7c59dcc47ebe1666 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 9 May 2017 13:33:54 +0800 Subject: [PATCH 0943/1348] update doc --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7e6b1227..a163f233 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ - Just one script to issue, renew and install your certificates automatically. - DOES NOT require `root/sudoer` access. - Docker friendly +- IPv6 support It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. From c487cd6af2067bbfee9d66465503cdac9bbbb102 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 11 May 2017 20:51:16 +0800 Subject: [PATCH 0944/1348] add VOLUME --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index feb89b0d..3b262615 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,5 +55,7 @@ else \n \ /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ fi" >/entry.sh && chmod +x /entry.sh +VOLUME /acme.sh + ENTRYPOINT ["/entry.sh"] CMD ["--help"] From d61ef6b49ae442b93b36aba67ba6037a0a5948d1 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 12 May 2017 11:27:06 +0800 Subject: [PATCH 0945/1348] gandi dns api updated. --- dnsapi/dns_gandi_livedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 28b8f99d..82ed599c 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -37,7 +37,7 @@ dns_gandi_livedns_add() { _debug sub_domain "$_sub_domain" _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ - && _contains "$response" '{"message": "Zone Record Created"}' \ + && _contains "$response" '{"message": "DNS Record Created"}' \ && _info "Add $(__green "success")" } From 319d49ddbe81a7d72009f203e1a56f1c6e614742 Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Fri, 12 May 2017 05:37:15 +0000 Subject: [PATCH 0946/1348] Add Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a163f233..afdda8a8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) + +[![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. - Simple, powerful and very easy to use. You only need 3 minutes to learn it. From df037db0bb804eb05352974b66dfd564fff7608c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 14 May 2017 10:15:40 +0800 Subject: [PATCH 0947/1348] clean cache --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3b262615..4cb33139 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,17 +4,17 @@ RUN apk update -f \ && apk --no-cache add -f \ openssl \ curl \ - netcat-openbsd + netcat-openbsd \ + && rm -rf /var/cache/apk/* 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 cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ + RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh From 2844d73dc752138c48c7ec05a93869d931782ff5 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 15 May 2017 20:46:02 +0800 Subject: [PATCH 0948/1348] fix https://github.com/Neilpang/acme.sh/issues/844 --- acme.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 7ce947ea..77be3fd5 100755 --- a/acme.sh +++ b/acme.sh @@ -1244,17 +1244,20 @@ createDomainKey() { fi domain=$1 - length=$2 + _cdl=$2 - if [ -z "$length" ]; then + if [ -z "$_cdl" ]; then _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH" - length="$DEFAULT_DOMAIN_KEY_LENGTH" + _cdl="$DEFAULT_DOMAIN_KEY_LENGTH" fi - _initpath "$domain" "$length" + _initpath "$domain" "$_cdl" if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then - _createkey "$length" "$CERT_KEY_PATH" + if _createkey "$_cdl" "$CERT_KEY_PATH"; then + _savedomainconf Le_Keylength "$_cdl" + _info "The domain key is here: $(__green $CERT_KEY_PATH)" + fi else if [ "$IS_RENEW" ]; then _info "Domain key exists, skip" From b420ec6cb96f625e400fccfe60c3ad6256f03c32 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 17 May 2017 13:16:53 +0800 Subject: [PATCH 0949/1348] fix for performance of _h2b() function --- acme.sh | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 77be3fd5..8edf2c61 100755 --- a/acme.sh +++ b/acme.sh @@ -444,19 +444,27 @@ if [ "$(printf '\x41')" != 'A' ]; then fi _h2b() { + if _exists xxd; then + xxd -r -p + return + fi + hex=$(cat) i=1 j=2 - - _debug3 _URGLY_PRINTF "$_URGLY_PRINTF" - while true; do - if [ -z "$_URGLY_PRINTF" ]; then + _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" + if [ -z "$_URGLY_PRINTF" ]; then + while true; do h="$(printf "%s" "$hex" | cut -c $i-$j)" if [ -z "$h" ]; then break fi printf "\x$h%s" - else + i="$(_math "$i" + 2)" + j="$(_math "$j" + 2)" + done + else + while true; do ic="$(printf "%s" "$hex" | cut -c $i)" jc="$(printf "%s" "$hex" | cut -c $j)" if [ -z "$ic$jc" ]; then @@ -465,12 +473,11 @@ _h2b() { ic="$(_h_char_2_dec "$ic")" jc="$(_h_char_2_dec "$jc")" printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" - fi - - i="$(_math "$i" + 2)" - j="$(_math "$j" + 2)" + i="$(_math "$i" + 2)" + j="$(_math "$j" + 2)" + done + fi - done } _is_solaris() { From fa93d68b085dd5cef9f09fba8de665b31d0a5665 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 20 May 2017 11:02:48 +0800 Subject: [PATCH 0950/1348] promote performance --- acme.sh | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index 8edf2c61..17062806 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.9 +VER=2.7.0 PROJECT_NAME="acme.sh" @@ -450,31 +450,35 @@ _h2b() { fi hex=$(cat) - i=1 - j=2 + ic="" + jc="" _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" if [ -z "$_URGLY_PRINTF" ]; then - while true; do - h="$(printf "%s" "$hex" | cut -c $i-$j)" - if [ -z "$h" ]; then - break - fi - printf "\x$h%s" - i="$(_math "$i" + 2)" - j="$(_math "$j" + 2)" - done + if _exists xargs; then + _debug2 "xargs" + echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf + else + for h in $(echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/ \1/gI') + do + if [ -z "$h" ]; then + break + fi + printf "\x$h%s" + done + fi else - while true; do - ic="$(printf "%s" "$hex" | cut -c $i)" - jc="$(printf "%s" "$hex" | cut -c $j)" - if [ -z "$ic$jc" ]; then - break + for c in $(echo "$hex" | sed 's/\([0-9A-F]\)/ \1/gI') + do + if [ -z "$ic" ]; then + ic=$c + continue fi + jc=$c ic="$(_h_char_2_dec "$ic")" jc="$(_h_char_2_dec "$jc")" printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" - i="$(_math "$i" + 2)" - j="$(_math "$j" + 2)" + ic="" + jc="" done fi From ed3dda7da960072f48370a25dd5beaccb7302cf2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 20 May 2017 11:15:26 +0800 Subject: [PATCH 0951/1348] fix format --- acme.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 17062806..f255c43f 100755 --- a/acme.sh +++ b/acme.sh @@ -458,8 +458,7 @@ _h2b() { _debug2 "xargs" echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf else - for h in $(echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/ \1/gI') - do + for h in $(echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/ \1/gI'); do if [ -z "$h" ]; then break fi @@ -467,8 +466,7 @@ _h2b() { done fi else - for c in $(echo "$hex" | sed 's/\([0-9A-F]\)/ \1/gI') - do + for c in $(echo "$hex" | sed 's/\([0-9A-F]\)/ \1/gI'); do if [ -z "$ic" ]; then ic=$c continue From 486e77f474d1da05bc9201a7446b12dc4abc38b4 Mon Sep 17 00:00:00 2001 From: Jean-Tiare Le Bigot Date: Mon, 22 May 2017 14:13:39 +0200 Subject: [PATCH 0952/1348] Support OVH credentials scoped to a specific zone When creating OVH API credentials, one can scope them to a specific subset of routes. Specifically, this allows to limit acme.sh to a specific zone as the zone is part of the URL. This is an important security/safety net feature. --- dnsapi/dns_ovh.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 6c1edb4d..eaa90bdf 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -238,7 +238,7 @@ _get_root() { return 1 fi - if ! _contains "$response" "This service does not exist" >/dev/null; then + if ! _contains "$response" "This service does not exist" >/dev/null && ! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" return 0 From 7eea9533e895f405d2fbbbb110a42d8f74967127 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 22 May 2017 14:53:26 -0500 Subject: [PATCH 0953/1348] Update README.md Fix usage documentation for dns_nsupdate. The NSUPDATE_KEY env needs to be a path to a file. --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index dff62399..5dca829a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -140,7 +140,7 @@ Finally, make the DNS server and update Key available to `acme.sh` ``` export NSUPDATE_SERVER="dns.example.com" -export NSUPDATE_KEY="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==" +export NSUPDATE_KEY="/path/to/your/nsupdate.key" ``` Ok, let's issue a cert now: From aa66dfff57b17e1fe1d37f1389be5a768a85116e Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 25 May 2017 21:06:59 +0800 Subject: [PATCH 0954/1348] fix doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index afdda8a8..8ddadf57 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) |19|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux |20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX -For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): +For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest): https://github.com/Neilpang/acmetest From ded4469efe8a61e94d4878c80420cac414c4e6d2 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 26 May 2017 14:58:52 +0800 Subject: [PATCH 0955/1348] fix for openbsd, sed doesn't support `I` option. --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index f255c43f..737d6a7c 100755 --- a/acme.sh +++ b/acme.sh @@ -456,9 +456,9 @@ _h2b() { if [ -z "$_URGLY_PRINTF" ]; then if _exists xargs; then _debug2 "xargs" - echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf + echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf else - for h in $(echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/ \1/gI'); do + for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do if [ -z "$h" ]; then break fi @@ -466,7 +466,7 @@ _h2b() { done fi else - for c in $(echo "$hex" | sed 's/\([0-9A-F]\)/ \1/gI'); do + for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do if [ -z "$ic" ]; then ic=$c continue From 6185244754718adbe99e564886a443f803a31583 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 27 May 2017 19:28:12 +0800 Subject: [PATCH 0956/1348] fix doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ddadf57..13188982 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,7 @@ The ownership and permission info of existing files are preserved. You may want Install/copy the issued cert/key to the production Apache or Nginx path. -The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the Apache/Nginx service will be restarted automatically by the command: `service apache2 restart` or `service nginx restart`. +The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`. # 4. Use Standalone server to issue cert From f8bcfeb2ab7b1c4486309b673b557c4ad2ea5df7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 29 May 2017 17:07:59 +0800 Subject: [PATCH 0957/1348] fix xargs issue for freebsd https://github.com/Neilpang/acme.sh/issues/865#issuecomment-304599955 --- acme.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 737d6a7c..60f0fd48 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.0 +VER=2.7.1 PROJECT_NAME="acme.sh" @@ -443,6 +443,11 @@ if [ "$(printf '\x41')" != 'A' ]; then _URGLY_PRINTF=1 fi +_ESCAPE_XARGS="" +if [ "$(printf %s '\\x41' | xargs printf)" == 'A' ]; then + _ESCAPE_XARGS=1 +fi + _h2b() { if _exists xxd; then xxd -r -p @@ -454,7 +459,7 @@ _h2b() { jc="" _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" if [ -z "$_URGLY_PRINTF" ]; then - if _exists xargs; then + if [ "$_ESCAPE_XARGS" ] && _exists xargs; then _debug2 "xargs" echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf else From 8a420dd853667db64ca1ac4e6618fd5040c5e89d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 29 May 2017 17:17:14 +0800 Subject: [PATCH 0958/1348] fix https://github.com/Neilpang/acme.sh/issues/865#issuecomment-304599955 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 60f0fd48..5f500045 100755 --- a/acme.sh +++ b/acme.sh @@ -444,7 +444,7 @@ if [ "$(printf '\x41')" != 'A' ]; then fi _ESCAPE_XARGS="" -if [ "$(printf %s '\\x41' | xargs printf)" == 'A' ]; then +if [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then _ESCAPE_XARGS=1 fi From df711b0ea2a4ee2737392d68bf7df815f47cc737 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Jun 2017 22:04:43 +0800 Subject: [PATCH 0959/1348] minor, add debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5f500045..4261d322 100755 --- a/acme.sh +++ b/acme.sh @@ -2579,7 +2579,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { _err "write nginx conf error, but don't worry, the file is restored." return 1 fi - + _debug3 "Modified config:$(cat $FOUND_REAL_NGINX_CONF)" _info "nginx conf is done, let's check it again." if ! _exec "nginx -t" >/dev/null; then _exec_err From 674790a511803c062c64dcc6999f378f9939fd37 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Jun 2017 22:14:58 +0800 Subject: [PATCH 0960/1348] add more detect for nginx mode --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4261d322..64bcf844 100755 --- a/acme.sh +++ b/acme.sh @@ -2665,7 +2665,8 @@ _isRealNginxConf() { _debug "_seg_n" "$_seg_n" - if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ]; then + if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] + || [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then _debug "ssl on, skip" return 1 fi From 7c67e3d7e231cc80ed6f5b86618ebc9db17da21a Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Jun 2017 22:18:03 +0800 Subject: [PATCH 0961/1348] fix typo --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 64bcf844..437706d3 100755 --- a/acme.sh +++ b/acme.sh @@ -2665,7 +2665,7 @@ _isRealNginxConf() { _debug "_seg_n" "$_seg_n" - if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] + if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] \ || [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then _debug "ssl on, skip" return 1 From 241cfc4342177e8ebd3bedcd842f09ebc4783400 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Jun 2017 22:29:21 +0800 Subject: [PATCH 0962/1348] fix nginx mode issue for multiple entries --- acme.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 437706d3..efe68c18 100755 --- a/acme.sh +++ b/acme.sh @@ -2668,10 +2668,11 @@ _isRealNginxConf() { if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] \ || [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then _debug "ssl on, skip" - return 1 - fi - FOUND_REAL_NGINX_CONF_LN=$_fln - return 0 + else + FOUND_REAL_NGINX_CONF_LN=$_fln + _debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN" + return 0 + fi fi done fi From 450efea191cc177cfaea01b4c50ce5fdef0fc2a0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Jun 2017 22:55:16 +0800 Subject: [PATCH 0963/1348] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index efe68c18..ffbc69b5 100755 --- a/acme.sh +++ b/acme.sh @@ -2672,7 +2672,7 @@ _isRealNginxConf() { FOUND_REAL_NGINX_CONF_LN=$_fln _debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN" return 0 - fi + fi fi done fi From 8e845d9f2196a43c4423aa9e6419ad87d8072ded Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 6 Jun 2017 10:08:09 +0800 Subject: [PATCH 0964/1348] make install command respect LE_CONFIG_HOME env --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index ffbc69b5..2e069244 100755 --- a/acme.sh +++ b/acme.sh @@ -4640,6 +4640,11 @@ install() { return 1 fi + if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then + _info "Using config home: $LE_CONFIG_HOME" + _c_home="$LE_CONFIG_HOME" + fi + #convert from le if [ -d "$HOME/.le" ]; then for envfile in "le.env" "le.sh.env"; do From 0b52645bb6afad03cb3c5fcab57e160ecadbf41b Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Thu, 8 Jun 2017 13:32:05 +0200 Subject: [PATCH 0965/1348] added view variable to infoblox integration script --- dnsapi/dns_infoblox.sh | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 3846e62e..7bb0b5a4 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/bin/bash ## Infoblox API integration by Jason Keller and Elijah Tenai ## @@ -9,7 +9,7 @@ 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" + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View" _info "Using Infoblox API" _debug fulldomain "$fulldomain" @@ -19,11 +19,15 @@ dns_infoblox_add() { 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." + _err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)." + _err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again." return 1 fi + if [ -z "$Infoblox_View" ]; then + Infoblox_View="default" + fi + ## Save the credentials to the account file _saveaccountconf Infoblox_Creds "$Infoblox_Creds" _saveaccountconf Infoblox_Server "$Infoblox_Server" @@ -39,7 +43,7 @@ dns_infoblox_add() { result=$(_post "" "$baseurlnObject" "" "POST") ## Let's see if we get something intelligible back from the unit - if echo "$result" | egrep 'record:txt/.*:.*/default'; then + if echo "$result" | egrep "record:txt/.*:.*/${Infoblox_View}"; then _info "Successfully created the txt record" return 0 else @@ -68,18 +72,18 @@ dns_infoblox_rm() { 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" + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_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') + objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_View}") 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 + if echo "$rmResult" | egrep "record:txt/.*:.*/${Infoblox_View}"; then _info "Successfully deleted $objRef" return 0 else @@ -94,4 +98,4 @@ dns_infoblox_rm() { fi } -#################### Private functions below ################################## +#################### Private functions below ################################## \ No newline at end of file From 0bd4a4f98fcb8c1b8816e2b8a90322e826aa2050 Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Thu, 8 Jun 2017 13:34:29 +0200 Subject: [PATCH 0966/1348] formated for sh instead of bash --- dnsapi/dns_infoblox.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 7bb0b5a4..a88b4c02 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/env sh ## Infoblox API integration by Jason Keller and Elijah Tenai ## @@ -43,7 +43,7 @@ dns_infoblox_add() { result=$(_post "" "$baseurlnObject" "" "POST") ## Let's see if we get something intelligible back from the unit - if echo "$result" | egrep "record:txt/.*:.*/${Infoblox_View}"; then + if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then _info "Successfully created the txt record" return 0 else @@ -78,12 +78,12 @@ dns_infoblox_rm() { ## 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/.*:.*/${Infoblox_View}") + objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View") 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/.*:.*/${Infoblox_View}"; then + if echo "$rmResult" | egrep "record:txt/.*:.*/$Infoblox_View"; then _info "Successfully deleted $objRef" return 0 else From b6f00ea241b7d42eedbafb9e5b208465b5b7572a Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Thu, 8 Jun 2017 13:35:27 +0200 Subject: [PATCH 0967/1348] changed path to env --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index a88b4c02..5a00bfd4 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,4 +1,4 @@ -#!/bin/env sh +#!/usr/bin/env sh ## Infoblox API integration by Jason Keller and Elijah Tenai ## From eef4acd07d5dcad20e5bbf9335dc556969a7c156 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Jun 2017 23:25:20 +0800 Subject: [PATCH 0968/1348] fix https://github.com/Neilpang/acme.sh/issues/874 --- dnsapi/dns_dynu.sh | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index f6eabde2..17a1cdb0 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -122,18 +122,30 @@ dns_dynu_rm() { # _domain_name=domain.com _get_root() { domain=$1 - if ! _dynu_rest GET "dns/getroot/$domain"; then - return 1 - fi + 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" "domain_name"; then - _debug "Domain name not found." - return 1 - fi + if ! _dynu_rest GET "dns/get/$h"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_name=$h + _node=$(printf "%s" "$domain" | cut -d . -f 1-$p) + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 - _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() { From 3b74ac841ec8b8cd6ffbcc1c0b1c314f4010b9a4 Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Wed, 14 Jun 2017 23:52:48 +0200 Subject: [PATCH 0969/1348] save Infoblox_View to account config --- dnsapi/dns_infoblox.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 5a00bfd4..78c49767 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -31,6 +31,7 @@ dns_infoblox_add() { ## Save the credentials to the account file _saveaccountconf Infoblox_Creds "$Infoblox_Creds" _saveaccountconf Infoblox_Server "$Infoblox_Server" + _saveaccountconf Infoblox_View "$Infoblox_View" ## Base64 encode the credentials Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) From b73f5a4e94704fa80f1240ab9a61ed81838cfc60 Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Thu, 15 Jun 2017 00:16:26 +0200 Subject: [PATCH 0970/1348] missed one egrep command --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 78c49767..da274bdb 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -77,7 +77,7 @@ dns_infoblox_rm() { result=$(_get "$baseurlnObject") ## Let's see if we get something intelligible back from the grid - if echo "$result" | egrep 'record:txt/.*:.*/default'; then + if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then ## Extract the object reference objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View") objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" From 65b22b493cc55f6969d56886c372f92fb1268ff2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Jun 2017 21:26:14 +0800 Subject: [PATCH 0971/1348] minor, debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ffbc69b5..8b31f9ac 100755 --- a/acme.sh +++ b/acme.sh @@ -2723,7 +2723,7 @@ _clearup() { _clearupdns() { _debug "_clearupdns" if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then - _debug "Dns not added, skip." + _debug "skip dns." return fi From 326c386b2e9675e2719e9e1ee45d0d436640d4e5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Jun 2017 21:44:10 +0800 Subject: [PATCH 0972/1348] add debug message --- acme.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/acme.sh b/acme.sh index f36ea2ed..d57aacc6 100755 --- a/acme.sh +++ b/acme.sh @@ -151,6 +151,13 @@ _dlg_versions() { echo "apache doesn't exists." fi + echo "nginx:" + if _exists "nginx"; then + nginx -V 2>&1 + else + echo "nginx doesn't exists." + fi + echo "nc:" if _exists "nc"; then nc -h 2>&1 From f3dc5dd12fbe4b369595a90a8a048d23158f3cc4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 16 Jun 2017 21:45:14 +0800 Subject: [PATCH 0973/1348] fix https://github.com/Neilpang/acme.sh/issues/881#issuecomment-309026385 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d57aacc6..ad700667 100755 --- a/acme.sh +++ b/acme.sh @@ -1733,7 +1733,7 @@ _send_signed_request() { nonce="$_CACHED_NONCE" _debug2 nonce "$nonce" - protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" From fcc0aef7f4b9da6a0cccda482b7a94a8cb3e3836 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 16 Jun 2017 22:41:33 +0800 Subject: [PATCH 0974/1348] start 2.7.2 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ad700667..84de9824 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.1 +VER=2.7.2 PROJECT_NAME="acme.sh" From 2a188905daa83d645ddba3ec6034231e7e51941a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:49:45 +0800 Subject: [PATCH 0975/1348] support `--server` --- acme.sh | 104 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index 84de9824..70381336 100755 --- a/acme.sh +++ b/acme.sh @@ -13,7 +13,8 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" -DEFAULT_CA="https://acme-v01.api.letsencrypt.org" +_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" +DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" @@ -24,7 +25,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" -STAGE_CA="https://acme-staging.api.letsencrypt.org" +STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -1714,8 +1715,8 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce." - nonceurl="$API/directory" + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" _headers="$(_get "$nonceurl" "onlyheader")" if [ "$?" != "0" ]; then @@ -2169,6 +2170,53 @@ __initHome() { fi } +#server +_initAPI() { + _api_server="${1:-$ACME_DIRECTORY}" + _debug "_init api for server: $_api_server" + + if [ "$_api_server" = "$DEFAULT_CA" ]; then + #just for performance, hardcode the default entry points + export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" + export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" + export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" + fi + + if [ -z "$ACME_KEY_CHANGE" ]; then + response=$(_get "$_api_server") + if [ "$?" != "0" ]; then + _debug2 "response" "$response" + _err "Can not init api." + return 1 + fi + _debug2 "response" "$response" + + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_KEY_CHANGE + + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_AUTHZ + + ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_CERT + + ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_REG + + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_REVOKE_CERT + + fi + + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" + _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" + _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" + _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" +} + #[domain] [keylength] _initpath() { @@ -2189,17 +2237,19 @@ _initpath() { CA_HOME="$DEFAULT_CA_HOME" fi - if [ -z "$API" ]; then + if [ -z "$ACME_DIRECTORY" ]; then if [ -z "$STAGE" ]; then - API="$DEFAULT_CA" + ACME_DIRECTORY="$DEFAULT_CA" else - API="$STAGE_CA" - _info "Using stage api:$API" + ACME_DIRECTORY="$STAGE_CA" + _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" fi fi - _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')" - CA_DIR="$CA_HOME/$_API_HOST" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" + + CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" _DEFAULT_CA_CONF="$CA_DIR/ca.conf" @@ -3020,7 +3070,7 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - + _initAPI _updateTos="" _reg_res="new-reg" while true; do @@ -3035,7 +3085,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3126,7 +3176,7 @@ __get_domain_new_authz() { _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do _debug "Try new-authz for the $_authz_i time." - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then + if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then _err "Can not get domain new authz." return 1 fi @@ -3204,13 +3254,16 @@ issue() { if [ "$_web_roots" = "dns-cx" ]; then _web_roots="dns_cx" fi - _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then _initpath "$_main_domain" "$_key_length" mkdir -p "$DOMAIN_PATH" fi + _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" + + _initAPI + if [ -f "$DOMAIN_CONF" ]; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" @@ -3244,7 +3297,7 @@ issue() { _cleardomainconf "Le_LocalAddress" fi - Le_API="$API" + Le_API="$ACME_DIRECTORY" _savedomainconf "Le_API" "$Le_API" if [ "$_alt_domains" = "$NO_VALUE" ]; then @@ -3683,7 +3736,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 @@ -3736,7 +3789,8 @@ issue() { Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') if ! _contains "$Le_LinkIssuer" ":"; then - Le_LinkIssuer="$API$Le_LinkIssuer" + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" fi _debug Le_LinkIssuer "$Le_LinkIssuer" _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" @@ -3852,7 +3906,11 @@ renew() { . "$DOMAIN_CONF" if [ "$Le_API" ]; then - API="$Le_API" + if [ "$_OLD_CA_HOST" = "$Le_API" ]; then + export Le_API="$DEFAULT_CA" + _savedomainconf Le_API "$Le_API" + fi + export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" ACCOUNT_JSON_PATH="" @@ -4315,8 +4373,10 @@ revoke() { return 1 fi + _initAPI + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" - uri="$API/acme/revoke-cert" + uri="${ACME_REVOKE_CERT}" if [ -f "$CERT_KEY_PATH" ]; then _info "Try domain key first." @@ -4875,6 +4935,7 @@ Parameters: --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. + --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 . --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. @@ -5150,6 +5211,11 @@ _process() { --staging | --test) STAGE="1" ;; + --server) + ACME_DIRECTORY="$2" + export ACME_DIRECTORY + shift + ;; --debug) if [ -z "$2" ] || _startswith "$2" "-"; then DEBUG="$DEBUG_LEVEL_DEFAULT" From f8c1d97a258f8c8769facee5432a78cfc4dabefb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:59:27 +0800 Subject: [PATCH 0976/1348] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 70381336..2c2130d5 100755 --- a/acme.sh +++ b/acme.sh @@ -2174,7 +2174,7 @@ __initHome() { _initAPI() { _api_server="${1:-$ACME_DIRECTORY}" _debug "_init api for server: $_api_server" - + if [ "$_api_server" = "$DEFAULT_CA" ]; then #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" From 287623df58d0603056e560a7c046585237dfe249 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:20:32 +0800 Subject: [PATCH 0977/1348] fix for deactivate function --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2c2130d5..e1e66d85 100755 --- a/acme.sh +++ b/acme.sh @@ -3171,7 +3171,7 @@ _findHook() { __get_domain_new_authz() { _gdnd="$1" _info "Getting new-authz for domain" "$_gdnd" - + _initAPI _Max_new_authz_retry_times=5 _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do From cbb74c984fa52d44137cf9f62421e4422312c991 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:30:04 +0800 Subject: [PATCH 0978/1348] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index e1e66d85..27d1cc49 100755 --- a/acme.sh +++ b/acme.sh @@ -4508,6 +4508,7 @@ deactivate() { _d_domain_list="$1" _d_type="$2" _initpath + _initAPI _debug _d_domain_list "$_d_domain_list" if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" From ce59fc6c102ec113921c1a20b81a487316e2db79 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 17:15:37 +0800 Subject: [PATCH 0979/1348] fix renew for stage cert --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 27d1cc49..d2c8cf24 100755 --- a/acme.sh +++ b/acme.sh @@ -26,6 +26,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" +_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -3910,6 +3911,10 @@ renew() { export Le_API="$DEFAULT_CA" _savedomainconf Le_API "$Le_API" fi + if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then + export Le_API="$STAGE_CA" + _savedomainconf Le_API "$Le_API" + fi export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" From 0a301cdd21f37a1b22da6c5709d82c3b526703e8 Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Sat, 17 Jun 2017 11:28:49 +0200 Subject: [PATCH 0980/1348] added new line at the end of the file --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index da274bdb..06ac87ec 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -99,4 +99,4 @@ dns_infoblox_rm() { fi } -#################### Private functions below ################################## \ No newline at end of file +#################### Private functions below ################################## From 395fbbfd14737e7a70322ff0c1e3fe8d0e2161cf Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 20:49:45 +0800 Subject: [PATCH 0981/1348] fix cron --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4cb33139..5254bd11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,7 @@ RUN for verb in help \ RUN printf "%b" '#!'"/usr/bin/env sh\n \ if [ \"\$1\" = \"daemon\" ]; then \n \ - crond; tail -f /dev/null;\n \ + crond -f\n \ else \n \ /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ fi" >/entry.sh && chmod +x /entry.sh From b9a972bccd0935b4042db950cb4f86bbd07afec4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Jun 2017 09:52:59 +0800 Subject: [PATCH 0982/1348] fix openssl 1.1.0 for https://github.com/Neilpang/acme.sh/issues/888 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 84de9824..e79680c0 100755 --- a/acme.sh +++ b/acme.sh @@ -1093,7 +1093,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - ${ACME_OPENSSL_BIN:-openssl} 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 | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n' } #_csrfile From b963dadc14579609671793b4aa348433a5d345fd Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Jun 2017 10:07:23 +0800 Subject: [PATCH 0983/1348] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e79680c0..8c067fd2 100755 --- a/acme.sh +++ b/acme.sh @@ -1093,7 +1093,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n' + ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n' } #_csrfile From 2c9ed4c565c90833e38fc838a14455c8da8f55f8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Jun 2017 10:18:20 +0800 Subject: [PATCH 0984/1348] check invalid subject cn in the csr fix https://github.com/Neilpang/acme.sh/issues/805 --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 8c067fd2..9ff8001f 100755 --- a/acme.sh +++ b/acme.sh @@ -3940,6 +3940,10 @@ signcsr() { return 1 fi _debug _csrsubj "$_csrsubj" + if _contains "$_csrsubj" ' ' || ! _contains "$_csrsubj" '.'; then + _info "It seems that the subject: $_csrsubj is not a valid domain name. Drop it." + _csrsubj="" + fi _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") if [ "$?" != "0" ]; then From 08b4e1a744000db29a0014de86684701602575c1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Jun 2017 22:13:33 +0800 Subject: [PATCH 0985/1348] add ACME_NO_COLOR and `--no-color` not to ouput color text --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 1ddec824..f20d935f 100755 --- a/acme.sh +++ b/acme.sh @@ -104,21 +104,21 @@ if [ -t 1 ]; then fi __green() { - if [ "$__INTERACTIVE" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then printf '\033[1;31;32m' fi printf -- "%b" "$1" - if [ "$__INTERACTIVE" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then printf '\033[0m' fi } __red() { - if [ "$__INTERACTIVE" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then printf '\033[1;31;40m' fi printf -- "%b" "$1" - if [ "$__INTERACTIVE" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then printf '\033[0m' fi } @@ -4896,6 +4896,7 @@ Parameters: --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. + --no-color Do not output color text. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. --pre-hook Command to be run before obtaining any certificates. @@ -5343,6 +5344,9 @@ _process() { --nocron) _nocron="1" ;; + --no-color) + export ACME_NO_COLOR=1 + ;; --ecc) _ecc="isEcc" ;; From 8afec596aabe4795036b7387e092c7cb4cd6995b Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:05:43 +0800 Subject: [PATCH 0986/1348] fix https://github.com/Neilpang/acme.sh/issues/882#issuecomment-309383956 --- acme.sh | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index d2c8cf24..c9c58074 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,9 +1716,18 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" - nonceurl="$ACME_DIRECTORY" - _headers="$(_get "$nonceurl" "onlyheader")" + if [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + if _post "" "$nonceurl" "" "HEAD"; then + _headers="$(cat "$HTTP_HEADER")" + fi + fi + if [ -z "$_headers" ]; then + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" + _headers="$(_get "$nonceurl" "onlyheader")" + fi if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." @@ -2180,12 +2189,12 @@ _initAPI() { #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" - export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" - export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" fi - if [ -z "$ACME_KEY_CHANGE" ]; then + if [ -z "$ACME_NEW_ACCOUNT" ]; then response=$(_get "$_api_server") if [ "$?" != "0" ]; then _debug2 "response" "$response" @@ -2200,21 +2209,30 @@ _initAPI() { ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_AUTHZ - ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_CERT + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ORDER - ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_REG + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ACCOUNT ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_REVOKE_CERT + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_NONCE + fi _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" - _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" - _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" + _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" } @@ -3086,7 +3104,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3737,7 +3755,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 From 87f3dc4558dbdb0f54a0adf6d9f2df093bbb6985 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:19:30 +0800 Subject: [PATCH 0987/1348] fix server host --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index c9c58074..18ed71a7 100755 --- a/acme.sh +++ b/acme.sh @@ -2265,7 +2265,7 @@ _initpath() { fi fi - _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" @@ -5119,6 +5119,7 @@ _process() { _openssl_bin="" _syslog="" _use_wget="" + _server="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5237,6 +5238,7 @@ _process() { ;; --server) ACME_DIRECTORY="$2" + _server="$ACME_DIRECTORY" export ACME_DIRECTORY shift ;; @@ -5560,6 +5562,9 @@ _process() { if [ "$DEBUG" ]; then version + if [ "$_server" ]; then + _debug "Using server: $_server" + fi fi case "${_CMD}" in From 1d384e3192a4ace6d3ef708d43e65e0015cd2e1d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:24:31 +0800 Subject: [PATCH 0988/1348] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 18ed71a7..428340d2 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,6 +1716,7 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then + _headers="" if [ "$ACME_NEW_NONCE" ]; then _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" From 48d9a8c18051ecd8bcd2922b14b0f83e99804663 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:49:45 +0800 Subject: [PATCH 0989/1348] support `--server` --- acme.sh | 104 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index f20d935f..ebee1e95 100755 --- a/acme.sh +++ b/acme.sh @@ -13,7 +13,8 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" -DEFAULT_CA="https://acme-v01.api.letsencrypt.org" +_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" +DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" @@ -24,7 +25,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" -STAGE_CA="https://acme-staging.api.letsencrypt.org" +STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -1714,8 +1715,8 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce." - nonceurl="$API/directory" + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" _headers="$(_get "$nonceurl" "onlyheader")" if [ "$?" != "0" ]; then @@ -2169,6 +2170,53 @@ __initHome() { fi } +#server +_initAPI() { + _api_server="${1:-$ACME_DIRECTORY}" + _debug "_init api for server: $_api_server" + + if [ "$_api_server" = "$DEFAULT_CA" ]; then + #just for performance, hardcode the default entry points + export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" + export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" + export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" + fi + + if [ -z "$ACME_KEY_CHANGE" ]; then + response=$(_get "$_api_server") + if [ "$?" != "0" ]; then + _debug2 "response" "$response" + _err "Can not init api." + return 1 + fi + _debug2 "response" "$response" + + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_KEY_CHANGE + + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_AUTHZ + + ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_CERT + + ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_REG + + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_REVOKE_CERT + + fi + + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" + _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" + _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" + _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" +} + #[domain] [keylength] _initpath() { @@ -2189,17 +2237,19 @@ _initpath() { CA_HOME="$DEFAULT_CA_HOME" fi - if [ -z "$API" ]; then + if [ -z "$ACME_DIRECTORY" ]; then if [ -z "$STAGE" ]; then - API="$DEFAULT_CA" + ACME_DIRECTORY="$DEFAULT_CA" else - API="$STAGE_CA" - _info "Using stage api:$API" + ACME_DIRECTORY="$STAGE_CA" + _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" fi fi - _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')" - CA_DIR="$CA_HOME/$_API_HOST" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" + + CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" _DEFAULT_CA_CONF="$CA_DIR/ca.conf" @@ -3020,7 +3070,7 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - + _initAPI _updateTos="" _reg_res="new-reg" while true; do @@ -3035,7 +3085,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3126,7 +3176,7 @@ __get_domain_new_authz() { _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do _debug "Try new-authz for the $_authz_i time." - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then + if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then _err "Can not get domain new authz." return 1 fi @@ -3204,13 +3254,16 @@ issue() { if [ "$_web_roots" = "dns-cx" ]; then _web_roots="dns_cx" fi - _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then _initpath "$_main_domain" "$_key_length" mkdir -p "$DOMAIN_PATH" fi + _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" + + _initAPI + if [ -f "$DOMAIN_CONF" ]; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" @@ -3244,7 +3297,7 @@ issue() { _cleardomainconf "Le_LocalAddress" fi - Le_API="$API" + Le_API="$ACME_DIRECTORY" _savedomainconf "Le_API" "$Le_API" if [ "$_alt_domains" = "$NO_VALUE" ]; then @@ -3683,7 +3736,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 @@ -3736,7 +3789,8 @@ issue() { Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') if ! _contains "$Le_LinkIssuer" ":"; then - Le_LinkIssuer="$API$Le_LinkIssuer" + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" fi _debug Le_LinkIssuer "$Le_LinkIssuer" _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" @@ -3852,7 +3906,11 @@ renew() { . "$DOMAIN_CONF" if [ "$Le_API" ]; then - API="$Le_API" + if [ "$_OLD_CA_HOST" = "$Le_API" ]; then + export Le_API="$DEFAULT_CA" + _savedomainconf Le_API "$Le_API" + fi + export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" ACCOUNT_JSON_PATH="" @@ -4319,8 +4377,10 @@ revoke() { return 1 fi + _initAPI + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" - uri="$API/acme/revoke-cert" + uri="${ACME_REVOKE_CERT}" if [ -f "$CERT_KEY_PATH" ]; then _info "Try domain key first." @@ -4879,6 +4939,7 @@ Parameters: --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. + --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 . --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. @@ -5155,6 +5216,11 @@ _process() { --staging | --test) STAGE="1" ;; + --server) + ACME_DIRECTORY="$2" + export ACME_DIRECTORY + shift + ;; --debug) if [ -z "$2" ] || _startswith "$2" "-"; then DEBUG="$DEBUG_LEVEL_DEFAULT" From 4cee14f3c5503699ffb9c19cc5eb81d9b11265d4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:59:27 +0800 Subject: [PATCH 0990/1348] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ebee1e95..676a7201 100755 --- a/acme.sh +++ b/acme.sh @@ -2174,7 +2174,7 @@ __initHome() { _initAPI() { _api_server="${1:-$ACME_DIRECTORY}" _debug "_init api for server: $_api_server" - + if [ "$_api_server" = "$DEFAULT_CA" ]; then #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" From 40ef86f475dcefcc46d3997869079aa0fb3d000e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:20:32 +0800 Subject: [PATCH 0991/1348] fix for deactivate function --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 676a7201..b1ddb500 100755 --- a/acme.sh +++ b/acme.sh @@ -3171,7 +3171,7 @@ _findHook() { __get_domain_new_authz() { _gdnd="$1" _info "Getting new-authz for domain" "$_gdnd" - + _initAPI _Max_new_authz_retry_times=5 _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do From a3bdaa85f2c944c828ee74e94669bef4d2f80649 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:30:04 +0800 Subject: [PATCH 0992/1348] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index b1ddb500..43929203 100755 --- a/acme.sh +++ b/acme.sh @@ -4512,6 +4512,7 @@ deactivate() { _d_domain_list="$1" _d_type="$2" _initpath + _initAPI _debug _d_domain_list "$_d_domain_list" if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" From 4a2ac7bd2ec2f95bd4974e751dbcac49e8c4e402 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 17:15:37 +0800 Subject: [PATCH 0993/1348] fix renew for stage cert --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 43929203..2ee7740c 100755 --- a/acme.sh +++ b/acme.sh @@ -26,6 +26,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" +_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -3910,6 +3911,10 @@ renew() { export Le_API="$DEFAULT_CA" _savedomainconf Le_API "$Le_API" fi + if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then + export Le_API="$STAGE_CA" + _savedomainconf Le_API "$Le_API" + fi export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" From cae50e16a71bdf921b9a1bd4708625cf8471278f Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:05:43 +0800 Subject: [PATCH 0994/1348] fix https://github.com/Neilpang/acme.sh/issues/882#issuecomment-309383956 --- acme.sh | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index 2ee7740c..81668480 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,9 +1716,18 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" - nonceurl="$ACME_DIRECTORY" - _headers="$(_get "$nonceurl" "onlyheader")" + if [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + if _post "" "$nonceurl" "" "HEAD"; then + _headers="$(cat "$HTTP_HEADER")" + fi + fi + if [ -z "$_headers" ]; then + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" + _headers="$(_get "$nonceurl" "onlyheader")" + fi if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." @@ -2180,12 +2189,12 @@ _initAPI() { #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" - export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" - export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" fi - if [ -z "$ACME_KEY_CHANGE" ]; then + if [ -z "$ACME_NEW_ACCOUNT" ]; then response=$(_get "$_api_server") if [ "$?" != "0" ]; then _debug2 "response" "$response" @@ -2200,21 +2209,30 @@ _initAPI() { ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_AUTHZ - ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_CERT + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ORDER - ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_REG + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ACCOUNT ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_REVOKE_CERT + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_NONCE + fi _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" - _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" - _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" + _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" } @@ -3086,7 +3104,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3737,7 +3755,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 From 98394f99b5649be9df419fd3bed5bfef4658971c Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:19:30 +0800 Subject: [PATCH 0995/1348] fix server host --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 81668480..a9a9c040 100755 --- a/acme.sh +++ b/acme.sh @@ -2265,7 +2265,7 @@ _initpath() { fi fi - _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" @@ -5124,6 +5124,7 @@ _process() { _openssl_bin="" _syslog="" _use_wget="" + _server="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5242,6 +5243,7 @@ _process() { ;; --server) ACME_DIRECTORY="$2" + _server="$ACME_DIRECTORY" export ACME_DIRECTORY shift ;; @@ -5568,6 +5570,9 @@ _process() { if [ "$DEBUG" ]; then version + if [ "$_server" ]; then + _debug "Using server: $_server" + fi fi case "${_CMD}" in From 8f01919f62513ad4daa08db2d292de1040381351 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:24:31 +0800 Subject: [PATCH 0996/1348] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index a9a9c040..dea5b4a7 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,6 +1716,7 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then + _headers="" if [ "$ACME_NEW_NONCE" ]; then _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" From 88ada806863aaaf3b0037573715d3bd589b3cafe Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 20 Jun 2017 21:51:18 +0800 Subject: [PATCH 0997/1348] step to 2.7.3 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index dea5b4a7..09cc9fd4 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.2 +VER=2.7.3 PROJECT_NAME="acme.sh" From 841b762796d4909d0bc40cfa7e4a9147aa17e28a Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 23 Jun 2017 18:11:11 +0800 Subject: [PATCH 0998/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 09cc9fd4..70033523 100755 --- a/acme.sh +++ b/acme.sh @@ -453,7 +453,7 @@ if [ "$(printf '\x41')" != 'A' ]; then fi _ESCAPE_XARGS="" -if [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then +if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then _ESCAPE_XARGS=1 fi From eb0ef6bd3dd56af440628b9b0f0edeb3753cf863 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Jun 2017 19:56:43 +0800 Subject: [PATCH 0999/1348] fix https://github.com/Neilpang/acme.sh/issues/614#issuecomment-311160843 --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 70033523..fa969b0f 100755 --- a/acme.sh +++ b/acme.sh @@ -1138,7 +1138,12 @@ _readKeyLengthFromCSR() { echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | tr "\t" " " | (_egrep_o "^ *Public.Key:.*" || _egrep_o "RSA Public.Key:.*") | cut -d '(' -f 2 | cut -d ' ' -f 1 + _rkl="$(echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1)" + if [ "$_rkl" ]; then + echo "$_rkl" + else + echo "$_outcsr" | tr "\t" " " | _egrep_o "RSA Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + fi fi } From fa98d72f3a87cf438ba16cccccf61fc268c517df Mon Sep 17 00:00:00 2001 From: RaidenII Date: Tue, 27 Jun 2017 09:21:39 -0400 Subject: [PATCH 1000/1348] Added preliminary support for DuckDNS TXT record API, a free Dynamic DNS provider --- dnsapi/dns_duckdns.sh | 93 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100755 dnsapi/dns_duckdns.sh diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh new file mode 100755 index 00000000..dc0d49ca --- /dev/null +++ b/dnsapi/dns_duckdns.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env sh + +#Created by RaidenII, to use DuckDNS's API to add/remove text records +#06/27/2017 + +# Currently only support single domain access + +# DuckDNS uses StartSSL as their cert provider +# Seems not supported natively on Linux +# So I fall back to HTTP for API +DuckDNS_API="http://www.duckdns.org/update" + +######## Public functions ##################### + +#Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_duckdns_add() { + fulldomain=$1 + txtvalue=$2 + + # We'll extract the domain/username from full domain + IFS='.' read -r -a fqdn <<< "$fulldomain" + DuckDNS_domain="${fqdn[-3]}" + + if [ -z "$DuckDNS_domain" ]; then + _err "Error extracting the domain." + return 1 + fi + + if [ -z "$DuckDNS_token" ]; then + DuckDNS_token="" + _err "The token for your DuckDNS account is necessary." + _err "You can look it up in your DuckDNS account." + return 1 + fi + + # Now save the credentials. + _saveaccountconf DuckDNS_domain "$DuckDNS_domain" + _saveaccountconf DuckDNS_token "$DuckDNS_token" + + # Unfortunately, DuckDNS does not seems to support lookup domain through API + # So I assume your credentials (which are your domain and token) are correct + # If something goes wrong, we will get a KO response from DuckDNS + + # Now add the TXT record to DuckDNS + _info "Trying to add TXT record" + if _duckdns_rest GET "domains=$DuckDNS_domain&token=$DuckDNS_token&txt=$txtvalue" && [ $response == "OK" ]; then + _info "TXT record has been successfully added to your DuckDNS domain." + _info "Note that all subdomains under this domain uses the same TXT record." + return 0 + else + _err "Errors happened during adding the TXT record." + return 1 + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_duckdns_rm() { + fulldomain=$1 + txtvalue=$2 + + # Now remove the TXT record from DuckDNS + _info "Trying to from TXT record" + if _duckdns_rest GET "domains=$DuckDNS_domain&token=$DuckDNS_token&txt=''&clear=true" && [ $response == "OK" ]; then + _info "TXT record has been successfully removed from your DuckDNS domain." + return 0 + else + _err "Errors happened during removing the TXT record." + return 1 + fi +} + +#################### Private functions below ################################## + +#Usage: method URI data +_duckdns_rest() { + method=$1 + param="$2" + _debug param "$param" + url="$DuckDNS_API?$param" + _debug url "$url" + + # DuckDNS uses GET to update domain info + if [ $method == "GET" ]; then + response="$(_get "$url")" + else + _err "Unsupported method" + return 1 + fi + + _debug response "$response" + return 0 +} From e7dff4756ffef5f14b40363cc2a888977b9d9efd Mon Sep 17 00:00:00 2001 From: RaidenII Date: Tue, 27 Jun 2017 15:28:10 -0400 Subject: [PATCH 1001/1348] Using HTTPS for DuckDNS API and added instruction. --- dnsapi/dns_duckdns.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index dc0d49ca..847b3fc5 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -4,11 +4,10 @@ #06/27/2017 # Currently only support single domain access +# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure must be used with acme.sh -# DuckDNS uses StartSSL as their cert provider -# Seems not supported natively on Linux -# So I fall back to HTTP for API -DuckDNS_API="http://www.duckdns.org/update" +DuckDNS_API="https://www.duckdns.org/update" +API_Params="domains=$DuckDNS_domain&token=$DuckDNS_token" ######## Public functions ##################### @@ -43,7 +42,7 @@ dns_duckdns_add() { # Now add the TXT record to DuckDNS _info "Trying to add TXT record" - if _duckdns_rest GET "domains=$DuckDNS_domain&token=$DuckDNS_token&txt=$txtvalue" && [ $response == "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ $response == "OK" ]; then _info "TXT record has been successfully added to your DuckDNS domain." _info "Note that all subdomains under this domain uses the same TXT record." return 0 @@ -60,8 +59,8 @@ dns_duckdns_rm() { txtvalue=$2 # Now remove the TXT record from DuckDNS - _info "Trying to from TXT record" - if _duckdns_rest GET "domains=$DuckDNS_domain&token=$DuckDNS_token&txt=''&clear=true" && [ $response == "OK" ]; then + _info "Trying to remove TXT record" + if _duckdns_rest GET "$API_Params&txt=''&clear=true" && [ $response == "OK" ]; then _info "TXT record has been successfully removed from your DuckDNS domain." return 0 else @@ -72,7 +71,7 @@ dns_duckdns_rm() { #################### Private functions below ################################## -#Usage: method URI data +#Usage: method URI _duckdns_rest() { method=$1 param="$2" From 9dd62ae0f8de8e125edb8396a1b25aba3d712bd3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 28 Jun 2017 19:21:03 +0800 Subject: [PATCH 1002/1348] fix https://github.com/Neilpang/acme.sh/issues/900 --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5254bd11..8f363852 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,9 +50,10 @@ RUN for verb in help \ RUN printf "%b" '#!'"/usr/bin/env sh\n \ if [ \"\$1\" = \"daemon\" ]; then \n \ - crond -f\n \ + trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \ + crond && while true; do sleep 1; done;\n \ else \n \ - /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ + exec -- \"\$@\"\n \ fi" >/entry.sh && chmod +x /entry.sh VOLUME /acme.sh From 7d2b6cfeaf888a34526fa291e5d9b5ad350ff6ff Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 28 Jun 2017 19:46:51 +0800 Subject: [PATCH 1003/1348] fix https://github.com/Neilpang/acme.sh/issues/905 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 13188982..5b6b03ae 100644 --- a/README.md +++ b/README.md @@ -296,6 +296,9 @@ acme.sh --renew -d example.com Ok, it's finished. +**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.** + +**Please use dns api mode instead.** # 9. Automatic DNS API integration From e64ad5176ef6e4865c0d8fd7da83e318e07ef853 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Wed, 28 Jun 2017 16:15:57 -0400 Subject: [PATCH 1004/1348] Added Name.com API support. Minor change to DuckDNS API support. --- dnsapi/dns_duckdns.sh | 2 +- dnsapi/dns_namecom.sh | 188 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 1 deletion(-) create mode 100755 dnsapi/dns_namecom.sh diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index 847b3fc5..f86d516e 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -60,7 +60,7 @@ dns_duckdns_rm() { # Now remove the TXT record from DuckDNS _info "Trying to remove TXT record" - if _duckdns_rest GET "$API_Params&txt=''&clear=true" && [ $response == "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ $response == "OK" ]; then _info "TXT record has been successfully removed from your DuckDNS domain." return 0 else diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh new file mode 100755 index 00000000..7a84685f --- /dev/null +++ b/dnsapi/dns_namecom.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +#Author: RaidneII +#Created 06/28/2017 +#Utilize name.com API to finish dns-01 verifications. +######## Public functions ##################### + +namecom_api="https://api.name.com/api/" + +#Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_namecom_add() { + fulldomain=$1 + txtvalue=$2 + + # First we need name.com credentials. + if [ -z "$namecom_username" ]; then + namecom_username="" + _err "Username for name.com is missing." + _err "Please specify that in your environment variable." + return 1 + fi + + if [ -z "$namecom_token" ]; then + namecom_token="" + _err "API token for name.com is missing." + _err "Please specify that in your environment variable." + return 1 + fi + + # Save them in configuration. + _saveaccountconf namecom_username "$namecom_username" + _saveaccountconf namecom_token "$namecom_token" + + # Login in using API + _namecom_login + + # Find domain in domain list. + if ! _namecom_get_root "$fulldomain"; then + _err "Unable to find domain specified." + _namecom_logout + return 1 + fi + + # Add TXT record. + _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" + if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + _debug retcode "$retcode" + if [ ! -z "$retcode" ]; then + _info "Successfully added TXT record, ready for validation." + _namecom_logout + return 0 + else + _err "Unable to add the DNS record." + _namecom_logout + return 1 + fi + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_namecom_rm() { + fulldomain=$1 + txtvalue=$2 + + _namecom_login + + # Find domain in domain list. + if ! _namecom_get_root "$fulldomain"; then + _err "Unable to find domain specified." + _namecom_logout + return 1 + fi + + # Get the record id. + if _namecom_rest GET "dns/list/$_domain"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + _debug retcode "$retcode" + if [ ! -z "$retcode" ]; then + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) + _debug record_id "$_record_id" + _info "Successfully retrieved the record id for ACME challenge." + else + _err "Unable to retrieve the record id." + _namecom_logout + return 1 + fi + fi + + # Remove the DNS record using record id. + _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" + if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + _debug retcode "$retcode" + if [ ! -z "$retcode" ]; then + _info "Successfully removed the TXT record." + _namecom_logout + return 0 + else + _err "Unable to remove the DNS record." + _namecom_logout + return 1 + fi + fi +} + +#################### Private functions below ################################## +_namecom_rest() { + method=$1 + param=$2 + data=$3 + + export _H1="Content-Type: application/json" + export _H2="Api-Session-Token: $sessionkey" + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$namecom_api/$param" "" "$method")" + else + response="$(_get "$namecom_api/$param")" + fi + + if [ "$?" != "0" ]; then + _err "error $param" + return 1 + fi + + _debug response "$response" + return 0 +} + +_namecom_login() { + namecom_login_json="{\"username\":\"$namecom_username\",\"api_token\":\"$namecom_token\"}" + + if _namecom_rest POST "login" "$namecom_login_json"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + _debug retcode "$retcode" + if [ ! -z "$retcode" ]; then + _info "Successfully logged in. Fetching session token..." + sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) + if [ ! -z "$sessionkey" ]; then + _debug sessionkey "$sessionkey" + _info "Session key obtained." + else + _err "Unable to get session key." + return 1 + fi + else + _err "Logging in failed." + return 1 + fi + fi +} + +_namecom_logout() { + if _namecom_rest GET "logout"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + if [ ! -z "$retcode" ]; then + _info "Successfully logged out." + else + _err "Error logging out." + return 1 + fi + fi +} + +_namecom_get_root() { + domain=$1 + i=2 + p=1 + + if _namecom_rest GET "domain/list"; then + while true; do + host=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$host" ]; then + return 1 + fi + + if _contains "$response" "$host"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$host" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} From 168d712decb687c4ac665b02df716a7de9c99b6e Mon Sep 17 00:00:00 2001 From: RaidenII Date: Thu, 29 Jun 2017 09:43:11 -0400 Subject: [PATCH 1005/1348] Fixed URL of Name.com API and removed useless debug for retcode. --- dnsapi/dns_namecom.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 7a84685f..158a11b0 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -5,7 +5,7 @@ #Utilize name.com API to finish dns-01 verifications. ######## Public functions ##################### -namecom_api="https://api.name.com/api/" +namecom_api="https://api.name.com/api" #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { @@ -45,7 +45,6 @@ dns_namecom_add() { _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - _debug retcode "$retcode" if [ ! -z "$retcode" ]; then _info "Successfully added TXT record, ready for validation." _namecom_logout @@ -76,7 +75,6 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "dns/list/$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - _debug retcode "$retcode" if [ ! -z "$retcode" ]; then _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) _debug record_id "$_record_id" @@ -92,7 +90,6 @@ dns_namecom_rm() { _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - _debug retcode "$retcode" if [ ! -z "$retcode" ]; then _info "Successfully removed the TXT record." _namecom_logout @@ -133,7 +130,6 @@ _namecom_login() { if _namecom_rest POST "login" "$namecom_login_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - _debug retcode "$retcode" if [ ! -z "$retcode" ]; then _info "Successfully logged in. Fetching session token..." sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) From eeda3062e1c2a79d65e01db192582586e11fb517 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Thu, 29 Jun 2017 15:40:29 -0400 Subject: [PATCH 1006/1348] Fix against POSIX standard. --- dnsapi/dns_duckdns.sh | 9 ++-- dnsapi/dns_namecom.sh | 104 +++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index f86d516e..a34c8d36 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -17,8 +17,7 @@ dns_duckdns_add() { txtvalue=$2 # We'll extract the domain/username from full domain - IFS='.' read -r -a fqdn <<< "$fulldomain" - DuckDNS_domain="${fqdn[-3]}" + DuckDNS_domain=$(printf "%s\n" "$fulldomain" | rev | cut -d \. -f 3 | rev) if [ -z "$DuckDNS_domain" ]; then _err "Error extracting the domain." @@ -42,7 +41,7 @@ dns_duckdns_add() { # Now add the TXT record to DuckDNS _info "Trying to add TXT record" - if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ $response == "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" -eq "OK" ]; then _info "TXT record has been successfully added to your DuckDNS domain." _info "Note that all subdomains under this domain uses the same TXT record." return 0 @@ -60,7 +59,7 @@ dns_duckdns_rm() { # Now remove the TXT record from DuckDNS _info "Trying to remove TXT record" - if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ $response == "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" -eq "OK" ]; then _info "TXT record has been successfully removed from your DuckDNS domain." return 0 else @@ -80,7 +79,7 @@ _duckdns_rest() { _debug url "$url" # DuckDNS uses GET to update domain info - if [ $method == "GET" ]; then + if [ "$method" -eq "GET" ]; then response="$(_get "$url")" else _err "Unsupported method" diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 158a11b0..9a6e81f9 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -45,15 +45,15 @@ dns_namecom_add() { _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _info "Successfully added TXT record, ready for validation." - _namecom_logout - return 0 - else - _err "Unable to add the DNS record." - _namecom_logout - return 1 - fi + if [ ! -z "$retcode" ]; then + _info "Successfully added TXT record, ready for validation." + _namecom_logout + return 0 + else + _err "Unable to add the DNS record." + _namecom_logout + return 1 + fi fi } @@ -75,30 +75,30 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "dns/list/$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) - _debug record_id "$_record_id" - _info "Successfully retrieved the record id for ACME challenge." - else - _err "Unable to retrieve the record id." - _namecom_logout - return 1 - fi + if [ ! -z "$retcode" ]; then + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) + _debug record_id "$_record_id" + _info "Successfully retrieved the record id for ACME challenge." + else + _err "Unable to retrieve the record id." + _namecom_logout + return 1 + fi fi # Remove the DNS record using record id. _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _info "Successfully removed the TXT record." - _namecom_logout - return 0 - else - _err "Unable to remove the DNS record." - _namecom_logout - return 1 - fi + if [ ! -z "$retcode" ]; then + _info "Successfully removed the TXT record." + _namecom_logout + return 0 + else + _err "Unable to remove the DNS record." + _namecom_logout + return 1 + fi fi } @@ -130,32 +130,32 @@ _namecom_login() { if _namecom_rest POST "login" "$namecom_login_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _info "Successfully logged in. Fetching session token..." - sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) - if [ ! -z "$sessionkey" ]; then - _debug sessionkey "$sessionkey" - _info "Session key obtained." - else - _err "Unable to get session key." - return 1 - fi + if [ ! -z "$retcode" ]; then + _info "Successfully logged in. Fetching session token..." + sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) + if [ ! -z "$sessionkey" ]; then + _debug sessionkey "$sessionkey" + _info "Session key obtained." else - _err "Logging in failed." + _err "Unable to get session key." return 1 fi - fi + else + _err "Logging in failed." + return 1 + fi + fi } _namecom_logout() { if _namecom_rest GET "logout"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _info "Successfully logged out." - else - _err "Error logging out." - return 1 - fi + if [ ! -z "$retcode" ]; then + _info "Successfully logged out." + else + _err "Error logging out." + return 1 + fi fi } @@ -171,13 +171,13 @@ _namecom_get_root() { return 1 fi - if _contains "$response" "$host"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$host" - return 0 - fi - p=$i - i=$(_math "$i" + 1) + if _contains "$response" "$host"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$host" + return 0 + fi + p=$i + i=$(_math "$i" + 1) done fi return 1 From d0f5aece5f5c1708668faed8e2a7fe5671eceea8 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Thu, 29 Jun 2017 15:43:58 -0400 Subject: [PATCH 1007/1348] Fix SC2170. --- dnsapi/dns_duckdns.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index a34c8d36..b1937cb8 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -41,7 +41,7 @@ dns_duckdns_add() { # Now add the TXT record to DuckDNS _info "Trying to add TXT record" - if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" -eq "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" = "OK" ]; then _info "TXT record has been successfully added to your DuckDNS domain." _info "Note that all subdomains under this domain uses the same TXT record." return 0 @@ -59,7 +59,7 @@ dns_duckdns_rm() { # Now remove the TXT record from DuckDNS _info "Trying to remove TXT record" - if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" -eq "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" = "OK" ]; then _info "TXT record has been successfully removed from your DuckDNS domain." return 0 else @@ -79,7 +79,7 @@ _duckdns_rest() { _debug url "$url" # DuckDNS uses GET to update domain info - if [ "$method" -eq "GET" ]; then + if [ "$method" = "GET" ]; then response="$(_get "$url")" else _err "Unsupported method" From 17fbfd14db2b71af580afb59cc515f09299ca37e Mon Sep 17 00:00:00 2001 From: RaidenII Date: Fri, 30 Jun 2017 08:32:39 -0400 Subject: [PATCH 1008/1348] Minor fixes. --- dnsapi/dns_duckdns.sh | 2 +- dnsapi/dns_namecom.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index b1937cb8..cacf5a8c 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -17,7 +17,7 @@ dns_duckdns_add() { txtvalue=$2 # We'll extract the domain/username from full domain - DuckDNS_domain=$(printf "%s\n" "$fulldomain" | rev | cut -d \. -f 3 | rev) + DuckDNS_domain=$(printf "%s\n" "$fulldomain" | rev | cut -d . -f 3 | rev) if [ -z "$DuckDNS_domain" ]; then _err "Error extracting the domain." diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 9a6e81f9..2c5a5df4 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -76,7 +76,7 @@ dns_namecom_rm() { if _namecom_rest GET "dns/list/$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") if [ ! -z "$retcode" ]; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4) _debug record_id "$_record_id" _info "Successfully retrieved the record id for ACME challenge." else From d04434e3ecd286c2109afd313aecf31d2cc7ec49 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 1 Jul 2017 10:54:14 +0800 Subject: [PATCH 1009/1348] fix alias --- acme.sh | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index fa969b0f..1f1071d1 100755 --- a/acme.sh +++ b/acme.sh @@ -4679,6 +4679,8 @@ _installalias() { _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" if [ "$_c_home" ]; then _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" + else + _sed_i "/^export LE_CONFIG_HOME/d" "$_envfile" fi _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" @@ -4700,6 +4702,8 @@ _installalias() { _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" if [ "$_c_home" ]; then _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" + else + _sed_i "/^setenv LE_CONFIG_HOME/d" "$_cshfile" fi _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" _setopt "$_csh_profile" "source \"$_cshfile\"" @@ -4764,20 +4768,24 @@ install() { _info "Installing to $LE_WORKING_DIR" - if ! mkdir -p "$LE_WORKING_DIR"; then - _err "Can not create working dir: $LE_WORKING_DIR" - return 1 + if [ ! -d "$LE_WORKING_DIR" ]; then + if ! mkdir -p "$LE_WORKING_DIR"; then + _err "Can not create working dir: $LE_WORKING_DIR" + return 1 + fi + + chmod 700 "$LE_WORKING_DIR" fi - chmod 700 "$LE_WORKING_DIR" + if [ ! -d "$LE_CONFIG_HOME" ]; then + if ! mkdir -p "$LE_CONFIG_HOME"; then + _err "Can not create config dir: $LE_CONFIG_HOME" + return 1 + fi - if ! mkdir -p "$LE_CONFIG_HOME"; then - _err "Can not create config dir: $LE_CONFIG_HOME" - return 1 + chmod 700 "$LE_CONFIG_HOME" fi - chmod 700 "$LE_CONFIG_HOME" - cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" if [ "$?" != "0" ]; then From 63c6ed3fd06263a5ad8ebb2788807bda13237f42 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sat, 1 Jul 2017 05:14:52 -0700 Subject: [PATCH 1010/1348] Fixes to follow coding standards. --- dnsapi/dns_duckdns.sh | 16 ++++++++-------- dnsapi/dns_namecom.sh | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index cacf5a8c..95df4c21 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -7,7 +7,7 @@ # Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure must be used with acme.sh DuckDNS_API="https://www.duckdns.org/update" -API_Params="domains=$DuckDNS_domain&token=$DuckDNS_token" +API_Params="domains=$DuckDNS_Domain&token=$DuckDNS_Token" ######## Public functions ##################### @@ -17,23 +17,23 @@ dns_duckdns_add() { txtvalue=$2 # We'll extract the domain/username from full domain - DuckDNS_domain=$(printf "%s\n" "$fulldomain" | rev | cut -d . -f 3 | rev) + DuckDNS_Domain=$(echo $fulldomain | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2) - if [ -z "$DuckDNS_domain" ]; then + if [ -z "$DuckDNS_Domain" ]; then _err "Error extracting the domain." return 1 fi - if [ -z "$DuckDNS_token" ]; then - DuckDNS_token="" + if [ -z "$DuckDNS_Token" ]; then + DuckDNS_Token="" _err "The token for your DuckDNS account is necessary." _err "You can look it up in your DuckDNS account." return 1 fi # Now save the credentials. - _saveaccountconf DuckDNS_domain "$DuckDNS_domain" - _saveaccountconf DuckDNS_token "$DuckDNS_token" + _saveaccountconf DuckDNS_Domain "$DuckDNS_Domain" + _saveaccountconf DuckDNS_Token "$DuckDNS_Token" # Unfortunately, DuckDNS does not seems to support lookup domain through API # So I assume your credentials (which are your domain and token) are correct @@ -86,6 +86,6 @@ _duckdns_rest() { return 1 fi - _debug response "$response" + _debug2 response "$response" return 0 } diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 2c5a5df4..15eae6c2 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -5,7 +5,7 @@ #Utilize name.com API to finish dns-01 verifications. ######## Public functions ##################### -namecom_api="https://api.name.com/api" +Namecom_API="https://api.name.com/api" #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { @@ -13,23 +13,23 @@ dns_namecom_add() { txtvalue=$2 # First we need name.com credentials. - if [ -z "$namecom_username" ]; then - namecom_username="" + if [ -z "$Namecom_Username" ]; then + Namecom_Username="" _err "Username for name.com is missing." _err "Please specify that in your environment variable." return 1 fi - if [ -z "$namecom_token" ]; then - namecom_token="" + if [ -z "$Namecom_Token" ]; then + Namecom_Token="" _err "API token for name.com is missing." _err "Please specify that in your environment variable." return 1 fi # Save them in configuration. - _saveaccountconf namecom_username "$namecom_username" - _saveaccountconf namecom_token "$namecom_token" + _saveaccountconf Namecom_Username "$Namecom_Username" + _saveaccountconf Namecom_Token "$Namecom_Token" # Login in using API _namecom_login @@ -45,7 +45,7 @@ dns_namecom_add() { _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _info "Successfully added TXT record, ready for validation." _namecom_logout return 0 @@ -75,7 +75,7 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "dns/list/$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4) _debug record_id "$_record_id" _info "Successfully retrieved the record id for ACME challenge." @@ -90,7 +90,7 @@ dns_namecom_rm() { _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _info "Successfully removed the TXT record." _namecom_logout return 0 @@ -111,9 +111,9 @@ _namecom_rest() { export _H1="Content-Type: application/json" export _H2="Api-Session-Token: $sessionkey" if [ "$method" != "GET" ]; then - response="$(_post "$data" "$namecom_api/$param" "" "$method")" + response="$(_post "$data" "$Namecom_API/$param" "" "$method")" else - response="$(_get "$namecom_api/$param")" + response="$(_get "$Namecom_API/$param")" fi if [ "$?" != "0" ]; then @@ -121,16 +121,16 @@ _namecom_rest() { return 1 fi - _debug response "$response" + _debug2 response "$response" return 0 } _namecom_login() { - namecom_login_json="{\"username\":\"$namecom_username\",\"api_token\":\"$namecom_token\"}" + namecom_login_json="{\"username\":\"$Namecom_Username\",\"api_token\":\"$Namecom_Token\"}" if _namecom_rest POST "login" "$namecom_login_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _info "Successfully logged in. Fetching session token..." sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) if [ ! -z "$sessionkey" ]; then @@ -150,7 +150,7 @@ _namecom_login() { _namecom_logout() { if _namecom_rest GET "logout"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _info "Successfully logged out." else _err "Error logging out." From 9aed1e2d17331e4c2eeb8ed9f48aa132bdbf07ae Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sat, 1 Jul 2017 05:18:12 -0700 Subject: [PATCH 1011/1348] Argh. Double quotes. --- dnsapi/dns_duckdns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index 95df4c21..d6987352 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -17,7 +17,7 @@ dns_duckdns_add() { txtvalue=$2 # We'll extract the domain/username from full domain - DuckDNS_Domain=$(echo $fulldomain | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2) + DuckDNS_Domain=$(echo "$fulldomain" | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2) if [ -z "$DuckDNS_Domain" ]; then _err "Error extracting the domain." From ea722da3deecf510c64e53df7b7ec4abe8c38123 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 1 Jul 2017 20:31:42 +0800 Subject: [PATCH 1012/1348] add debug info --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 1f1071d1..76509af0 100755 --- a/acme.sh +++ b/acme.sh @@ -2999,9 +2999,9 @@ _on_issue_err() { fi #trigger the validation to flush the pending authz + _debug2 "_chk_vlist" "$_chk_vlist" if [ "$_chk_vlist" ]; then ( - _debug2 "_chk_vlist" "$_chk_vlist" _debug2 "start to deactivate authz" ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') for ventry in $ventries; do @@ -3498,7 +3498,7 @@ issue() { if [ "$?" != "0" ]; then _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi dnsadded='1' @@ -3510,7 +3510,7 @@ issue() { _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi From 14d7bfdab2c3f16c64080aec0dccd0fc9437288c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 1 Jul 2017 21:47:30 +0800 Subject: [PATCH 1013/1348] fix deactivate for lower rate limit --- acme.sh | 65 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/acme.sh b/acme.sh index 76509af0..6590a00a 100755 --- a/acme.sh +++ b/acme.sh @@ -1152,7 +1152,7 @@ _ss() { if _exists "ss"; then _debug "Using: ss" - ss -ntpl | grep ":$_port " + ss -ntpl 2>/dev/null | grep ":$_port " return 0 fi @@ -4479,26 +4479,51 @@ _deactivate() { _d_type="$2" _initpath - _d_i=0 - _d_max_retry=9 - while [ "$_d_i" -lt "$_d_max_retry" ]; do - _info "Deactivate: $_d_domain" - _d_i="$(_math $_d_i + 1)" + if ! __get_domain_new_authz "$_d_domain"; then + _err "Can not get domain new authz token." + return 1 + fi - if ! __get_domain_new_authz "$_d_domain"; then - _err "Can not get domain new authz token." - return 1 - fi + authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" + _debug "authzUri" "$authzUri" - authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" - _debug "authzUri" "$authzUri" + if [ "$code" ] && [ ! "$code" = '201' ]; then + _err "new-authz error: $response" + return 1 + fi - if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then - _err "new-authz error: $response" + entries="$(echo "$response" | _egrep_o '{ *"type":"[^"]*", *"status": *"valid", *"uri"[^}]*')" + if [ -z "$entries" ]; then + _info "No valid entries found." + if [ -z "$thumbprint" ]; then + thumbprint="$(__calc_account_thumbprint)" + fi + _debug "Trigger validation." + vtype="$VTYPE_HTTP" + entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + _debug entry "$entry" + if [ -z "$entry" ]; then + _err "Error, can not get domain token $d" return 1 fi + token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" + _debug token "$token" - entry="$(printf "%s\n" "$response" | _egrep_o '{"type":"[^"]*","status":"valid","uri"[^}]*')" + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" + _debug uri "$uri" + + keyauthorization="$token.$thumbprint" + _debug keyauthorization "$keyauthorization" + __trigger_validation "$uri" "$keyauthorization" + + fi + + _d_i=0 + _d_max_retry=$(echo "$entries" | wc -l) + while [ "$_d_i" -lt "$_d_max_retry" ]; do + _info "Deactivate: $_d_domain" + _d_i="$(_math $_d_i + 1)" + entry="$(echo "$entries" | sed -n "${_d_i}p")" _debug entry "$entry" if [ -z "$entry" ]; then @@ -4520,16 +4545,16 @@ _deactivate() { _info "Deactivate: $_vtype" - if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}"; then + if _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then + _info "Deactivate: $_vtype success." + else _err "Can not deactivate $_vtype." - return 1 + break fi - _info "Deactivate: $_vtype success." - done _debug "$_d_i" - if [ "$_d_i" -lt "$_d_max_retry" ]; then + if [ "$_d_i" -eq "$_d_max_retry" ]; then _info "Deactivated success!" else _err "Deactivate failed." From 1be222f6ed23e5c793f7a6be834f5c96871d6ffe Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 13:38:44 +0800 Subject: [PATCH 1014/1348] minor --- acme.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 6590a00a..95964984 100755 --- a/acme.sh +++ b/acme.sh @@ -4614,9 +4614,7 @@ _detect_profile() { fi fi - if [ ! -z "$DETECTED_PROFILE" ]; then - echo "$DETECTED_PROFILE" - fi + echo "$DETECTED_PROFILE" } _initconf() { From c4b2e5829e7ad66941c60e4aa146f227f7df8cb9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 15:25:35 +0800 Subject: [PATCH 1015/1348] add always-force-new-domain-key. fix https://github.com/Neilpang/acme.sh/issues/914 --- acme.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 95964984..e8e04e7c 100755 --- a/acme.sh +++ b/acme.sh @@ -1281,7 +1281,7 @@ createDomainKey() { _initpath "$domain" "$_cdl" - if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then + if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ] ; then if _createkey "$_cdl" "$CERT_KEY_PATH"; then _savedomainconf Le_Keylength "$_cdl" _info "The domain key is here: $(__green $CERT_KEY_PATH)" @@ -3148,7 +3148,7 @@ _regAccount() { return 1 fi if [ "$code" = '202' ]; then - _info "Update success." + _info "Update account tos info success." CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" @@ -3355,7 +3355,7 @@ issue() { else _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" - if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ]; then + if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ] || [ "$Le_ForceNewDomainKey" = "1" ]; then if ! createDomainKey "$_main_domain" "$_key_length"; then _err "Create domain key error." _clearup @@ -3885,6 +3885,12 @@ issue() { _cleardomainconf Le_Listen_V4 fi + if [ "$Le_ForceNewDomainKey" = "1" ]; then + _savedomainconf "Le_ForceNewDomainKey" "$Le_ForceNewDomainKey" + else + _cleardomainconf Le_ForceNewDomainKey + fi + Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60) Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime") @@ -5026,6 +5032,7 @@ Parameters: --renew-hook Command to be run once for each successfully renewed certificate. --deploy-hook The hook file to deploy cert --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. + --always-force-new-domain-key Generate new domain key when renewal. Otherwise, the domain key is not changed by default. --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. --listen-v4 Force standalone/tls server to listen at ipv4. --listen-v6 Force standalone/tls server to listen at ipv6. @@ -5506,6 +5513,14 @@ _process() { --ocsp-must-staple | --ocsp) Le_OCSP_Staple="1" ;; + --always-force-new-domain-key) + if [ -z "$2" ] || _startswith "$2" "-"; then + Le_ForceNewDomainKey=1 + else + Le_ForceNewDomainKey="$2" + shift + fi + ;; --log | --logfile) _log="1" _logfile="$2" From 422dd1fa4f57c977ccb4083be9463500b544d293 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 17:02:54 +0800 Subject: [PATCH 1016/1348] Implement deactivate account: --deactivate-account --- acme.sh | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e8e04e7c..99c83a04 100755 --- a/acme.sh +++ b/acme.sh @@ -366,6 +366,7 @@ _hasfield() { return 1 #not contains } +# str index [sep] _getfield() { _str="$1" _findex="$2" @@ -3127,7 +3128,7 @@ _regAccount() { _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" - + _savecaconf "ACCOUNT_URL" "$_accUri" _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')" _debug "_tos" "$_tos" if [ -z "$_tos" ]; then @@ -3153,6 +3154,9 @@ _regAccount() { CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" _savecaconf CA_KEY_HASH "$CA_KEY_HASH" + elif [ "$code" = '403' ]; then + _err "It seems that the account key is already deactivated, please use a new account key." + return 1 else _err "Update account error." return 1 @@ -3165,6 +3169,71 @@ _regAccount() { } + +#Implement deactivate account +deactivateaccount() { + _initpath + + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + mkdir -p "$CA_DIR" + _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" + mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" + fi + + if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then + mkdir -p "$CA_DIR" + _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" + mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" + fi + + if [ ! -f "$ACCOUNT_KEY_PATH" ]; then + _err "Account key is not found at: $ACCOUNT_KEY_PATH" + return 1 + fi + + _accUri=$(_readcaconf "ACCOUNT_URL") + _debug _accUri "$_accUri" + + if [ -z "$_accUri" ]; then + _err "The account url is empty, please run '--update-account' first to update the account info first," + _err "Then try again." + return 1 + fi + + if ! _calcjwk "$ACCOUNT_KEY_PATH"; then + return 1 + fi + _initAPI + + if _send_signed_request "$_accUri" "{\"resource\": \"reg\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then + _info "Deactivate account success for $_accUri." + _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,') + elif [ "$code" = "403" ]; then + _info "The account is already deactivated." + _accid=$(_getfield "$_accUri" "999" "/") + else + _err "Deactivate: account failed for $_accUri." + return 1 + fi + + _debug "Account id: $_accid" + if [ "$_accid" ]; then + _deactivated_account_path="$CA_DIR/deactivated/$_accid" + _debug _deactivated_account_path "$_deactivated_account_path" + if mkdir -p "$_deactivated_account_path"; then + _info "Moving deactivated account info to $_deactivated_account_path/" + mv "$CA_CONF" "$_deactivated_account_path/" + mv "$ACCOUNT_JSON_PATH" "$_deactivated_account_path/" + mv "$ACCOUNT_KEY_PATH" "$_deactivated_account_path/" + else + _err "Can not create dir: $_deactivated_account_path, try to remove the deactivated account key." + rm -f "$CA_CONF" + rm -f "$ACCOUNT_JSON_PATH" + rm -f "$ACCOUNT_KEY_PATH" + fi + fi +} + # domain folder file _findHook() { _hookdomain="$1" @@ -4972,6 +5041,7 @@ Commands: --toPkcs8 Convert to pkcs8 format. --update-account Update account info. --register-account Register account key. + --deactivate-account Deactivate the account. --create-account-key Create an account private key, professional use. --create-domain-key Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. @@ -5252,6 +5322,9 @@ _process() { --registeraccount | --register-account) _CMD="registeraccount" ;; + --deactivate-account) + _CMD="deactivateaccount" + ;; --domain | -d) _dvalue="$2" @@ -5667,6 +5740,9 @@ _process() { updateaccount) updateaccount ;; + deactivateaccount) + deactivateaccount + ;; list) list "$_listraw" ;; From a71eba07a1530aba3d6c2a454e40f1436a64996e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 18:05:55 +0800 Subject: [PATCH 1017/1348] minor, fix resource name --- acme.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 99c83a04..41818c75 100755 --- a/acme.sh +++ b/acme.sh @@ -2197,7 +2197,9 @@ _initAPI() { export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_ORDER_RES="new-cert" export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_NEW_ACCOUNT_RES="new-reg" export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" fi @@ -2217,16 +2219,22 @@ _initAPI() { export ACME_NEW_AUTHZ ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ORDER_RES="new-cert" if [ -z "$ACME_NEW_ORDER" ]; then ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ORDER_RES="new-order" fi export ACME_NEW_ORDER + export ACME_NEW_ORDER_RES ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ACCOUNT_RES="new-reg" if [ -z "$ACME_NEW_ACCOUNT" ]; then ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ACCOUNT_RES="new-account" fi export ACME_NEW_ACCOUNT + export ACME_NEW_ACCOUNT_RES ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_REVOKE_CERT @@ -3098,7 +3106,7 @@ _regAccount() { fi _initAPI _updateTos="" - _reg_res="new-reg" + _reg_res="$ACME_NEW_ACCOUNT_RES" while true; do _debug AGREEMENT "$AGREEMENT" @@ -3830,7 +3838,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 From 1bbc33a0cf2d46067c6d0901e8c94aa7f7749ebf Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 18:24:55 +0800 Subject: [PATCH 1018/1348] minor fix CA_DIR --- acme.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 41818c75..4d272750 100755 --- a/acme.sh +++ b/acme.sh @@ -3082,14 +3082,13 @@ _regAccount() { _initpath _reg_length="$1" + mkdir -p "$CA_DIR" if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then - mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" fi if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then - mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" fi @@ -3183,13 +3182,11 @@ deactivateaccount() { _initpath if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then - mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" fi if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then - mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" fi From 6b185d20c0be746632fa621a0fee762b65ea9cf9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 18:40:11 +0800 Subject: [PATCH 1019/1348] fix format --- acme.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 4d272750..fa090cdf 100755 --- a/acme.sh +++ b/acme.sh @@ -1282,7 +1282,7 @@ createDomainKey() { _initpath "$domain" "$_cdl" - if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ] ; then + if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ]; then if _createkey "$_cdl" "$CERT_KEY_PATH"; then _savedomainconf Le_Keylength "$_cdl" _info "The domain key is here: $(__green $CERT_KEY_PATH)" @@ -3176,7 +3176,6 @@ _regAccount() { } - #Implement deactivate account deactivateaccount() { _initpath From 2e602ef6b078543c79b9c86a179ed039bad30ce6 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sun, 2 Jul 2017 04:45:07 -0700 Subject: [PATCH 1020/1348] Added ret value verification. --- dnsapi/dns_namecom.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 15eae6c2..146db4f6 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -32,7 +32,9 @@ dns_namecom_add() { _saveaccountconf Namecom_Token "$Namecom_Token" # Login in using API - _namecom_login + if ! _namecom_login; then + return 1 + fi # Find domain in domain list. if ! _namecom_get_root "$fulldomain"; then @@ -63,7 +65,9 @@ dns_namecom_rm() { fulldomain=$1 txtvalue=$2 - _namecom_login + if ! _namecom_login; then + return 1 + fi # Find domain in domain list. if ! _namecom_get_root "$fulldomain"; then From 1a504118e56dd73ae1fe7b2fb16b58fd76e68765 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sun, 2 Jul 2017 04:55:06 -0700 Subject: [PATCH 1021/1348] Updated DNS API support list. --- README.md | 3 ++- dnsapi/README.md | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b6b03ae..7780b9ab 100644 --- a/README.md +++ b/README.md @@ -334,7 +334,8 @@ You don't have to do anything manually! 1. Dynu API (https://www.dynu.com) 1. DNSimple API 1. NS1.com API - +1. DuckDNS.org API +1. Name.com API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 5dca829a..7584b31e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -505,6 +505,37 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_nsone -d example.com -d www.example.com ``` +## 27. Use DuckDNS.org API + +``` +export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" +``` + +Please note that since DuckDNS uses StartSSL as their cert provider, thus +--insecure must be used when issuing certs: +``` +acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org +``` + +Also, DuckDNS uses the domain name as username for recording changing, so the +account file will always store the lastly used domain name. + +For issues, please report to https://github.com/raidenii/acme.sh/issues. + +## 28. Use Name.com API + +``` +export Namecom_Username="testuser" +export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +``` + +And now you can issue certs with: +``` +acme.sh --issue --dns dns_namecom -d example.com -d www.example.com +``` + +For issues, please report to https://github.com/raidenii/acme.sh/issues. + # Use custom API If your API is not supported yet, you can write your own DNS API. From 3002f6dfd5f2324fba4ee9fef1cf8ee8b896b8a9 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sun, 2 Jul 2017 06:02:44 -0700 Subject: [PATCH 1022/1348] Updated README.md for Name.com API application. --- dnsapi/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 7584b31e..e956b355 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -525,6 +525,10 @@ For issues, please report to https://github.com/raidenii/acme.sh/issues. ## 28. Use Name.com API ``` +You'll need to fill out the form at https://www.name.com/reseller/apply to apply +for API username and token. +``` + export Namecom_Username="testuser" export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ``` From 333090a96733f6701453ab3f5a1281ed99ff1ab5 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sun, 2 Jul 2017 06:38:25 -0700 Subject: [PATCH 1023/1348] Fix README.md for DNS API. --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index e956b355..57c360b7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -524,16 +524,16 @@ For issues, please report to https://github.com/raidenii/acme.sh/issues. ## 28. Use Name.com API -``` You'll need to fill out the form at https://www.name.com/reseller/apply to apply for API username and token. -``` +``` export Namecom_Username="testuser" export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ``` And now you can issue certs with: + ``` acme.sh --issue --dns dns_namecom -d example.com -d www.example.com ``` From 6c3430b6e592b0dad0783c4daee0ee692d5e0484 Mon Sep 17 00:00:00 2001 From: 2globalnomads Date: Sun, 2 Jul 2017 23:24:14 +0400 Subject: [PATCH 1024/1348] Wrote missing cpanel.sh This script I wrote works for me on GoDaddy, but I don't have any other hosting services or cpanel version to test it. Hope it's better than nothing for you. Thanks for your great script! Cheers, Santeri --- deploy/cpanel.sh | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/deploy/cpanel.sh b/deploy/cpanel.sh index bf1332ff..6ab012a3 100644 --- a/deploy/cpanel.sh +++ b/deploy/cpanel.sh @@ -1,8 +1,9 @@ -#!/usr/bin/env sh - -#Here is the script to deploy the cert to your cpanel account by the cpanel APIs. - -#returns 0 means success, otherwise error. +#!/bin/bash +# Here is the script to deploy the cert to your cpanel using the cpanel API. +# Uses command line uapi. Cpanel username is needed only when run as root. +# Returns 0 when success, otherwise error. +# Written by Santeri Kannisto +# Public domain, 2017 #export DEPLOY_CPANEL_USER=myusername #export DEPLOY_CPANEL_PASSWORD=PASSWORD @@ -10,6 +11,7 @@ ######## Public functions ##################### #domain keyfile certfile cafile fullchain + cpanel_deploy() { _cdomain="$1" _ckey="$2" @@ -23,7 +25,33 @@ cpanel_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _err "Not implemented yet" - return 1 + # read cert and key files and urlencode both + _certstr=`cat "$_ccert"` + _keystr=`cat "$_ckey"` + _cert=$(php -r "echo urlencode(\"$_certstr\");") + _key=$(php -r "echo urlencode(\"$_keystr\");") + + _debug _cert "$_cert" + _debug _key "$_key" + + if [[ $EUID -eq 0 ]] + then + _opt="--user=$DEPLOY_CPANEL_USER SSL install_ssl" + else + _opt="SSL install_ssl" + fi + + _debug _opt "$_opt" + + response=$(uapi $_opt domain="$_cdommain" cert="$_cert" key="$_key") + + if [ $? -ne 0 ] + then + _err "Error in deploying certificate:" + _err "$response" + return 1 + fi + _debug response "$response" + _info "Certificate successfully deployed" } From 6963f3880d1e06211bc8c631154868efa8c6bafb Mon Sep 17 00:00:00 2001 From: RaidenII Date: Mon, 3 Jul 2017 03:28:28 -0700 Subject: [PATCH 1025/1348] Fixes the get_root function so that when domain doesn't exist it will correctly return error. --- dnsapi/dns_namecom.sh | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 146db4f6..fae56d65 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -168,21 +168,26 @@ _namecom_get_root() { i=2 p=1 - if _namecom_rest GET "domain/list"; then - while true; do - host=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$host" ]; then - return 1 - fi - - if _contains "$response" "$host"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$host" - return 0 - fi - p=$i - i=$(_math "$i" + 1) - done + if ! _namecom_rest GET "domain/list"; then + return 1 fi + + # Need to exclude the last field (tld) + numfields=$(echo "$domain" | _egrep_o "\." | wc -l) + while [ $i -le $numfields ]; do + host=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug host "$host" + if [ -z "$host" ]; then + return 1 + fi + + if _contains "$response" "$host"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$host" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done return 1 } From 7b32bbfc266015b69a3dfc316e03097add2bdd3e Mon Sep 17 00:00:00 2001 From: RaidenII Date: Mon, 3 Jul 2017 08:22:16 -0400 Subject: [PATCH 1026/1348] Fix for SC2086. --- dnsapi/dns_namecom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index fae56d65..3af8bf4c 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -174,7 +174,7 @@ _namecom_get_root() { # Need to exclude the last field (tld) numfields=$(echo "$domain" | _egrep_o "\." | wc -l) - while [ $i -le $numfields ]; do + while [ $i -le "$numfields" ]; do host=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug host "$host" if [ -z "$host" ]; then From 5f8b60a0e5653595689703fe68d9b3e99d14d1ab Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Jul 2017 08:23:09 +0800 Subject: [PATCH 1027/1348] fix https://github.com/Neilpang/acme.sh/issues/926 don't trigger validation for dns manually mode --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index fa090cdf..ef468a45 100755 --- a/acme.sh +++ b/acme.sh @@ -3543,11 +3543,11 @@ issue() { if [ "$d_api" ]; then _info "Found domain api file: $d_api" else - _err "Add the following TXT record:" - _err "Domain: '$(__green "$txtdomain")'" - _err "TXT value: '$(__green "$txt")'" - _err "Please be aware that you prepend _acme-challenge. before your domain" - _err "so the resulting subdomain will be: $txtdomain" + _info "$(__red "Add the following TXT record:")" + _info "$(__red "Domain: '$(__green "$txtdomain")'")" + _info "$(__red "TXT value: '$(__green "$txt")'")" + _info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")" + _info "$(__red "so the resulting subdomain will be: $txtdomain")" continue fi @@ -3583,7 +3583,7 @@ issue() { _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup - _on_issue_err "$_post_hook" "$vlist" + _on_issue_err "$_post_hook" return 1 fi From 81772fb703af18f7d7f8d7b7b7e3a6d61be14554 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 4 Jul 2017 09:08:54 +0800 Subject: [PATCH 1028/1348] minor, fix format --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index ef468a45..35842f4e 100755 --- a/acme.sh +++ b/acme.sh @@ -3544,10 +3544,10 @@ issue() { _info "Found domain api file: $d_api" else _info "$(__red "Add the following TXT record:")" - _info "$(__red "Domain: '$(__green "$txtdomain")'")" - _info "$(__red "TXT value: '$(__green "$txt")'")" - _info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")" - _info "$(__red "so the resulting subdomain will be: $txtdomain")" + _info "$(__red "Domain: '$(__green "$txtdomain")'")" + _info "$(__red "TXT value: '$(__green "$txt")'")" + _info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")" + _info "$(__red "so the resulting subdomain will be: $txtdomain")" continue fi From 72fcf5ab85779aca28db1f4057e63d4e9ea850d4 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 7 Jul 2017 09:51:43 -0500 Subject: [PATCH 1029/1348] Add 'dns_dyn' DNS challenge validation script for Dyn Managed DNS API --- dnsapi/README.md | 33 +++++ dnsapi/dns_dyn.sh | 340 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 373 insertions(+) create mode 100644 dnsapi/dns_dyn.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 57c360b7..41f89a88 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -540,6 +540,39 @@ acme.sh --issue --dns dns_namecom -d example.com -d www.example.com For issues, please report to https://github.com/raidenii/acme.sh/issues. +## 29. Use Dyn Managed DNS API to automatically issue cert + +First, login to your Dyn Managed DNS account: https://portal.dynect.net/login/ + +It is recommended to add a new user specific for API access. + +The minimum "Zones & Records Permissions" required are: +``` +RecordAdd +RecordUpdate +RecordDelete +RecordGet +ZoneGet +ZoneAddNode +ZoneRemoveNode +ZonePublish +``` + +Pass the API user credentials to the environment: +``` +export DYN_Customer="customer" +export DYN_Username="apiuser" +export DYN_Password="secret" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_dyn -d example.com -d www.example.com +``` + +The `DYN_Customer`, `DYN_Username` and `DYN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh new file mode 100644 index 00000000..d3998809 --- /dev/null +++ b/dnsapi/dns_dyn.sh @@ -0,0 +1,340 @@ +#!/usr/bin/env sh +# +# Dyn.com Domain API +# +# Author: Gerd Naschenweng +# https://github.com/magicdude4eva +# +# Dyn Managed DNS API +# https://help.dyn.com/dns-api-knowledge-base/ +# +# It is recommended to add a "Dyn Managed DNS" user specific for API access. +# The "Zones & Records Permissions" required by this script are: +# -- +# RecordAdd +# RecordUpdate +# RecordDelete +# RecordGet +# ZoneGet +# ZoneAddNode +# ZoneRemoveNode +# ZonePublish +# -- +# +# Pass credentials before "acme.sh --issue --dns dns_dyn ..." +# -- +# export DYN_Customer="customer" +# export DYN_Username="apiuser" +# export DYN_Password="secret" +# -- + +DYN_API="https://api.dynect.net/REST" + +#REST_API +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "Challenge-code" +dns_dyn_add() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable DYN_Customer "$DYN_Customer" + _saveaccountconf_mutable DYN_Username "$DYN_Username" + _saveaccountconf_mutable DYN_Password "$DYN_Password" + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_add_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dyn_rm() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_record_id; then + _dyn_end_session + return 1 + fi + + if [ -z "$_dyn_record_id" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_rm_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#################### Private functions below ################################## + +#get Auth-Token +_dyn_get_authtoken() { + + _info "Start Dyn API Session" + + data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}" + dyn_url="$DYN_API/Session/" + method="POST" + + _debug data "$data" + _debug dyn_url "$dyn_url" + + export _H1="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | head -n 1 | sed 's#^"token" *: *"##')" + _info "Token received" + _debug _dyn_authtoken "$_dyn_authtoken" + return 0 + fi + + _dyn_authtoken="" + _err "get token failed" + return 1 +} + +#fulldomain=_acme-challenge.www.domain.com +#returns +# _dyn_zone=domain.com +_dyn_get_zone() { + i=2 + while true; do + domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")" + if [ -z "$domain" ]; then + break + fi + + dyn_url="$DYN_API/Zone/$domain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug dyn_url "$dyn_url" + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_zone="$domain" + return 0 + fi + i=$(_math "$i" + 1) + done + + _dyn_zone="" + _err "get zone failed" + return 1 +} + +#add TXT record +_dyn_add_record() { + + _info "Adding TXT record" + + data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}" + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + method="POST" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT Record successfully added" + return 0 + fi + + _err "add TXT record failed" + return 1 +} + +#publish the zone +_dyn_publish_zone() { + + _info "Publishing zone" + + data="{\"publish\":\"true\"}" + dyn_url="$DYN_API/Zone/$_dyn_zone/" + method="PUT" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "Zone published" + return 0 + fi + + _err "publish zone failed" + return 1 +} + +#get record_id of TXT record so we can delete the record +_dyn_get_record_id() { + + _info "Getting record_id of TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | head -n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" + _debug _dyn_record_id "$_dyn_record_id" + return 0 + fi + + _dyn_record_id="" + _err "getting record_id failed" + return 1 +} + +#delete TXT record +_dyn_rm_record() { + + _info "Deleting TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT record successfully deleted" + return 0 + fi + + _err "delete TXT record failed" + return 1 +} + +#logout +_dyn_end_session() { + + _info "End Dyn API Session" + + dyn_url="$DYN_API/Session/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + + _debug response "$response" + + _dyn_authtoken="" + return 0 +} + From 0aba5dc8de914cae7256cacdc189e2f31e491b74 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 7 Jul 2017 10:22:20 -0500 Subject: [PATCH 1030/1348] dns_dyn.sh, remove empty line at end --- dnsapi/dns_dyn.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh index d3998809..c0dc1c74 100644 --- a/dnsapi/dns_dyn.sh +++ b/dnsapi/dns_dyn.sh @@ -337,4 +337,3 @@ _dyn_end_session() { _dyn_authtoken="" return 0 } - From 528d2f29d34a3d9e417a91f02ffde35cc63b2476 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 7 Jul 2017 10:33:24 -0500 Subject: [PATCH 1031/1348] dns_dyn.sh, remove trailing spaces at end of line --- dnsapi/dns_dyn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh index c0dc1c74..e1120018 100644 --- a/dnsapi/dns_dyn.sh +++ b/dnsapi/dns_dyn.sh @@ -240,7 +240,7 @@ _dyn_publish_zone() { _info "Publishing zone" - data="{\"publish\":\"true\"}" + data="{\"publish\":\"true\"}" dyn_url="$DYN_API/Zone/$_dyn_zone/" method="PUT" From 13a8c309f5b4de09ac263a5ad2ae0cbeed044f30 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 8 Jul 2017 09:20:12 +0800 Subject: [PATCH 1032/1348] fix new shellcheck errors --- .travis.yml | 2 +- dnsapi/dns_aws.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f7e120c..2ba02b9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ script: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 800c3d09..40782573 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -208,7 +208,7 @@ aws_rest() { kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" _debug2 kServiceH "$kServiceH" - kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)" + kSigningH="$(printf "%s" "aws4_request" | _hmac "$Hash" "$kServiceH" hex)" _debug2 kSigningH "$kSigningH" signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" From 0b797f596409683f90ed4fd1354f4027d3bf7b3c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 8 Jul 2017 14:12:31 +0800 Subject: [PATCH 1033/1348] fix new shellcheck error --- dnsapi/dns_infoblox.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 06ac87ec..4cbb2146 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -41,10 +41,10 @@ dns_infoblox_add() { export _H2="Authorization: Basic $Infoblox_CredsEncoded" ## Add the challenge record to the Infoblox grid member - result=$(_post "" "$baseurlnObject" "" "POST") + result="$(_post "" "$baseurlnObject" "" "POST")" ## Let's see if we get something intelligible back from the unit - if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then _info "Successfully created the txt record" return 0 else @@ -66,7 +66,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)" ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -74,17 +74,17 @@ dns_infoblox_rm() { ## Does the record exist? Let's check. baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty" - result=$(_get "$baseurlnObject") + result="$(_get "$baseurlnObject")" ## Let's see if we get something intelligible back from the grid - if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then ## Extract the object reference - objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View") + objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! - rmResult=$(_post "" "$objRmUrl" "" "DELETE") + rmResult="$(_post "" "$objRmUrl" "" "DELETE")" ## Let's see if that worked - if echo "$rmResult" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then _info "Successfully deleted $objRef" return 0 else From 200287254bce74e8deb1f28da611de432015c837 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 8 Jul 2017 17:25:01 +0800 Subject: [PATCH 1034/1348] add deactivate-account --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 8f363852..5849eb46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,6 +44,7 @@ RUN for verb in help \ create-domain-key \ createCSR \ deactivate \ + deactivate-account \ ; 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 From babe884b7c7a3b599defc37ff1e392d4c61bd6ad Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Sat, 8 Jul 2017 06:39:18 -0500 Subject: [PATCH 1035/1348] Replace 'head -n' with the '_head_n' function --- dnsapi/dns_dyn.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh index e1120018..024e0a38 100644 --- a/dnsapi/dns_dyn.sh +++ b/dnsapi/dns_dyn.sh @@ -156,13 +156,13 @@ _dyn_get_authtoken() { export _H1="Content-Type: application/json" response="$(_post "$data" "$dyn_url" "" "$method")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" if [ "$sessionstatus" = "success" ]; then - _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | head -n 1 | sed 's#^"token" *: *"##')" + _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" _info "Token received" _debug _dyn_authtoken "$_dyn_authtoken" return 0 @@ -190,7 +190,7 @@ _dyn_get_zone() { export _H2="Content-Type: application/json" response="$(_get "$dyn_url" "" "")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug dyn_url "$dyn_url" _debug response "$response" @@ -221,7 +221,7 @@ _dyn_add_record() { export _H2="Content-Type: application/json" response="$(_post "$data" "$dyn_url" "" "$method")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" @@ -248,7 +248,7 @@ _dyn_publish_zone() { export _H2="Content-Type: application/json" response="$(_post "$data" "$dyn_url" "" "$method")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" @@ -273,13 +273,13 @@ _dyn_get_record_id() { export _H2="Content-Type: application/json" response="$(_get "$dyn_url" "" "")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" if [ "$sessionstatus" = "success" ]; then - _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | head -n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" + _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" _debug _dyn_record_id "$_dyn_record_id" return 0 fi @@ -303,7 +303,7 @@ _dyn_rm_record() { export _H2="Content-Type: application/json" response="$(_post "" "$dyn_url" "" "$method")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" From 9bd2d927559fce8fe393cfb935f96c7fd6fc8723 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Sat, 8 Jul 2017 06:43:21 -0500 Subject: [PATCH 1036/1348] Update main README.md DNS API list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7780b9ab..5c306a59 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,7 @@ You don't have to do anything manually! 1. NS1.com API 1. DuckDNS.org API 1. Name.com API +1. Dyn Managed DNS API And: From 42b2adc03ed35a54f6cb2a237dd37f0e498774f2 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 7 Jul 2017 09:51:43 -0500 Subject: [PATCH 1037/1348] Add 'dns_dyn' DNS challenge validation script for Dyn Managed DNS API dns_dyn.sh, remove empty line at end dns_dyn.sh, remove trailing spaces at end of line Replace 'head -n' with the '_head_n' function Update main README.md DNS API list --- .travis.yml | 2 +- Dockerfile | 1 + README.md | 1 + dnsapi/README.md | 33 ++++ dnsapi/dns_aws.sh | 2 +- dnsapi/dns_dyn.sh | 339 +++++++++++++++++++++++++++++++++++++++++ dnsapi/dns_infoblox.sh | 16 +- 7 files changed, 384 insertions(+), 10 deletions(-) create mode 100644 dnsapi/dns_dyn.sh diff --git a/.travis.yml b/.travis.yml index 7f7e120c..2ba02b9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ script: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/Dockerfile b/Dockerfile index 8f363852..5849eb46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,6 +44,7 @@ RUN for verb in help \ create-domain-key \ createCSR \ deactivate \ + deactivate-account \ ; 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 diff --git a/README.md b/README.md index 7780b9ab..5c306a59 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,7 @@ You don't have to do anything manually! 1. NS1.com API 1. DuckDNS.org API 1. Name.com API +1. Dyn Managed DNS API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 57c360b7..41f89a88 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -540,6 +540,39 @@ acme.sh --issue --dns dns_namecom -d example.com -d www.example.com For issues, please report to https://github.com/raidenii/acme.sh/issues. +## 29. Use Dyn Managed DNS API to automatically issue cert + +First, login to your Dyn Managed DNS account: https://portal.dynect.net/login/ + +It is recommended to add a new user specific for API access. + +The minimum "Zones & Records Permissions" required are: +``` +RecordAdd +RecordUpdate +RecordDelete +RecordGet +ZoneGet +ZoneAddNode +ZoneRemoveNode +ZonePublish +``` + +Pass the API user credentials to the environment: +``` +export DYN_Customer="customer" +export DYN_Username="apiuser" +export DYN_Password="secret" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_dyn -d example.com -d www.example.com +``` + +The `DYN_Customer`, `DYN_Username` and `DYN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 800c3d09..40782573 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -208,7 +208,7 @@ aws_rest() { kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" _debug2 kServiceH "$kServiceH" - kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)" + kSigningH="$(printf "%s" "aws4_request" | _hmac "$Hash" "$kServiceH" hex)" _debug2 kSigningH "$kSigningH" signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh new file mode 100644 index 00000000..024e0a38 --- /dev/null +++ b/dnsapi/dns_dyn.sh @@ -0,0 +1,339 @@ +#!/usr/bin/env sh +# +# Dyn.com Domain API +# +# Author: Gerd Naschenweng +# https://github.com/magicdude4eva +# +# Dyn Managed DNS API +# https://help.dyn.com/dns-api-knowledge-base/ +# +# It is recommended to add a "Dyn Managed DNS" user specific for API access. +# The "Zones & Records Permissions" required by this script are: +# -- +# RecordAdd +# RecordUpdate +# RecordDelete +# RecordGet +# ZoneGet +# ZoneAddNode +# ZoneRemoveNode +# ZonePublish +# -- +# +# Pass credentials before "acme.sh --issue --dns dns_dyn ..." +# -- +# export DYN_Customer="customer" +# export DYN_Username="apiuser" +# export DYN_Password="secret" +# -- + +DYN_API="https://api.dynect.net/REST" + +#REST_API +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "Challenge-code" +dns_dyn_add() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable DYN_Customer "$DYN_Customer" + _saveaccountconf_mutable DYN_Username "$DYN_Username" + _saveaccountconf_mutable DYN_Password "$DYN_Password" + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_add_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dyn_rm() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_record_id; then + _dyn_end_session + return 1 + fi + + if [ -z "$_dyn_record_id" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_rm_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#################### Private functions below ################################## + +#get Auth-Token +_dyn_get_authtoken() { + + _info "Start Dyn API Session" + + data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}" + dyn_url="$DYN_API/Session/" + method="POST" + + _debug data "$data" + _debug dyn_url "$dyn_url" + + export _H1="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" + _info "Token received" + _debug _dyn_authtoken "$_dyn_authtoken" + return 0 + fi + + _dyn_authtoken="" + _err "get token failed" + return 1 +} + +#fulldomain=_acme-challenge.www.domain.com +#returns +# _dyn_zone=domain.com +_dyn_get_zone() { + i=2 + while true; do + domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")" + if [ -z "$domain" ]; then + break + fi + + dyn_url="$DYN_API/Zone/$domain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug dyn_url "$dyn_url" + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_zone="$domain" + return 0 + fi + i=$(_math "$i" + 1) + done + + _dyn_zone="" + _err "get zone failed" + return 1 +} + +#add TXT record +_dyn_add_record() { + + _info "Adding TXT record" + + data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}" + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + method="POST" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT Record successfully added" + return 0 + fi + + _err "add TXT record failed" + return 1 +} + +#publish the zone +_dyn_publish_zone() { + + _info "Publishing zone" + + data="{\"publish\":\"true\"}" + dyn_url="$DYN_API/Zone/$_dyn_zone/" + method="PUT" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "Zone published" + return 0 + fi + + _err "publish zone failed" + return 1 +} + +#get record_id of TXT record so we can delete the record +_dyn_get_record_id() { + + _info "Getting record_id of TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" + _debug _dyn_record_id "$_dyn_record_id" + return 0 + fi + + _dyn_record_id="" + _err "getting record_id failed" + return 1 +} + +#delete TXT record +_dyn_rm_record() { + + _info "Deleting TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT record successfully deleted" + return 0 + fi + + _err "delete TXT record failed" + return 1 +} + +#logout +_dyn_end_session() { + + _info "End Dyn API Session" + + dyn_url="$DYN_API/Session/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + + _debug response "$response" + + _dyn_authtoken="" + return 0 +} diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 06ac87ec..4cbb2146 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -41,10 +41,10 @@ dns_infoblox_add() { export _H2="Authorization: Basic $Infoblox_CredsEncoded" ## Add the challenge record to the Infoblox grid member - result=$(_post "" "$baseurlnObject" "" "POST") + result="$(_post "" "$baseurlnObject" "" "POST")" ## Let's see if we get something intelligible back from the unit - if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then _info "Successfully created the txt record" return 0 else @@ -66,7 +66,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)" ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -74,17 +74,17 @@ dns_infoblox_rm() { ## Does the record exist? Let's check. baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty" - result=$(_get "$baseurlnObject") + result="$(_get "$baseurlnObject")" ## Let's see if we get something intelligible back from the grid - if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then ## Extract the object reference - objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View") + objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! - rmResult=$(_post "" "$objRmUrl" "" "DELETE") + rmResult="$(_post "" "$objRmUrl" "" "DELETE")" ## Let's see if that worked - if echo "$rmResult" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then _info "Successfully deleted $objRef" return 0 else From 3bf2e89a1a9f68188264aa7cbf0f1b2e17400566 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:35:22 +0300 Subject: [PATCH 1038/1348] add pdd.yandex.ru dns api --- dnsapi/dns_yandex.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 dnsapi/dns_yandex.sh diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh new file mode 100755 index 00000000..db38eb52 --- /dev/null +++ b/dnsapi/dns_yandex.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env sh +# Author: non7top@gmail.com +# 07 Jul 2017 +# report bugs at https://github.com/non7top/acme.sh + +# Values to export: +# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_yandex_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" + _PDD_credentials + export _H1="PddToken: $PDD_Token" + + curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" + curUri="https://pddimp.yandex.ru/api2/admin/dns/add" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" +} + +#Usage: dns_myapi_rm _acme-challenge.www.domain.com +dns_yandex_rm() { + fulldomain="${1}" + _debug "Calling: dns_yandex_rm() '${fulldomain}'" + _PDD_credentials + export _H1="PddToken: $PDD_Token" + local record_id=$( pdd_get_record_id ${fulldomain} ) + + curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" + curData="domain=${curDomain}&record_id=${record_id}" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" +} + +#################### Private functions below ################################## + +_PDD_credentials() { + if [ -z "${PDD_Token}" ]; then + PDD_Token="" + _err "You haven't specified the ISPConfig Login data." + return 1 + else + _saveaccountconf PDD_Token "${PDD_Token}" + fi +} + +pdd_get_record_id() { + local fulldomain="${1}" + local curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + local curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" + local curResult="$(_get "${curUri}")" + echo ${curResult} | \ +python -c ' +import sys, json; +rs=json.load(sys.stdin)["records"] +for r in rs: + if r["fqdn"]=="${fulldomain}": + print r["record_id"] + exit +' +} From 6445a7674bd31e521e1eec12d16def544893dd69 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:52:47 +0300 Subject: [PATCH 1039/1348] fix syntax --- dnsapi/dns_yandex.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index db38eb52..a792d495 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - local record_id=$( pdd_get_record_id ${fulldomain} ) + record_id=$( pdd_get_record_id ${fulldomain} ) - curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -53,17 +53,17 @@ _PDD_credentials() { } pdd_get_record_id() { - local fulldomain="${1}" - local curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - local curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" - local curResult="$(_get "${curUri}")" + fulldomain="${1}" + curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" + curResult="$(_get "${curUri}")" echo ${curResult} | \ -python -c ' + python -c " import sys, json; -rs=json.load(sys.stdin)["records"] +rs=json.load(sys.stdin)[\"records\"] for r in rs: - if r["fqdn"]=="${fulldomain}": - print r["record_id"] + if r[\"fqdn\"]==\"${fulldomain}\": + print r[\"record_id\"] exit -' +" } From a2038ab07e485153ac5b73fb5a8991d6c01c2352 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:57:27 +0300 Subject: [PATCH 1040/1348] fix syntax --- dnsapi/dns_yandex.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index a792d495..1b4b9ae3 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" + curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - record_id=$( pdd_get_record_id ${fulldomain} ) + record_id=$( pdd_get_record_id "${fulldomain}" ) - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" + curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -57,8 +57,8 @@ pdd_get_record_id() { curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}")" - echo ${curResult} | \ - python -c " + echo "${curResult}" \ + | python -c " import sys, json; rs=json.load(sys.stdin)[\"records\"] for r in rs: From bd41f50ba5e7bd55f78fd3658da1470c57a33f0e Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 22:02:34 +0300 Subject: [PATCH 1041/1348] fix formatting --- dnsapi/dns_yandex.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 1b4b9ae3..077e6614 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - record_id=$( pdd_get_record_id "${fulldomain}" ) + record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -54,11 +54,11 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}")" echo "${curResult}" \ - | python -c " + | python -c " import sys, json; rs=json.load(sys.stdin)[\"records\"] for r in rs: From 8f3a3b293d46708eef7c6b5018379d721d82e815 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:00:42 +0300 Subject: [PATCH 1042/1348] add newline and checks --- dnsapi/dns_yandex.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 077e6614..fc707816 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -13,7 +13,7 @@ dns_yandex_add() { fulldomain="${1}" txtvalue="${2}" _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - _PDD_credentials + _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" @@ -28,7 +28,7 @@ dns_yandex_add() { dns_yandex_rm() { fulldomain="${1}" _debug "Calling: dns_yandex_rm() '${fulldomain}'" - _PDD_credentials + _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") @@ -67,3 +67,4 @@ for r in rs: exit " } + From 256cb90f3cf878086fa14b21f0379a11344b8cec Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:15:01 +0300 Subject: [PATCH 1043/1348] remove awk --- dnsapi/dns_yandex.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index fc707816..f6a7248e 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" - curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -32,8 +32,8 @@ dns_yandex_rm() { export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" - curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" From 9ec54ef89b50fd2367706c7d1747ccc9d36c63ca Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:21:55 +0300 Subject: [PATCH 1044/1348] shfmt fixes --- dnsapi/dns_yandex.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index f6a7248e..664da77b 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -32,8 +32,8 @@ dns_yandex_rm() { export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -67,4 +67,3 @@ for r in rs: exit " } - From 266e9d06194c7eea0dd7854fd7c8fa9da680fcce Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 20:00:02 +0300 Subject: [PATCH 1045/1348] remove python --- dnsapi/dns_yandex.sh | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 664da77b..2a47150c 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -31,6 +31,7 @@ dns_yandex_rm() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") + _debug "Result: $record_id" curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" @@ -54,16 +55,10 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" - curResult="$(_get "${curUri}")" - echo "${curResult}" \ - | python -c " -import sys, json; -rs=json.load(sys.stdin)[\"records\"] -for r in rs: - if r[\"fqdn\"]==\"${fulldomain}\": - print r[\"record_id\"] - exit -" + curResult="$(_get "${curUri}" | _normalizeJson)" + _debug "Result: $curResult" + echo "$curResult" | grep -o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' } From 796647158ea23ebf673d817a254e1d61c7ce652c Mon Sep 17 00:00:00 2001 From: Santeri Date: Mon, 10 Jul 2017 15:36:16 +0400 Subject: [PATCH 1046/1348] Removed double quotes from _opt Broke GoDaddy cpanel causing error (thanks Hedgehog) --- deploy/cpanel.sh | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/deploy/cpanel.sh b/deploy/cpanel.sh index 6ab012a3..b9552397 100644 --- a/deploy/cpanel.sh +++ b/deploy/cpanel.sh @@ -1,12 +1,12 @@ -#!/bin/bash +#!/usr/bin/env sh # Here is the script to deploy the cert to your cpanel using the cpanel API. -# Uses command line uapi. Cpanel username is needed only when run as root. -# Returns 0 when success, otherwise error. +# Uses command line uapi. +# Cpanel username is needed only when run as root (I did not test this). +# Returns 0 when success. # Written by Santeri Kannisto # Public domain, 2017 #export DEPLOY_CPANEL_USER=myusername -#export DEPLOY_CPANEL_PASSWORD=PASSWORD ######## Public functions ##################### @@ -26,32 +26,28 @@ cpanel_deploy() { _debug _cfullchain "$_cfullchain" # read cert and key files and urlencode both - _certstr=`cat "$_ccert"` - _keystr=`cat "$_ckey"` + _certstr=$(cat "$_ccert") + _keystr=$(cat "$_ckey") _cert=$(php -r "echo urlencode(\"$_certstr\");") _key=$(php -r "echo urlencode(\"$_keystr\");") _debug _cert "$_cert" _debug _key "$_key" - if [[ $EUID -eq 0 ]] - then - _opt="--user=$DEPLOY_CPANEL_USER SSL install_ssl" - else - _opt="SSL install_ssl" - fi - - _debug _opt "$_opt" + if [ "$(id -u)" = 0 ]; then + _opt="--user=$DEPLOY_CPANEL_USER" + _debug _opt "$_opt" + fi - response=$(uapi $_opt domain="$_cdommain" cert="$_cert" key="$_key") + _response=$(uapi $_opt SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") - if [ $? -ne 0 ] - then + if [ $? -ne 0 ]; then _err "Error in deploying certificate:" - _err "$response" + _err "$_response" return 1 fi - _debug response "$response" + _debug response "$_response" _info "Certificate successfully deployed" + return 0 } From c4d0aec536dcd8886579d7f528f85217304c7366 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 10 Jul 2017 19:51:55 +0800 Subject: [PATCH 1047/1348] do not retry for a invalid cert in cronjob. fix https://github.com/Neilpang/acme.sh/issues/939 --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 35842f4e..486f8678 100755 --- a/acme.sh +++ b/acme.sh @@ -4033,6 +4033,11 @@ renew() { return "$RENEW_SKIP" fi + if [ "$IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then + _info "Skip invalid cert for: $Le_Domain" + return 0 + fi + IS_RENEW="1" issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" res="$?" From a577c7215f0b2a5ad6729b175fb6e0033abeb4d5 Mon Sep 17 00:00:00 2001 From: Santeri Date: Mon, 10 Jul 2017 16:43:42 +0400 Subject: [PATCH 1048/1348] One more change to pass the check shellcheck test Now it is tested and works also when run as a root. --- deploy/cpanel.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/deploy/cpanel.sh b/deploy/cpanel.sh index b9552397..9de8dbbb 100644 --- a/deploy/cpanel.sh +++ b/deploy/cpanel.sh @@ -1,7 +1,6 @@ #!/usr/bin/env sh # Here is the script to deploy the cert to your cpanel using the cpanel API. -# Uses command line uapi. -# Cpanel username is needed only when run as root (I did not test this). +# Uses command line uapi. --user option is needed only if run as root. # Returns 0 when success. # Written by Santeri Kannisto # Public domain, 2017 @@ -35,12 +34,11 @@ cpanel_deploy() { _debug _key "$_key" if [ "$(id -u)" = 0 ]; then - _opt="--user=$DEPLOY_CPANEL_USER" - _debug _opt "$_opt" + _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") + else + _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") fi - _response=$(uapi $_opt SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") - if [ $? -ne 0 ]; then _err "Error in deploying certificate:" _err "$_response" From 10cb7585a7140c7f709e2dcdee27913a55503545 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Tue, 11 Jul 2017 02:19:39 +0300 Subject: [PATCH 1049/1348] fix egrep and exit --- dnsapi/dns_yandex.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 2a47150c..d2ccf18e 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -13,7 +13,7 @@ dns_yandex_add() { fulldomain="${1}" txtvalue="${2}" _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - _PDD_credentials || exit 1 + _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" @@ -28,7 +28,7 @@ dns_yandex_add() { dns_yandex_rm() { fulldomain="${1}" _debug "Calling: dns_yandex_rm() '${fulldomain}'" - _PDD_credentials || exit 1 + _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" @@ -60,5 +60,5 @@ pdd_get_record_id() { curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" _debug "Result: $curResult" - echo "$curResult" | grep -o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' + echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' } From e6a95ecd0889779a39e988b392dcdd9568f34798 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Wed, 12 Jul 2017 03:51:48 +0300 Subject: [PATCH 1050/1348] rework root domain detection --- dnsapi/dns_yandex.sh | 57 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index d2ccf18e..4b00219b 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,9 @@ dns_yandex_add() { _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -33,8 +34,10 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -43,10 +46,47 @@ dns_yandex_rm() { #################### Private functions below ################################## +_PDD_get_domain() { + fulldomain="${1}" + __page=1 + __last=0 + while [ $__last -eq 0 ]; do + uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" + res1=$(_get $uri1 | _normalizeJson) + #_debug "$res1" + __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') + _debug "found: $__found results on page" + if [ $__found -lt 20 ]; then + _debug "last page: $__page" + __last=1 + fi + + __all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" + + __page=$(_math $__page + 1) + done + + k=2 + while [ $k -lt 10 ]; do + __t=$(echo "$fulldomain" | cut -d . -f $k-100) + _debug "finding zone for domain $__t" + for d in $__all_domains; do + if [ "$d" == "$__t" ]; then + echo "$__t" + return + fi + done + k=$(_math $k + 1) + done + _err "No suitable domain found in your account" + return 1 +} + _PDD_credentials() { if [ -z "${PDD_Token}" ]; then PDD_Token="" - _err "You haven't specified the ISPConfig Login data." + _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx" + _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token" return 1 else _saveaccountconf PDD_Token "${PDD_Token}" @@ -55,8 +95,11 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" + curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" _debug "Result: $curResult" From 6a9b4db448775b59913563aaeb3280296a0febc3 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Wed, 12 Jul 2017 04:07:18 +0300 Subject: [PATCH 1051/1348] fix formatting --- dnsapi/dns_yandex.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 4b00219b..eb60d5af 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,7 +16,7 @@ dns_yandex_add() { _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" @@ -34,7 +34,7 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" @@ -52,11 +52,11 @@ _PDD_get_domain() { __last=0 while [ $__last -eq 0 ]; do uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" - res1=$(_get $uri1 | _normalizeJson) + res1=$(_get "$uri1" | _normalizeJson) #_debug "$res1" __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') _debug "found: $__found results on page" - if [ $__found -lt 20 ]; then + if [ "$__found" -lt 20 ]; then _debug "last page: $__page" __last=1 fi @@ -71,7 +71,7 @@ _PDD_get_domain() { __t=$(echo "$fulldomain" | cut -d . -f $k-100) _debug "finding zone for domain $__t" for d in $__all_domains; do - if [ "$d" == "$__t" ]; then + if [ "$d" = "$__t" ]; then echo "$__t" return fi @@ -96,7 +96,7 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" From 7d64e141e45be32479773f8a4fb44bd8304dacc1 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Wed, 12 Jul 2017 20:24:54 +0200 Subject: [PATCH 1052/1348] Add dns_he - DNS API script for Hurricane Electric DNS service ... Although not yet fully Posix compatible. --- dnsapi/README.md | 18 +++++ dnsapi/dns_he.sh | 200 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100755 dnsapi/dns_he.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 41f89a88..15399048 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -572,6 +572,24 @@ acme.sh --issue --dns dns_dyn -d example.com -d www.example.com The `DYN_Customer`, `DYN_Username` and `DYN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +# 30. Use Hurricane Electric + +Hurricane Electric doesn't have an API so just set your login credentials like so: + +``` +export HE_Username="yourusername" +export HE_Password="password" +``` + +Then you can issue your certificate: + +``` +acme.sh --issue --dns dns_he -d example.com -d www.example.com +``` + +The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +Please report any issues to https://github.com/angel333/acme.sh or to . # Use custom API diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh new file mode 100755 index 00000000..269db8d2 --- /dev/null +++ b/dnsapi/dns_he.sh @@ -0,0 +1,200 @@ +#!/usr/bin/env sh + +# TODO Somehow use _get instead of curl - not sure how to support +# cookies though... + +######################################################################## +# Hurricane Electric hook script for acme.sh +# +# Environment variables: +# +# - $HE_Username (your dns.he.net username) +# - $HE_Password (your dns.he.net password) +# +# Author: Ondrej Simek +# Git repo: https://github.com/angel333/acme.sh + + +#-- dns_he_add() - Add TXT record -------------------------------------- +# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..." + +dns_he_add() { + _full_domain=$1 + _txt_value=$2 + _info "Using DNS-01 Hurricane Electric hook" + + _authenticate || return 1 + _saveaccountconf HE_Username "$HE_Username" + _saveaccountconf HE_Password "$HE_Password" + + # fills in the $_zone_id + _find_zone $_full_domain || return 1 + _debug "Zone id \"$_zone_id\" will be used." + + curl -L --silent --show-error --cookie "$_he_cookie" \ + --form "account=" \ + --form "menu=edit_zone" \ + --form "Type=TXT" \ + --form "hosted_dns_zoneid=$_zone_id" \ + --form "hosted_dns_recordid=" \ + --form "hosted_dns_editzone=1" \ + --form "Priority=" \ + --form "Name=$_full_domain" \ + --form "Content=$_txt_value" \ + --form "TTL=300" \ + --form "hosted_dns_editrecord=Submit" \ + "https://dns.he.net/" \ + > /dev/null +} + + +#-- dns_he_rm() - Remove TXT record ------------------------------------ +# Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..." + +dns_he_rm() { + _full_domain=$1 + _txt_value=$2 + _info "Cleaning up after DNS-01 Hurricane Electric hook" + + _authenticate || return 1 + + # fills in the $_zone_id + _find_zone $_full_domain || return 1 + _debug "Zone id \"$_zone_id\" will be used." + + # Find the record id to clean + _record_id=$( \ + curl -L --silent --show-error --cookie "$_he_cookie" \ + "https://dns.he.net/?hosted_dns_zoneid=$_zone_id&menu=edit_zone&hosted_dns_editzone" \ + | grep -A 1 "data=\"\("\)\?${_txt_value}\("\)\?\"" \ + | tail -n 1 \ + | _egrep_o "'[[:digit:]]+','[^']+','TXT'" \ + | cut -b 2- \ + | _egrep_o "[[:digit:]]+" \ + | head -n1) # ... oh my, what have I done... + + # Remove the record + curl -L --silent --show-error --cookie "$_he_cookie" \ + --form "menu=edit_zone" \ + --form "hosted_dns_zoneid=$_zone_id" \ + --form "hosted_dns_recordid=$_record_id" \ + --form "hosted_dns_editzone=1" \ + --form "hosted_dns_delrecord=1" \ + --form "hosted_dns_delconfirm=delete" \ + --form "hosted_dns_editzone=1" \ + "https://dns.he.net/" \ + | grep '
Successfully removed record.
' \ + > /dev/null + if [ $? -eq 0 ]; then + _info "Record removed successfuly." + else + _err \ + "Could not clean (remove) up the record. Please go to HE" \ + "administration interface and clean it by hand." + fi +} + + +########################## PRIVATE FUNCTIONS ########################### + + +#-- _find_zone() ------------------------------------------------------- + +# Usage: _authenticate +# +# - needs $HE_Username and $HE_Password +# - sets the $_he_cookie + +_authenticate() { + if [ -z "$HE_Username" ] && [ -z "$HE_Password" ]; then + _err \ + 'No auth details provided. Please set user credentials using the \ + \$HE_Username and \$HE_Password envoronment variables.' + return 1 + fi + # Just get a session + _he_cookie=$( \ + curl -L --silent --show-error -I "https://dns.he.net/" \ + | grep '^Set-Cookie:' \ + | _egrep_o 'CGISESSID=[a-z0-9]*') + # Attempt login + curl -L --silent --show-error --cookie "$_he_cookie" \ + --form "email=${HE_Username}" \ + --form "pass=${HE_Password}" \ + "https://dns.he.net/" \ + > /dev/null + # TODO detect unsuccessful logins +} + + +#-- _find_zone() ------------------------------------------------------- + +# Returns the most specific zone found in administration interface. +# +# - needs $_he_cookie +# +# Example: +# +# _find_zone first.second.third.co.uk +# +# ... will return the first zone that exists in admin out of these: +# - "first.second.third.co.uk" +# - "second.third.co.uk" +# - "third.co.uk" +# - "co.uk" <-- unlikely +# - "uk" <-' +# +# (another approach would be something like this: +# https://github.com/hlandau/acme/blob/master/_doc/dns.hook +# - that's better if there are multiple pages. It's so much simpler. +# ) + +_find_zone() { + + _domain="$1" + + ## _all_zones is an array that looks like this: + ## ( zone1:id zone2:id ... ) + _all_zones=( $(curl -L --silent --show-error --cookie "$_he_cookie" \ + "https://dns.he.net/" \ + | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ + | cut -d '"' -f 3,5 --output-delimiter=":" \ + ) ) + + _strip_counter=1 + while [ true ] + do + _attempted_zone=$(echo $_domain | cut -d . -f ${_strip_counter}-) + + # All possible zone names have been tried + if [ "$_attempted_zone" == "" ] + then + _err "No zone for domain \"$_domain\" found." + break + fi + + # Walk through all zones on the account + #echo "$_all_zones" | while IFS=' ' read _zone_name _zone_id + for i in ${_all_zones[@]} + do + _zone_name=$(echo $i | cut -d ':' -f 1) + _zone_id=$(echo $i | cut -d ':' -f 2) + if [ "$_zone_name" == "$_attempted_zone" ] + then + # Zone found - we got $_zone_name and $_zone_id, let's get out... + _debug "Found relevant zone \"$_zone_name\" with id" \ + "\"$_zone_id\" - will be used for domain \"$_domain\"." + return 0 + fi + done + + _debug "Zone \"$_attempted_zone\" doesn't exist, let's try another \ + variation." + _strip_counter=$(expr $_strip_counter + 1) + done + + # No zone found. + return 1 +} + +# vim: et:ts=2:sw=2: From accbda9d2f91c48c31f5e10ec073c44054647919 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 13 Jul 2017 20:52:44 +0800 Subject: [PATCH 1053/1348] output log --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5849eb46..7ca042ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ 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) && rm -rf /install_acme.sh/ -RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh +RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | sed 's#> /dev/null##' | crontab - RUN for verb in help \ version \ From 84a251c8c7eea52e819445c4d407fefc2b52c852 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Thu, 13 Jul 2017 17:05:57 +0300 Subject: [PATCH 1054/1348] add documentation --- README.md | 1 + dnsapi/README.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 7780b9ab..afb8a761 100644 --- a/README.md +++ b/README.md @@ -335,6 +335,7 @@ You don't have to do anything manually! 1. DNSimple API 1. NS1.com API 1. DuckDNS.org API +1. Yandex PDD API (https://pdd.yandex.ru) 1. Name.com API diff --git a/dnsapi/README.md b/dnsapi/README.md index 57c360b7..55fd65a2 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -522,6 +522,21 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. + +## 27. Use pdd.yandex.ru API + +``` +export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +``` + +Follow these instructions to get the token for your domain https://tech.yandex.com/domain/doc/concepts/access-docpage/ +``` +acme.sh --issue --dns dns_yandex -d mydomain.example.org +``` + +For issues, please report to https://github.com/non7top/acme.sh/issues. + + ## 28. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply From bdee66fe2942affb0ba0675785d6c0ef567fbf8e Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Thu, 13 Jul 2017 18:37:13 +0300 Subject: [PATCH 1055/1348] minor fixes --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 55fd65a2..71154033 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -523,7 +523,7 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. -## 27. Use pdd.yandex.ru API +## 28. Use pdd.yandex.ru API ``` export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" @@ -537,7 +537,7 @@ acme.sh --issue --dns dns_yandex -d mydomain.example.org For issues, please report to https://github.com/non7top/acme.sh/issues. -## 28. Use Name.com API +## 29. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply for API username and token. From a460ac021fadffda93359b9acab6508cafcd6c24 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:35:22 +0300 Subject: [PATCH 1056/1348] add pdd.yandex.ru dns api --- dnsapi/dns_yandex.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 dnsapi/dns_yandex.sh diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh new file mode 100755 index 00000000..db38eb52 --- /dev/null +++ b/dnsapi/dns_yandex.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env sh +# Author: non7top@gmail.com +# 07 Jul 2017 +# report bugs at https://github.com/non7top/acme.sh + +# Values to export: +# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_yandex_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" + _PDD_credentials + export _H1="PddToken: $PDD_Token" + + curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" + curUri="https://pddimp.yandex.ru/api2/admin/dns/add" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" +} + +#Usage: dns_myapi_rm _acme-challenge.www.domain.com +dns_yandex_rm() { + fulldomain="${1}" + _debug "Calling: dns_yandex_rm() '${fulldomain}'" + _PDD_credentials + export _H1="PddToken: $PDD_Token" + local record_id=$( pdd_get_record_id ${fulldomain} ) + + curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" + curData="domain=${curDomain}&record_id=${record_id}" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" +} + +#################### Private functions below ################################## + +_PDD_credentials() { + if [ -z "${PDD_Token}" ]; then + PDD_Token="" + _err "You haven't specified the ISPConfig Login data." + return 1 + else + _saveaccountconf PDD_Token "${PDD_Token}" + fi +} + +pdd_get_record_id() { + local fulldomain="${1}" + local curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + local curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" + local curResult="$(_get "${curUri}")" + echo ${curResult} | \ +python -c ' +import sys, json; +rs=json.load(sys.stdin)["records"] +for r in rs: + if r["fqdn"]=="${fulldomain}": + print r["record_id"] + exit +' +} From a09b2c0074f43e017966cb22018100774df76832 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:52:47 +0300 Subject: [PATCH 1057/1348] fix syntax --- dnsapi/dns_yandex.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index db38eb52..a792d495 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - local record_id=$( pdd_get_record_id ${fulldomain} ) + record_id=$( pdd_get_record_id ${fulldomain} ) - curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -53,17 +53,17 @@ _PDD_credentials() { } pdd_get_record_id() { - local fulldomain="${1}" - local curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - local curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" - local curResult="$(_get "${curUri}")" + fulldomain="${1}" + curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" + curResult="$(_get "${curUri}")" echo ${curResult} | \ -python -c ' + python -c " import sys, json; -rs=json.load(sys.stdin)["records"] +rs=json.load(sys.stdin)[\"records\"] for r in rs: - if r["fqdn"]=="${fulldomain}": - print r["record_id"] + if r[\"fqdn\"]==\"${fulldomain}\": + print r[\"record_id\"] exit -' +" } From e9d540779257ac5378ea594391de387393a03c84 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:57:27 +0300 Subject: [PATCH 1058/1348] fix syntax --- dnsapi/dns_yandex.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index a792d495..1b4b9ae3 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" + curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - record_id=$( pdd_get_record_id ${fulldomain} ) + record_id=$( pdd_get_record_id "${fulldomain}" ) - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" + curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -57,8 +57,8 @@ pdd_get_record_id() { curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}")" - echo ${curResult} | \ - python -c " + echo "${curResult}" \ + | python -c " import sys, json; rs=json.load(sys.stdin)[\"records\"] for r in rs: From 18cb11dcbf932fe324c9d0426546e63770cf7355 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 22:02:34 +0300 Subject: [PATCH 1059/1348] fix formatting --- dnsapi/dns_yandex.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 1b4b9ae3..077e6614 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - record_id=$( pdd_get_record_id "${fulldomain}" ) + record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -54,11 +54,11 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}")" echo "${curResult}" \ - | python -c " + | python -c " import sys, json; rs=json.load(sys.stdin)[\"records\"] for r in rs: From 42ab7a5d725109a15df5d0a049232a3f461908bc Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:00:42 +0300 Subject: [PATCH 1060/1348] add newline and checks --- dnsapi/dns_yandex.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 077e6614..fc707816 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -13,7 +13,7 @@ dns_yandex_add() { fulldomain="${1}" txtvalue="${2}" _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - _PDD_credentials + _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" @@ -28,7 +28,7 @@ dns_yandex_add() { dns_yandex_rm() { fulldomain="${1}" _debug "Calling: dns_yandex_rm() '${fulldomain}'" - _PDD_credentials + _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") @@ -67,3 +67,4 @@ for r in rs: exit " } + From d61b687853e00f72dbfc1d7137767ba0ae4fdf57 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:15:01 +0300 Subject: [PATCH 1061/1348] remove awk --- dnsapi/dns_yandex.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index fc707816..f6a7248e 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" - curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -32,8 +32,8 @@ dns_yandex_rm() { export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" - curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" From 57d1db58db275bda6e89608d5af75ae4f60320f7 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:21:55 +0300 Subject: [PATCH 1062/1348] shfmt fixes --- dnsapi/dns_yandex.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index f6a7248e..664da77b 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -32,8 +32,8 @@ dns_yandex_rm() { export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -67,4 +67,3 @@ for r in rs: exit " } - From a0df46258dfb327ff5f2de471b13d1250b4ea3e3 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 20:00:02 +0300 Subject: [PATCH 1063/1348] remove python --- dnsapi/dns_yandex.sh | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 664da77b..2a47150c 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -31,6 +31,7 @@ dns_yandex_rm() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") + _debug "Result: $record_id" curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" @@ -54,16 +55,10 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" - curResult="$(_get "${curUri}")" - echo "${curResult}" \ - | python -c " -import sys, json; -rs=json.load(sys.stdin)[\"records\"] -for r in rs: - if r[\"fqdn\"]==\"${fulldomain}\": - print r[\"record_id\"] - exit -" + curResult="$(_get "${curUri}" | _normalizeJson)" + _debug "Result: $curResult" + echo "$curResult" | grep -o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' } From fceb728501472961e73ed8bbdd292311de31cd40 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Tue, 11 Jul 2017 02:19:39 +0300 Subject: [PATCH 1064/1348] fix egrep and exit --- dnsapi/dns_yandex.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 2a47150c..d2ccf18e 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -13,7 +13,7 @@ dns_yandex_add() { fulldomain="${1}" txtvalue="${2}" _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - _PDD_credentials || exit 1 + _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" @@ -28,7 +28,7 @@ dns_yandex_add() { dns_yandex_rm() { fulldomain="${1}" _debug "Calling: dns_yandex_rm() '${fulldomain}'" - _PDD_credentials || exit 1 + _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" @@ -60,5 +60,5 @@ pdd_get_record_id() { curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" _debug "Result: $curResult" - echo "$curResult" | grep -o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' + echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' } From eb6be88fac9510aa137b3dea9e16b56aa3d10c1e Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Wed, 12 Jul 2017 03:51:48 +0300 Subject: [PATCH 1065/1348] rework root domain detection --- dnsapi/dns_yandex.sh | 57 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index d2ccf18e..4b00219b 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,9 @@ dns_yandex_add() { _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -33,8 +34,10 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -43,10 +46,47 @@ dns_yandex_rm() { #################### Private functions below ################################## +_PDD_get_domain() { + fulldomain="${1}" + __page=1 + __last=0 + while [ $__last -eq 0 ]; do + uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" + res1=$(_get $uri1 | _normalizeJson) + #_debug "$res1" + __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') + _debug "found: $__found results on page" + if [ $__found -lt 20 ]; then + _debug "last page: $__page" + __last=1 + fi + + __all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" + + __page=$(_math $__page + 1) + done + + k=2 + while [ $k -lt 10 ]; do + __t=$(echo "$fulldomain" | cut -d . -f $k-100) + _debug "finding zone for domain $__t" + for d in $__all_domains; do + if [ "$d" == "$__t" ]; then + echo "$__t" + return + fi + done + k=$(_math $k + 1) + done + _err "No suitable domain found in your account" + return 1 +} + _PDD_credentials() { if [ -z "${PDD_Token}" ]; then PDD_Token="" - _err "You haven't specified the ISPConfig Login data." + _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx" + _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token" return 1 else _saveaccountconf PDD_Token "${PDD_Token}" @@ -55,8 +95,11 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" + curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" _debug "Result: $curResult" From c848d3ee22b085a18ff52567efb7d0f213374f7b Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Wed, 12 Jul 2017 04:07:18 +0300 Subject: [PATCH 1066/1348] fix formatting --- dnsapi/dns_yandex.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 4b00219b..eb60d5af 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,7 +16,7 @@ dns_yandex_add() { _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" @@ -34,7 +34,7 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" @@ -52,11 +52,11 @@ _PDD_get_domain() { __last=0 while [ $__last -eq 0 ]; do uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" - res1=$(_get $uri1 | _normalizeJson) + res1=$(_get "$uri1" | _normalizeJson) #_debug "$res1" __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') _debug "found: $__found results on page" - if [ $__found -lt 20 ]; then + if [ "$__found" -lt 20 ]; then _debug "last page: $__page" __last=1 fi @@ -71,7 +71,7 @@ _PDD_get_domain() { __t=$(echo "$fulldomain" | cut -d . -f $k-100) _debug "finding zone for domain $__t" for d in $__all_domains; do - if [ "$d" == "$__t" ]; then + if [ "$d" = "$__t" ]; then echo "$__t" return fi @@ -96,7 +96,7 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" From 377fe5ecdeb750a95ffdb38b669d66d77ad0a03d Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Thu, 13 Jul 2017 17:05:57 +0300 Subject: [PATCH 1067/1348] add documentation --- README.md | 1 + dnsapi/README.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 5c306a59..ae73b0fe 100644 --- a/README.md +++ b/README.md @@ -335,6 +335,7 @@ You don't have to do anything manually! 1. DNSimple API 1. NS1.com API 1. DuckDNS.org API +1. Yandex PDD API (https://pdd.yandex.ru) 1. Name.com API 1. Dyn Managed DNS API diff --git a/dnsapi/README.md b/dnsapi/README.md index 41f89a88..afaf94f8 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -522,6 +522,21 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. + +## 27. Use pdd.yandex.ru API + +``` +export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +``` + +Follow these instructions to get the token for your domain https://tech.yandex.com/domain/doc/concepts/access-docpage/ +``` +acme.sh --issue --dns dns_yandex -d mydomain.example.org +``` + +For issues, please report to https://github.com/non7top/acme.sh/issues. + + ## 28. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply From 283ef9adb7a9f5f33e04ce03b6db158802a30f3a Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Thu, 13 Jul 2017 18:37:13 +0300 Subject: [PATCH 1068/1348] minor fixes --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index afaf94f8..3d571af1 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -523,7 +523,7 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. -## 27. Use pdd.yandex.ru API +## 28. Use pdd.yandex.ru API ``` export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" @@ -537,7 +537,7 @@ acme.sh --issue --dns dns_yandex -d mydomain.example.org For issues, please report to https://github.com/non7top/acme.sh/issues. -## 28. Use Name.com API +## 29. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply for API username and token. From ae302ee600b1a07bd1132676ab204df72208e15b Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Fri, 14 Jul 2017 03:51:08 +0300 Subject: [PATCH 1069/1348] reformat docs --- README.md | 2 +- dnsapi/README.md | 29 +++++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ae73b0fe..5a3a3adf 100644 --- a/README.md +++ b/README.md @@ -335,9 +335,9 @@ You don't have to do anything manually! 1. DNSimple API 1. NS1.com API 1. DuckDNS.org API -1. Yandex PDD API (https://pdd.yandex.ru) 1. Name.com API 1. Dyn Managed DNS API +1. Yandex PDD API (https://pdd.yandex.ru) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 3d571af1..d3dff12a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -522,22 +522,7 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. - -## 28. Use pdd.yandex.ru API - -``` -export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -``` - -Follow these instructions to get the token for your domain https://tech.yandex.com/domain/doc/concepts/access-docpage/ -``` -acme.sh --issue --dns dns_yandex -d mydomain.example.org -``` - -For issues, please report to https://github.com/non7top/acme.sh/issues. - - -## 29. Use Name.com API +## 28. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply for API username and token. @@ -587,6 +572,18 @@ acme.sh --issue --dns dns_dyn -d example.com -d www.example.com The `DYN_Customer`, `DYN_Username` and `DYN_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 30. Use pdd.yandex.ru API + +``` +export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +``` + +Follow these instructions to get the token for your domain https://tech.yandex.com/domain/doc/concepts/access-docpage/ +``` +acme.sh --issue --dns dns_yandex -d mydomain.example.org +``` + +For issues, please report to https://github.com/non7top/acme.sh/issues. # Use custom API From 90fd18bf423b91e6c48aa38ed1fa6dba52cde5e7 Mon Sep 17 00:00:00 2001 From: Santeri Date: Tue, 18 Jul 2017 15:48:17 +0400 Subject: [PATCH 1070/1348] Renamed script to cpanel_uapi.sh As per Neil's request. --- deploy/{cpanel.sh => cpanel_uapi.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deploy/{cpanel.sh => cpanel_uapi.sh} (100%) diff --git a/deploy/cpanel.sh b/deploy/cpanel_uapi.sh similarity index 100% rename from deploy/cpanel.sh rename to deploy/cpanel_uapi.sh From d09b5cb80eab19fb5e14a484cca5de09fb5c01ef Mon Sep 17 00:00:00 2001 From: Santeri Date: Wed, 19 Jul 2017 07:39:21 +0400 Subject: [PATCH 1071/1348] Rename cpanel_uapi.sh to cpanel_deploy.sh --- deploy/{cpanel_uapi.sh => cpanel_deploy.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deploy/{cpanel_uapi.sh => cpanel_deploy.sh} (100%) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_deploy.sh similarity index 100% rename from deploy/cpanel_uapi.sh rename to deploy/cpanel_deploy.sh From 4286b2917ef97ab44d0fd6208d183979633a401a Mon Sep 17 00:00:00 2001 From: Santeri Date: Wed, 19 Jul 2017 12:22:00 +0400 Subject: [PATCH 1072/1348] renamed function --- deploy/{cpanel_deploy.sh => cpanel_uapi.sh} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename deploy/{cpanel_deploy.sh => cpanel_uapi.sh} (98%) diff --git a/deploy/cpanel_deploy.sh b/deploy/cpanel_uapi.sh similarity index 98% rename from deploy/cpanel_deploy.sh rename to deploy/cpanel_uapi.sh index 9de8dbbb..ded50d0c 100644 --- a/deploy/cpanel_deploy.sh +++ b/deploy/cpanel_uapi.sh @@ -11,7 +11,7 @@ #domain keyfile certfile cafile fullchain -cpanel_deploy() { +cpanel_uapi() { _cdomain="$1" _ckey="$2" _ccert="$3" From 4285d81ca9d2805e99cf4ed0b601891b4ffd77ce Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sun, 23 Jul 2017 05:00:02 +0200 Subject: [PATCH 1073/1348] Get rid of curl. --- dnsapi/dns_he.sh | 102 +++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 65 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 269db8d2..141268ac 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -1,8 +1,5 @@ #!/usr/bin/env sh -# TODO Somehow use _get instead of curl - not sure how to support -# cookies though... - ######################################################################## # Hurricane Electric hook script for acme.sh # @@ -23,7 +20,12 @@ dns_he_add() { _txt_value=$2 _info "Using DNS-01 Hurricane Electric hook" - _authenticate || return 1 + if [ -z "$HE_Username" ] && [ -z "$HE_Password" ]; then + _err \ + 'No auth details provided. Please set user credentials using the \ + \$HE_Username and \$HE_Password envoronment variables.' + return 1 + fi _saveaccountconf HE_Username "$HE_Username" _saveaccountconf HE_Password "$HE_Password" @@ -31,20 +33,20 @@ dns_he_add() { _find_zone $_full_domain || return 1 _debug "Zone id \"$_zone_id\" will be used." - curl -L --silent --show-error --cookie "$_he_cookie" \ - --form "account=" \ - --form "menu=edit_zone" \ - --form "Type=TXT" \ - --form "hosted_dns_zoneid=$_zone_id" \ - --form "hosted_dns_recordid=" \ - --form "hosted_dns_editzone=1" \ - --form "Priority=" \ - --form "Name=$_full_domain" \ - --form "Content=$_txt_value" \ - --form "TTL=300" \ - --form "hosted_dns_editrecord=Submit" \ - "https://dns.he.net/" \ - > /dev/null + body="email=${HE_Username}&pass=${HE_Password}" + body="$body&account=" + body="$body&account=" + body="$body&menu=edit_zone" + body="$body&Type=TXT" + body="$body&hosted_dns_zoneid=$_zone_id" + body="$body&hosted_dns_recordid=" + body="$body&hosted_dns_editzone=1" + body="$body&Priority=" + body="$body&Name=$_full_domain" + body="$body&Content=$_txt_value" + body="$body&TTL=300" + body="$body&hosted_dns_editrecord=Submit" + _post $body "https://dns.he.net/" >/dev/null } @@ -56,16 +58,16 @@ dns_he_rm() { _txt_value=$2 _info "Cleaning up after DNS-01 Hurricane Electric hook" - _authenticate || return 1 - # fills in the $_zone_id _find_zone $_full_domain || return 1 _debug "Zone id \"$_zone_id\" will be used." # Find the record id to clean - _record_id=$( \ - curl -L --silent --show-error --cookie "$_he_cookie" \ - "https://dns.he.net/?hosted_dns_zoneid=$_zone_id&menu=edit_zone&hosted_dns_editzone" \ + body="email=${HE_Username}&pass=${HE_Password}" + body="$body&hosted_dns_zoneid=$_zone_id" + body="$body&menu=edit_zone" + body="$body&hosted_dns_editzone=" + _record_id=$(_post $body "https://dns.he.net/" \ | grep -A 1 "data=\"\("\)\?${_txt_value}\("\)\?\"" \ | tail -n 1 \ | _egrep_o "'[[:digit:]]+','[^']+','TXT'" \ @@ -74,15 +76,15 @@ dns_he_rm() { | head -n1) # ... oh my, what have I done... # Remove the record - curl -L --silent --show-error --cookie "$_he_cookie" \ - --form "menu=edit_zone" \ - --form "hosted_dns_zoneid=$_zone_id" \ - --form "hosted_dns_recordid=$_record_id" \ - --form "hosted_dns_editzone=1" \ - --form "hosted_dns_delrecord=1" \ - --form "hosted_dns_delconfirm=delete" \ - --form "hosted_dns_editzone=1" \ - "https://dns.he.net/" \ + body="email=${HE_Username}&pass=${HE_Password}" + body="$body&menu=edit_zone" + body="$body&hosted_dns_zoneid=$_zone_id" + body="$body&hosted_dns_recordid=$_record_id" + body="$body&hosted_dns_editzone=1" + body="$body&hosted_dns_delrecord=1" + body="$body&hosted_dns_delconfirm=delete" + body="$body&hosted_dns_editzone=1" + _post $body "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ > /dev/null if [ $? -eq 0 ]; then @@ -98,41 +100,10 @@ dns_he_rm() { ########################## PRIVATE FUNCTIONS ########################### -#-- _find_zone() ------------------------------------------------------- - -# Usage: _authenticate -# -# - needs $HE_Username and $HE_Password -# - sets the $_he_cookie - -_authenticate() { - if [ -z "$HE_Username" ] && [ -z "$HE_Password" ]; then - _err \ - 'No auth details provided. Please set user credentials using the \ - \$HE_Username and \$HE_Password envoronment variables.' - return 1 - fi - # Just get a session - _he_cookie=$( \ - curl -L --silent --show-error -I "https://dns.he.net/" \ - | grep '^Set-Cookie:' \ - | _egrep_o 'CGISESSID=[a-z0-9]*') - # Attempt login - curl -L --silent --show-error --cookie "$_he_cookie" \ - --form "email=${HE_Username}" \ - --form "pass=${HE_Password}" \ - "https://dns.he.net/" \ - > /dev/null - # TODO detect unsuccessful logins -} - - #-- _find_zone() ------------------------------------------------------- # Returns the most specific zone found in administration interface. # -# - needs $_he_cookie -# # Example: # # _find_zone first.second.third.co.uk @@ -155,8 +126,9 @@ _find_zone() { ## _all_zones is an array that looks like this: ## ( zone1:id zone2:id ... ) - _all_zones=( $(curl -L --silent --show-error --cookie "$_he_cookie" \ - "https://dns.he.net/" \ + + body="email=${HE_Username}&pass=${HE_Password}" + _all_zones=( $(_post $body "https://dns.he.net/" \ | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ | cut -d '"' -f 3,5 --output-delimiter=":" \ ) ) From 8ca45d3d03718c4ba7dc89eb030209ebe2be9ac7 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sun, 23 Jul 2017 05:13:33 +0200 Subject: [PATCH 1074/1348] Add HE to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5a3a3adf..7d4353c6 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,7 @@ You don't have to do anything manually! 1. Name.com API 1. Dyn Managed DNS API 1. Yandex PDD API (https://pdd.yandex.ru) +1. Hurricane Electric DNS service (https://dns.he.net) And: From f7299403f7b7c0642fee665a7780ef0d8794681f Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sun, 23 Jul 2017 07:31:55 +0200 Subject: [PATCH 1075/1348] Incorporate Neilpang's comments --- dnsapi/dns_he.sh | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 141268ac..019a7a0b 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -20,7 +20,7 @@ dns_he_add() { _txt_value=$2 _info "Using DNS-01 Hurricane Electric hook" - if [ -z "$HE_Username" ] && [ -z "$HE_Password" ]; then + if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then _err \ 'No auth details provided. Please set user credentials using the \ \$HE_Username and \$HE_Password envoronment variables.' @@ -46,7 +46,8 @@ dns_he_add() { body="$body&Content=$_txt_value" body="$body&TTL=300" body="$body&hosted_dns_editrecord=Submit" - _post $body "https://dns.he.net/" >/dev/null + response="$(_post $body "https://dns.he.net/")" + _debug2 response "$response" } @@ -68,12 +69,14 @@ dns_he_rm() { body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" _record_id=$(_post $body "https://dns.he.net/" \ - | grep -A 1 "data=\"\("\)\?${_txt_value}\("\)\?\"" \ - | tail -n 1 \ - | _egrep_o "'[[:digit:]]+','[^']+','TXT'" \ - | cut -b 2- \ - | _egrep_o "[[:digit:]]+" \ - | head -n1) # ... oh my, what have I done... + | tr -d '\n' \ + | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${_full_domain}','TXT'\)" \ + | _egrep_o "[0-9]+','${_full_domain}','TXT'\)$" \ + | _egrep_o "^[0-9]+" + ) + # The series of egreps above could have been done a bit shorter but + # I wanted to double-check whether it's the correct record (in case + # HE changes their website somehow). # Remove the record body="email=${HE_Username}&pass=${HE_Password}" @@ -134,12 +137,12 @@ _find_zone() { ) ) _strip_counter=1 - while [ true ] + while true do _attempted_zone=$(echo $_domain | cut -d . -f ${_strip_counter}-) # All possible zone names have been tried - if [ "$_attempted_zone" == "" ] + if [ -z "$_attempted_zone" ] then _err "No zone for domain \"$_domain\" found." break @@ -151,7 +154,7 @@ _find_zone() { do _zone_name=$(echo $i | cut -d ':' -f 1) _zone_id=$(echo $i | cut -d ':' -f 2) - if [ "$_zone_name" == "$_attempted_zone" ] + if [ "$_zone_name" = "$_attempted_zone" ] then # Zone found - we got $_zone_name and $_zone_id, let's get out... _debug "Found relevant zone \"$_zone_name\" with id" \ @@ -162,7 +165,7 @@ _find_zone() { _debug "Zone \"$_attempted_zone\" doesn't exist, let's try another \ variation." - _strip_counter=$(expr $_strip_counter + 1) + _strip_counter=$(_math $_strip_counter + 1) done # No zone found. From 3281043e2784154345b10aef7b107893ea7ff78b Mon Sep 17 00:00:00 2001 From: Brian Candler Date: Tue, 25 Jul 2017 09:39:15 +0100 Subject: [PATCH 1076/1348] Clarify keylength parameter to _isEccKey() and _initpath() Closes #950 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 486f8678..38965ddc 100755 --- a/acme.sh +++ b/acme.sh @@ -926,7 +926,7 @@ _sign() { } -#keylength +#keylength or isEcc flag (empty str => not ecc) _isEccKey() { _length="$1" @@ -2251,7 +2251,7 @@ _initAPI() { _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" } -#[domain] [keylength] +#[domain] [keylength or isEcc flag] _initpath() { __initHome From 29b21b828b01b37ad9f6536cba27af79a1f6aac3 Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Wed, 26 Jul 2017 09:44:11 -0400 Subject: [PATCH 1077/1348] Fix DNS API scripts on *BSD \n isn't available in all regex/sed --- dnsapi/dns_ad.sh | 3 ++- dnsapi/dns_do.sh | 6 ++++-- dnsapi/dns_freedns.sh | 6 ++++-- dnsapi/dns_linode.sh | 6 ++++-- dnsapi/dns_vscale.sh | 3 ++- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index fc4a664b..79b8c2ab 100755 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -92,7 +92,8 @@ _get_root() { p=1 if _ad_rest GET "domain/"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\ +&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 3a2f8f49..fb6d7dec 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -69,9 +69,11 @@ _dns_do_list_rrs() { fi _rr_list="$(echo "${response}" \ | tr -d "\n\r\t" \ - | sed -e 's//\n/g' \ + | sed -e 's//\ +/g' \ | grep ">$(_regexcape "$fulldomain")" \ - | sed -e 's/<\/item>/\n/g' \ + | sed -e 's/<\/item>/\ +/g' \ | grep '>id[0-9]{1,16}<' \ | tr -d '><')" diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 53da4118..d9677632 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -77,7 +77,8 @@ dns_freedns_add() { | grep -i -e ']*>/\n/Ig' \ + | sed 's/<\/TR[^>]*>/\ +/Ig' \ | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ @@ -216,7 +217,8 @@ dns_freedns_rm() { | grep -i -e ']*>/\n/Ig' \ + | sed 's/<\/TR[^>]*>/\ +/Ig' \ | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 6d54e6c1..d84ad5fb 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,7 +68,8 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\ +&/g')" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -128,7 +129,8 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\ +&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh index e50b7d8b..fcd162c9 100755 --- a/dnsapi/dns_vscale.sh +++ b/dnsapi/dns_vscale.sh @@ -93,7 +93,8 @@ _get_root() { p=1 if _vscale_rest GET "domains/"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\ +&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" From ff74778dea38ef22fb13fbdf452991c4a70135a1 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Wed, 26 Jul 2017 20:15:34 +0200 Subject: [PATCH 1078/1348] Fix few issues from Travis --- dnsapi/dns_he.sh | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 019a7a0b..1a6f8dbc 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -21,16 +21,14 @@ dns_he_add() { _info "Using DNS-01 Hurricane Electric hook" if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then - _err \ - 'No auth details provided. Please set user credentials using the \ - \$HE_Username and \$HE_Password envoronment variables.' + _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables." return 1 fi _saveaccountconf HE_Username "$HE_Username" _saveaccountconf HE_Password "$HE_Password" # fills in the $_zone_id - _find_zone $_full_domain || return 1 + _find_zone "$_full_domain" || return 1 _debug "Zone id \"$_zone_id\" will be used." body="email=${HE_Username}&pass=${HE_Password}" @@ -46,11 +44,10 @@ dns_he_add() { body="$body&Content=$_txt_value" body="$body&TTL=300" body="$body&hosted_dns_editrecord=Submit" - response="$(_post $body "https://dns.he.net/")" + response="$(_post "$body" "https://dns.he.net/")" _debug2 response "$response" } - #-- dns_he_rm() - Remove TXT record ------------------------------------ # Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..." @@ -60,7 +57,7 @@ dns_he_rm() { _info "Cleaning up after DNS-01 Hurricane Electric hook" # fills in the $_zone_id - _find_zone $_full_domain || return 1 + _find_zone "$_full_domain" || return 1 _debug "Zone id \"$_zone_id\" will be used." # Find the record id to clean @@ -68,7 +65,7 @@ dns_he_rm() { body="$body&hosted_dns_zoneid=$_zone_id" body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" - _record_id=$(_post $body "https://dns.he.net/" \ + _record_id=$(_post "$body" "https://dns.he.net/" \ | tr -d '\n' \ | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${_full_domain}','TXT'\)" \ | _egrep_o "[0-9]+','${_full_domain}','TXT'\)$" \ @@ -87,9 +84,9 @@ dns_he_rm() { body="$body&hosted_dns_delrecord=1" body="$body&hosted_dns_delconfirm=delete" body="$body&hosted_dns_editzone=1" - _post $body "https://dns.he.net/" \ + _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ - > /dev/null + >/dev/null if [ $? -eq 0 ]; then _info "Record removed successfuly." else @@ -99,12 +96,9 @@ dns_he_rm() { fi } - ########################## PRIVATE FUNCTIONS ########################### - #-- _find_zone() ------------------------------------------------------- - # Returns the most specific zone found in administration interface. # # Example: @@ -131,31 +125,28 @@ _find_zone() { ## ( zone1:id zone2:id ... ) body="email=${HE_Username}&pass=${HE_Password}" - _all_zones=( $(_post $body "https://dns.he.net/" \ + # TODO arrays aren't supported in POSIX sh + _all_zones=($(_post $body "https://dns.he.net/" \ | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ - | cut -d '"' -f 3,5 --output-delimiter=":" \ - ) ) + | cut -d '"' -f 3,5 --output-delimiter=":" + )) _strip_counter=1 - while true - do - _attempted_zone=$(echo $_domain | cut -d . -f ${_strip_counter}-) + while true; do + _attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-) # All possible zone names have been tried - if [ -z "$_attempted_zone" ] - then + if [ -z "$_attempted_zone" ]; then _err "No zone for domain \"$_domain\" found." break fi # Walk through all zones on the account #echo "$_all_zones" | while IFS=' ' read _zone_name _zone_id - for i in ${_all_zones[@]} - do - _zone_name=$(echo $i | cut -d ':' -f 1) - _zone_id=$(echo $i | cut -d ':' -f 2) - if [ "$_zone_name" = "$_attempted_zone" ] - then + for i in ${_all_zones[@]}; do + _zone_name=$(echo "$i" | cut -d ':' -f 1) + _zone_id=$(echo "$i" | cut -d ':' -f 2) + if [ "$_zone_name" = "$_attempted_zone" ]; then # Zone found - we got $_zone_name and $_zone_id, let's get out... _debug "Found relevant zone \"$_zone_name\" with id" \ "\"$_zone_id\" - will be used for domain \"$_domain\"." From 1546b7e5a971578cef11f960a44aadad3a45b754 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Wed, 26 Jul 2017 20:21:36 +0200 Subject: [PATCH 1079/1348] Missing quotes --- dnsapi/dns_he.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 1a6f8dbc..3e23b2e0 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -126,7 +126,7 @@ _find_zone() { body="email=${HE_Username}&pass=${HE_Password}" # TODO arrays aren't supported in POSIX sh - _all_zones=($(_post $body "https://dns.he.net/" \ + _all_zones=($(_post "$body" "https://dns.he.net/" \ | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ | cut -d '"' -f 3,5 --output-delimiter=":" )) From d39649f30d6718d7b0ec7e1e746a518b23bfd9be Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Thu, 27 Jul 2017 08:52:46 -0400 Subject: [PATCH 1080/1348] Revert non-linode scripts since they're untested --- dnsapi/dns_ad.sh | 3 +-- dnsapi/dns_do.sh | 6 ++---- dnsapi/dns_freedns.sh | 6 ++---- dnsapi/dns_vscale.sh | 3 +-- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 79b8c2ab..fc4a664b 100755 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -92,8 +92,7 @@ _get_root() { p=1 if _ad_rest GET "domain/"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\ -&/g')" + 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" diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index fb6d7dec..3a2f8f49 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -69,11 +69,9 @@ _dns_do_list_rrs() { fi _rr_list="$(echo "${response}" \ | tr -d "\n\r\t" \ - | sed -e 's//\ -/g' \ + | sed -e 's//\n/g' \ | grep ">$(_regexcape "$fulldomain")" \ - | sed -e 's/<\/item>/\ -/g' \ + | sed -e 's/<\/item>/\n/g' \ | grep '>id[0-9]{1,16}<' \ | tr -d '><')" diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index d9677632..53da4118 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -77,8 +77,7 @@ dns_freedns_add() { | grep -i -e ']*>/\ -/Ig' \ + | sed 's/<\/TR[^>]*>/\n/Ig' \ | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ @@ -217,8 +216,7 @@ dns_freedns_rm() { | grep -i -e ']*>/\ -/Ig' \ + | sed 's/<\/TR[^>]*>/\n/Ig' \ | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh index fcd162c9..e50b7d8b 100755 --- a/dnsapi/dns_vscale.sh +++ b/dnsapi/dns_vscale.sh @@ -93,8 +93,7 @@ _get_root() { p=1 if _vscale_rest GET "domains/"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\ -&/g')" + 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" From aefed1d1b9a5264f460aa94e119cb8a40f8bdddd Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Thu, 27 Jul 2017 18:04:53 +0200 Subject: [PATCH 1081/1348] Get rid of shell arrays. --- dnsapi/dns_he.sh | 73 +++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 3e23b2e0..ada5f794 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -121,16 +121,19 @@ _find_zone() { _domain="$1" - ## _all_zones is an array that looks like this: - ## ( zone1:id zone2:id ... ) - body="email=${HE_Username}&pass=${HE_Password}" - # TODO arrays aren't supported in POSIX sh - _all_zones=($(_post "$body" "https://dns.he.net/" \ - | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ - | cut -d '"' -f 3,5 --output-delimiter=":" - )) - + _matches=$(_post "$body" "https://dns.he.net/" \ + | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" + ) + # Zone names and zone IDs are in same order + _zone_ids=$(echo "$_matches" | cut -d '"' -f 5 --output-delimiter=":") + _zone_names=$(echo "$_matches" | cut -d '"' -f 3 --output-delimiter=":") + _debug2 "These are the zones on this HE account:" + _debug2 "$_zone_names" + _debug2 "And these are their respective IDs:" + _debug2 "$_zone_ids" + + # Walk through all possible zone names _strip_counter=1 while true; do _attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-) @@ -138,28 +141,46 @@ _find_zone() { # All possible zone names have been tried if [ -z "$_attempted_zone" ]; then _err "No zone for domain \"$_domain\" found." - break + return 1 fi - # Walk through all zones on the account - #echo "$_all_zones" | while IFS=' ' read _zone_name _zone_id - for i in ${_all_zones[@]}; do - _zone_name=$(echo "$i" | cut -d ':' -f 1) - _zone_id=$(echo "$i" | cut -d ':' -f 2) - if [ "$_zone_name" = "$_attempted_zone" ]; then - # Zone found - we got $_zone_name and $_zone_id, let's get out... - _debug "Found relevant zone \"$_zone_name\" with id" \ - "\"$_zone_id\" - will be used for domain \"$_domain\"." - return 0 - fi - done - - _debug "Zone \"$_attempted_zone\" doesn't exist, let's try another \ - variation." + _debug "Looking for zone \"${_attempted_zone}\"" + _line_num=$(echo "$_zone_names" | _find_linenum "$_attempted_zone") + if [ -n "$_line_num" ]; then + _zone_id=$(echo "$_zone_ids" | sed "${_line_num}q;d") + _debug "Found relevant zone \"$_attempted_zone\" with id" \ + "\"$_zone_id\" - will be used for domain \"$_domain\"." + return 0 + fi + + _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less" \ + "specific zone." _strip_counter=$(_math $_strip_counter + 1) done +} - # No zone found. +#-- _find_linenum()----------------------------------------------------- +# Returns line number of line (supplied as an argument) in STDIN. +# +# Example: +# +# printf "a\nb\nc" | _find_linenum "b" +# +# This will: +# - print out 2 because that's the line number of "b" +# - return code 0 because it was found + +_find_linenum() { + _current_line_num=0 + while read line; do + _current_line_num=$(expr "$_current_line_num" + 1) + if [ "$line" = "$1" ]; then + # Found! Let's echo the line number and quit + echo $_current_line_num + return 0 + fi + done + # Not found return 1 } From 235b5b0c154331879b70fd149d1fe7df19eac4c8 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Thu, 27 Jul 2017 18:06:19 +0200 Subject: [PATCH 1082/1348] Small cosmetic fixes. --- dnsapi/dns_he.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index ada5f794..51418aa9 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -11,7 +11,6 @@ # Author: Ondrej Simek # Git repo: https://github.com/angel333/acme.sh - #-- dns_he_add() - Add TXT record -------------------------------------- # Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..." @@ -86,7 +85,7 @@ dns_he_rm() { body="$body&hosted_dns_editzone=1" _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ - >/dev/null + >/dev/null if [ $? -eq 0 ]; then _info "Record removed successfuly." else From 577380e98e33c32f87d74df07d0d9d862b89b5be Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Thu, 27 Jul 2017 18:44:55 +0200 Subject: [PATCH 1083/1348] Few fixes for shellcheck --- dnsapi/dns_he.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 51418aa9..9b789d35 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -154,7 +154,7 @@ _find_zone() { _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less" \ "specific zone." - _strip_counter=$(_math $_strip_counter + 1) + _strip_counter=$(_math "$_strip_counter" + 1) done } @@ -171,11 +171,11 @@ _find_zone() { _find_linenum() { _current_line_num=0 - while read line; do - _current_line_num=$(expr "$_current_line_num" + 1) + while read -r line; do + _current_line_num=$(_math "$_current_line_num" + 1) if [ "$line" = "$1" ]; then # Found! Let's echo the line number and quit - echo $_current_line_num + echo "$_current_line_num" return 0 fi done From 8e6cf669ad01905d4d9e22f7a2874dcba8c7e263 Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Thu, 27 Jul 2017 14:15:19 -0400 Subject: [PATCH 1084/1348] Try awk instead for \n replacements --- dnsapi/dns_linode.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index d84ad5fb..ee3b1c8b 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,8 +68,7 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\ -&/g')" + response="$(echo "$response" | tr -d "\n" | awk '{ gsub("{","\n{",$1); print $1 }')" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -129,8 +128,7 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\ -&/g')" + response="$(echo "$response" | tr -d "\n" | awk '{ gsub("{","\n{",$1); print $1 }')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" From 8534e3b2f7fd16477b811c262f60e9b63cb85e32 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Fri, 28 Jul 2017 13:58:47 +0200 Subject: [PATCH 1085/1348] Make shellcheck happier --- dnsapi/dns_he.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 9b789d35..3ca00af9 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -20,6 +20,8 @@ dns_he_add() { _info "Using DNS-01 Hurricane Electric hook" if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then + HE_Username= + HE_Password= _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables." return 1 fi From d6780f9e49f18bf503f46c5d4859289e593935c0 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Fri, 28 Jul 2017 15:29:35 +0200 Subject: [PATCH 1086/1348] Retain an exit code --- dnsapi/dns_he.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 3ca00af9..ab4393c7 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -46,7 +46,9 @@ dns_he_add() { body="$body&TTL=300" body="$body&hosted_dns_editrecord=Submit" response="$(_post "$body" "https://dns.he.net/")" + exitcode=$? _debug2 response "$response" + return $exitvalue } #-- dns_he_rm() - Remove TXT record ------------------------------------ From ab1efd923b56b9014f07e7fcac7a81325d93d0b8 Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Fri, 28 Jul 2017 10:26:56 -0400 Subject: [PATCH 1087/1348] back to sed --- dnsapi/dns_linode.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index ee3b1c8b..00634d5d 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,7 +68,7 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | awk '{ gsub("{","\n{",$1); print $1 }')" + response="$(echo "$response" | tr -d "\n" | sed $'s/{/\\\n&/g')" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -128,7 +128,7 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | awk '{ gsub("{","\n{",$1); print $1 }')" + 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" From ccf9a9976c1b7cf31c60a4b74ead0f30fba1de28 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Fri, 28 Jul 2017 18:33:25 +0200 Subject: [PATCH 1088/1348] Fix the previous rushed commit. --- dnsapi/dns_he.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index ab4393c7..2fb1101e 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -46,9 +46,14 @@ dns_he_add() { body="$body&TTL=300" body="$body&hosted_dns_editrecord=Submit" response="$(_post "$body" "https://dns.he.net/")" - exitcode=$? + exit_code="$?" + if [ "$exit_code" -eq 0 ]; then + _info "TXT record added successfuly." + else + _err "Couldn't add the TXT record." + return "$exit_code" + fi _debug2 response "$response" - return $exitvalue } #-- dns_he_rm() - Remove TXT record ------------------------------------ @@ -90,7 +95,7 @@ dns_he_rm() { _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ >/dev/null - if [ $? -eq 0 ]; then + if [ "$?" -eq 0 ]; then _info "Record removed successfuly." else _err \ From a5c56c547d024493bb90732cda20108d09392715 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 29 Jul 2017 15:23:31 +0800 Subject: [PATCH 1089/1348] minor, fix dns param --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 38965ddc..9486bcc5 100755 --- a/acme.sh +++ b/acme.sh @@ -5440,7 +5440,7 @@ _process() { ;; --dns) wvalue="dns" - if ! _startswith "$2" "-"; then + if [ "$2" ] && ! _startswith "$2" "-"; then wvalue="$2" shift fi From 31b67ab92efd23802acb8510126418b83e1af8db Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 13:52:28 +0200 Subject: [PATCH 1090/1348] Few non-critical fixes. --- dnsapi/dns_he.sh | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 2fb1101e..a160e16a 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -28,13 +28,12 @@ dns_he_add() { _saveaccountconf HE_Username "$HE_Username" _saveaccountconf HE_Password "$HE_Password" - # fills in the $_zone_id + # Fills in the $_zone_id _find_zone "$_full_domain" || return 1 _debug "Zone id \"$_zone_id\" will be used." body="email=${HE_Username}&pass=${HE_Password}" body="$body&account=" - body="$body&account=" body="$body&menu=edit_zone" body="$body&Type=TXT" body="$body&hosted_dns_zoneid=$_zone_id" @@ -91,16 +90,13 @@ dns_he_rm() { body="$body&hosted_dns_editzone=1" body="$body&hosted_dns_delrecord=1" body="$body&hosted_dns_delconfirm=delete" - body="$body&hosted_dns_editzone=1" _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ >/dev/null if [ "$?" -eq 0 ]; then _info "Record removed successfuly." else - _err \ - "Could not clean (remove) up the record. Please go to HE" \ - "administration interface and clean it by hand." + _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." fi } @@ -134,8 +130,8 @@ _find_zone() { | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" ) # Zone names and zone IDs are in same order - _zone_ids=$(echo "$_matches" | cut -d '"' -f 5 --output-delimiter=":") - _zone_names=$(echo "$_matches" | cut -d '"' -f 3 --output-delimiter=":") + _zone_ids=$(echo "$_matches" | cut -d '"' -f 5) + _zone_names=$(echo "$_matches" | cut -d '"' -f 3) _debug2 "These are the zones on this HE account:" _debug2 "$_zone_names" _debug2 "And these are their respective IDs:" @@ -156,13 +152,11 @@ _find_zone() { _line_num=$(echo "$_zone_names" | _find_linenum "$_attempted_zone") if [ -n "$_line_num" ]; then _zone_id=$(echo "$_zone_ids" | sed "${_line_num}q;d") - _debug "Found relevant zone \"$_attempted_zone\" with id" \ - "\"$_zone_id\" - will be used for domain \"$_domain\"." + _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"." return 0 fi - _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less" \ - "specific zone." + _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone." _strip_counter=$(_math "$_strip_counter" + 1) done } From a25b2af66cd6a4c69ee673ec32aaebd068079042 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 14:25:07 +0200 Subject: [PATCH 1091/1348] Get rid of _find_num --- dnsapi/dns_he.sh | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index a160e16a..7dde55d4 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -149,9 +149,18 @@ _find_zone() { fi _debug "Looking for zone \"${_attempted_zone}\"" - _line_num=$(echo "$_zone_names" | _find_linenum "$_attempted_zone") - if [ -n "$_line_num" ]; then - _zone_id=$(echo "$_zone_ids" | sed "${_line_num}q;d") + + # Take care of "." and only match whole lines. Note that grep -F + # cannot be used because there's no way to make it match whole + # lines. + regex="^$(echo "$_attempted_zone" | sed 's/\./\\./g')$" + line_num=$(echo "$_zone_names" \ + | grep -n "$regex" \ + | cut -d : -f 1 + ) + + if [ -n "$line_num" ]; then + _zone_id=$(echo "$_zone_ids" | sed "${line_num}q;d") _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"." return 0 fi @@ -160,30 +169,4 @@ _find_zone() { _strip_counter=$(_math "$_strip_counter" + 1) done } - -#-- _find_linenum()----------------------------------------------------- -# Returns line number of line (supplied as an argument) in STDIN. -# -# Example: -# -# printf "a\nb\nc" | _find_linenum "b" -# -# This will: -# - print out 2 because that's the line number of "b" -# - return code 0 because it was found - -_find_linenum() { - _current_line_num=0 - while read -r line; do - _current_line_num=$(_math "$_current_line_num" + 1) - if [ "$line" = "$1" ]; then - # Found! Let's echo the line number and quit - echo "$_current_line_num" - return 0 - fi - done - # Not found - return 1 -} - # vim: et:ts=2:sw=2: From f438ff4bab695818932149d5b6bcecb1b6bed712 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 14:29:13 +0200 Subject: [PATCH 1092/1348] Fix an improbable corner case. --- dnsapi/dns_he.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 7dde55d4..152d469c 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -72,10 +72,11 @@ dns_he_rm() { body="$body&hosted_dns_zoneid=$_zone_id" body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" + domain_regex="$(echo "$_full_domain" | sed 's/\./\\./g')" # escape dots _record_id=$(_post "$body" "https://dns.he.net/" \ | tr -d '\n' \ - | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${_full_domain}','TXT'\)" \ - | _egrep_o "[0-9]+','${_full_domain}','TXT'\)$" \ + | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${domain_regex}','TXT'\)" \ + | _egrep_o "[0-9]+','${domain_regex}','TXT'\)$" \ | _egrep_o "^[0-9]+" ) # The series of egreps above could have been done a bit shorter but From baa1160594921e465ee798b77c5add4ed6b1d907 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 14:31:27 +0200 Subject: [PATCH 1093/1348] Make Shellcheck happier about exit codes --- dnsapi/dns_he.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 152d469c..3a1e6979 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -94,10 +94,12 @@ dns_he_rm() { _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ >/dev/null - if [ "$?" -eq 0 ]; then + exit_code="$?" + if [ "$exit_code" -eq 0 ]; then _info "Record removed successfuly." else _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." + return "$exit_code" fi } From 4dd69a8b1adaacfbb5a4894a8a5fc0403e3b4e88 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 14:40:56 +0200 Subject: [PATCH 1094/1348] Exit codes, exit codes... Exit codes everywhere... --- dnsapi/dns_he.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 3a1e6979..7d86eb7a 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -50,9 +50,9 @@ dns_he_add() { _info "TXT record added successfuly." else _err "Couldn't add the TXT record." - return "$exit_code" fi _debug2 response "$response" + return "$exit_code" } #-- dns_he_rm() - Remove TXT record ------------------------------------ From 8eab77f3c607075ff1cd59b59f76b074f1d46605 Mon Sep 17 00:00:00 2001 From: Brian Candler Date: Mon, 24 Jul 2017 14:23:01 +0100 Subject: [PATCH 1095/1348] Add deployment script for unifi controller --- acme.sh | 28 +++++++++++--- deploy/unifi.sh | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 deploy/unifi.sh diff --git a/acme.sh b/acme.sh index 9486bcc5..60eef4bb 100755 --- a/acme.sh +++ b/acme.sh @@ -1182,6 +1182,28 @@ _ss() { return 1 } +#outfile key cert cacert [password [name [caname]]] +_toPkcs() { + _cpfx="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + pfxPassword="$5" + pfxName="$6" + pfxCaname="$7" + + if [ "$pfxCaname" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" -caname "$pfxCaname" + elif [ "$pfxName" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" + elif [ "$pfxPassword" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" + else + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" + fi + +} + #domain [password] [isEcc] toPkcs() { domain="$1" @@ -1195,11 +1217,7 @@ toPkcs() { _initpath "$domain" "$_isEcc" - if [ "$pfxPassword" ]; then - ${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 - ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" - fi + _toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$pfxPassword" if [ "$?" = "0" ]; then _info "Success, Pfx is exported to: $CERT_PFX_PATH" diff --git a/deploy/unifi.sh b/deploy/unifi.sh new file mode 100644 index 00000000..184aa62e --- /dev/null +++ b/deploy/unifi.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to unifi server. + +#returns 0 means success, otherwise error. + +#DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" +#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise" +#DEPLOY_UNIFI_RELOAD="service unifi restart" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +unifi_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists keytool; then + _err "keytool not found" + return 1 + fi + + DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" + _unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}" + DEFAULT_UNIFI_KEYPASS="aircontrolenterprise" + _unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}" + DEFAULT_UNIFI_RELOAD="service unifi restart" + _reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}" + + _debug _unifi_keystore "$_unifi_keystore" + if [ ! -f "$_unifi_keystore" ]; then + if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then + _err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE" + return 1 + else + _err "It seems that the specified unifi keystore is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_unifi_keystore" ]; then + _err "The file $_unifi_keystore is not writable, please change the permission." + return 1 + fi + + _info "Generate import pkcs12" + _import_pkcs12="$(_mktemp)" + _toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root + if [ "$?" != "0" ]; then + _err "Oops, error creating import pkcs12, please report bug to us." + return 1 + fi + + _info "Modify unifi keystore: $_unifi_keystore" + if keytool -importkeystore \ + -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \ + -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \ + -alias unifi -noprompt; then + _info "Import keystore success!" + rm "$_import_pkcs12" + else + _err "Import unifi keystore error, please report bug to us." + rm "$_import_pkcs12" + return 1 + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then + _savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE" + else + _cleardomainconf DEPLOY_UNIFI_KEYSTORE + fi + if [ "$DEPLOY_UNIFI_KEYPASS" ]; then + _savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS" + else + _cleardomainconf DEPLOY_UNIFI_KEYPASS + fi + if [ "$DEPLOY_UNIFI_RELOAD" ]; then + _savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD" + else + _cleardomainconf DEPLOY_UNIFI_RELOAD + fi + return 0 + else + _err "Reload error" + return 1 + fi + return 0 + +} From cd3a4573f26c03315121f505ac97b45c511d9cb9 Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Mon, 31 Jul 2017 08:37:30 -0400 Subject: [PATCH 1096/1348] Fix shell check errors --- dnsapi/dns_linode.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 00634d5d..26ca53e4 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,7 +68,7 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | sed $'s/{/\\\n&/g')" + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -128,7 +128,7 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | sed $'s/{/\\\n&/g')" + 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" From c145f24621455f8608c179fc253d1fd00244bb6f Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Thu, 3 Aug 2017 09:47:45 -0400 Subject: [PATCH 1097/1348] Remove extra space --- dnsapi/dns_linode.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 26ca53e4..ead5b164 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,7 +68,7 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -128,7 +128,7 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + 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" From 5c3b41bd93c2c4e6da40c445cd5f15a1ba3f7274 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Aug 2017 21:57:45 +0800 Subject: [PATCH 1098/1348] format --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 0888517b..b3b6344e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -585,7 +585,7 @@ acme.sh --issue --dns dns_yandex -d mydomain.example.org For issues, please report to https://github.com/non7top/acme.sh/issues. -# 31. Use Hurricane Electric +## 31. Use Hurricane Electric Hurricane Electric doesn't have an API so just set your login credentials like so: From 415f375ce6f0de5a20545ba7ff6a9a7aa044c484 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 10 Aug 2017 21:31:28 +0800 Subject: [PATCH 1099/1348] support fcrontab, fix https://github.com/Neilpang/acme.sh/issues/966 --- acme.sh | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 60eef4bb..fe884e33 100755 --- a/acme.sh +++ b/acme.sh @@ -4417,15 +4417,19 @@ _installcert() { installcronjob() { _c_home="$1" _initpath - if ! _exists "crontab"; then - _err "crontab doesn't exist, so, we can not install cron jobs." + _CRONTAB="crontab" + if ! _exists "$_CRONTAB" && _exists "fcrontab"; then + _CRONTAB="fcrontab" + fi + if ! _exists "$_CRONTAB"; then + _err "crontab/fcrontab doesn't exist, so, we can not install cron jobs." _err "All your certs will not be renewed automatically." _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday." return 1 fi _info "Installing cron job" - if ! crontab -l | grep "$PROJECT_ENTRY --cron"; then + if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" else @@ -4439,15 +4443,15 @@ installcronjob() { _t=$(_time) random_minute=$(_math $_t % 60) if _exists uname && uname -a | grep SunOS >/dev/null; then - crontab -l | { + $_CRONTAB -l | { cat echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" - } | crontab -- + } | $_CRONTAB -- else - crontab -l | { + $_CRONTAB -l | { cat echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" - } | crontab - + } | $_CRONTAB - fi fi if [ "$?" != "0" ]; then @@ -4459,16 +4463,21 @@ installcronjob() { } uninstallcronjob() { - if ! _exists "crontab"; then + _CRONTAB="crontab" + if ! _exists "$_CRONTAB" && _exists "fcrontab"; then + _CRONTAB="fcrontab" + fi + + if ! _exists "$_CRONTAB"; then return fi _info "Removing cron job" - cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")" + cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")" if [ "$cr" ]; then if _exists uname && uname -a | grep solaris >/dev/null; then - crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -- + $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -- else - crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab - + $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB - fi LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" @@ -4745,7 +4754,7 @@ _precheck() { fi if [ -z "$_nocron" ]; then - if ! _exists "crontab"; then + if ! _exists "crontab" && ! _exists "fcrontab"; then _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." _err "We need to set cron job to renew the certs automatically." _err "Otherwise, your certs will not be able to be renewed automatically." From 96801e3478d64427f8ec0937de1d30ec05b9432a Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 11 Aug 2017 16:46:29 -0500 Subject: [PATCH 1100/1348] Update DuckDNS support, fix failure on first call, no longer save the domain/username as a global, and other tweaks --- dnsapi/README.md | 5 +-- dnsapi/dns_duckdns.sh | 79 +++++++++++++++++++++++++++++++------------ 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index b3b6344e..34b38678 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -512,14 +512,11 @@ export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" ``` Please note that since DuckDNS uses StartSSL as their cert provider, thus ---insecure must be used when issuing certs: +--insecure may need to be used when issuing certs: ``` acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org ``` -Also, DuckDNS uses the domain name as username for recording changing, so the -account file will always store the lastly used domain name. - For issues, please report to https://github.com/raidenii/acme.sh/issues. ## 28. Use Name.com API diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index d6987352..711b81ee 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -3,11 +3,14 @@ #Created by RaidenII, to use DuckDNS's API to add/remove text records #06/27/2017 -# Currently only support single domain access -# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure must be used with acme.sh +# Pass credentials before "acme.sh --issue --dns dns_duckdns ..." +# -- +# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" +# -- +# +# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh DuckDNS_API="https://www.duckdns.org/update" -API_Params="domains=$DuckDNS_Domain&token=$DuckDNS_Token" ######## Public functions ##################### @@ -16,35 +19,36 @@ dns_duckdns_add() { fulldomain=$1 txtvalue=$2 - # We'll extract the domain/username from full domain - DuckDNS_Domain=$(echo "$fulldomain" | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2) - - if [ -z "$DuckDNS_Domain" ]; then - _err "Error extracting the domain." - return 1 - fi - + DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" if [ -z "$DuckDNS_Token" ]; then - DuckDNS_Token="" + _err "You must export variable: DuckDNS_Token" _err "The token for your DuckDNS account is necessary." _err "You can look it up in your DuckDNS account." return 1 fi # Now save the credentials. - _saveaccountconf DuckDNS_Domain "$DuckDNS_Domain" - _saveaccountconf DuckDNS_Token "$DuckDNS_Token" + _saveaccountconf_mutable DuckDNS_Token "$DuckDNS_Token" # Unfortunately, DuckDNS does not seems to support lookup domain through API # So I assume your credentials (which are your domain and token) are correct # If something goes wrong, we will get a KO response from DuckDNS + if ! _duckdns_get_domain; then + return 1 + fi + # Now add the TXT record to DuckDNS _info "Trying to add TXT record" - if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" = "OK" ]; then - _info "TXT record has been successfully added to your DuckDNS domain." - _info "Note that all subdomains under this domain uses the same TXT record." - return 0 + if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=$txtvalue"; then + if [ "$response" = "OK" ]; then + _info "TXT record has been successfully added to your DuckDNS domain." + _info "Note that all subdomains under this domain uses the same TXT record." + return 0 + else + _err "Errors happened during adding the TXT record, response=$response" + return 1 + fi else _err "Errors happened during adding the TXT record." return 1 @@ -57,11 +61,28 @@ dns_duckdns_rm() { fulldomain=$1 txtvalue=$2 + DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" + if [ -z "$DuckDNS_Token" ]; then + _err "You must export variable: DuckDNS_Token" + _err "The token for your DuckDNS account is necessary." + _err "You can look it up in your DuckDNS account." + return 1 + fi + + if ! _duckdns_get_domain; then + return 1 + fi + # Now remove the TXT record from DuckDNS _info "Trying to remove TXT record" - if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" = "OK" ]; then - _info "TXT record has been successfully removed from your DuckDNS domain." - return 0 + if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=&clear=true"; then + if [ "$response" = "OK" ]; then + _info "TXT record has been successfully removed from your DuckDNS domain." + return 0 + else + _err "Errors happened during removing the TXT record, response=$response" + return 1 + fi else _err "Errors happened during removing the TXT record." return 1 @@ -70,6 +91,22 @@ dns_duckdns_rm() { #################### Private functions below ################################## +#fulldomain=_acme-challenge.domain.duckdns.org +#returns +# _duckdns_domain=domain +_duckdns_get_domain() { + + # We'll extract the domain/username from full domain + _duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.]duckdns.org' | cut -d . -f 2)" + + if [ -z "$_duckdns_domain" ]; then + _err "Error extracting the domain." + return 1 + fi + + return 0 +} + #Usage: method URI _duckdns_rest() { method=$1 From a07395fb563faff04f786e2e352aacf4dc7840ce Mon Sep 17 00:00:00 2001 From: Michele Date: Thu, 17 Aug 2017 12:50:28 +0200 Subject: [PATCH 1101/1348] Added support for busybox in time2str() awk fallback if none of preceding method works --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index fe884e33..9bf9e1e0 100755 --- a/acme.sh +++ b/acme.sh @@ -1367,6 +1367,10 @@ _time2str() { echo "$_t_s_a" fi + #Busybox + if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then + return + fi } _normalizeJson() { From 309bec474f11c1c9a2be472c44818703bfe6d911 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Aug 2017 20:27:13 +0800 Subject: [PATCH 1102/1348] add warning for dns manual mode --- acme.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/acme.sh b/acme.sh index 9bf9e1e0..cd2f981c 100755 --- a/acme.sh +++ b/acme.sh @@ -100,6 +100,10 @@ _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations" _STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode" +_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead." + +_DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" + __INTERACTIVE="" if [ -t 1 ]; then __INTERACTIVE="1" @@ -3046,6 +3050,10 @@ _on_issue_err() { ) fi + if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "dns"; then + _err "$_DNS_MANUAL_ERR" + fi + if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then _debug "$(_dlg_versions)" fi @@ -3078,6 +3086,10 @@ _on_issue_success() { fi fi + if _hasfield "$Le_Webroot" "dns"; then + _err "$_DNS_MANUAL_WARN" + fi + } updateaccount() { From 48e9006cd120317b62ee17e207c82517cc629d31 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 25 Aug 2017 20:51:31 +0800 Subject: [PATCH 1103/1348] fix cpanel uapi --- deploy/README.md | 18 ++++++++++++++++++ deploy/cpanel_uapi.sh | 15 ++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 232fdb4a..e026cadf 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -80,3 +80,21 @@ acme.sh --deploy -d ftp.example.com --deploy-hook exim4 ```sh acme.sh --deploy -d ftp.example.com --deploy-hook keychain ``` + +## 7. Deploy to cpanel host. + +``` +acme.sh --deploy -d example.com --deploy-hook cpanel_uapi +``` + +If you are login as root, please specify the username to deploy cert to: + +```sh +export DEPLOY_CPANEL_USER=username +acme.sh --deploy -d example.com --deploy-hook cpanel_uapi +``` + + + + + diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index ded50d0c..89ce1988 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -11,7 +11,7 @@ #domain keyfile certfile cafile fullchain -cpanel_uapi() { +cpanel_uapi_deploy() { _cdomain="$1" _ckey="$2" _ccert="$3" @@ -24,6 +24,14 @@ cpanel_uapi() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" + if ! _exists uapi; then + _err "The command uapi is not found." + return 1 + fi + if ! _exists php; then + _err "The command php is not found." + return 1 + fi # read cert and key files and urlencode both _certstr=$(cat "$_ccert") _keystr=$(cat "$_ckey") @@ -34,6 +42,11 @@ cpanel_uapi() { _debug _key "$_key" if [ "$(id -u)" = 0 ]; then + if [ -z "$DEPLOY_CPANEL_USER" ]; then + _err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username" + return 1; + fi + _savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER" _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") else _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") From a2d6daaef47feec91dcbf4dc1c4caec8630c1484 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 25 Aug 2017 20:54:10 +0800 Subject: [PATCH 1104/1348] fix cpanel_uapi.sh --- deploy/cpanel_uapi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index 89ce1988..2ba112c4 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -44,7 +44,7 @@ cpanel_uapi_deploy() { if [ "$(id -u)" = 0 ]; then if [ -z "$DEPLOY_CPANEL_USER" ]; then _err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username" - return 1; + return 1 fi _savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER" _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") From 88bb7b780d445d1874611aa841b51bdb153f1bfb Mon Sep 17 00:00:00 2001 From: fritteli Date: Tue, 29 Aug 2017 22:35:11 +0200 Subject: [PATCH 1105/1348] Typos --- dnsapi/dns_he.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 7d86eb7a..4d1973ad 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -47,7 +47,7 @@ dns_he_add() { response="$(_post "$body" "https://dns.he.net/")" exit_code="$?" if [ "$exit_code" -eq 0 ]; then - _info "TXT record added successfuly." + _info "TXT record added successfully." else _err "Couldn't add the TXT record." fi @@ -96,7 +96,7 @@ dns_he_rm() { >/dev/null exit_code="$?" if [ "$exit_code" -eq 0 ]; then - _info "Record removed successfuly." + _info "Record removed successfully." else _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." return "$exit_code" From f6da19ba835e52fba79caec2544aa89af0116c62 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 29 Aug 2017 23:13:29 +0200 Subject: [PATCH 1106/1348] add deploy script for the AVM FRITZ!Box --- deploy/fritzbox.sh | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 deploy/fritzbox.sh diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh new file mode 100644 index 00000000..1290dc7a --- /dev/null +++ b/deploy/fritzbox.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to an AVM FRITZ!Box router. + +#returns 0 means success, otherwise error. + +#DEPLOY_FRITZBOX_USERNAME="username" +#DEPLOY_FRITZBOX_PASSWORD="password" +#DEPLOY_FRITZBOX_URL="https://fritz.box" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +fritzbox_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists wget; then + _err "wget not found" + return 1 + fi + if ! exists iconv; then + _err "iconv not found" + return 1 + fi + + _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" + _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" + _fritzbox_url="${DEPLOY_FRITZBOX_URL}" + + _debug _fritzbox_url "$_fritzbox_url" + _debug _fritzbox_usename "$_fritzbox_username" + _secure_debug _fritzbox_password "$_fritzbox_password" + if [ ! -z "$_fritzbox_username" ]; then + _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." + return 1 + fi + if [ ! -z "$_fritzbox_password" ]; then + _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." + return 1 + fi + if [ ! -z "$_fritzbox_url" ]; then + _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." + return 1 + fi + + _info "Log in in to the FRITZ!Box" + _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_frithbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + + _info "Generate form POST request" + _post_request="$(_mktemp)" + _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" + printf "Content-Type: application/octet-stream\r\n\r\n" >> "${_post_request}" + cat "${_ckey}" >> "${_post_request}" + cat "${_cfullchain}" >> "${_post_request}" + printf "\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}--" >> "${_post_request}" + + _info "Upload certificate to the FRITZ!Box" + wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" + + _info "Upload successful" + rm "${_post_request}" + + return 0 +} + From 4bb488258d24159284fc55b5b81d7a146880f0fc Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 29 Aug 2017 23:53:41 +0200 Subject: [PATCH 1107/1348] - Bugfixes - Make sure the login actually worked - Less output --- deploy/fritzbox.sh | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 1290dc7a..c6a730c5 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -28,7 +28,7 @@ fritzbox_deploy() { _err "wget not found" return 1 fi - if ! exists iconv; then + if ! _exists iconv; then _err "iconv not found" return 1 fi @@ -40,23 +40,32 @@ fritzbox_deploy() { _debug _fritzbox_url "$_fritzbox_url" _debug _fritzbox_usename "$_fritzbox_username" _secure_debug _fritzbox_password "$_fritzbox_password" - if [ ! -z "$_fritzbox_username" ]; then + if [ -z "$_fritzbox_username" ]; then _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." return 1 fi - if [ ! -z "$_fritzbox_password" ]; then + if [ -z "$_fritzbox_password" ]; then _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." return 1 fi - if [ ! -z "$_fritzbox_url" ]; then + if [ -z "$_fritzbox_url" ]; then _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." return 1 fi - _info "Log in in to the FRITZ!Box" + _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" + _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" + _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" + + _info "Log in to the FRITZ!Box" _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_frithbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + + if [ -z "${_fritzbox_sid}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then + _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." + return 1 + fi _info "Generate form POST request" _post_request="$(_mktemp)" @@ -65,6 +74,7 @@ fritzbox_deploy() { printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" printf -- "--${_post_boundary}\r\n" >> "${_post_request}" # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! + _CERTPASSWORD_= printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" printf -- "--${_post_boundary}\r\n" >> "${_post_request}" printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" @@ -75,11 +85,10 @@ fritzbox_deploy() { printf -- "--${_post_boundary}--" >> "${_post_request}" _info "Upload certificate to the FRITZ!Box" - wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" + wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL _info "Upload successful" rm "${_post_request}" return 0 } - From d50281453d6bc704c0a647b523073f06b002ca34 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 29 Aug 2017 23:57:24 +0200 Subject: [PATCH 1108/1348] Add --no-check-certificate option to wget, or else the initial deployment won't work because there isn't a valid certificate installed on the router yet. --- deploy/fritzbox.sh | 6 +-- deploy/fritzbox.sh~ | 94 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 deploy/fritzbox.sh~ diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index c6a730c5..16c310bc 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -58,9 +58,9 @@ fritzbox_deploy() { _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" _info "Log in to the FRITZ!Box" - _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_challenge="$(wget --no-check-certificate -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_sid="$(wget --no-check-certificate -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" if [ -z "${_fritzbox_sid}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." @@ -85,7 +85,7 @@ fritzbox_deploy() { printf -- "--${_post_boundary}--" >> "${_post_request}" _info "Upload certificate to the FRITZ!Box" - wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL + wget --no-check-certificate -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL _info "Upload successful" rm "${_post_request}" diff --git a/deploy/fritzbox.sh~ b/deploy/fritzbox.sh~ new file mode 100644 index 00000000..c6a730c5 --- /dev/null +++ b/deploy/fritzbox.sh~ @@ -0,0 +1,94 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to an AVM FRITZ!Box router. + +#returns 0 means success, otherwise error. + +#DEPLOY_FRITZBOX_USERNAME="username" +#DEPLOY_FRITZBOX_PASSWORD="password" +#DEPLOY_FRITZBOX_URL="https://fritz.box" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +fritzbox_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists wget; then + _err "wget not found" + return 1 + fi + if ! _exists iconv; then + _err "iconv not found" + return 1 + fi + + _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" + _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" + _fritzbox_url="${DEPLOY_FRITZBOX_URL}" + + _debug _fritzbox_url "$_fritzbox_url" + _debug _fritzbox_usename "$_fritzbox_username" + _secure_debug _fritzbox_password "$_fritzbox_password" + if [ -z "$_fritzbox_username" ]; then + _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." + return 1 + fi + if [ -z "$_fritzbox_password" ]; then + _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." + return 1 + fi + if [ -z "$_fritzbox_url" ]; then + _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." + return 1 + fi + + _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" + _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" + _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" + + _info "Log in to the FRITZ!Box" + _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + + if [ -z "${_fritzbox_sid}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then + _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." + return 1 + fi + + _info "Generate form POST request" + _post_request="$(_mktemp)" + _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! + _CERTPASSWORD_= + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" + printf "Content-Type: application/octet-stream\r\n\r\n" >> "${_post_request}" + cat "${_ckey}" >> "${_post_request}" + cat "${_cfullchain}" >> "${_post_request}" + printf "\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}--" >> "${_post_request}" + + _info "Upload certificate to the FRITZ!Box" + wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL + + _info "Upload successful" + rm "${_post_request}" + + return 0 +} From e6f81173a38c5768aae800acf058a2aea07f092e Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 29 Aug 2017 23:58:20 +0200 Subject: [PATCH 1109/1348] Delete auto-backup file --- deploy/fritzbox.sh~ | 94 --------------------------------------------- 1 file changed, 94 deletions(-) delete mode 100644 deploy/fritzbox.sh~ diff --git a/deploy/fritzbox.sh~ b/deploy/fritzbox.sh~ deleted file mode 100644 index c6a730c5..00000000 --- a/deploy/fritzbox.sh~ +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to an AVM FRITZ!Box router. - -#returns 0 means success, otherwise error. - -#DEPLOY_FRITZBOX_USERNAME="username" -#DEPLOY_FRITZBOX_PASSWORD="password" -#DEPLOY_FRITZBOX_URL="https://fritz.box" - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -fritzbox_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - if ! _exists wget; then - _err "wget not found" - return 1 - fi - if ! _exists iconv; then - _err "iconv not found" - return 1 - fi - - _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" - _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" - _fritzbox_url="${DEPLOY_FRITZBOX_URL}" - - _debug _fritzbox_url "$_fritzbox_url" - _debug _fritzbox_usename "$_fritzbox_username" - _secure_debug _fritzbox_password "$_fritzbox_password" - if [ -z "$_fritzbox_username" ]; then - _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." - return 1 - fi - if [ -z "$_fritzbox_password" ]; then - _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." - return 1 - fi - if [ -z "$_fritzbox_url" ]; then - _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." - return 1 - fi - - _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" - _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" - _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" - - _info "Log in to the FRITZ!Box" - _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" - _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" - - if [ -z "${_fritzbox_sid}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then - _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." - return 1 - fi - - _info "Generate form POST request" - _post_request="$(_mktemp)" - _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! - _CERTPASSWORD_= - printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" - printf "Content-Type: application/octet-stream\r\n\r\n" >> "${_post_request}" - cat "${_ckey}" >> "${_post_request}" - cat "${_cfullchain}" >> "${_post_request}" - printf "\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}--" >> "${_post_request}" - - _info "Upload certificate to the FRITZ!Box" - wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL - - _info "Upload successful" - rm "${_post_request}" - - return 0 -} From 412e4e6cf9ecbf26c4d9b9330c3dfef1ddc92e42 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Wed, 30 Aug 2017 00:24:31 +0200 Subject: [PATCH 1110/1348] Add acknowledgement note --- deploy/fritzbox.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 16c310bc..804548c5 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -8,6 +8,9 @@ #DEPLOY_FRITZBOX_PASSWORD="password" #DEPLOY_FRITZBOX_URL="https://fritz.box" +# Kudos to wikrie at Github for his FRITZ!Box update script: +# https://gist.github.com/wikrie/f1d5747a714e0a34d0582981f7cb4cfb + ######## Public functions ##################### #domain keyfile certfile cafile fullchain From b6d48b7a144cefeebd3db92f8a3cabcad05139c6 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Wed, 30 Aug 2017 00:45:03 +0200 Subject: [PATCH 1111/1348] Update README.md for the deploy hooks. --- deploy/README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index e026cadf..d0f3d7f0 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -93,8 +93,18 @@ If you are login as root, please specify the username to deploy cert to: export DEPLOY_CPANEL_USER=username acme.sh --deploy -d example.com --deploy-hook cpanel_uapi ``` +## 8. Deploy the cert to your FRITZ!Box router +You must specify the credentials that have administrative privileges on the FRITZ!Box in order to deploy the certificate, plus the URL of your FRITZ!Box, through the following environment variables: +```sh +$ export DEPLOY_FRITZBOX_USERNAME=my_username +$ export DEPLOY_FRITZBOX_PASSWORD=the_password +$ export DEPLOY_FRITZBOX_URL=https://fritzbox.example.com +``` +After the first deployment, these values will be stored in your $HOME/.acme.sh/account.conf. You may now deploy the certificate like this: - +```sh +acme.sh --deploy -d fritz.box --deploy-hook fritzbox +``` From 103fa959cb7346d6bbade60d4009df84f1726a21 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Wed, 30 Aug 2017 00:47:31 +0200 Subject: [PATCH 1112/1348] Typo --- deploy/fritzbox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 804548c5..cea84f59 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -41,7 +41,7 @@ fritzbox_deploy() { _fritzbox_url="${DEPLOY_FRITZBOX_URL}" _debug _fritzbox_url "$_fritzbox_url" - _debug _fritzbox_usename "$_fritzbox_username" + _debug _fritzbox_username "$_fritzbox_username" _secure_debug _fritzbox_password "$_fritzbox_password" if [ -z "$_fritzbox_username" ]; then _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." From a3a92ff1dfc283ffc80bfd2a3cb9527295a832e7 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Thu, 31 Aug 2017 17:12:11 +0200 Subject: [PATCH 1113/1348] Fix formatting errors. --- deploy/fritzbox.sh | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index cea84f59..e2102eda 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -61,11 +61,11 @@ fritzbox_deploy() { _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" _info "Log in to the FRITZ!Box" - _fritzbox_challenge="$(wget --no-check-certificate -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" - _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget --no-check-certificate -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_challenge="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_hash="$(echo -n "${_fritzbox_challenge}-${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" - if [ -z "${_fritzbox_sid}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then + if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." return 1 fi @@ -73,19 +73,24 @@ fritzbox_deploy() { _info "Generate form POST request" _post_request="$(_mktemp)" _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + { + printf -- "--%s\r\n" "${_post_boundary}"; + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}"; + printf -- "--%s\r\n""${_post_boundary}"; + } >>"${_post_request}" # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! _CERTPASSWORD_= - printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" - printf "Content-Type: application/octet-stream\r\n\r\n" >> "${_post_request}" - cat "${_ckey}" >> "${_post_request}" - cat "${_cfullchain}" >> "${_post_request}" - printf "\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}--" >> "${_post_request}" + { + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}"; + printf -- "--%s\r\n" "${_post_boundary}"; + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n"; + printf "Content-Type: application/octet-stream\r\n\r\n"; + } >>"${_post_request}" + cat "${_ckey}${_cfullchain}" >>"${_post_request}" + { + printf "\r\n"; + printf -- "--%s--" "${_post_boundary}"; + } >>"${_post_request}" _info "Upload certificate to the FRITZ!Box" wget --no-check-certificate -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL From 6cb5377d73c2ad6a4c9e7adfc727b191f127910b Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Thu, 31 Aug 2017 17:25:08 +0200 Subject: [PATCH 1114/1348] Fix bugs and more/new formatting errors. --- deploy/fritzbox.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index e2102eda..1fe28e89 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -63,7 +63,7 @@ fritzbox_deploy() { _info "Log in to the FRITZ!Box" _fritzbox_challenge="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" _fritzbox_hash="$(echo -n "${_fritzbox_challenge}-${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." @@ -74,22 +74,22 @@ fritzbox_deploy() { _post_request="$(_mktemp)" _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" { - printf -- "--%s\r\n" "${_post_boundary}"; - printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}"; - printf -- "--%s\r\n""${_post_boundary}"; + printf -- "--%s\r\n" "${_post_boundary}" + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" + printf -- "--%s\r\n" "${_post_boundary}" } >>"${_post_request}" # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! _CERTPASSWORD_= { - printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}"; - printf -- "--%s\r\n" "${_post_boundary}"; - printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n"; - printf "Content-Type: application/octet-stream\r\n\r\n"; + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" + printf -- "--%s\r\n" "${_post_boundary}" + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" + printf "Content-Type: application/octet-stream\r\n\r\n" } >>"${_post_request}" - cat "${_ckey}${_cfullchain}" >>"${_post_request}" + cat "${_ckey}" "${_cfullchain}" >>"${_post_request}" { - printf "\r\n"; - printf -- "--%s--" "${_post_boundary}"; + printf "\r\n" + printf -- "--%s--" "${_post_boundary}" } >>"${_post_request}" _info "Upload certificate to the FRITZ!Box" From 3794b5cb5846cc9713979027d68fc930211ec86e Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 1 Sep 2017 23:01:37 +0800 Subject: [PATCH 1115/1348] fix changes for :https://community.letsencrypt.org/t/acme-sh-standalone-fails-multiple-validation-requests-staging-multi-va/41249/8 use socat instead of nc. --- acme.sh | 79 +++++++++++++-------------------------------------------- 1 file changed, 17 insertions(+), 62 deletions(-) diff --git a/acme.sh b/acme.sh index cd2f981c..c7f8eddd 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.3 +VER=2.7.4 PROJECT_NAME="acme.sh" @@ -164,11 +164,11 @@ _dlg_versions() { echo "nginx doesn't exists." fi - echo "nc:" - if _exists "nc"; then - nc -h 2>&1 + echo "socat:" + if _exists "socat"; then + socat -h 2>&1 else - _debug "nc doesn't exists." + _debug "socat doesn't exists." fi } @@ -1967,68 +1967,22 @@ _startserver() { _debug "ncaddr" "$ncaddr" _debug "startserver: $$" - nchelp="$(nc -h 2>&1)" _debug Le_HTTPPort "$Le_HTTPPort" _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" - _NC="nc" + _NC="socat" if [ "$Le_Listen_V4" ]; then _NC="$_NC -4" elif [ "$Le_Listen_V6" ]; then _NC="$_NC -6" fi - if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then - if ! _contains "$nchelp" "-4"; then - _err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again." - _err "See $(__green $_PREPARE_LINK)" - return 1 - fi - fi - - if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then - _NC="$_NC -q 1 -l $ncaddr" - else - if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null; then - _NC="$_NC -c -l $ncaddr" - elif echo "$nchelp" | grep "\-N" | grep "Shutdown the network socket after EOF on stdin" >/dev/null; then - _NC="$_NC -N -l $ncaddr" - else - _NC="$_NC -l $ncaddr" - fi - fi - _debug "_NC" "$_NC" - - #for centos ncat - if _contains "$nchelp" "nmap.org"; then - _debug "Using ncat: nmap.org" - if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"; then - _exec_err - return 1 - fi - if [ "$DEBUG" ]; then - _exec_err - fi - return - fi - - # while true ; do - if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC -p \"$Le_HTTPPort\" >&2"; then - _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2" - fi - - if [ "$?" != "0" ]; then - _err "nc listen error." - _exec_err - exit 1 - fi - if [ "$DEBUG" ]; then - _exec_err - fi - # done + #todo listen address + socat TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + serverproc="$!" } _stopserver() { @@ -2038,6 +1992,8 @@ _stopserver() { return fi + kill $pid + _debug2 "Le_HTTPPort" "$Le_HTTPPort" if [ "$Le_HTTPPort" ]; then if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then @@ -2943,8 +2899,8 @@ _on_before_issue() { fi if _hasfield "$_chk_web_roots" "$NO_VALUE"; then - if ! _exists "nc"; then - _err "Please install netcat(nc) tools first." + if ! _exists "socat"; then + _err "Please install socat tools first." return 1 fi fi @@ -3665,13 +3621,12 @@ issue() { _info "Standalone mode server" _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" _ncIndex="$(_math $_ncIndex + 1)" - _startserver "$keyauthorization" "$_ncaddr" & + _startserver "$keyauthorization" "$_ncaddr" if [ "$?" != "0" ]; then _clearup _on_issue_err "$_post_hook" "$vlist" return 1 fi - serverproc="$!" sleep 1 _debug serverproc "$serverproc" elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then @@ -4788,9 +4743,9 @@ _precheck() { return 1 fi - if ! _exists "nc"; then - _err "It is recommended to install nc first, try to install 'nc' or 'netcat'." - _err "We use nc for standalone server if you use standalone mode." + if ! _exists "socat"; then + _err "It is recommended to install socat first." + _err "We use socat for standalone server if you use standalone mode." _err "If you don't use standalone mode, just ignore this warning." fi From 443a5ca0c2d0af8e11f720f3acbb04ee628a001b Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 1 Sep 2017 23:44:52 +0800 Subject: [PATCH 1116/1348] socat tls mode --- acme.sh | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/acme.sh b/acme.sh index c7f8eddd..84ae7e93 100755 --- a/acme.sh +++ b/acme.sh @@ -1994,25 +1994,6 @@ _stopserver() { kill $pid - _debug2 "Le_HTTPPort" "$Le_HTTPPort" - if [ "$Le_HTTPPort" ]; then - if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then - _get "http://localhost:$Le_HTTPPort" "" 1 - else - _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1 - fi - fi - - _debug2 "Le_TLSPort" "$Le_TLSPort" - if [ "$Le_TLSPort" ]; then - if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then - _get "https://localhost:$Le_TLSPort" "" 1 - _get "https://localhost:$Le_TLSPort" "" 1 - else - _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1 - _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1 - fi - fi } # sleep sec @@ -2067,12 +2048,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -cert $TLS_CERT -key $TLS_KEY " - if [ "$opaddr" ]; then - __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" - else - __S_OPENSSL="$__S_OPENSSL -accept $port" - fi + __S_OPENSSL="socat" _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" @@ -2083,12 +2059,9 @@ _starttlsserver() { fi _debug "$__S_OPENSSL" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) & - else - (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL >/dev/null 2>&1) & - fi + #todo listen address + $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 7b8ddfdd96d5edd6992335a1f289b845ab9403d2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Sep 2017 08:59:30 +0800 Subject: [PATCH 1117/1348] use socat --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2ba02b9c..1378e947 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ install: - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then brew update && brew install openssl; brew info openssl; + brew info socat; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; @@ -30,6 +31,7 @@ install: openssl version 2>&1 || true; $ACME_OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; + else sudo apt-get install socat; fi script: From cc6610edc2fe1c4d19aed233ac5449b2124de4ea Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Sep 2017 17:32:40 +0800 Subject: [PATCH 1118/1348] add socat --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1378e947..b45cc464 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,9 +18,8 @@ addons: install: - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then - brew update && brew install openssl; + brew update && brew install openssl socat; brew info openssl; - brew info socat; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; From f9cdfd3e5baf89eb84f04a5a912223e2c57c01bb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Sep 2017 18:58:07 +0800 Subject: [PATCH 1119/1348] fix for behind proxy --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 84ae7e93..07617c40 100755 --- a/acme.sh +++ b/acme.sh @@ -1981,7 +1981,7 @@ _startserver() { _debug "_NC" "$_NC" #todo listen address - socat TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + socat TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" } @@ -2061,7 +2061,7 @@ _starttlsserver() { _debug "$__S_OPENSSL" #todo listen address - $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 6104680caa1c1542b5c2291b8392f5b67b061717 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Sep 2017 20:46:04 +0800 Subject: [PATCH 1120/1348] fix https://github.com/Neilpang/acme.sh/issues/999 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 07617c40..45287eef 100755 --- a/acme.sh +++ b/acme.sh @@ -3934,7 +3934,10 @@ issue() { Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - _on_issue_success "$_post_hook" "$_renew_hook" + if ! _on_issue_success "$_post_hook" "$_renew_hook"; then + _err "Call hook error." + return 1 + fi if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then _savedomainconf "Le_RealCertPath" "$_real_cert" From 4356eefbb10d519cdbd6d44a52b757e3df348075 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Sep 2017 08:42:44 +0800 Subject: [PATCH 1121/1348] fix https://github.com/Neilpang/acme.sh/issues/1005#event-1232471561 --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 45287eef..f6447f73 100755 --- a/acme.sh +++ b/acme.sh @@ -4821,9 +4821,11 @@ install() { _debug "Skip install cron job" fi - if ! _precheck "$_nocron"; then - _err "Pre-check failed, can not install." - return 1 + if [ "$IN_CRON" != "1" ]; then + if ! _precheck "$_nocron"; then + _err "Pre-check failed, can not install." + return 1 + fi fi if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then @@ -4876,7 +4878,9 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" - _installalias "$_c_home" + if [ "$IN_CRON" != "1" ]; then + _installalias "$_c_home" + fi for subf in $_SUB_FOLDERS; do if [ -d "$subf" ]; then From c73fdd402243071d01a23eae7ae17088b5914d7d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Sep 2017 08:45:58 +0800 Subject: [PATCH 1122/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index f6447f73..e482b87b 100755 --- a/acme.sh +++ b/acme.sh @@ -4970,7 +4970,7 @@ _uninstallalias() { } cron() { - IN_CRON=1 + export IN_CRON=1 _initpath _info "$(__green "===Starting cron===")" if [ "$AUTO_UPGRADE" = "1" ]; then From e52304edb47b974c905e88bc41b7124705f514e6 Mon Sep 17 00:00:00 2001 From: Santeri Date: Sun, 3 Sep 2017 13:35:20 +0400 Subject: [PATCH 1123/1348] cpanel_uapi tried to make it a bit less confusing --- deploy/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index e026cadf..62a3fb6f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -6,6 +6,8 @@ Here are the scripts to deploy the certs/key to the server/services. ## 1. Deploy the certs to your cpanel host. +If you want to deploy using cpanel UAPI see 7. + (cpanel deploy hook is not finished yet, this is just an example.) @@ -81,14 +83,13 @@ acme.sh --deploy -d ftp.example.com --deploy-hook exim4 acme.sh --deploy -d ftp.example.com --deploy-hook keychain ``` -## 7. Deploy to cpanel host. +## 7. Deploy to cpanel host using UAPI +This hook is using UAPI and works in cPanel & WHM version 56 or newer. ``` acme.sh --deploy -d example.com --deploy-hook cpanel_uapi ``` - -If you are login as root, please specify the username to deploy cert to: - +DEPLOY_CPANEL_USER is required only if you run the script as root and it should contain cpanel username. ```sh export DEPLOY_CPANEL_USER=username acme.sh --deploy -d example.com --deploy-hook cpanel_uapi From a098167bdbd145ff3d522b33c4d18f99e8ff09ec Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:07:10 +0200 Subject: [PATCH 1124/1348] Fix more formatting errors --- deploy/fritzbox.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 1fe28e89..c86b44ad 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -62,7 +62,7 @@ fritzbox_deploy() { _info "Log in to the FRITZ!Box" _fritzbox_challenge="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" - _fritzbox_hash="$(echo -n "${_fritzbox_challenge}-${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then @@ -73,14 +73,12 @@ fritzbox_deploy() { _info "Generate form POST request" _post_request="$(_mktemp)" _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" + # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it! + _CERTPASSWORD_= { printf -- "--%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" printf -- "--%s\r\n" "${_post_boundary}" - } >>"${_post_request}" - # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! - _CERTPASSWORD_= - { printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" printf -- "--%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" From bd8b1a2501a867a373772398b3687ac47341f0f5 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:27:22 +0200 Subject: [PATCH 1125/1348] Don't use wget directly, but instead use _get and _post. --- deploy/fritzbox.sh | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index c86b44ad..e7d01a8b 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -27,10 +27,6 @@ fritzbox_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - if ! _exists wget; then - _err "wget not found" - return 1 - fi if ! _exists iconv; then _err "iconv not found" return 1 @@ -60,10 +56,13 @@ fritzbox_deploy() { _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" + # Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate + export HTTPS_INSECURE=1 + _info "Log in to the FRITZ!Box" - _fritzbox_challenge="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." @@ -91,10 +90,17 @@ fritzbox_deploy() { } >>"${_post_request}" _info "Upload certificate to the FRITZ!Box" - wget --no-check-certificate -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL - _info "Upload successful" + export _H1="Content-type: multipart/form-data boundary=${_post_boundary}" + _post "$(cat ${_post_request})" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL + + retval=$? + if [ $retval = 0 ] ; then + _info "Upload successful" + else + _err "Upload failed" + fi rm "${_post_request}" - return 0 + return $retval } From 8ee5ede834f2493b9d0e3af9a251ccfbaf4156ec Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:30:40 +0200 Subject: [PATCH 1126/1348] Fix more formatting errors --- deploy/fritzbox.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index e7d01a8b..a6f6684c 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -92,10 +92,10 @@ fritzbox_deploy() { _info "Upload certificate to the FRITZ!Box" export _H1="Content-type: multipart/form-data boundary=${_post_boundary}" - _post "$(cat ${_post_request})" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL + _post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL retval=$? - if [ $retval = 0 ] ; then + if [ $retval = 0 ]; then _info "Upload successful" else _err "Upload failed" From 72e1eb88d969dfb26935b1c8070db7685105d6b1 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:40:28 +0200 Subject: [PATCH 1127/1348] Don't use individual redirects, but do it all in one block. --- deploy/fritzbox.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index a6f6684c..dbff3680 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -82,9 +82,7 @@ fritzbox_deploy() { printf -- "--%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" printf "Content-Type: application/octet-stream\r\n\r\n" - } >>"${_post_request}" - cat "${_ckey}" "${_cfullchain}" >>"${_post_request}" - { + cat "${_ckey}" "${_cfullchain}" printf "\r\n" printf -- "--%s--" "${_post_boundary}" } >>"${_post_request}" From 1e30718df63555700444226ef056f132f8620a1c Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:48:27 +0200 Subject: [PATCH 1128/1348] Try and work around shellcheck error SC2039: In POSIX sh, printf -%s-- is undefined. --- deploy/fritzbox.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index dbff3680..943b198d 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -75,16 +75,20 @@ fritzbox_deploy() { # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it! _CERTPASSWORD_= { - printf -- "--%s\r\n" "${_post_boundary}" + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" - printf -- "--%s\r\n" "${_post_boundary}" + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" - printf -- "--%s\r\n" "${_post_boundary}" + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" printf "Content-Type: application/octet-stream\r\n\r\n" cat "${_ckey}" "${_cfullchain}" printf "\r\n" - printf -- "--%s--" "${_post_boundary}" + printf -- "--" + printf -- "%s--" "${_post_boundary}" } >>"${_post_request}" _info "Upload certificate to the FRITZ!Box" From 8148bfeacf43a311551c00473f39c514e5f50d52 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 5 Sep 2017 20:32:14 +0800 Subject: [PATCH 1129/1348] fix https://github.com/Neilpang/acme.sh/issues/998 --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e482b87b..d9855651 100755 --- a/acme.sh +++ b/acme.sh @@ -1814,7 +1814,12 @@ _send_signed_request() { _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - if _contains "$response" "JWS has invalid anti-replay nonce"; then + _body="$response" + if [ "$needbase64" ]; then + _body="$(echo "$_body" | _dbase64)" + fi + _debug3 _body "$_body" + if _contains "$_body" "JWS has invalid anti-replay nonce"; then _info "It seems the CA server is busy now, let's wait and retry." _request_retry_times=$(_math "$_request_retry_times" + 1) _sleep 5 From f81d4033fa0e85f4a4cb789e250bb52d3a282e5f Mon Sep 17 00:00:00 2001 From: Santeri Kannisto Date: Tue, 5 Sep 2017 17:37:48 +0400 Subject: [PATCH 1130/1348] One cert per domain Deploy works only for the first domain --- deploy/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/README.md b/deploy/README.md index 62a3fb6f..48caea6f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -94,6 +94,7 @@ DEPLOY_CPANEL_USER is required only if you run the script as root and it should export DEPLOY_CPANEL_USER=username acme.sh --deploy -d example.com --deploy-hook cpanel_uapi ``` +Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue only one certificate per domain. From a9726fde1948c7404e8873e9b6264785081b025a Mon Sep 17 00:00:00 2001 From: Santeri Kannisto Date: Tue, 5 Sep 2017 17:42:17 +0400 Subject: [PATCH 1131/1348] 1 cert per domain for cpanel_uapi --- deploy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 48caea6f..c80a567e 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -94,7 +94,7 @@ DEPLOY_CPANEL_USER is required only if you run the script as root and it should export DEPLOY_CPANEL_USER=username acme.sh --deploy -d example.com --deploy-hook cpanel_uapi ``` -Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue only one certificate per domain. +Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain. From 3eeb090578a371eb5e5ce507adb27a6cf1676ac8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 6 Sep 2017 20:50:31 +0800 Subject: [PATCH 1132/1348] fix tls mode back to use openssl --- acme.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index d9855651..83c06fa5 100755 --- a/acme.sh +++ b/acme.sh @@ -2053,7 +2053,12 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="socat" + __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY " + if [ "$opaddr" ]; then + __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" + else + __S_OPENSSL="$__S_OPENSSL -accept $port" + fi _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" @@ -2064,9 +2069,12 @@ _starttlsserver() { fi _debug "$__S_OPENSSL" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + $__S_OPENSSL -tlsextdebug & + else + $__S_OPENSSL >/dev/null 2>&1 & + fi - #todo listen address - $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 53273a15bf54d2b3c48e8351c592f42ee1e49dab Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 6 Sep 2017 21:18:02 +0800 Subject: [PATCH 1133/1348] use socat for tls mode --- acme.sh | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index 83c06fa5..d9855651 100755 --- a/acme.sh +++ b/acme.sh @@ -2053,12 +2053,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY " - if [ "$opaddr" ]; then - __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" - else - __S_OPENSSL="$__S_OPENSSL -accept $port" - fi + __S_OPENSSL="socat" _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" @@ -2069,12 +2064,9 @@ _starttlsserver() { fi _debug "$__S_OPENSSL" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - $__S_OPENSSL -tlsextdebug & - else - $__S_OPENSSL >/dev/null 2>&1 & - fi + #todo listen address + $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 856811bd2e23279fcc44efed041c65e011253eb7 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 6 Sep 2017 17:04:40 +0000 Subject: [PATCH 1134/1348] Use stable gandi API url The gandi api has changed its url for a more stable one. Although https://dns.beta.gandi.net will continue to work for the foreseable future, this commits updates the url to new official one. --- dnsapi/dns_gandi_livedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 82ed599c..7a21aba6 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -11,7 +11,7 @@ # ######## Public functions ##################### -GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5" +GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5" #Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_gandi_livedns_add() { From a6b399286e4dcd387c5193589358d066174d51eb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 9 Sep 2017 14:15:11 +0800 Subject: [PATCH 1135/1348] add socat --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7ca042ea..e85098e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ RUN apk update -f \ && apk --no-cache add -f \ openssl \ curl \ - netcat-openbsd \ + socat \ && rm -rf /var/cache/apk/* ENV LE_CONFIG_HOME /acme.sh From 36309e6dbc5b074b108c268bb2a652689aae379d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 11 Sep 2017 21:28:37 +0800 Subject: [PATCH 1136/1348] minor, fix debug info --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d9855651..b1a7f68a 100755 --- a/acme.sh +++ b/acme.sh @@ -1817,8 +1817,9 @@ _send_signed_request() { _body="$response" if [ "$needbase64" ]; then _body="$(echo "$_body" | _dbase64)" + _debug2 _body "$_body" fi - _debug3 _body "$_body" + if _contains "$_body" "JWS has invalid anti-replay nonce"; then _info "It seems the CA server is busy now, let's wait and retry." _request_retry_times=$(_math "$_request_retry_times" + 1) From 95949b6519b4b7e8de5f8dc83ef900d558caa331 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 11 Sep 2017 21:40:56 +0800 Subject: [PATCH 1137/1348] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index b1a7f68a..e7746931 100755 --- a/acme.sh +++ b/acme.sh @@ -1987,7 +1987,7 @@ _startserver() { _debug "_NC" "$_NC" #todo listen address - socat TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + $_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" } From 2fc0225bc98da5e0a7221c12ea13b20c9cf26ec2 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 12 Sep 2017 11:35:21 +0200 Subject: [PATCH 1138/1348] Make command line example consistent with env variable example. --- deploy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index f76c667a..af6fc5f3 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -108,6 +108,6 @@ $ export DEPLOY_FRITZBOX_URL=https://fritzbox.example.com After the first deployment, these values will be stored in your $HOME/.acme.sh/account.conf. You may now deploy the certificate like this: ```sh -acme.sh --deploy -d fritz.box --deploy-hook fritzbox +acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox ``` From 270ce87582e8749b629033c2448bccf313aeb365 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 23 Sep 2017 22:12:17 +0800 Subject: [PATCH 1139/1348] add debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index e7746931..0f2a436d 100755 --- a/acme.sh +++ b/acme.sh @@ -2241,6 +2241,7 @@ _initpath() { fi fi + _debug2 ACME_DIRECTORY "$ACME_DIRECTORY" _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" From acf117584bb92c3c5e06774ef1c5b5fd7c4582cc Mon Sep 17 00:00:00 2001 From: Santeri Kannisto Date: Tue, 26 Sep 2017 07:04:30 +0400 Subject: [PATCH 1140/1348] #1042 Apparently UAPI does not return any error code, just JSON output that has a string "status: 0" whenever the command fails. --- deploy/cpanel_uapi.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index 2ba112c4..4563b9c4 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -51,8 +51,8 @@ cpanel_uapi_deploy() { else _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") fi - - if [ $? -ne 0 ]; then + error_response="status: 0" + if test "${_response#*$error_response}" != "$_response"; then _err "Error in deploying certificate:" _err "$_response" return 1 From 5261162fdfbc4cfe458267e822a9f89a4bea7f16 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 26 Sep 2017 19:43:06 +0400 Subject: [PATCH 1141/1348] Remove stray single-quote Get rid of a single stray erroneous single-quote that is breaking socat when using standalone mode. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 0f2a436d..3e63282d 100755 --- a/acme.sh +++ b/acme.sh @@ -1987,7 +1987,7 @@ _startserver() { _debug "_NC" "$_NC" #todo listen address - $_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + $_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK; echo ; echo $content; echo;" & serverproc="$!" } From 754a4a7c8bef3fcaa384be159e1744cdae0399bc Mon Sep 17 00:00:00 2001 From: sahsanu Date: Sat, 30 Sep 2017 20:12:53 +0200 Subject: [PATCH 1142/1348] Update dns_cloudns.sh Added code to save CLOUDNS_AUTH_ID and CLOUDNS_AUTH_PASSWORD on account.conf file so the id and password for cloudns can be reused. --- dnsapi/dns_cloudns.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index f48a8052..14403a7d 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -96,6 +96,16 @@ _dns_cloudns_init_check() { return 0 fi + CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" + CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" + if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + CLOUDNS_AUTH_ID="" + CLOUDNS_AUTH_PASSWORD="" + _err "You don't specify cloudns api id and password yet." + _err "Please create you id and password and try again." + return 1 + fi + if [ -z "$CLOUDNS_AUTH_ID" ]; then _err "CLOUDNS_AUTH_ID is not configured" return 1 @@ -113,8 +123,12 @@ _dns_cloudns_init_check() { return 1 fi + #save the api id and password to the account conf file. + _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + CLOUDNS_INIT_CHECK_COMPLETED=1 - + return 0 } From 6c7da215e7d364fb9d9af3274397c947269b966e Mon Sep 17 00:00:00 2001 From: sahsanu Date: Sun, 1 Oct 2017 10:06:38 +0200 Subject: [PATCH 1143/1348] Update dns_cloudns.sh --- dnsapi/dns_cloudns.sh | 272 ++++++++++++++++++++---------------------- 1 file changed, 129 insertions(+), 143 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 14403a7d..2ad77ca0 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -11,174 +11,160 @@ CLOUDNS_API="https://api.cloudns.net" #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 + _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 + _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 - - CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" - CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" - if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then - CLOUDNS_AUTH_ID="" - CLOUDNS_AUTH_PASSWORD="" - _err "You don't specify cloudns api id and password yet." - _err "Please create you id and password and try again." - return 1 - 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 - - #save the api id and password to the account conf file. - _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" - _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - - CLOUDNS_INIT_CHECK_COMPLETED=1 - - return 0 + 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) + i=2 + while true; do + zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) - if [ -z "$zoneForCheck" ]; then - return 1 - fi + if [ -z "$zoneForCheck" ]; then + return 1 + fi - _debug zoneForCheck "$zoneForCheck" + _debug zoneForCheck "$zoneForCheck" - _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$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 + if ! _contains "$response" "\"status\":\"Failed\""; then + echo "$zoneForCheck" + return 0 + fi - i=$(_math "$i" + 1) - done - return 1 + 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 "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 + method=$1 - _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" - _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + _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 + 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")" + response="$(_get "$CLOUDNS_API/$method?$data")" - _debug2 response "$response" + _debug2 response "$response" - return 0 + return 0 } From c73c33f94c4d5731ef1d9bee92a33ab71dea1f92 Mon Sep 17 00:00:00 2001 From: sahsanu Date: Sun, 1 Oct 2017 10:31:38 +0200 Subject: [PATCH 1144/1348] Update dns_cloudns.sh --- dnsapi/dns_cloudns.sh | 272 ++++++++++++++++++++++-------------------- 1 file changed, 143 insertions(+), 129 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 2ad77ca0..b1861b24 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -11,160 +11,174 @@ CLOUDNS_API="https://api.cloudns.net" #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 + _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 + _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 + if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then + return 0 + fi + + CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" + CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" + if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + CLOUDNS_AUTH_ID="" + CLOUDNS_AUTH_PASSWORD="" + _err "You don't specify cloudns api id and password yet." + _err "Please create you id and password and try again." + return 1 + 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 + + #save the api id and password to the account conf file. + _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + + 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) + i=2 + while true; do + zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) - if [ -z "$zoneForCheck" ]; then - return 1 - fi + if [ -z "$zoneForCheck" ]; then + return 1 + fi - _debug zoneForCheck "$zoneForCheck" + _debug zoneForCheck "$zoneForCheck" - _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$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 + if ! _contains "$response" "\"status\":\"Failed\""; then + echo "$zoneForCheck" + return 0 + fi - i=$(_math "$i" + 1) - done - return 1 + 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 "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 + method=$1 - _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" - _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + _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 + 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")" + response="$(_get "$CLOUDNS_API/$method?$data")" - _debug2 response "$response" + _debug2 response "$response" - return 0 + return 0 } From 641a2895a6282472fe3c8d52e5289165bf8a3d7d Mon Sep 17 00:00:00 2001 From: hiska Date: Mon, 2 Oct 2017 08:32:36 +0900 Subject: [PATCH 1145/1348] Create strongswan.sh --- deploy/strongswan.sh | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 deploy/strongswan.sh diff --git a/deploy/strongswan.sh b/deploy/strongswan.sh new file mode 100644 index 00000000..73232785 --- /dev/null +++ b/deploy/strongswan.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env sh + +#Here is a sample custom api script. +#This file name is "myapi.sh" +#So, here must be a method myapi_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +strongswan_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + cat "$_ckey" >"/etc/ipsec.d/private/$(basename "$_ckey")" + cat "$_ccert" >"/etc/ipsec.d/certs/$(basename "$_ccert")" + cat "$_cca" >"/etc/ipsec.d/cacerts/$(basename "$_cca")" + cat "$_cfullchain" >"/etc/ipsec.d/cacerts/$(basename "$_cfullchain")" + + ipsec reload + + return 0 + +} From afe3283c53930c66017aadbb8e35d5f01b3c714e Mon Sep 17 00:00:00 2001 From: hiska Date: Mon, 2 Oct 2017 08:34:32 +0900 Subject: [PATCH 1146/1348] Update README.md --- deploy/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index c80a567e..31053579 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -97,6 +97,10 @@ acme.sh --deploy -d example.com --deploy-hook cpanel_uapi Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain. +## 8. Deploy the cert to strongswan +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook strongswan +``` From 372f691fd69a191cb2d718ace2d6f6a16568514e Mon Sep 17 00:00:00 2001 From: hebbet Date: Mon, 2 Oct 2017 15:04:02 +0200 Subject: [PATCH 1147/1348] unify headlines unify headlines in deploy readme --- deploy/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index af6fc5f3..4e4a7261 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -4,7 +4,7 @@ Before you can deploy your cert, you must [issue the cert first](https://github. Here are the scripts to deploy the certs/key to the server/services. -## 1. Deploy the certs to your cpanel host. +## 1. Deploy the certs to your cpanel host If you want to deploy using cpanel UAPI see 7. @@ -20,7 +20,7 @@ export DEPLOY_CPANEL_PASSWORD=PASSWORD 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). Currently supports Kong-v0.10.x. @@ -29,11 +29,11 @@ Currently supports Kong-v0.10.x. 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 (TODO) -## 4. Deploy the cert to local vsftpd server. +## 4. Deploy the cert to local vsftpd server ```sh acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd @@ -55,7 +55,7 @@ export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart" acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd ``` -## 5. Deploy the cert to local exim4 server. +## 5. Deploy the cert to local exim4 server ```sh acme.sh --deploy -d ftp.example.com --deploy-hook exim4 From c924e7c537249a33713e8dc6691ae3311e0b7a23 Mon Sep 17 00:00:00 2001 From: hiska Date: Wed, 4 Oct 2017 06:44:02 +0900 Subject: [PATCH 1148/1348] remove "return 0" --- deploy/strongswan.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/deploy/strongswan.sh b/deploy/strongswan.sh index 73232785..2de18f88 100644 --- a/deploy/strongswan.sh +++ b/deploy/strongswan.sh @@ -29,6 +29,4 @@ strongswan_deploy() { ipsec reload - return 0 - } From ee56b9cd4e50da0ff36af392676074d3914f12d7 Mon Sep 17 00:00:00 2001 From: sahsanu Date: Sat, 7 Oct 2017 21:31:24 +0200 Subject: [PATCH 1149/1348] Update ClouDNS.net API doc Update ClouDNS.net API doc to show that CLOUDNS_AUTH_ID and CLOUDNS_AUTH_PASSWORD will be saved in ~/.acme.sh/account.conf --- dnsapi/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 34b38678..ce8bbfb9 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -420,6 +420,7 @@ Ok, let's issue a cert now: ``` acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com ``` +The `CLOUDNS_AUTH_ID` and `CLOUDNS_AUTH_PASSWORD` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. ## 22. Use Infoblox API From 5f6e3da766ef6ffcefca8d5ced3df4b2fcdd7a62 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 8 Oct 2017 19:45:50 +0800 Subject: [PATCH 1150/1348] fix https://github.com/Neilpang/acme.sh/issues/1062 change back to use openssl for tls mode. --- acme.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 3e63282d..9b917f7b 100755 --- a/acme.sh +++ b/acme.sh @@ -2054,7 +2054,12 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="socat" + __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY " + if [ "$opaddr" ]; then + __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" + else + __S_OPENSSL="$__S_OPENSSL -accept $port" + fi _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" @@ -2065,9 +2070,12 @@ _starttlsserver() { fi _debug "$__S_OPENSSL" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + $__S_OPENSSL -tlsextdebug & + else + $__S_OPENSSL >/dev/null 2>&1 & + fi - #todo listen address - $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 872bfe4757a9593e1a3a6f8e9969ad465ef66beb Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 11 Oct 2017 20:34:56 +0800 Subject: [PATCH 1151/1348] fix for PR https://github.com/Neilpang/acme.sh/pull/1069 --- dnsapi/dns_aws.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 40782573..5a716514 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -87,6 +87,7 @@ _get_root() { _debug "response" "$response" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" if [ -z "$h" ]; then if _contains "$response" "true" && _contains "$response" ""; then _debug "IsTruncated" @@ -102,23 +103,23 @@ _get_root() { fi fi #not valid + _err "Invalid domain" return 1 fi if _contains "$response" "$h."; then hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*false<.PrivateZone>.*<.HostedZone>")" _debug hostedzone "$hostedzone" - if [ -z "$hostedzone" ]; then - _err "Error, can not get hostedzone." + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + _err "Can not find domain id: $h" return 1 fi - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | 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) From 352dd907ac0d90ed5cecf4a9553a59d25ca4ac3d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 18 Oct 2017 20:27:09 +0800 Subject: [PATCH 1152/1348] fix https://github.com/Neilpang/acme.sh/issues/1074 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 9b917f7b..d988eb06 100755 --- a/acme.sh +++ b/acme.sh @@ -3135,7 +3135,7 @@ _regAccount() { fi if [ "$code" = '202' ]; then _info "Update account tos info success." - + echo "$response" >"$ACCOUNT_JSON_PATH" CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" _savecaconf CA_KEY_HASH "$CA_KEY_HASH" From 7902d10a3aaeff25bd2225e5c2ffd1af1f8e834b Mon Sep 17 00:00:00 2001 From: max2711 <32955673+max2711@users.noreply.github.com> Date: Fri, 20 Oct 2017 14:22:20 +0200 Subject: [PATCH 1153/1348] remove unused crontab jobs --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e85098e0..97626ba0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ 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) && rm -rf /install_acme.sh/ -RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | sed 's#> /dev/null##' | crontab - +RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab - RUN for verb in help \ version \ From 4c99c0127b849a8db29151a10b78acb66f78ebdd Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 1 Nov 2017 10:14:44 +0800 Subject: [PATCH 1154/1348] add dev guide --- dnsapi/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index ce8bbfb9..cff59c79 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -618,6 +618,7 @@ acme.sh --issue --dns dns_myapi -d example.com -d www.example.com For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) +See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide # Use lexicon DNS API From 212d0f24d8d264c30969d5f19bb61c5840ae5108 Mon Sep 17 00:00:00 2001 From: Daniel Lo Nigro Date: Tue, 31 Oct 2017 22:35:15 -0700 Subject: [PATCH 1155/1348] [cloudns] Add support for sub user IDs --- dnsapi/README.md | 7 +++++-- dnsapi/dns_cloudns.sh | 20 +++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index cff59c79..7aeef011 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -409,10 +409,13 @@ 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/ +You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/. For security reasons, it's recommended to use a sub user ID that only has access to the necessary zones, as a regular API user has access to your entire account. ``` -export CLOUDNS_AUTH_ID=XXXXX +# Use this for a sub auth ID +export CLOUDNS_SUB_AUTH_ID=XXXXX +# Use this for a regular auth ID +#export CLOUDNS_AUTH_ID=XXXXX export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" ``` diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index b1861b24..c459551f 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -97,17 +97,19 @@ _dns_cloudns_init_check() { fi CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" + CLOUDNS_SUB_AUTH_ID="${CLOUDNS_SUB_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_SUB_AUTH_ID)}" CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" - if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + if [ -z "$CLOUDNS_AUTH_ID$CLOUDNS_SUB_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then CLOUDNS_AUTH_ID="" + CLOUDNS_SUB_AUTH_ID="" CLOUDNS_AUTH_PASSWORD="" _err "You don't specify cloudns api id and password yet." _err "Please create you id and password and try again." return 1 fi - if [ -z "$CLOUDNS_AUTH_ID" ]; then - _err "CLOUDNS_AUTH_ID is not configured" + if [ -z "$CLOUDNS_AUTH_ID" ] && [ -z "$CLOUDNS_SUB_AUTH_ID" ]; then + _err "CLOUDNS_AUTH_ID or CLOUDNS_SUB_AUTH_ID is not configured" return 1 fi @@ -125,6 +127,7 @@ _dns_cloudns_init_check() { #save the api id and password to the account conf file. _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _saveaccountconf_mutable CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID" _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" CLOUDNS_INIT_CHECK_COMPLETED=1 @@ -168,12 +171,19 @@ _dns_cloudns_http_api_call() { method=$1 _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _debug CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID" _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + if [ ! -z "$CLOUDNS_SUB_AUTH_ID" ]; then + auth_user="sub-auth-id=$CLOUDNS_SUB_AUTH_ID" + else + auth_user="auth-id=$CLOUDNS_AUTH_ID" + fi; + if [ -z "$2" ]; then - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" + data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD" else - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" fi response="$(_get "$CLOUDNS_API/$method?$data")" From 6e93ff8bcac9744ff451181b6feeb7269d2ce1a8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 10 Nov 2017 23:01:29 +0800 Subject: [PATCH 1156/1348] fix https://github.com/Neilpang/acme.sh/issues/1106 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d988eb06..9c8d6d4e 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.4 +VER=2.7.5 PROJECT_NAME="acme.sh" @@ -3474,7 +3474,7 @@ issue() { token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" _debug uri "$uri" keyauthorization="$token.$thumbprint" From bab4f691c5bade8a50a88ef715b834c8ec18cb1e Mon Sep 17 00:00:00 2001 From: Daniel Lo Nigro Date: Sun, 12 Nov 2017 18:38:30 -0800 Subject: [PATCH 1157/1348] Fix lint warning --- dnsapi/dns_cloudns.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index c459551f..4a1ae641 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -4,6 +4,7 @@ # Repository: https://github.com/ClouDNS/acme.sh/ #CLOUDNS_AUTH_ID=XXXXX +#CLOUDNS_SUB_AUTH_ID=XXXXX #CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" CLOUDNS_API="https://api.cloudns.net" @@ -178,7 +179,7 @@ _dns_cloudns_http_api_call() { auth_user="sub-auth-id=$CLOUDNS_SUB_AUTH_ID" else auth_user="auth-id=$CLOUDNS_AUTH_ID" - fi; + fi if [ -z "$2" ]; then data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD" From f62457a24e2f286f309c245b09bd52631f8e00f9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 13 Nov 2017 20:54:29 +0800 Subject: [PATCH 1158/1348] fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b45cc464..dda8eb10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ install: openssl version 2>&1 || true; $ACME_OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; - else sudo apt-get install socat; + else sudo apt-get -y update && sudo apt-get install -y socat; fi script: From ceafe389afb406b92f77392fd7fe2005cb6b750f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 26 Nov 2017 20:57:02 +0800 Subject: [PATCH 1159/1348] fix https://github.com/Neilpang/acme.sh/issues/1109 --- dnsapi/dns_freedns.sh | 77 ++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 53da4118..ae77d061 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,6 +53,8 @@ dns_freedns_add() { i="$(_math "$i" - 1)" sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" + _debug top_domain "$top_domain" + _debug sub_domain "$sub_domain" # Sometimes FreeDNS does not return the subdomain page but rather # returns a page regarding becoming a premium member. This usually # happens after a period of inactivity. Immediately trying again @@ -61,7 +63,6 @@ dns_freedns_add() { attempts=2 while [ "$attempts" -gt "0" ]; do attempts="$(_math "$attempts" - 1)" - htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" if [ "$?" != "0" ]; then if [ "$using_cached_cookies" = "true" ]; then @@ -70,19 +71,11 @@ dns_freedns_add() { fi return 1 fi + _debug2 htmlpage "$htmlpage" + + subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '
' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep $top_domain)" + _debug2 subdomain_csv "$subdomain_csv" - # Now convert the tables in the HTML to CSV. This litte gem from - # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv - subdomain_csv="$(echo "$htmlpage" \ - | grep -i -e ']*>/\n/Ig' \ - | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ - | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ - | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ - | grep 'edit.php?' \ - | grep "$top_domain")" # The above beauty ends with striping out rows that do not have an # href to edit.php and do not have the top domain we are looking for. # So all we should be left with is CSV of table of subdomains we are @@ -90,30 +83,32 @@ dns_freedns_add() { # Now we have to read through this table and extract the data we need lines="$(echo "$subdomain_csv" | wc -l)" - nl=' -' i=0 found=0 while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" - tmp="$(echo "$line" | cut -d ',' -f 1)" - if [ $found = 0 ] && _startswith "$tmp" "$top_domain"; then + line="$(echo "$subdomain_csv" | sed -n ${i}p)" + _debug2 line "$line" + if [ $found = 0 ] && _contains "$line" "$top_domain"; then # this line will contain DNSdomainid for the top_domain - DNSdomainid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')" + DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)" + _debug2 DNSdomainid "$DNSdomainid" found=1 else # lines contain DNS records for all subdomains - DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" - DNStype="$(echo "$line" | cut -d ',' -f 3)" + DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug2 DNSname "$DNSname" + DNStype="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" + _debug2 DNStype "$DNStype" if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" + DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" # Now get current value for the TXT record. This method may # not produce accurate results as the value field is truncated # on this webpage. To get full value we would need to load # another page. However we don't really need this so long as # 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" | sed 's/' -f 2 | cut -d '<' -f 1)" + _debug2 DNSvalue "$DNSvalue" if [ $found != 0 ]; then break # we are breaking out of the loop at the first match of DNS name @@ -169,8 +164,7 @@ dns_freedns_add() { return 0 else # Delete the old TXT record (with the wrong value) - _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" - if [ "$?" = "0" ]; then + if _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"; then # And add in new TXT record with the value provided _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" fi @@ -210,18 +204,9 @@ dns_freedns_rm() { return 1 fi - # Now convert the tables in the HTML to CSV. This litte gem from - # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv - subdomain_csv="$(echo "$htmlpage" \ - | grep -i -e ']*>/\n/Ig' \ - | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ - | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ - | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ - | grep 'edit.php?' \ - | grep "$fulldomain")" + subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep $fulldomain)" + _debug2 subdomain_csv "$subdomain_csv" + # The above beauty ends with striping out rows that do not have an # href to edit.php and do not have the domain name we are looking for. # So all we should be left with is CSV of table of subdomains we are @@ -229,19 +214,21 @@ dns_freedns_rm() { # Now we have to read through this table and extract the data we need lines="$(echo "$subdomain_csv" | wc -l)" - nl=' -' i=0 found=0 while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" - DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" - DNStype="$(echo "$line" | cut -d ',' -f 3)" + line="$(echo "$subdomain_csv" | sed -n ${i}p)" + _debug2 line "$line" + DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug2 DNSname "$DNSname" + DNStype="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" + _debug2 DNStype "$DNStype" if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" - DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" - _debug "DNSvalue: $DNSvalue" + DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" + _debug2 DNSdataid "$DNSdataid" + DNSvalue="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" + _debug2 DNSvalue "$DNSvalue" # if [ "$DNSvalue" = "$txtvalue" ]; then # Testing value match fails. Website is truncating the value # field. So for now we will assume that there is only one TXT From b615cce92d69c0de937a15538ef764a21fda33b5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Dec 2017 19:54:33 +0800 Subject: [PATCH 1160/1348] fix https://github.com/Neilpang/acme.sh/issues/1127 --- Dockerfile | 2 +- acme.sh | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 97626ba0..b2866739 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine +FROM alpine:3.6 RUN apk update -f \ && apk --no-cache add -f \ diff --git a/acme.sh b/acme.sh index 9c8d6d4e..98f4067a 100755 --- a/acme.sh +++ b/acme.sh @@ -463,8 +463,7 @@ if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then fi _h2b() { - if _exists xxd; then - xxd -r -p + if _exists xxd && xxd -r -p 2>/dev/null; then return fi From 529cbc037900506969e996e98903d7e60b211751 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Dec 2017 12:51:51 +0800 Subject: [PATCH 1161/1348] run ci in docker --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dda8eb10..ab5632dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,14 @@ language: shell sudo: required +dist: trusty os: - linux - osx +services: + - docker + env: global: - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 @@ -30,7 +34,6 @@ install: openssl version 2>&1 || true; $ACME_OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; - else sudo apt-get -y update && sudo apt-get install -y socat; fi script: @@ -44,7 +47,7 @@ script: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi From dcf8457f4d4b6d80236557fbc77ecd7060f56ec0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Dec 2017 13:16:37 +0800 Subject: [PATCH 1162/1348] fix format --- dnsapi/dns_freedns.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index ae77d061..afd8b796 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -73,7 +73,7 @@ dns_freedns_add() { fi _debug2 htmlpage "$htmlpage" - subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep $top_domain)" + subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep "$top_domain")" _debug2 subdomain_csv "$subdomain_csv" # The above beauty ends with striping out rows that do not have an @@ -87,7 +87,7 @@ dns_freedns_add() { found=0 while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | sed -n ${i}p)" + line="$(echo "$subdomain_csv" | sed -n "${i}p")" _debug2 line "$line" if [ $found = 0 ] && _contains "$line" "$top_domain"; then # this line will contain DNSdomainid for the top_domain @@ -204,7 +204,7 @@ dns_freedns_rm() { return 1 fi - subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep $fulldomain)" + subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")" _debug2 subdomain_csv "$subdomain_csv" # The above beauty ends with striping out rows that do not have an @@ -218,7 +218,7 @@ dns_freedns_rm() { found=0 while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | sed -n ${i}p)" + line="$(echo "$subdomain_csv" | sed -n "${i}p")" _debug2 line "$line" DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug2 DNSname "$DNSname" From 9eeebb147f9747a68e567ac40e202c51dc7aa4a3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Dec 2017 20:57:25 +0800 Subject: [PATCH 1163/1348] fix osx build --- .travis.yml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab5632dd..b6b57423 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,20 +22,10 @@ addons: install: - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then - brew update && brew install openssl socat; - brew info openssl; - ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; - _old_path="$PATH"; - echo "PATH=$PATH"; - export PATH=""; - export ACME_OPENSSL_BIN="/usr/local/openssl"; - openssl version 2>&1 || true; - $ACME_OPENSSL_BIN version 2>&1 || true; - export PATH="$_old_path"; + brew update && brew install socat; + export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" ; fi - + script: - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - command -V openssl && openssl version From 0ca3141088ead8a638c5067519e6c97216f699cf Mon Sep 17 00:00:00 2001 From: Aarup Date: Wed, 6 Dec 2017 11:50:54 +0100 Subject: [PATCH 1164/1348] Added support for UnoEuro api --- dnsapi/dns_unoeuro.sh | 194 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 dnsapi/dns_unoeuro.sh diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh new file mode 100644 index 00000000..985b441d --- /dev/null +++ b/dnsapi/dns_unoeuro.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env sh + +# +#Uno_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#Uno_User="UExxxxxx" + +Uno_Api="https://api.unoeuro.com/1/$Uno_User/$Uno_Key" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_unoeuro_add() { + fulldomain=$1 + txtvalue=$2 + + Uno_Key="${Uno_Key:-$(_readaccountconf_mutable Uno_Key)}" + Uno_User="${Uno_User:-$(_readaccountconf_mutable Uno_User)}" + if [ -z "$Uno_Key" ] || [ -z "$Uno_User" ]; then + Uno_Key="" + Uno_User="" + _err "You haven't specified a UnoEuro api key and account yet." + _err "Please create your key and try again." + return 1 + fi + + if ! _contains "$Uno_User" "UE"; then + _err "It seems that the Uno_User=$Uno_User is not a valid email address." + _err "Please check and retry." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable Uno_Key "$Uno_Key" + _saveaccountconf_mutable Uno_User "$Uno_User" + + _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" + _uno_rest GET "my/products/$h/dns/records" + + if ! _contains "$response" "\"status\": 200" >/dev/null; then + _err "Error" + return 1 + fi + + if ! _contains "$response" "$_sub_domain" >/dev/null; then + _info "Adding record" + if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then + if _contains "$response" "\"status\": 200" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | head -1 | _egrep_o "[0-9]{1,}") + _debug "record_id" "$record_id" + + _uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}" + if _contains "$response" "\"status\": 200" >/dev/null; then + _info "Updated, OK" + return 0 + fi + _err "Update error" + return 1 + fi + +} + +#fulldomain txtvalue +dns_unoeuro_rm() { + fulldomain=$1 + txtvalue=$2 + + Uno_Key="${Uno_Key:-$(_readaccountconf_mutable Uno_Key)}" + Uno_User="${Uno_User:-$(_readaccountconf_mutable Uno_User)}" + if [ -z "$Uno_Key" ] || [ -z "$Uno_User" ]; then + Uno_Key="" + Uno_User="" + _err "You haven't specified a UnoEuro api key and account yet." + _err "Please create your key and try again." + return 1 + fi + + _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" + _uno_rest GET "my/products/$h/dns/records" + + if ! _contains "$response" "\"status\": 200" >/dev/null; then + _err "Error" + return 1 + fi + + if ! _contains "$response" "$_sub_domain" >/dev/null; then + _info "Don't need to remove." + else + record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | head -1 | _egrep_o "[0-9]{1,}") + _debug "record_id" "$record_id" + + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + + if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "\"status\": 200" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_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 ! _uno_rest GET "my/products/$h/dns/records"; then + return 1 + fi + + if _contains "$response" "\"status\": 200" >/dev/null; then + _domain_id=$h + 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 +} + +_uno_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + #export _H1="X-Auth-Email: $Uno_User" + #export _H2="X-Auth-Key: $Uno_Key" + export _H1="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$Uno_Api/$ep" "" "$m")" + else + response="$(_get "$Uno_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 70702e41e994ce98dac23b06bf59e2bbcdf4f560 Mon Sep 17 00:00:00 2001 From: Aarup Date: Wed, 6 Dec 2017 11:55:29 +0100 Subject: [PATCH 1165/1348] Use _head_n --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 985b441d..4774187d 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -65,7 +65,7 @@ dns_unoeuro_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | head -1 | _egrep_o "[0-9]{1,}") + record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | _head_n -1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" _uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}" @@ -114,7 +114,7 @@ dns_unoeuro_rm() { if ! _contains "$response" "$_sub_domain" >/dev/null; then _info "Don't need to remove." else - record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | head -1 | _egrep_o "[0-9]{1,}") + record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | _head_n -1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" if [ -z "$record_id" ]; then From 78712245f70800f4bd4875732271b9e96af1c4f9 Mon Sep 17 00:00:00 2001 From: Aarup Date: Wed, 6 Dec 2017 12:13:40 +0100 Subject: [PATCH 1166/1348] Add UnoEuro to README --- README.md | 1 + dnsapi/README.md | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/README.md b/README.md index 7d4353c6..9e64e613 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,7 @@ You don't have to do anything manually! 1. Dyn Managed DNS API 1. Yandex PDD API (https://pdd.yandex.ru) 1. Hurricane Electric DNS service (https://dns.he.net) +1. UnoEuro API (https://www.unoeuro.com/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index cff59c79..5fdcd849 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -602,6 +602,22 @@ The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/accoun Please report any issues to https://github.com/angel333/acme.sh or to . +## 32. Use UnoEuro API to automatically issue cert + +First you need to login to your UnoEuro account to get your API key. + +``` +export Uno_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +export Uno_User="UExxxxxx" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_unoeuro -d example.com -d www.example.com +``` + +The `Uno_Key` and `Uno_User` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. From 657334fb67e25b5503d02fc9abba2f5a2dbca410 Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 11:47:01 +0100 Subject: [PATCH 1167/1348] Add support for inwx.de API --- README.md | 1 + dnsapi/README.md | 17 +++ dnsapi/dns_inwx.sh | 365 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 383 insertions(+) create mode 100755 dnsapi/dns_inwx.sh diff --git a/README.md b/README.md index 7d4353c6..e8f94644 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,7 @@ You don't have to do anything manually! 1. Dyn Managed DNS API 1. Yandex PDD API (https://pdd.yandex.ru) 1. Hurricane Electric DNS service (https://dns.he.net) +1. INWX (https://www.inwx.de/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index cff59c79..768f69a3 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -602,6 +602,23 @@ The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/accoun Please report any issues to https://github.com/angel333/acme.sh or to . +## 31. Use INWX + +INWX offers an xmlrpc api with your standard login credentials, set them like so: + +``` +export INWX_User="yourusername" +export INWX_Password="password" +``` + +Then you can issue your certificates with: + +``` +acme.sh --issue --dns dns_inwx -d example.com -d www.example.com +``` + +The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh new file mode 100755 index 00000000..db5b18c8 --- /dev/null +++ b/dnsapi/dns_inwx.sh @@ -0,0 +1,365 @@ +#!/usr/local/bin/bash + +# +#INWX_User="username" +# +#INWX_Password="password" + +INWX_Api="https://api.domrobot.com/xmlrpc/" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_inwx_add() { + fulldomain=$1 + txtvalue=$2 + + INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" + INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" + if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then + INWX_User="" + INWX_Password="" + _err "You don't specify inwx user and password yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable INWX_User "$INWX_User" + _saveaccountconf_mutable INWX_Password "$INWX_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" + + _debug "Getting txt records" + + + printf -v xml_content ' + + nameserver.info + + + + + + domain + + %s + + + + type + + TXT + + + + name + + %s + + + + + + + ' $_domain $_sub_domain + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" > /dev/null; then + _err "Error could net get txt records" + return 1 + fi + + if ! printf "%s" "$response" | grep "count" -q; then + _info "Adding record" + _inwx_add_record $_domain $_sub_domain $txtvalue + else + _record_id=$(printf '%s' $response | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _info "Updating record" + _inwx_update_record $_record_id $txtvalue + fi + +} + +#fulldomain txtvalue +dns_inwx_rm() { + + fulldomain=$1 + txtvalue=$2 + + INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" + INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" + if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then + INWX_User="" + INWX_Password="" + _err "You don't specify inwx user and password yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable INWX_User "$INWX_User" + _saveaccountconf_mutable INWX_Password "$INWX_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" + + _debug "Getting txt records" + + + printf -v xml_content ' + + nameserver.info + + + + + + domain + + %s + + + + type + + TXT + + + + name + + %s + + + + + + + ' $_domain $_sub_domain + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" > /dev/null; then + _err "Error could not get txt records" + return 1 + fi + + if ! printf "%s" "$response" | grep "count" -q; then + _info "Do not need to delete record" + else + _record_id=$(printf '%s' $response | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _info "Deleting record" + _inwx_delete_record $_record_id + fi + + +} + +#################### Private functions below ################################## + +_inwx_login() { + + printf -v xml_content ' + + account.login + + + + + + user + + %s + + + + pass + + %s + + + + + + + ' $INWX_User $INWX_Password + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')" + +} + +_get_root() { + domain=$1 + _debug "get root" + + domain=$1 + i=2 + p=1 + + + export _H1=$(_inwx_login) + printf -v xml_content ' + + nameserver.list + ' + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + 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" "$h"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +_inwx_delete_record() { + record_id=$1 + printf -v xml_content ' + + nameserver.deleteRecord + + + + + + id + + %s + + + + + + + ' $record_id + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 + + +} + +_inwx_update_record() { + record_id=$1 + txtval=$2 + printf -v xml_content ' + + nameserver.updateRecord + + + + + + content + + %s + + + + id + + %s + + + + + + + ' $txtval $record_id + + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 + +} + +_inwx_add_record() { + + domain=$1 + sub_domain=$2 + txtval=$3 + + _debug domain: $domain + _debug value: $txtval + _debug subd: $sub_domain + + printf -v xml_content ' + + nameserver.createRecord + + + + + + domain + + %s + + + + type + + TXT + + + + content + + %s + + + + name + + %s + + + + + + + ' $domain $txtval $sub_domain + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 +} From a8202d4b3780e04b3b68cc7196ee47871e63ee3d Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 12:05:03 +0100 Subject: [PATCH 1168/1348] Fix CI issues --- dnsapi/dns_inwx.sh | 64 +++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index db5b18c8..9e2302b7 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -35,11 +35,9 @@ dns_inwx_add() { fi _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _debug "Getting txt records" - - printf -v xml_content ' + printf -v xml_content ' nameserver.info @@ -68,21 +66,21 @@ dns_inwx_add() { - ' $_domain $_sub_domain + ' "$_domain" "$_sub_domain" response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - if ! printf "%s" "$response" | grep "Command completed successfully" > /dev/null; then + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error could net get txt records" return 1 fi if ! printf "%s" "$response" | grep "count" -q; then _info "Adding record" - _inwx_add_record $_domain $_sub_domain $txtvalue + _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" else - _record_id=$(printf '%s' $response | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') _info "Updating record" - _inwx_update_record $_record_id $txtvalue + _inwx_update_record "$_record_id" "$txtvalue" fi } @@ -117,8 +115,7 @@ dns_inwx_rm() { _debug "Getting txt records" - - printf -v xml_content ' + printf -v xml_content ' nameserver.info @@ -147,10 +144,10 @@ dns_inwx_rm() { - ' $_domain $_sub_domain + ' "$_domain" "$_sub_domain" response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - if ! printf "%s" "$response" | grep "Command completed successfully" > /dev/null; then + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error could not get txt records" return 1 fi @@ -158,12 +155,11 @@ dns_inwx_rm() { if ! printf "%s" "$response" | grep "count" -q; then _info "Do not need to delete record" else - _record_id=$(printf '%s' $response | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') _info "Deleting record" - _inwx_delete_record $_record_id + _inwx_delete_record "$_record_id" fi - } #################### Private functions below ################################## @@ -196,26 +192,26 @@ _inwx_login() { ' $INWX_User $INWX_Password response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')" } _get_root() { - domain=$1 + domain=$1 _debug "get root" domain=$1 i=2 p=1 - - export _H1=$(_inwx_login) + _H1=$(_inwx_login) + export _H1 printf -v xml_content ' nameserver.list ' - + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) @@ -256,17 +252,16 @@ _inwx_delete_record() { - ' $record_id - + ' "$record_id" + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error" return 1 fi return 0 - - + } _inwx_update_record() { @@ -295,17 +290,16 @@ _inwx_update_record() { - ' $txtval $record_id - - + ' "$txtval" "$record_id" + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error" return 1 fi return 0 - + } _inwx_add_record() { @@ -314,10 +308,6 @@ _inwx_add_record() { sub_domain=$2 txtval=$3 - _debug domain: $domain - _debug value: $txtval - _debug subd: $sub_domain - printf -v xml_content ' nameserver.createRecord @@ -353,10 +343,10 @@ _inwx_add_record() { - ' $domain $txtval $sub_domain - + ' "$domain" "$txtval" "$sub_domain" + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error" return 1 From ecba959dd99cda64d72c88c1d9c7d77894f72f80 Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 13:07:05 +0100 Subject: [PATCH 1169/1348] Fix missed whitespaces --- dnsapi/dns_inwx.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 9e2302b7..b02d1fb1 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -155,7 +155,7 @@ dns_inwx_rm() { if ! printf "%s" "$response" | grep "count" -q; then _info "Do not need to delete record" else - _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') _info "Deleting record" _inwx_delete_record "$_record_id" fi @@ -253,7 +253,7 @@ _inwx_delete_record() { ' "$record_id" - + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then @@ -261,7 +261,7 @@ _inwx_delete_record() { return 1 fi return 0 - + } _inwx_update_record() { @@ -293,13 +293,13 @@ _inwx_update_record() { ' "$txtval" "$record_id" response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error" return 1 fi return 0 - + } _inwx_add_record() { From a00169451fc21653763efefd0dc7938362a0e5fa Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 13:10:59 +0100 Subject: [PATCH 1170/1348] Change bash to sh to fit project requirements --- dnsapi/dns_inwx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index b02d1fb1..78e101e9 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -1,4 +1,4 @@ -#!/usr/local/bin/bash +#!/usr/local/bin/sh # #INWX_User="username" From 4a9f607d318a6a5e451f6962e44697c857580eea Mon Sep 17 00:00:00 2001 From: JAA Date: Thu, 7 Dec 2017 13:53:27 +0100 Subject: [PATCH 1171/1348] Cleanup --- dnsapi/dns_unoeuro.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 4774187d..f48b8b9d 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -5,7 +5,7 @@ # #Uno_User="UExxxxxx" -Uno_Api="https://api.unoeuro.com/1/$Uno_User/$Uno_Key" +Uno_Api="https://api.unoeuro.com/1" ######## Public functions ##################### @@ -25,7 +25,7 @@ dns_unoeuro_add() { fi if ! _contains "$Uno_User" "UE"; then - _err "It seems that the Uno_User=$Uno_User is not a valid email address." + _err "It seems that the Uno_User=$Uno_User is not a valid username." _err "Please check and retry." return 1 fi @@ -94,6 +94,12 @@ dns_unoeuro_rm() { return 1 fi + if ! _contains "$Uno_User" "UE"; then + _err "It seems that the Uno_User=$Uno_User is not a valid username." + _err "Please check and retry." + return 1 + fi + _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" @@ -174,15 +180,13 @@ _uno_rest() { data="$3" _debug "$ep" - #export _H1="X-Auth-Email: $Uno_User" - #export _H2="X-Auth-Key: $Uno_Key" export _H1="Content-Type: application/json" if [ "$m" != "GET" ]; then _debug data "$data" - response="$(_post "$data" "$Uno_Api/$ep" "" "$m")" + response="$(_post "$data" "$Uno_Api/$Uno_User/$Uno_Key/$ep" "" "$m")" else - response="$(_get "$Uno_Api/$ep")" + response="$(_get "$Uno_Api/$Uno_User/$Uno_Key/$ep")" fi if [ "$?" != "0" ]; then From b91c0a0616f11f3475d21269883cf3107201581f Mon Sep 17 00:00:00 2001 From: JAA Date: Thu, 7 Dec 2017 13:53:40 +0100 Subject: [PATCH 1172/1348] Don't use grep -B --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index f48b8b9d..d19e9eb4 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -65,7 +65,7 @@ dns_unoeuro_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | _head_n -1 | _egrep_o "[0-9]{1,}") + record_id=$(echo "$response" | sed -n -e "/$_sub_domain/{x;p;d;}" -e x | _head_n -1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" _uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}" @@ -120,7 +120,7 @@ dns_unoeuro_rm() { if ! _contains "$response" "$_sub_domain" >/dev/null; then _info "Don't need to remove." else - record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | _head_n -1 | _egrep_o "[0-9]{1,}") + record_id=$(echo "$response" | sed -n -e "/$_sub_domain/{x;p;d;}" -e x | _head_n -1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" if [ -z "$record_id" ]; then From 9a1f769828c426b26589110b70f324bde4e6c7e2 Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 14:18:54 +0100 Subject: [PATCH 1173/1348] Avoid usage of `sed -E` `grep -q` and `printf -v` --- dnsapi/dns_inwx.sh | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 78e101e9..2a2895f1 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -37,7 +37,7 @@ dns_inwx_add() { _debug _domain "$_domain" _debug "Getting txt records" - printf -v xml_content ' + xml_content=$(printf ' nameserver.info @@ -66,7 +66,7 @@ dns_inwx_add() { - ' "$_domain" "$_sub_domain" + ' "$_domain" "$_sub_domain") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then @@ -74,11 +74,11 @@ dns_inwx_add() { return 1 fi - if ! printf "%s" "$response" | grep "count" -q; then + if ! printf "%s" "$response" | grep "count" >/dev/null; then _info "Adding record" _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" else - _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | egrep -o '[0-9]+') _info "Updating record" _inwx_update_record "$_record_id" "$txtvalue" fi @@ -115,7 +115,7 @@ dns_inwx_rm() { _debug "Getting txt records" - printf -v xml_content ' + xml_content=$(printf ' nameserver.info @@ -144,7 +144,7 @@ dns_inwx_rm() { - ' "$_domain" "$_sub_domain" + ' "$_domain" "$_sub_domain") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then @@ -152,10 +152,10 @@ dns_inwx_rm() { return 1 fi - if ! printf "%s" "$response" | grep "count" -q; then + if ! printf "%s" "$response" | grep "count" >/dev/null; then _info "Do not need to delete record" else - _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | egrep -o '[0-9]+') _info "Deleting record" _inwx_delete_record "$_record_id" fi @@ -166,7 +166,7 @@ dns_inwx_rm() { _inwx_login() { - printf -v xml_content ' + xml_content=$(printf ' account.login @@ -189,7 +189,7 @@ _inwx_login() { - ' $INWX_User $INWX_Password + ' $INWX_User $INWX_Password) response="$(_post "$xml_content" "$INWX_Api" "" "POST")" @@ -207,7 +207,7 @@ _get_root() { _H1=$(_inwx_login) export _H1 - printf -v xml_content ' + xml_content=' nameserver.list ' @@ -235,7 +235,7 @@ _get_root() { _inwx_delete_record() { record_id=$1 - printf -v xml_content ' + xml_content=$(printf ' nameserver.deleteRecord @@ -252,7 +252,7 @@ _inwx_delete_record() { - ' "$record_id" + ' "$record_id") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" @@ -267,7 +267,7 @@ _inwx_delete_record() { _inwx_update_record() { record_id=$1 txtval=$2 - printf -v xml_content ' + xml_content=$(printf ' nameserver.updateRecord @@ -290,7 +290,7 @@ _inwx_update_record() { - ' "$txtval" "$record_id" + ' "$txtval" "$record_id") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" @@ -308,7 +308,7 @@ _inwx_add_record() { sub_domain=$2 txtval=$3 - printf -v xml_content ' + xml_content=$(printf ' nameserver.createRecord @@ -343,7 +343,7 @@ _inwx_add_record() { - ' "$domain" "$txtval" "$sub_domain" + ' "$domain" "$txtval" "$sub_domain") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" From 5911594906f07aa2db4b7d3256388e7514f28b92 Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 14:21:37 +0100 Subject: [PATCH 1174/1348] Fix egrep invocation --- dnsapi/dns_inwx.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 2a2895f1..ae20074b 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -78,7 +78,7 @@ dns_inwx_add() { _info "Adding record" _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" else - _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | egrep -o '[0-9]+') + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | _egrep_o '[0-9]+') _info "Updating record" _inwx_update_record "$_record_id" "$txtvalue" fi @@ -155,7 +155,7 @@ dns_inwx_rm() { if ! printf "%s" "$response" | grep "count" >/dev/null; then _info "Do not need to delete record" else - _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | egrep -o '[0-9]+') + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | _egrep_o '[0-9]+') _info "Deleting record" _inwx_delete_record "$_record_id" fi From f87890cb4b534feecd23dd2e7042e8601f15a3c3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 7 Dec 2017 21:32:17 +0800 Subject: [PATCH 1175/1348] v2.7.6 fix ECC 384 signature https://github.com/Neilpang/acme.sh/issues/1130 https://github.com/Neilpang/acme.sh/issues/990 --- acme.sh | 149 ++++++++++++++++++++++---------------------------------- 1 file changed, 57 insertions(+), 92 deletions(-) diff --git a/acme.sh b/acme.sh index 98f4067a..0755f78a 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.5 +VER=2.7.6 PROJECT_NAME="acme.sh" @@ -15,7 +15,7 @@ _SUB_FOLDERS="dnsapi deploy" _OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" -DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" + DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -900,17 +900,11 @@ _sign() { fi _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " - if [ "$alg" = "sha256" ]; then - _sign_openssl="$_sign_openssl -$alg" - else - _err "$alg is not supported yet" - return 1 - fi if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - $_sign_openssl | _base64 + $_sign_openssl -$alg | _base64 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - if ! _signedECText="$($_sign_openssl | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then + if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" _err "Key content:$(wc -l <"$keyfile") lines" @@ -1433,7 +1427,11 @@ _calcjwk() { _debug "EC key" crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" - + __ECC_KEY_LEN=$(echo "$crv" | cut -d "-" -f 2) + if [ "$__ECC_KEY_LEN" = "521" ]; then + __ECC_KEY_LEN=512 + fi + _debug3 __ECC_KEY_LEN "$__ECC_KEY_LEN" if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" 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")" @@ -1441,12 +1439,15 @@ _calcjwk() { case "${crv_oid}" in "prime256v1") crv="P-256" + __ECC_KEY_LEN=256 ;; "secp384r1") crv="P-384" + __ECC_KEY_LEN=384 ;; "secp521r1") crv="P-521" + __ECC_KEY_LEN=512 ;; *) _err "ECC oid : $crv_oid" @@ -1488,9 +1489,9 @@ _calcjwk() { jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' _debug3 jwk "$jwk" - JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}' + JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' - JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' else _err "Only RSA or EC key is supported." return 1 @@ -2160,17 +2161,6 @@ _initAPI() { _api_server="${1:-$ACME_DIRECTORY}" _debug "_init api for server: $_api_server" - if [ "$_api_server" = "$DEFAULT_CA" ]; then - #just for performance, hardcode the default entry points - export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" - export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" - export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" - export ACME_NEW_ORDER_RES="new-cert" - export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" - export ACME_NEW_ACCOUNT_RES="new-reg" - export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" - fi - if [ -z "$ACME_NEW_ACCOUNT" ]; then response=$(_get "$_api_server") if [ "$?" != "0" ]; then @@ -2209,14 +2199,18 @@ _initAPI() { ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_NONCE + + ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_AGREEMENT - fi + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" + _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" + _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" + _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" + _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" + _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" - _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" - _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" - _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" - _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" - _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" + fi } #[domain] [keylength or isEcc flag] @@ -3058,7 +3052,7 @@ __calc_account_thumbprint() { _regAccount() { _initpath _reg_length="$1" - + _debug3 _regAccount "$_regAccount" mkdir -p "$CA_DIR" if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" @@ -3081,75 +3075,46 @@ _regAccount() { return 1 fi _initAPI - _updateTos="" _reg_res="$ACME_NEW_ACCOUNT_RES" - while true; do - _debug AGREEMENT "$AGREEMENT" + regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + if [ "$ACCOUNT_EMAIL" ]; then + regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + fi - regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}' + if [ -z "$_updateTos" ]; then + _info "Registering account" - if [ "$ACCOUNT_EMAIL" ]; then - regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' - fi + if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then + _err "Register account Error: $response" + return 1 + fi - if [ -z "$_updateTos" ]; then - _info "Registering account" + if [ "$code" = "" ] || [ "$code" = '201' ]; then + echo "$response" >"$ACCOUNT_JSON_PATH" + _info "Registered" + elif [ "$code" = '409' ]; then + _info "Already registered" + else + _err "Register account Error: $response" + return 1 + fi - if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then - _err "Register account Error: $response" - return 1 - fi + _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" + _debug "_accUri" "$_accUri" + _savecaconf "ACCOUNT_URL" "$_accUri" - if [ "$code" = "" ] || [ "$code" = '201' ]; then - echo "$response" >"$ACCOUNT_JSON_PATH" - _info "Registered" - elif [ "$code" = '409' ]; then - _info "Already registered" - else - _err "Register account Error: $response" - return 1 - fi + echo "$response" >"$ACCOUNT_JSON_PATH" + CA_KEY_HASH="$(__calcAccountKeyHash)" + _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" + _savecaconf CA_KEY_HASH "$CA_KEY_HASH" - _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" - _debug "_accUri" "$_accUri" - _savecaconf "ACCOUNT_URL" "$_accUri" - _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')" - _debug "_tos" "$_tos" - if [ -z "$_tos" ]; then - _debug "Use default tos: $DEFAULT_AGREEMENT" - _tos="$DEFAULT_AGREEMENT" - fi - if [ "$_tos" != "$AGREEMENT" ]; then - _updateTos=1 - AGREEMENT="$_tos" - _reg_res="reg" - continue - fi + if [ "$code" = '403' ]; then + _err "It seems that the account key is already deactivated, please use a new account key." + return 1 + fi - else - _debug "Update tos: $_tos" - if ! _send_signed_request "$_accUri" "$regjson"; then - _err "Update tos error." - return 1 - fi - if [ "$code" = '202' ]; then - _info "Update account tos info success." - echo "$response" >"$ACCOUNT_JSON_PATH" - CA_KEY_HASH="$(__calcAccountKeyHash)" - _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" - _savecaconf CA_KEY_HASH "$CA_KEY_HASH" - elif [ "$code" = '403' ]; then - _err "It seems that the account key is already deactivated, please use a new account key." - return 1 - else - _err "Update account error." - return 1 - fi - fi - ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" - _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" - return 0 - done + ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" + _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" } From db3043553cbfb9ca05f5a6807590603ee381a80a Mon Sep 17 00:00:00 2001 From: JAA Date: Thu, 7 Dec 2017 14:52:09 +0100 Subject: [PATCH 1176/1348] Also don't use sed --- dnsapi/dns_unoeuro.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index d19e9eb4..6b582ddd 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -53,6 +53,7 @@ dns_unoeuro_add() { if ! _contains "$response" "$_sub_domain" >/dev/null; then _info "Adding record" + if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then if _contains "$response" "\"status\": 200" >/dev/null; then _info "Added, OK" @@ -65,7 +66,9 @@ dns_unoeuro_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(echo "$response" | sed -n -e "/$_sub_domain/{x;p;d;}" -e x | _head_n -1 | _egrep_o "[0-9]{1,}") + record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) + record_line_number=$(($record_line_number-1)) + record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" _uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}" @@ -76,7 +79,6 @@ dns_unoeuro_add() { _err "Update error" return 1 fi - } #fulldomain txtvalue @@ -120,7 +122,9 @@ dns_unoeuro_rm() { if ! _contains "$response" "$_sub_domain" >/dev/null; then _info "Don't need to remove." else - record_id=$(echo "$response" | sed -n -e "/$_sub_domain/{x;p;d;}" -e x | _head_n -1 | _egrep_o "[0-9]{1,}") + record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) + record_line_number=$(($record_line_number-1)) + record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" if [ -z "$record_id" ]; then From 1f635b90e76a5fb61a92f038a20a78b5381b1ea2 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 08:26:52 +0100 Subject: [PATCH 1177/1348] Try to fix build --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 6b582ddd..8a1928de 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -67,7 +67,7 @@ dns_unoeuro_add() { else _info "Updating record" record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(($record_line_number-1)) + record_line_number=$(($record_line_number - 1)) record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" @@ -123,7 +123,7 @@ dns_unoeuro_rm() { _info "Don't need to remove." else record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(($record_line_number-1)) + record_line_number=$(($record_line_number - 1)) record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" From 3f1e6c128ff0d1af3fc1fc896f115821b55af885 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 08:31:24 +0100 Subject: [PATCH 1178/1348] Try again --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 8a1928de..be0fadbe 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -67,7 +67,7 @@ dns_unoeuro_add() { else _info "Updating record" record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(($record_line_number - 1)) + record_line_number=$((record_line_number - 1)) record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" @@ -123,7 +123,7 @@ dns_unoeuro_rm() { _info "Don't need to remove." else record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(($record_line_number - 1)) + record_line_number=$((record_line_number - 1)) record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" From ca7ebd933324db4c9ea4a383321413c6deb399f3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 8 Dec 2017 19:49:18 +0800 Subject: [PATCH 1179/1348] fix typo --- acme.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 0755f78a..2affeb93 100755 --- a/acme.sh +++ b/acme.sh @@ -3081,8 +3081,7 @@ _regAccount() { regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' fi - if [ -z "$_updateTos" ]; then - _info "Registering account" + _info "Registering account" if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then _err "Register account Error: $response" From 4249e13eb4089deb518d0e54e10b8bd24d2f5640 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 8 Dec 2017 19:54:25 +0800 Subject: [PATCH 1180/1348] fix format --- acme.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 2affeb93..88273cf5 100755 --- a/acme.sh +++ b/acme.sh @@ -16,7 +16,6 @@ _SUB_FOLDERS="dnsapi deploy" _OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" - DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -2199,7 +2198,7 @@ _initAPI() { ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_NONCE - + ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_AGREEMENT From dbc3ad130461a4c9dde8b2ce778ae1881960508f Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 12:59:02 +0100 Subject: [PATCH 1181/1348] use _math --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index be0fadbe..1479d54d 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -67,7 +67,7 @@ dns_unoeuro_add() { else _info "Updating record" record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$((record_line_number - 1)) + record_line_number=$(_math "$record_line_number" - 1) record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" @@ -123,7 +123,7 @@ dns_unoeuro_rm() { _info "Don't need to remove." else record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$((record_line_number - 1)) + record_line_number=$(_math "$record_line_number" - 1) record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" From f763e1edd7c677e9d313288b8426223f86ca9e49 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 13:20:25 +0100 Subject: [PATCH 1182/1348] fix contains usage --- dnsapi/dns_unoeuro.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 1479d54d..f75de39e 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -114,12 +114,12 @@ dns_unoeuro_rm() { _debug "Getting txt records" _uno_rest GET "my/products/$h/dns/records" - if ! _contains "$response" "\"status\": 200" >/dev/null; then + if ! _contains "$response" "\"status\": 200"; then _err "Error" return 1 fi - if ! _contains "$response" "$_sub_domain" >/dev/null; then + if ! _contains "$response" "$_sub_domain"; then _info "Don't need to remove." else record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) @@ -163,7 +163,7 @@ _get_root() { return 1 fi - if _contains "$response" "\"status\": 200" >/dev/null; then + if _contains "$response" "\"status\": 200"; then _domain_id=$h if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) From f9b8d7a9d8316ad0e6b663572f552bb32a6236a4 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 13:22:17 +0100 Subject: [PATCH 1183/1348] renamed uno_user and uno_key --- dnsapi/dns_unoeuro.sh | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index f75de39e..a3803a21 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -1,9 +1,9 @@ #!/usr/bin/env sh # -#Uno_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +#UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" # -#Uno_User="UExxxxxx" +#UNO_User="UExxxxxx" Uno_Api="https://api.unoeuro.com/1" @@ -14,25 +14,25 @@ dns_unoeuro_add() { fulldomain=$1 txtvalue=$2 - Uno_Key="${Uno_Key:-$(_readaccountconf_mutable Uno_Key)}" - Uno_User="${Uno_User:-$(_readaccountconf_mutable Uno_User)}" - if [ -z "$Uno_Key" ] || [ -z "$Uno_User" ]; then - Uno_Key="" - Uno_User="" + UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" + UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" + if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then + UNO_Key="" + UNO_User="" _err "You haven't specified a UnoEuro api key and account yet." _err "Please create your key and try again." return 1 fi - if ! _contains "$Uno_User" "UE"; then - _err "It seems that the Uno_User=$Uno_User is not a valid username." + if ! _contains "$UNO_User" "UE"; then + _err "It seems that the UNO_User=$UNO_User is not a valid username." _err "Please check and retry." return 1 fi #save the api key and email to the account conf file. - _saveaccountconf_mutable Uno_Key "$Uno_Key" - _saveaccountconf_mutable Uno_User "$Uno_User" + _saveaccountconf_mutable UNO_Key "$UNO_Key" + _saveaccountconf_mutable UNO_User "$UNO_User" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -86,18 +86,18 @@ dns_unoeuro_rm() { fulldomain=$1 txtvalue=$2 - Uno_Key="${Uno_Key:-$(_readaccountconf_mutable Uno_Key)}" - Uno_User="${Uno_User:-$(_readaccountconf_mutable Uno_User)}" - if [ -z "$Uno_Key" ] || [ -z "$Uno_User" ]; then - Uno_Key="" - Uno_User="" + UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" + UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" + if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then + UNO_Key="" + UNO_User="" _err "You haven't specified a UnoEuro api key and account yet." _err "Please create your key and try again." return 1 fi - if ! _contains "$Uno_User" "UE"; then - _err "It seems that the Uno_User=$Uno_User is not a valid username." + if ! _contains "$UNO_User" "UE"; then + _err "It seems that the UNO_User=$UNO_User is not a valid username." _err "Please check and retry." return 1 fi @@ -188,9 +188,9 @@ _uno_rest() { if [ "$m" != "GET" ]; then _debug data "$data" - response="$(_post "$data" "$Uno_Api/$Uno_User/$Uno_Key/$ep" "" "$m")" + response="$(_post "$data" "$Uno_Api/$UNO_User/$UNO_Key/$ep" "" "$m")" else - response="$(_get "$Uno_Api/$Uno_User/$Uno_Key/$ep")" + response="$(_get "$Uno_Api/$UNO_User/$UNO_Key/$ep")" fi if [ "$?" != "0" ]; then From fb6e0658cf23a79cf4c16a3898fd57d281be0a32 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 14:09:04 +0100 Subject: [PATCH 1184/1348] update README --- dnsapi/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 5fdcd849..8a486aee 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -607,8 +607,8 @@ Please report any issues to https://github.com/angel333/acme.sh or to Date: Sat, 9 Dec 2017 14:13:05 +0100 Subject: [PATCH 1185/1348] Fix shebang --- dnsapi/dns_inwx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index ae20074b..74440bd7 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -1,4 +1,4 @@ -#!/usr/local/bin/sh +#!/usr/bin/env sh # #INWX_User="username" From f7c346de0928fcc57eb0c8f7561fada69118022d Mon Sep 17 00:00:00 2001 From: speedmann Date: Sat, 9 Dec 2017 14:20:36 +0100 Subject: [PATCH 1186/1348] Fix order in README and add link to inwx.de and apidocs --- README.md | 2 +- dnsapi/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8420c02c..eb122917 100644 --- a/README.md +++ b/README.md @@ -339,8 +339,8 @@ You don't have to do anything manually! 1. Dyn Managed DNS API 1. Yandex PDD API (https://pdd.yandex.ru) 1. Hurricane Electric DNS service (https://dns.he.net) -1. INWX (https://www.inwx.de/) 1. UnoEuro API (https://www.unoeuro.com/) +1. INWX (https://www.inwx.de/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 11b6b3af..c16e7598 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -620,7 +620,7 @@ The `UNO_Key` and `UNO_User` will be saved in `~/.acme.sh/account.conf` and will ## 33. Use INWX -INWX offers an xmlrpc api with your standard login credentials, set them like so: +[INWX](https://www.inwx.de/) offers an [xmlrpc api](https://www.inwx.de/de/help/apidoc) with your standard login credentials, set them like so: ``` export INWX_User="yourusername" From 8201458332ea5898177118097621dbac842ad64f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 9 Dec 2017 21:50:45 +0800 Subject: [PATCH 1187/1348] fix https://github.com/Neilpang/acme.sh/issues/1123 --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 88273cf5..472975a6 100755 --- a/acme.sh +++ b/acme.sh @@ -4308,7 +4308,12 @@ _installcert() { if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then cp "$_real_key" "$_backup_path/key.bak" fi - cat "$CERT_KEY_PATH" >"$_real_key" + if [ -f "$_real_key" ]; then + cat "$CERT_KEY_PATH" >"$_real_key" + else + cat "$CERT_KEY_PATH" >"$_real_key" + chmod 700 "$_real_key" + fi fi if [ "$_real_fullchain" ]; then From ae29929714b8cb8e4b7c612a354b56433f8ac47c Mon Sep 17 00:00:00 2001 From: Jens Hartlep Date: Sat, 9 Dec 2017 19:32:53 +0100 Subject: [PATCH 1188/1348] added dns api for servercow --- dnsapi/README.md | 16 ++++ dnsapi/dns_servercow.sh | 170 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100755 dnsapi/dns_servercow.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index c16e7598..d357c053 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -635,6 +635,22 @@ acme.sh --issue --dns dns_inwx -d example.com -d www.example.com The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 34. User Servercow API v1 + +Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user. + +``` +export SERVERCOW_API_Username=username +export SERVERCOW_API_Password=password +``` + +Now you cann issue a cert: + +``` +acme.sh --issue --dns dns_servercow -d example.com -d www.example.com +``` +Both, `SERVERCOW_API_Username` and `SERVERCOW_API_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh new file mode 100755 index 00000000..e7049598 --- /dev/null +++ b/dnsapi/dns_servercow.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env sh + +########## +# Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/Neilpang/acme.sh) +# +# Usage: +# export SERVERCOW_API_Username=username +# export SERVERCOW_API_Password=password +# acme.sh --issue -d example.com --dns dns_servercow +# +# Issues: +# Any issues / questions / suggestions can be posted here: +# https://github.com/jhartlep/servercow-dns-api/issues +# +# Author: Jens Hartlep +########## + +SERVERCOW_API="https://api.servercow.de/dns/v1/domains" + +# Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz" +dns_servercow_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and password and try again." + return 1 + fi + + # save the credentials to the account conf file + _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" + _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_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 _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; 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_servercow_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$fulldomain" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and 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 _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then + if printf -- "%s" "$response" | grep "ok" > /dev/null; then + _info "Deleted, OK" + _contains "$response" '"message":"ok"' + else + _err "delete txt record error." + return 1 + fi + fi + +} + +#################### 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 + + while true; do + _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + + _debug _domain "$_domain" + if [ -z "$_domain" ]; then + # not valid + return 1 + fi + + if ! _servercow_api GET "$_domain"; then + return 1 + fi + + if ! _contains "$response" '"error":"no such domain in user context"' > /dev/null; then + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + if [ -z "$_sub_domain" ]; then + # not valid + return 1 + fi + + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done; + + return 1 +} + +_servercow_api() { + method=$1 + domain=$2 + data="$3" + + export _H1="Content-Type: application/json" + export _H2="X-Auth-Username: $SERVERCOW_API_Username" + export _H3="X-Auth-Password: $SERVERCOW_API_Password" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" + else + response="$(_get "$SERVERCOW_API/$domain")" + fi + + if [ "$?" != "0" ]; then + _err "error $domain" + return 1 + fi + _debug2 response "$response" + return 0 +} From b140e2553bdfce40b99fb3ecd246ef3e64d33d42 Mon Sep 17 00:00:00 2001 From: Jens Hartlep Date: Sat, 9 Dec 2017 19:33:48 +0100 Subject: [PATCH 1189/1348] added Servercow to supported list --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb122917..5574b67a 100644 --- a/README.md +++ b/README.md @@ -341,7 +341,7 @@ You don't have to do anything manually! 1. Hurricane Electric DNS service (https://dns.he.net) 1. UnoEuro API (https://www.unoeuro.com/) 1. INWX (https://www.inwx.de/) - +1. Servercow (https://servercow.de) And: From 488745f3783e767adf5421b20ff96fc82aae9a37 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 9 Dec 2017 20:05:05 +0100 Subject: [PATCH 1190/1348] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5574b67a..0d942757 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,7 @@ You don't have to do anything manually! 1. INWX (https://www.inwx.de/) 1. Servercow (https://servercow.de) + And: 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api From 1c9b19833cf0ebd0087f171f9f3f5cf24fc96ecc Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 9 Dec 2017 20:14:46 +0100 Subject: [PATCH 1191/1348] Update dns_servercow.sh replaced tab with space --- dnsapi/dns_servercow.sh | 260 ++++++++++++++++++++-------------------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh index e7049598..3ffc393e 100755 --- a/dnsapi/dns_servercow.sh +++ b/dnsapi/dns_servercow.sh @@ -19,88 +19,88 @@ SERVERCOW_API="https://api.servercow.de/dns/v1/domains" # Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz" dns_servercow_add() { - fulldomain=$1 - txtvalue=$2 - - _info "Using servercow" - _debug fulldomain "$fulldomain" - _debug txtvalue "$txtvalue" - - SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" - SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" - if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then - SERVERCOW_API_Username="" - SERVERCOW_API_Password="" - _err "You don't specify servercow api username and password yet." - _err "Please create your username and password and try again." - return 1 - fi - - # save the credentials to the account conf file - _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" - _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_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 _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; 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 + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and password and try again." + return 1 + fi + + # save the credentials to the account conf file + _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" + _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_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 _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; 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_servercow_rm() { - fulldomain=$1 - txtvalue=$2 - - _info "Using servercow" - _debug fulldomain "$fulldomain" - _debug txtvalue "$fulldomain" - - SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" - SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" - if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then - SERVERCOW_API_Username="" - SERVERCOW_API_Password="" - _err "You don't specify servercow api username and password yet." - _err "Please create your username and 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 _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then - if printf -- "%s" "$response" | grep "ok" > /dev/null; then - _info "Deleted, OK" - _contains "$response" '"message":"ok"' - else - _err "delete txt record error." - return 1 - fi - fi + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$fulldomain" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and 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 _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then + if printf -- "%s" "$response" | grep "ok" > /dev/null; then + _info "Deleted, OK" + _contains "$response" '"message":"ok"' + else + _err "delete txt record error." + return 1 + fi + fi } @@ -111,60 +111,60 @@ dns_servercow_rm() { # _sub_domain=_acme-challenge.www # _domain=domain.com _get_root() { - fulldomain=$1 - i=2 - p=1 - - while true; do - _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) - - _debug _domain "$_domain" - if [ -z "$_domain" ]; then - # not valid - return 1 - fi - - if ! _servercow_api GET "$_domain"; then - return 1 - fi - - if ! _contains "$response" '"error":"no such domain in user context"' > /dev/null; then - _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) - if [ -z "$_sub_domain" ]; then - # not valid - return 1 - fi - - return 0 - fi - - p=$i - i=$(_math "$i" + 1) - done; - - return 1 + fulldomain=$1 + i=2 + p=1 + + while true; do + _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + + _debug _domain "$_domain" + if [ -z "$_domain" ]; then + # not valid + return 1 + fi + + if ! _servercow_api GET "$_domain"; then + return 1 + fi + + if ! _contains "$response" '"error":"no such domain in user context"' > /dev/null; then + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + if [ -z "$_sub_domain" ]; then + # not valid + return 1 + fi + + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done; + + return 1 } _servercow_api() { - method=$1 - domain=$2 - data="$3" - - export _H1="Content-Type: application/json" - export _H2="X-Auth-Username: $SERVERCOW_API_Username" - export _H3="X-Auth-Password: $SERVERCOW_API_Password" - - if [ "$method" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" - else - response="$(_get "$SERVERCOW_API/$domain")" - fi - - if [ "$?" != "0" ]; then - _err "error $domain" - return 1 - fi - _debug2 response "$response" - return 0 + method=$1 + domain=$2 + data="$3" + + export _H1="Content-Type: application/json" + export _H2="X-Auth-Username: $SERVERCOW_API_Username" + export _H3="X-Auth-Password: $SERVERCOW_API_Password" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" + else + response="$(_get "$SERVERCOW_API/$domain")" + fi + + if [ "$?" != "0" ]; then + _err "error $domain" + return 1 + fi + _debug2 response "$response" + return 0 } From 8101aceab5dad0ac83c8446380d814d77f44fecf Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 9 Dec 2017 20:18:05 +0100 Subject: [PATCH 1192/1348] Update dns_servercow.sh fixed remaining issues from shellcheck --- dnsapi/dns_servercow.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh index 3ffc393e..872ae58c 100755 --- a/dnsapi/dns_servercow.sh +++ b/dnsapi/dns_servercow.sh @@ -50,7 +50,7 @@ dns_servercow_add() { _debug _domain "$_domain" if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then - if printf -- "%s" "$response" | grep "ok" > /dev/null; then + if printf -- "%s" "$response" | grep "ok" >/dev/null; then _info "Added, OK" return 0 else @@ -92,8 +92,8 @@ dns_servercow_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then - if printf -- "%s" "$response" | grep "ok" > /dev/null; then + if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then + if printf -- "%s" "$response" | grep "ok" >/dev/null; then _info "Deleted, OK" _contains "$response" '"message":"ok"' else @@ -140,7 +140,7 @@ _get_root() { p=$i i=$(_math "$i" + 1) - done; + done return 1 } From a95ccc7e4cecd7fa92144dc8af7bca5ffccb107a Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 9 Dec 2017 20:22:09 +0100 Subject: [PATCH 1193/1348] Update dns_servercow.sh ... didn't see this line in spellcheck ... :S --- dnsapi/dns_servercow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh index 872ae58c..be4e59da 100755 --- a/dnsapi/dns_servercow.sh +++ b/dnsapi/dns_servercow.sh @@ -128,7 +128,7 @@ _get_root() { return 1 fi - if ! _contains "$response" '"error":"no such domain in user context"' > /dev/null; then + if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) if [ -z "$_sub_domain" ]; then # not valid From a582e7c2fb7c4ef85c324d69377f3e9644406eba Mon Sep 17 00:00:00 2001 From: sjau Date: Tue, 2 Jan 2018 15:05:26 +0100 Subject: [PATCH 1194/1348] dns_ispconfig.sh: remove unnecessary permission in api user --- dnsapi/dns_ispconfig.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index 6d1f34c5..1e500ad6 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -2,7 +2,6 @@ # ISPConfig 3.1 API # User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to: -# - DNS zone Functions # - DNS txt Functions # Report bugs to https://github.com/sjau/acme.sh From 8ea800205c2e5496b63e3244dc4849d629acc1ad Mon Sep 17 00:00:00 2001 From: hiska Date: Thu, 4 Jan 2018 19:01:57 +0900 Subject: [PATCH 1195/1348] support both debian and redhat --- deploy/strongswan.sh | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/deploy/strongswan.sh b/deploy/strongswan.sh index 2de18f88..f991d690 100644 --- a/deploy/strongswan.sh +++ b/deploy/strongswan.sh @@ -16,17 +16,38 @@ strongswan_deploy() { _cca="$4" _cfullchain="$5" + _info "Using strongswan" + + if [ -x /usr/sbin/ipsec ]; then + _ipsec=/usr/sbin/ipsec + elif [ -x /usr/sbin/strongswan ]; then + _ipsec=/usr/sbin/strongswan + else + _err "no strongswan or ipsec command is detected" + return 1 + fi + + _info _ipsec "$_ipsec" + + _confdir=$($_ipsec --confdir) + if [ $? -ne 0 ] || [ -z "$_confdir" ]; then + _err "no strongswan --confdir is detected" + return 1 + fi + + _info _confdir "$_confdir" + _debug _cdomain "$_cdomain" _debug _ckey "$_ckey" _debug _ccert "$_ccert" _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - cat "$_ckey" >"/etc/ipsec.d/private/$(basename "$_ckey")" - cat "$_ccert" >"/etc/ipsec.d/certs/$(basename "$_ccert")" - cat "$_cca" >"/etc/ipsec.d/cacerts/$(basename "$_cca")" - cat "$_cfullchain" >"/etc/ipsec.d/cacerts/$(basename "$_cfullchain")" + cat "$_ckey" >"${_confdir}/ipsec.d/private/$(basename "$_ckey")" + cat "$_ccert" >"${_confdir}/ipsec.d/certs/$(basename "$_ccert")" + cat "$_cca" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cca")" + cat "$_cfullchain" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cfullchain")" - ipsec reload + $_ipsec reload } From 6541492a5598eb4d27aa9c3cd06f8ba7317da41c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 12:45:24 +0800 Subject: [PATCH 1196/1348] first version to support ACME v2 --- acme.sh | 308 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 239 insertions(+), 69 deletions(-) diff --git a/acme.sh b/acme.sh index 472975a6..604bff04 100755 --- a/acme.sh +++ b/acme.sh @@ -13,8 +13,15 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" -_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" -DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" +LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory" +LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" + +LETSENCRYPT_CA_V2="https://acme-v02.api.letsencrypt.org/directory" +LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/directory" + +DEFAULT_CA=$LETSENCRYPT_CA_V1 +DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1 + DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -24,13 +31,13 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" -STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" +_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" VTYPE_TLS="tls-sni-01" -#VTYPE_TLS2="tls-sni-02" +VTYPE_TLS2="tls-sni-02" LOCAL_ANY_ADDRESS="0.0.0.0" @@ -1044,13 +1051,14 @@ _createcsr() { if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then #single domain _info "Single domain" "$domain" + printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf" else domainlist="$(_idn "$domainlist")" _debug2 domainlist "$domainlist" if _contains "$domainlist" ","; then - alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" + alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" else - alt="DNS:$domainlist" + alt="DNS:$domain,DNS:$domainlist" fi #multi _info "Multi domain" "$alt" @@ -1421,7 +1429,7 @@ _calcjwk() { JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' - JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART2='", "alg": "RS256"' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" @@ -1490,7 +1498,7 @@ _calcjwk() { JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' - JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"' else _err "Only RSA or EC key is supported." return 1 @@ -1580,7 +1588,7 @@ _inithttp() { # body url [needbase64] [POST|PUT] _post() { body="$1" - url="$2" + _post_url="$2" needbase64="$3" httpmethod="$4" @@ -1588,7 +1596,7 @@ _post() { httpmethod="POST" fi _debug $httpmethod - _debug "url" "$url" + _debug "_post_url" "$_post_url" _debug2 "body" "$body" _inithttp @@ -1600,9 +1608,9 @@ _post() { fi _debug "_CURL" "$_CURL" if [ "$needbase64" ]; then - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" fi _ret="$?" if [ "$_ret" != "0" ]; then @@ -1620,15 +1628,15 @@ _post() { _debug "_WGET" "$_WGET" if [ "$needbase64" ]; then if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" fi else if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" fi fi _ret="$?" @@ -1776,7 +1784,15 @@ _send_signed_request() { nonce="$_CACHED_NONCE" _debug2 nonce "$nonce" - protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2" + if [ "$ACME_VERSION" = "2" ]; then + if [ "$url" = "$ACME_NEW_ACCOUNT" ]; then + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' + else + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"$ACCOUNT_URL\""'}' + fi + else + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' + fi _debug3 protected "$protected" protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" @@ -1791,7 +1807,11 @@ _send_signed_request() { sig="$(printf "%s" "$_sig_t" | _url_replace)" _debug3 sig "$sig" - body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + if [ "$ACME_VERSION" = "2" ]; then + body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + else + body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + fi _debug3 body "$body" response="$(_post "$body" "$url" "$needbase64")" @@ -2170,9 +2190,15 @@ _initAPI() { _debug2 "response" "$response" ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_KEY_CHANGE" ]; then + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'keyChange" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_KEY_CHANGE ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_AUTHZ" ]; then + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'newAuthz" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_NEW_AUTHZ ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) @@ -2180,6 +2206,9 @@ _initAPI() { if [ -z "$ACME_NEW_ORDER" ]; then ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) ACME_NEW_ORDER_RES="new-order" + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'newOrder" *: *"[^"]*"' | cut -d '"' -f 3) + fi fi export ACME_NEW_ORDER export ACME_NEW_ORDER_RES @@ -2189,17 +2218,32 @@ _initAPI() { if [ -z "$ACME_NEW_ACCOUNT" ]; then ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) ACME_NEW_ACCOUNT_RES="new-account" + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'newAccount" *: *"[^"]*"' | cut -d '"' -f 3) + if [ "$ACME_NEW_ACCOUNT" ]; then + export ACME_VERSION=2 + fi + fi fi export ACME_NEW_ACCOUNT export ACME_NEW_ACCOUNT_RES ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_REVOKE_CERT" ]; then + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revokeCert" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_REVOKE_CERT ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_NONCE" ]; then + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'newNonce" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_NEW_NONCE ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_AGREEMENT" ]; then + ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_AGREEMENT _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" @@ -2208,6 +2252,8 @@ _initAPI() { _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" + _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE" + _debug "ACME_VERSION" "$ACME_VERSION" fi } @@ -2236,7 +2282,7 @@ _initpath() { if [ -z "$STAGE" ]; then ACME_DIRECTORY="$DEFAULT_CA" else - ACME_DIRECTORY="$STAGE_CA" + ACME_DIRECTORY="$DEFAULT_STAGING_CA" _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" fi fi @@ -2951,6 +2997,7 @@ _on_issue_err() { _chk_post_hook="$1" _chk_vlist="$2" _debug _on_issue_err + _cleardomainconf "ORDER_FINALIZE" if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" else @@ -3052,6 +3099,8 @@ _regAccount() { _initpath _reg_length="$1" _debug3 _regAccount "$_regAccount" + _initAPI + mkdir -p "$CA_DIR" if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" @@ -3073,11 +3122,18 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - _initAPI - _reg_res="$ACME_NEW_ACCOUNT_RES" - regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ]; then - regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + + if [ "$ACME_VERSION" = "2" ]; then + regjson='{"termsOfServiceAgreed": true}' + if [ "$ACCOUNT_EMAIL" ]; then + regjson='{"contact": ["mailto: '$ACCOUNT_EMAIL'"], "termsOfServiceAgreed": true}' + fi + else + _reg_res="$ACME_NEW_ACCOUNT_RES" + regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + if [ "$ACCOUNT_EMAIL" ]; then + regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + fi fi _info "Registering account" @@ -3100,8 +3156,8 @@ _regAccount() { _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" _savecaconf "ACCOUNT_URL" "$_accUri" + export ACCOUNT_URL="$ACCOUNT_URL" - echo "$response" >"$ACCOUNT_JSON_PATH" CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" _savecaconf CA_KEY_HASH "$CA_KEY_HASH" @@ -3113,7 +3169,6 @@ _regAccount() { ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" - } #Implement deactivate account @@ -3251,7 +3306,11 @@ __trigger_validation() { _debug2 _t_url "$_t_url" _t_key_authz="$2" _debug2 _t_key_authz "$_t_key_authz" - _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" + if [ "$ACME_VERSION" = "2" ]; then + _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}" + else + _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" + fi } #webroot, domain domainlist keylength @@ -3393,32 +3452,107 @@ issue() { sep='#' dvsep=',' if [ -z "$vlist" ]; then + if [ "$ACME_VERSION" = "2" ] && [ -z "$ORDER_FINALIZE" ]; then + #make new order request + _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" + for d in $(echo "$_alt_domains" | tr ',' ' '); do + #todo: check wildcard ? + if [ "$d" ]; then + _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" + fi + done + _debug2 _identifiers "$_identifiers" + if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then + _err "Create new order error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + ORDER_FINALIZE="$(echo "$response"| tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" + _debug ORDER_FINALIZE "$ORDER_FINALIZE" + if [ -z "$ORDER_FINALIZE" ]; then + _err "ORDER_FINALIZE not found." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + #for dns manual mode + _savedomainconf "ORDER_FINALIZE" "$ORDER_FINALIZE" + + _authorizations_seg="$(echo "$response"| tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _debug2 _authorizations_seg "$_authorizations_seg" + if [ -z "$_authorizations_seg" ]; then + _err "_authorizations_seg not found." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + #domain and authz map + _authorizations_map="" + for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' ' ); do + _debug2 "_authz_url" "$_authz_url" + if ! response="$(_get "$_authz_url")"; then + _err "get to authz error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')" + _debug2 _d "$_d" + _authorizations_map="$_d,$response +$_authorizations_map" + done + _debug2 _authorizations_map "$_authorizations_map" + fi + alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ') - _index=1 + _index=0 _currentRoot="" for d in $alldomains; do _info "Getting webroot for domain" "$d" + _index=$(_math $_index + 1) _w="$(echo $_web_roots | cut -d , -f $_index)" _debug _w "$_w" if [ "$_w" ]; then _currentRoot="$_w" fi _debug "_currentRoot" "$_currentRoot" - _index=$(_math $_index + 1) vtype="$VTYPE_HTTP" + #todo, v2 wildcard force to use dns if _startswith "$_currentRoot" "dns"; then vtype="$VTYPE_DNS" fi if [ "$_currentRoot" = "$W_TLS" ]; then - vtype="$VTYPE_TLS" + if [ "$ACME_VERSION" = "2" ]; then + vtype="$VTYPE_TLS2" + else + vtype="$VTYPE_TLS" + fi fi - if ! __get_domain_new_authz "$d"; then - _clearup - _on_issue_err "$_post_hook" - return 1 + if [ "$ACME_VERSION" = "2" ]; then + response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")" + _debug2 "response" "$response" + if [ -z "$response" ]; then + _err "get to authz error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + else + if ! __get_domain_new_authz "$d"; then + _clearup + _on_issue_err "$_post_hook" + return 1 + fi fi if [ -z "$thumbprint" ]; then @@ -3436,14 +3570,18 @@ issue() { token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" + if [ "$ACME_VERSION" = "2" ]; then + uri="$(printf "%s\n" "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)" + else + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" + fi _debug uri "$uri" keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then - _debug "$d is already verified, skip." + _debug "$d is already verified." keyauthorization="$STATE_VERIFIED" _debug keyauthorization "$keyauthorization" fi @@ -3685,12 +3823,16 @@ issue() { return 1 fi - if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then - _err "$d:Challenge error: $response" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 + if [ "$code" ] && [ "$code" != '202' ]; then + if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then + _debug "trigger validation code: $code" + else + _err "$d:Challenge error: $response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi fi waittimes=0 @@ -3773,18 +3915,32 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then - _err "Sign failed." - _on_issue_err "$_post_hook" - return 1 - fi - - _rcert="$response" - Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" - _debug "Le_LinkCert" "$Le_LinkCert" - _savedomainconf "Le_LinkCert" "$Le_LinkCert" + if [ "$ACME_VERSION" = "2" ]; then + if ! _send_signed_request "${ORDER_FINALIZE}" "{\"csr\": \"$der\"}"; then + _err "Sign failed." + _on_issue_err "$_post_hook" + return 1 + fi + if [ "$code" != "200" ]; then + _err "Sign failed, code is not 200." + _on_issue_err "$_post_hook" + return 1 + fi + Le_LinkCert="$(echo "$response"| tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" - if [ "$Le_LinkCert" ]; then + if ! _get "$Le_LinkCert" > "$CERT_PATH"; then + _err "Sign failed, code is not 200." + _on_issue_err "$_post_hook" + return 1 + fi + else + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then + _err "Sign failed." + _on_issue_err "$_post_hook" + return 1 + fi + _rcert="$response" + Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" echo "$BEGIN_CERT" >"$CERT_PATH" #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then @@ -3798,6 +3954,12 @@ issue() { fi echo "$END_CERT" >>"$CERT_PATH" + fi + + _debug "Le_LinkCert" "$Le_LinkCert" + _savedomainconf "Le_LinkCert" "$Le_LinkCert" + + if [ "$Le_LinkCert" ]; then _info "$(__green "Cert success.")" cat "$CERT_PATH" @@ -3825,29 +3987,37 @@ issue() { _cleardomainconf "Le_Vlist" Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') - if ! _contains "$Le_LinkIssuer" ":"; then - _info "$(__red "Relative issuer link found.")" - Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" - fi - _debug Le_LinkIssuer "$Le_LinkIssuer" - _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ]; then + if ! _contains "$Le_LinkIssuer" ":"; then + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" + fi + _debug Le_LinkIssuer "$Le_LinkIssuer" + _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" + _link_issuer_retry=0 _MAX_ISSUER_RETRY=5 while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do _debug _link_issuer_retry "$_link_issuer_retry" - if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then - echo "$BEGIN_CERT" >"$CA_CERT_PATH" - _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" - echo "$END_CERT" >>"$CA_CERT_PATH" + + if [ "$ACME_VERSION" = "2" ]; then + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then + break + fi + else + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then + echo "$BEGIN_CERT" >"$CA_CERT_PATH" + _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" + echo "$END_CERT" >>"$CA_CERT_PATH" - _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 ")" + _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 + rm -f "$CA_CERT_PATH.der" + break + fi fi _link_issuer_retry=$(_math $_link_issuer_retry + 1) _sleep "$_link_issuer_retry" @@ -3957,7 +4127,7 @@ renew() { _savedomainconf Le_API "$Le_API" fi if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then - export Le_API="$STAGE_CA" + export Le_API="$DEFAULT_STAGING_CA" _savedomainconf Le_API "$Le_API" fi export ACME_DIRECTORY="$Le_API" From 136aebc009cf9e32a9a16dead43378a1ba9effe1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 13:57:35 +0800 Subject: [PATCH 1197/1348] fix format --- acme.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index 604bff04..890cdd82 100755 --- a/acme.sh +++ b/acme.sh @@ -22,7 +22,6 @@ LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/director DEFAULT_CA=$LETSENCRYPT_CA_V1 DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1 - DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -3122,7 +3121,7 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - + if [ "$ACME_VERSION" = "2" ]; then regjson='{"termsOfServiceAgreed": true}' if [ "$ACCOUNT_EMAIL" ]; then @@ -3469,7 +3468,7 @@ issue() { return 1 fi - ORDER_FINALIZE="$(echo "$response"| tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" + ORDER_FINALIZE="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" _debug ORDER_FINALIZE "$ORDER_FINALIZE" if [ -z "$ORDER_FINALIZE" ]; then _err "ORDER_FINALIZE not found." @@ -3481,7 +3480,7 @@ issue() { #for dns manual mode _savedomainconf "ORDER_FINALIZE" "$ORDER_FINALIZE" - _authorizations_seg="$(echo "$response"| tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" _debug2 _authorizations_seg "$_authorizations_seg" if [ -z "$_authorizations_seg" ]; then _err "_authorizations_seg not found." @@ -3492,7 +3491,7 @@ issue() { #domain and authz map _authorizations_map="" - for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' ' ); do + for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do _debug2 "_authz_url" "$_authz_url" if ! response="$(_get "$_authz_url")"; then _err "get to authz error." @@ -3926,9 +3925,9 @@ $_authorizations_map" _on_issue_err "$_post_hook" return 1 fi - Le_LinkCert="$(echo "$response"| tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" + Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" - if ! _get "$Le_LinkCert" > "$CERT_PATH"; then + if ! _get "$Le_LinkCert" >"$CERT_PATH"; then _err "Sign failed, code is not 200." _on_issue_err "$_post_hook" return 1 @@ -4000,7 +3999,6 @@ $_authorizations_map" _MAX_ISSUER_RETRY=5 while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do _debug _link_issuer_retry "$_link_issuer_retry" - if [ "$ACME_VERSION" = "2" ]; then if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then break From 6ae3911972d6c67e4170cc90e941e733e21429fd Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 17:39:15 +0800 Subject: [PATCH 1198/1348] support ACME v2 wildcard cert --- acme.sh | 38 +++++++++++++++++++++++++++++------- dnsapi/dns_cf.sh | 51 +++++++++++++++++++++++++----------------------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/acme.sh b/acme.sh index 890cdd82..1021dcd0 100755 --- a/acme.sh +++ b/acme.sh @@ -997,7 +997,7 @@ _createkey() { _is_idn() { _is_idn_d="$1" _debug2 _is_idn_d "$_is_idn_d" - _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-') + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-') _debug2 _idn_temp "$_idn_temp" [ "$_idn_temp" ] } @@ -1055,7 +1055,7 @@ _createcsr() { domainlist="$(_idn "$domainlist")" _debug2 domainlist "$domainlist" if _contains "$domainlist" ","; then - alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" + alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" else alt="DNS:$domain,DNS:$domainlist" fi @@ -1663,7 +1663,7 @@ _get() { onlyheader="$2" t="$3" _debug url "$url" - _debug "timeout" "$t" + _debug "timeout=$t" _inithttp @@ -2277,6 +2277,11 @@ _initpath() { CA_HOME="$DEFAULT_CA_HOME" fi + if [ "$ACME_VERSION" = "2" ]; then + DEFAULT_CA="$LETSENCRYPT_CA_V2" + DEFAULT_STAGING_CA="$LETSENCRYPT_STAGING_CA_V2" + fi + if [ -z "$ACME_DIRECTORY" ]; then if [ -z "$STAGE" ]; then ACME_DIRECTORY="$DEFAULT_CA" @@ -2863,7 +2868,11 @@ _clearupdns() { return 1 fi - txtdomain="_acme-challenge.$d" + _dns_root_d="$d" + if _startswith "$_dns_root_d" "*."; then + _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" + fi + txtdomain="_acme-challenge.$_dns_root_d" if ! $rmcommand "$txtdomain" "$txt"; then _err "Error removing txt for domain:$txtdomain" @@ -3503,6 +3512,9 @@ issue() { response="$(echo "$response" | _normalizeJson)" _debug2 response "$response" _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')" + if _contains "$response" "\"wildcard\" *: *true"; then + _d="*.$_d" + fi _debug2 _d "$_d" _authorizations_map="$_d,$response $_authorizations_map" @@ -3600,7 +3612,7 @@ $_authorizations_map" keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) vtype=$(echo "$ventry" | cut -d "$sep" -f 4) _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - + _debug d "$d" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _debug "$d is already verified, skip $vtype." continue @@ -3608,12 +3620,16 @@ $_authorizations_map" if [ "$vtype" = "$VTYPE_DNS" ]; then dnsadded='0' - txtdomain="_acme-challenge.$d" + _dns_root_d="$d" + if _startswith "$_dns_root_d" "*."; then + _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" + fi + txtdomain="_acme-challenge.$_dns_root_d" _debug txtdomain "$txtdomain" txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" - d_api="$(_findHook "$d" dnsapi "$_currentRoot")" + d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")" _debug d_api "$d_api" @@ -5476,8 +5492,16 @@ _process() { fi if [ -z "$_domain" ]; then + if _startswith "$_dvalue" "*."; then + _err "The first domain can not be wildcard, '$_dvalue' is a wildcard domain." + return 1 + fi _domain="$_dvalue" else + if _startswith "$_dvalue" "*."; then + _debug "Wildcard domain" + export ACME_VERSION=2 + fi if [ "$_altdomains" = "$NO_VALUE" ]; then _altdomains="$_dvalue" else diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 57a2e884..abe7700c 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -51,33 +51,36 @@ dns_cf_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) - _debug count "$count" - 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 - _info "Added, OK" - return 0 - else - _err "Add txt record error." - return 1 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) - _debug "record_id" "$record_id" - - _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" - if [ "$?" = "0" ]; then - _info "Updated, OK" +# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so +# we can not use updating anymore. +# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) +# _debug count "$count" +# 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 + _info "Added, OK" return 0 + else + _err "Add txt record error." + return 1 fi - _err "Update error" - return 1 fi + _err "Add txt record error." + return 1 +# else +# _info "Updating record" +# record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) +# _debug "record_id" "$record_id" +# +# _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" +# if [ "$?" = "0" ]; then +# _info "Updated, OK" +# return 0 +# fi +# _err "Update error" +# return 1 +# fi } From 4f3b3a273f67b0dcc6a6ab4055133298d8e21c9f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 19:42:29 +0800 Subject: [PATCH 1199/1348] fix format --- dnsapi/dns_cf.sh | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index abe7700c..68264a42 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -51,11 +51,11 @@ dns_cf_add() { return 1 fi -# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so -# we can not use updating anymore. -# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) -# _debug count "$count" -# if [ "$count" = "0" ]; then + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # 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 @@ -68,19 +68,19 @@ dns_cf_add() { fi _err "Add txt record error." return 1 -# else -# _info "Updating record" -# record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) -# _debug "record_id" "$record_id" -# -# _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" -# if [ "$?" = "0" ]; then -# _info "Updated, OK" -# return 0 -# fi -# _err "Update error" -# return 1 -# fi + # else + # _info "Updating record" + # record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + # _debug "record_id" "$record_id" + # + # _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" + # if [ "$?" = "0" ]; then + # _info "Updated, OK" + # return 0 + # fi + # _err "Update error" + # return 1 + # fi } From 2823306810ab2574bc2ca5312a75e7b3f371bd6e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 21:33:27 +0800 Subject: [PATCH 1200/1348] fix ACME v2: deactivate/deactivate-account/revoke --- acme.sh | 103 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 29 deletions(-) diff --git a/acme.sh b/acme.sh index 1021dcd0..5a5f0337 100755 --- a/acme.sh +++ b/acme.sh @@ -1784,7 +1784,7 @@ _send_signed_request() { _debug2 nonce "$nonce" if [ "$ACME_VERSION" = "2" ]; then - if [ "$url" = "$ACME_NEW_ACCOUNT" ]; then + if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' else protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"$ACCOUNT_URL\""'}' @@ -3005,7 +3005,7 @@ _on_issue_err() { _chk_post_hook="$1" _chk_vlist="$2" _debug _on_issue_err - _cleardomainconf "ORDER_FINALIZE" + _cleardomainconf "Le_OrderFinalize" if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" else @@ -3212,7 +3212,12 @@ deactivateaccount() { fi _initAPI - if _send_signed_request "$_accUri" "{\"resource\": \"reg\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then + if [ "$ACME_VERSION" = "2" ]; then + _djson="{\"status\":\"deactivated\"}" + else + _djson="{\"resource\": \"reg\", \"status\":\"deactivated\"}" + fi + if _send_signed_request "$_accUri" "$_djson" && _contains "$response" '"deactivated"'; then _info "Deactivate account success for $_accUri." _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,') elif [ "$code" = "403" ]; then @@ -3334,6 +3339,11 @@ issue() { _web_roots="$1" _main_domain="$2" _alt_domains="$3" + + if _startswith "$_main_domain" "*."; then + _err "The first domain can not be wildcard, '$_main_domain' is a wildcard domain." + return 1 + fi if _contains "$_main_domain" ","; then _main_domain=$(echo "$2,$3" | cut -d , -f 1) _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") @@ -3460,7 +3470,7 @@ issue() { sep='#' dvsep=',' if [ -z "$vlist" ]; then - if [ "$ACME_VERSION" = "2" ] && [ -z "$ORDER_FINALIZE" ]; then + if [ "$ACME_VERSION" = "2" ]; then #make new order request _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" for d in $(echo "$_alt_domains" | tr ',' ' '); do @@ -3477,17 +3487,17 @@ issue() { return 1 fi - ORDER_FINALIZE="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" - _debug ORDER_FINALIZE "$ORDER_FINALIZE" - if [ -z "$ORDER_FINALIZE" ]; then - _err "ORDER_FINALIZE not found." + Le_OrderFinalize="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" + _debug Le_OrderFinalize "$Le_OrderFinalize" + if [ -z "$Le_OrderFinalize" ]; then + _err "Le_OrderFinalize not found." _clearup _on_issue_err "$_post_hook" return 1 fi #for dns manual mode - _savedomainconf "ORDER_FINALIZE" "$ORDER_FINALIZE" + _savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize" _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" _debug2 _authorizations_seg "$_authorizations_seg" @@ -3931,7 +3941,7 @@ $_authorizations_map" der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" if [ "$ACME_VERSION" = "2" ]; then - if ! _send_signed_request "${ORDER_FINALIZE}" "{\"csr\": \"$der\"}"; then + if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 @@ -4632,7 +4642,11 @@ revoke() { _initAPI - data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" + if [ "$ACME_VERSION" = "2" ]; then + data="{\"certificate\": \"$cert\"}" + else + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" + fi uri="${ACME_REVOKE_CERT}" if [ -f "$CERT_KEY_PATH" ]; then @@ -4703,27 +4717,56 @@ _deactivate() { _d_type="$2" _initpath - if ! __get_domain_new_authz "$_d_domain"; then - _err "Can not get domain new authz token." - return 1 - fi + if [ "$ACME_VERSION" = "2" ]; then + _identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}" + if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then + _err "Can not get domain new order." + return 1 + fi + _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _debug2 _authorizations_seg "$_authorizations_seg" + if [ -z "$_authorizations_seg" ]; then + _err "_authorizations_seg not found." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi - authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" - _debug "authzUri" "$authzUri" + authzUri="$_authorizations_seg" + _debug2 "authzUri" "$authzUri" + if ! response="$(_get "$authzUri")"; then + _err "get to authz error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi - if [ "$code" ] && [ ! "$code" = '201' ]; then - _err "new-authz error: $response" - return 1 + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + _URL_NAME="url" + else + if ! __get_domain_new_authz "$_d_domain"; then + _err "Can not get domain new authz token." + return 1 + fi + + authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" + _debug "authzUri" "$authzUri" + if [ "$code" ] && [ ! "$code" = '201' ]; then + _err "new-authz error: $response" + return 1 + fi + _URL_NAME="uri" fi - entries="$(echo "$response" | _egrep_o '{ *"type":"[^"]*", *"status": *"valid", *"uri"[^}]*')" + entries="$(echo "$response" | _egrep_o "{ *\"type\":\"[^\"]*\", *\"status\": *\"valid\", *\"$_URL_NAME\"[^}]*")" if [ -z "$entries" ]; then _info "No valid entries found." if [ -z "$thumbprint" ]; then thumbprint="$(__calc_account_thumbprint)" fi _debug "Trigger validation." - vtype="$VTYPE_HTTP" + vtype="$VTYPE_DNS" entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ]; then @@ -4733,7 +4776,7 @@ _deactivate() { token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" + uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" _debug uri "$uri" keyauthorization="$token.$thumbprint" @@ -4759,7 +4802,7 @@ _deactivate() { _debug _vtype "$_vtype" _info "Found $_vtype" - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" + uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" _debug uri "$uri" if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then @@ -4769,7 +4812,13 @@ _deactivate() { _info "Deactivate: $_vtype" - if _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then + if [ "$ACME_VERSION" = "2" ]; then + _djson="{\"status\":\"deactivated\"}" + else + _djson="{\"resource\": \"authz\", \"status\":\"deactivated\"}" + fi + + if _send_signed_request "$authzUri" "$_djson" && _contains "$response" '"deactivated"'; then _info "Deactivate: $_vtype success." else _err "Can not deactivate $_vtype." @@ -5492,10 +5541,6 @@ _process() { fi if [ -z "$_domain" ]; then - if _startswith "$_dvalue" "*."; then - _err "The first domain can not be wildcard, '$_dvalue' is a wildcard domain." - return 1 - fi _domain="$_dvalue" else if _startswith "$_dvalue" "*."; then From 4a139934f696867f81cb135296c409a788a39ffd Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 21:50:57 +0800 Subject: [PATCH 1201/1348] fix dns manual mode. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5a5f0337..4433e814 100755 --- a/acme.sh +++ b/acme.sh @@ -3005,7 +3005,7 @@ _on_issue_err() { _chk_post_hook="$1" _chk_vlist="$2" _debug _on_issue_err - _cleardomainconf "Le_OrderFinalize" + if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" else From ee6f78805f2eff9c8c4cf969470662fca6bf7874 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 7 Jan 2018 12:12:40 +0800 Subject: [PATCH 1202/1348] update doc for v2 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0d942757..2845488e 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. +- Support ACME v1 and ACME v2 +- Support ACME v2 wildcard certs - Simple, powerful and very easy to use. You only need 3 minutes to learn it. - Bash, dash and sh compatible. - Simplest shell script for Let's Encrypt free certificate client. From c99d4948b7e3525f9d9ff1aed760d21284bbad2a Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 20:43:23 +0800 Subject: [PATCH 1203/1348] we should not use "updating" to support wildcard --- dnsapi/dns_ovh.sh | 47 +++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index eaa90bdf..03b75d97 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -137,48 +137,27 @@ dns_ovh_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _debug "Getting txt records" - _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" - - if _contains "$response" '\[\]' || _contains "$response" "This service does not exist"; then - _info "Adding record" - if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then - if _contains "$response" "$txtvalue"; then - _ovh_rest POST "domain/zone/$_domain/refresh" - _debug "Refresh:$response" - _info "Added, sleeping 10 seconds" - sleep 10 - return 0 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 1) - if [ -z "$record_id" ]; then - _err "Can not get record id." - return 1 - fi - _debug "record_id" "$record_id" - - if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}"; then - if _contains "$response" "null"; then - _ovh_rest POST "domain/zone/$_domain/refresh" - _debug "Refresh:$response" - _info "Updated, sleeping 10 seconds" - sleep 10 - return 0 - fi + _info "Adding record" + if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then + if _contains "$response" "$txtvalue"; then + _ovh_rest POST "domain/zone/$_domain/refresh" + _debug "Refresh:$response" + _info "Added, sleeping 10 seconds" + sleep 10 + return 0 fi - _err "Update error" - return 1 fi + _err "Add txt record error." + return 1 } #fulldomain dns_ovh_rm() { fulldomain=$1 + txtvalue=$2 + _debug "Getting txt records" + #_ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" } From 6d5e7826aebcce830636b8b34eb9b36295d52a44 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 21:36:48 +0800 Subject: [PATCH 1204/1348] support dns_ovh_rm() --- dnsapi/dns_ovh.sh | 56 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 03b75d97..96c2044b 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -78,13 +78,8 @@ _ovh_get_api() { esac } -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_ovh_add() { - fulldomain=$1 - txtvalue=$2 +_initAuth() { if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then OVH_AK="" OVH_AS="" @@ -127,6 +122,19 @@ dns_ovh_add() { return 1 fi _info "Consumer key is ok." + return 0 +} + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ovh_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _initAuth; then + return 1 + fi _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -156,9 +164,39 @@ dns_ovh_add() { dns_ovh_rm() { fulldomain=$1 txtvalue=$2 + + if ! _initAuth; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" _debug "Getting txt records" - #_ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" + if ! _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"; then + return 1 + fi + for rid in $(echo "$response" | tr '[,]' ' '); do + _debug rid "$rid" + if ! _ovh_rest GET "domain/zone/$_domain/record/$rid"; then + return 1 + fi + if _contains "$response" "\"target\":\"$txtvalue\""; then + _debug "Found txt id:$rid" + if ! _ovh_rest DELETE "domain/zone/$_domain/record/$rid"; then + return 1 + fi + return 0 + fi + done + + return 1 } #################### Private functions below ################################## @@ -170,7 +208,7 @@ _ovh_authentication() { _H3="" _H4="" - _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' + _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"},{"method": "DELETE","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" _debug3 response "$response" @@ -258,7 +296,7 @@ _ovh_rest() { export _H3="X-Ovh-Timestamp: $_ovh_t" export _H4="X-Ovh-Consumer: $OVH_CK" export _H5="Content-Type: application/json;charset=utf-8" - if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then + if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then _debug data "$data" response="$(_post "$data" "$_ovh_url" "" "$m")" else From 2befb5e7849c3dddbdc32633e5d5b11a64ef1795 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 22:04:03 +0800 Subject: [PATCH 1205/1348] fix ovh --- dnsapi/dns_ovh.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 96c2044b..60ce1898 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -114,8 +114,7 @@ _initAuth() { _info "Checking authentication" - response="$(_ovh_rest GET "domain")" - if _contains "$response" "INVALID_CREDENTIAL"; then + if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL"; then _err "The consumer key is invalid: $OVH_CK" _err "Please retry to create a new one." _clearaccountconf OVH_CK @@ -150,8 +149,7 @@ dns_ovh_add() { if _contains "$response" "$txtvalue"; then _ovh_rest POST "domain/zone/$_domain/refresh" _debug "Refresh:$response" - _info "Added, sleeping 10 seconds" - sleep 10 + _info "Added" return 0 fi fi @@ -303,8 +301,8 @@ _ovh_rest() { response="$(_get "$_ovh_url")" fi - if [ "$?" != "0" ]; then - _err "error $ep" + if [ "$?" != "0" ] || _contains "$response" "INVALID_CREDENTIAL"; then + _err "error $response" return 1 fi _debug2 response "$response" From a8ae23d0a29d796ce5f465a7572538bb2c232cc9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 22:47:01 +0800 Subject: [PATCH 1206/1348] add more sleep for ovh --- dnsapi/dns_ovh.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 60ce1898..de69bd91 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -149,7 +149,8 @@ dns_ovh_add() { if _contains "$response" "$txtvalue"; then _ovh_rest POST "domain/zone/$_domain/refresh" _debug "Refresh:$response" - _info "Added" + _info "Added, sleep 10 seconds." + _sleep 10 return 0 fi fi From 06a2e5fc82e5cf91922d921cb5490e04893afc61 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 23:05:55 +0800 Subject: [PATCH 1207/1348] fix format --- dnsapi/dns_ovh.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index de69bd91..60094739 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -78,7 +78,6 @@ _ovh_get_api() { esac } - _initAuth() { if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then OVH_AK="" @@ -181,7 +180,7 @@ dns_ovh_rm() { return 1 fi - for rid in $(echo "$response" | tr '[,]' ' '); do + for rid in $(echo "$response" | tr '][,' ' '); do _debug rid "$rid" if ! _ovh_rest GET "domain/zone/$_domain/record/$rid"; then return 1 From eb207322d3ee34ddc2098c246f76fc980129fcc9 Mon Sep 17 00:00:00 2001 From: Meowthink Date: Sun, 14 Jan 2018 14:19:33 +0800 Subject: [PATCH 1208/1348] Add namesilo.com dns api support --- README.md | 1 + dnsapi/README.md | 15 +++++ dnsapi/dns_namesilo.sh | 137 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100755 dnsapi/dns_namesilo.sh diff --git a/README.md b/README.md index 0d942757..bd39a202 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ You don't have to do anything manually! 1. UnoEuro API (https://www.unoeuro.com/) 1. INWX (https://www.inwx.de/) 1. Servercow (https://servercow.de) +1. Namesilo (https://www.namesilo.com) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index d357c053..ed36b97c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -651,6 +651,21 @@ acme.sh --issue --dns dns_servercow -d example.com -d www.example.com ``` Both, `SERVERCOW_API_Username` and `SERVERCOW_API_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 35. Use Namesilo.com API + +You'll need to generate an API key at https://www.namesilo.com/account_api.php +Optionally you may restrict the access to an IP range there. + +``` +export Namesilo_Key="xxxxxxxxxxxxxxxxxxxxxxxx" +``` + +And now you can issue certs with: + +``` +acme.sh --issue --dns dns_namesilo --dnssleep 900 -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_namesilo.sh b/dnsapi/dns_namesilo.sh new file mode 100755 index 00000000..dc1a4fda --- /dev/null +++ b/dnsapi/dns_namesilo.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env sh + +#Author: meowthink +#Created 01/14/2017 +#Utilize namesilo.com API to finish dns-01 verifications. + +Namesilo_API="https://www.namesilo.com/api" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_namesilo_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$Namesilo_Key" ]; then + Namesilo_Key="" + _err "API token for namesilo.com is missing." + _err "Please specify that in your environment variable." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf Namesilo_Key "$Namesilo_Key" + + if ! _get_root "$fulldomain"; then + _err "Unable to find domain specified." + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug txtvalue "$txtvalue" + if _namesilo_rest GET "dnsAddRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrtype=TXT&rrhost=$_sub_domain&rrvalue=$txtvalue"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "300") + if [ "$retcode" ]; then + _info "Successfully added TXT record, ready for validation." + return 0 + else + _err "Unable to add the DNS record." + return 1 + fi + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_namesilo_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _get_root "$fulldomain"; then + _err "Unable to find domain specified." + return 1 + fi + + # Get the record id. + if _namesilo_rest GET "dnsListRecords?version=1&type=xml&key=$Namesilo_Key&domain=$_domain"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "300") + if [ "$retcode" ]; then + _record_id=$(printf "%s\n" "$response" | _egrep_o "([^<]*)TXT$fulldomain" | _egrep_o "([^<]*)" | sed -r "s/([^<]*)<\/record_id>/\1/" | tail -n 1) + _debug record_id "$_record_id" + _info "Successfully retrieved the record id for ACME challenge." + else + _err "Unable to retrieve the record id." + return 1 + fi + fi + + # Remove the DNS record using record id. + if _namesilo_rest GET "dnsDeleteRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrid=$_record_id"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "300") + if [ "$retcode" ]; then + _info "Successfully removed the TXT record." + return 0 + else + _err "Unable to remove the DNS record." + return 1 + fi + fi +} + +#################### Private functions below ################################## + +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + + if ! _namesilo_rest GET "listDomains?version=1&type=xml&key=$Namesilo_Key"; then + return 1 + fi + + # Need to exclude the last field (tld) + numfields=$(echo "$domain" | _egrep_o "\." | wc -l) + while [ $i -le "$numfields" ]; do + host=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug host "$host" + if [ -z "$host" ]; then + return 1 + fi + + if _contains "$response" "$host"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$host" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_namesilo_rest() { + method=$1 + param=$2 + data=$3 + + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$Namesilo_API/$param" "" "$method")" + else + response="$(_get "$Namesilo_API/$param")" + fi + + if [ "$?" != "0" ]; then + _err "error $param" + return 1 + fi + + _debug2 response "$response" + return 0 +} From cd2fe698bb627c4fb9a12a775f71672df1d07d6e Mon Sep 17 00:00:00 2001 From: AA Date: Mon, 15 Jan 2018 10:59:50 +0100 Subject: [PATCH 1209/1348] Create dns_autodns.sh --- dnsapi/dns_autodns.sh | 264 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 dnsapi/dns_autodns.sh diff --git a/dnsapi/dns_autodns.sh b/dnsapi/dns_autodns.sh new file mode 100644 index 00000000..92534489 --- /dev/null +++ b/dnsapi/dns_autodns.sh @@ -0,0 +1,264 @@ +#!/usr/bin/env sh +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- + +# This is the InternetX autoDNS xml api wrapper for acme.sh +# Author: auerswald@gmail.com +# Created: 2018-01-14 +# +# export AUTODNS_USER="username" +# export AUTODNS_PASSWORD="password" +# export AUTODNS_CONTEXT="context" +# +# Usage: +# acme.sh --issue --dns dns_autodns -d example.com + +AUTODNS_API="https://gateway.autodns.com" + +# Arguments: +# txtdomain +# txt +dns_autodns_add() { + fulldomain="$1" + txtvalue="$2" + + AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" + AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" + AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}" + + if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then + _err "You don't specify autodns user, password and context." + return 1 + fi + + _saveaccountconf_mutable AUTODNS_USER "$AUTODNS_USER" + _saveaccountconf_mutable AUTODNS_PASSWORD "$AUTODNS_PASSWORD" + _saveaccountconf_mutable AUTODNS_CONTEXT "$AUTODNS_CONTEXT" + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Adding TXT record" + + autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Added, OK" + return 0 + fi + + return 1 +} + +# Arguments: +# txtdomain +# txt +dns_autodns_rm() { + fulldomain="$1" + txtvalue="$2" + + AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" + AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" + AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}" + + if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then + _err "You don't specify autodns user, password and context." + return 1 + fi + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "zone not found" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Delete TXT record" + + autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Deleted, OK" + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## + +# Arguments: +# fulldomain +# Returns: +# _sub_domain=_acme-challenge.www +# _zone=domain.com +# _system_ns +_get_autodns_zone() { + 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 + + autodns_response="$(_autodns_zone_inquire "$h")" + + if [ "$?" -ne "0" ]; then + _err "invalid domain" + return 1 + fi + + if _contains "$autodns_response" "1" >/dev/null; then + _zone="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _system_ns="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_build_request_auth_xml() { + printf " + %s + %s + %s + " "$AUTODNS_USER" "$AUTODNS_PASSWORD" "$AUTODNS_CONTEXT" +} + +# Arguments: +# zone +_build_zone_inquire_xml() { + printf " + + %s + + 0205 + + 1 + 1 + + + name + eq + %s + + + " "$(_build_request_auth_xml)" "$1" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_build_zone_update_xml() { + printf " + + %s + + 0202001 + + + %s + 600 + TXT + %s + + + + %s + %s + + + " "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4" +} + +# Arguments: +# zone +_autodns_zone_inquire() { + request_data="$(_build_zone_inquire_xml "$1")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_update() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_cleanup() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + # replace 'rr_add>' with 'rr_rem>' in request_data + request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# request_data +_autodns_api_call() { + request_data="$1" + + _debug request_data "$request_data" + + autodns_response="$(_post "$request_data" "$AUTODNS_API")" + ret="$?" + + _debug autodns_response "$autodns_response" + + if [ "$ret" -ne "0" ]; then + _err "error" + return 1 + fi + + if _contains "$autodns_response" "success" >/dev/null; then + _info "success" + printf "%s" "$autodns_response" + return 0 + fi + + return 1 +} From a01da2fd92dafbf0a1e67dbe8ff45dce6a5be33b Mon Sep 17 00:00:00 2001 From: AA Date: Mon, 15 Jan 2018 11:00:44 +0100 Subject: [PATCH 1210/1348] Update README.md --- dnsapi/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index ed36b97c..83ef4ea7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -666,6 +666,24 @@ And now you can issue certs with: acme.sh --issue --dns dns_namesilo --dnssleep 900 -d example.com -d www.example.com ``` +## 37. Use autoDNS (InternetX) + +[InternetX](https://www.internetx.com/) offers an [xml api](https://help.internetx.com/display/API/AutoDNS+XML-API) with your standard login credentials, set them like so: + +``` +export AUTODNS_USER="yourusername" +export AUTODNS_PASSWORD="password" +export AUTODNS_CONTEXT="context" +``` + +Then you can issue your certificates with: + +``` +acme.sh --issue --dns dns_autodns -d example.com -d www.example.com +``` + +The `AUTODNS_USER`, `AUTODNS_PASSWORD` and `AUTODNS_CONTEXT` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. From 775aae7082efab15175449d9183114a976c3a4d1 Mon Sep 17 00:00:00 2001 From: AA Date: Mon, 15 Jan 2018 11:15:26 +0100 Subject: [PATCH 1211/1348] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd39a202..a2c210e8 100644 --- a/README.md +++ b/README.md @@ -343,7 +343,7 @@ You don't have to do anything manually! 1. INWX (https://www.inwx.de/) 1. Servercow (https://servercow.de) 1. Namesilo (https://www.namesilo.com) - +1. InternetX autoDNS API (https://internetx.com) And: From 7e212c4d406e3d8669b23b89b2107ea1c2b6b390 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 15 Jan 2018 19:48:57 +0800 Subject: [PATCH 1212/1348] typo --- acme.sh | 1 - dnsapi/dns_aws.sh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 4433e814..6c3f6e05 100755 --- a/acme.sh +++ b/acme.sh @@ -3474,7 +3474,6 @@ issue() { #make new order request _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" for d in $(echo "$_alt_domains" | tr ',' ' '); do - #todo: check wildcard ? if [ "$d" ]; then _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" fi diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 5a716514..8c1513d1 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -23,7 +23,7 @@ dns_aws_add() { AWS_ACCESS_KEY_ID="" AWS_SECRET_ACCESS_KEY="" _err "You don't specify aws route53 api key id and and api key secret yet." - _err "Please create you key and try again. see $(__green $AWS_WIKI)" + _err "Please create your key and try again. see $(__green $AWS_WIKI)" return 1 fi From e6cda79ee8411255d191f7781df42522bbf3aedc Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 15 Jan 2018 21:55:40 +0800 Subject: [PATCH 1213/1348] support only one wildcard domain. fix https://github.com/Neilpang/acme.sh/issues/1188#issuecomment-357684744 --- acme.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index 6c3f6e05..74b437cb 100755 --- a/acme.sh +++ b/acme.sh @@ -3340,10 +3340,6 @@ issue() { _main_domain="$2" _alt_domains="$3" - if _startswith "$_main_domain" "*."; then - _err "The first domain can not be wildcard, '$_main_domain' is a wildcard domain." - return 1 - fi if _contains "$_main_domain" ","; then _main_domain=$(echo "$2,$3" | cut -d , -f 1) _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") @@ -5539,13 +5535,13 @@ _process() { return 1 fi + if _startswith "$_dvalue" "*."; then + _debug "Wildcard domain" + export ACME_VERSION=2 + fi if [ -z "$_domain" ]; then _domain="$_dvalue" else - if _startswith "$_dvalue" "*."; then - _debug "Wildcard domain" - export ACME_VERSION=2 - fi if [ "$_altdomains" = "$NO_VALUE" ]; then _altdomains="$_dvalue" else From 3164b5ab1307321548aca49c9e97e117d72d9e8f Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 16 Jan 2018 20:55:07 +0800 Subject: [PATCH 1214/1348] fix https://github.com/Neilpang/acme.sh/issues/1189 --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 74b437cb..59a7d960 100755 --- a/acme.sh +++ b/acme.sh @@ -2259,6 +2259,8 @@ _initAPI() { #[domain] [keylength or isEcc flag] _initpath() { + domain="$1" + _ilength="$2" __initHome @@ -2346,13 +2348,10 @@ _initpath() { ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" fi - if [ -z "$1" ]; then + if [ -z "$domain" ]; then return 0 fi - domain="$1" - _ilength="$2" - if [ -z "$DOMAIN_PATH" ]; then domainhome="$CERT_HOME/$domain" domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" @@ -4234,8 +4233,6 @@ signcsr() { return 1 fi - _initpath - _csrsubj=$(_readSubjectFromCSR "$_csrfile") if [ "$?" != "0" ]; then _err "Can not read subject from csr: $_csrfile" @@ -4272,6 +4269,9 @@ signcsr() { return 1 fi + if [ -z "$ACME_VERSION" ] && _contains "$_csrsubj,$_csrdomainlist" "*."; then + export ACME_VERSION=2 + fi _initpath "$_csrsubj" "$_csrkeylength" mkdir -p "$DOMAIN_PATH" From c1151b0d459c4e9cfac45c8dd2cfc70cedeecfff Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 12:45:24 +0800 Subject: [PATCH 1215/1348] first version to support ACME v2 --- acme.sh | 308 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 239 insertions(+), 69 deletions(-) diff --git a/acme.sh b/acme.sh index 472975a6..604bff04 100755 --- a/acme.sh +++ b/acme.sh @@ -13,8 +13,15 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" -_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" -DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" +LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory" +LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" + +LETSENCRYPT_CA_V2="https://acme-v02.api.letsencrypt.org/directory" +LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/directory" + +DEFAULT_CA=$LETSENCRYPT_CA_V1 +DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1 + DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -24,13 +31,13 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" -STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" +_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" VTYPE_TLS="tls-sni-01" -#VTYPE_TLS2="tls-sni-02" +VTYPE_TLS2="tls-sni-02" LOCAL_ANY_ADDRESS="0.0.0.0" @@ -1044,13 +1051,14 @@ _createcsr() { if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then #single domain _info "Single domain" "$domain" + printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf" else domainlist="$(_idn "$domainlist")" _debug2 domainlist "$domainlist" if _contains "$domainlist" ","; then - alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" + alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" else - alt="DNS:$domainlist" + alt="DNS:$domain,DNS:$domainlist" fi #multi _info "Multi domain" "$alt" @@ -1421,7 +1429,7 @@ _calcjwk() { JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' - JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART2='", "alg": "RS256"' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" @@ -1490,7 +1498,7 @@ _calcjwk() { JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' - JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"' else _err "Only RSA or EC key is supported." return 1 @@ -1580,7 +1588,7 @@ _inithttp() { # body url [needbase64] [POST|PUT] _post() { body="$1" - url="$2" + _post_url="$2" needbase64="$3" httpmethod="$4" @@ -1588,7 +1596,7 @@ _post() { httpmethod="POST" fi _debug $httpmethod - _debug "url" "$url" + _debug "_post_url" "$_post_url" _debug2 "body" "$body" _inithttp @@ -1600,9 +1608,9 @@ _post() { fi _debug "_CURL" "$_CURL" if [ "$needbase64" ]; then - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")" + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" fi _ret="$?" if [ "$_ret" != "0" ]; then @@ -1620,15 +1628,15 @@ _post() { _debug "_WGET" "$_WGET" if [ "$needbase64" ]; then if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" fi else if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" fi fi _ret="$?" @@ -1776,7 +1784,15 @@ _send_signed_request() { nonce="$_CACHED_NONCE" _debug2 nonce "$nonce" - protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2" + if [ "$ACME_VERSION" = "2" ]; then + if [ "$url" = "$ACME_NEW_ACCOUNT" ]; then + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' + else + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"$ACCOUNT_URL\""'}' + fi + else + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' + fi _debug3 protected "$protected" protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" @@ -1791,7 +1807,11 @@ _send_signed_request() { sig="$(printf "%s" "$_sig_t" | _url_replace)" _debug3 sig "$sig" - body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + if [ "$ACME_VERSION" = "2" ]; then + body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + else + body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + fi _debug3 body "$body" response="$(_post "$body" "$url" "$needbase64")" @@ -2170,9 +2190,15 @@ _initAPI() { _debug2 "response" "$response" ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_KEY_CHANGE" ]; then + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'keyChange" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_KEY_CHANGE ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_AUTHZ" ]; then + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'newAuthz" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_NEW_AUTHZ ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) @@ -2180,6 +2206,9 @@ _initAPI() { if [ -z "$ACME_NEW_ORDER" ]; then ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) ACME_NEW_ORDER_RES="new-order" + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'newOrder" *: *"[^"]*"' | cut -d '"' -f 3) + fi fi export ACME_NEW_ORDER export ACME_NEW_ORDER_RES @@ -2189,17 +2218,32 @@ _initAPI() { if [ -z "$ACME_NEW_ACCOUNT" ]; then ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) ACME_NEW_ACCOUNT_RES="new-account" + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'newAccount" *: *"[^"]*"' | cut -d '"' -f 3) + if [ "$ACME_NEW_ACCOUNT" ]; then + export ACME_VERSION=2 + fi + fi fi export ACME_NEW_ACCOUNT export ACME_NEW_ACCOUNT_RES ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_REVOKE_CERT" ]; then + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revokeCert" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_REVOKE_CERT ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_NONCE" ]; then + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'newNonce" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_NEW_NONCE ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_AGREEMENT" ]; then + ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3) + fi export ACME_AGREEMENT _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" @@ -2208,6 +2252,8 @@ _initAPI() { _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" + _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE" + _debug "ACME_VERSION" "$ACME_VERSION" fi } @@ -2236,7 +2282,7 @@ _initpath() { if [ -z "$STAGE" ]; then ACME_DIRECTORY="$DEFAULT_CA" else - ACME_DIRECTORY="$STAGE_CA" + ACME_DIRECTORY="$DEFAULT_STAGING_CA" _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" fi fi @@ -2951,6 +2997,7 @@ _on_issue_err() { _chk_post_hook="$1" _chk_vlist="$2" _debug _on_issue_err + _cleardomainconf "ORDER_FINALIZE" if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" else @@ -3052,6 +3099,8 @@ _regAccount() { _initpath _reg_length="$1" _debug3 _regAccount "$_regAccount" + _initAPI + mkdir -p "$CA_DIR" if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" @@ -3073,11 +3122,18 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - _initAPI - _reg_res="$ACME_NEW_ACCOUNT_RES" - regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' - if [ "$ACCOUNT_EMAIL" ]; then - regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + + if [ "$ACME_VERSION" = "2" ]; then + regjson='{"termsOfServiceAgreed": true}' + if [ "$ACCOUNT_EMAIL" ]; then + regjson='{"contact": ["mailto: '$ACCOUNT_EMAIL'"], "termsOfServiceAgreed": true}' + fi + else + _reg_res="$ACME_NEW_ACCOUNT_RES" + regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + if [ "$ACCOUNT_EMAIL" ]; then + regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + fi fi _info "Registering account" @@ -3100,8 +3156,8 @@ _regAccount() { _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" _savecaconf "ACCOUNT_URL" "$_accUri" + export ACCOUNT_URL="$ACCOUNT_URL" - echo "$response" >"$ACCOUNT_JSON_PATH" CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" _savecaconf CA_KEY_HASH "$CA_KEY_HASH" @@ -3113,7 +3169,6 @@ _regAccount() { ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" - } #Implement deactivate account @@ -3251,7 +3306,11 @@ __trigger_validation() { _debug2 _t_url "$_t_url" _t_key_authz="$2" _debug2 _t_key_authz "$_t_key_authz" - _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" + if [ "$ACME_VERSION" = "2" ]; then + _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}" + else + _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" + fi } #webroot, domain domainlist keylength @@ -3393,32 +3452,107 @@ issue() { sep='#' dvsep=',' if [ -z "$vlist" ]; then + if [ "$ACME_VERSION" = "2" ] && [ -z "$ORDER_FINALIZE" ]; then + #make new order request + _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" + for d in $(echo "$_alt_domains" | tr ',' ' '); do + #todo: check wildcard ? + if [ "$d" ]; then + _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" + fi + done + _debug2 _identifiers "$_identifiers" + if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then + _err "Create new order error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + ORDER_FINALIZE="$(echo "$response"| tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" + _debug ORDER_FINALIZE "$ORDER_FINALIZE" + if [ -z "$ORDER_FINALIZE" ]; then + _err "ORDER_FINALIZE not found." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + #for dns manual mode + _savedomainconf "ORDER_FINALIZE" "$ORDER_FINALIZE" + + _authorizations_seg="$(echo "$response"| tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _debug2 _authorizations_seg "$_authorizations_seg" + if [ -z "$_authorizations_seg" ]; then + _err "_authorizations_seg not found." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + #domain and authz map + _authorizations_map="" + for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' ' ); do + _debug2 "_authz_url" "$_authz_url" + if ! response="$(_get "$_authz_url")"; then + _err "get to authz error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')" + _debug2 _d "$_d" + _authorizations_map="$_d,$response +$_authorizations_map" + done + _debug2 _authorizations_map "$_authorizations_map" + fi + alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ') - _index=1 + _index=0 _currentRoot="" for d in $alldomains; do _info "Getting webroot for domain" "$d" + _index=$(_math $_index + 1) _w="$(echo $_web_roots | cut -d , -f $_index)" _debug _w "$_w" if [ "$_w" ]; then _currentRoot="$_w" fi _debug "_currentRoot" "$_currentRoot" - _index=$(_math $_index + 1) vtype="$VTYPE_HTTP" + #todo, v2 wildcard force to use dns if _startswith "$_currentRoot" "dns"; then vtype="$VTYPE_DNS" fi if [ "$_currentRoot" = "$W_TLS" ]; then - vtype="$VTYPE_TLS" + if [ "$ACME_VERSION" = "2" ]; then + vtype="$VTYPE_TLS2" + else + vtype="$VTYPE_TLS" + fi fi - if ! __get_domain_new_authz "$d"; then - _clearup - _on_issue_err "$_post_hook" - return 1 + if [ "$ACME_VERSION" = "2" ]; then + response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")" + _debug2 "response" "$response" + if [ -z "$response" ]; then + _err "get to authz error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + else + if ! __get_domain_new_authz "$d"; then + _clearup + _on_issue_err "$_post_hook" + return 1 + fi fi if [ -z "$thumbprint" ]; then @@ -3436,14 +3570,18 @@ issue() { token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" + if [ "$ACME_VERSION" = "2" ]; then + uri="$(printf "%s\n" "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)" + else + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" + fi _debug uri "$uri" keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then - _debug "$d is already verified, skip." + _debug "$d is already verified." keyauthorization="$STATE_VERIFIED" _debug keyauthorization "$keyauthorization" fi @@ -3685,12 +3823,16 @@ issue() { return 1 fi - if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then - _err "$d:Challenge error: $response" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 + if [ "$code" ] && [ "$code" != '202' ]; then + if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then + _debug "trigger validation code: $code" + else + _err "$d:Challenge error: $response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi fi waittimes=0 @@ -3773,18 +3915,32 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then - _err "Sign failed." - _on_issue_err "$_post_hook" - return 1 - fi - - _rcert="$response" - Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" - _debug "Le_LinkCert" "$Le_LinkCert" - _savedomainconf "Le_LinkCert" "$Le_LinkCert" + if [ "$ACME_VERSION" = "2" ]; then + if ! _send_signed_request "${ORDER_FINALIZE}" "{\"csr\": \"$der\"}"; then + _err "Sign failed." + _on_issue_err "$_post_hook" + return 1 + fi + if [ "$code" != "200" ]; then + _err "Sign failed, code is not 200." + _on_issue_err "$_post_hook" + return 1 + fi + Le_LinkCert="$(echo "$response"| tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" - if [ "$Le_LinkCert" ]; then + if ! _get "$Le_LinkCert" > "$CERT_PATH"; then + _err "Sign failed, code is not 200." + _on_issue_err "$_post_hook" + return 1 + fi + else + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then + _err "Sign failed." + _on_issue_err "$_post_hook" + return 1 + fi + _rcert="$response" + Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" echo "$BEGIN_CERT" >"$CERT_PATH" #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then @@ -3798,6 +3954,12 @@ issue() { fi echo "$END_CERT" >>"$CERT_PATH" + fi + + _debug "Le_LinkCert" "$Le_LinkCert" + _savedomainconf "Le_LinkCert" "$Le_LinkCert" + + if [ "$Le_LinkCert" ]; then _info "$(__green "Cert success.")" cat "$CERT_PATH" @@ -3825,29 +3987,37 @@ issue() { _cleardomainconf "Le_Vlist" Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') - if ! _contains "$Le_LinkIssuer" ":"; then - _info "$(__red "Relative issuer link found.")" - Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" - fi - _debug Le_LinkIssuer "$Le_LinkIssuer" - _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ]; then + if ! _contains "$Le_LinkIssuer" ":"; then + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" + fi + _debug Le_LinkIssuer "$Le_LinkIssuer" + _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" + _link_issuer_retry=0 _MAX_ISSUER_RETRY=5 while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do _debug _link_issuer_retry "$_link_issuer_retry" - if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then - echo "$BEGIN_CERT" >"$CA_CERT_PATH" - _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" - echo "$END_CERT" >>"$CA_CERT_PATH" + + if [ "$ACME_VERSION" = "2" ]; then + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then + break + fi + else + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then + echo "$BEGIN_CERT" >"$CA_CERT_PATH" + _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" + echo "$END_CERT" >>"$CA_CERT_PATH" - _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 ")" + _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 + rm -f "$CA_CERT_PATH.der" + break + fi fi _link_issuer_retry=$(_math $_link_issuer_retry + 1) _sleep "$_link_issuer_retry" @@ -3957,7 +4127,7 @@ renew() { _savedomainconf Le_API "$Le_API" fi if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then - export Le_API="$STAGE_CA" + export Le_API="$DEFAULT_STAGING_CA" _savedomainconf Le_API "$Le_API" fi export ACME_DIRECTORY="$Le_API" From f8d22c486e243704b58a40b377a1b15dc8366d3e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 13:57:35 +0800 Subject: [PATCH 1216/1348] fix format --- acme.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index 604bff04..890cdd82 100755 --- a/acme.sh +++ b/acme.sh @@ -22,7 +22,6 @@ LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/director DEFAULT_CA=$LETSENCRYPT_CA_V1 DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1 - DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -3122,7 +3121,7 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - + if [ "$ACME_VERSION" = "2" ]; then regjson='{"termsOfServiceAgreed": true}' if [ "$ACCOUNT_EMAIL" ]; then @@ -3469,7 +3468,7 @@ issue() { return 1 fi - ORDER_FINALIZE="$(echo "$response"| tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" + ORDER_FINALIZE="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" _debug ORDER_FINALIZE "$ORDER_FINALIZE" if [ -z "$ORDER_FINALIZE" ]; then _err "ORDER_FINALIZE not found." @@ -3481,7 +3480,7 @@ issue() { #for dns manual mode _savedomainconf "ORDER_FINALIZE" "$ORDER_FINALIZE" - _authorizations_seg="$(echo "$response"| tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" _debug2 _authorizations_seg "$_authorizations_seg" if [ -z "$_authorizations_seg" ]; then _err "_authorizations_seg not found." @@ -3492,7 +3491,7 @@ issue() { #domain and authz map _authorizations_map="" - for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' ' ); do + for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do _debug2 "_authz_url" "$_authz_url" if ! response="$(_get "$_authz_url")"; then _err "get to authz error." @@ -3926,9 +3925,9 @@ $_authorizations_map" _on_issue_err "$_post_hook" return 1 fi - Le_LinkCert="$(echo "$response"| tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" + Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" - if ! _get "$Le_LinkCert" > "$CERT_PATH"; then + if ! _get "$Le_LinkCert" >"$CERT_PATH"; then _err "Sign failed, code is not 200." _on_issue_err "$_post_hook" return 1 @@ -4000,7 +3999,6 @@ $_authorizations_map" _MAX_ISSUER_RETRY=5 while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do _debug _link_issuer_retry "$_link_issuer_retry" - if [ "$ACME_VERSION" = "2" ]; then if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then break From 72f54ca6c13c33943aafbacaee03423907f5e738 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 17:39:15 +0800 Subject: [PATCH 1217/1348] support ACME v2 wildcard cert --- acme.sh | 38 +++++++++++++++++++++++++++++------- dnsapi/dns_cf.sh | 51 +++++++++++++++++++++++++----------------------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/acme.sh b/acme.sh index 890cdd82..1021dcd0 100755 --- a/acme.sh +++ b/acme.sh @@ -997,7 +997,7 @@ _createkey() { _is_idn() { _is_idn_d="$1" _debug2 _is_idn_d "$_is_idn_d" - _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-') + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-') _debug2 _idn_temp "$_idn_temp" [ "$_idn_temp" ] } @@ -1055,7 +1055,7 @@ _createcsr() { domainlist="$(_idn "$domainlist")" _debug2 domainlist "$domainlist" if _contains "$domainlist" ","; then - alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" + alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" else alt="DNS:$domain,DNS:$domainlist" fi @@ -1663,7 +1663,7 @@ _get() { onlyheader="$2" t="$3" _debug url "$url" - _debug "timeout" "$t" + _debug "timeout=$t" _inithttp @@ -2277,6 +2277,11 @@ _initpath() { CA_HOME="$DEFAULT_CA_HOME" fi + if [ "$ACME_VERSION" = "2" ]; then + DEFAULT_CA="$LETSENCRYPT_CA_V2" + DEFAULT_STAGING_CA="$LETSENCRYPT_STAGING_CA_V2" + fi + if [ -z "$ACME_DIRECTORY" ]; then if [ -z "$STAGE" ]; then ACME_DIRECTORY="$DEFAULT_CA" @@ -2863,7 +2868,11 @@ _clearupdns() { return 1 fi - txtdomain="_acme-challenge.$d" + _dns_root_d="$d" + if _startswith "$_dns_root_d" "*."; then + _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" + fi + txtdomain="_acme-challenge.$_dns_root_d" if ! $rmcommand "$txtdomain" "$txt"; then _err "Error removing txt for domain:$txtdomain" @@ -3503,6 +3512,9 @@ issue() { response="$(echo "$response" | _normalizeJson)" _debug2 response "$response" _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')" + if _contains "$response" "\"wildcard\" *: *true"; then + _d="*.$_d" + fi _debug2 _d "$_d" _authorizations_map="$_d,$response $_authorizations_map" @@ -3600,7 +3612,7 @@ $_authorizations_map" keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) vtype=$(echo "$ventry" | cut -d "$sep" -f 4) _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - + _debug d "$d" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _debug "$d is already verified, skip $vtype." continue @@ -3608,12 +3620,16 @@ $_authorizations_map" if [ "$vtype" = "$VTYPE_DNS" ]; then dnsadded='0' - txtdomain="_acme-challenge.$d" + _dns_root_d="$d" + if _startswith "$_dns_root_d" "*."; then + _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" + fi + txtdomain="_acme-challenge.$_dns_root_d" _debug txtdomain "$txtdomain" txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" - d_api="$(_findHook "$d" dnsapi "$_currentRoot")" + d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")" _debug d_api "$d_api" @@ -5476,8 +5492,16 @@ _process() { fi if [ -z "$_domain" ]; then + if _startswith "$_dvalue" "*."; then + _err "The first domain can not be wildcard, '$_dvalue' is a wildcard domain." + return 1 + fi _domain="$_dvalue" else + if _startswith "$_dvalue" "*."; then + _debug "Wildcard domain" + export ACME_VERSION=2 + fi if [ "$_altdomains" = "$NO_VALUE" ]; then _altdomains="$_dvalue" else diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 57a2e884..abe7700c 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -51,33 +51,36 @@ dns_cf_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) - _debug count "$count" - 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 - _info "Added, OK" - return 0 - else - _err "Add txt record error." - return 1 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) - _debug "record_id" "$record_id" - - _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" - if [ "$?" = "0" ]; then - _info "Updated, OK" +# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so +# we can not use updating anymore. +# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) +# _debug count "$count" +# 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 + _info "Added, OK" return 0 + else + _err "Add txt record error." + return 1 fi - _err "Update error" - return 1 fi + _err "Add txt record error." + return 1 +# else +# _info "Updating record" +# record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) +# _debug "record_id" "$record_id" +# +# _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" +# if [ "$?" = "0" ]; then +# _info "Updated, OK" +# return 0 +# fi +# _err "Update error" +# return 1 +# fi } From 506c41cb157bf45fc27d5930458688eb2ff666b4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 19:42:29 +0800 Subject: [PATCH 1218/1348] fix format --- dnsapi/dns_cf.sh | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index abe7700c..68264a42 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -51,11 +51,11 @@ dns_cf_add() { return 1 fi -# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so -# we can not use updating anymore. -# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) -# _debug count "$count" -# if [ "$count" = "0" ]; then + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # 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 @@ -68,19 +68,19 @@ dns_cf_add() { fi _err "Add txt record error." return 1 -# else -# _info "Updating record" -# record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) -# _debug "record_id" "$record_id" -# -# _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" -# if [ "$?" = "0" ]; then -# _info "Updated, OK" -# return 0 -# fi -# _err "Update error" -# return 1 -# fi + # else + # _info "Updating record" + # record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + # _debug "record_id" "$record_id" + # + # _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" + # if [ "$?" = "0" ]; then + # _info "Updated, OK" + # return 0 + # fi + # _err "Update error" + # return 1 + # fi } From d2cde379ad310767fc84e2f6f92599b9b6d8c458 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 21:33:27 +0800 Subject: [PATCH 1219/1348] fix ACME v2: deactivate/deactivate-account/revoke --- acme.sh | 103 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 29 deletions(-) diff --git a/acme.sh b/acme.sh index 1021dcd0..5a5f0337 100755 --- a/acme.sh +++ b/acme.sh @@ -1784,7 +1784,7 @@ _send_signed_request() { _debug2 nonce "$nonce" if [ "$ACME_VERSION" = "2" ]; then - if [ "$url" = "$ACME_NEW_ACCOUNT" ]; then + if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' else protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"$ACCOUNT_URL\""'}' @@ -3005,7 +3005,7 @@ _on_issue_err() { _chk_post_hook="$1" _chk_vlist="$2" _debug _on_issue_err - _cleardomainconf "ORDER_FINALIZE" + _cleardomainconf "Le_OrderFinalize" if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" else @@ -3212,7 +3212,12 @@ deactivateaccount() { fi _initAPI - if _send_signed_request "$_accUri" "{\"resource\": \"reg\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then + if [ "$ACME_VERSION" = "2" ]; then + _djson="{\"status\":\"deactivated\"}" + else + _djson="{\"resource\": \"reg\", \"status\":\"deactivated\"}" + fi + if _send_signed_request "$_accUri" "$_djson" && _contains "$response" '"deactivated"'; then _info "Deactivate account success for $_accUri." _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,') elif [ "$code" = "403" ]; then @@ -3334,6 +3339,11 @@ issue() { _web_roots="$1" _main_domain="$2" _alt_domains="$3" + + if _startswith "$_main_domain" "*."; then + _err "The first domain can not be wildcard, '$_main_domain' is a wildcard domain." + return 1 + fi if _contains "$_main_domain" ","; then _main_domain=$(echo "$2,$3" | cut -d , -f 1) _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") @@ -3460,7 +3470,7 @@ issue() { sep='#' dvsep=',' if [ -z "$vlist" ]; then - if [ "$ACME_VERSION" = "2" ] && [ -z "$ORDER_FINALIZE" ]; then + if [ "$ACME_VERSION" = "2" ]; then #make new order request _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" for d in $(echo "$_alt_domains" | tr ',' ' '); do @@ -3477,17 +3487,17 @@ issue() { return 1 fi - ORDER_FINALIZE="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" - _debug ORDER_FINALIZE "$ORDER_FINALIZE" - if [ -z "$ORDER_FINALIZE" ]; then - _err "ORDER_FINALIZE not found." + Le_OrderFinalize="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" + _debug Le_OrderFinalize "$Le_OrderFinalize" + if [ -z "$Le_OrderFinalize" ]; then + _err "Le_OrderFinalize not found." _clearup _on_issue_err "$_post_hook" return 1 fi #for dns manual mode - _savedomainconf "ORDER_FINALIZE" "$ORDER_FINALIZE" + _savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize" _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" _debug2 _authorizations_seg "$_authorizations_seg" @@ -3931,7 +3941,7 @@ $_authorizations_map" der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" if [ "$ACME_VERSION" = "2" ]; then - if ! _send_signed_request "${ORDER_FINALIZE}" "{\"csr\": \"$der\"}"; then + if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 @@ -4632,7 +4642,11 @@ revoke() { _initAPI - data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" + if [ "$ACME_VERSION" = "2" ]; then + data="{\"certificate\": \"$cert\"}" + else + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" + fi uri="${ACME_REVOKE_CERT}" if [ -f "$CERT_KEY_PATH" ]; then @@ -4703,27 +4717,56 @@ _deactivate() { _d_type="$2" _initpath - if ! __get_domain_new_authz "$_d_domain"; then - _err "Can not get domain new authz token." - return 1 - fi + if [ "$ACME_VERSION" = "2" ]; then + _identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}" + if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then + _err "Can not get domain new order." + return 1 + fi + _authorizations_seg="$(echo "$response" | tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _debug2 _authorizations_seg "$_authorizations_seg" + if [ -z "$_authorizations_seg" ]; then + _err "_authorizations_seg not found." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi - authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" - _debug "authzUri" "$authzUri" + authzUri="$_authorizations_seg" + _debug2 "authzUri" "$authzUri" + if ! response="$(_get "$authzUri")"; then + _err "get to authz error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi - if [ "$code" ] && [ ! "$code" = '201' ]; then - _err "new-authz error: $response" - return 1 + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + _URL_NAME="url" + else + if ! __get_domain_new_authz "$_d_domain"; then + _err "Can not get domain new authz token." + return 1 + fi + + authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" + _debug "authzUri" "$authzUri" + if [ "$code" ] && [ ! "$code" = '201' ]; then + _err "new-authz error: $response" + return 1 + fi + _URL_NAME="uri" fi - entries="$(echo "$response" | _egrep_o '{ *"type":"[^"]*", *"status": *"valid", *"uri"[^}]*')" + entries="$(echo "$response" | _egrep_o "{ *\"type\":\"[^\"]*\", *\"status\": *\"valid\", *\"$_URL_NAME\"[^}]*")" if [ -z "$entries" ]; then _info "No valid entries found." if [ -z "$thumbprint" ]; then thumbprint="$(__calc_account_thumbprint)" fi _debug "Trigger validation." - vtype="$VTYPE_HTTP" + vtype="$VTYPE_DNS" entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ]; then @@ -4733,7 +4776,7 @@ _deactivate() { token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" + uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" _debug uri "$uri" keyauthorization="$token.$thumbprint" @@ -4759,7 +4802,7 @@ _deactivate() { _debug _vtype "$_vtype" _info "Found $_vtype" - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" + uri="$(printf "%s\n" "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" _debug uri "$uri" if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then @@ -4769,7 +4812,13 @@ _deactivate() { _info "Deactivate: $_vtype" - if _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then + if [ "$ACME_VERSION" = "2" ]; then + _djson="{\"status\":\"deactivated\"}" + else + _djson="{\"resource\": \"authz\", \"status\":\"deactivated\"}" + fi + + if _send_signed_request "$authzUri" "$_djson" && _contains "$response" '"deactivated"'; then _info "Deactivate: $_vtype success." else _err "Can not deactivate $_vtype." @@ -5492,10 +5541,6 @@ _process() { fi if [ -z "$_domain" ]; then - if _startswith "$_dvalue" "*."; then - _err "The first domain can not be wildcard, '$_dvalue' is a wildcard domain." - return 1 - fi _domain="$_dvalue" else if _startswith "$_dvalue" "*."; then From cd8fc35968b6009d349284a3acb24f10d531e50f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 6 Jan 2018 21:50:57 +0800 Subject: [PATCH 1220/1348] fix dns manual mode. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5a5f0337..4433e814 100755 --- a/acme.sh +++ b/acme.sh @@ -3005,7 +3005,7 @@ _on_issue_err() { _chk_post_hook="$1" _chk_vlist="$2" _debug _on_issue_err - _cleardomainconf "Le_OrderFinalize" + if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" else From 79a2bed640430d68da691a956ef64229de954c1a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 7 Jan 2018 12:12:40 +0800 Subject: [PATCH 1221/1348] update doc for v2 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a2c210e8..ea509e24 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. +- Support ACME v1 and ACME v2 +- Support ACME v2 wildcard certs - Simple, powerful and very easy to use. You only need 3 minutes to learn it. - Bash, dash and sh compatible. - Simplest shell script for Let's Encrypt free certificate client. From ea25492c2823a4971b3d2eb28fa0dcd2b5105db9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 20:43:23 +0800 Subject: [PATCH 1222/1348] we should not use "updating" to support wildcard --- dnsapi/dns_ovh.sh | 47 +++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index eaa90bdf..03b75d97 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -137,48 +137,27 @@ dns_ovh_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _debug "Getting txt records" - _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" - - if _contains "$response" '\[\]' || _contains "$response" "This service does not exist"; then - _info "Adding record" - if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then - if _contains "$response" "$txtvalue"; then - _ovh_rest POST "domain/zone/$_domain/refresh" - _debug "Refresh:$response" - _info "Added, sleeping 10 seconds" - sleep 10 - return 0 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 1) - if [ -z "$record_id" ]; then - _err "Can not get record id." - return 1 - fi - _debug "record_id" "$record_id" - - if _ovh_rest PUT "domain/zone/$_domain/record/$record_id" "{\"target\":\"$txtvalue\",\"subDomain\":\"$_sub_domain\",\"ttl\":60}"; then - if _contains "$response" "null"; then - _ovh_rest POST "domain/zone/$_domain/refresh" - _debug "Refresh:$response" - _info "Updated, sleeping 10 seconds" - sleep 10 - return 0 - fi + _info "Adding record" + if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then + if _contains "$response" "$txtvalue"; then + _ovh_rest POST "domain/zone/$_domain/refresh" + _debug "Refresh:$response" + _info "Added, sleeping 10 seconds" + sleep 10 + return 0 fi - _err "Update error" - return 1 fi + _err "Add txt record error." + return 1 } #fulldomain dns_ovh_rm() { fulldomain=$1 + txtvalue=$2 + _debug "Getting txt records" + #_ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" } From be186bd39ba8f0fdd971ca23e12138b81d5e95c4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 21:36:48 +0800 Subject: [PATCH 1223/1348] support dns_ovh_rm() --- dnsapi/dns_ovh.sh | 56 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 03b75d97..96c2044b 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -78,13 +78,8 @@ _ovh_get_api() { esac } -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_ovh_add() { - fulldomain=$1 - txtvalue=$2 +_initAuth() { if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then OVH_AK="" OVH_AS="" @@ -127,6 +122,19 @@ dns_ovh_add() { return 1 fi _info "Consumer key is ok." + return 0 +} + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ovh_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _initAuth; then + return 1 + fi _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -156,9 +164,39 @@ dns_ovh_add() { dns_ovh_rm() { fulldomain=$1 txtvalue=$2 + + if ! _initAuth; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" _debug "Getting txt records" - #_ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain" + if ! _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"; then + return 1 + fi + for rid in $(echo "$response" | tr '[,]' ' '); do + _debug rid "$rid" + if ! _ovh_rest GET "domain/zone/$_domain/record/$rid"; then + return 1 + fi + if _contains "$response" "\"target\":\"$txtvalue\""; then + _debug "Found txt id:$rid" + if ! _ovh_rest DELETE "domain/zone/$_domain/record/$rid"; then + return 1 + fi + return 0 + fi + done + + return 1 } #################### Private functions below ################################## @@ -170,7 +208,7 @@ _ovh_authentication() { _H3="" _H4="" - _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' + _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"},{"method": "DELETE","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" _debug3 response "$response" @@ -258,7 +296,7 @@ _ovh_rest() { export _H3="X-Ovh-Timestamp: $_ovh_t" export _H4="X-Ovh-Consumer: $OVH_CK" export _H5="Content-Type: application/json;charset=utf-8" - if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then + if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then _debug data "$data" response="$(_post "$data" "$_ovh_url" "" "$m")" else From f823f170e64a641639fdf2c97a8c6a334f3264b7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 22:04:03 +0800 Subject: [PATCH 1224/1348] fix ovh --- dnsapi/dns_ovh.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 96c2044b..60ce1898 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -114,8 +114,7 @@ _initAuth() { _info "Checking authentication" - response="$(_ovh_rest GET "domain")" - if _contains "$response" "INVALID_CREDENTIAL"; then + if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL"; then _err "The consumer key is invalid: $OVH_CK" _err "Please retry to create a new one." _clearaccountconf OVH_CK @@ -150,8 +149,7 @@ dns_ovh_add() { if _contains "$response" "$txtvalue"; then _ovh_rest POST "domain/zone/$_domain/refresh" _debug "Refresh:$response" - _info "Added, sleeping 10 seconds" - sleep 10 + _info "Added" return 0 fi fi @@ -303,8 +301,8 @@ _ovh_rest() { response="$(_get "$_ovh_url")" fi - if [ "$?" != "0" ]; then - _err "error $ep" + if [ "$?" != "0" ] || _contains "$response" "INVALID_CREDENTIAL"; then + _err "error $response" return 1 fi _debug2 response "$response" From 01cc2e13d81cbcda3485c8256a591230defe2626 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 22:47:01 +0800 Subject: [PATCH 1225/1348] add more sleep for ovh --- dnsapi/dns_ovh.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 60ce1898..de69bd91 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -149,7 +149,8 @@ dns_ovh_add() { if _contains "$response" "$txtvalue"; then _ovh_rest POST "domain/zone/$_domain/refresh" _debug "Refresh:$response" - _info "Added" + _info "Added, sleep 10 seconds." + _sleep 10 return 0 fi fi From 0170c20e9a7d9632f8c83417c73c56fe0d985c51 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 9 Jan 2018 23:05:55 +0800 Subject: [PATCH 1226/1348] fix format --- dnsapi/dns_ovh.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index de69bd91..60094739 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -78,7 +78,6 @@ _ovh_get_api() { esac } - _initAuth() { if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then OVH_AK="" @@ -181,7 +180,7 @@ dns_ovh_rm() { return 1 fi - for rid in $(echo "$response" | tr '[,]' ' '); do + for rid in $(echo "$response" | tr '][,' ' '); do _debug rid "$rid" if ! _ovh_rest GET "domain/zone/$_domain/record/$rid"; then return 1 From 60814ecfe10427238a8bcb39caa778ed520f0f7f Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 15 Jan 2018 19:48:57 +0800 Subject: [PATCH 1227/1348] typo --- acme.sh | 1 - dnsapi/dns_aws.sh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 4433e814..6c3f6e05 100755 --- a/acme.sh +++ b/acme.sh @@ -3474,7 +3474,6 @@ issue() { #make new order request _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" for d in $(echo "$_alt_domains" | tr ',' ' '); do - #todo: check wildcard ? if [ "$d" ]; then _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" fi diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 5a716514..8c1513d1 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -23,7 +23,7 @@ dns_aws_add() { AWS_ACCESS_KEY_ID="" AWS_SECRET_ACCESS_KEY="" _err "You don't specify aws route53 api key id and and api key secret yet." - _err "Please create you key and try again. see $(__green $AWS_WIKI)" + _err "Please create your key and try again. see $(__green $AWS_WIKI)" return 1 fi From 9e9f839d96053cae020aab3817cdb94d9622df18 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 15 Jan 2018 21:55:40 +0800 Subject: [PATCH 1228/1348] support only one wildcard domain. fix https://github.com/Neilpang/acme.sh/issues/1188#issuecomment-357684744 --- acme.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index 6c3f6e05..74b437cb 100755 --- a/acme.sh +++ b/acme.sh @@ -3340,10 +3340,6 @@ issue() { _main_domain="$2" _alt_domains="$3" - if _startswith "$_main_domain" "*."; then - _err "The first domain can not be wildcard, '$_main_domain' is a wildcard domain." - return 1 - fi if _contains "$_main_domain" ","; then _main_domain=$(echo "$2,$3" | cut -d , -f 1) _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") @@ -5539,13 +5535,13 @@ _process() { return 1 fi + if _startswith "$_dvalue" "*."; then + _debug "Wildcard domain" + export ACME_VERSION=2 + fi if [ -z "$_domain" ]; then _domain="$_dvalue" else - if _startswith "$_dvalue" "*."; then - _debug "Wildcard domain" - export ACME_VERSION=2 - fi if [ "$_altdomains" = "$NO_VALUE" ]; then _altdomains="$_dvalue" else From cd9fb3b63581a2f4dadca299c847b365528ea718 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 16 Jan 2018 20:55:07 +0800 Subject: [PATCH 1229/1348] fix https://github.com/Neilpang/acme.sh/issues/1189 --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 74b437cb..59a7d960 100755 --- a/acme.sh +++ b/acme.sh @@ -2259,6 +2259,8 @@ _initAPI() { #[domain] [keylength or isEcc flag] _initpath() { + domain="$1" + _ilength="$2" __initHome @@ -2346,13 +2348,10 @@ _initpath() { ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" fi - if [ -z "$1" ]; then + if [ -z "$domain" ]; then return 0 fi - domain="$1" - _ilength="$2" - if [ -z "$DOMAIN_PATH" ]; then domainhome="$CERT_HOME/$domain" domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" @@ -4234,8 +4233,6 @@ signcsr() { return 1 fi - _initpath - _csrsubj=$(_readSubjectFromCSR "$_csrfile") if [ "$?" != "0" ]; then _err "Can not read subject from csr: $_csrfile" @@ -4272,6 +4269,9 @@ signcsr() { return 1 fi + if [ -z "$ACME_VERSION" ] && _contains "$_csrsubj,$_csrdomainlist" "*."; then + export ACME_VERSION=2 + fi _initpath "$_csrsubj" "$_csrkeylength" mkdir -p "$DOMAIN_PATH" From 78d1cfb4648dcf6fbb5ae30074f95e6a517057c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20B=C3=B6hnke?= Date: Wed, 17 Jan 2018 19:21:14 +0100 Subject: [PATCH 1230/1348] fix bug in the --ca-bundle param of passing -f to _readlink When _readlink is called the -f param must not be passed. _readlink (with leading underscore) is a wrapper around readlink (without leading underscore). _readlink already passes -f to readlink, that's why it must not be passed to _readlink. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 472975a6..2d245518 100755 --- a/acme.sh +++ b/acme.sh @@ -5510,7 +5510,7 @@ _process() { HTTPS_INSECURE="1" ;; --ca-bundle) - _ca_bundle="$(_readlink -f "$2")" + _ca_bundle="$(_readlink "$2")" CA_BUNDLE="$_ca_bundle" shift ;; From 6ba4f8b54cbc5019ce0b4da537975d10d39c0251 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 18 Jan 2018 21:04:06 +0800 Subject: [PATCH 1231/1348] fix https://github.com/Neilpang/acme.sh/issues/1204 --- dnsapi/dns_aws.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 5a716514..450e42de 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -19,6 +19,8 @@ dns_aws_add() { fulldomain=$1 txtvalue=$2 + AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" + AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then AWS_ACCESS_KEY_ID="" AWS_SECRET_ACCESS_KEY="" @@ -27,10 +29,9 @@ dns_aws_add() { return 1 fi - if [ -z "$AWS_SESSION_TOKEN" ]; then - _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" - _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" - fi + #save for future use + _saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" + _saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -56,6 +57,8 @@ dns_aws_rm() { fulldomain=$1 txtvalue=$2 + AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" + AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" From 37f39c0870ce3f381a586f331ee5fe41cc3d89b3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 19 Jan 2018 22:41:42 +0800 Subject: [PATCH 1232/1348] minor --- acme.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 2d245518..bd460521 100755 --- a/acme.sh +++ b/acme.sh @@ -2548,10 +2548,7 @@ _setNginx() { _d="$1" _croot="$2" _thumbpt="$3" - if ! _exists "nginx"; then - _err "nginx command is not found." - return 1 - fi + FOUND_REAL_NGINX_CONF="" FOUND_REAL_NGINX_CONF_LN="" BACKUP_NGINX_CONF="" @@ -2561,6 +2558,10 @@ _setNginx() { if [ -z "$_start_f" ]; then _debug "find start conf from nginx command" if [ -z "$NGINX_CONF" ]; then + if ! _exists "nginx"; then + _err "nginx command is not found." + return 1 + fi NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")" _debug NGINX_CONF "$NGINX_CONF" NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)" @@ -2605,6 +2606,10 @@ _setNginx() { return 1 fi + if ! _exists "nginx"; then + _err "nginx command is not found." + return 1 + fi _info "Check the nginx conf before setting up." if ! _exec "nginx -t" >/dev/null; then _exec_err From 258cf20c92d3ea541283cf3eff0ecc0b07305ae7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 19 Jan 2018 22:48:06 +0800 Subject: [PATCH 1233/1348] minor --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 83ef4ea7..cf88462a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -666,7 +666,7 @@ And now you can issue certs with: acme.sh --issue --dns dns_namesilo --dnssleep 900 -d example.com -d www.example.com ``` -## 37. Use autoDNS (InternetX) +## 36. Use autoDNS (InternetX) [InternetX](https://www.internetx.com/) offers an [xml api](https://help.internetx.com/display/API/AutoDNS+XML-API) with your standard login credentials, set them like so: From 04a609b51f38f1db8792d57dbc0af0eadaf108fe Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 21 Jan 2018 20:20:54 +0800 Subject: [PATCH 1234/1348] fix https://github.com/Neilpang/acme.sh/issues/1209 --- acme.sh | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index bd460521..920f15fc 100755 --- a/acme.sh +++ b/acme.sh @@ -2702,7 +2702,7 @@ _isRealNginxConf() { for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do _debug _fln "$_fln" if [ "$_fln" ]; then - _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) + _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *" | grep -v server_name | _tail_n 1) _debug "_start" "$_start" _start_n=$(echo "$_start" | cut -d : -f 1) _start_nn=$(_math $_start_n + 1) @@ -2711,8 +2711,8 @@ _isRealNginxConf() { _left="$(sed -n "${_start_nn},99999p" "$2")" _debug2 _left "$_left" - if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" >/dev/null; then - _end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" | _head_n 1) + if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *" >/dev/null; then + _end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *" | _head_n 1) _debug "_end" "$_end" _end_n=$(echo "$_end" | cut -d : -f 1) _debug "_end_n" "$_end_n" @@ -2723,8 +2723,20 @@ _isRealNginxConf() { _debug "_seg_n" "$_seg_n" - if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] \ - || [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then + _skip_ssl=1 + for _listen_i in $(echo "$_seg_n" | grep "^ *listen" | tr -d " "); do + if [ "$_listen_i" ]; then + if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl[ |;]")" ]; then + _debug2 "$_listen_i is ssl" + else + _debug2 "$_listen_i is plain text" + _skip_ssl="" + break; + fi + fi + done + + if [ "$_skip_ssl" = "1" ]; then _debug "ssl on, skip" else FOUND_REAL_NGINX_CONF_LN=$_fln From c05eb0b1b2b859a1e20f82d0ee2593f6840f13a4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 23 Jan 2018 19:42:57 +0800 Subject: [PATCH 1235/1348] fx format --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 920f15fc..77ab439e 100755 --- a/acme.sh +++ b/acme.sh @@ -2731,8 +2731,8 @@ _isRealNginxConf() { else _debug2 "$_listen_i is plain text" _skip_ssl="" - break; - fi + break + fi fi done From 9134b6ea989fb0f390ecf680e62f867cae3063a9 Mon Sep 17 00:00:00 2001 From: Herve Couplet Date: Tue, 23 Jan 2018 17:53:40 +0100 Subject: [PATCH 1236/1348] if local-address is present, bind to that ip instead of 0.0.0.0 --- acme.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 77ab439e..c3cba1e7 100755 --- a/acme.sh +++ b/acme.sh @@ -1984,9 +1984,15 @@ _startserver() { _NC="$_NC -6" fi + SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork + + #Adding bind to local-address + if [ "$_local_address" ]; then + $SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${_local_address}" + fi + _debug "_NC" "$_NC" - #todo listen address - $_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK; echo ; echo $content; echo;" & + $_NC $SOCAT_OPTIONS SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK; echo ; echo $content; echo;" & serverproc="$!" } From e90f3b84c1a1694f7f5c13a3ebfabc2da246a78d Mon Sep 17 00:00:00 2001 From: martgras Date: Tue, 23 Jan 2018 18:24:08 +0100 Subject: [PATCH 1237/1348] Add support for Azure DNS Adding support for Azure DNS See https://docs.microsoft.com/en-us/azure/dns/ --- dnsapi/dns_azure.sh | 241 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 dnsapi/dns_azure.sh diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh new file mode 100644 index 00000000..40997740 --- /dev/null +++ b/dnsapi/dns_azure.sh @@ -0,0 +1,241 @@ +#!/usr/bin/env sh + + +######## Public functions ##################### + + # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +# +# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate +# +dns_azure_add() +{ + fulldomain=$1 + txtvalue=$2 + + AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" + AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" + AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" + AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" + + if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Subscription ID " + return 1 + fi + + if [ -z "$AZUREDNS_TENANTID" ] ; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify then Azure Tenant ID " + return 1 + fi + + if [ -z "$AZUREDNS_APPID" ] ; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure App ID" + return 1 + fi + + if [ -z "$AZUREDNS_CLIENTSECRET" ]; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Client Secret" + return 1 + fi + #save account details to account conf file. + _saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID" + _saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID" + _saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID" + _saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET" + + + accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") + + if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + acmeRecordURI="https://management.azure.com$(printf '%s' $_domain_id |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + _debug $acmeRecordURI + body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" + _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" + _debug $response +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +# +# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete +# +dns_azure_rm() +{ + fulldomain=$1 + txtvalue=$2 + + AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" + AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" + AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" + AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" + + if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Subscription ID " + return 1 + fi + + if [ -z "$AZUREDNS_TENANTID" ] ; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Tenant ID " + return 1 + fi + + if [ -z "$AZUREDNS_APPID" ] ;then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure App ID" + return 1 + fi + + if [ -z "$AZUREDNS_CLIENTSECRET" ]; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify Azure Client Secret" + return 1 + fi + + accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") + + if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + acmeRecordURI="https://management.azure.com$(printf '%s' $_domain_id |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + _debug $acmeRecordURI + body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" + _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" + _debug $response +} + +################### Private functions below ################################## + +_azure_rest() { + m=$1 + ep="$2" + data="$3" + accesstoken="$4" + + _debug "$ep" + + export _H1="authorization: Bearer $accesstoken" + export _H2="accept: application/json" + export _H3="Content-Type: application/json" + _H1="authorization: Bearer $accesstoken" + _H2="accept: application/json" + _H3="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _debug2 response "$response" + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + return 0 +} + +## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token +_azure_getaccess_token() { + TENANTID=$1 + clientID=$2 + clientSecret=$3 + + export _H1="accept: application/json" + export _H2="Content-Type: application/x-www-form-urlencoded" + export _H3="" + + body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" $clientID | _url_encode)&client_secret=$(printf "%s" $clientSecret| _url_encode)&grant_type=client_credentials" + _debug data "$body" + response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST" )" + accesstoken=$(printf "%s\n" "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + + if [ "$?" != "0" ]; then + _err "error $response" + return 1 + fi + printf $accesstoken + _debug2 response "$response" + return 0 +} + +_get_root() { + domain=$1 + subscriptionId=$2 + accesstoken=$3 + i=2 + p=1 + + ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list + ## returns up to 100 zones in one response therefore handling more results is not not implemented + ## (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 + + # Find matching domain name is Json response + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" + if [ -z "$h" ]; then + #not valid + _err "Invalid domain" + 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 [ "$_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 +} + From b6fc8398cf03a0c7c6b173f6f61704c09047c578 Mon Sep 17 00:00:00 2001 From: martgras Date: Tue, 23 Jan 2018 18:25:52 +0100 Subject: [PATCH 1238/1348] Usage instructions for Azure DNS --- dnsapi/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index cf88462a..76b0cdf4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -684,6 +684,25 @@ acme.sh --issue --dns dns_autodns -d example.com -d www.example.com The `AUTODNS_USER`, `AUTODNS_PASSWORD` and `AUTODNS_CONTEXT` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 37. Use Azure DNS + +You have to create a service principal first. See: https://github.com/Neilpang/acme.sh/wiki/How-to-use-AzureDns-API + +``` +export AZUREDNS_SUBSCRIPTIONID="12345678-9abc-def0-1234-567890abcdef" +export AZUREDNS_TENANTID="11111111-2222-3333-4444-555555555555" +export AZUREDNS_APPID="3b5033b5-7a66-43a5-b3b9-a36b9e7c25ed" +export AZUREDNS_CLIENTSECRET="1b0224ef-34d4-5af9-110f-77f527d561bd" +``` + +Then you can issue your certificates with: + +``` +acme.sh --issue --dns dns_azure -d example.com -d www.example.com +``` + +`AZUREDNS_SUBSCRIPTIONID`, `AZUREDNS_TENANTID`,`AZUREDNS_APPID` and `AZUREDNS_CLIENTSECRET` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. From c82cd90ed6f64a982acfc45ce94db518c7603cad Mon Sep 17 00:00:00 2001 From: martgras Date: Tue, 23 Jan 2018 18:46:59 +0100 Subject: [PATCH 1239/1348] Relative link to Azure DNS wiki page --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 76b0cdf4..1148ea7f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -686,7 +686,7 @@ The `AUTODNS_USER`, `AUTODNS_PASSWORD` and `AUTODNS_CONTEXT` settings will be sa ## 37. Use Azure DNS -You have to create a service principal first. See: https://github.com/Neilpang/acme.sh/wiki/How-to-use-AzureDns-API +You have to create a service principal first. See:[How to use Azure DNS](../../../wiki/How-to-use-Azure-DNS) ``` export AZUREDNS_SUBSCRIPTIONID="12345678-9abc-def0-1234-567890abcdef" From 3fdbbafcb5eb10a55f195c90d77f31a9aa342850 Mon Sep 17 00:00:00 2001 From: martgras Date: Wed, 24 Jan 2018 09:59:05 +0100 Subject: [PATCH 1240/1348] fix getroot with multiple dns zones --- dnsapi/dns_azure.sh | 96 ++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 40997740..583a37d8 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -1,56 +1,55 @@ #!/usr/bin/env sh - ######## Public functions ##################### - # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" # Used to add txt record # # Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate # -dns_azure_add() -{ +dns_azure_add() +{ fulldomain=$1 txtvalue=$2 - + AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" - + if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure Subscription ID " + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Subscription ID " return 1 fi if [ -z "$AZUREDNS_TENANTID" ] ; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify then Azure Tenant ID " + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify then Azure Tenant ID " return 1 fi if [ -z "$AZUREDNS_APPID" ] ; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure App ID" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure App ID" return 1 fi if [ -z "$AZUREDNS_CLIENTSECRET" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure Client Secret" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Client Secret" return 1 fi #save account details to account conf file. @@ -61,15 +60,15 @@ dns_azure_add() accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") - + if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then _err "invalid domain" return 1 fi _debug _domain_id "$_domain_id" _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - + _debug _domain "$_domain" + acmeRecordURI="https://management.azure.com$(printf '%s' $_domain_id |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" _debug $acmeRecordURI body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" @@ -82,62 +81,62 @@ dns_azure_add() # # Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete # -dns_azure_rm() -{ +dns_azure_rm() +{ fulldomain=$1 txtvalue=$2 - + AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" - + if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure Subscription ID " + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Subscription ID " return 1 fi if [ -z "$AZUREDNS_TENANTID" ] ; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure Tenant ID " + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Tenant ID " return 1 fi if [ -z "$AZUREDNS_APPID" ] ;then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure App ID" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure App ID" return 1 fi if [ -z "$AZUREDNS_CLIENTSECRET" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify Azure Client Secret" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify Azure Client Secret" return 1 fi accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") - + if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then _err "invalid domain" return 1 fi _debug _domain_id "$_domain_id" _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - + _debug _domain "$_domain" + acmeRecordURI="https://management.azure.com$(printf '%s' $_domain_id |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" _debug $acmeRecordURI body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" @@ -152,7 +151,7 @@ _azure_rest() { ep="$2" data="$3" accesstoken="$4" - + _debug "$ep" export _H1="authorization: Bearer $accesstoken" @@ -181,16 +180,16 @@ _azure_getaccess_token() { TENANTID=$1 clientID=$2 clientSecret=$3 - + export _H1="accept: application/json" export _H2="Content-Type: application/x-www-form-urlencoded" export _H3="" - + body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" $clientID | _url_encode)&client_secret=$(printf "%s" $clientSecret| _url_encode)&grant_type=client_credentials" _debug data "$body" response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST" )" accesstoken=$(printf "%s\n" "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") - + if [ "$?" != "0" ]; then _err "error $response" return 1 @@ -208,11 +207,11 @@ _get_root() { p=1 ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list - ## returns up to 100 zones in one response therefore handling more results is not not implemented + ## returns up to 100 zones in one response therefore handling more results is not not implemented ## (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 + ## 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?api-version=2017-09-01" "" $accesstoken # Find matching domain name is Json response while true; do @@ -225,7 +224,7 @@ _get_root() { 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 \") + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | 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 @@ -238,4 +237,3 @@ _get_root() { done return 1 } - From f7d4698ef038b245ad6163bf604d167ceb51eb8b Mon Sep 17 00:00:00 2001 From: martgras Date: Wed, 24 Jan 2018 13:39:38 +0100 Subject: [PATCH 1241/1348] improve error checking --- dnsapi/dns_azure.sh | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 583a37d8..24b13bba 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -73,7 +73,11 @@ dns_azure_add() _debug $acmeRecordURI body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" - _debug $response + if [ "$_code" = "200" ] || [ "$code" = '201' ]; then + _info "validation record added" + else + _err "error adding validation record ($_code)" + fi } # Usage: fulldomain txtvalue @@ -141,7 +145,11 @@ dns_azure_rm() _debug $acmeRecordURI body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" - _debug $response + if [ "$_code" = "200" ] || [ "$code" = '204' ]; then + _info "validation record removed" + else + _err "error removing validation record ($_code)" + fi } ################### Private functions below ################################## @@ -168,6 +176,10 @@ _azure_rest() { response="$(_get "$ep")" fi _debug2 response "$response" + + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug2 "http response code $_code" + if [ "$?" != "0" ]; then _err "error $ep" return 1 @@ -189,13 +201,18 @@ _azure_getaccess_token() { _debug data "$body" response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST" )" accesstoken=$(printf "%s\n" "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") - + _debug2 "response $response" + + if [ -Z "$accesstoken" ] ; then + _err "no acccess token received" + return 1 + fi if [ "$?" != "0" ]; then _err "error $response" return 1 fi printf $accesstoken - _debug2 response "$response" + return 0 } From d51c383866a7fb029479e99b28a86c1ff4b9d9aa Mon Sep 17 00:00:00 2001 From: martgras Date: Wed, 24 Jan 2018 15:08:06 +0100 Subject: [PATCH 1242/1348] remove unused code and fix error handling --- dnsapi/dns_azure.sh | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 24b13bba..1841b070 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -77,6 +77,7 @@ dns_azure_add() _info "validation record added" else _err "error adding validation record ($_code)" + return 1 fi } @@ -149,6 +150,7 @@ dns_azure_rm() _info "validation record removed" else _err "error removing validation record ($_code)" + return 1 fi } @@ -160,15 +162,11 @@ _azure_rest() { data="$3" accesstoken="$4" - _debug "$ep" - export _H1="authorization: Bearer $accesstoken" export _H2="accept: application/json" export _H3="Content-Type: application/json" - _H1="authorization: Bearer $accesstoken" - _H2="accept: application/json" - _H3="Content-Type: application/json" - + + _debug "$ep" if [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$ep" "" "$m")" @@ -195,7 +193,6 @@ _azure_getaccess_token() { export _H1="accept: application/json" export _H2="Content-Type: application/x-www-form-urlencoded" - export _H3="" body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" $clientID | _url_encode)&client_secret=$(printf "%s" $clientSecret| _url_encode)&grant_type=client_credentials" _debug data "$body" @@ -203,7 +200,7 @@ _azure_getaccess_token() { accesstoken=$(printf "%s\n" "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") _debug2 "response $response" - if [ -Z "$accesstoken" ] ; then + if [ -z "$accesstoken" ] ; then _err "no acccess token received" return 1 fi From c7b8debb6eb1e378b63b2df151fcadeae660adf2 Mon Sep 17 00:00:00 2001 From: martgras Date: Thu, 25 Jan 2018 07:01:39 +0100 Subject: [PATCH 1243/1348] fix travis issues --- dnsapi/dns_azure.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 1841b070..b7ebe546 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -69,11 +69,11 @@ dns_azure_add() _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - acmeRecordURI="https://management.azure.com$(printf '%s' $_domain_id |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" - _debug $acmeRecordURI + acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + _debug "$acmeRecordURI" body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" - if [ "$_code" = "200" ] || [ "$code" = '201' ]; then + if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then _info "validation record added" else _err "error adding validation record ($_code)" @@ -142,8 +142,8 @@ dns_azure_rm() _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - acmeRecordURI="https://management.azure.com$(printf '%s' $_domain_id |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" - _debug $acmeRecordURI + acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + _debug "$acmeRecordURI" body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" if [ "$_code" = "200" ] || [ "$code" = '204' ]; then @@ -194,7 +194,7 @@ _azure_getaccess_token() { export _H1="accept: application/json" export _H2="Content-Type: application/x-www-form-urlencoded" - body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" $clientID | _url_encode)&client_secret=$(printf "%s" $clientSecret| _url_encode)&grant_type=client_credentials" + body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret"| _url_encode)&grant_type=client_credentials" _debug data "$body" response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST" )" accesstoken=$(printf "%s\n" "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") @@ -208,7 +208,7 @@ _azure_getaccess_token() { _err "error $response" return 1 fi - printf $accesstoken + printf "$accesstoken" return 0 } @@ -225,7 +225,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?api-version=2017-09-01" "" "$accesstoken" # Find matching domain name is Json response while true; do From 00781dd4e1f0be3c9e83872ca9fc7a53bb0370bd Mon Sep 17 00:00:00 2001 From: martgras Date: Thu, 25 Jan 2018 07:06:42 +0100 Subject: [PATCH 1244/1348] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a2c210e8..8e1b22da 100644 --- a/README.md +++ b/README.md @@ -344,6 +344,7 @@ You don't have to do anything manually! 1. Servercow (https://servercow.de) 1. Namesilo (https://www.namesilo.com) 1. InternetX autoDNS API (https://internetx.com) +1. Azure DNS And: From 441c26dd3286bb326523e4d56ea5d303c2571a65 Mon Sep 17 00:00:00 2001 From: martgras Date: Thu, 25 Jan 2018 07:40:35 +0100 Subject: [PATCH 1245/1348] Update dns_azure.sh --- dnsapi/dns_azure.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index b7ebe546..3c7e4de9 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -146,7 +146,7 @@ dns_azure_rm() _debug "$acmeRecordURI" body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" - if [ "$_code" = "200" ] || [ "$code" = '204' ]; then + if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then _info "validation record removed" else _err "error removing validation record ($_code)" @@ -208,7 +208,7 @@ _azure_getaccess_token() { _err "error $response" return 1 fi - printf "$accesstoken" + printf "%s" "$accesstoken" return 0 } From d1067c60bf93011eb74695ab34fc9cce52fdd0b1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 25 Jan 2018 21:08:20 +0800 Subject: [PATCH 1246/1348] fix https://github.com/Neilpang/acme.sh/issues/1193#issuecomment-360025170 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 77ab439e..48297c7d 100755 --- a/acme.sh +++ b/acme.sh @@ -2724,7 +2724,7 @@ _isRealNginxConf() { _debug "_seg_n" "$_seg_n" _skip_ssl=1 - for _listen_i in $(echo "$_seg_n" | grep "^ *listen" | tr -d " "); do + 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 _debug2 "$_listen_i is ssl" From 91607bb2a1e207fa693d3c09dfafee15dd8a912e Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Jan 2018 22:58:11 +0800 Subject: [PATCH 1247/1348] Update dns_azure.sh --- dnsapi/dns_azure.sh | 406 ++++++++++++++++++++++---------------------- 1 file changed, 201 insertions(+), 205 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 3c7e4de9..104a81a6 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -7,78 +7,76 @@ # # Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate # -dns_azure_add() -{ - fulldomain=$1 - txtvalue=$2 - - AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" - AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" - AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" - AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" - - if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then - AZUREDNS_SUBSCRIPTIONID="" - AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure Subscription ID " - return 1 - fi +dns_azure_add() { + fulldomain=$1 + txtvalue=$2 + + AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" + AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" + AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" + AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" + + if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Subscription ID " + return 1 + fi - if [ -z "$AZUREDNS_TENANTID" ] ; then - AZUREDNS_SUBSCRIPTIONID="" - AZUREDNS_TENANTID="" - AZUREDNS_APPID="" + if [ -z "$AZUREDNS_TENANTID" ] ; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" AZUREDNS_CLIENTSECRET="" _err "You didn't specify then Azure Tenant ID " return 1 - fi - - if [ -z "$AZUREDNS_APPID" ] ; then - AZUREDNS_SUBSCRIPTIONID="" - AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure App ID" - return 1 - fi - - if [ -z "$AZUREDNS_CLIENTSECRET" ]; then - AZUREDNS_SUBSCRIPTIONID="" - AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure Client Secret" - return 1 - fi - #save account details to account conf file. - _saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID" - _saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID" - _saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID" - _saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET" - + fi + + if [ -z "$AZUREDNS_APPID" ] ; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure App ID" + return 1 + fi + + if [ -z "$AZUREDNS_CLIENTSECRET" ]; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Client Secret" + return 1 + fi + #save account details to account conf file. + _saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID" + _saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID" + _saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID" + _saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET" - accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") + accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") - if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then - _err "invalid domain" + if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + _debug "$acmeRecordURI" + body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" + _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" + if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then + _info "validation record added" + else + _err "error adding validation record ($_code)" return 1 - fi - _debug _domain_id "$_domain_id" - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - - acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" - _debug "$acmeRecordURI" - body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" - _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" - if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then - _info "validation record added" - else - _err "error adding validation record ($_code)" - return 1 - fi + fi } # Usage: fulldomain txtvalue @@ -86,156 +84,154 @@ dns_azure_add() # # Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/delete # -dns_azure_rm() -{ - fulldomain=$1 - txtvalue=$2 - - AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" - AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" - AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" - AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" - - if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then - AZUREDNS_SUBSCRIPTIONID="" - AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure Subscription ID " - return 1 - fi - - if [ -z "$AZUREDNS_TENANTID" ] ; then - AZUREDNS_SUBSCRIPTIONID="" - AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure Tenant ID " - return 1 - fi - - if [ -z "$AZUREDNS_APPID" ] ;then - AZUREDNS_SUBSCRIPTIONID="" - AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify the Azure App ID" - return 1 - fi - - if [ -z "$AZUREDNS_CLIENTSECRET" ]; then - AZUREDNS_SUBSCRIPTIONID="" - AZUREDNS_TENANTID="" - AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify Azure Client Secret" - return 1 - fi +dns_azure_rm() { + fulldomain=$1 + txtvalue=$2 + + AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}" + AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" + AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" + AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" + + if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Subscription ID " + return 1 + fi + + if [ -z "$AZUREDNS_TENANTID" ] ; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure Tenant ID " + return 1 + fi + + if [ -z "$AZUREDNS_APPID" ] ;then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify the Azure App ID" + return 1 + fi + + if [ -z "$AZUREDNS_CLIENTSECRET" ]; then + AZUREDNS_SUBSCRIPTIONID="" + AZUREDNS_TENANTID="" + AZUREDNS_APPID="" + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify Azure Client Secret" + return 1 + fi - accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") + accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") - if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then - _err "invalid domain" + if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + _debug "$acmeRecordURI" + body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" + _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" + if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then + _info "validation record removed" + else + _err "error removing validation record ($_code)" return 1 - fi - _debug _domain_id "$_domain_id" - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - - acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" - _debug "$acmeRecordURI" - body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" - _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" - if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then - _info "validation record removed" - else - _err "error removing validation record ($_code)" - return 1 - fi + fi } ################### Private functions below ################################## _azure_rest() { - m=$1 - ep="$2" - data="$3" - accesstoken="$4" - - export _H1="authorization: Bearer $accesstoken" - export _H2="accept: application/json" - export _H3="Content-Type: application/json" - - _debug "$ep" - if [ "$m" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$ep" "" "$m")" - else - response="$(_get "$ep")" - fi - _debug2 response "$response" - - _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" - _debug2 "http response code $_code" - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - return 0 + m=$1 + ep="$2" + data="$3" + accesstoken="$4" + + export _H1="authorization: Bearer $accesstoken" + export _H2="accept: application/json" + export _H3="Content-Type: application/json" + + _debug "$ep" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _debug2 response "$response" + + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug2 "http response code $_code" + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + return 0 } ## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token _azure_getaccess_token() { - TENANTID=$1 - clientID=$2 - clientSecret=$3 - - export _H1="accept: application/json" - export _H2="Content-Type: application/x-www-form-urlencoded" - - body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret"| _url_encode)&grant_type=client_credentials" - _debug data "$body" - response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST" )" - accesstoken=$(printf "%s\n" "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") - _debug2 "response $response" - - if [ -z "$accesstoken" ] ; then - _err "no acccess token received" - return 1 - fi - if [ "$?" != "0" ]; then - _err "error $response" - return 1 - fi - printf "%s" "$accesstoken" - - return 0 + TENANTID=$1 + clientID=$2 + clientSecret=$3 + + export _H1="accept: application/json" + export _H2="Content-Type: application/x-www-form-urlencoded" + + body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret"| _url_encode)&grant_type=client_credentials" + _debug data "$body" + response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST" )" + accesstoken=$(printf "%s\n" "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + _debug2 "response $response" + + if [ -z "$accesstoken" ] ; then + _err "no acccess token received" + return 1 + fi + if [ "$?" != "0" ]; then + _err "error $response" + return 1 + fi + printf "%s" "$accesstoken" + return 0 } _get_root() { - domain=$1 - subscriptionId=$2 - accesstoken=$3 - i=2 - p=1 - - ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list - ## returns up to 100 zones in one response therefore handling more results is not not implemented - ## (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" - - # Find matching domain name is Json response - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - _debug2 "Checking domain: $h" - if [ -z "$h" ]; then - #not valid - _err "Invalid domain" - return 1 - fi + domain=$1 + subscriptionId=$2 + accesstoken=$3 + i=2 + p=1 + + ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list + ## returns up to 100 zones in one response therefore handling more results is not not implemented + ## (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" + + # Find matching domain name is Json response + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" + if [ -z "$h" ]; then + #not valid + _err "Invalid domain" + return 1 + fi if _contains "$response" "\"name\":\"$h\"" >/dev/null; then _domain_id=$(printf "%s\n" "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \") @@ -245,9 +241,9 @@ _get_root() { return 0 fi return 1 - fi - p=$i - i=$(_math "$i" + 1) - done - return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 } From e4b24d20acb68b741422d3e078fbf572d1d86f36 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 25 Jan 2018 23:08:56 +0800 Subject: [PATCH 1248/1348] Update dns_azure.sh --- dnsapi/dns_azure.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 104a81a6..9952a16e 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -29,9 +29,9 @@ dns_azure_add() { AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" AZUREDNS_APPID="" - AZUREDNS_CLIENTSECRET="" - _err "You didn't specify then Azure Tenant ID " - return 1 + AZUREDNS_CLIENTSECRET="" + _err "You didn't specify then Azure Tenant ID " + return 1 fi if [ -z "$AZUREDNS_APPID" ] ; then @@ -194,7 +194,7 @@ _azure_getaccess_token() { body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret"| _url_encode)&grant_type=client_credentials" _debug data "$body" response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST" )" - accesstoken=$(printf "%s\n" "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") _debug2 "response $response" if [ -z "$accesstoken" ] ; then @@ -234,7 +234,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \") + _domain_id=$(echo "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | 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 From a4fc802d1b84c49c3357aa2765dead14ec4320e7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 25 Jan 2018 23:18:37 +0800 Subject: [PATCH 1249/1348] Add selectel.com(selectel.ru) DNS API. fix https://github.com/Neilpang/acme.sh/issues/1220 --- README.md | 1 + dnsapi/README.md | 17 +++++ dnsapi/dns_selectel.sh | 161 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 dnsapi/dns_selectel.sh diff --git a/README.md b/README.md index 8e1b22da..ad3befcd 100644 --- a/README.md +++ b/README.md @@ -345,6 +345,7 @@ You don't have to do anything manually! 1. Namesilo (https://www.namesilo.com) 1. InternetX autoDNS API (https://internetx.com) 1. Azure DNS +1. selectel.com(selectel.ru) DNS API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 1148ea7f..32eca131 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -703,6 +703,23 @@ acme.sh --issue --dns dns_azure -d example.com -d www.example.com `AZUREDNS_SUBSCRIPTIONID`, `AZUREDNS_TENANTID`,`AZUREDNS_APPID` and `AZUREDNS_CLIENTSECRET` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 38. Use selectel.com(selectel.ru) domain API to automatically issue cert + +First you need to login to your account to get your API key from: https://my.selectel.ru/profile/apikeys. + +```sh +export SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" + +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_selectel -d example.com -d www.example.com +``` + +The `SL_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_selectel.sh b/dnsapi/dns_selectel.sh new file mode 100644 index 00000000..8dd9b352 --- /dev/null +++ b/dnsapi/dns_selectel.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env sh + +# +#SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# + +SL_Api="https://api.selectel.ru/domains/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_selectel_add() { + fulldomain=$1 + txtvalue=$2 + + SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}" + + if [ -z "$SL_Key" ]; then + SL_Key="" + _err "You don't specify selectel.ru api key yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key to the account conf file. + _saveaccountconf_mutable SL_Key "$SL_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" + + _info "Adding record" + if _sl_rest POST "/$_domain_id/records/" "{\"type\": \"TXT\", \"ttl\": 60, \"name\": \"$fulldomain\", \"content\": \"$txtvalue\"}"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + fi + fi + _err "Add txt record error." + return 1 +} + +#fulldomain txtvalue +dns_selectel_rm() { + fulldomain=$1 + txtvalue=$2 + + SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}" + + if [ -z "$SL_Key" ]; then + SL_Key="" + _err "You don't specify slectel api key yet." + _err "Please create you key and try again." + return 1 + fi + + _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" + _sl_rest GET "/${_domain_id}/records/" + + if ! _contains "$response" "$txtvalue"; then + _err "Txt record not found" + return 1 + fi + + _record_seg="$(echo "$response" | _egrep_o "\"content\" *: *\"$txtvalue\"[^}]*}")" + _debug2 "_record_seg" "$_record_seg" + if [ -z "$_record_seg" ]; then + _err "can not find _record_seg" + return 1 + fi + + _record_id="$(echo "$_record_seg" | tr ",}" "\n\n" | tr -d " " | grep "\"id\"" | cut -d : -f 2)" + _debug2 "_record_id" "$_record_id" + if [ -z "$_record_id" ]; then + _err "can not find _record_id" + return 1 + fi + + if ! _sl_rest DELETE "/$_domain_id/records/$_record_id"; then + _err "Delete record error." + return 1 + fi + return 0; +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + + if ! _sl_rest GET "/"; then + return 1 + fi + + 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\","; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + _debug "Getting domain id for $h" + if ! _sl_rest GET "/$h"; then + return 1 + fi + _domain_id="$(echo "$response" | tr ",}" "\n\n" | tr -d " " | grep "\"id\":" | cut -d : -f 2)" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_sl_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="X-Token: $SL_Key" + export _H2="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$SL_Api/$ep" "" "$m")" + else + response="$(_get "$SL_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 03140865f031dfe2d9ee9bb3c3017b23d52f8971 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 25 Jan 2018 23:25:50 +0800 Subject: [PATCH 1250/1348] fix for existing record --- dnsapi/dns_selectel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_selectel.sh b/dnsapi/dns_selectel.sh index 8dd9b352..c5e40788 100644 --- a/dnsapi/dns_selectel.sh +++ b/dnsapi/dns_selectel.sh @@ -36,7 +36,7 @@ dns_selectel_add() { _info "Adding record" if _sl_rest POST "/$_domain_id/records/" "{\"type\": \"TXT\", \"ttl\": 60, \"name\": \"$fulldomain\", \"content\": \"$txtvalue\"}"; then - if _contains "$response" "$txtvalue"; then + if _contains "$response" "$txtvalue" || _contains "$response" "record_already_exists"; then _info "Added, OK" return 0 fi From 72fe7396d6d2779b03b40ec0d7c76fc137423f12 Mon Sep 17 00:00:00 2001 From: martgras Date: Fri, 26 Jan 2018 07:53:47 +0100 Subject: [PATCH 1251/1348] spelling mistake in error message --- dnsapi/dns_azure.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 9952a16e..6e53131f 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -30,7 +30,7 @@ dns_azure_add() { AZUREDNS_TENANTID="" AZUREDNS_APPID="" AZUREDNS_CLIENTSECRET="" - _err "You didn't specify then Azure Tenant ID " + _err "You didn't specify the Azure Tenant ID " return 1 fi @@ -125,7 +125,7 @@ dns_azure_rm() { AZUREDNS_TENANTID="" AZUREDNS_APPID="" AZUREDNS_CLIENTSECRET="" - _err "You didn't specify Azure Client Secret" + _err "You didn't specify the Azure Client Secret" return 1 fi From dd171ca44a2ed193c5dd9e21c1aedc6cfe251fde Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 26 Jan 2018 20:14:51 +0800 Subject: [PATCH 1252/1348] fix format --- dnsapi/dns_azure.sh | 48 +++++++++++++++++++++--------------------- dnsapi/dns_selectel.sh | 4 ++-- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 6e53131f..2c39a00c 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -15,7 +15,7 @@ dns_azure_add() { AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}" AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}" AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}" - + if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" @@ -25,7 +25,7 @@ dns_azure_add() { return 1 fi - if [ -z "$AZUREDNS_TENANTID" ] ; then + if [ -z "$AZUREDNS_TENANTID" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" AZUREDNS_APPID="" @@ -34,7 +34,7 @@ dns_azure_add() { return 1 fi - if [ -z "$AZUREDNS_APPID" ] ; then + if [ -z "$AZUREDNS_APPID" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" AZUREDNS_APPID="" @@ -59,15 +59,15 @@ dns_azure_add() { accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") - if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then - _err "invalid domain" - return 1 + if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then + _err "invalid domain" + return 1 fi _debug _domain_id "$_domain_id" _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" _debug "$acmeRecordURI" body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" @@ -76,7 +76,7 @@ dns_azure_add() { else _err "error adding validation record ($_code)" return 1 - fi + fi } # Usage: fulldomain txtvalue @@ -102,7 +102,7 @@ dns_azure_rm() { return 1 fi - if [ -z "$AZUREDNS_TENANTID" ] ; then + if [ -z "$AZUREDNS_TENANTID" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" AZUREDNS_APPID="" @@ -111,7 +111,7 @@ dns_azure_rm() { return 1 fi - if [ -z "$AZUREDNS_APPID" ] ;then + if [ -z "$AZUREDNS_APPID" ];then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" AZUREDNS_APPID="" @@ -131,15 +131,15 @@ dns_azure_rm() { accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET") - if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then - _err "invalid domain" - return 1 + if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then + _err "invalid domain" + return 1 fi _debug _domain_id "$_domain_id" _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" |sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" + acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" _debug "$acmeRecordURI" body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" @@ -165,10 +165,10 @@ _azure_rest() { _debug "$ep" if [ "$m" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$ep" "" "$m")" + _debug data "$data" + response="$(_post "$data" "$ep" "" "$m")" else - response="$(_get "$ep")" + response="$(_get "$ep")" fi _debug2 response "$response" @@ -176,8 +176,8 @@ _azure_rest() { _debug2 "http response code $_code" if [ "$?" != "0" ]; then - _err "error $ep" - return 1 + _err "error $ep" + return 1 fi return 0 } @@ -191,15 +191,15 @@ _azure_getaccess_token() { export _H1="accept: application/json" export _H2="Content-Type: application/x-www-form-urlencoded" - body="resource=$(printf "%s" 'https://management.core.windows.net/'| _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret"| _url_encode)&grant_type=client_credentials" + body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials" _debug data "$body" - response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST" )" - accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST")" + accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") _debug2 "response $response" - if [ -z "$accesstoken" ] ; then + if [ -z "$accesstoken" ]; then _err "no acccess token received" - return 1 + return 1 fi if [ "$?" != "0" ]; then _err "error $response" diff --git a/dnsapi/dns_selectel.sh b/dnsapi/dns_selectel.sh index c5e40788..460f89c3 100644 --- a/dnsapi/dns_selectel.sh +++ b/dnsapi/dns_selectel.sh @@ -42,7 +42,7 @@ dns_selectel_add() { fi fi _err "Add txt record error." - return 1 + return 1 } #fulldomain txtvalue @@ -94,7 +94,7 @@ dns_selectel_rm() { _err "Delete record error." return 1 fi - return 0; + return 0 } #################### Private functions below ################################## From 8c88757451b2ca2bb61814180442b4606555fe16 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 26 Jan 2018 20:39:41 +0800 Subject: [PATCH 1253/1348] fix format --- dnsapi/dns_azure.sh | 8 ++++---- dnsapi/dns_selectel.sh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 2c39a00c..0834ede7 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -111,7 +111,7 @@ dns_azure_rm() { return 1 fi - if [ -z "$AZUREDNS_APPID" ];then + if [ -z "$AZUREDNS_APPID" ]; then AZUREDNS_SUBSCRIPTIONID="" AZUREDNS_TENANTID="" AZUREDNS_APPID="" @@ -162,7 +162,7 @@ _azure_rest() { export _H1="authorization: Bearer $accesstoken" export _H2="accept: application/json" export _H3="Content-Type: application/json" - + _debug "$ep" if [ "$m" != "GET" ]; then _debug data "$data" @@ -173,7 +173,7 @@ _azure_rest() { _debug2 response "$response" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" - _debug2 "http response code $_code" + _debug2 "http response code $_code" if [ "$?" != "0" ]; then _err "error $ep" @@ -197,7 +197,7 @@ _azure_getaccess_token() { accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") _debug2 "response $response" - if [ -z "$accesstoken" ]; then + if [ -z "$accesstoken" ]; then _err "no acccess token received" return 1 fi diff --git a/dnsapi/dns_selectel.sh b/dnsapi/dns_selectel.sh index 460f89c3..94252d81 100644 --- a/dnsapi/dns_selectel.sh +++ b/dnsapi/dns_selectel.sh @@ -83,7 +83,7 @@ dns_selectel_rm() { return 1 fi - _record_id="$(echo "$_record_seg" | tr ",}" "\n\n" | tr -d " " | grep "\"id\"" | cut -d : -f 2)" + _record_id="$(echo "$_record_seg" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\"" | cut -d : -f 2)" _debug2 "_record_id" "$_record_id" if [ -z "$_record_id" ]; then _err "can not find _record_id" @@ -127,7 +127,7 @@ _get_root() { if ! _sl_rest GET "/$h"; then return 1 fi - _domain_id="$(echo "$response" | tr ",}" "\n\n" | tr -d " " | grep "\"id\":" | cut -d : -f 2)" + _domain_id="$(echo "$response" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\":" | cut -d : -f 2)" return 0 fi p=$i From 1c35f46b457fa65612ed7eaa7a9236d6f1f0c3c9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 26 Jan 2018 21:37:30 +0800 Subject: [PATCH 1254/1348] fix https://github.com/Neilpang/acme.sh/issues/1212 --- acme.sh | 82 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/acme.sh b/acme.sh index 9bdb66aa..f64955d3 100755 --- a/acme.sh +++ b/acme.sh @@ -3969,6 +3969,16 @@ $_authorizations_map" _on_issue_err "$_post_hook" return 1 fi + + if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then + _debug "Found cert chain" + cat "$CERT_PATH" > "$CERT_FULLCHAIN_PATH" + _end_n="$(grep -n -- "$END_CERT" "$CERT_FULLCHAIN_PATH" | _head_n 1 | cut -d : -f 1)" + _debug _end_n "$_end_n" + sed -n "1,${_end_n}p" "$CERT_FULLCHAIN_PATH" > "$CERT_PATH" + _end_n="$(_math $_end_n + 1)" + sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" > "$CA_CERT_PATH" + fi else if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." @@ -4022,47 +4032,49 @@ $_authorizations_map" _cleardomainconf "Le_Vlist" - Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') - - if [ "$Le_LinkIssuer" ]; then - if ! _contains "$Le_LinkIssuer" ":"; then - _info "$(__red "Relative issuer link found.")" - Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" - fi - _debug Le_LinkIssuer "$Le_LinkIssuer" - _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" - - _link_issuer_retry=0 - _MAX_ISSUER_RETRY=5 - while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do - _debug _link_issuer_retry "$_link_issuer_retry" - if [ "$ACME_VERSION" = "2" ]; then - if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then - break - fi - else - if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then - echo "$BEGIN_CERT" >"$CA_CERT_PATH" - _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" - echo "$END_CERT" >>"$CA_CERT_PATH" + if [ "$ACME_VERSION" = "2" ]; then + _debug "v2 chain." + else + Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') - _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 ")" + if [ "$Le_LinkIssuer" ]; then + if ! _contains "$Le_LinkIssuer" ":"; then + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" + fi + _debug Le_LinkIssuer "$Le_LinkIssuer" + _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" - rm -f "$CA_CERT_PATH.der" - break + _link_issuer_retry=0 + _MAX_ISSUER_RETRY=5 + while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do + _debug _link_issuer_retry "$_link_issuer_retry" + if [ "$ACME_VERSION" = "2" ]; then + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then + break + fi + else + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then + echo "$BEGIN_CERT" >"$CA_CERT_PATH" + _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" + echo "$END_CERT" >>"$CA_CERT_PATH" + cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" + rm -f "$CA_CERT_PATH.der" + break + fi fi + _link_issuer_retry=$(_math $_link_issuer_retry + 1) + _sleep "$_link_issuer_retry" + done + if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then + _err "Max retry for issuer ca cert is reached." fi - _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." + else + _debug "No Le_LinkIssuer header found." fi - else - _debug "No Le_LinkIssuer header found." fi + [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" + [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" Le_CertCreateTime=$(_time) _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" From 120cde169bd5c3b815994b6190ea830b3bdb7d70 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 27 Jan 2018 17:20:38 +0800 Subject: [PATCH 1255/1348] fix format --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index f64955d3..2438fd10 100755 --- a/acme.sh +++ b/acme.sh @@ -3972,12 +3972,12 @@ $_authorizations_map" if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then _debug "Found cert chain" - cat "$CERT_PATH" > "$CERT_FULLCHAIN_PATH" + cat "$CERT_PATH" >"$CERT_FULLCHAIN_PATH" _end_n="$(grep -n -- "$END_CERT" "$CERT_FULLCHAIN_PATH" | _head_n 1 | cut -d : -f 1)" _debug _end_n "$_end_n" - sed -n "1,${_end_n}p" "$CERT_FULLCHAIN_PATH" > "$CERT_PATH" + sed -n "1,${_end_n}p" "$CERT_FULLCHAIN_PATH" >"$CERT_PATH" _end_n="$(_math $_end_n + 1)" - sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" > "$CA_CERT_PATH" + sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" >"$CA_CERT_PATH" fi else if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then From a4964b90730621e0f6f0b8f4bdc4266b6a9383ff Mon Sep 17 00:00:00 2001 From: Felix Wolfsteller Date: Thu, 1 Feb 2018 18:06:26 +0100 Subject: [PATCH 1256/1348] Add Readme-section about cert removal (#1137) --- README.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ad3befcd..9b42fc76 100644 --- a/README.md +++ b/README.md @@ -409,7 +409,18 @@ acme.sh --renew -d example.com --force --ecc ``` -# 12. How to upgrade `acme.sh` +# 12. How to stop cert renewal + +To stop renewal of a cert, you can execute: + +``` +acme.sh --remove -d example.com [--ecc] +``` + +or remove the respective directory (e.g. `~/.acme.sh/example.com`). + + +# 13. How to upgrade `acme.sh` acme.sh is in constant development, so it's strongly recommended to use the latest code. @@ -434,26 +445,26 @@ acme.sh --upgrade --auto-upgrade 0 ``` -# 13. Issue a cert from an existing CSR +# 14. Issue a cert from an existing CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR -# 14. Under the Hood +# 15. Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". TODO: -# 15. Acknowledgments +# 16. Acknowledgments 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme 3. Certbot: https://github.com/certbot/certbot -# 16. License & Others +# 17. License & Others License is GPLv3 @@ -462,7 +473,7 @@ Please Star and Fork me. [Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome. -# 17. Donate +# 18. Donate Your donation makes **acme.sh** better: 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) From 47b49f1be93db798529ab6275aa77645a4fc7c86 Mon Sep 17 00:00:00 2001 From: Felix Wolfsteller Date: Thu, 1 Feb 2018 18:07:29 +0100 Subject: [PATCH 1257/1348] Slightly improved --help output, fixes #1137 . --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 48297c7d..dbcc872f 100755 --- a/acme.sh +++ b/acme.sh @@ -5017,7 +5017,7 @@ Commands: --renew, -r Renew a cert. --renew-all Renew all the certs. --revoke Revoke a cert. - --remove Remove the cert from $PROJECT + --remove Remove the cert from list of certs known to $PROJECT_NAME. --list List all the certs. --showcsr Show the content of a csr. --install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. From a51f109930f34ecdbdc306d30e6ae05d7460bd7d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Feb 2018 20:28:50 +0800 Subject: [PATCH 1258/1348] fix https://github.com/Neilpang/acme.sh/issues/1234 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 522d9c53..4b80c120 100755 --- a/acme.sh +++ b/acme.sh @@ -5152,7 +5152,7 @@ install() { #Modify shebang if _exists bash; then _info "Good, bash is found, so change the shebang to use bash as preferred." - _shebang='#!'"$(env bash -c "command -v bash")" + _shebang='#!'"$(bash -c "command -v bash")" _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" for subf in $_SUB_FOLDERS; do if [ -d "$LE_WORKING_DIR/$subf" ]; then From e27dfbb0bbafa277dd766f8bc2dcb527ffb5e369 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Feb 2018 21:19:48 +0800 Subject: [PATCH 1259/1348] update doc --- README.md | 135 +++++++++++++++++++++++++++++------------------------- 1 file changed, 73 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 9ef1352f..c66b7f6c 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ Ok, you are ready to issue certs now. Show help message: -``` +```sh root@v1:~# acme.sh -h ``` @@ -166,16 +166,16 @@ You must have at least one domain there. You must point and bind all the domains to the same webroot dir: `/home/wwwroot/example.com`. -Generated/issued certs will be placed in `~/.acme.sh/example.com/` +The certs will be placed in `~/.acme.sh/example.com/` -The issued cert will be renewed automatically every **60** days. +The certs will be renewed automatically every **60** days. More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# 3. Install the issued cert to Apache/Nginx etc. +# 3. Install the cert to Apache/Nginx etc. -After you issue a cert, you probably want to install/copy the cert to your Apache/Nginx or other servers. +After the cert is generated, you probably want to install/copy the cert to your Apache/Nginx or other servers. You **MUST** use this command to copy the certs to the target files, **DO NOT** use the certs files in **~/.acme.sh/** folder, they are for internal use only, the folder structure may change in the future. **Apache** example: @@ -197,9 +197,9 @@ acme.sh --install-cert -d example.com \ Only the domain is required, all the other parameters are optional. -The ownership and permission info of existing files are preserved. You may want to precreate the files to have defined ownership and permission. +The ownership and permission info of existing files are preserved. You can pre-create the files to define the ownership and permission. -Install/copy the issued cert/key to the production Apache or Nginx path. +Install/copy the cert/key to the production Apache or Nginx path. The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`. @@ -242,7 +242,7 @@ Particularly, if you are running an Apache server, you should use Apache mode in Just set string "apache" as the second argument and it will force use of apache plugin automatically. -``` +```sh acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com ``` @@ -262,47 +262,13 @@ It will configure nginx server automatically to verify the domain and then resto So, the config is not changed. -``` +```sh acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com ``` More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert -# 8. Use DNS mode: - -Support the `dns-01` challenge. - -```bash -acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com -``` - -You should get an output like below: - -``` -Add the following txt record: -Domain:_acme-challenge.example.com -Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c - -Add the following txt record: -Domain:_acme-challenge.www.example.com -Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - -Please add those txt records to the domains. Waiting for the dns to take effect. -``` - -Then just rerun with `renew` argument: - -```bash -acme.sh --renew -d example.com -``` - -Ok, it's finished. - -**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.** - -**Please use dns api mode instead.** - -# 9. Automatic DNS API integration +# 8. Automatic DNS API integration If your DNS provider supports API access, we can use that API to automatically issue the certs. @@ -362,6 +328,39 @@ If your DNS provider is not on the supported list above, you can write your own For more details: [How to use DNS API](dnsapi) +# 9. Use DNS manual mode: + +If your dns provider doesn't support any api access, you will have to add the txt record by your hand. + +```bash +acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com +``` + +You should get an output like below: + +```sh +Add the following txt record: +Domain:_acme-challenge.example.com +Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c + +Add the following txt record: +Domain:_acme-challenge.www.example.com +Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +Please add those txt records to the domains. Waiting for the dns to take effect. +``` + +Then just rerun with `renew` argument: + +```bash +acme.sh --renew -d example.com +``` + +Ok, it's done. + +**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.** + +**Please use dns api mode instead.** # 10. Issue ECC certificates @@ -394,47 +393,60 @@ Valid values are: 3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)** -# 11. How to renew the issued certs -No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. +# 11. Issue Wildcard certificates -However, you can also force to renew any cert: +It's simple, just give a wildcard domain as the `-d` parameter. +```sh +acme.sh --issue -d example.com -d *.example.com --dns dns_cf ``` + + + +# 12. How to renew the certs + +No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. + +However, you can also force to renew a cert: + +```sh acme.sh --renew -d example.com --force ``` or, for ECC cert: -``` +```sh acme.sh --renew -d example.com --force --ecc ``` -# 12. How to stop cert renewal +# 13. How to stop cert renewal -To stop renewal of a cert, you can execute: +To stop renewal of a cert, you can execute the following to remove the cert from the renewal list: -``` +```sh acme.sh --remove -d example.com [--ecc] ``` -or remove the respective directory (e.g. `~/.acme.sh/example.com`). +The cert/key file is not removed from the disk. +You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself. -# 13. How to upgrade `acme.sh` + +# 14. How to upgrade `acme.sh` acme.sh is in constant development, so it's strongly recommended to use the latest code. You can update acme.sh to the latest code: -``` +```sh acme.sh --upgrade ``` You can also enable auto upgrade: -``` +```sh acme.sh --upgrade --auto-upgrade ``` @@ -442,31 +454,30 @@ Then **acme.sh** will be kept up to date automatically. Disable auto upgrade: -``` +```sh acme.sh --upgrade --auto-upgrade 0 ``` -# 14. Issue a cert from an existing CSR +# 15. Issue a cert from an existing CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR -# 15. Under the Hood +# 16. Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". TODO: -# 16. Acknowledgments +# 17. Acknowledgments 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme -3. Certbot: https://github.com/certbot/certbot -# 17. License & Others +# 18. License & Others License is GPLv3 @@ -475,7 +486,7 @@ Please Star and Fork me. [Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome. -# 18. Donate +# 19. Donate Your donation makes **acme.sh** better: 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) From 7df20e5049e5e6d48ee5ae359d898876cef5dfb5 Mon Sep 17 00:00:00 2001 From: jim-p Date: Mon, 5 Feb 2018 16:37:57 -0500 Subject: [PATCH 1260/1348] When registering, consider a 200 final response code as an account that already exists. Fixes #1242 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4b80c120..266a2ccc 100755 --- a/acme.sh +++ b/acme.sh @@ -3170,7 +3170,7 @@ _regAccount() { if [ "$code" = "" ] || [ "$code" = '201' ]; then echo "$response" >"$ACCOUNT_JSON_PATH" _info "Registered" - elif [ "$code" = '409' ]; then + elif [ "$code" = '409' ] || [ "$code" = '200' ]; then _info "Already registered" else _err "Register account Error: $response" From 6b798b01a80ad0b44d664f62e467676ab31398bd Mon Sep 17 00:00:00 2001 From: jim-p Date: Mon, 5 Feb 2018 16:38:42 -0500 Subject: [PATCH 1261/1348] Add braces around ACCOUNT_URL when forming the protected= line. Fixes #1243 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4b80c120..c778e2e9 100755 --- a/acme.sh +++ b/acme.sh @@ -1787,7 +1787,7 @@ _send_signed_request() { if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' else - protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"$ACCOUNT_URL\""'}' + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"${ACCOUNT_URL}\""'}' fi else protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' From 584fb2904b6b63cf13d71ba20fa184ade62730a0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Feb 2018 21:23:08 +0800 Subject: [PATCH 1262/1348] fix https://github.com/Neilpang/acme.sh/issues/1191 https://github.com/Neilpang/acme.sh/issues/1246 --- acme.sh | 14 ++++++++++++- dnsapi/dns_inwx.sh | 50 +++------------------------------------------- 2 files changed, 16 insertions(+), 48 deletions(-) diff --git a/acme.sh b/acme.sh index 928a31f4..2a0a7ff0 100755 --- a/acme.sh +++ b/acme.sh @@ -3594,7 +3594,7 @@ $_authorizations_map" entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" _debug entry "$entry" if [ -z "$entry" ]; then - _err "Error, can not get domain token $d" + _err "Error, can not get domain token entry $d" _clearup _on_issue_err "$_post_hook" return 1 @@ -3602,6 +3602,12 @@ $_authorizations_map" token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" + if [ -z "$token" ]; then + _err "Error, can not get domain token $entry" + _clearup + _on_issue_err "$_post_hook" + return 1 + fi if [ "$ACME_VERSION" = "2" ]; then uri="$(printf "%s\n" "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)" else @@ -3609,6 +3615,12 @@ $_authorizations_map" fi _debug uri "$uri" + if [ -z "$uri" ]; then + _err "Error, can not get domain uri. $entry" + _clearup + _on_issue_err "$_post_hook" + return 1 + fi keyauthorization="$token.$thumbprint" _debug keyauthorization "$keyauthorization" diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 74440bd7..5dfba7d1 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -35,53 +35,9 @@ dns_inwx_add() { fi _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _debug "Getting txt records" - - xml_content=$(printf ' - - nameserver.info - - - - - - domain - - %s - - - - type - - TXT - - - - name - - %s - - - - - - - ' "$_domain" "$_sub_domain") - response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - - if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then - _err "Error could net get txt records" - return 1 - fi - if ! printf "%s" "$response" | grep "count" >/dev/null; then - _info "Adding record" - _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" - else - _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | _egrep_o '[0-9]+') - _info "Updating record" - _inwx_update_record "$_record_id" "$txtvalue" - fi + _info "Adding record" + _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" } @@ -147,7 +103,7 @@ dns_inwx_rm() { ' "$_domain" "$_sub_domain") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + if ! _contains "$response" "Command completed successfully"; then _err "Error could not get txt records" return 1 fi From 52b945164cb8d13bd0557d0e2e6177ded2a65369 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Feb 2018 20:54:05 +0800 Subject: [PATCH 1263/1348] fix https://github.com/Neilpang/acme.sh/issues/1247 --- dnsapi/dns_yandex.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index eb60d5af..a0d8a02c 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -18,7 +18,6 @@ dns_yandex_add() { curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" - curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -36,7 +35,6 @@ dns_yandex_rm() { curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" - curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" @@ -61,7 +59,7 @@ _PDD_get_domain() { __last=1 fi - __all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" + __all_domains="$__all_domains $(echo "$res1" | tr "," "\n" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" __page=$(_math $__page + 1) done @@ -72,6 +70,8 @@ _PDD_get_domain() { _debug "finding zone for domain $__t" for d in $__all_domains; do if [ "$d" = "$__t" ]; then + p=$(_math $k - 1) + curSubdomain="$(echo "$fulldomain" | cut -d . -f 1-$p)" echo "$__t" return fi @@ -98,7 +98,6 @@ pdd_get_record_id() { curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" - curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" From 7f59d7ea48f53cb31c0b4a709c3d1ce3cc90087f Mon Sep 17 00:00:00 2001 From: Skid Date: Wed, 7 Feb 2018 14:07:14 +0100 Subject: [PATCH 1264/1348] Fix the command to generate tsig key for knot api --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 32eca131..cabbc16f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -354,7 +354,7 @@ acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com First, generate a TSIG key for updating the zone. ``` -keymgr tsig generate acme_key algorithm hmac-sha512 > /etc/knot/acme.key +keymgr tsig generate -t acme_key hmac-sha512 > /etc/knot/acme.key ``` Include this key in your knot configuration file. From 694af4aeb108386e9b41d0baa319fb9bfc111976 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Feb 2018 21:12:49 +0800 Subject: [PATCH 1265/1348] fix https://github.com/Neilpang/acme.sh/issues/1234 --- acme.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2a0a7ff0..0874edc0 100755 --- a/acme.sh +++ b/acme.sh @@ -5163,8 +5163,14 @@ install() { if [ -z "$NO_DETECT_SH" ]; then #Modify shebang if _exists bash; then + _bash_path="$(bash -c "command -v bash 2>/dev/null")" + if [ -z "$_bash_path" ]; then + _bash_path="$(bash -c 'echo $SHELL')" + fi + fi + if [ "$_bash_path" ]; then _info "Good, bash is found, so change the shebang to use bash as preferred." - _shebang='#!'"$(bash -c "command -v bash")" + _shebang='#!'"$_bash_path" _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" for subf in $_SUB_FOLDERS; do if [ -d "$LE_WORKING_DIR/$subf" ]; then From 3e3161c747a60e6782179a42affac11b073518bd Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Feb 2018 22:18:04 +0800 Subject: [PATCH 1266/1348] fix format --- dnsapi/dns_yandex.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index a0d8a02c..7ebb15dc 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -71,7 +71,7 @@ _PDD_get_domain() { for d in $__all_domains; do if [ "$d" = "$__t" ]; then p=$(_math $k - 1) - curSubdomain="$(echo "$fulldomain" | cut -d . -f 1-$p)" + curSubdomain="$(echo "$fulldomain" | cut -d . -f "1-$p")" echo "$__t" return fi From 78915896d5eed0eba9ffd65c2403315f7285452f Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Feb 2018 23:49:08 +0800 Subject: [PATCH 1267/1348] minor, fix error message --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 0874edc0..a21b24e7 100755 --- a/acme.sh +++ b/acme.sh @@ -3321,7 +3321,7 @@ __get_domain_new_authz() { _err "new-authz retry reach the max $_Max_new_authz_retry_times times." fi - if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then + if [ "$code" ] && [ "$code" != '201' ]; then _err "new-authz error: $response" return 1 fi @@ -3501,7 +3501,7 @@ issue() { Le_OrderFinalize="$(echo "$response" | tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" _debug Le_OrderFinalize "$Le_OrderFinalize" if [ -z "$Le_OrderFinalize" ]; then - _err "Le_OrderFinalize not found." + _err "Create new order error. Le_OrderFinalize not found. $response" _clearup _on_issue_err "$_post_hook" return 1 From da0bd5a9dc414c3b934371145fb8c1ce4073c661 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Feb 2018 09:03:55 +0800 Subject: [PATCH 1268/1348] begin 2.7.7 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a21b24e7..907ab30d 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.6 +VER=2.7.7 PROJECT_NAME="acme.sh" From 875625b1477b4e82513c4e9576f3030ee792fc52 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Feb 2018 10:45:29 +0800 Subject: [PATCH 1269/1348] Support domain alias mode --- README.md | 1 + acme.sh | 63 ++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c66b7f6c..ef699080 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ https://github.com/Neilpang/acmetest - Apache mode - Nginx mode ( Beta ) - DNS mode +- [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode) - [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) diff --git a/acme.sh b/acme.sh index 907ab30d..46e58d90 100755 --- a/acme.sh +++ b/acme.sh @@ -105,6 +105,8 @@ _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations" _STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode" +_DNS_ALIAS_WIKI="https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode" + _DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead." _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" @@ -2845,8 +2847,9 @@ _clearupdns() { _debug "skip dns." return fi - + _info "Removing DNS records." ventries=$(echo "$vlist" | tr ',' ' ') + _alias_index=1 for ventry in $ventries; do d=$(echo "$ventry" | cut -d "$sep" -f 1) keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) @@ -2860,7 +2863,7 @@ _clearupdns() { fi if [ "$vtype" != "$VTYPE_DNS" ]; then - _info "Skip $d for $vtype" + _debug "Skip $d for $vtype" continue fi @@ -2888,7 +2891,15 @@ _clearupdns() { if _startswith "$_dns_root_d" "*."; then _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" fi - txtdomain="_acme-challenge.$_dns_root_d" + + _d_alias="$(_getfield "$_challenge_alias" "$_alias_index")" + _alias_index="$(_math "$_alias_index" + 1)" + _debug "_d_alias" "$_d_alias" + if [ "$_d_alias" ]; then + txtdomain="_acme-challenge.$_d_alias" + else + txtdomain="_acme-challenge.$_dns_root_d" + fi if ! $rmcommand "$txtdomain" "$txt"; then _err "Error removing txt for domain:$txtdomain" @@ -3370,7 +3381,7 @@ issue() { _post_hook="${11}" _renew_hook="${12}" _local_addr="${13}" - + _challenge_alias="${14}" #remove these later. if [ "$_web_roots" = "dns-cf" ]; then _web_roots="dns_cf" @@ -3423,7 +3434,13 @@ issue() { else _cleardomainconf "Le_LocalAddress" fi - + if [ "$_challenge_alias" ]; then + _savedomainconf "Le_ChallengeAlias" "$_challenge_alias" + else + _cleardomainconf "Le_ChallengeAlias" + fi + + Le_API="$ACME_DIRECTORY" _savedomainconf "Le_API" "$Le_API" @@ -3640,6 +3657,7 @@ $_authorizations_map" #add entry dnsadded="" ventries=$(echo "$vlist" | tr "$dvsep" ' ') + _alias_index=1; for ventry in $ventries; do d=$(echo "$ventry" | cut -d "$sep" -f 1) keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) @@ -3657,7 +3675,14 @@ $_authorizations_map" if _startswith "$_dns_root_d" "*."; then _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" fi - txtdomain="_acme-challenge.$_dns_root_d" + _d_alias="$(_getfield "$_challenge_alias" "$_alias_index")" + _alias_index="$(_math "$_alias_index" + 1)" + _debug "_d_alias" "$_d_alias" + if [ "$_d_alias" ]; then + txtdomain="_acme-challenge.$_d_alias" + else + txtdomain="_acme-challenge.$_dns_root_d" + fi _debug txtdomain "$txtdomain" txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" @@ -4210,7 +4235,7 @@ renew() { fi IS_RENEW="1" - issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" + issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" res="$?" if [ "$res" != "0" ]; then return "$res" @@ -4274,6 +4299,17 @@ signcsr() { return 1 fi + _real_cert="$3" + _real_key="$4" + _real_ca="$5" + _reload_cmd="$6" + _real_fullchain="$7" + _pre_hook="${8}" + _post_hook="${9}" + _renew_hook="${10}" + _local_addr="${11}" + _challenge_alias="${12}" + _csrsubj=$(_readSubjectFromCSR "$_csrfile") if [ "$?" != "0" ]; then _err "Can not read subject from csr: $_csrfile" @@ -4319,7 +4355,7 @@ signcsr() { _info "Copy csr to: $CSR_PATH" cp "$_csrfile" "$CSR_PATH" - issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" + issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias" } @@ -5293,6 +5329,7 @@ Commands: Parameters: --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. + --challenge-alias domain.tld The domain alis for DNS alias mode: $_DNS_ALIAS_WIKI --force, -f Used to force to install or force to renew a cert immediately. --staging, --test Use staging server, just for test. --debug Output debug info. @@ -5443,6 +5480,7 @@ _process() { _domain="" _altdomains="$NO_VALUE" _webroot="" + _challenge_alias="" _keylength="" _accountkeylength="" _cert_file="" @@ -5632,6 +5670,11 @@ _process() { fi shift ;; + --challenge-alias) + cvalue="$2" + _challenge_alias="$_challenge_alias$cvalue," + shift + ;; --standalone) wvalue="$NO_VALUE" if [ -z "$_webroot" ]; then @@ -5953,13 +5996,13 @@ _process() { uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_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" "$_challenge_alias" ;; deploy) deploy "$_domain" "$_deploy_hook" "$_ecc" ;; signcsr) - signcsr "$_csr" "$_webroot" + signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" ;; showcsr) showcsr "$_csr" "$_domain" From 6ca5f3d8f6164cb17cc4670dd3f7a6983ad76e21 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Feb 2018 23:23:31 +0800 Subject: [PATCH 1270/1348] support Zonomi.com dns api: https://github.com/Neilpang/acme.sh/issues/1255 --- README.md | 2 +- acme.sh | 3 ++ dnsapi/README.md | 22 +++++++++++ dnsapi/dns_zonomi.sh | 87 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 dnsapi/dns_zonomi.sh diff --git a/README.md b/README.md index c66b7f6c..d6b2c555 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ You don't have to do anything manually! 1. InternetX autoDNS API (https://internetx.com) 1. Azure DNS 1. selectel.com(selectel.ru) DNS API - +1. zonomi.com DNS API And: 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/acme.sh b/acme.sh index 907ab30d..ebddf81d 100755 --- a/acme.sh +++ b/acme.sh @@ -1561,6 +1561,9 @@ _inithttp() { _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " fi + if _contains "$(curl --help 2>&1)" "--globoff"; then + _ACME_CURL="$_ACME_CURL -g " + fi fi if [ -z "$_ACME_WGET" ] && _exists "wget"; then diff --git a/dnsapi/README.md b/dnsapi/README.md index 32eca131..5ded260c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -719,6 +719,28 @@ acme.sh --issue --dns dns_selectel -d example.com -d www.example.com The `SL_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 39. Use zonomi.com domain API to automatically issue cert + +First you need to login to your account to find your API key from: http://zonomi.com/app/dns/dyndns.jsp + +Your will find your api key in the example urls: + +```sh +https://zonomi.com/app/dns/dyndns.jsp?host=example.com&api_key=1063364558943540954358668888888888 +``` + +```sh +export ZM_Key="1063364558943540954358668888888888" + +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_zonomi -d example.com -d www.example.com +``` + +The `ZM_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API diff --git a/dnsapi/dns_zonomi.sh b/dnsapi/dns_zonomi.sh new file mode 100644 index 00000000..e3a5f440 --- /dev/null +++ b/dnsapi/dns_zonomi.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env sh + +# +#ZM_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#https://zonomi.com dns api + +ZM_Api="https://zonomi.com/app/dns/dyndns.jsp" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_zonomi_add() { + fulldomain=$1 + txtvalue=$2 + + ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}" + + if [ -z "$ZM_Key" ]; then + ZM_Key="" + _err "You don't specify zonomi api key yet." + _err "Please create your key and try again." + return 1 + fi + + #save the api key to the account conf file. + _saveaccountconf_mutable ZM_Key "$ZM_Key" + + _info "Get existing txt records for $fulldomain" + if ! _zm_request "action=QUERY&name=$fulldomain"; then + _err "error" + return 1 + fi + + if _contains "$response" "' | tr "<" "\n" | grep record | grep 'type="TXT"' | cut -d '"' -f 6); do + _debug2 t "$t" + _qstr="$_qstr&action[$_qindex]=SET&type[$_qindex]=TXT&name[$_qindex]=$fulldomain&value[$_qindex]=$t" + _qindex="$(_math "$_qindex" + 1)" + done + _zm_request "$_qstr" + else + _debug "Just add record" + _zm_request "action=SET&type=TXT&name=$fulldomain&value=$txtvalue" + fi + +} + +#fulldomain txtvalue +dns_zonomi_rm() { + fulldomain=$1 + txtvalue=$2 + + ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}" + if [ -z "$ZM_Key" ]; then + ZM_Key="" + _err "You don't specify zonomi api key yet." + _err "Please create your key and try again." + return 1 + fi + + _zm_request "action=DELETE&type=TXT&name=$fulldomain" + +} + +#################### Private functions below ################################## +#qstr +_zm_request() { + qstr="$1" + + _debug2 "action" "$action" + _debug2 "qstr" "$qstr" + + _zm_url="$ZM_Api?api_key=$ZM_Key&$qstr" + _debug2 "_zm_url" "$_zm_url" + response="$(_get "$_zm_url")" + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + _contains "$response" "OK:" +} From 0159277dbf8c73e7c1fce21fcbba92ef991b46bf Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Feb 2018 23:24:43 +0800 Subject: [PATCH 1271/1348] fix format --- dnsapi/dns_zonomi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_zonomi.sh b/dnsapi/dns_zonomi.sh index e3a5f440..efc9b1fd 100644 --- a/dnsapi/dns_zonomi.sh +++ b/dnsapi/dns_zonomi.sh @@ -31,7 +31,7 @@ dns_zonomi_add() { _err "error" return 1 fi - + if _contains "$response" " Date: Sat, 10 Feb 2018 23:34:34 +0800 Subject: [PATCH 1272/1348] fix format --- dnsapi/dns_zonomi.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dnsapi/dns_zonomi.sh b/dnsapi/dns_zonomi.sh index efc9b1fd..52a889ea 100644 --- a/dnsapi/dns_zonomi.sh +++ b/dnsapi/dns_zonomi.sh @@ -35,7 +35,7 @@ dns_zonomi_add() { if _contains "$response" "' | tr "<" "\n" | grep record | grep 'type="TXT"' | cut -d '"' -f 6); do _debug2 t "$t" _qstr="$_qstr&action[$_qindex]=SET&type[$_qindex]=TXT&name[$_qindex]=$fulldomain&value[$_qindex]=$t" @@ -71,7 +71,6 @@ dns_zonomi_rm() { _zm_request() { qstr="$1" - _debug2 "action" "$action" _debug2 "qstr" "$qstr" _zm_url="$ZM_Api?api_key=$ZM_Key&$qstr" @@ -79,7 +78,6 @@ _zm_request() { response="$(_get "$_zm_url")" if [ "$?" != "0" ]; then - _err "error $ep" return 1 fi _debug2 response "$response" From 2c83224f07ff1a29cbf1ea88cbf09aac1ccd36ac Mon Sep 17 00:00:00 2001 From: Martin Donlon Date: Sun, 11 Feb 2018 07:37:15 -0800 Subject: [PATCH 1273/1348] Fixup dns_dreamhost travis failures --- README.md | 1 + dnsapi/README.md | 14 +++++- dnsapi/dns_dreamhost.sh | 97 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 dnsapi/dns_dreamhost.sh diff --git a/README.md b/README.md index c66b7f6c..e7b62f7a 100644 --- a/README.md +++ b/README.md @@ -302,6 +302,7 @@ You don't have to do anything manually! 1. Dynu API (https://www.dynu.com) 1. DNSimple API 1. NS1.com API +1. DreamHost.com API 1. DuckDNS.org API 1. Name.com API 1. Dyn Managed DNS API diff --git a/dnsapi/README.md b/dnsapi/README.md index 32eca131..aef528eb 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -512,7 +512,7 @@ acme.sh --issue --dns dns_nsone -d example.com -d www.example.com export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" ``` -Please note that since DuckDNS uses StartSSL as their cert provider, thus +Please note that since DuckDNS uses StartSSL as their cert provider, thus --insecure may need to be used when issuing certs: ``` acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org @@ -719,6 +719,18 @@ acme.sh --issue --dns dns_selectel -d example.com -d www.example.com The `SL_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 39. Use DreamHost DNS API + +DNS API keys may be created at https://panel.dreamhost.com/?tree=home.api. +Ensure the created key has add and remove privelages. + +``` +export DH_API_Key="" +acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com +``` + +The 'DH_API_KEY' will be saved in `~/.acme.sh/account.conf` and will +be reused when needed. # Use custom API diff --git a/dnsapi/dns_dreamhost.sh b/dnsapi/dns_dreamhost.sh new file mode 100644 index 00000000..35b34443 --- /dev/null +++ b/dnsapi/dns_dreamhost.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env sh + +#Author: RhinoLance +#Report Bugs here: https://github.com/RhinoLance/acme.sh +# + +#define the api endpoint +DH_API_ENDPOINT="https://api.dreamhost.com/" +querystring="" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dreamhost_add() { + fulldomain=$1 + txtvalue=$2 + + if ! validate "$fulldomain" "$txtvalue"; then + return 1 + fi + + querystring="key=$DH_API_KEY&cmd=dns-add_record&record=$fulldomain&type=TXT&value=$txtvalue" + if ! submit "$querystring"; then + return 1 + fi + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dreamhost_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! validate "$fulldomain" "$txtvalue"; then + return 1 + fi + + querystring="key=$DH_API_KEY&cmd=dns-remove_record&record=$fulldomain&type=TXT&value=$txtvalue" + if ! submit "$querystring"; then + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## + +#send the command to the api endpoint. +submit() { + querystring=$1 + + url="$DH_API_ENDPOINT?$querystring" + + _debug url "$url" + + if ! response="$(_get "$url")"; then + _err "Error <$1>" + return 1 + fi + + if [ -z "$2" ]; then + message="$(printf "%s" "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + if [ -n "$message" ]; then + _err "$message" + return 1 + fi + fi + + _debug response "$response" + + return 0 +} + +#check that we have a valid API Key +validate() { + fulldomain=$1 + txtvalue=$2 + + _info "Using dreamhost" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + #retrieve the API key from the environment variable if it exists, otherwise look for a saved key. + DH_API_KEY="${DH_API_KEY:-$(_readaccountconf_mutable DH_API_KEY)}" + + if [ -z "$DH_API_KEY" ]; then + DH_API_KEY="" + _err "You didn't specify the DreamHost api key yet (export DH_API_KEY=\"\")" + _err "Please login to your control panel, create a key and try again." + return 1 + fi + + #save the api key to the account conf file. + _saveaccountconf_mutable DH_API_KEY "$DH_API_KEY" +} From 012dd6986b259f73ef82610084fc393b841e07d1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 12 Feb 2018 20:01:40 +0800 Subject: [PATCH 1274/1348] nginx --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index ebddf81d..a4224fc9 100755 --- a/acme.sh +++ b/acme.sh @@ -2763,9 +2763,9 @@ _isRealNginxConf() { _left="$(sed -n "${_start_nn},99999p" "$2")" _debug2 _left "$_left" - if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *" >/dev/null; then - _end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *" | _head_n 1) - _debug "_end" "$_end" + _end="$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *" | grep -v server_name | _head_n 1)" + _debug "_end" "$_end" + if [ "$_end" ]; then _end_n=$(echo "$_end" | cut -d : -f 1) _debug "_end_n" "$_end_n" _seg_n=$(echo "$_left" | sed -n "1,${_end_n}p") From 2655e726c9dc2fee656bc642ea0e8e5c7aa866e6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 12 Feb 2018 20:40:24 +0800 Subject: [PATCH 1275/1348] update dns he --- README.md | 7 +++++++ dnsapi/README.md | 2 +- dnsapi/dns_he.sh | 9 ++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d6b2c555..9e3ec1a5 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,13 @@ You don't have to do anything manually! 1. Azure DNS 1. selectel.com(selectel.ru) DNS API 1. zonomi.com DNS API + + + + + + + And: 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/dnsapi/README.md b/dnsapi/README.md index 5ded260c..fa0780b0 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -585,7 +585,7 @@ For issues, please report to https://github.com/non7top/acme.sh/issues. ## 31. Use Hurricane Electric -Hurricane Electric doesn't have an API so just set your login credentials like so: +Hurricane Electric (https://dns.he.net/) doesn't have an API so just set your login credentials like so: ``` export HE_Username="yourusername" diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 4d1973ad..7b854ead 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -19,14 +19,16 @@ dns_he_add() { _txt_value=$2 _info "Using DNS-01 Hurricane Electric hook" + HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}" + HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}" if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then HE_Username= HE_Password= _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables." return 1 fi - _saveaccountconf HE_Username "$HE_Username" - _saveaccountconf HE_Password "$HE_Password" + _saveaccountconf_mutable HE_Username "$HE_Username" + _saveaccountconf_mutable HE_Password "$HE_Password" # Fills in the $_zone_id _find_zone "$_full_domain" || return 1 @@ -62,7 +64,8 @@ dns_he_rm() { _full_domain=$1 _txt_value=$2 _info "Cleaning up after DNS-01 Hurricane Electric hook" - + HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}" + HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}" # fills in the $_zone_id _find_zone "$_full_domain" || return 1 _debug "Zone id \"$_zone_id\" will be used." From 64821ad4f594786093f05afc36c35901e408ff00 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 12 Feb 2018 21:49:22 +0800 Subject: [PATCH 1276/1348] support "--domain-alias" --- acme.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 46e58d90..b04270a2 100755 --- a/acme.sh +++ b/acme.sh @@ -47,6 +47,7 @@ DEFAULT_DNS_SLEEP=120 NO_VALUE="no" W_TLS="tls" +DNS_ALIAS_PREFIX="=" MODE_STATELESS="stateless" @@ -2896,7 +2897,11 @@ _clearupdns() { _alias_index="$(_math "$_alias_index" + 1)" _debug "_d_alias" "$_d_alias" if [ "$_d_alias" ]; then - txtdomain="_acme-challenge.$_d_alias" + if _startswith "$_d_alias" "$DNS_ALIAS_PREFIX"; then + txtdomain="$(echo "$_d_alias" | sed "s/$DNS_ALIAS_PREFIX//")" + else + txtdomain="_acme-challenge.$_d_alias" + fi else txtdomain="_acme-challenge.$_dns_root_d" fi @@ -3679,7 +3684,11 @@ $_authorizations_map" _alias_index="$(_math "$_alias_index" + 1)" _debug "_d_alias" "$_d_alias" if [ "$_d_alias" ]; then - txtdomain="_acme-challenge.$_d_alias" + if _startswith "$_d_alias" "$DNS_ALIAS_PREFIX"; then + txtdomain="$(echo "$_d_alias" | sed "s/$DNS_ALIAS_PREFIX//")" + else + txtdomain="_acme-challenge.$_d_alias" + fi else txtdomain="_acme-challenge.$_dns_root_d" fi @@ -5329,7 +5338,8 @@ Commands: Parameters: --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. - --challenge-alias domain.tld The domain alis for DNS alias mode: $_DNS_ALIAS_WIKI + --challenge-alias domain.tld The challenge domain alias for DNS alias mode: $_DNS_ALIAS_WIKI + --domain-alias domain.tld The domain alias for DNS alias mode: $_DNS_ALIAS_WIKI --force, -f Used to force to install or force to renew a cert immediately. --staging, --test Use staging server, just for test. --debug Output debug info. @@ -5675,6 +5685,11 @@ _process() { _challenge_alias="$_challenge_alias$cvalue," shift ;; + --domain-alias) + cvalue="$DNS_ALIAS_PREFIX$2" + _challenge_alias="$_challenge_alias$cvalue," + shift + ;; --standalone) wvalue="$NO_VALUE" if [ -z "$_webroot" ]; then From 9144ce746e0e138c0eb34fc05f6efdb3c811375c Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Feb 2018 19:30:54 +0800 Subject: [PATCH 1277/1348] fix for v2 wildcard --- dnsapi/dns_aws.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index ed317460..bbc54284 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -42,7 +42,7 @@ dns_aws_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _aws_tmpl_xml="UPSERT$fulldomainTXT300\"$txtvalue\"" + _aws_tmpl_xml="CREATE$fulldomainTXT300\"$txtvalue\"" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then _info "txt record updated success." From 849a6c12be49ae3d03a8b6068451b241b3c5f284 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Feb 2018 20:08:05 +0800 Subject: [PATCH 1278/1348] fix for acme v2 --- dnsapi/dns_cx.sh | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index e2f0f099..d27cd841 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -36,33 +36,18 @@ dns_cx_add() { return 1 fi - existing_records "$_domain" "$_sub_domain" - _debug count "$count" - if [ "$?" != "0" ]; then - _err "Error get existing records." - return 1 - fi - - if [ "$count" = "0" ]; then - add_record "$_domain" "$_sub_domain" "$txtvalue" - else - update_record "$_domain" "$_sub_domain" "$txtvalue" - fi - - if [ "$?" = "0" ]; then - return 0 - fi - return 1 + add_record "$_domain" "$_sub_domain" "$txtvalue" } -#fulldomain +#fulldomain txtvalue dns_cx_rm() { fulldomain=$1 + txtvalue=$2 REST_API="$CX_Api" if _get_root "$fulldomain"; then record_id="" - existing_records "$_domain" "$_sub_domain" - if ! [ "$record_id" = "" ]; then + existing_records "$_domain" "$_sub_domain" "$txtvalue" + if [ "$record_id" ]; then _rest DELETE "record/$record_id/$_domain_id" "{}" _info "Deleted record ${fulldomain}" fi @@ -114,23 +99,6 @@ add_record() { return 0 } -#update the txt record -#Usage: root sub txtvalue -update_record() { - root=$1 - sub=$2 - txtvalue=$3 - fulldomain="$sub.$root" - - _info "Updating record" - - if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then - return 0 - fi - - return 1 -} - #################### Private functions below ################################## #_acme-challenge.www.domain.com #returns From 64f07d9bf39be06b53475e4219ceb83530345611 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Feb 2018 22:17:20 +0800 Subject: [PATCH 1279/1348] fix aws for acme v2 --- dnsapi/dns_aws.sh | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index bbc54284..33e7e707 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -42,7 +42,26 @@ dns_aws_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _aws_tmpl_xml="CREATE$fulldomainTXT300\"$txtvalue\"" + _info "Geting existing records for $fulldomain" + if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then + return 1 + fi + + if _contains "$response" "$fulldomain."; then + _resource_record="$(echo "$response" | _egrep_o "" | sed "s///" | sed "s###")" + _debug "_resource_record" "$_resource_record" + else + _debug "single new add" + fi + + if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then + _info "The txt record already exists, skip" + return 0 + fi + + _debug "Adding records" + + _aws_tmpl_xml="UPSERT$fulldomainTXT300$_resource_record\"$txtvalue\"" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then _info "txt record updated success." @@ -68,7 +87,20 @@ dns_aws_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _aws_tmpl_xml="DELETE\"$txtvalue\"$fulldomain.TXT300" + _info "Geting existing records for $fulldomain" + if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then + return 1 + fi + + if _contains "$response" "$fulldomain."; then + _resource_record="$(echo "$response" | _egrep_o "" | sed "s///" | sed "s###")" + _debug "_resource_record" "$_resource_record" + else + _debug "no records exists, skip" + return 0 + fi + + _aws_tmpl_xml="DELETE$_resource_record$fulldomain.TXT300" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then _info "txt record deleted success." @@ -87,7 +119,6 @@ _get_root() { p=1 if aws_rest GET "2013-04-01/hostedzone"; then - _debug "response" "$response" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug2 "Checking domain: $h" @@ -236,6 +267,7 @@ aws_rest() { fi _ret="$?" + _debug2 response "$response" if [ "$_ret" = "0" ]; then if _contains "$response" " Date: Tue, 13 Feb 2018 22:23:36 +0800 Subject: [PATCH 1280/1348] fix format --- dnsapi/dns_aws.sh | 4 ++-- dnsapi/dns_cx.sh | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 33e7e707..ee8efb38 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -48,7 +48,7 @@ dns_aws_add() { fi if _contains "$response" "$fulldomain."; then - _resource_record="$(echo "$response" | _egrep_o "" | sed "s///" | sed "s###")" + _resource_record="$(echo "$response" | _egrep_o "" | sed "s///" | sed "s###")" _debug "_resource_record" "$_resource_record" else _debug "single new add" @@ -93,7 +93,7 @@ dns_aws_rm() { fi if _contains "$response" "$fulldomain."; then - _resource_record="$(echo "$response" | _egrep_o "" | sed "s///" | sed "s###")" + _resource_record="$(echo "$response" | _egrep_o "" | sed "s///" | sed "s###")" _debug "_resource_record" "$_resource_record" else _debug "no records exists, skip" diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index d27cd841..b3e04032 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -74,7 +74,6 @@ existing_records() { fi if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then - count=1 record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1) _debug record_id "$record_id" return 0 From 1f7df33e289001d72c2637411ce3df499cf4c171 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Feb 2018 22:26:36 +0800 Subject: [PATCH 1281/1348] fix format --- acme.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index b04270a2..ce00aed6 100755 --- a/acme.sh +++ b/acme.sh @@ -3444,8 +3444,7 @@ issue() { else _cleardomainconf "Le_ChallengeAlias" fi - - + Le_API="$ACME_DIRECTORY" _savedomainconf "Le_API" "$Le_API" @@ -3662,7 +3661,7 @@ $_authorizations_map" #add entry dnsadded="" ventries=$(echo "$vlist" | tr "$dvsep" ' ') - _alias_index=1; + _alias_index=1 for ventry in $ventries; do d=$(echo "$ventry" | cut -d "$sep" -f 1) keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) @@ -5689,7 +5688,7 @@ _process() { cvalue="$DNS_ALIAS_PREFIX$2" _challenge_alias="$_challenge_alias$cvalue," shift - ;; + ;; --standalone) wvalue="$NO_VALUE" if [ -z "$_webroot" ]; then From 84649e9d20603e402462b09fd1481371cd1b5ebc Mon Sep 17 00:00:00 2001 From: Martin Donlon Date: Tue, 13 Feb 2018 21:02:38 -0800 Subject: [PATCH 1282/1348] Addressing PR feedback Replace printf with echo Move dreamhost to bottom of DNS API list --- README.md | 2 +- dnsapi/dns_dreamhost.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f6c73ba5..5e3709a1 100644 --- a/README.md +++ b/README.md @@ -302,7 +302,6 @@ You don't have to do anything manually! 1. Dynu API (https://www.dynu.com) 1. DNSimple API 1. NS1.com API -1. DreamHost.com API 1. DuckDNS.org API 1. Name.com API 1. Dyn Managed DNS API @@ -316,6 +315,7 @@ You don't have to do anything manually! 1. Azure DNS 1. selectel.com(selectel.ru) DNS API 1. zonomi.com DNS API +1. DreamHost.com API And: 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/dnsapi/dns_dreamhost.sh b/dnsapi/dns_dreamhost.sh index 35b34443..a4017938 100644 --- a/dnsapi/dns_dreamhost.sh +++ b/dnsapi/dns_dreamhost.sh @@ -61,7 +61,7 @@ submit() { fi if [ -z "$2" ]; then - message="$(printf "%s" "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" if [ -n "$message" ]; then _err "$message" return 1 From 7b92371a035bb013746bbffb0d62858850f2690b Mon Sep 17 00:00:00 2001 From: Jose Luis Duran Date: Wed, 14 Feb 2018 06:44:06 -0200 Subject: [PATCH 1283/1348] Fix key file permissions Introduced in 8201458332ea5898177118097621dbac842ad64f. Related to #1256. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a4224fc9..b9e57a7b 100755 --- a/acme.sh +++ b/acme.sh @@ -4545,7 +4545,7 @@ _installcert() { cat "$CERT_KEY_PATH" >"$_real_key" else cat "$CERT_KEY_PATH" >"$_real_key" - chmod 700 "$_real_key" + chmod 600 "$_real_key" fi fi From 5f345d208939bad2408c7e652646dc42ef5bf6d4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Feb 2018 19:39:47 +0800 Subject: [PATCH 1284/1348] fix https://github.com/Neilpang/acme.sh/issues/1262 --- dnsapi/dns_aws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index ee8efb38..71f969f0 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -48,7 +48,7 @@ dns_aws_add() { fi if _contains "$response" "$fulldomain."; then - _resource_record="$(echo "$response" | _egrep_o "" | sed "s///" | sed "s###")" + _resource_record="$(echo "$response" | sed 's//"/g' | tr '"' "\n" | grep "$fulldomain." | _egrep_o "" | sed "s///" | sed "s###")" _debug "_resource_record" "$_resource_record" else _debug "single new add" @@ -93,7 +93,7 @@ dns_aws_rm() { fi if _contains "$response" "$fulldomain."; then - _resource_record="$(echo "$response" | _egrep_o "" | sed "s///" | sed "s###")" + _resource_record="$(echo "$response" | sed 's//"/g' | tr '"' "\n" | grep "$fulldomain." | _egrep_o "" | sed "s///" | sed "s###")" _debug "_resource_record" "$_resource_record" else _debug "no records exists, skip" From 28145a9debc32232ebfe987fe73bec189ac2bf30 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Feb 2018 20:40:49 +0800 Subject: [PATCH 1285/1348] fix ovh --- dnsapi/dns_cx.sh | 1 - dnsapi/dns_ovh.sh | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index b3e04032..f2d3eadb 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -62,7 +62,6 @@ existing_records() { _debug "Getting txt records" root=$1 sub=$2 - count=0 if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then return 1 fi diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 60094739..296a2698 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -79,6 +79,9 @@ _ovh_get_api() { } _initAuth() { + OVH_AK="${OVH_AK:-$(_readaccountconf_mutable OVH_AK)}" + OVH_AS="${OVH_AS:-$(_readaccountconf_mutable OVH_AS)}" + if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then OVH_AK="" OVH_AS="" @@ -87,21 +90,22 @@ _initAuth() { return 1 fi - #save the api key and email to the account conf file. - _saveaccountconf OVH_AK "$OVH_AK" - _saveaccountconf OVH_AS "$OVH_AS" + _saveaccountconf_mutable OVH_AK "$OVH_AK" + _saveaccountconf_mutable OVH_AS "$OVH_AS" + OVH_END_POINT="${OVH_END_POINT:-$(_readaccountconf_mutable OVH_END_POINT)}" if [ -z "$OVH_END_POINT" ]; then OVH_END_POINT="ovh-eu" fi _info "Using OVH endpoint: $OVH_END_POINT" if [ "$OVH_END_POINT" != "ovh-eu" ]; then - _saveaccountconf OVH_END_POINT "$OVH_END_POINT" + _saveaccountconf_mutable OVH_END_POINT "$OVH_END_POINT" fi OVH_API="$(_ovh_get_api $OVH_END_POINT)" _debug OVH_API "$OVH_API" + OVH_CK="${OVH_CK:-$(_readaccountconf_mutable OVH_CK)}" if [ -z "$OVH_CK" ]; then _info "OVH consumer key is empty, Let's get one:" if ! _ovh_authentication; then From a6b6e31cdaf05f0f18d7be98c488a8fe13624376 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Feb 2018 20:52:06 +0800 Subject: [PATCH 1286/1348] fix dp --- dnsapi/dns_dp.sh | 75 ++++++------------------------------------------ 1 file changed, 9 insertions(+), 66 deletions(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 301a1f6c..bf623e26 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -15,6 +15,8 @@ dns_dp_add() { fulldomain=$1 txtvalue=$2 + DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}" + DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}" if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then DP_Id="" DP_Key="" @@ -24,8 +26,8 @@ dns_dp_add() { fi #save the api key and email to the account conf file. - _saveaccountconf DP_Id "$DP_Id" - _saveaccountconf DP_Key "$DP_Key" + _saveaccountconf_mutable DP_Id "$DP_Id" + _saveaccountconf_mutable DP_Key "$DP_Key" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -33,24 +35,18 @@ dns_dp_add() { return 1 fi - existing_records "$_domain" "$_sub_domain" - _debug count "$count" - if [ "$?" != "0" ]; then - _err "Error get existing records." - return 1 - fi + add_record "$_domain" "$_sub_domain" "$txtvalue" - if [ "$count" = "0" ]; then - add_record "$_domain" "$_sub_domain" "$txtvalue" - else - update_record "$_domain" "$_sub_domain" "$txtvalue" - fi } #fulldomain txtvalue dns_dp_rm() { fulldomain=$1 txtvalue=$2 + + DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}" + DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}" + _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" @@ -83,37 +79,6 @@ dns_dp_rm() { } -#usage: root sub -#return if the sub record already exists. -#echos the existing records count. -# '0' means doesn't exist -existing_records() { - _debug "Getting txt records" - root=$1 - sub=$2 - - if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&domain_id=$_domain_id&sub_domain=$_sub_domain"; then - return 1 - fi - - if _contains "$response" 'No records'; then - count=0 - return 0 - fi - - if _contains "$response" "Action completed successful"; then - count=$(printf "%s" "$response" | grep -c 'TXT' | tr -d ' ') - record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) - _debug record_id "$record_id" - return 0 - else - _err "get existing records error." - return 1 - fi - - count=0 -} - #add the txt record. #usage: root sub txtvalue add_record() { @@ -136,28 +101,6 @@ add_record() { return 1 #error } -#update the txt record -#Usage: root sub txtvalue -update_record() { - root=$1 - sub=$2 - txtvalue=$3 - fulldomain="$sub.$root" - - _info "Updating record" - - if ! _rest POST "Record.Modify" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认&record_id=$record_id"; then - return 1 - fi - - if _contains "$response" "Action completed successful"; then - - return 0 - fi - - return 1 #error -} - #################### Private functions below ################################## #_acme-challenge.www.domain.com #returns From c6f5c7f1a3bd48bcbe4193b363f2a6b82add58b2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Feb 2018 22:31:02 +0800 Subject: [PATCH 1287/1348] fix gd --- dnsapi/dns_gd.sh | 67 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index f2dd1fd5..0e25f9d8 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -15,6 +15,8 @@ dns_gd_add() { fulldomain=$1 txtvalue=$2 + GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}" + GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}" if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then GD_Key="" GD_Secret="" @@ -24,8 +26,8 @@ dns_gd_add() { fi #save the api key and email to the account conf file. - _saveaccountconf GD_Key "$GD_Key" - _saveaccountconf GD_Secret "$GD_Secret" + _saveaccountconf_mutable GD_Key "$GD_Key" + _saveaccountconf_mutable GD_Secret "$GD_Secret" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -36,8 +38,27 @@ dns_gd_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" + _debug "Getting existing records" + if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then + return 1 + fi + + if _contains "$response" "$txtvalue"; then + _info "The record is existing, skip" + return 0; + fi + + _add_data="{\"data\":\"$txtvalue\"}" + for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do + _debug2 t "$t" + if [ "$t" ]; then + _add_data="$_add_data,{\"data\":$t}" + fi + done + _debug2 _add_data "$_add_data" + _info "Adding record" - if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then + if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then if [ "$response" = "{}" ]; then _info "Added, sleeping 10 seconds" _sleep 10 @@ -56,7 +77,47 @@ dns_gd_add() { #fulldomain dns_gd_rm() { fulldomain=$1 + txtvalue=$2 + + GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}" + GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}" + + _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 existing records" + if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then + return 1 + fi + + if ! _contains "$response" "$txtvalue"; then + _info "The record is not existing, skip" + return 0; + fi + + _add_data="" + for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do + _debug2 t "$t" + if [ "$t" ] && [ "$t" != "\"$txtvalue\"" ]; then + if [ "$_add_data" ]; then + _add_data="$_add_data,{\"data\":$t}" + else + _add_data="{\"data\":$t}" + fi + fi + done + if [ -z "$_add_data" ]; then + _add_data="{\"data\":\"\"}" + fi + _debug2 _add_data "$_add_data" + _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; } #################### Private functions below ################################## From d8eb08e21405dc65dc2d9312ec8e040fd016e565 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Feb 2018 22:36:17 +0800 Subject: [PATCH 1288/1348] fix format --- dnsapi/dns_gd.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 0e25f9d8..5fb1b174 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -45,11 +45,11 @@ dns_gd_add() { if _contains "$response" "$txtvalue"; then _info "The record is existing, skip" - return 0; + return 0 fi _add_data="{\"data\":\"$txtvalue\"}" - for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do + for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do _debug2 t "$t" if [ "$t" ]; then _add_data="$_add_data,{\"data\":$t}" @@ -98,11 +98,11 @@ dns_gd_rm() { if ! _contains "$response" "$txtvalue"; then _info "The record is not existing, skip" - return 0; + return 0 fi _add_data="" - for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do + for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do _debug2 t "$t" if [ "$t" ] && [ "$t" != "\"$txtvalue\"" ]; then if [ "$_add_data" ]; then @@ -117,7 +117,7 @@ dns_gd_rm() { fi _debug2 _add_data "$_add_data" - _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; + _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]" } #################### Private functions below ################################## From b51ed9bbb74356fa54e83b86204232499ccb5edd Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Feb 2018 10:29:03 +0800 Subject: [PATCH 1289/1348] https://github.com/Neilpang/acme.sh/issues/1251 --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index b9e57a7b..8cd9c594 100755 --- a/acme.sh +++ b/acme.sh @@ -3598,6 +3598,10 @@ $_authorizations_map" _debug entry "$entry" if [ -z "$entry" ]; then _err "Error, can not get domain token entry $d" + _supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')" + if [ "$_supported_vtypes" ]; then + _err "The supported validation types are: $_supported_vtypes, but you specified: $vtype" + fi _clearup _on_issue_err "$_post_hook" return 1 From ce6c7d4b594ccc0ecc253c459ffa8020fb1ec447 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Feb 2018 10:51:13 +0800 Subject: [PATCH 1290/1348] fix dp --- dnsapi/dns_dp.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index bf623e26..3cc720aa 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -93,12 +93,7 @@ add_record() { return 1 fi - if _contains "$response" "Action completed successful"; then - - return 0 - fi - - return 1 #error + _contains "$response" "Action completed successful" || _contains "$response" "Domain record already exists" } #################### Private functions below ################################## From 0096ef4ddb5e6b86c512a6a4a57afc62ba725701 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Feb 2018 12:26:35 +0800 Subject: [PATCH 1291/1348] fix ali --- dnsapi/dns_ali.sh | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index f796f076..543a0a54 100755 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -10,6 +10,8 @@ dns_ali_add() { fulldomain=$1 txtvalue=$2 + Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}" + Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}" if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then Ali_Key="" Ali_Secret="" @@ -18,8 +20,8 @@ dns_ali_add() { fi #save the api key and secret to the account conf file. - _saveaccountconf Ali_Key "$Ali_Key" - _saveaccountconf Ali_Secret "$Ali_Secret" + _saveaccountconf_mutable Ali_Key "$Ali_Key" + _saveaccountconf_mutable Ali_Secret "$Ali_Secret" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -32,6 +34,15 @@ dns_ali_add() { dns_ali_rm() { fulldomain=$1 + txtvalue=$2 + Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}" + Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + return 1 + fi + _clean } @@ -76,16 +87,14 @@ _ali_rest() { return 1 fi + _debug2 response "$response" if [ -z "$2" ]; then - message="$(printf "%s" "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" - if [ -n "$message" ]; then + message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + if [ "$message" ]; then _err "$message" return 1 fi fi - - _debug2 response "$response" - return 0 } _ali_urlencode() { @@ -112,12 +121,14 @@ _ali_nonce() { } _check_exist_query() { + _qdomain="$1" + _qsubdomain="$2" query='' query=$query'AccessKeyId='$Ali_Key query=$query'&Action=DescribeDomainRecords' - query=$query'&DomainName='$1 + query=$query'&DomainName='$_qdomain query=$query'&Format=json' - query=$query'&RRKeyWord=_acme-challenge' + query=$query'&RRKeyWord='$_qsubdomain query=$query'&SignatureMethod=HMAC-SHA1' query=$query"&SignatureNonce=$(_ali_nonce)" query=$query'&SignatureVersion=1.0' @@ -169,17 +180,21 @@ _describe_records_query() { } _clean() { - _check_exist_query "$_domain" + _check_exist_query "$_domain" "$_sub_domain" if ! _ali_rest "Check exist records" "ignore"; then return 1 fi - records="$(echo "$response" -n | _egrep_o "\"RecordId\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" - printf "%s" "$records" \ - | while read -r record_id; do - _delete_record_query "$record_id" - _ali_rest "Delete record $record_id" "ignore" - done + record_id="$(echo "$response" | tr '{' "\n" | grep "$_sub_domain" | grep "$txtvalue" | tr "," "\n" | grep RecordId | cut -d '"' -f 4)" + _debug2 record_id "$record_id" + + if [ -z "$record_id" ]; then + _debug "record not found, skip" + else + _delete_record_query "$record_id" + _ali_rest "Delete record $record_id" "ignore" + fi + } _timestamp() { From f213215c81c2b3df4ea18cdc0ac86e757099c050 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Feb 2018 12:38:45 +0800 Subject: [PATCH 1292/1348] fix lua --- dnsapi/dns_lua.sh | 50 +++++++++++++---------------------------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 00c54430..be678b9d 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -17,6 +17,8 @@ dns_lua_add() { fulldomain=$1 txtvalue=$2 + LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}" + LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}" if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then LUA_Key="" LUA_Email="" @@ -26,8 +28,8 @@ dns_lua_add() { fi #save the api key and email to the account conf file. - _saveaccountconf LUA_Key "$LUA_Key" - _saveaccountconf LUA_Email "$LUA_Email" + _saveaccountconf_mutable LUA_Key "$LUA_Key" + _saveaccountconf_mutable LUA_Email "$LUA_Email" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -38,50 +40,26 @@ dns_lua_add() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _debug "Getting txt records" - _LUA_rest GET "zones/${_domain_id}/records" - - if ! _contains "$response" "\"id\":"; then - _err "Error" - return 1 - fi - - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") - _debug count "$count" - if [ "$count" = "0" ]; then - _info "Adding record" - if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if _contains "$response" "$fulldomain"; then - _info "Added" - #todo: check if the record takes effect - return 0 - else - _err "Add txt record error." - return 1 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) - _debug "record_id" "$record_id" - - _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}" - if [ "$?" = "0" ] && _contains "$response" "updated_at"; then - _info "Updated!" + _info "Adding record" + if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if _contains "$response" "$fulldomain"; then + _info "Added" #todo: check if the record takes effect return 0 + else + _err "Add txt record error." + return 1 fi - _err "Update error" - return 1 fi - } #fulldomain dns_lua_rm() { fulldomain=$1 txtvalue=$2 + + LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}" + LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" From abd0dad2bf500885f2fdb005b51c43f76380fcf9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Feb 2018 20:35:31 +0800 Subject: [PATCH 1293/1348] fix https://github.com/Neilpang/acme.sh/issues/1145#issuecomment-365863118 --- dnsapi/dns_ovh.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 296a2698..2669cc86 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -90,6 +90,10 @@ _initAuth() { return 1 fi + if [ "$OVH_AK" != "$(_readaccountconf OVH_AK)" ]; then + _info "It seems that your ovh key is changed, let's clear consumer key first." + _clearaccountconf OVH_CK + fi _saveaccountconf_mutable OVH_AK "$OVH_AK" _saveaccountconf_mutable OVH_AS "$OVH_AS" From a63766a0050065b90596eec429c93015a6099e3f Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Feb 2018 21:04:53 +0800 Subject: [PATCH 1294/1348] fix format --- README.md | 6 +++--- acme.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 66cac020..db2e024e 100644 --- a/README.md +++ b/README.md @@ -317,13 +317,13 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API + And: -1. 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.) +**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.)** - **More APIs coming soon...** If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project. diff --git a/acme.sh b/acme.sh index 8cd9c594..2be989f2 100755 --- a/acme.sh +++ b/acme.sh @@ -3598,7 +3598,7 @@ $_authorizations_map" _debug entry "$entry" if [ -z "$entry" ]; then _err "Error, can not get domain token entry $d" - _supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')" + _supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')" if [ "$_supported_vtypes" ]; then _err "The supported validation types are: $_supported_vtypes, but you specified: $vtype" fi From 90e587a9742569f2ba0752ac2d18a553869c05a4 Mon Sep 17 00:00:00 2001 From: Bob Belnap Date: Thu, 15 Feb 2018 15:34:47 -0500 Subject: [PATCH 1295/1348] add vault deploy hook script --- deploy/vault.sh | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 deploy/vault.sh diff --git a/deploy/vault.sh b/deploy/vault.sh new file mode 100644 index 00000000..b95d8af5 --- /dev/null +++ b/deploy/vault.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env sh + +# Here is a script to deploy cert to hashicorp vault +# (https://www.vaultproject.io/) +# +# it requires the vault binary to be available in PATH, and the following +# environment variables: +# +# VAULT_PREFIX - this contains the prefix path in vault +# VAULT_ADDR - vault requires this to find your vault server +# +# additionally, you need to ensure that VAULT_TOKEN is avialable or +# `vault auth` has applied the appropriate authorization for the vault binary +# to access the vault server + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +vault_deploy() { + + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + # validate required env vars + if [ -z "$VAULT_PREFIX" ] + then + _err "VAULT_PREFIX needs to be defined (contains prefix path in vault)" + return 1 + fi + + if [ -z "$VAULT_ADDR" ] + then + _err "VAULT_ADDR needs to be defined (contains vault connection address)" + return 1 + fi + + VAULT_CMD=$(which vault) + if [ ! $? ] + then + _err "cannot find vault binary!" + 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}/fullchain.pem" value=@"$_cfullchain" || return 1 + +} From d5865989cfb0a424362b364f04d5f88a5b264e35 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 16 Feb 2018 10:48:25 +0800 Subject: [PATCH 1296/1348] update doc --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index db2e024e..220168b7 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ https://github.com/Neilpang/acmetest - Webroot mode - Standalone mode - Apache mode -- Nginx mode ( Beta ) +- Nginx mode - DNS mode - [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) @@ -238,7 +238,7 @@ More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`. -Particularly, if you are running an Apache server, you should use Apache mode instead. This mode doesn't write any files to your web root folder. +Particularly, if you are running an Apache server, you can use Apache mode instead. This mode doesn't write any files to your web root folder. Just set string "apache" as the second argument and it will force use of apache plugin automatically. @@ -246,6 +246,10 @@ Just set string "apache" as the second argument and it will force use of apache acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com ``` +**This apache mode is only to issue the cert, it will not change your apache config files. +You will need to configure your website config files to use the cert by yourself. +We don't want to mess your apache server, don't worry.** + More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert # 7. Use Nginx mode @@ -266,6 +270,10 @@ So, the config is not changed. acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com ``` +**This apache mode is only to issue the cert, it will not change your apache config files. +You will need to configure your website config files to use the cert by yourself. +We don't want to mess your apache server, don't worry.** + More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert # 8. Automatic DNS API integration @@ -332,7 +340,7 @@ For more details: [How to use DNS API](dnsapi) # 9. Use DNS manual mode: -If your dns provider doesn't support any api access, you will have to add the txt record by your hand. +If your dns provider doesn't support any api access, you can add the txt record by your hand. ```bash acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com @@ -370,7 +378,7 @@ Ok, it's done. And we support them too! -Just set the `length` parameter with a prefix `ec-`. +Just set the `keylength` parameter with a prefix `ec-`. For example: @@ -386,7 +394,7 @@ 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 -d www.example.com --keylength ec-256 ``` -Please look at the last parameter above. +Please look at the `keylength` parameter above. Valid values are: From c1f5229906414e78d24330568409c9d91a4fef7a Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 16 Feb 2018 11:21:14 +0800 Subject: [PATCH 1297/1348] update doc --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 220168b7..1f9002c9 100644 --- a/README.md +++ b/README.md @@ -270,9 +270,9 @@ So, the config is not changed. acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com ``` -**This apache mode is only to issue the cert, it will not change your apache config files. +**This nginx mode is only to issue the cert, it will not change your nginx config files. You will need to configure your website config files to use the cert by yourself. -We don't want to mess your apache server, don't worry.** +We don't want to mess your nginx server, don't worry.** More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert From fac0beaa0ab48a6e63b08474c66b3159dd748bca Mon Sep 17 00:00:00 2001 From: Jose Luis Duran Date: Fri, 16 Feb 2018 11:23:10 -0200 Subject: [PATCH 1298/1348] Add support for strongSwan deploys in FreeBSD Related to 8ea800205c2e5496b63e3244dc4849d629acc1ad --- deploy/strongswan.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/strongswan.sh b/deploy/strongswan.sh index f991d690..3d5f1b34 100644 --- a/deploy/strongswan.sh +++ b/deploy/strongswan.sh @@ -22,6 +22,8 @@ strongswan_deploy() { _ipsec=/usr/sbin/ipsec elif [ -x /usr/sbin/strongswan ]; then _ipsec=/usr/sbin/strongswan + elif [ -x /usr/local/sbin/ipsec ]; then + _ipsec=/usr/local/sbin/ipsec else _err "no strongswan or ipsec command is detected" return 1 From b8418ced44167f1923354ff34441a58ddcef0d88 Mon Sep 17 00:00:00 2001 From: Bob Belnap Date: Fri, 16 Feb 2018 09:01:26 -0500 Subject: [PATCH 1299/1348] syntax fixes --- deploy/vault.sh | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/deploy/vault.sh b/deploy/vault.sh index b95d8af5..8a6c55be 100644 --- a/deploy/vault.sh +++ b/deploy/vault.sh @@ -33,21 +33,18 @@ vault_deploy() { _debug _cfullchain "$_cfullchain" # validate required env vars - if [ -z "$VAULT_PREFIX" ] - then + if [ -z "$VAULT_PREFIX" ]; then _err "VAULT_PREFIX needs to be defined (contains prefix path in vault)" return 1 fi - if [ -z "$VAULT_ADDR" ] - then + if [ -z "$VAULT_ADDR" ]; then _err "VAULT_ADDR needs to be defined (contains vault connection address)" return 1 fi VAULT_CMD=$(which vault) - if [ ! $? ] - then + if [ ! $? ]; then _err "cannot find vault binary!" return 1 fi From c86755f1ab80e0de9c238e266bdd05137b366000 Mon Sep 17 00:00:00 2001 From: Bob Belnap Date: Fri, 16 Feb 2018 09:19:47 -0500 Subject: [PATCH 1300/1348] format fix --- deploy/vault.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/vault.sh b/deploy/vault.sh index 8a6c55be..7b91ec51 100644 --- a/deploy/vault.sh +++ b/deploy/vault.sh @@ -44,7 +44,7 @@ vault_deploy() { fi VAULT_CMD=$(which vault) - if [ ! $? ]; then + if [ ! $? ]; then _err "cannot find vault binary!" return 1 fi From 6d6b2efdb5131e77a1c4efa08f857b29013ae1d3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 16 Feb 2018 23:16:25 +0800 Subject: [PATCH 1301/1348] fix he for solaris --- acme.sh | 2 +- dnsapi/dns_he.sh | 76 ++++++++++++++++++------------------------------ 2 files changed, 29 insertions(+), 49 deletions(-) diff --git a/acme.sh b/acme.sh index 2be989f2..4829507b 100755 --- a/acme.sh +++ b/acme.sh @@ -1838,7 +1838,7 @@ _send_signed_request() { _body="$response" if [ "$needbase64" ]; then _body="$(echo "$_body" | _dbase64)" - _debug2 _body "$_body" + _debug3 _body "$_body" fi if _contains "$_body" "JWS has invalid anti-replay nonce"; then diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 7b854ead..d1744dc4 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -75,17 +75,19 @@ dns_he_rm() { body="$body&hosted_dns_zoneid=$_zone_id" body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" - domain_regex="$(echo "$_full_domain" | sed 's/\./\\./g')" # escape dots - _record_id=$(_post "$body" "https://dns.he.net/" \ - | tr -d '\n' \ - | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${domain_regex}','TXT'\)" \ - | _egrep_o "[0-9]+','${domain_regex}','TXT'\)$" \ - | _egrep_o "^[0-9]+" - ) - # The series of egreps above could have been done a bit shorter but - # I wanted to double-check whether it's the correct record (in case - # HE changes their website somehow). + response="$(_post "$body" "https://dns.he.net/")" + _debug2 "response" "$response" + if ! _contains "$response" "$_txt_value"; then + _debug "The txt record is not found, just skip" + return 0 + fi + _record_id="$(echo "$response" | tr -d "#" | sed "s/ Date: Fri, 16 Feb 2018 15:40:05 -0200 Subject: [PATCH 1302/1348] Set the account key file permissions --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 4829507b..d958b074 100755 --- a/acme.sh +++ b/acme.sh @@ -1281,6 +1281,7 @@ _create_account_key() { else #generate account key _createkey "$length" "$ACCOUNT_KEY_PATH" + chmod 600 "$ACCOUNT_KEY_PATH" fi } From d84665cb64afb4dbb81eed775e50ce7f7fddf060 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Feb 2018 10:16:04 +0800 Subject: [PATCH 1303/1348] fix https://github.com/Neilpang/acme.sh/issues/1271 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 1586b73b..f79ccc85 100755 --- a/acme.sh +++ b/acme.sh @@ -2010,8 +2010,8 @@ _startserver() { SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork #Adding bind to local-address - if [ "$_local_address" ]; then - $SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${_local_address}" + if [ "$ncaddr" ]; then + $SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}" fi _debug "_NC" "$_NC" From 5c568d6999905414781812f2d8089fe6332d03b4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Feb 2018 10:31:34 +0800 Subject: [PATCH 1304/1348] https://github.com/Neilpang/acme.sh/issues/1277 --- acme.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index f79ccc85..20f446aa 100755 --- a/acme.sh +++ b/acme.sh @@ -2007,6 +2007,10 @@ _startserver() { _NC="$_NC -6" fi + if [ "$DEBUG" -gt "1" ]; then + _NC="$_NC -d -d -v" + fi + SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork #Adding bind to local-address @@ -2014,8 +2018,8 @@ _startserver() { $SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}" fi - _debug "_NC" "$_NC" - $_NC $SOCAT_OPTIONS SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK; echo ; echo $content; echo;" & + _debug "_NC" "$_NC $SOCAT_OPTIONS" + $_NC $SOCAT_OPTIONS SYSTEM:"sleep 0.5; echo HTTP/1.0 200 OK; echo ; echo $content; echo;" & serverproc="$!" } From b00919c6928571baacacb2210662ad30dc2b8ba0 Mon Sep 17 00:00:00 2001 From: nytral Date: Sat, 17 Feb 2018 15:08:13 +0100 Subject: [PATCH 1305/1348] various fixes --- dnsapi/dns_lua.sh | 6 ++++-- dnsapi/dns_nsone.sh | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index be678b9d..9bf8cd9c 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/bin/bash # bug reports to dev@1e.ca @@ -8,7 +8,6 @@ #LUA_Email="user@luadns.net" LUA_Api="https://api.luadns.com/v1" -LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) ######## Public functions ##################### @@ -19,6 +18,8 @@ dns_lua_add() { LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}" LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}" + LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) + if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then LUA_Key="" LUA_Email="" @@ -60,6 +61,7 @@ dns_lua_rm() { LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}" LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}" + LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index adf1f422..00e186d2 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -59,10 +59,10 @@ dns_nsone_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1) - _debug "record_id" "$record_id" + prev_txt=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",\"short_answers\":\[\"[^,]*\]" | _head_n 1 | cut -d: -f3 | cut -d, -f1) + _debug "prev_txt" "$prev_txt" - _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" + _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]},{\"answer\": $prev_txt}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then _info "Updated!" #todo: check if the record takes effect From 55787ff7b9d65ac64684dac19d7fe9bc5d1ba813 Mon Sep 17 00:00:00 2001 From: nytral Date: Sat, 17 Feb 2018 15:12:19 +0100 Subject: [PATCH 1306/1348] other fixes --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 9bf8cd9c..30c15579 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env sh # bug reports to dev@1e.ca From d6f8d6374231df715f02ec8efbdd5a8d6fee7118 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Feb 2018 12:43:56 +0800 Subject: [PATCH 1307/1348] fix https://github.com/Neilpang/acme.sh/issues/1286 --- dnsapi/dns_yandex.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 7ebb15dc..5fbb09d8 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,7 +16,7 @@ dns_yandex_add() { _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - curDomain=$(_PDD_get_domain "$fulldomain") + _PDD_get_domain "$fulldomain" _debug "Found suitable domain in pdd: $curDomain" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" @@ -33,7 +33,7 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain=$(_PDD_get_domain "$fulldomain") + _PDD_get_domain "$fulldomain" _debug "Found suitable domain in pdd: $curDomain" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" @@ -72,8 +72,8 @@ _PDD_get_domain() { if [ "$d" = "$__t" ]; then p=$(_math $k - 1) curSubdomain="$(echo "$fulldomain" | cut -d . -f "1-$p")" - echo "$__t" - return + curDomain="$__t" + return 0 fi done k=$(_math $k + 1) @@ -96,7 +96,7 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain=$(_PDD_get_domain "$fulldomain") + _PDD_get_domain "$fulldomain" _debug "Found suitable domain in pdd: $curDomain" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" From 41e3ecad4603c0dcac9d3e26db49cd02922e91bd Mon Sep 17 00:00:00 2001 From: Boyan Peychev Date: Mon, 19 Feb 2018 14:14:08 +0200 Subject: [PATCH 1308/1348] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_cloudns.sh | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 4a1ae641..c9d38ed8 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -26,30 +26,18 @@ dns_cloudns_add() { 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." + _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." return 0 } From 9ad7ac632aa6920d71b9aaa21f93a8cede0518fe Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Feb 2018 21:07:01 +0800 Subject: [PATCH 1309/1348] fix https://github.com/Neilpang/acme.sh/issues/1284#issuecomment-366616855 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 20f446aa..3aa2c7be 100755 --- a/acme.sh +++ b/acme.sh @@ -2007,7 +2007,7 @@ _startserver() { _NC="$_NC -6" fi - if [ "$DEBUG" -gt "1" ]; then + if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then _NC="$_NC -d -d -v" fi @@ -2015,7 +2015,7 @@ _startserver() { #Adding bind to local-address if [ "$ncaddr" ]; then - $SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}" + SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}" fi _debug "_NC" "$_NC $SOCAT_OPTIONS" From 48eaa0e5bfb7579b6719a640eb6253f92c93c842 Mon Sep 17 00:00:00 2001 From: Mal Graty Date: Mon, 19 Feb 2018 17:48:54 +0000 Subject: [PATCH 1310/1348] Let AWS DNS API code pull creds from instance role Add option (AWS_USE_INSTANCE_ROLE) to have the AWS DNS API driver pull the necessary credentials from the AWS EC2 instance metadata endpoint when required. This is a non-breaking change as it only takes effect when explicitly turned on via the environment variable, and fails safe back to the normal code path. --- dnsapi/dns_aws.sh | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 71f969f0..c754341c 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -9,6 +9,7 @@ AWS_HOST="route53.amazonaws.com" AWS_URL="https://$AWS_HOST" +AWS_METADATA_URL="http://169.254.169.254/latest/meta-data" AWS_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-use-Amazon-Route53-API" @@ -19,6 +20,10 @@ dns_aws_add() { fulldomain=$1 txtvalue=$2 + if [ -n "${AWS_USE_INSTANCE_ROLE:=$(_readaccountconf_mutable AWS_USE_INSTANCE_ROLE)}" ]; then + _use_instance_role + fi + AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then @@ -30,8 +35,12 @@ dns_aws_add() { fi #save for future use - _saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" - _saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" + if [ -n "$AWS_USE_INSTANCE_ROLE" ]; then + _saveaccountconf_mutable AWS_USE_INSTANCE_ROLE "$AWS_USE_INSTANCE_ROLE" + else + _saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" + _saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" + fi _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -76,6 +85,10 @@ dns_aws_rm() { fulldomain=$1 txtvalue=$2 + if [ -n "${AWS_USE_INSTANCE_ROLE:=$(_readaccountconf_mutable AWS_USE_INSTANCE_ROLE)}" ]; then + _use_instance_role + fi + AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" _debug "First detect the root zone" @@ -162,6 +175,34 @@ _get_root() { return 1 } +_use_instance_role() { + if ! _get "$AWS_METADATA_URL/iam/security-credentials/" true | _head_n 1 | grep -Fq 200; then + _err "Unable to fetch IAM role from AWS instance metadata." + return + fi + _aws_role=$(_get "$AWS_METADATA_URL/iam/security-credentials/") + _debug "_aws_role" "$_aws_role" + _aws_creds="$( + _get "$AWS_METADATA_URL/iam/security-credentials/$_aws_role" \ + | _normalizeJson \ + | tr '{,}' '\n' \ + | while read -r _line; do + _key="$(echo "${_line%%:*}" | tr -d '"')" + _value="${_line#*:}" + _debug3 "_key" "$_key" + _secure_debug3 "_value" "$_value" + case "$_key" in + AccessKeyId) echo "AWS_ACCESS_KEY_ID=$_value" ;; + SecretAccessKey) echo "AWS_SECRET_ACCESS_KEY=$_value" ;; + Token) echo "AWS_SESSION_TOKEN=$_value" ;; + esac + done \ + | paste -sd' ' - + )" + _secure_debug "_aws_creds" "$_aws_creds" + eval "$_aws_creds" +} + #method uri qstr data aws_rest() { mtd="$1" From 693627a858e22391201ef385388756508da9c070 Mon Sep 17 00:00:00 2001 From: Mal Graty Date: Tue, 20 Feb 2018 00:34:55 +0000 Subject: [PATCH 1311/1348] Emulate Boto when using role metadata Use the behavior established in the botocore python library to inform how and when instance metadata is fetched in an attempt to acquire valid AWS credentials. - Use it as a fallback when no other credentials are provided - Set the timeout of metadata requests to 1 second --- dnsapi/dns_aws.sh | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index c754341c..05a62008 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -20,12 +20,13 @@ dns_aws_add() { fulldomain=$1 txtvalue=$2 - if [ -n "${AWS_USE_INSTANCE_ROLE:=$(_readaccountconf_mutable AWS_USE_INSTANCE_ROLE)}" ]; then + AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" + AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" + + if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then _use_instance_role fi - AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" - AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then AWS_ACCESS_KEY_ID="" AWS_SECRET_ACCESS_KEY="" @@ -34,10 +35,8 @@ dns_aws_add() { return 1 fi - #save for future use - if [ -n "$AWS_USE_INSTANCE_ROLE" ]; then - _saveaccountconf_mutable AWS_USE_INSTANCE_ROLE "$AWS_USE_INSTANCE_ROLE" - else + #save for future use, unless using a role which will be fetched as needed + if [ -z "$_using_instance_role" ]; then _saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" _saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" fi @@ -85,12 +84,13 @@ dns_aws_rm() { fulldomain=$1 txtvalue=$2 - if [ -n "${AWS_USE_INSTANCE_ROLE:=$(_readaccountconf_mutable AWS_USE_INSTANCE_ROLE)}" ]; then + AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" + AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" + + if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then _use_instance_role fi - AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" - AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" @@ -176,14 +176,14 @@ _get_root() { } _use_instance_role() { - if ! _get "$AWS_METADATA_URL/iam/security-credentials/" true | _head_n 1 | grep -Fq 200; then + if ! _get "$AWS_METADATA_URL/iam/security-credentials/" true 1 | _head_n 1 | grep -Fq 200; then _err "Unable to fetch IAM role from AWS instance metadata." return fi - _aws_role=$(_get "$AWS_METADATA_URL/iam/security-credentials/") + _aws_role=$(_get "$AWS_METADATA_URL/iam/security-credentials/" "" 1) _debug "_aws_role" "$_aws_role" _aws_creds="$( - _get "$AWS_METADATA_URL/iam/security-credentials/$_aws_role" \ + _get "$AWS_METADATA_URL/iam/security-credentials/$_aws_role" "" 1 \ | _normalizeJson \ | tr '{,}' '\n' \ | while read -r _line; do @@ -201,6 +201,7 @@ _use_instance_role() { )" _secure_debug "_aws_creds" "$_aws_creds" eval "$_aws_creds" + _using_instance_role=true } #method uri qstr data From 5309afc347d22917cb250d59ca4c97638223decb Mon Sep 17 00:00:00 2001 From: Boyan Peychev Date: Tue, 20 Feb 2018 11:09:37 +0200 Subject: [PATCH 1312/1348] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_cloudns.sh | 49 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index c9d38ed8..dfab302b 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -60,22 +60,32 @@ dns_cloudns_rm() { 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" + _dns_cloudns_http_api_call "dns/records.json" "domain-name=$zone&host=$host&type=TXT" + if ! _contains "$response" "\"id\":"; then + return 1 + fi - 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 + for i in $(echo $response | tr '{' "\n" | grep $record); do + record_id=$(echo $i | tr ',' "\n"| grep -E '^"id"'| sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g'); + + if [ ! -z "$record_id" ]; then + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + _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." + else + _info "Deleted." + fi fi - _info "Deleted." - fi + done + return 0 } @@ -114,7 +124,7 @@ _dns_cloudns_init_check() { return 1 fi - #save the api id and password to the account conf file. + # save the api id and password to the account conf file. _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" _saveaccountconf_mutable CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID" _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" @@ -147,15 +157,6 @@ _dns_cloudns_get_zone_name() { 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 @@ -177,7 +178,7 @@ _dns_cloudns_http_api_call() { response="$(_get "$CLOUDNS_API/$method?$data")" - _debug2 response "$response" + _debug response "$response" return 0 } From 9f6832d636316e7dfacea6c93cf455a835b084ca Mon Sep 17 00:00:00 2001 From: Boyan Peychev Date: Tue, 20 Feb 2018 11:16:42 +0200 Subject: [PATCH 1313/1348] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_cloudns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index dfab302b..6f2cbfe6 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -66,8 +66,8 @@ dns_cloudns_rm() { return 1 fi - for i in $(echo $response | tr '{' "\n" | grep $record); do - record_id=$(echo $i | tr ',' "\n"| grep -E '^"id"'| sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g'); + for i in $(echo "$response" | tr '{' "\n" | grep $record); do + record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"'| sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g') if [ ! -z "$record_id" ]; then _debug zone "$zone" From 28355335f82a04f68a1aecbc1ce7bec865df4fe8 Mon Sep 17 00:00:00 2001 From: Boyan Peychev Date: Tue, 20 Feb 2018 11:22:06 +0200 Subject: [PATCH 1314/1348] Update dns api to support v2 wildcard cert #1261 --- dnsapi/dns_cloudns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 6f2cbfe6..df824e86 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -66,8 +66,8 @@ dns_cloudns_rm() { return 1 fi - for i in $(echo "$response" | tr '{' "\n" | grep $record); do - record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"'| sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g') + for i in $(echo "$response" | tr '{' "\n" | grep "$record"); do + record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g') if [ ! -z "$record_id" ]; then _debug zone "$zone" From 759f4f2c62bd5118495937713134f9e7960bd98e Mon Sep 17 00:00:00 2001 From: Mal Graty Date: Tue, 20 Feb 2018 12:40:24 +0000 Subject: [PATCH 1315/1348] Make the instance metadata fetcher self-contained This is to provide a clean path to future extension work such as adding a _use_container_role function to offer similar support for ECS containers. The $_using_role flag has also been made generic so that future role providers can also make use of it. --- dnsapi/dns_aws.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 05a62008..9c9e9313 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -9,7 +9,6 @@ AWS_HOST="route53.amazonaws.com" AWS_URL="https://$AWS_HOST" -AWS_METADATA_URL="http://169.254.169.254/latest/meta-data" AWS_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-use-Amazon-Route53-API" @@ -36,7 +35,7 @@ dns_aws_add() { fi #save for future use, unless using a role which will be fetched as needed - if [ -z "$_using_instance_role" ]; then + if [ -z "$_using_role" ]; then _saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" _saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" fi @@ -176,14 +175,16 @@ _get_root() { } _use_instance_role() { - if ! _get "$AWS_METADATA_URL/iam/security-credentials/" true 1 | _head_n 1 | grep -Fq 200; then + _url="http://169.254.169.254/latest/meta-data/iam/security-credentials/" + _debug "_url" "$_url" + if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then _err "Unable to fetch IAM role from AWS instance metadata." return fi - _aws_role=$(_get "$AWS_METADATA_URL/iam/security-credentials/" "" 1) + _aws_role=$(_get "$_url" "" 1) _debug "_aws_role" "$_aws_role" _aws_creds="$( - _get "$AWS_METADATA_URL/iam/security-credentials/$_aws_role" "" 1 \ + _get "$_url$_aws_role" "" 1 \ | _normalizeJson \ | tr '{,}' '\n' \ | while read -r _line; do @@ -201,7 +202,7 @@ _use_instance_role() { )" _secure_debug "_aws_creds" "$_aws_creds" eval "$_aws_creds" - _using_instance_role=true + _using_role=true } #method uri qstr data From 2c45f27356de74567ecd2fcc82842e9a8863ccc3 Mon Sep 17 00:00:00 2001 From: Bob Belnap Date: Tue, 20 Feb 2018 09:11:45 -0500 Subject: [PATCH 1316/1348] rename deploy hook vault to vault_cli --- deploy/{vault.sh => vault_cli.sh} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename deploy/{vault.sh => vault_cli.sh} (98%) diff --git a/deploy/vault.sh b/deploy/vault_cli.sh similarity index 98% rename from deploy/vault.sh rename to deploy/vault_cli.sh index 7b91ec51..02617c5e 100644 --- a/deploy/vault.sh +++ b/deploy/vault_cli.sh @@ -18,7 +18,7 @@ ######## Public functions ##################### #domain keyfile certfile cafile fullchain -vault_deploy() { +vault_cli_deploy() { _cdomain="$1" _ckey="$2" From bae50da799e73b8069393248824da3de14137e72 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Feb 2018 09:45:36 +0800 Subject: [PATCH 1317/1348] fix https://github.com/Neilpang/acme.sh/issues/1266 --- README.md | 4 +++- acme.sh | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1f9002c9..1e2defb7 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) # [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) -# Who are using **acme.sh** +# Who: - [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/) - [ruby-china.org](https://ruby-china.org/topics/31983) - [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer)) @@ -204,6 +204,8 @@ Install/copy the cert/key to the production Apache or Nginx path. The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`. +**Please take care: The reloadcmd is very important. The cert can be automatically renewed, but, without a correct 'reloadcmd' the cert may not be flushed to your server(like nginx or apache), then your website will not be able to show renewwed cert in 60 days.** + # 4. Use Standalone server to issue cert **(requires you to be root/sudoer or have permission to listen on port 80 (TCP))** diff --git a/acme.sh b/acme.sh index 3aa2c7be..a81b42d3 100755 --- a/acme.sh +++ b/acme.sh @@ -2019,7 +2019,7 @@ _startserver() { fi _debug "_NC" "$_NC $SOCAT_OPTIONS" - $_NC $SOCAT_OPTIONS SYSTEM:"sleep 0.5; echo HTTP/1.0 200 OK; echo ; echo $content; echo;" & + $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; echo HTTP/1.0 200 OK; echo ; echo $content; echo;" & serverproc="$!" } From 86ef0a260942ef5962ba01e0e7f1aeeeaaa846ab Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Feb 2018 10:05:27 +0800 Subject: [PATCH 1318/1348] fix https://github.com/Neilpang/acme.sh/issues/1295 --- acme.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index a81b42d3..56d10f88 100755 --- a/acme.sh +++ b/acme.sh @@ -5073,7 +5073,7 @@ _installalias() { } -# nocron confighome +# nocron confighome noprofile install() { if [ -z "$LE_WORKING_DIR" ]; then @@ -5082,6 +5082,7 @@ install() { _nocron="$1" _c_home="$2" + _noprofile="$3" if ! _initpath; then _err "Install failed." return 1 @@ -5147,7 +5148,7 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" - if [ "$IN_CRON" != "1" ]; then + if [ "$IN_CRON" != "1" ] && [ -z "$_noprofile" ]; then _installalias "$_c_home" fi @@ -5373,10 +5374,11 @@ Parameters: " } -# nocron +# nocron noprofile _installOnline() { _info "Installing from online archive." _nocron="$1" + _noprofile="$2" if [ ! "$BRANCH" ]; then BRANCH="master" fi @@ -5397,7 +5399,7 @@ _installOnline() { cd "$PROJECT_NAME-$BRANCH" chmod +x $PROJECT_ENTRY - if ./$PROJECT_ENTRY install "$_nocron"; then + if ./$PROJECT_ENTRY install "$_nocron" "" "$_noprofile"; then _info "Install success!" fi @@ -5413,7 +5415,7 @@ upgrade() { _initpath export LE_WORKING_DIR cd "$LE_WORKING_DIR" - _installOnline "nocron" + _installOnline "nocron" "noprofile" ); then _info "Upgrade success!" exit 0 From 58f753136a6b92607fe8767b3367ab56108efe56 Mon Sep 17 00:00:00 2001 From: hebbet Date: Wed, 21 Feb 2018 09:01:56 +0100 Subject: [PATCH 1319/1348] small typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e2defb7..ad2a2459 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ Install/copy the cert/key to the production Apache or Nginx path. The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`. -**Please take care: The reloadcmd is very important. The cert can be automatically renewed, but, without a correct 'reloadcmd' the cert may not be flushed to your server(like nginx or apache), then your website will not be able to show renewwed cert in 60 days.** +**Please take care: The reloadcmd is very important. The cert can be automatically renewed, but, without a correct 'reloadcmd' the cert may not be flushed to your server(like nginx or apache), then your website will not be able to show renewed cert in 60 days.** # 4. Use Standalone server to issue cert From f49f55f4a51e0e5eb84212d670a3ac373ff78acb Mon Sep 17 00:00:00 2001 From: Mal Graty Date: Tue, 20 Feb 2018 14:55:05 +0000 Subject: [PATCH 1320/1348] Pull AWS creds from container role Extend the AWS DNS API driver to support ECS container metadata by using the special environment variable ECS sets in containers. --- dnsapi/dns_aws.sh | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 9c9e9313..8ce7c347 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -23,7 +23,7 @@ dns_aws_add() { AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then - _use_instance_role + _use_container_role || _use_instance_role fi if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then @@ -87,7 +87,7 @@ dns_aws_rm() { AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then - _use_instance_role + _use_container_role || _use_instance_role fi _debug "First detect the root zone" @@ -174,17 +174,30 @@ _get_root() { return 1 } +_use_container_role() { + # automatically set if running inside ECS + if [ -z "$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" ]; then + _debug "No ECS environment variable detected" + return 1 + fi + _use_metadata "169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" +} + _use_instance_role() { _url="http://169.254.169.254/latest/meta-data/iam/security-credentials/" _debug "_url" "$_url" if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then - _err "Unable to fetch IAM role from AWS instance metadata." - return + _debug "Unable to fetch IAM role from instance metadata" + return 1 fi _aws_role=$(_get "$_url" "" 1) _debug "_aws_role" "$_aws_role" + _use_metadata "$_url$_aws_role" +} + +_use_metadata() { _aws_creds="$( - _get "$_url$_aws_role" "" 1 \ + _get "$1" "" 1 \ | _normalizeJson \ | tr '{,}' '\n' \ | while read -r _line; do @@ -201,6 +214,11 @@ _use_instance_role() { | paste -sd' ' - )" _secure_debug "_aws_creds" "$_aws_creds" + + if [ -z "$_aws_creds" ]; then + return 1 + fi + eval "$_aws_creds" _using_role=true } From 83b1a98db18dded8eecb21d3937e4339ca64a2d9 Mon Sep 17 00:00:00 2001 From: martgras Date: Sun, 18 Feb 2018 16:32:39 +0100 Subject: [PATCH 1321/1348] Azure DNS API - support for ACME v2 and reliability improvments support adding 2 txt records Adding retry logic for REST API calls Reusing bearer token removes 50% of required REST calls --- dnsapi/dns_azure.sh | 158 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 124 insertions(+), 34 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 0834ede7..677a9f75 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -1,5 +1,7 @@ #!/usr/bin/env sh +WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-use-Azure-DNS" + ######## Public functions ##################### # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -69,12 +71,36 @@ dns_azure_add() { acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" _debug "$acmeRecordURI" - body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" + # Get existing TXT record + _azure_rest GET "$acmeRecordURI" "" "$accesstoken" + values="{\"value\":[\"$txtvalue\"]}" + timestamp="$(_time)" + if [ "$_code" = "200" ]; then + vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"")" + _debug "existing TXT found" + _debug "$vlist" + existingts="$(echo "$response" | _egrep_o "\"acmetscheck\"\s*:\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")" + if [ -z "$existingts" ]; then + # the record was not created by acme.sh. Copy the exisiting entires + existingts=$timestamp + fi + _diff="$(_math "$timestamp - $existingts")" + _debug "existing txt age: $_diff" + # only use recently added records and discard if older than 2 hours because they are probably orphaned + if [ "$_diff" -lt 7200 ]; then + _debug "existing txt value: $vlist" + for v in $vlist; do + values="$values ,{\"value\":[\"$v\"]}" + done + fi + fi + # Add the txtvalue TXT Record + body="{\"properties\":{\"metadata\":{\"acmetscheck\":\"$timestamp\"},\"TTL\":10, \"TXTRecords\":[$values]}}" _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then - _info "validation record added" + _info "validation value added" else - _err "error adding validation record ($_code)" + _err "error adding validation value ($_code)" return 1 fi } @@ -141,13 +167,38 @@ dns_azure_rm() { acmeRecordURI="https://management.azure.com$(printf '%s' "$_domain_id" | sed 's/\\//g')/TXT/$_sub_domain?api-version=2017-09-01" _debug "$acmeRecordURI" - body="{\"properties\": {\"TTL\": 3600, \"TXTRecords\": [{\"value\": [\"$txtvalue\"]}]}}" - _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" - if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then - _info "validation record removed" - else - _err "error removing validation record ($_code)" - return 1 + # Get existing TXT record + _azure_rest GET "$acmeRecordURI" "" "$accesstoken" + timestamp="$(_time)" + if [ "$_code" = "200" ]; then + vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")" + values="" + comma="" + for v in $vlist; do + values="$values$comma{\"value\":[\"$v\"]}" + comma="," + done + if [ -z "$values" ]; then + # No values left remove record + _debug "removing validation record completely $acmeRecordURI" + _azure_rest DELETE "$acmeRecordURI" "" "$accesstoken" + if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then + _info "validation record removed" + else + _err "error removing validation record ($_code)" + return 1 + fi + else + # Remove only txtvalue from the TXT Record + body="{\"properties\":{\"metadata\":{\"acmetscheck\":\"$timestamp\"},\"TTL\":10, \"TXTRecords\":[$values]}}" + _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" + if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then + _info "validation value removed" + else + _err "error removing validation value ($_code)" + return 1 + fi + fi fi } @@ -159,52 +210,92 @@ _azure_rest() { data="$3" accesstoken="$4" - export _H1="authorization: Bearer $accesstoken" - export _H2="accept: application/json" - export _H3="Content-Type: application/json" - - _debug "$ep" - if [ "$m" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$ep" "" "$m")" - else - response="$(_get "$ep")" - fi - _debug2 response "$response" - - _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" - _debug2 "http response code $_code" - - if [ "$?" != "0" ]; then - _err "error $ep" + MAX_REQUEST_RETRY_TIMES=5 + _request_retry_times=0 + while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do + _debug3 _request_retry_times "$_request_retry_times" + export _H1="authorization: Bearer $accesstoken" + export _H2="accept: application/json" + export _H3="Content-Type: application/json" + # clear headers from previous request to avoid getting wrong http code on timeouts + :>"$HTTP_HEADER" + _debug "$ep" + if [ "$m" != "GET" ]; then + _secure_debug2 "data $data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _secure_debug2 "response $response" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug "http response code $_code" + if [ "$_code" = "401" ]; then + # we have an invalid access token set to expired + _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "0" + _err "access denied make sure your Azure settings are correct. See $WIKI" + return 1 + fi + # See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes + if [ "$?" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then + _request_retry_times="$(_math "$_request_retry_times" + 1)" + _info "REST call error $_code retrying $ep in $_request_retry_times s" + _sleep "$_request_retry_times" + continue + fi + break + done + if [ "$_request_retry_times" = "$MAX_REQUEST_RETRY_TIMES" ]; then + _err "Error Azure REST called was retried $MAX_REQUEST_RETRY_TIMES times." + _err "Calling $ep failed." return 1 fi + response="$(echo "$response" | _normalizeJson)" return 0 } ## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token _azure_getaccess_token() { - TENANTID=$1 + tenantID=$1 clientID=$2 clientSecret=$3 + accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}" + expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}" + + # can we reuse the bearer token? + if [ -n "$accesstoken" ] && [ -n "$expires_on" ]; then + if [ "$(_time)" -lt "$expires_on" ]; then + # brearer token is still valid - reuse it + _debug "reusing bearer token" + printf "%s" "$accesstoken" + return 0 + else + _debug "bearer token expired" + fi + fi + _debug "getting new bearer token" + export _H1="accept: application/json" export _H2="Content-Type: application/x-www-form-urlencoded" body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials" - _debug data "$body" - response="$(_post "$body" "https://login.windows.net/$TENANTID/oauth2/token" "" "POST")" + _secure_debug2 "data $body" + response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")" + _secure_debug2 "response $response" + response="$(echo "$response" | _normalizeJson)" accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") - _debug2 "response $response" + expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") if [ -z "$accesstoken" ]; then - _err "no acccess token received" + _err "no acccess token received. Check your Azure settings see $WIKI" return 1 fi if [ "$?" != "0" ]; then _err "error $response" return 1 fi + _saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$accesstoken" + _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on" printf "%s" "$accesstoken" return 0 } @@ -222,7 +313,6 @@ _get_root() { ## 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" - # Find matching domain name is Json response while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) From e26f9b8095291f83b4fa5a0a56f5958824b404f1 Mon Sep 17 00:00:00 2001 From: nytral Date: Sat, 24 Feb 2018 09:08:44 +0100 Subject: [PATCH 1322/1348] DNSMadeEasy ACMEv2 support --- dnsapi/dns_me.sh | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 3393fb75..dec07b71 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -45,8 +45,7 @@ dns_me_add() { count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) _debug count "$count" - if [ "$count" = "0" ]; then - _info "Adding record" +# _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then if printf -- "%s" "$response" | grep \"id\": >/dev/null; then _info "Added" @@ -58,20 +57,7 @@ dns_me_add() { fi fi _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) - _debug "record_id" "$record_id" - - _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" - if [ "$?" = "0" ]; then - _info "Updated" - #todo: check if the record takes effect - return 0 - fi - _err "Update error" return 1 - fi } @@ -96,7 +82,7 @@ dns_me_rm() { if [ "$count" = "0" ]; then _info "Don't need to remove." else - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o ",\"value\":\"..$txtvalue..\",\"id\":[^,]*" | cut -d : -f 3 | head -n 1) _debug "record_id" "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." @@ -152,7 +138,7 @@ _me_rest() { data="$3" _debug "$ep" - cdate=$(date -u +"%a, %d %b %Y %T %Z") + cdate=$(LANG=C date -u +"%a, %d %b %Y %T %Z") hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex) export _H1="x-dnsme-apiKey: $ME_Key" From 5a883889a221f9983ae6d5cc94f7271401f8b225 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 26 Feb 2018 14:53:31 +0100 Subject: [PATCH 1323/1348] fixes --- dnsapi/dns_me.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index dec07b71..ca36607f 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -43,8 +43,6 @@ dns_me_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) - _debug count "$count" # _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then if printf -- "%s" "$response" | grep \"id\": >/dev/null; then @@ -56,8 +54,6 @@ dns_me_add() { return 1 fi fi - _err "Add txt record error." - return 1 } From 3bc59a0327df3e1a1662fff2351ffd29c834ad6c Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 26 Feb 2018 21:47:51 +0100 Subject: [PATCH 1324/1348] first attempt to fix CI errors --- dnsapi/dns_me.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index ca36607f..382eeedd 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -43,17 +43,17 @@ dns_me_add() { return 1 fi -# _info "Adding record" - if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep \"id\": >/dev/null; then - _info "Added" - #todo: check if the record takes effect - return 0 - else - _err "Add txt record error." - return 1 - fi + _info "Adding record" + if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep \"id\": >/dev/null; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 fi + fi } From d064260bf1c6ae3403601314cac49ca0f2ddaea2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 1 Mar 2018 21:59:46 +0800 Subject: [PATCH 1325/1348] fix https://github.com/Neilpang/acme.sh/issues/1315 --- dnsapi/dns_he.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index d1744dc4..f42d56af 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -117,7 +117,7 @@ _find_zone() { _debug2 response "$response" _table="$(echo "$response" | tr -d "#" | sed "s/ Date: Thu, 1 Mar 2018 14:19:43 -0500 Subject: [PATCH 1326/1348] Rewrote to adapt the new name.com v4 API. --- dnsapi/dns_namecom.sh | 126 +++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 76 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 3af8bf4c..40908904 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -1,36 +1,42 @@ #!/usr/bin/env sh -#Author: RaidneII +#Author: RaidenII #Created 06/28/2017 +#Updated 03/01/2018, rewrote to support name.com API v4 #Utilize name.com API to finish dns-01 verifications. ######## Public functions ##################### -Namecom_API="https://api.name.com/api" +Namecom_API="https://api.name.com/v4" + +# First we need name.com credentials. +if [ -z "$Namecom_Username" ]; then + Namecom_Username="" + _err "Username for name.com is missing." + _err "Please specify that in your environment variable." + return 1 +fi + +if [ -z "$Namecom_Token" ]; then + Namecom_Token="" + _err "API token for name.com is missing." + _err "Please specify that in your environment variable." + return 1 +fi + +# Save them in configuration. +_saveaccountconf Namecom_Username "$Namecom_Username" +_saveaccountconf Namecom_Token "$Namecom_Token" + +# Auth string +# Name.com API v4 uses http basic auth to authenticate +# need to convert the token for http auth +_namecom_auth=`echo -n "$Namecom_Username:$Namecom_Token" | base64` #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { fulldomain=$1 txtvalue=$2 - # First we need name.com credentials. - if [ -z "$Namecom_Username" ]; then - Namecom_Username="" - _err "Username for name.com is missing." - _err "Please specify that in your environment variable." - return 1 - fi - - if [ -z "$Namecom_Token" ]; then - Namecom_Token="" - _err "API token for name.com is missing." - _err "Please specify that in your environment variable." - return 1 - fi - - # Save them in configuration. - _saveaccountconf Namecom_Username "$Namecom_Username" - _saveaccountconf Namecom_Token "$Namecom_Token" - # Login in using API if ! _namecom_login; then return 1 @@ -39,21 +45,18 @@ dns_namecom_add() { # Find domain in domain list. if ! _namecom_get_root "$fulldomain"; then _err "Unable to find domain specified." - _namecom_logout return 1 fi # Add TXT record. - _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" - if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then - retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ "$retcode" ]; then + _namecom_addtxt_json="{\"host\":\"$_sub_domain\",\"type\":\"TXT\",\"answer\":\"$txtvalue\",\"ttl\":\"300\"}" + if _namecom_rest POST "domains/$_domain/records" "$_namecom_addtxt_json"; then + _retvalue=$(printf "%s\n" "$response" | _egrep_o "\"$_sub_domain\"") + if [ "$_retvalue" ]; then _info "Successfully added TXT record, ready for validation." - _namecom_logout return 0 else _err "Unable to add the DNS record." - _namecom_logout return 1 fi fi @@ -72,37 +75,28 @@ dns_namecom_rm() { # Find domain in domain list. if ! _namecom_get_root "$fulldomain"; then _err "Unable to find domain specified." - _namecom_logout return 1 fi # Get the record id. - if _namecom_rest GET "dns/list/$_domain"; then - retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ "$retcode" ]; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4) - _debug record_id "$_record_id" + if _namecom_rest GET "domains/$_domain/records"; then + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\"" | cut -d \" -f 3 | _egrep_o [0-9]+) + _debug record_id "$_record_id" + if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." else _err "Unable to retrieve the record id." - _namecom_logout return 1 fi fi # Remove the DNS record using record id. - _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" - if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then - retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ "$retcode" ]; then - _info "Successfully removed the TXT record." - _namecom_logout - return 0 - else - _err "Unable to remove the DNS record." - _namecom_logout - return 1 - fi + if _namecom_rest DELETE "domains/$_domain/records/$_record_id"; then + _info "Successfully removed the TXT record." + return 0 + else + _err "Unable to delete record id." + return 1 fi } @@ -112,8 +106,9 @@ _namecom_rest() { param=$2 data=$3 - export _H1="Content-Type: application/json" - export _H2="Api-Session-Token: $sessionkey" + export _H1="Authorization: Basic $_namecom_auth" + export _H2="Content-Type: application/json" + if [ "$method" != "GET" ]; then response="$(_post "$data" "$Namecom_API/$param" "" "$method")" else @@ -125,25 +120,15 @@ _namecom_rest() { return 1 fi - _debug2 response "$response" + _debug response "$response" return 0 } _namecom_login() { - namecom_login_json="{\"username\":\"$Namecom_Username\",\"api_token\":\"$Namecom_Token\"}" - - if _namecom_rest POST "login" "$namecom_login_json"; then - retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + if _namecom_rest GET "hello"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"username\"\:\"$Namecom_Username\"") if [ "$retcode" ]; then - _info "Successfully logged in. Fetching session token..." - sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) - if [ ! -z "$sessionkey" ]; then - _debug sessionkey "$sessionkey" - _info "Session key obtained." - else - _err "Unable to get session key." - return 1 - fi + _info "Successfully logged in." else _err "Logging in failed." return 1 @@ -151,24 +136,12 @@ _namecom_login() { fi } -_namecom_logout() { - if _namecom_rest GET "logout"; then - retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ "$retcode" ]; then - _info "Successfully logged out." - else - _err "Error logging out." - return 1 - fi - fi -} - _namecom_get_root() { domain=$1 i=2 p=1 - if ! _namecom_rest GET "domain/list"; then + if ! _namecom_rest GET "domains"; then return 1 fi @@ -191,3 +164,4 @@ _namecom_get_root() { done return 1 } + From 14c27554369623e8162b11fe4b1007cc8479cebe Mon Sep 17 00:00:00 2001 From: TigerP Date: Thu, 1 Mar 2018 19:39:10 +0100 Subject: [PATCH 1327/1348] Add support for DirectAdmin --- dnsapi/README.md | 28 +++++++ dnsapi/dns_da.sh | 185 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100755 dnsapi/dns_da.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 8c43806c..4effb8d6 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -757,6 +757,34 @@ acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com The 'DH_API_KEY' will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 41. Use DirectAdmin API +The DirectAdmin interface has it's own Let's encrypt functionality, but this +script can be used to generate certificates for names which are not hosted on +DirectAdmin + +User must provide login data and URL to the DirectAdmin incl. port. +You can create an user which only has access to + +- CMD_API_DNS_CONTROL +- CMD_API_SHOW_DOMAINS + +By using the Login Keys function. +See also https://www.directadmin.com/api.php and https://www.directadmin.com/features.php?id=1298 + +``` +export DA_Api="https://remoteUser:remotePassword@da.domain.tld:8443" +export DA_Api_Insecure=1 +``` +Set `DA_Api_Insecure` to 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1) + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_da -d example.com -d www.example.com +``` + +The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_da.sh b/dnsapi/dns_da.sh new file mode 100755 index 00000000..0cf02c6a --- /dev/null +++ b/dnsapi/dns_da.sh @@ -0,0 +1,185 @@ +#!/usr/bin/env sh +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- +# vim: et ts=2 sw=2 +# +# DirectAdmin 1.41.0 API +# The DirectAdmin interface has it's own Let's encrypt functionality, but this +# script can be used to generate certificates for names which are not hosted on +# DirectAdmin +# +# User must provide login data and URL to DirectAdmin incl. port. +# You can create login key, by using the Login Keys function +# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to +# - CMD_API_DNS_CONTROL +# - CMD_API_SHOW_DOMAINS +# +# See also https://www.directadmin.com/api.php and +# https://www.directadmin.com/features.php?id=1298 +# +# Report bugs to https://github.com/TigerP/acme.sh/issues +# +# Values to export: +# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443" +# export DA_Api_Insecure=1 +# +# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is +# whether ssl cert is checked for validity (0) or whether it is just accepted +# (1) +# +######## Public functions ##################### + +# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_da_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_da_add() '${fulldomain}' '${txtvalue}'" + _DA_credentials && _DA_getDomainInfo && _DA_addTxt +} + +# Usage: dns_da_rm _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to remove the txt record after validation +dns_da_rm() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_da_rm() '${fulldomain}' '${txtvalue}'" + _DA_credentials && _DA_getDomainInfo && _DA_rmTxt +} + +#################### Private functions below ################################## +# Usage: _DA_credentials +# It will check if the needed settings are available +_DA_credentials() { + DA_Api="${DA_Api:-$(_readaccountconf_mutable DA_Api)}" + DA_Api_Insecure="${DA_Api_Insecure:-$(_readaccountconf_mutable DA_Api_Insecure)}" + if [ -z "${DA_Api}" ] || [ -z "${DA_Api_Insecure}" ]; then + DA_Api="" + DA_Api_Insecure="" + _err "You haven't specified the DirectAdmin Login data, URL and whether you want check the DirectAdmin SSL cert. Please try again." + return 1 + else + _saveaccountconf_mutable DA_Api "${DA_Api}" + _saveaccountconf_mutable DA_Api_Insecure "${DA_Api_Insecure}" + # Set whether curl should use secure or insecure mode + export HTTPS_INSECURE="${DA_Api_Insecure}" + fi +} + +# Usage: _get_root _acme-challenge.www.example.com +# Split the full domain to a domain and subdomain +#returns +# _sub_domain=_acme-challenge.www +# _domain=example.com +_get_root() { + domain=$1 + i=2 + p=1 + # Get a list of all the domains + # response will contain "list[]=example.com&list[]=example.org" + _da_api CMD_API_SHOW_DOMAINS "" ${domain} + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + # not valid + _debug "The given domain $h is not valid" + return 1 + fi + if _contains "$response" "$h" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + _debug "Stop on 100" + return 1 +} + +# Usage: _da_api CMD_API_* data example.com +# Use the DirectAdmin API and check the result +# returns +# response="error=0&text=Result text&details=" +_da_api() { + cmd=$1 + data=$2 + domain=$3 + _debug "$domain; $data" + response="$(_post "$data" "$DA_Api/$cmd" "" "POST")" + + if [ "$?" != "0" ]; then + _err "error $cmd" + return 1 + fi + _debug response "$response" + + case "${cmd}" in + CMD_API_DNS_CONTROL) + # Parse the result in general + # error=0&text=Records Deleted&details= + # error=1&text=Cannot View Dns Record&details=No domain provided + err_field="$(_getfield "$response" 1 '&')" + txt_field="$(_getfield "$response" 2 '&')" + details_field="$(_getfield "$response" 3 '&')" + error="$(_getfield "$err_field" 2 '=')" + text="$(_getfield "$txt_field" 2 '=')" + details="$(_getfield "$details_field" 2 '=')" + if [ "$error" != "0" ]; then + _err "error $response" + return 1 + fi + ;; + CMD_API_SHOW_DOMAINS) + ;; + esac + return 0 +} + +# Usage: _DA_getDomainInfo +# Get the root zone if possible +_DA_getDomainInfo() { + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + else + _debug "The root domain: $_domain" + _debug "The sub domain: $_sub_domain" + fi + return 0 +} + +# Usage: _DA_addTxt +# Use the API to add a record +_DA_addTxt() { + curData="domain=${_domain}&action=add&type=TXT&name=${_sub_domain}&value=\"${txtvalue}\"" + _debug "Calling _DA_addTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'" + _da_api CMD_API_DNS_CONTROL ${curData} ${_domain} + _debug "Result of _DA_addTxt: '$response'" + if _contains "${response}" 'error=0'; then + _debug "Add TXT succeeded" + return 0 + fi + _debug "Add TXT failed" + return 1 +} + +# Usage: _DA_rmTxt +# Use the API to remove a record +_DA_rmTxt() { + curData="domain=${_domain}&action=select&txtrecs0=name=${_sub_domain}&value=\"${txtvalue}\"" + _debug "Calling _DA_rmTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'" + if [ "$(_da_api CMD_API_DNS_CONTROL ${curData} ${_domain})" == "0" ]; then + _debug "Result of _DA_rmTxt: '$response'" + else + _err "Result of _DA_rmTxt: '$response'" + fi + if _contains "${response}" 'error=0'; then + _debug "RM TXT succeeded" + return 0 + fi + _debug "RM TXT failed" + return 1 +} + From 19277aec87f9fc2dfc8770f4a06a00d131bc7ef2 Mon Sep 17 00:00:00 2001 From: raidenii Date: Thu, 1 Mar 2018 14:29:14 -0500 Subject: [PATCH 1328/1348] Use printf instead of echo, hopefully fix SC2039. --- dnsapi/dns_namecom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 40908904..702bc6e2 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -30,7 +30,7 @@ _saveaccountconf Namecom_Token "$Namecom_Token" # Auth string # Name.com API v4 uses http basic auth to authenticate # need to convert the token for http auth -_namecom_auth=`echo -n "$Namecom_Username:$Namecom_Token" | base64` +_namecom_auth=`printf "$Namecom_Username:$Namecom_Token" | base64` #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { From a6c2d4b0e245829ff32555afe0891b15f12a8940 Mon Sep 17 00:00:00 2001 From: raidenii Date: Thu, 1 Mar 2018 14:38:49 -0500 Subject: [PATCH 1329/1348] Another fix. --- dnsapi/dns_namecom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 702bc6e2..2d3293c8 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -30,7 +30,7 @@ _saveaccountconf Namecom_Token "$Namecom_Token" # Auth string # Name.com API v4 uses http basic auth to authenticate # need to convert the token for http auth -_namecom_auth=`printf "$Namecom_Username:$Namecom_Token" | base64` +_namecom_auth=$(printf "$Namecom_Username:$Namecom_Token" | base64) #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { From 3e1a94cbcdf6c82958c19b29b3cf8e9317399dda Mon Sep 17 00:00:00 2001 From: raidenii Date: Thu, 1 Mar 2018 14:43:08 -0500 Subject: [PATCH 1330/1348] Yet another fix. --- dnsapi/dns_namecom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 2d3293c8..667f7688 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -30,7 +30,7 @@ _saveaccountconf Namecom_Token "$Namecom_Token" # Auth string # Name.com API v4 uses http basic auth to authenticate # need to convert the token for http auth -_namecom_auth=$(printf "$Namecom_Username:$Namecom_Token" | base64) +_namecom_auth=$(printf "%s:%s" "$Namecom_Username" "$Namecom_Token" | base64) #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { From 628a6ffa073f8f4bf1144b8f240d84cf28d1b66b Mon Sep 17 00:00:00 2001 From: raidenii Date: Thu, 1 Mar 2018 15:03:28 -0500 Subject: [PATCH 1331/1348] Tried to fix some weird problems --- dnsapi/dns_namecom.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 667f7688..bb813bdd 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -164,4 +164,3 @@ _namecom_get_root() { done return 1 } - From 399d6592b839f9e937a843d7bb230983b47c0f3e Mon Sep 17 00:00:00 2001 From: TigerP Date: Thu, 1 Mar 2018 21:25:24 +0100 Subject: [PATCH 1332/1348] Fix some quotes and a check --- dnsapi/dns_da.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_da.sh b/dnsapi/dns_da.sh index 0cf02c6a..598c1714 100755 --- a/dnsapi/dns_da.sh +++ b/dnsapi/dns_da.sh @@ -76,7 +76,7 @@ _get_root() { p=1 # Get a list of all the domains # response will contain "list[]=example.com&list[]=example.org" - _da_api CMD_API_SHOW_DOMAINS "" ${domain} + _da_api CMD_API_SHOW_DOMAINS "" "${domain}" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" @@ -125,13 +125,13 @@ _da_api() { error="$(_getfield "$err_field" 2 '=')" text="$(_getfield "$txt_field" 2 '=')" details="$(_getfield "$details_field" 2 '=')" + _debug "error: ${error}, text: ${text}, details: ${details}" if [ "$error" != "0" ]; then _err "error $response" return 1 fi ;; - CMD_API_SHOW_DOMAINS) - ;; + CMD_API_SHOW_DOMAINS) ;; esac return 0 } @@ -155,7 +155,7 @@ _DA_getDomainInfo() { _DA_addTxt() { curData="domain=${_domain}&action=add&type=TXT&name=${_sub_domain}&value=\"${txtvalue}\"" _debug "Calling _DA_addTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'" - _da_api CMD_API_DNS_CONTROL ${curData} ${_domain} + _da_api CMD_API_DNS_CONTROL "${curData}" "${_domain}" _debug "Result of _DA_addTxt: '$response'" if _contains "${response}" 'error=0'; then _debug "Add TXT succeeded" @@ -170,7 +170,7 @@ _DA_addTxt() { _DA_rmTxt() { curData="domain=${_domain}&action=select&txtrecs0=name=${_sub_domain}&value=\"${txtvalue}\"" _debug "Calling _DA_rmTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'" - if [ "$(_da_api CMD_API_DNS_CONTROL ${curData} ${_domain})" == "0" ]; then + if _da_api CMD_API_DNS_CONTROL "${curData}" "${_domain}"; then _debug "Result of _DA_rmTxt: '$response'" else _err "Result of _DA_rmTxt: '$response'" From e8d808d708d997cc92f0bfbeace3d9431d8f4553 Mon Sep 17 00:00:00 2001 From: TigerP Date: Sat, 3 Mar 2018 14:40:23 +0100 Subject: [PATCH 1333/1348] Remove empty line at the end --- dnsapi/dns_da.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_da.sh b/dnsapi/dns_da.sh index 598c1714..7755c7e1 100755 --- a/dnsapi/dns_da.sh +++ b/dnsapi/dns_da.sh @@ -182,4 +182,3 @@ _DA_rmTxt() { _debug "RM TXT failed" return 1 } - From 2d7b9817cb4f694ef1ec717e5f363a1fc356d52e Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Sat, 3 Mar 2018 16:27:17 +0100 Subject: [PATCH 1334/1348] Fix typos --- deploy/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index cab1f4fb..0b820dff 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -114,8 +114,8 @@ user Any backups older than 180 days will be deleted when new certificates are deployed. This defaults to "yes" set to "no" to disable backup. -###Eamples using SSH deploy -The following example illustrates deploying certifcates to a QNAP NAS +###Examples using SSH deploy +The following example illustrates deploying certificates to a QNAP NAS (tested with QTS version 4.2.3) ```sh @@ -132,8 +132,8 @@ the same file. This will result in the certificate being appended to the same file as the private key... a common requirement of several services. -The next example illustates deploying certificates to a Unifi -Contolller (tested with version 5.4.11). +The next example illustrates deploying certificates to a Unifi +Controller (tested with version 5.4.11). ```sh export DEPLOY_SSH_USER="root" @@ -153,9 +153,9 @@ export DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \ acme.sh --deploy -d unifi.example.com --deploy-hook ssh ``` -In this exmple we execute several commands on the remote host +In this example we execute several commands on the remote host after the certificate files have been copied... to generate a pkcs12 file -compatible with Unifi, to import it into the Unifi keystore and then finaly +compatible with Unifi, to import it into the Unifi keystore and then finally to restart the service. Note also that once the certificate is imported @@ -233,7 +233,7 @@ DEPLOY_CPANEL_USER is required only if you run the script as root and it should export DEPLOY_CPANEL_USER=username acme.sh --deploy -d example.com --deploy-hook cpanel_uapi ``` -Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain. +Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separate certificate for each domain. ## 8. Deploy the cert to your FRITZ!Box router From 9fa207e613cc417514f1a97b3c5ada10b81076e1 Mon Sep 17 00:00:00 2001 From: raidenii Date: Sun, 4 Mar 2018 14:13:14 -0500 Subject: [PATCH 1335/1348] Move code to fit DNS API dev guide. --- dnsapi/dns_namecom.sh | 48 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index bb813bdd..931bf30e 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -8,35 +8,30 @@ Namecom_API="https://api.name.com/v4" -# First we need name.com credentials. -if [ -z "$Namecom_Username" ]; then - Namecom_Username="" - _err "Username for name.com is missing." - _err "Please specify that in your environment variable." - return 1 -fi - -if [ -z "$Namecom_Token" ]; then - Namecom_Token="" - _err "API token for name.com is missing." - _err "Please specify that in your environment variable." - return 1 -fi - -# Save them in configuration. -_saveaccountconf Namecom_Username "$Namecom_Username" -_saveaccountconf Namecom_Token "$Namecom_Token" - -# Auth string -# Name.com API v4 uses http basic auth to authenticate -# need to convert the token for http auth -_namecom_auth=$(printf "%s:%s" "$Namecom_Username" "$Namecom_Token" | base64) - #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { fulldomain=$1 txtvalue=$2 + # First we need name.com credentials. + if [ -z "$Namecom_Username" ]; then + Namecom_Username="" + _err "Username for name.com is missing." + _err "Please specify that in your environment variable." + return 1 + fi + + if [ -z "$Namecom_Token" ]; then + Namecom_Token="" + _err "API token for name.com is missing." + _err "Please specify that in your environment variable." + return 1 + fi + + # Save them in configuration. + _saveaccountconf Namecom_Username "$Namecom_Username" + _saveaccountconf Namecom_Token "$Namecom_Token" + # Login in using API if ! _namecom_login; then return 1 @@ -125,6 +120,11 @@ _namecom_rest() { } _namecom_login() { + # Auth string + # Name.com API v4 uses http basic auth to authenticate + # need to convert the token for http auth + _namecom_auth=$(printf "%s:%s" "$Namecom_Username" "$Namecom_Token" | base64) + if _namecom_rest GET "hello"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"username\"\:\"$Namecom_Username\"") if [ "$retcode" ]; then From 508012342daf716d3c99228a1bec5f7c893285a9 Mon Sep 17 00:00:00 2001 From: raidenii Date: Sun, 4 Mar 2018 17:22:13 -0500 Subject: [PATCH 1336/1348] Make sure the removal of DNS record is the desired one (i.e., by txtvalue) --- dnsapi/dns_namecom.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 931bf30e..e8bce7b3 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -75,7 +75,7 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "domains/$_domain/records"; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\"" | cut -d \" -f 3 | _egrep_o [0-9]+) + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\",\"fqdn\":\"$fulldomain.\",\"type\":\"$txtvalue\"" | cut -d \" -f 3 | _egrep_o [0-9]+) _debug record_id "$_record_id" if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." @@ -115,7 +115,7 @@ _namecom_rest() { return 1 fi - _debug response "$response" + _debug2 response "$response" return 0 } From 3052ba433a70aae287f0fa90698f0bf8081db58e Mon Sep 17 00:00:00 2001 From: raidenii Date: Sun, 4 Mar 2018 17:27:34 -0500 Subject: [PATCH 1337/1348] Fix an obvious stupidity. --- dnsapi/dns_namecom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index e8bce7b3..b712fa94 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -75,7 +75,7 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "domains/$_domain/records"; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\",\"fqdn\":\"$fulldomain.\",\"type\":\"$txtvalue\"" | cut -d \" -f 3 | _egrep_o [0-9]+) + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\",\"fqdn\":\"$fulldomain.\",\"type\":\"TXT\",\"answer\":\"$txtvalue\"" | cut -d \" -f 3 | _egrep_o [0-9]+) _debug record_id "$_record_id" if [ "$_record_id" ]; then _info "Successfully retrieved the record id for ACME challenge." From 2bbc25c1ebfbb478fbc182f9b0a322335c2bfebd Mon Sep 17 00:00:00 2001 From: TigerP Date: Tue, 6 Mar 2018 17:00:19 +0100 Subject: [PATCH 1338/1348] Add DirectAdmin to the main README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1e2defb7..4565b464 100644 --- a/README.md +++ b/README.md @@ -326,6 +326,7 @@ You don't have to do anything manually! 1. selectel.com(selectel.ru) DNS API 1. zonomi.com DNS API 1. DreamHost.com API +1. DirectAdmin API And: From 7445a3be591b8804ef29b693a7e4df64a00497de Mon Sep 17 00:00:00 2001 From: jim-p Date: Tue, 6 Mar 2018 17:00:57 -0500 Subject: [PATCH 1339/1348] Add ACME v2 test around cert copy. Fixes #1330 Without this, the work done a few lines above is clobbered, leaving the fullchain.cer containing only the certificate, not the CA and certificate chain. --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2ca7fa97..5ea331c9 100755 --- a/acme.sh +++ b/acme.sh @@ -4078,7 +4078,9 @@ $_authorizations_map" _info "Your cert key is in $(__green " $CERT_KEY_PATH ")" fi - cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" + if [ "$ACME_VERSION" != "2" ]; then + cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" + fi if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then USER_PATH="$PATH" From e1db5db8ac4604c123fbbfe3c87615b25657820c Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Mar 2018 21:25:07 +0800 Subject: [PATCH 1340/1348] fix https://github.com/Neilpang/acme.sh/issues/1105 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5ea331c9..550d89b2 100755 --- a/acme.sh +++ b/acme.sh @@ -1841,7 +1841,7 @@ _send_signed_request() { _body="$response" if [ "$needbase64" ]; then - _body="$(echo "$_body" | _dbase64)" + _body="$(echo "$_body" | _dbase64 | tr -d '\0')" _debug3 _body "$_body" fi From 45e386b26ddf69bb614278767e425a88809a5cfc Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 8 Mar 2018 19:49:53 +0800 Subject: [PATCH 1341/1348] fix https://github.com/Neilpang/acme.sh/issues/1336 --- acme.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 550d89b2..f906d0a2 100755 --- a/acme.sh +++ b/acme.sh @@ -63,6 +63,7 @@ END_CSR="-----END CERTIFICATE REQUEST-----" BEGIN_CERT="-----BEGIN CERTIFICATE-----" END_CERT="-----END CERTIFICATE-----" +CONTENT_TYPE_JSON="application/jose+json" RENEW_SKIP=2 ECC_SEP="_" @@ -1591,12 +1592,13 @@ _inithttp() { } -# body url [needbase64] [POST|PUT] +# body url [needbase64] [POST|PUT] [ContentType] _post() { body="$1" _post_url="$2" needbase64="$3" httpmethod="$4" + _postContentType="$5" if [ -z "$httpmethod" ]; then httpmethod="POST" @@ -1612,6 +1614,9 @@ _post() { if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " fi + if [ "$_postContentType" ]; then + _CURL="$_CURL -H \"Content-Type: $_postContentType\" " + fi _debug "_CURL" "$_CURL" if [ "$needbase64" ]; then response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" @@ -1631,6 +1636,9 @@ _post() { if [ "$HTTPS_INSECURE" ]; then _WGET="$_WGET --no-check-certificate " fi + if [ "$_postContentType" ]; then + _WGET="$_WGET --header \"Content-Type: $_postContentType\" " + fi _debug "_WGET" "$_WGET" if [ "$needbase64" ]; then if [ "$httpmethod" = "POST" ]; then @@ -1765,7 +1773,7 @@ _send_signed_request() { if [ "$ACME_NEW_NONCE" ]; then _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" - if _post "" "$nonceurl" "" "HEAD"; then + if _post "" "$nonceurl" "" "HEAD" "$CONTENT_TYPE_JSON"; then _headers="$(cat "$HTTP_HEADER")" fi fi @@ -1820,7 +1828,7 @@ _send_signed_request() { fi _debug3 body "$body" - response="$(_post "$body" "$url" "$needbase64")" + response="$(_post "$body" "$url" "$needbase64" "POST" "$CONTENT_TYPE_JSON")" _CACHED_NONCE="" if [ "$?" != "0" ]; then From ef871775b72e0cd201276c9fafa68e0c129f8765 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 8 Mar 2018 21:27:52 +0800 Subject: [PATCH 1342/1348] fix https://github.com/Neilpang/acme.sh/issues/1336 for wget --- acme.sh | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index f906d0a2..a93ada8c 100755 --- a/acme.sh +++ b/acme.sh @@ -1636,21 +1636,34 @@ _post() { if [ "$HTTPS_INSECURE" ]; then _WGET="$_WGET --no-check-certificate " fi - if [ "$_postContentType" ]; then - _WGET="$_WGET --header \"Content-Type: $_postContentType\" " - fi _debug "_WGET" "$_WGET" if [ "$needbase64" ]; then if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + fi else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + fi fi else if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + fi else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + fi fi fi _ret="$?" From 183063a244b389ff125425a5bd14c237b64de259 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 9 Mar 2018 08:06:42 +0800 Subject: [PATCH 1343/1348] add more safe check --- acme.sh | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index a93ada8c..914292bc 100755 --- a/acme.sh +++ b/acme.sh @@ -849,6 +849,16 @@ _dbase64() { fi } +#file +_checkcert() { + _cf="$1" + if [ "$DEBUG" ]; then + openssl x509 -noout -text -in "$_cf" + else + openssl x509 -noout -text -in "$_cf" >/dev/null 2>&1 + fi +} + #Usage: hashalg [outputhex] #Output Base64-encoded digest _digest() { @@ -4089,6 +4099,13 @@ $_authorizations_map" _debug "Le_LinkCert" "$Le_LinkCert" _savedomainconf "Le_LinkCert" "$Le_LinkCert" + if [ -z "$Le_LinkCert" ] || ! _checkcert "$CERT_PATH"; then + response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)" + _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" + _on_issue_err "$_post_hook" + return 1 + fi + if [ "$Le_LinkCert" ]; then _info "$(__green "Cert success.")" cat "$CERT_PATH" @@ -4099,28 +4116,18 @@ $_authorizations_map" _info "Your cert key is in $(__green " $CERT_KEY_PATH ")" fi - if [ "$ACME_VERSION" != "2" ]; then - cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" - fi - if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then USER_PATH="$PATH" _saveaccountconf "USER_PATH" "$USER_PATH" fi fi - if [ -z "$Le_LinkCert" ]; then - response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)" - _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" - _on_issue_err "$_post_hook" - return 1 - fi - _cleardomainconf "Le_Vlist" if [ "$ACME_VERSION" = "2" ]; then _debug "v2 chain." else + cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') if [ "$Le_LinkIssuer" ]; then @@ -4144,6 +4151,10 @@ $_authorizations_map" echo "$BEGIN_CERT" >"$CA_CERT_PATH" _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" echo "$END_CERT" >>"$CA_CERT_PATH" + if !_checkcert "$CA_CERT_PATH"; then + _err "Can not get the ca cert." + break + fi cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" rm -f "$CA_CERT_PATH.der" break From 7e381f8e5d5f9f95cb914102200481d7c77a7e45 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 9 Mar 2018 08:09:32 +0800 Subject: [PATCH 1344/1348] fix format --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 914292bc..cf3a8ac2 100755 --- a/acme.sh +++ b/acme.sh @@ -853,9 +853,9 @@ _dbase64() { _checkcert() { _cf="$1" if [ "$DEBUG" ]; then - openssl x509 -noout -text -in "$_cf" + openssl x509 -noout -text -in "$_cf" else - openssl x509 -noout -text -in "$_cf" >/dev/null 2>&1 + openssl x509 -noout -text -in "$_cf" >/dev/null 2>&1 fi } From 716f727753c18527b909ea3207ad8a72fbf110fd Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 9 Mar 2018 20:14:41 +0800 Subject: [PATCH 1345/1348] fix https://github.com/Neilpang/acme.sh/issues/1105 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index cf3a8ac2..0fe6b819 100755 --- a/acme.sh +++ b/acme.sh @@ -4100,7 +4100,7 @@ $_authorizations_map" _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ -z "$Le_LinkCert" ] || ! _checkcert "$CERT_PATH"; then - response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)" + response="$(echo "$response" | _dbase64 "multiline" | tr -d '\0' | _normalizeJson)" _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" _on_issue_err "$_post_hook" return 1 From e3ddb677e174c033282c78e50e1135a10380c8a8 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Fri, 9 Mar 2018 16:39:08 -0500 Subject: [PATCH 1346/1348] Adding support for API v2 (multiple TXT records) --- dnsapi/dns_freedns.sh | 146 ++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 91 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index afd8b796..1f03791a 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,8 +53,9 @@ dns_freedns_add() { i="$(_math "$i" - 1)" sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" - _debug top_domain "$top_domain" - _debug sub_domain "$sub_domain" + _debug "top_domain: $top_domain" + _debug "sub_domain: $sub_domain" + # Sometimes FreeDNS does not return the subdomain page but rather # returns a page regarding becoming a premium member. This usually # happens after a period of inactivity. Immediately trying again @@ -63,6 +64,7 @@ dns_freedns_add() { attempts=2 while [ "$attempts" -gt "0" ]; do attempts="$(_math "$attempts" - 1)" + htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" if [ "$?" != "0" ]; then if [ "$using_cached_cookies" = "true" ]; then @@ -71,10 +73,9 @@ dns_freedns_add() { fi return 1 fi - _debug2 htmlpage "$htmlpage" subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep "$top_domain")" - _debug2 subdomain_csv "$subdomain_csv" + _debug3 "subdomain_csv: $subdomain_csv" # The above beauty ends with striping out rows that do not have an # href to edit.php and do not have the top domain we are looking for. @@ -85,55 +86,25 @@ dns_freedns_add() { lines="$(echo "$subdomain_csv" | wc -l)" i=0 found=0 + DNSdomainid="" while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" line="$(echo "$subdomain_csv" | sed -n "${i}p")" - _debug2 line "$line" + _debug2 "line $line" if [ $found = 0 ] && _contains "$line" ""; then # this line will contain DNSdomainid for the top_domain DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)" - _debug2 DNSdomainid "$DNSdomainid" + _debug2 "DNSdomainid: $DNSdomainid" found=1 - else - # lines contain DNS records for all subdomains - DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" - _debug2 DNSname "$DNSname" - DNStype="$(echo "$line" | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")" - _debug2 subdomain_csv "$subdomain_csv" + _debug3 "subdomain_csv: $subdomain_csv" # The above beauty ends with striping out rows that do not have an # href to edit.php and do not have the domain name we are looking for. @@ -216,35 +164,51 @@ dns_freedns_rm() { lines="$(echo "$subdomain_csv" | wc -l)" i=0 found=0 + DNSdataid="" while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" line="$(echo "$subdomain_csv" | sed -n "${i}p")" - _debug2 line "$line" + _debug3 "line: $line" DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" - _debug2 DNSname "$DNSname" - DNStype="$(echo "$line" | sed 's/"; then # this line will contain DNSdomainid for the top_domain DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)" _debug2 "DNSdomainid: $DNSdomainid" found=1 - break; + break fi done @@ -191,7 +191,7 @@ dns_freedns_rm() { fi _debug2 "DNSvalue: $DNSvalue" - if [ -n "$DNSdataid" ] && _startswith "$txtvalue" "$DNSvalue"; then + if [ -n "$DNSdataid" ] && _startswith "$txtvalue" "$DNSvalue"; then # Found a match. But note... Website is truncating the # value field so we are only testing that part that is not # truncated. This should be accurate enough. From a5a0e564dd5682ca12bdcd66dd2d9cd6e9afb9be Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Mar 2018 10:33:33 +0800 Subject: [PATCH 1348/1348] fix https://github.com/Neilpang/acme.sh/issues/1322 --- acme.sh | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/acme.sh b/acme.sh index 0fe6b819..2a3138cb 100755 --- a/acme.sh +++ b/acme.sh @@ -5399,7 +5399,6 @@ Parameters: --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --standalone Use standalone mode. --stateless Use stateless mode, see: $_STATELESS_WIKI - --tls Use standalone tls mode. --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. --dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds. @@ -5429,7 +5428,6 @@ 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. @@ -5780,14 +5778,6 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; - --tls) - wvalue="$W_TLS" - if [ -z "$_webroot" ]; then - _webroot="$wvalue" - else - _webroot="$_webroot,$wvalue" - fi - ;; --dns) wvalue="dns" if [ "$2" ] && ! _startswith "$2" "-"; then @@ -5883,12 +5873,6 @@ _process() { Le_HTTPPort="$_httpport" shift ;; - --tlsport) - _tlsport="$2" - Le_TLSPort="$_tlsport" - shift - ;; - --listraw) _listraw="raw" ;;
$top_domain' -f 2 | cut -d '<' -f 1)" - _debug2 DNStype "$DNStype" - if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" - # Now get current value for the TXT record. This method may - # not produce accurate results as the value field is truncated - # on this webpage. To get full value we would need to load - # another page. However we don't really need this so long as - # there is only one TXT record for the acme challenge subdomain. - DNSvalue="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" - _debug2 DNSvalue "$DNSvalue" - if [ $found != 0 ]; then - break - # we are breaking out of the loop at the first match of DNS name - # and DNS type (if we are past finding the domainid). This assumes - # that there is only ever one TXT record for the LetsEncrypt/acme - # challenge subdomain. This seems to be a reasonable assumption - # as the acme client deletes the TXT record on successful validation. - fi - else - DNSname="" - DNStype="" - fi + break; fi done - _debug "DNSname: $DNSname DNStype: $DNStype DNSdomainid: $DNSdomainid DNSdataid: $DNSdataid" - _debug "DNSvalue: $DNSvalue" - if [ -z "$DNSdomainid" ]; then # If domain ID is empty then something went wrong (top level # domain not found at FreeDNS). if [ "$attempts" = "0" ]; then # exhausted maximum retry attempts - _debug "$htmlpage" - _debug "$subdomain_csv" _err "Domain $top_domain not found at FreeDNS" return 1 fi @@ -145,33 +116,10 @@ dns_freedns_add() { _info "Retry loading subdomain page ($attempts attempts remaining)" done - if [ -z "$DNSdataid" ]; then - # If data ID is empty then specific subdomain does not exist yet, need - # to create it this should always be the case as the acme client - # deletes the entry after domain is validated. - _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" - return $? - else - if [ "$txtvalue" = "$DNSvalue" ]; then - # if value in TXT record matches value requested then DNS record - # does not need to be updated. But... - # Testing value match fails. Website is truncating the value field. - # So for now we will always go down the else path. Though in theory - # should never come here anyway as the acme client deletes - # the TXT record on successful validation, so we should not even - # have found a TXT record !! - _info "No update necessary for $fulldomain at FreeDNS" - return 0 - else - # Delete the old TXT record (with the wrong value) - if _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"; then - # And add in new TXT record with the value provided - _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" - fi - return $? - fi - fi - return 0 + # Add in new TXT record with the value provided + _debug "Adding TXT record for $fulldomain, $txtvalue" + _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" + return $? } #Usage: fulldomain txtvalue @@ -205,7 +153,7 @@ dns_freedns_rm() { fi subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's/
' -f 2 | cut -d '<' -f 1)" - _debug2 DNStype "$DNStype" - if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" - _debug2 DNSdataid "$DNSdataid" - DNSvalue="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" - _debug2 DNSvalue "$DNSvalue" - # if [ "$DNSvalue" = "$txtvalue" ]; then - # Testing value match fails. Website is truncating the value - # field. So for now we will assume that there is only one TXT - # field for the sub domain and just delete it. Currently this - # is a safe assumption. - _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" - return $? - # fi + _debug2 "DNSname: $DNSname" + if [ "$DNSname" = "$fulldomain" ]; then + DNStype="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" + _debug2 "DNStype: $DNStype" + if [ "$DNStype" = "TXT" ]; then + DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" + _debug2 "DNSdataid: $DNSdataid" + DNSvalue="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" + if _startswith "$DNSvalue" """; then + # remove the quotation from the start + DNSvalue="$(echo "$DNSvalue" | cut -c 7-)" + fi + if _endswith "$DNSvalue" "..."; then + # value was truncated, remove the dot dot dot from the end + DNSvalue="$(echo "$DNSvalue" | sed 's/...$//')" + elif _endswith "$DNSvalue" """; then + # else remove the closing quotation from the end + DNSvalue="$(echo "$DNSvalue" | sed 's/......$//')" + fi + _debug2 "DNSvalue: $DNSvalue" + + if [ -n "$DNSdataid" ] && _startswith "$txtvalue" "$DNSvalue"; then + # Found a match. But note... Website is truncating the + # value field so we are only testing that part that is not + # truncated. This should be accurate enough. + _debug "Deleting TXT record for $fulldomain, $txtvalue" + _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" + return $? + fi + + fi fi done done # If we get this far we did not find a match (after two attempts) # Not necessarily an error, but log anyway. - _debug2 "$subdomain_csv" - _info "Cannot delete TXT record for $fulldomain/$txtvalue. Does not exist at FreeDNS" + _debug3 "$subdomain_csv" + _info "Cannot delete TXT record for $fulldomain, $txtvalue. Does not exist at FreeDNS" return 0 } @@ -272,7 +236,7 @@ _freedns_login() { # if cookies is not empty then logon successful if [ -z "$cookies" ]; then - _debug "$htmlpage" + _debug3 "htmlpage: $htmlpage" _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file" return 1 fi @@ -301,7 +265,7 @@ _freedns_retrieve_subdomain_page() { return 1 fi - _debug2 "$htmlpage" + _debug3 "htmlpage: $htmlpage" printf "%s" "$htmlpage" return 0 @@ -323,17 +287,17 @@ _freedns_add_txt_record() { _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" return 1 elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then - _debug "$htmlpage" + _debug3 "htmlpage: $htmlpage" _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" return 1 elif _contains "$htmlpage" "security code was incorrect"; then - _debug "$htmlpage" + _debug3 "htmlpage: $htmlpage" _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" return 1 fi - _debug2 "$htmlpage" + _debug3 "htmlpage: $htmlpage" _info "Added acme challenge TXT record for $fulldomain at FreeDNS" return 0 } @@ -352,7 +316,7 @@ _freedns_delete_txt_record() { _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" return 1 elif ! _contains "$htmlheader" "200 OK"; then - _debug "$htmlheader" + _debug2 "htmlheader: $htmlheader" _err "FreeDNS failed to delete TXT record $data_id" return 1 fi From 62dd3a5380eaffd76edf0ad558e14cd494ac236d Mon Sep 17 00:00:00 2001 From: David Kerr Date: Fri, 9 Mar 2018 16:54:42 -0500 Subject: [PATCH 1347/1348] Fix Travis CI errors. --- dnsapi/dns_freedns.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 1f03791a..0d8fae73 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -90,13 +90,13 @@ dns_freedns_add() { while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" line="$(echo "$subdomain_csv" | sed -n "${i}p")" - _debug2 "line $line" + _debug2 "line: $line" if [ $found = 0 ] && _contains "$line" "$top_domain