From 989651c23be6f8fbf2d507aaae76ec5c774f2644 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 4 Feb 2017 23:17:24 -0500 Subject: [PATCH 001/231] 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 7d75ad4c56a97ae7576bcc89eb41610df1d856b5 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 5 Feb 2017 14:35:05 -0500 Subject: [PATCH 002/231] 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 003/231] 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 004/231] 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 005/231] 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 006/231] 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 007/231] 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 008/231] 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 009/231] 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 f158caa2ebba77a343ca7badddba8395e822a609 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Mon, 6 Feb 2017 21:49:20 -0500 Subject: [PATCH 010/231] 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 011/231] 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 012/231] 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 013/231] 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 014/231] 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 68d708e56da391e86bd13ea8900d015048d7f279 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 11 Feb 2017 16:11:27 -0500 Subject: [PATCH 015/231] 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 016/231] 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 017/231] 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 3a77a6eded17122416ecec87babe59b8492ef927 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sun, 12 Feb 2017 11:17:23 -0500 Subject: [PATCH 018/231] 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 019/231] 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 020/231] 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 021/231] 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 022/231] 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 68a35155e4c2ab8ecd13c60a6e723fb0bdd8eaf3 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Mon, 13 Feb 2017 20:32:12 -0500 Subject: [PATCH 023/231] 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 06492067966ef03344c92892d19b6fccee1cb86e Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 7 Mar 2017 11:57:03 -0500 Subject: [PATCH 024/231] 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 025/231] 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 212d0f24d8d264c30969d5f19bb61c5840ae5108 Mon Sep 17 00:00:00 2001 From: Daniel Lo Nigro Date: Tue, 31 Oct 2017 22:35:15 -0700 Subject: [PATCH 026/231] [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 bab4f691c5bade8a50a88ef715b834c8ec18cb1e Mon Sep 17 00:00:00 2001 From: Daniel Lo Nigro Date: Sun, 12 Nov 2017 18:38:30 -0800 Subject: [PATCH 027/231] 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 e75b56073b3e412d0b85c94527a632a6de5913f1 Mon Sep 17 00:00:00 2001 From: MaomiHz Date: Mon, 11 Dec 2017 16:03:02 -0600 Subject: [PATCH 028/231] Fix digitalocean api not remove record --- dnsapi/dns_dgon.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index 7e1f1fec..1dc1a858 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -92,11 +92,11 @@ dns_dgon_rm() { domain_list="$(_get "$GURL")" ## 2) find record ## check for what we are looing for: "type":"A","name":"$_sub_domain" - record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*\d+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" + record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[[:digit:]]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" ## 3) check record and get next page if [ -z "$record" ]; then ## find the next page if we dont have a match - nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=\d+")" + nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[[:digit:]]+")" if [ -z "$nextpage" ]; then _err "no record and no nextpage in digital ocean DNS removal" return 1 @@ -108,7 +108,7 @@ dns_dgon_rm() { done ## we found the record - rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")" + rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[[:digit:]]+" | _egrep_o "[[:digit:]]+")" _debug rec_id "$rec_id" ## delete the record From 9c4f7aa6889a2883028673e7276b8c2b15dfaf5b Mon Sep 17 00:00:00 2001 From: MaomiHz Date: Mon, 11 Dec 2017 16:20:27 -0600 Subject: [PATCH 029/231] check for env var exist in DigitalOcean API --- dnsapi/dns_dgon.sh | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index 1dc1a858..57613349 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -20,12 +20,22 @@ dns_dgon_add() { fulldomain="$(echo "$1" | _lower_case)" txtvalue=$2 + + DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}" + # Check if API Key Exist + if [ -z "$DO_API_KEY" ]; then + DO_API_KEY="" + _err "You did not specify DigitalOcean API key." + _err "Please export DO_API_KEY and try again." + return 1 + fi + _info "Using digitalocean dns validation - add record" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" ## save the env vars (key and domain split location) for later automated use - _saveaccountconf DO_API_KEY "$DO_API_KEY" + _saveaccountconf_mutable DO_API_KEY "$DO_API_KEY" ## split the domain for DO API if ! _get_base_domain "$fulldomain"; then @@ -39,7 +49,7 @@ dns_dgon_add() { export _H1="Content-Type: application/json" export _H2="Authorization: Bearer $DO_API_KEY" PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records' - PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}' + PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'","ttl":120}' _debug PURL "$PURL" _debug PBODY "$PBODY" @@ -65,6 +75,16 @@ dns_dgon_add() { dns_dgon_rm() { fulldomain="$(echo "$1" | _lower_case)" txtvalue=$2 + + DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}" + # Check if API Key Exist + if [ -z "$DO_API_KEY" ]; then + DO_API_KEY="" + _err "You did not specify DigitalOcean API key." + _err "Please export DO_API_KEY and try again." + return 1 + fi + _info "Using digitalocean dns validation - remove record" _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" From c1f8ffa3861f93d624674732180f60ac1db768ed Mon Sep 17 00:00:00 2001 From: MaomiHz Date: Wed, 17 Jan 2018 21:39:13 -0600 Subject: [PATCH 030/231] Use [0-9] instead --- dnsapi/dns_dgon.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh index 57613349..5d38ef76 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -112,11 +112,11 @@ dns_dgon_rm() { domain_list="$(_get "$GURL")" ## 2) find record ## check for what we are looing for: "type":"A","name":"$_sub_domain" - record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[[:digit:]]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" + record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" ## 3) check record and get next page if [ -z "$record" ]; then ## find the next page if we dont have a match - nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[[:digit:]]+")" + nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")" if [ -z "$nextpage" ]; then _err "no record and no nextpage in digital ocean DNS removal" return 1 @@ -128,7 +128,7 @@ dns_dgon_rm() { done ## we found the record - rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[[:digit:]]+" | _egrep_o "[[:digit:]]+")" + rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")" _debug rec_id "$rec_id" ## delete the record From 9134b6ea989fb0f390ecf680e62f867cae3063a9 Mon Sep 17 00:00:00 2001 From: Herve Couplet Date: Tue, 23 Jan 2018 17:53:40 +0100 Subject: [PATCH 031/231] 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 7f59d7ea48f53cb31c0b4a709c3d1ce3cc90087f Mon Sep 17 00:00:00 2001 From: Skid Date: Wed, 7 Feb 2018 14:07:14 +0100 Subject: [PATCH 032/231] 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 da0bd5a9dc414c3b934371145fb8c1ce4073c661 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Feb 2018 09:03:55 +0800 Subject: [PATCH 033/231] 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 034/231] 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 035/231] 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 036/231] 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 037/231] 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 038/231] 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 039/231] 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 040/231] 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 041/231] 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 042/231] 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 043/231] 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 044/231] 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 045/231] 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 046/231] 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 047/231] 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 048/231] 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 049/231] 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 050/231] 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 051/231] 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 052/231] 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 053/231] 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 054/231] 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 055/231] 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 056/231] 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 057/231] 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 058/231] 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 059/231] 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 060/231] 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 061/231] 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 062/231] 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 063/231] 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 064/231] 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 065/231] 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 066/231] 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 067/231] 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 068/231] 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 069/231] 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 070/231] 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 071/231] 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 072/231] 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 073/231] 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 074/231] 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 075/231] 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 076/231] 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 077/231] 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 078/231] 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 079/231] 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 080/231] 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 081/231] 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 082/231] 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 083/231] 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 084/231] 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 085/231] 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 086/231] 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 087/231] 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 088/231] 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 089/231] 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 090/231] 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 091/231] 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 092/231] 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 093/231] 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 094/231] 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 095/231] 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 096/231] 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 097/231] 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 098/231] 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 099/231] 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 100/231] 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 101/231] 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 102/231] 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 103/231] 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 104/231] 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 105/231] 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 106/231] 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 107/231] 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 108/231] 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 109/231] 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 110/231] 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 111/231] 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 113/231] 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" ;; From 224e0c298a6de49fa41754839855ffaf256578d8 Mon Sep 17 00:00:00 2001 From: martgras Date: Mon, 12 Mar 2018 10:27:56 +0100 Subject: [PATCH 114/231] Fix missing success return value from dns_azure_add/rm --- dnsapi/dns_azure.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index 677a9f75..e0d9516f 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -99,6 +99,7 @@ dns_azure_add() { _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then _info "validation value added" + return 0 else _err "error adding validation value ($_code)" return 1 @@ -194,6 +195,7 @@ dns_azure_rm() { _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken" if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then _info "validation value removed" + return 0 else _err "error removing validation value ($_code)" return 1 @@ -226,6 +228,7 @@ _azure_rest() { else response="$(_get "$ep")" fi + _ret="$?" _secure_debug2 "response $response" _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" _debug "http response code $_code" @@ -236,7 +239,7 @@ _azure_rest() { return 1 fi # See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes - if [ "$?" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then + if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then _request_retry_times="$(_math "$_request_retry_times" + 1)" _info "REST call error $_code retrying $ep in $_request_retry_times s" _sleep "$_request_retry_times" @@ -281,6 +284,7 @@ _azure_getaccess_token() { body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials" _secure_debug2 "data $body" response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")" + _ret="$?" _secure_debug2 "response $response" response="$(echo "$response" | _normalizeJson)" accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") @@ -290,7 +294,7 @@ _azure_getaccess_token() { _err "no acccess token received. Check your Azure settings see $WIKI" return 1 fi - if [ "$?" != "0" ]; then + if [ "$_ret" != "0" ]; then _err "error $response" return 1 fi From 0f120c41f1649d1b0a704a439927b47ab214aae8 Mon Sep 17 00:00:00 2001 From: anabis <7274563+anabis@users.noreply.github.com> Date: Wed, 14 Mar 2018 11:05:57 +0100 Subject: [PATCH 115/231] fix syntax error missing space --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2a3138cb..5d9b63c2 100755 --- a/acme.sh +++ b/acme.sh @@ -4151,7 +4151,7 @@ $_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 + if ! _checkcert "$CA_CERT_PATH"; then _err "Can not get the ca cert." break fi From 749c0e51e681c77fe10f38c083332c5c71969cb9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 19:42:02 +0800 Subject: [PATCH 116/231] start 2.7.8 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2a3138cb..151b8e90 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.7 +VER=2.7.8 PROJECT_NAME="acme.sh" From c5f1cca3a0057e17ca817c8260027d4895e5d4f4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 20:30:51 +0800 Subject: [PATCH 117/231] fix https://github.com/Neilpang/acme.sh/issues/1372 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 439e0384..178852a5 100755 --- a/acme.sh +++ b/acme.sh @@ -4264,7 +4264,7 @@ renew() { fi . "$DOMAIN_CONF" - + _debug Le_API "$Le_API" if [ "$Le_API" ]; then if [ "$_OLD_CA_HOST" = "$Le_API" ]; then export Le_API="$DEFAULT_CA" From 664446631f0601d21a607cb0e76ba06d4acb3536 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 20:52:18 +0800 Subject: [PATCH 118/231] add debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 178852a5..2898beb8 100755 --- a/acme.sh +++ b/acme.sh @@ -2341,7 +2341,7 @@ _initpath() { fi fi - _debug2 ACME_DIRECTORY "$ACME_DIRECTORY" + _debug 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 3881f22192ac16f298e2d5dd603971e4450124c2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 21:20:27 +0800 Subject: [PATCH 119/231] fix https://github.com/Neilpang/acme.sh/issues/1375 add more info --- acme.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 2898beb8..337d8b9b 100755 --- a/acme.sh +++ b/acme.sh @@ -47,6 +47,7 @@ DEFAULT_DNS_SLEEP=120 NO_VALUE="no" W_TLS="tls" +W_DNS="dns" DNS_ALIAS_PREFIX="=" MODE_STATELESS="stateless" @@ -3118,7 +3119,7 @@ _on_issue_err() { ) fi - if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "dns"; then + if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "$W_DNS"; then _err "$_DNS_MANUAL_ERR" fi @@ -3154,7 +3155,7 @@ _on_issue_success() { fi fi - if _hasfield "$Le_Webroot" "dns"; then + if _hasfield "$Le_Webroot" "$W_DNS"; then _err "$_DNS_MANUAL_WARN" fi @@ -3624,7 +3625,7 @@ $_authorizations_map" vtype="$VTYPE_HTTP" #todo, v2 wildcard force to use dns - if _startswith "$_currentRoot" "dns"; then + if _startswith "$_currentRoot" "$W_DNS"; then vtype="$VTYPE_DNS" fi @@ -3751,6 +3752,10 @@ $_authorizations_map" if [ "$d_api" ]; then _info "Found domain api file: $d_api" else + if [ "$_currentRoot" != "$W_DNS" ]; then + _err "Can not find dns api hook for: $_currentRoot" + _info "You need to add the txt record manually." + fi _info "$(__red "Add the following TXT record:")" _info "$(__red "Domain: '$(__green "$txtdomain")'")" _info "$(__red "TXT value: '$(__green "$txt")'")" @@ -5779,7 +5784,7 @@ _process() { fi ;; --dns) - wvalue="dns" + wvalue="$W_DNS" if [ "$2" ] && ! _startswith "$2" "-"; then wvalue="$2" shift From 263c38caecbcf735e94646cb3483381680233960 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 21:27:29 +0800 Subject: [PATCH 120/231] add more debug info --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 337d8b9b..e65b74af 100755 --- a/acme.sh +++ b/acme.sh @@ -3592,6 +3592,8 @@ issue() { _debug2 "_authz_url" "$_authz_url" if ! response="$(_get "$_authz_url")"; then _err "get to authz error." + _err "_authorizations_seg" "$_authorizations_seg" + _err "_authz_url" "$_authz_url" _clearup _on_issue_err "$_post_hook" return 1 @@ -3642,6 +3644,7 @@ $_authorizations_map" _debug2 "response" "$response" if [ -z "$response" ]; then _err "get to authz error." + _err "_authorizations_map" "$_authorizations_map" _clearup _on_issue_err "$_post_hook" return 1 @@ -4873,6 +4876,8 @@ _deactivate() { _debug2 "authzUri" "$authzUri" if ! response="$(_get "$authzUri")"; then _err "get to authz error." + _err "_authorizations_seg" "$_authorizations_seg" + _err "authzUri" "$authzUri" _clearup _on_issue_err "$_post_hook" return 1 From 674b50889e30cbbb10eea33fd4a0ace9e259d51e Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 21:42:12 +0800 Subject: [PATCH 121/231] fix wildcard domains --- acme.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index e65b74af..16f82fdb 100755 --- a/acme.sh +++ b/acme.sh @@ -3422,6 +3422,9 @@ issue() { _main_domain=$(echo "$2,$3" | cut -d , -f 1) _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi + _debug _main_domain "$_main_domain" + _debug _alt_domains "$_alt_domains" + _key_length="$4" _real_cert="$5" _real_key="$6" @@ -3552,10 +3555,15 @@ issue() { if [ "$ACME_VERSION" = "2" ]; then #make new order request _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" - for d in $(echo "$_alt_domains" | tr ',' ' '); do - if [ "$d" ]; then - _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" + while true; do + _w_index=1 + d="$(echo "$$_alt_domains" | cut -d , -f "$_w_index")" + _w_index="$(_math "$_w_index" + 1)" + _debug d "$d" + if [ -z "$d" ]; then + break fi + _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}" done _debug2 _identifiers "$_identifiers" if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then From dd17124ec6eb5d89a68c515bfa4972b5c6e6a4dc Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 21:45:16 +0800 Subject: [PATCH 122/231] fix error --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 16f82fdb..1fb9b476 100755 --- a/acme.sh +++ b/acme.sh @@ -3557,7 +3557,7 @@ issue() { _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" while true; do _w_index=1 - d="$(echo "$$_alt_domains" | cut -d , -f "$_w_index")" + d="$(echo "$_alt_domains," | cut -d , -f "$_w_index")" _w_index="$(_math "$_w_index" + 1)" _debug d "$d" if [ -z "$d" ]; then From 88bbe55b859fef97d18a2d7a67dfee297e41b40f Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 21:54:32 +0800 Subject: [PATCH 123/231] fix wrong wildcard domain interpretation --- acme.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 1fb9b476..fecc1b55 100755 --- a/acme.sh +++ b/acme.sh @@ -3620,10 +3620,16 @@ $_authorizations_map" _debug2 _authorizations_map "$_authorizations_map" fi - alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ') _index=0 _currentRoot="" - for d in $alldomains; do + while true; do + _w_index=1 + d="$(echo "$_main_domain,$_alt_domains," | cut -d , -f "$_w_index")" + _w_index="$(_math "$_w_index" + 1)" + _debug d "$d" + if [ -z "$d" ]; then + break + fi _info "Getting webroot for domain" "$d" _index=$(_math $_index + 1) _w="$(echo $_web_roots | cut -d , -f $_index)" From 931d19eece68266299e492f680ae37747edaa0e8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 21:56:40 +0800 Subject: [PATCH 124/231] fix for wildcard domain interpretation --- acme.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index fecc1b55..4710947b 100755 --- a/acme.sh +++ b/acme.sh @@ -3019,11 +3019,17 @@ _on_before_issue() { _debug Le_LocalAddress "$_chk_local_addr" - alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ') _index=1 _currentRoot="" _addrIndex=1 - for d in $alldomains; do + while true; do + _w_index=1 + d="$(echo "$_chk_main_domain,$_chk_alt_domains," | cut -d , -f "$_w_index")" + _w_index="$(_math "$_w_index" + 1)" + _debug d "$d" + if [ -z "$d" ]; then + break + fi _debug "Check for domain" "$d" _currentRoot="$(_getfield "$_chk_web_roots" $_index)" _debug "_currentRoot" "$_currentRoot" From 38f1b4d205c67a6b75084956759d2d0d321aadf7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 22:03:58 +0800 Subject: [PATCH 125/231] fix wildcard interpretation --- acme.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 4710947b..e7c40c01 100755 --- a/acme.sh +++ b/acme.sh @@ -2999,6 +2999,8 @@ _on_before_issue() { _chk_pre_hook="$4" _chk_local_addr="$5" _debug _on_before_issue + _debug _chk_main_domain "$_chk_main_domain" + _debug _chk_alt_domains "$_chk_alt_domains" #run pre hook if [ "$_chk_pre_hook" ]; then _info "Run pre hook:'$_chk_pre_hook'" @@ -3022,8 +3024,8 @@ _on_before_issue() { _index=1 _currentRoot="" _addrIndex=1 + _w_index=1 while true; do - _w_index=1 d="$(echo "$_chk_main_domain,$_chk_alt_domains," | cut -d , -f "$_w_index")" _w_index="$(_math "$_w_index" + 1)" _debug d "$d" @@ -3561,8 +3563,8 @@ issue() { if [ "$ACME_VERSION" = "2" ]; then #make new order request _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}" + _w_index=1 while true; do - _w_index=1 d="$(echo "$_alt_domains," | cut -d , -f "$_w_index")" _w_index="$(_math "$_w_index" + 1)" _debug d "$d" @@ -3628,8 +3630,8 @@ $_authorizations_map" _index=0 _currentRoot="" + _w_index=1 while true; do - _w_index=1 d="$(echo "$_main_domain,$_alt_domains," | cut -d , -f "$_w_index")" _w_index="$(_math "$_w_index" + 1)" _debug d "$d" From 28d83d42e2a629d308afddc0cb2526c42bea192d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Mar 2018 22:09:34 +0800 Subject: [PATCH 126/231] remove tls mode from doc https://github.com/Neilpang/acme.sh/issues/1322 --- README.md | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index bfcb477f..5471c573 100644 --- a/README.md +++ b/README.md @@ -220,22 +220,7 @@ 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 to be root/sudoer or have permission to listen on port 443 (TCP))** - -acme.sh supports `tls-sni-01` validation. - -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 -``` - -More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert - - -# 6. Use Apache mode +# 5. Use Apache mode **(requires you to be root/sudoer, since it is required to interact with Apache server)** @@ -255,7 +240,7 @@ 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 +# 6. Use Nginx mode **(requires you to be root/sudoer, since it is required to interact with Nginx server)** @@ -279,7 +264,7 @@ 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 -# 8. Automatic DNS API integration +# 7. Automatic DNS API integration If your DNS provider supports API access, we can use that API to automatically issue the certs. @@ -342,7 +327,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. Use DNS manual mode: +# 8. Use DNS manual mode: If your dns provider doesn't support any api access, you can add the txt record by your hand. @@ -376,7 +361,7 @@ Ok, it's done. **Please use dns api mode instead.** -# 10. Issue ECC certificates +# 9. Issue ECC certificates `Let's Encrypt` can now issue **ECDSA** certificates. @@ -408,7 +393,7 @@ Valid values are: -# 11. Issue Wildcard certificates +# 10. Issue Wildcard certificates It's simple, just give a wildcard domain as the `-d` parameter. @@ -418,7 +403,7 @@ acme.sh --issue -d example.com -d *.example.com --dns dns_cf -# 12. How to renew the certs +# 11. 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. @@ -435,7 +420,7 @@ acme.sh --renew -d example.com --force --ecc ``` -# 13. How to stop cert renewal +# 12. How to stop cert renewal To stop renewal of a cert, you can execute the following to remove the cert from the renewal list: @@ -448,7 +433,7 @@ The cert/key file is not removed from the disk. You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself. -# 14. How to upgrade `acme.sh` +# 13. How to upgrade `acme.sh` acme.sh is in constant development, so it's strongly recommended to use the latest code. @@ -473,25 +458,25 @@ acme.sh --upgrade --auto-upgrade 0 ``` -# 15. 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 -# 16. Under the Hood +# 15. Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". TODO: -# 17. Acknowledgments +# 16. Acknowledgments 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme -# 18. License & Others +# 17. License & Others License is GPLv3 @@ -500,7 +485,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. -# 19. Donate +# 18. Donate Your donation makes **acme.sh** better: 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) From cac3b3ea354a41fe047c9b07ffe77dd586d97b4f Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Wed, 14 Mar 2018 12:32:02 -0400 Subject: [PATCH 127/231] add dns_loopia --- dnsapi/dns_loopia.sh | 227 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 dnsapi/dns_loopia.sh diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh new file mode 100644 index 00000000..7845db45 --- /dev/null +++ b/dnsapi/dns_loopia.sh @@ -0,0 +1,227 @@ +#!/usr/bin/env sh + +# +#LOOPIA_User="username" +# +#LOOPIA_Password="password" + +LOOPIA_Api="https://api.loopia.se/RPCSERV" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_loopia_add() { + fulldomain=$1 + txtvalue=$2 + + LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}" + LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}" + if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then + LOOPIA_User="" + LOOPIA_Password="" + _err "You don't specify loopia 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 LOOPIA_User "$LOOPIA_User" + _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_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" + + _info "Adding record" + + _loopia_add_record "$_domain" "$_sub_domain" + _loopia_update_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +dns_loopia_rm() { + fulldomain=$1 + txtvalue=$2 + + LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}" + LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}" + if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then + LOOPIA_User="" + LOOPIA_Password="" + _err "You don't specify LOOPIA 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 LOOPIA_User "$LOOPIA_User" + _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + xml_content=$(printf ' + + removeSubdomain + + + %s + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$_domain" "$_sub_domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! _contains "$response" "OK"; then + _err "Error could not get txt records" + return 1 + fi +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + _debug "get root" + + domain=$1 + i=2 + p=1 + + xml_content=$(printf ' + + getDomains + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password) + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + 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 + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +_loopia_update_record() { + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + updateZoneRecord + + + %s + + + %s + + + %s + + + %s + + + + + type + TXT + + + priority + 0 + + + ttl + 60 + + + rdata + %s + + + record_id + 0 + + + + + ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain" "$txtval") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "OK" >/dev/null; then + _err "Error" + return 1 + fi + return 0 +} + +_loopia_add_record() { + domain=$1 + sub_domain=$2 + + xml_content=$(printf ' + + addSubdomain + + + %s + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "OK" >/dev/null; then + _err "Error" + return 1 + fi + return 0 +} From 6b26d2b62de49e59517f7f5a0d14c4c91cb6dc2a Mon Sep 17 00:00:00 2001 From: Rid Date: Thu, 15 Mar 2018 09:50:54 +0000 Subject: [PATCH 128/231] Fixed grammatical errors --- dnsapi/dns_cf.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 68264a42..3595b9b0 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -19,8 +19,8 @@ dns_cf_add() { if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then CF_Key="" CF_Email="" - _err "You don't specify cloudflare api key and email yet." - _err "Please create you key and try again." + _err "You didn't specify a cloudflare api key and email yet." + _err "Please create the key and try again." return 1 fi @@ -94,8 +94,8 @@ dns_cf_rm() { if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then CF_Key="" CF_Email="" - _err "You don't specify cloudflare api key and email yet." - _err "Please create you key and try again." + _err "You didn't specify a cloudflare api key and email yet." + _err "Please create the key and try again." return 1 fi From 7a46293f7a54240a82dda4d0bb34106415944f33 Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Thu, 15 Mar 2018 10:55:31 -0400 Subject: [PATCH 129/231] loopia documentation --- README.md | 1 + dnsapi/README.md | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/README.md b/README.md index 5471c573..20b306e5 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API +1. Loopia API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a8358..e2e9172b 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -784,6 +784,28 @@ 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. +## 42. Use Loopia API +User must provide login credentials to the Loopia API. +The user needs the following permissions: + +- addSubdomain +- updateZoneRecord +- getDomains +- removeSubdomain + +Set the login credentials: +``` +export LOOPIA_User="user@loopiaapi" +export LOOPIA_Password="password" +``` + +And to issue a cert: +``` +acme.sh --issue --dns dns_loopia -d example.com -d *.example.com +``` + +The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API From a8b62261f6a02a6601d0fec235325e48deccbd05 Mon Sep 17 00:00:00 2001 From: "Claus F. Strasburger" Date: Fri, 16 Mar 2018 11:21:03 +0100 Subject: [PATCH 130/231] Documentation: what to do when using dns-manual Change the hint that tells you how to use DNS manual (second run needs to be --renew) --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e7c40c01..79717ad5 100755 --- a/acme.sh +++ b/acme.sh @@ -3819,7 +3819,7 @@ $_authorizations_map" if [ "$dnsadded" = '0' ]; then _savedomainconf "Le_Vlist" "$vlist" _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." - _err "Please add the TXT records to the domains, and retry again." + _err "Please add the TXT records to the domains, and re-run with --renew." _clearup _on_issue_err "$_post_hook" return 1 From a5c1c30368a176ec76dcb2c379ca82a24d95ab5b Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 16 Mar 2018 21:29:38 +0800 Subject: [PATCH 131/231] update doc --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5471c573..2898629c 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) +- [CentOS Web Panel](http://centos-webpanel.com/) +- [lnmp.org](https://lnmp.org/) - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS From 4ae108009c0000f3d3d1e52c6a544a51a7bf57e4 Mon Sep 17 00:00:00 2001 From: Rafael Gieschke Date: Thu, 15 Mar 2018 02:38:17 +0100 Subject: [PATCH 132/231] dns_pdns.sh: Allow "." as root zone --- dnsapi/dns_pdns.sh | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 7d807c81..3d99e103 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -90,7 +90,7 @@ set_record() { full=$2 txtvalue=$3 - if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then _err "Set txt record error." return 1 fi @@ -107,7 +107,7 @@ rm_record() { root=$1 full=$2 - if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then _err "Delete txt record error." return 1 fi @@ -122,7 +122,7 @@ rm_record() { notify_slaves() { root=$1 - if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify"; then + if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root/notify"; then _err "Notify slaves error." return 1 fi @@ -144,15 +144,18 @@ _get_root() { while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$h" ]; then - return 1 - fi if _contains "$_zones_response" "\"name\": \"$h.\""; then - _domain="$h" + _domain="$h." + if [ -z "$h" ]; then + _domain="=2E" + fi return 0 fi + if [ -z "$h" ]; then + return 1 + fi i=$(_math $i + 1) done _debug "$domain not found" From 9082862b9dd5df4d893e8bcd37c1804f446e8b6c Mon Sep 17 00:00:00 2001 From: Casper Date: Sat, 17 Mar 2018 14:45:49 +0100 Subject: [PATCH 133/231] Updated --accountemail help https://github.com/Neilpang/acme.sh/issues/1074#issuecomment-337672763 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index e7c40c01..d9bc701a 100755 --- a/acme.sh +++ b/acme.sh @@ -5456,8 +5456,8 @@ Parameters: --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. --config-home Specifies the home dir to save all the configurations. --useragent Specifies the user agent string. it will be saved for future use too. - --accountemail Specifies the account email for registering, Only valid for the '--install' command. - --accountkey Specifies the account key path, Only valid for the '--install' command. + --accountemail Specifies the account email, only valid for the '--install' and '--update-account' command. + --accountkey Specifies the account key path, only valid for the '--install' command. --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days. --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. --local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses. From 32d8f349c9207226f3e030999bc8c880b73c6da5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 11:04:14 +0800 Subject: [PATCH 134/231] add debug info --- 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 5fbb09d8..318dee0c 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -50,9 +50,9 @@ _PDD_get_domain() { __last=0 while [ $__last -eq 0 ]; do uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" - res1=$(_get "$uri1" | _normalizeJson) - #_debug "$res1" - __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') + res1="$(_get "$uri1" | _normalizeJson)" + _debug2 "res1" "$res1" + __found="$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')" _debug "found: $__found results on page" if [ "$__found" -lt 20 ]; then _debug "last page: $__page" From 323febe8c78d2d17a40153c97e40e7b641747268 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 11:14:03 +0800 Subject: [PATCH 135/231] add more debug log --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 90627c8d..07cfb0ec 100755 --- a/acme.sh +++ b/acme.sh @@ -4105,7 +4105,7 @@ $_authorizations_map" fi else if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then - _err "Sign failed." + _err "Sign failed. $response" _on_issue_err "$_post_hook" return 1 fi From f2aa5c02352308a24d784e1abac08015e0f3e6b3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 11:18:37 +0800 Subject: [PATCH 136/231] update doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2898629c..8a12d9fe 100644 --- a/README.md +++ b/README.md @@ -400,7 +400,7 @@ Valid values are: It's simple, just give a wildcard domain as the `-d` parameter. ```sh -acme.sh --issue -d example.com -d *.example.com --dns dns_cf +acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf ``` From 5d8d217a133977899ebdf62db3eb5462304af422 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 11:36:04 +0800 Subject: [PATCH 137/231] add more debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 07cfb0ec..db2547dd 100755 --- a/acme.sh +++ b/acme.sh @@ -3247,6 +3247,7 @@ _regAccount() { return 1 fi + _debug2 responseHeaders "$responseHeaders" _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" _savecaconf "ACCOUNT_URL" "$_accUri" From 7e0b334b384e09e50f50c7b94553191513466ba4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 18:20:29 +0800 Subject: [PATCH 138/231] fix empty ACCOUNT_URL for v2 for the first time use --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index db2547dd..4a2f8253 100755 --- a/acme.sh +++ b/acme.sh @@ -3250,8 +3250,13 @@ _regAccount() { _debug2 responseHeaders "$responseHeaders" _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" + if [ -z "$_accUri" ]; then + _err "Can not find account id url." + _err "$responseHeaders" + return 1 + fi _savecaconf "ACCOUNT_URL" "$_accUri" - export ACCOUNT_URL="$ACCOUNT_URL" + export ACCOUNT_URL="$_accUri" CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" From 36a7a84080c25eec363e5de9bc35f084a6ea6133 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 18:34:35 +0800 Subject: [PATCH 139/231] fix https://github.com/Neilpang/acme.sh/issues/1411 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4a2f8253..fafd514a 100755 --- a/acme.sh +++ b/acme.sh @@ -4116,7 +4116,7 @@ $_authorizations_map" return 1 fi _rcert="$response" - Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)" echo "$BEGIN_CERT" >"$CERT_PATH" #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then From 6a66ba8a21c7c4ecef5860c48a22186349f60766 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 18:57:56 +0800 Subject: [PATCH 140/231] fix https://github.com/Neilpang/acme.sh/issues/1411 --- acme.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index fafd514a..4cc9483f 100755 --- a/acme.sh +++ b/acme.sh @@ -1617,6 +1617,7 @@ _post() { _debug $httpmethod _debug "_post_url" "$_post_url" _debug2 "body" "$body" + _debug2 "_postContentType" "$_postContentType" _inithttp @@ -1785,6 +1786,11 @@ _send_signed_request() { return 1 fi + if [ "$ACME_VERSION" = "2" ]; then + __request_conent_type="$CONTENT_TYPE_JSON" + else + __request_conent_type="" + fi payload64=$(printf "%s" "$payload" | _base64 | _url_replace) _debug3 payload64 "$payload64" @@ -1797,7 +1803,7 @@ _send_signed_request() { if [ "$ACME_NEW_NONCE" ]; then _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" - if _post "" "$nonceurl" "" "HEAD" "$CONTENT_TYPE_JSON"; then + if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then _headers="$(cat "$HTTP_HEADER")" fi fi @@ -1852,7 +1858,7 @@ _send_signed_request() { fi _debug3 body "$body" - response="$(_post "$body" "$url" "$needbase64" "POST" "$CONTENT_TYPE_JSON")" + response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")" _CACHED_NONCE="" if [ "$?" != "0" ]; then From 39852662a62b428d6de14a6bf5fbfb26a744cd9b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 19:29:02 +0800 Subject: [PATCH 141/231] fix content type --- acme.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 4cc9483f..6d4223eb 100755 --- a/acme.sh +++ b/acme.sh @@ -1626,14 +1626,19 @@ _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)" + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + fi else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + fi fi _ret="$?" if [ "$_ret" != "0" ]; then From e8b54a50876e687c52c572afd87736df08547a9d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 19:32:45 +0800 Subject: [PATCH 142/231] fix ACCOUNT_URL --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 6d4223eb..72d0e2af 100755 --- a/acme.sh +++ b/acme.sh @@ -3538,7 +3538,7 @@ issue() { _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")" _debug2 _saved_account_key_hash "$_saved_account_key_hash" - if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then + if [ -z "$ACCOUNT_URL" ] || [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then if ! _regAccount "$_accountkeylength"; then _on_issue_err "$_post_hook" return 1 From 668c43abf36d3ba42216faee096e7e18c8adacda Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Mar 2018 21:06:37 +0800 Subject: [PATCH 143/231] add more debug info --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 72d0e2af..a69d4bb0 100755 --- a/acme.sh +++ b/acme.sh @@ -4100,13 +4100,15 @@ $_authorizations_map" fi if [ "$code" != "200" ]; then _err "Sign failed, code is not 200." + _err "$response" _on_issue_err "$_post_hook" return 1 fi Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" if ! _get "$Le_LinkCert" >"$CERT_PATH"; then - _err "Sign failed, code is not 200." + _err "Sign failed, can not download cert:$Le_LinkCert." + _err "$response" _on_issue_err "$_post_hook" return 1 fi From 413f071861c6205fa5a9d783e50a56e35776be8b Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Sun, 18 Mar 2018 10:00:10 -0400 Subject: [PATCH 144/231] use echo --- dnsapi/dns_loopia.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index 7845db45..55b4f94a 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -119,7 +119,7 @@ _get_root() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(echo "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then #not valid return 1 @@ -187,7 +187,7 @@ _loopia_update_record() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" - if ! printf "%s" "$response" | grep "OK" >/dev/null; then + if ! echo "$response" | grep "OK" >/dev/null; then _err "Error" return 1 fi @@ -219,7 +219,7 @@ _loopia_add_record() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" - if ! printf "%s" "$response" | grep "OK" >/dev/null; then + if ! echo "$response" | grep "OK" >/dev/null; then _err "Error" return 1 fi From 912bcf94873bc4e5906af188e60210517fdcda39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20G=C3=A5rdenberg?= Date: Mon, 19 Mar 2018 11:15:25 +0100 Subject: [PATCH 145/231] Fixed HTTPS-url with regard to #1192 --- 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 0d8fae73..7262755e 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -279,7 +279,7 @@ _freedns_add_txt_record() { domain_id="$2" subdomain="$3" value="$(printf '%s' "$4" | _url_encode)" - url="http://freedns.afraid.org/subdomain/save.php?step=2" + url="https://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")" From ae329385316511db8a4f377f3c630b2ba31e01d7 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 19 Mar 2018 12:17:47 -0300 Subject: [PATCH 146/231] added dnsapi/dns_kinghost.sh --- dnsapi/dns_kinghost.sh | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 dnsapi/dns_kinghost.sh diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh new file mode 100644 index 00000000..3697e4ae --- /dev/null +++ b/dnsapi/dns_kinghost.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env sh + +#KINGHOST_username="xxxx@sss.com" +#KINGHOST_Password="sdfsdfsdfljlbjkljlkjsdfoiwje" + +KING_Api="https://api.kinghost.net/acme" + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_kinghost_add() { + fulldomain=$1 + txtvalue=$2 + + KINGHOST_username="${KINGHOST_username:-$(_readaccountconf_mutable KINGHOST_username)}" + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + if [ -z "$KINGHOST_username" ] || [ -z "$KINGHOST_Password" ]; then + KINGHOST_username="" + KINGHOST_Password="" + _err "You don't specify KingHost api password and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable KINGHOST_username "$KINGHOST_username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are creating a new txt record here, so we expect the "ok" status + if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" + if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0; +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_kinghost_rm() { + fulldomain=$1 + txtvalue=$2 + + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + KINGHOST_username="${KINGHOST_username:-$(_readaccountconf_mutable KINGHOST_username)}" + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_username" ]; then + KINGHOST_Password="" + KINGHOST_username="" + _err "You don't specify KingHost api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are removing a txt record here, so the record must exists + if printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" + if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0; +} + + +#################### Private functions below ################################## +_kinghost_rest() { + method=$1 + uri="$2" + data="$3" + _debug "$uri" + + export _H1="X-Auth-Email: $KINGHOST_username" + export _H2="X-Auth-Key: $KINGHOST_Password" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$KING_Api/$uri.json" "" "$method")" + else + response="$(_get "$KING_Api/$uri.json?$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $uri" + return 1 + fi + _debug2 response "$response" + return 0 +} From 2ff6f4d3cfe9494f552fdd0fd72e418a75ece7e5 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 19 Mar 2018 12:26:54 -0300 Subject: [PATCH 147/231] updated docs for dns_kinghost api usage --- README.md | 1 + dnsapi/README.md | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index 5471c573..0faea3ed 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API +1. KingHost (https://www.kinghost.com.br/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a8358..caae7cff 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -784,6 +784,17 @@ 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. +## 42. Use KingHost DNS API + +API access must be enabled at https://painel.kinghost.com.br/painel.api.php + +``` +export KINGHOST_username="yourusername" +export KINGHOST_Password="yourpassword" +acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com +``` + +The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API From 48bdfa23771393bfe62d858aacb1110ed1eb5639 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 19 Mar 2018 13:49:58 -0300 Subject: [PATCH 148/231] added doc header to dns_kinghost.sh --- dnsapi/dns_kinghost.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 3697e4ae..5d3a4935 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -1,7 +1,16 @@ #!/usr/bin/env sh -#KINGHOST_username="xxxx@sss.com" -#KINGHOST_Password="sdfsdfsdfljlbjkljlkjsdfoiwje" +############################################################ +# KingHost API support # +# http://api.kinghost.net/doc/ # +# # +# Author: Felipe Keller Braz # +# Report Bugs here: https://github.com/kinghost/acme.sh # +# # +# Values to export: # +# export KINGHOST_username="email@provider.com" # +# export KINGHOST_Password="xxxxxxxxxx" # +############################################################ KING_Api="https://api.kinghost.net/acme" @@ -83,7 +92,6 @@ dns_kinghost_rm() { return 0; } - #################### Private functions below ################################## _kinghost_rest() { method=$1 From 6787c81abe86a8339d917069f74e2601b4f878ff Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Tue, 20 Mar 2018 09:58:10 -0300 Subject: [PATCH 149/231] renamed KINGHOST_username => KINGHOST_Username --- dnsapi/dns_kinghost.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 5d3a4935..fc436bbd 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -8,7 +8,7 @@ # Report Bugs here: https://github.com/kinghost/acme.sh # # # # Values to export: # -# export KINGHOST_username="email@provider.com" # +# export KINGHOST_Username="email@provider.com" # # export KINGHOST_Password="xxxxxxxxxx" # ############################################################ @@ -20,10 +20,10 @@ dns_kinghost_add() { fulldomain=$1 txtvalue=$2 - KINGHOST_username="${KINGHOST_username:-$(_readaccountconf_mutable KINGHOST_username)}" + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" - if [ -z "$KINGHOST_username" ] || [ -z "$KINGHOST_Password" ]; then - KINGHOST_username="" + if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then + KINGHOST_Username="" KINGHOST_Password="" _err "You don't specify KingHost api password and email yet." _err "Please create you key and try again." @@ -31,7 +31,7 @@ dns_kinghost_add() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable KINGHOST_username "$KINGHOST_username" + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" _debug "Getting txt records" @@ -62,10 +62,10 @@ dns_kinghost_rm() { txtvalue=$2 KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" - KINGHOST_username="${KINGHOST_username:-$(_readaccountconf_mutable KINGHOST_username)}" - if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_username" ]; then + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then KINGHOST_Password="" - KINGHOST_username="" + KINGHOST_Username="" _err "You don't specify KingHost api key and email yet." _err "Please create you key and try again." return 1 @@ -99,7 +99,7 @@ _kinghost_rest() { data="$3" _debug "$uri" - export _H1="X-Auth-Email: $KINGHOST_username" + export _H1="X-Auth-Email: $KINGHOST_Username" export _H2="X-Auth-Key: $KINGHOST_Password" if [ "$method" != "GET" ]; then From aa9975ad0d03d08a7cd7beaad60b4ff29adc3277 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Tue, 20 Mar 2018 10:08:52 -0300 Subject: [PATCH 150/231] dns_kinghost.sh :: changed printf to echo --- dnsapi/dns_kinghost.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index fc436bbd..2dc57cb8 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -39,14 +39,14 @@ dns_kinghost_add() { #This API call returns "status":"ok" if dns record does not exists #We are creating a new txt record here, so we expect the "ok" status - if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" _err "$response" return 1 fi _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" - if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" _err "$response" return 1 @@ -76,14 +76,14 @@ dns_kinghost_rm() { #This API call returns "status":"ok" if dns record does not exists #We are removing a txt record here, so the record must exists - if printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + if echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" _err "$response" return 1 fi _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" - if ! printf "%s" "$response" | grep '"status":"ok"' >/dev/null; then + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" _err "$response" return 1 From a0923622aea8f650be8d92116f464d1c426e49ba Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Mar 2018 20:30:52 +0800 Subject: [PATCH 151/231] fix https://github.com/Neilpang/acme.sh/issues/1029 https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode --- acme.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/acme.sh b/acme.sh index a69d4bb0..c1298c44 100755 --- a/acme.sh +++ b/acme.sh @@ -110,10 +110,14 @@ _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_WIKI="https://github.com/Neilpang/acme.sh/wiki/dns-manual-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" +_DNS_MANUAL_ERROR="It seems that you are using dns manual mode. Read this link first: $_DNS_MANUAL_WIKI" + __INTERACTIVE="" if [ -t 1 ]; then __INTERACTIVE="1" @@ -3477,6 +3481,11 @@ issue() { mkdir -p "$DOMAIN_PATH" fi + if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then + _err "$_DNS_MANUAL_ERROR" + return 1 + fi + _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" _initAPI @@ -5500,6 +5509,7 @@ Parameters: --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. + --yes-I-know-dns-manual-mode-enough-go-ahead-please Force to use dns manual mode: $_DNS_MANUAL_WIKI " } @@ -5988,6 +5998,9 @@ _process() { shift fi ;; + --yes-I-know-dns-manual-mode-enough-go-ahead-please) + export FORCE_DNS_MANUAL=1 + ;; --log | --logfile) _log="1" _logfile="$2" From 46ac97a3ff455b6c16b9fabfc4b42f331d9cc7ef Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Mar 2018 20:57:48 +0800 Subject: [PATCH 152/231] update doc --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8a12d9fe..6a268350 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,8 @@ For more details: [How to use DNS API](dnsapi) # 8. Use DNS manual mode: +See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first. + If your dns provider doesn't support any api access, you can add the txt record by your hand. ```bash From 5f9b0675e2065e73c1bafafd13c833cbfcdc2c55 Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Wed, 21 Mar 2018 11:18:26 -0400 Subject: [PATCH 153/231] loopia -> loopia.se --- README.md | 2 +- dnsapi/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 20b306e5..c6ea9938 100644 --- a/README.md +++ b/README.md @@ -313,7 +313,7 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API -1. Loopia API +1. Loopia.se API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index e2e9172b..fe4a701c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -784,7 +784,7 @@ 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. -## 42. Use Loopia API +## 42. Use Loopia.se API User must provide login credentials to the Loopia API. The user needs the following permissions: From 8995d3434faec3779c2caf580e9d5f713381f2cf Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Wed, 21 Mar 2018 11:19:22 -0400 Subject: [PATCH 154/231] _contains instead of echo --- dnsapi/dns_loopia.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_loopia.sh b/dnsapi/dns_loopia.sh index 55b4f94a..5d761187 100644 --- a/dnsapi/dns_loopia.sh +++ b/dnsapi/dns_loopia.sh @@ -187,7 +187,7 @@ _loopia_update_record() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" - if ! echo "$response" | grep "OK" >/dev/null; then + if ! _contains "$response" "OK"; then _err "Error" return 1 fi @@ -219,7 +219,7 @@ _loopia_add_record() { response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" - if ! echo "$response" | grep "OK" >/dev/null; then + if ! _contains "$response" "OK"; then _err "Error" return 1 fi From af5ff2bb93acaa14c29e7ef5291b682a341edca4 Mon Sep 17 00:00:00 2001 From: Nils Sandmann Date: Wed, 21 Mar 2018 16:43:42 +0100 Subject: [PATCH 155/231] Modified DNSAPI for PowerDNS to support wildcard certificates --- dnsapi/dns_pdns.sh | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 3d99e103..40b344c0 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -88,9 +88,20 @@ set_record() { _info "Adding record" root=$1 full=$2 - txtvalue=$3 + new_challenge=$3 - if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then + _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" + _existing_challenges=($(echo "$response" | _normalizeJson | grep -Po "\"name\":\"$fulldomain\K.*?}]" | grep -Po 'content\":\"\\"\K[^\\]*')) + _record_string="" + _build_record_string $new_challenge + + for i in "${_existing_challenges[@]}" + do + _record_string+=", " + _build_record_string $i + done + + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then _err "Set txt record error." return 1 fi @@ -185,3 +196,7 @@ _pdns_rest() { return 0 } + +_build_record_string() { + _record_string+="{\"content\": \"\\\"$1\\\"\", \"disabled\": false}" +} From 893917a25dac51a5e0354f8122c5043060ecd573 Mon Sep 17 00:00:00 2001 From: Nils Sandmann Date: Thu, 22 Mar 2018 11:13:46 +0100 Subject: [PATCH 156/231] Fix travis errors --- dnsapi/dns_pdns.sh | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 40b344c0..594f9b24 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -91,14 +91,12 @@ set_record() { new_challenge=$3 _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" - _existing_challenges=($(echo "$response" | _normalizeJson | grep -Po "\"name\":\"$fulldomain\K.*?}]" | grep -Po 'content\":\"\\"\K[^\\]*')) _record_string="" - _build_record_string $new_challenge - - for i in "${_existing_challenges[@]}" - do - _record_string+=", " - _build_record_string $i + _build_record_string "$new_challenge" + _existing_challenges=$(echo "$response" | _normalizeJson | grep -Po "\"name\":\"$fulldomain\\K.*?}]" | grep -Po 'content\":\"\\"\K[^\\]*') + for oldchallenge in $_existing_challenges; do + _record_string="${_record_string}, " + _build_record_string "$oldchallenge" done if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then @@ -106,10 +104,6 @@ set_record() { return 1 fi - if ! notify_slaves "$root"; then - return 1 - fi - return 0 } @@ -198,5 +192,5 @@ _pdns_rest() { } _build_record_string() { - _record_string+="{\"content\": \"\\\"$1\\\"\", \"disabled\": false}" + _record_string="${_record_string}{\"content\": \"\\\"$1\\\"\", \"disabled\": false}" } From fbd8ab47eab3b62515978e17bac8609336c32cd5 Mon Sep 17 00:00:00 2001 From: pyriand3r Date: Thu, 22 Mar 2018 11:23:16 +0100 Subject: [PATCH 157/231] only reseller can use do.de's reseller interface --- dnsapi/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a8358..504a8b57 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -325,6 +325,8 @@ The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.s ## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API +ATTENTION: You need to be a registered Reseller to be able to use the ResellerInterface. As a normal user you can not use this method. + 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" From 6b15cf3f722632bf183a2a2c081652dba531738b Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 22 Mar 2018 13:45:43 -0400 Subject: [PATCH 158/231] Remove template text --- deploy/keychain.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/deploy/keychain.sh b/deploy/keychain.sh index a99ed465..d86b4d03 100644 --- a/deploy/keychain.sh +++ b/deploy/keychain.sh @@ -1,11 +1,5 @@ #!/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 From ba9e7fbf64b907c4bd53864b6a938b885201e346 Mon Sep 17 00:00:00 2001 From: James Gibson Date: Thu, 22 Mar 2018 22:46:21 -0600 Subject: [PATCH 159/231] Clarified the language around the Name.com steps Name.com has simplified the process to obtain API tokens, this clarifies the language around requesting a key. --- dnsapi/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a8358..ffd61dc6 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -525,8 +525,9 @@ 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. +Create your API token here: https://www.name.com/account/settings/api + +Note: `Namecom_Username` should be your Name.com username and not the token name. If you accidentally run the script with the token name as the username see `~/.acme.sh/account.conf` to fix the issue ``` export Namecom_Username="testuser" From aad309ee4f41da300daf61ac303d4eb6fd3d6bca Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 24 Mar 2018 00:06:39 +0800 Subject: [PATCH 160/231] fix https://github.com/Neilpang/acme.sh/issues/1430 --- acme.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index c1298c44..da8e60c9 100755 --- a/acme.sh +++ b/acme.sh @@ -1806,6 +1806,7 @@ _send_signed_request() { MAX_REQUEST_RETRY_TIMES=5 _request_retry_times=0 while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do + _request_retry_times=$(_math "$_request_retry_times" + 1) _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then _headers="" @@ -1836,7 +1837,11 @@ _send_signed_request() { fi nonce="$_CACHED_NONCE" _debug2 nonce "$nonce" - + if [ -z "$nonce" ]; then + _info "Could not get nonce, let's try again." + _sleep 2 + continue + fi if [ "$ACME_VERSION" = "2" ]; then if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' @@ -1894,7 +1899,6 @@ _send_signed_request() { 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 continue fi From 9c88971bc14314f061f17e71b292027586d0b63e Mon Sep 17 00:00:00 2001 From: James Gibson Date: Thu, 22 Mar 2018 23:09:38 -0600 Subject: [PATCH 161/231] Use internal base64 util instead of PATH bin/ --- 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 b712fa94..254952d6 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -123,7 +123,7 @@ _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) + _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\"") From a3f7ff90e300379c1acfbe5788d855a9584b82ae Mon Sep 17 00:00:00 2001 From: Nils Sandmann Date: Sat, 24 Mar 2018 18:46:04 +0100 Subject: [PATCH 162/231] Used e_grep_o instead grep -Po, dns_pdns_rm() now deletes only entry with matching txt value --- dnsapi/dns_pdns.sh | 58 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 594f9b24..8f07e8c4 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -69,15 +69,21 @@ dns_pdns_add() { #fulldomain dns_pdns_rm() { fulldomain=$1 + txtvalue=$2 + + if [ -z "$PDNS_Ttl" ]; then + PDNS_Ttl="$DEFAULT_PDNS_TTL" + fi _debug "Detect root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi + _debug _domain "$_domain" - if ! rm_record "$_domain" "$fulldomain"; then + if ! rm_record "$_domain" "$fulldomain" "$txtvalue"; then return 1 fi @@ -90,12 +96,10 @@ set_record() { full=$2 new_challenge=$3 - _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" _record_string="" _build_record_string "$new_challenge" - _existing_challenges=$(echo "$response" | _normalizeJson | grep -Po "\"name\":\"$fulldomain\\K.*?}]" | grep -Po 'content\":\"\\"\K[^\\]*') + _list_existingchallenges for oldchallenge in $_existing_challenges; do - _record_string="${_record_string}, " _build_record_string "$oldchallenge" done @@ -104,6 +108,10 @@ set_record() { return 1 fi + if ! notify_slaves "$root"; then + return 1 + fi + return 0 } @@ -111,14 +119,37 @@ rm_record() { _info "Remove record" root=$1 full=$2 + txtvalue=$3 - 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 + #Enumerate existing acme challenges + _list_existingchallenges - if ! notify_slaves "$root"; then - return 1 + if _contains "$_existing_challenges" "$txtvalue"; then + #Delete all challenges (PowerDNS API does not allow to delete content) + 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 + _record_string="" + #If the only existing challenge was the challenge to delete: nothing to do + if ! [ "$_existing_challenges" = "$txtvalue" ]; then + for oldchallenge in $_existing_challenges; do + #Build up the challenges to re-add, ommitting the one what should be deleted + if ! [ "$oldchallenge" = "$txtvalue" ]; then + _build_record_string "$oldchallenge" + fi + done + #Recreate the existing challenges + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then + _err "Set txt record error." + return 1 + fi + fi + if ! notify_slaves "$root"; then + return 1 + fi + else + _info "Record not found, nothing to remove" fi return 0 @@ -192,5 +223,10 @@ _pdns_rest() { } _build_record_string() { - _record_string="${_record_string}{\"content\": \"\\\"$1\\\"\", \"disabled\": false}" + _record_string="${_record_string:+${_record_string}, }{\"content\": \"\\\"${1}\\\"\", \"disabled\": false}" +} + +_list_existingchallenges() { + _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" + _existing_challenges=$(echo "$response" | _normalizeJson | _egrep_o "\"name\":\"${fulldomain}[^]]*}" | _egrep_o 'content\":\"\\"[^\\]*' | sed -n 's/^content":"\\"//p') } From 5b355c6ca7d3b8c690d70567f08a6e347a7a5e47 Mon Sep 17 00:00:00 2001 From: Austin Drummond Date: Sat, 24 Mar 2018 18:57:22 -0400 Subject: [PATCH 163/231] Fixed Dreamhost ENV var name in dnsapi/README.md --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 8b4a8358..c03e383c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -750,7 +750,7 @@ 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="" +export DH_API_KEY="" acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com ``` From fe843bc466b3d3267ac0b1866bf3e3365663c505 Mon Sep 17 00:00:00 2001 From: martgras Date: Sun, 25 Mar 2018 14:32:51 +0200 Subject: [PATCH 164/231] dns_he - proposed fix for #1438 if you have more than one zone of a domain (e.g. example.com and subdomain.example.com) _find_zone fails. This fix removes partials matches. --- 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 f42d56af..d196fbec 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -143,7 +143,7 @@ _find_zone() { _debug "Looking for zone \"${_attempted_zone}\"" - line_num="$(echo "$_zone_names" | grep -n "$_attempted_zone" | cut -d : -f 1)" + line_num="$(echo "$_zone_names" | grep -n "^$_attempted_zone" | cut -d : -f 1)" if [ "$line_num" ]; then _zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p") From 7588fc0989dcfb5f99da70a3ad70621b54cef533 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 26 Mar 2018 09:32:41 +0200 Subject: [PATCH 165/231] Fixes DNSimple for Wildcard certificates --- dnsapi/dns_dnsimple.sh | 55 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index 0bfe2b99..0a5b79bb 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -39,7 +39,7 @@ dns_dnsimple_add() { _get_records "$_account_id" "$_domain" "$_sub_domain" - if [ "$_records_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 @@ -51,22 +51,22 @@ dns_dnsimple_add() { fi fi _err "Add txt record error." - else - _info "Updating record" - _extract_record_id "$_records" "$_sub_domain" - - if _dnsimple_rest \ - PATCH \ - "$_account_id/zones/$_domain/records/$_record_id" \ - "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - - _info "Updated!" - return 0 - fi - - _err "Update error" - return 1 - fi +# else +# _info "Updating record" +# _extract_record_id "$_records" "$_sub_domain" + +# if _dnsimple_rest \ +# PATCH \ +# "$_account_id/zones/$_domain/records/$_record_id" \ +# "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + +# _info "Updated!" +# return 0 +# fi + +# _err "Update error" +# return 1 +# fi } # fulldomain @@ -84,19 +84,20 @@ dns_dnsimple_rm() { fi _get_records "$_account_id" "$_domain" "$_sub_domain" - _extract_record_id "$_records" "$_sub_domain" + _extract_record_id "$_records" "$_sub_domain" if [ "$_record_id" ]; then - - if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then - _info "removed record" "$_record_id" - return 0 - fi + echo "$_record_id" | while read -r item + do + if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$item"; then + _info "removed record" "$item" + return 0 + else + _err "failed to remove record" "$item" + return 1 + fi + done fi - - _err "failed to remove record" "$_record_id" - return 1 - } #################### Private functions bellow ################################## From 30283282d2f99afcfd39c45e4b3cdbaa0fef4035 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 26 Mar 2018 09:40:33 +0200 Subject: [PATCH 166/231] Fixing code style according to Travis --- dnsapi/dns_dnsimple.sh | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index 0a5b79bb..0dd3918a 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -39,34 +39,17 @@ dns_dnsimple_add() { _get_records "$_account_id" "$_domain" "$_sub_domain" -# if [ "$_records_count" = "0" ]; then - _info "Adding record" - if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then - _info "Added" - return 0 - else - _err "Unexpected response while adding text record." - return 1 - fi + _info "Adding record" + if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then + _info "Added" + return 0 + else + _err "Unexpected response while adding text record." + return 1 fi - _err "Add txt record error." -# else -# _info "Updating record" -# _extract_record_id "$_records" "$_sub_domain" - -# if _dnsimple_rest \ -# PATCH \ -# "$_account_id/zones/$_domain/records/$_record_id" \ -# "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - -# _info "Updated!" -# return 0 -# fi - -# _err "Update error" -# return 1 -# fi + fi + _err "Add txt record error." } # fulldomain @@ -87,8 +70,7 @@ dns_dnsimple_rm() { _extract_record_id "$_records" "$_sub_domain" if [ "$_record_id" ]; then - echo "$_record_id" | while read -r item - do + echo "$_record_id" | while read -r item; do if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$item"; then _info "removed record" "$item" return 0 From 4d2a0697edfbded749df960e0cbb8a770794bcfc Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 10:49:34 -0300 Subject: [PATCH 167/231] fix identation dnsapi/dns_kinghost.sh --- .gitignore | 2 + dnsapi/dns_kinghost.sh | 136 ++++++++++++++++++++--------------------- 2 files changed, 70 insertions(+), 68 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a13ea469 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +ae.sh diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 2dc57cb8..ddf9f899 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -17,79 +17,79 @@ KING_Api="https://api.kinghost.net/acme" # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" # Used to add txt record dns_kinghost_add() { - fulldomain=$1 - txtvalue=$2 - - KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" - KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" - if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then - KINGHOST_Username="" - KINGHOST_Password="" - _err "You don't specify KingHost api password and email yet." - _err "Please create you key and try again." - return 1 - fi - - #save the credentials to the account conf file. - _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" - _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" - - _debug "Getting txt records" - _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - #This API call returns "status":"ok" if dns record does not exists - #We are creating a new txt record here, so we expect the "ok" status - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - return 0; + fulldomain=$1 + txtvalue=$2 + + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then + KINGHOST_Username="" + KINGHOST_Password="" + _err "You don't specify KingHost api password and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are creating a new txt record here, so we expect the "ok" status + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0; } # Usage: fulldomain txtvalue # Used to remove the txt record after validation dns_kinghost_rm() { - fulldomain=$1 - txtvalue=$2 - - KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" - KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" - if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then - KINGHOST_Password="" - KINGHOST_Username="" - _err "You don't specify KingHost api key and email yet." - _err "Please create you key and try again." - return 1 - fi - - _debug "Getting txt records" - _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - #This API call returns "status":"ok" if dns record does not exists - #We are removing a txt record here, so the record must exists - if echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - return 0; + fulldomain=$1 + txtvalue=$2 + + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then + KINGHOST_Password="" + KINGHOST_Username="" + _err "You don't specify KingHost api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are removing a txt record here, so the record must exists + if echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0; } #################### Private functions below ################################## From 7efa54666559b797d38a676f3d8ac9d1a7e61b09 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 10:58:22 -0300 Subject: [PATCH 168/231] removed local .gitignore file --- .gitignore | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a13ea469..00000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea -ae.sh From e8fd373e6c68a7044a90b82690b917c1b9ce530e Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 10:58:56 -0300 Subject: [PATCH 169/231] removed blank space at ending of dnsapi/dns_kinghost.sh --- dnsapi/dns_kinghost.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index ddf9f899..d3a8fb3a 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -115,4 +115,4 @@ _kinghost_rest() { fi _debug2 response "$response" return 0 -} +} \ No newline at end of file From 86ef6e6987d6f8413f0f9184d008a6a5ea7e62b5 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 11:21:12 -0300 Subject: [PATCH 170/231] fixes on dnsapi/dns_kinghost.sh and dnsapi/README.md --- dnsapi/README.md | 2 +- dnsapi/dns_kinghost.sh | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index f99671e0..e459094e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -792,7 +792,7 @@ The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` an API access must be enabled at https://painel.kinghost.com.br/painel.api.php ``` -export KINGHOST_username="yourusername" +export KINGHOST_Username="yourusername" export KINGHOST_Password="yourpassword" acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com ``` diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index d3a8fb3a..7c0d159b 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -31,8 +31,8 @@ dns_kinghost_add() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" - _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" _debug "Getting txt records" _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" @@ -52,7 +52,7 @@ dns_kinghost_add() { return 1 fi - return 0; + return 0 } # Usage: fulldomain txtvalue @@ -63,7 +63,7 @@ dns_kinghost_rm() { KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" - if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then KINGHOST_Password="" KINGHOST_Username="" _err "You don't specify KingHost api key and email yet." @@ -89,7 +89,7 @@ dns_kinghost_rm() { return 1 fi - return 0; + return 0 } #################### Private functions below ################################## @@ -115,4 +115,4 @@ _kinghost_rest() { fi _debug2 response "$response" return 0 -} \ No newline at end of file +} From f8fb0e67b458821a913e981111b26196001e3a61 Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 12:17:10 -0300 Subject: [PATCH 171/231] fix dnsapi/dns_kinghost.sh with shfmt utility --- dnsapi/dns_kinghost.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 7c0d159b..2ac8e6df 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -31,8 +31,8 @@ dns_kinghost_add() { fi #save the credentials to the account conf file. - _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" - _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" _debug "Getting txt records" _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" From 9e3c931b34a438c78e03ab69206722330ec28297 Mon Sep 17 00:00:00 2001 From: martgras Date: Sun, 25 Mar 2018 17:47:56 +0200 Subject: [PATCH 172/231] dns_azure add support for validation record at domain apex Prevent the issue described in #1442 Fix [SC1117] Backslash is literal in "\[". --- dnsapi/dns_azure.sh | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_azure.sh b/dnsapi/dns_azure.sh index e0d9516f..c6893a0c 100644 --- a/dnsapi/dns_azure.sh +++ b/dnsapi/dns_azure.sh @@ -76,10 +76,10 @@ dns_azure_add() { 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 "[]\"")" + 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 "\"")" + 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 @@ -172,7 +172,7 @@ dns_azure_rm() { _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")" + 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 @@ -230,7 +230,7 @@ _azure_rest() { fi _ret="$?" _secure_debug2 "response $response" - _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 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 "http response code $_code" if [ "$_code" = "401" ]; then # we have an invalid access token set to expired @@ -308,7 +308,7 @@ _get_root() { domain=$1 subscriptionId=$2 accesstoken=$3 - i=2 + i=1 p=1 ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list @@ -328,9 +328,14 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(echo "$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) + if [ "$i" = 1 ]; then + #create the record at the domain apex (@) if only the domain name was provided as --domain-alias + _sub_domain="@" + else + _sub_domain=$(echo "$domain" | cut -d . -f 1-$p) + fi _domain=$h return 0 fi From 37bc099d393f661bce904097be027e4ccef87a9a Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 14:27:21 -0300 Subject: [PATCH 173/231] removed redundant api call --- dnsapi/dns_infraws.sh | 102 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 dnsapi/dns_infraws.sh diff --git a/dnsapi/dns_infraws.sh b/dnsapi/dns_infraws.sh new file mode 100644 index 00000000..30abcbfb --- /dev/null +++ b/dnsapi/dns_infraws.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env sh + +############################################################ +# Plugin para criação automática da entrada de DNS txt # +# Uso com o sistema acme.sh # +# # +# Author: Felipe Keller Braz # +# Report Bugs here: infra_interno@kinghost.com.br # +# # +# Values to export: # +# export INFRAWS_Hash="PASSWORD" # +############################################################ + +INFRAWS_Api="http://infra-ws.kinghost.net/serverbackend/acme" + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_infraws_add() { + fulldomain=$1 + txtvalue=$2 + + INFRAWS_Hash="${INFRAWS_Hash:-$(_readaccountconf_mutable INFRAWS_Hash)}" + + if [ -z "$INFRAWS_Hash" ]; then + INFRAWS_Hash="" + _err "You don't specify KingHost api password and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable INFRAWS_Hash "$INFRAWS_Hash" + + _debug "Getting txt records" + infraws_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exists + #We are creating a new txt record here, so we expect the "ok" status + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + infraws_rest POST "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0 +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_infraws_rm() { + fulldomain=$1 + txtvalue=$2 + + INFRAWS_Hash="${INFRAWS_Hash:-$(_readaccountconf_mutable INFRAWS_Hash)}" + if [ -z "$INFRAWS_Hash" ]; then + INFRAWS_Hash="" + _err "You don't specify KingHost api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + _debug "Getting txt records" + infraws_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + infraws_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## +infraws_rest() { + method=$1 + uri="$2" + data="$3" + _debug "$uri" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$INFRAWS_Api/hash/$INFRAWS_Hash/" "" "$method")" + else + response="$(_get "$INFRAWS_Api/hash/$INFRAWS_Hash/?$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $uri" + return 1 + fi + _debug2 response "$response" + return 0 +} From 2d1d512d0f968f0bdbca36aafdd043ec427a7bed Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Mon, 26 Mar 2018 14:28:52 -0300 Subject: [PATCH 174/231] removed redundant api call --- dnsapi/dns_kinghost.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/dnsapi/dns_kinghost.sh b/dnsapi/dns_kinghost.sh index 2ac8e6df..898ab286 100644 --- a/dnsapi/dns_kinghost.sh +++ b/dnsapi/dns_kinghost.sh @@ -71,17 +71,6 @@ dns_kinghost_rm() { return 1 fi - _debug "Getting txt records" - _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - #This API call returns "status":"ok" if dns record does not exists - #We are removing a txt record here, so the record must exists - if echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" if ! echo "$response" | grep '"status":"ok"' >/dev/null; then _err "Error" From 914808b867dd57c485edaab9a43358ac0716d41a Mon Sep 17 00:00:00 2001 From: Habetdin Date: Tue, 27 Mar 2018 06:16:39 +0300 Subject: [PATCH 175/231] Adding Zilore API support --- dnsapi/dns_zilore.sh | 139 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 dnsapi/dns_zilore.sh diff --git a/dnsapi/dns_zilore.sh b/dnsapi/dns_zilore.sh new file mode 100644 index 00000000..4365004b --- /dev/null +++ b/dnsapi/dns_zilore.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env sh + +Zilore_API="https://api.zilore.com/dns/v1" +# Zilore_Key="YOUR-ZILORE-API-KEY" + +######## Public functions ##################### + +dns_zilore_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using Zilore" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}" + if [ -z "$Zilore_Key" ]; then + Zilore_Key="" + _err "Please define Zilore API key" + return 1 + fi + _saveaccountconf_mutable Zilore_Key "$Zilore_Key" + + if ! _get_root "$fulldomain"; then + _err "Unable to determine root domain" + return 1 + else + _debug _domain "$_domain" + fi + + if _zilore_rest POST "domains/$_domain/records?record_type=TXT&record_ttl=600&record_name=$fulldomain&record_value=\"$txtvalue\""; then + if _contains "$response" '"added"' >/dev/null; then + _info "Added TXT record, waiting for validation" + return 0 + else + _debug response "$response" + _err "Error while adding DNS records" + return 1 + fi + fi + + return 1 +} + +dns_zilore_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Using Zilore" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}" + if [ -z "$Zilore_Key" ]; then + Zilore_Key="" + _err "Please define Zilore API key" + return 1 + fi + _saveaccountconf_mutable Zilore_Key "$Zilore_Key" + + if ! _get_root "$fulldomain"; then + _err "Unable to determine root domain" + return 1 + else + _debug _domain "$_domain" + fi + + _debug "Getting TXT records" + _zilore_rest GET "domains/${_domain}/records?search_text=$txtvalue&search_record_type=TXT" + _debug response "$response" + + if ! _contains "$response" '"ok"' >/dev/null; then + _err "Error while getting records list" + return 1 + else + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | head -n 1) + if [ -z "$_record_id" ]; then + _err "Cannot determine _record_id" + return 1 + else + _debug _record_id "$_record_id" + fi + if ! _zilore_rest DELETE "domains/${_domain}/records?record_id=$_record_id"; then + _err "Error while deleting chosen record" + return 1 + fi + _contains "$response" '"ok"' + fi +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=2 + 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 ! _zilore_rest GET "domains?search_text=$h"; then + return 1 + fi + + if _contains "$response" "\"$h\"" >/dev/null; then + _domain=$h + return 0 + else + _debug "$h not found" + fi + i=$(_math "$i" + 1) + done + return 1 +} + +_zilore_rest() { + method=$1 + param=$2 + data=$3 + + export _H1="X-Auth-Key: $Zilore_Key" + + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$Zilore_API/$param" "" "$method")" + else + response="$(_get "$Zilore_API/$param")" + fi + + if [ "$?" != "0" ]; then + _err "error $param" + return 1 + fi + + _debug2 response "$response" + return 0 +} From 6b0333e919e5d7eee10f7a0c3156b44bd81d7fcb Mon Sep 17 00:00:00 2001 From: Habetdin Date: Tue, 27 Mar 2018 06:21:10 +0300 Subject: [PATCH 176/231] Update README #1 --- dnsapi/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index f3edfb6f..9df2d01a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -787,6 +787,20 @@ 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. +## 42. Use Zilore API to automatically issue cert + +First you need to login to your Zilore account to get your API key. + +``` +export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_zilore -d example.com -d www.example.com +``` + +The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API From 882e1db1d61d129fa5354a7eeb4d70c77049fff0 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Tue, 27 Mar 2018 06:23:15 +0300 Subject: [PATCH 177/231] Update README #2 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6a268350..8d437291 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,7 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API +1. Zilore API And: From fde971fe81b5c64d724c1453a74d4023b3f13fb1 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Tue, 27 Mar 2018 06:31:25 +0300 Subject: [PATCH 178/231] Fix formatting --- dnsapi/dns_zilore.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_zilore.sh b/dnsapi/dns_zilore.sh index 4365004b..6969944c 100644 --- a/dnsapi/dns_zilore.sh +++ b/dnsapi/dns_zilore.sh @@ -106,7 +106,7 @@ _get_root() { fi if _contains "$response" "\"$h\"" >/dev/null; then - _domain=$h + _domain=$h return 0 else _debug "$h not found" From 986f61ac92bcb38b95d7eaff3612d8fb1ec6a5eb Mon Sep 17 00:00:00 2001 From: Felipe Braz Date: Wed, 28 Mar 2018 10:18:43 -0300 Subject: [PATCH 179/231] deleted wrog file --- dnsapi/dns_infraws.sh | 102 ------------------------------------------ 1 file changed, 102 deletions(-) delete mode 100644 dnsapi/dns_infraws.sh diff --git a/dnsapi/dns_infraws.sh b/dnsapi/dns_infraws.sh deleted file mode 100644 index 30abcbfb..00000000 --- a/dnsapi/dns_infraws.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env sh - -############################################################ -# Plugin para criação automática da entrada de DNS txt # -# Uso com o sistema acme.sh # -# # -# Author: Felipe Keller Braz # -# Report Bugs here: infra_interno@kinghost.com.br # -# # -# Values to export: # -# export INFRAWS_Hash="PASSWORD" # -############################################################ - -INFRAWS_Api="http://infra-ws.kinghost.net/serverbackend/acme" - -# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -# Used to add txt record -dns_infraws_add() { - fulldomain=$1 - txtvalue=$2 - - INFRAWS_Hash="${INFRAWS_Hash:-$(_readaccountconf_mutable INFRAWS_Hash)}" - - if [ -z "$INFRAWS_Hash" ]; then - INFRAWS_Hash="" - _err "You don't specify KingHost api password and email yet." - _err "Please create you key and try again." - return 1 - fi - - #save the credentials to the account conf file. - _saveaccountconf_mutable INFRAWS_Hash "$INFRAWS_Hash" - - _debug "Getting txt records" - infraws_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - #This API call returns "status":"ok" if dns record does not exists - #We are creating a new txt record here, so we expect the "ok" status - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - infraws_rest POST "dns" "name=$fulldomain&content=$txtvalue" - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - return 0 -} - -# Usage: fulldomain txtvalue -# Used to remove the txt record after validation -dns_infraws_rm() { - fulldomain=$1 - txtvalue=$2 - - INFRAWS_Hash="${INFRAWS_Hash:-$(_readaccountconf_mutable INFRAWS_Hash)}" - if [ -z "$INFRAWS_Hash" ]; then - INFRAWS_Hash="" - _err "You don't specify KingHost api key and email yet." - _err "Please create you key and try again." - return 1 - fi - - _debug "Getting txt records" - infraws_rest GET "dns" "name=$fulldomain&content=$txtvalue" - - infraws_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" - if ! echo "$response" | grep '"status":"ok"' >/dev/null; then - _err "Error" - _err "$response" - return 1 - fi - - return 0 -} - -#################### Private functions below ################################## -infraws_rest() { - method=$1 - uri="$2" - data="$3" - _debug "$uri" - - if [ "$method" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$INFRAWS_Api/hash/$INFRAWS_Hash/" "" "$method")" - else - response="$(_get "$INFRAWS_Api/hash/$INFRAWS_Hash/?$data")" - fi - - if [ "$?" != "0" ]; then - _err "error $uri" - return 1 - fi - _debug2 response "$response" - return 0 -} From b14ef537e13096d5565d71243b9c7f7976efa76f Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:14:45 +0300 Subject: [PATCH 180/231] head => _head_n --- dnsapi/dns_zilore.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_zilore.sh b/dnsapi/dns_zilore.sh index 6969944c..42111025 100644 --- a/dnsapi/dns_zilore.sh +++ b/dnsapi/dns_zilore.sh @@ -73,7 +73,7 @@ dns_zilore_rm() { _err "Error while getting records list" return 1 else - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | head -n 1) + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | _head_n 1) if [ -z "$_record_id" ]; then _err "Cannot determine _record_id" return 1 From b4f4c28871debcc627d1fc5225fbb34d0a1451e1 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:17:22 +0300 Subject: [PATCH 181/231] Update README.md --- dnsapi/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9df2d01a..10295266 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -787,7 +787,19 @@ 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. -## 42. Use Zilore API to automatically issue cert +## 42. Use KingHost DNS API + +API access must be enabled at https://painel.kinghost.com.br/painel.api.php + +``` +export KINGHOST_Username="yourusername" +export KINGHOST_Password="yourpassword" +acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com +``` + +The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 43. Use Zilore DNS API First you need to login to your Zilore account to get your API key. From 2bc38b206364d6b00e72cd217ddc933f2b1dbd4e Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:22:33 +0300 Subject: [PATCH 182/231] Revert "Update README.md" This reverts commit b4f4c28871debcc627d1fc5225fbb34d0a1451e1. --- dnsapi/README.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 10295266..9df2d01a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -787,19 +787,7 @@ 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. -## 42. Use KingHost DNS API - -API access must be enabled at https://painel.kinghost.com.br/painel.api.php - -``` -export KINGHOST_Username="yourusername" -export KINGHOST_Password="yourpassword" -acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com -``` - -The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. - -## 43. Use Zilore DNS API +## 42. Use Zilore API to automatically issue cert First you need to login to your Zilore account to get your API key. From ce9f77afed08f5a1136d903d87a434329a1d44e5 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:22:36 +0300 Subject: [PATCH 183/231] Revert "Update README #2" This reverts commit 882e1db1d61d129fa5354a7eeb4d70c77049fff0. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 8d437291..6a268350 100644 --- a/README.md +++ b/README.md @@ -315,7 +315,6 @@ You don't have to do anything manually! 1. zonomi.com DNS API 1. DreamHost.com API 1. DirectAdmin API -1. Zilore API And: From e32c2b84ee941fbefd74ddc735c14dd5533e5579 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:22:38 +0300 Subject: [PATCH 184/231] Revert "Update README #1" This reverts commit 6b0333e919e5d7eee10f7a0c3156b44bd81d7fcb. --- dnsapi/README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9df2d01a..f3edfb6f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -787,20 +787,6 @@ 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. -## 42. Use Zilore API to automatically issue cert - -First you need to login to your Zilore account to get your API key. - -``` -export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" -``` - -Ok, let's issue a cert now: -``` -acme.sh --issue --dns dns_zilore -d example.com -d www.example.com -``` - -The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API From ce9c22742503efed89dfa4300c7d72739fe9aaf9 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:25:52 +0300 Subject: [PATCH 185/231] Update README.md --- dnsapi/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index e459094e..10295266 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -799,6 +799,21 @@ acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 43. Use Zilore DNS API + +First you need to login to your Zilore account to get your API key. + +``` +export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_zilore -d example.com -d www.example.com +``` + +The `Zilore_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 8f5ee989baa03579a98c9434762bd2376263136b Mon Sep 17 00:00:00 2001 From: Habetdin Date: Wed, 28 Mar 2018 18:26:34 +0300 Subject: [PATCH 186/231] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4c46c926..b5d5aff0 100644 --- a/README.md +++ b/README.md @@ -316,6 +316,7 @@ You don't have to do anything manually! 1. DreamHost.com API 1. DirectAdmin API 1. KingHost (https://www.kinghost.com.br/) +1. Zilore (https://zilore.com) And: From 87a8dda95525eddcbac441d8944a94e63401d48d Mon Sep 17 00:00:00 2001 From: Bob Belnap Date: Wed, 28 Mar 2018 12:40:31 -0400 Subject: [PATCH 187/231] add chain cert --- deploy/vault_cli.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/vault_cli.sh b/deploy/vault_cli.sh index 02617c5e..79c25aa2 100644 --- a/deploy/vault_cli.sh +++ b/deploy/vault_cli.sh @@ -51,6 +51,7 @@ vault_cli_deploy() { $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1 $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 } From 696d9c6bd38a0424cbadd8985947fd14a38c4a66 Mon Sep 17 00:00:00 2001 From: Ivar Larsson Date: Wed, 28 Mar 2018 17:15:31 -0400 Subject: [PATCH 188/231] remove merge chars --- dnsapi/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 58ebecb1..af0542da 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -821,8 +821,6 @@ acme.sh --issue --dns dns_loopia -d example.com -d *.example.com The username and 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. From 98e15f658ef14c68c040766e4bb8c979ae5703a7 Mon Sep 17 00:00:00 2001 From: Habetdin Date: Thu, 29 Mar 2018 04:31:46 +0300 Subject: [PATCH 189/231] Update Zilore API description --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 10295266..ba1c045c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -801,7 +801,7 @@ The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/acc ## 43. Use Zilore DNS API -First you need to login to your Zilore account to get your API key. +First, get your API key at https://my.zilore.com/account/api ``` export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" @@ -809,7 +809,7 @@ export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9" Ok, let's issue a cert now: ``` -acme.sh --issue --dns dns_zilore -d example.com -d www.example.com +acme.sh --issue --dns dns_zilore -d example.com -d *.example.com ``` The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. From 09304c33c12277e85bf4229b0e0ec883beb182f6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 29 Mar 2018 21:51:33 +0800 Subject: [PATCH 190/231] start 2.7.9 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index da8e60c9..a5e4b391 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.8 +VER=2.7.9 PROJECT_NAME="acme.sh" From 499f745732863a210c66ee242f3ee26c142fc185 Mon Sep 17 00:00:00 2001 From: pandiloko <1jasotel@gmail.com> Date: Sun, 1 Apr 2018 14:41:35 +0200 Subject: [PATCH 191/231] False case in variable name for dreamhost api --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index ba1c045c..045ed0e1 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -753,7 +753,7 @@ 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="" +export DH_API_KEY="" acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com ``` From 792f3775ce464f4f7a9066bfe8e28ca33a394a55 Mon Sep 17 00:00:00 2001 From: martgras <25747549+martgras@users.noreply.github.com> Date: Mon, 2 Apr 2018 18:26:50 +0200 Subject: [PATCH 192/231] Fixes dns_he Issue #1476 username / password has to be urlencoded --- dnsapi/dns_he.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index d196fbec..da4a1b81 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -33,8 +33,9 @@ dns_he_add() { # 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}" + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" body="$body&account=" body="$body&menu=edit_zone" body="$body&Type=TXT" @@ -71,7 +72,9 @@ dns_he_rm() { _debug "Zone id \"$_zone_id\" will be used." # Find the record id to clean - body="email=${HE_Username}&pass=${HE_Password}" + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" body="$body&hosted_dns_zoneid=$_zone_id" body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" @@ -112,9 +115,15 @@ dns_he_rm() { _find_zone() { _domain="$1" - body="email=${HE_Username}&pass=${HE_Password}" + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" response="$(_post "$body" "https://dns.he.net/")" _debug2 response "$response" + if _contains "$response" '>Incorrect<'; then + _err "Unable to login to dns.he.net please check username and password" + return 1 + fi _table="$(echo "$response" | tr -d "#" | sed "s/
$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 112/231] 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
Date: Fri, 16 Mar 2018 11:20:18 +0100 Subject: [PATCH 193/231] add acme-dns plugin --- README.md | 1 + dnsapi/README.md | 16 +++++++++++++ dnsapi/dns_acmedns.sh | 55 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 dnsapi/dns_acmedns.sh diff --git a/README.md b/README.md index 44b96604..52f79974 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,7 @@ You don't have to do anything manually! 1. KingHost (https://www.kinghost.com.br/) 1. Zilore (https://zilore.com) 1. Loopia.se API +1. acme-dns (https://github.com/joohoi/acme-dns) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index bc1919de..b8bdbbb2 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -835,6 +835,22 @@ acme.sh --issue --dns dns_loopia -d example.com -d *.example.com ``` The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 45. Use ACME DNS API + +ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely. +https://github.com/joohoi/acme-dns + +``` +export ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update" +export ACMEDNS_USERNAME="" +export ACMEDNS_PASSWORD="" +export ACMEDNS_SUBDOMAIN="" + +acme.sh --issue --dns dns_acmedns -d example.com -d www.example.com +``` + +The credentials will be saved in `~/.acme.sh/account.conf` and will +be reused when needed. # Use custom API diff --git a/dnsapi/dns_acmedns.sh b/dnsapi/dns_acmedns.sh new file mode 100644 index 00000000..9b3efa48 --- /dev/null +++ b/dnsapi/dns_acmedns.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env sh +# +#Author: Wolfgang Ebner +#Report Bugs here: https://github.com/webner/acme.sh +# +######## Public functions ##################### + +#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_acmedns_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using acme-dns" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}" + ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}" + ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}" + ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}" + + if [ "$ACMEDNS_UPDATE_URL" = "" ]; then + ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update" + fi + + _saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL" + _saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME" + _saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD" + _saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN" + + export _H1="X-Api-User: $ACMEDNS_USERNAME" + export _H2="X-Api-Key: $ACMEDNS_PASSWORD" + data="{\"subdomain\":\"$ACMEDNS_SUBDOMAIN\", \"txt\": \"$txtvalue\"}" + + _debug data "$data" + response="$(_post "$data" "$ACMEDNS_UPDATE_URL" "" "POST")" + _debug response "$response" + + if ! echo "$response" | grep "\"$txtvalue\"" >/dev/null; then + _err "invalid response of acme-dns" + return 1 + fi + +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_acmedns_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using acme-dns" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" +} + +#################### Private functions below ################################## From ed817c81defb98efdbde427089c6a081990b98ce Mon Sep 17 00:00:00 2001 From: AlexeyStolyarov Date: Thu, 5 Apr 2018 14:18:53 +0500 Subject: [PATCH 194/231] #issue with nsupdate on Ubuntu 14.04.1 LTS on Ubuntu 14.04.1 LTS if nsupdate runs without port number given it treated argument following server name as port number. and throws error: ``` port 'update' is not numeric syntax error ``` --- dnsapi/dns_nsupdate.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 7acb2ef7..ad77502a 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -8,12 +8,14 @@ dns_nsupdate_add() { txtvalue=$2 _checkKeyFile || return 1 [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" + [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 # save the dns server and key to the account conf file. - _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" + _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER} " + _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT} " _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" nsupdate -k "${NSUPDATE_KEY}" < Date: Thu, 5 Apr 2018 14:45:15 +0500 Subject: [PATCH 195/231] Update dns_nsupdate.sh --- dnsapi/dns_nsupdate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index ad77502a..db653b6c 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -15,7 +15,7 @@ dns_nsupdate_add() { _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" nsupdate -k "${NSUPDATE_KEY}" < Date: Thu, 5 Apr 2018 14:50:55 +0500 Subject: [PATCH 196/231] Update dns_nsupdate.sh --- dnsapi/dns_nsupdate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index db653b6c..555f4d29 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -10,8 +10,8 @@ dns_nsupdate_add() { [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 # save the dns server and key to the account conf file. - _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER} " - _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT} " + _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" + _saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" nsupdate -k "${NSUPDATE_KEY}" < Date: Mon, 9 Apr 2018 00:10:27 +0200 Subject: [PATCH 197/231] Add Support for inwx mobile tan --- dnsapi/README.md | 8 ++++++++ dnsapi/dns_inwx.sh | 50 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index b8bdbbb2..a90b3f75 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -641,6 +641,14 @@ 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. +If your account is secured by mobile tan you have also defined the shared secret. + +``` +export INWX_Shared_Secret="shared secret" +``` + +You may need to re-enable the mobile tan to gain the shared secret. + ## 34. User Servercow API v1 Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user. diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 5dfba7d1..cd5af91b 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -4,6 +4,10 @@ #INWX_User="username" # #INWX_Password="password" +# +# Dependencies: +# ------------- +# - oathtool (When using 2 Factor Authentication) INWX_Api="https://api.domrobot.com/xmlrpc/" @@ -16,6 +20,7 @@ dns_inwx_add() { INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" + INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}" if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then INWX_User="" INWX_Password="" @@ -27,6 +32,7 @@ dns_inwx_add() { #save the api key and email to the account conf file. _saveaccountconf_mutable INWX_User "$INWX_User" _saveaccountconf_mutable INWX_Password "$INWX_Password" + _saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -148,8 +154,46 @@ _inwx_login() { ' $INWX_User $INWX_Password) response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + _H1=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')") + export _H1 - printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')" + #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71 + if _contains "$response" "tfa"; then + if [ -z "$INWX_Shared_Secret" ]; then + _err "Mobile TAN detected." + _err "Please define a shared secret." + return 1 + fi + + if ! _exists oathtool; then + _err "Please install oathtool to use 2 Factor Authentication." + _err "" + return 1 + fi + + tan="$(oathtool --base32 --totp "${INWX_Shared_Secret}" 2>/dev/null)" + + xml_content=$(printf ' + + account.unlock + + + + + + tan + + %s + + + + + + + ' "$tan") + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + fi } @@ -161,8 +205,8 @@ _get_root() { i=2 p=1 - _H1=$(_inwx_login) - export _H1 + _inwx_login + xml_content=' nameserver.list From 98a7e72f0aa581cb8f3a2a7f7734d728d571b1a7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 13 Apr 2018 21:28:13 +0800 Subject: [PATCH 198/231] fix https://github.com/Neilpang/acme.sh/issues/1512#issuecomment-381121303 --- 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 5fb1b174..ad1a2867 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -59,7 +59,7 @@ dns_gd_add() { _info "Adding record" if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then - if [ "$response" = "{}" ]; then + if [ "$response" = "{}" ] || [ "$response" = "null" ]; then _info "Added, sleeping 10 seconds" _sleep 10 #todo: check if the record takes effect From f8526f027cac5facbebe237252e5110a838ec3aa Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 20 Apr 2018 14:05:09 +0800 Subject: [PATCH 199/231] fix https://github.com/Neilpang/acme.sh/issues/1539 --- dnsapi/dns_gd.sh | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index ad1a2867..97902dfe 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -59,19 +59,13 @@ dns_gd_add() { _info "Adding record" if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then - if [ "$response" = "{}" ] || [ "$response" = "null" ]; 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 + _info "Added, sleeping 10 seconds" + _sleep 10 + #todo: check if the record takes effect + return 0 fi _err "Add txt record error." - + return 1 } #fulldomain From 8a5c4979ad96d3547c318e98b8633b1c77804c1e Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 20 Apr 2018 23:22:25 +0800 Subject: [PATCH 200/231] fix shellcheck --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index b6b57423..5d0e4db4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,12 +13,6 @@ 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 @@ -40,7 +34,6 @@ script: - 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 - matrix: fast_finish: true From f0a87da3759026176b5aa42dfcbe1c063974de70 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 20 Apr 2018 23:32:42 +0800 Subject: [PATCH 201/231] fix shfmt --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d0e4db4..04de1934 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,9 +23,7 @@ install: script: - 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 - - 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 curl -sSL $SHFMT_URL -o ~/shfmt && chmod +x ~/shfmt && ~/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 SC2181 **/*.sh && echo "shellcheck OK" ; fi From ce8dca7afe06c96cb0e1321bd552ef31c7c6003f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Apr 2018 13:15:17 +0800 Subject: [PATCH 202/231] move renewhook after installcert fix https://github.com/Neilpang/acme.sh/issues/1547 --- acme.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index a5e4b391..5fdac381 100755 --- a/acme.sh +++ b/acme.sh @@ -4287,20 +4287,21 @@ $_authorizations_map" Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - 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" _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" "$_real_fullchain" "$_reload_cmd" + if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then + return 1 + fi fi + if ! _on_issue_success "$_post_hook" "$_renew_hook"; then + _err "Call hook error." + return 1 + fi } #domain [isEcc] From 66686de4e4afc555260538c28b943777d79d019d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Apr 2018 13:21:56 +0800 Subject: [PATCH 203/231] add --branch --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 5fdac381..e7a30d91 100755 --- a/acme.sh +++ b/acme.sh @@ -5515,6 +5515,7 @@ Parameters: --openssl-bin Specifies a custom openssl bin location. --use-wget Force to use wget, if you have both curl and wget installed. --yes-I-know-dns-manual-mode-enough-go-ahead-please Force to use dns manual mode: $_DNS_MANUAL_WIKI + --branch, -b Only valid for '--upgrade' command, specifies the branch name to upgrade to. " } @@ -6059,6 +6060,10 @@ _process() { _use_wget="1" ACME_USE_WGET="1" ;; + --branch | -b) + export BRANCH="$2" + shift + ;; *) _err "Unknown parameter : $1" return 1 From 8259e82787befd82a52d1458d4f0a3a15afac5ec Mon Sep 17 00:00:00 2001 From: Oleg Rakovitch Date: Mon, 23 Apr 2018 18:34:15 +0300 Subject: [PATCH 204/231] Add missing package to docker image Issue #1552 --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index b2866739..5a64c720 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,7 @@ FROM alpine:3.6 RUN apk update -f \ && apk --no-cache add -f \ openssl \ + coreutils \ curl \ socat \ && rm -rf /var/cache/apk/* From 676402d918cb064999d05d33289e9f41fb3fe48a Mon Sep 17 00:00:00 2001 From: Kordian Bruck Date: Thu, 26 Apr 2018 11:40:17 +0200 Subject: [PATCH 205/231] Increase serial when adding txt records --- 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 1e500ad6..c8f7eedc 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -128,7 +128,7 @@ _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}}}" + curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}},\"update_serial\":true}}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'" _debug "Result of _ISPC_addTxt: '$curResult'" From e32b3aac22a64aa2357860f9cdf8697d268af811 Mon Sep 17 00:00:00 2001 From: Steffen Busch Date: Thu, 26 Apr 2018 21:02:37 +0200 Subject: [PATCH 206/231] Added --force-color to enforce the use of ANSI Color. Issue #1557 --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index e7a30d91..5e794a5a 100755 --- a/acme.sh +++ b/acme.sh @@ -124,21 +124,21 @@ if [ -t 1 ]; then fi __green() { - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then printf '\033[1;31;32m' fi printf -- "%b" "$1" - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then printf '\033[0m' fi } __red() { - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then printf '\033[1;31;40m' fi printf -- "%b" "$1" - if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then printf '\033[0m' fi } @@ -5501,6 +5501,7 @@ Parameters: --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. + --force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails. --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. @@ -5966,6 +5967,9 @@ _process() { --no-color) export ACME_NO_COLOR=1 ;; + --force-color) + export ACME_FORCE_COLOR=1 + ;; --ecc) _ecc="isEcc" ;; From 4e05062def15d4b99dcc6e26457ebebe853e977f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Bli=C5=BE=C3=ADk?= Date: Mon, 30 Apr 2018 15:09:07 +0200 Subject: [PATCH 207/231] add tele3-dns plugin --- README.md | 1 + dnsapi/README.md | 12 ++++++++ dnsapi/dns_tele3.sh | 70 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 dnsapi/dns_tele3.sh diff --git a/README.md b/README.md index 52f79974..f395e49a 100644 --- a/README.md +++ b/README.md @@ -319,6 +319,7 @@ You don't have to do anything manually! 1. Zilore (https://zilore.com) 1. Loopia.se API 1. acme-dns (https://github.com/joohoi/acme-dns) +1. TELE3 (https://www.tele3.cz) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index a90b3f75..ef61a244 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -859,7 +859,19 @@ acme.sh --issue --dns dns_acmedns -d example.com -d www.example.com The credentials will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 46. Use TELE3 API +First you need to login to your TELE3 account to set your API-KEY. +https://www.tele3.cz/system-acme-api.html + +``` +export TELE3_Key="MS2I4uPPaI..." +export TELE3_Secret="kjhOIHGJKHg" + +acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com +``` + +The TELE3_Key and TELE3_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_tele3.sh b/dnsapi/dns_tele3.sh new file mode 100644 index 00000000..3dced486 --- /dev/null +++ b/dnsapi/dns_tele3.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env sh +# +# tele3.cz DNS API +# +# Author: Roman Blizik +# Report Bugs here: https://github.com/par-pa/acme.sh +# +# -- +# export TELE3_Key="MS2I4uPPaI..." +# export TELE3_Secret="kjhOIHGJKHg" +# -- + +TELE3_API="https://www.tele3.cz/acme/" + +######## Public functions ##################### + +dns_tele3_add() { + _info "Using TELE3 DNS" + data="\"ope\":\"add\", \"domain\":\"$1\", \"value\":\"$2\"" + if ! _tele3_call; then + _err "Publish zone failed" + return 1 + fi + + _info "Zone published" +} + +dns_tele3_rm() { + _info "Using TELE3 DNS" + data="\"ope\":\"rm\", \"domain\":\"$1\", \"value\":\"$2\"" + if ! _tele3_call; then + _err "delete TXT record failed" + return 1 + fi + + _info "TXT record successfully deleted" +} + +#################### Private functions below ################################## + +_tele3_init() { + TELE3_Key="${TELE3_Key:-$(_readaccountconf_mutable TELE3_Key)}" + TELE3_Secret="${TELE3_Secret:-$(_readaccountconf_mutable TELE3_Secret)}" + if [ -z "$TELE3_Key" ] || [ -z "$TELE3_Secret" ]; then + TELE3_Key="" + TELE3_Secret="" + _err "You must export variables: TELE3_Key and TELE3_Secret" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable TELE3_Key "$TELE3_Key" + _saveaccountconf_mutable TELE3_Secret "$TELE3_Secret" +} + +_tele3_call() { + _tele3_init + data="{\"key\":\"$TELE3_Key\", \"secret\":\"$TELE3_Secret\", $data}" + + _debug data "$data" + + response="$(_post "$data" "$TELE3_API" "" "POST")" + _debug response "$response" + + if [ "$response" != "success" ]; then + _err "$response" + return 1 + fi +} + From 70b56eb527400f645e78004c56fd4154b9b2df1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Bli=C5=BE=C3=ADk?= Date: Wed, 2 May 2018 11:13:10 +0200 Subject: [PATCH 208/231] remove whitespace --- dnsapi/dns_tele3.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_tele3.sh b/dnsapi/dns_tele3.sh index 3dced486..76c90913 100644 --- a/dnsapi/dns_tele3.sh +++ b/dnsapi/dns_tele3.sh @@ -67,4 +67,3 @@ _tele3_call() { return 1 fi } - From 03a1386902fc38ce042c04e7af11c1fa629b6c58 Mon Sep 17 00:00:00 2001 From: Kordian Bruck Date: Wed, 2 May 2018 23:01:52 +0200 Subject: [PATCH 209/231] Update serial also when deleting the token --- dnsapi/dns_ispconfig.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index c8f7eedc..2d8d6b0a 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -128,7 +128,7 @@ _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}},\"update_serial\":true}}" + curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}},\"update_serial\":true}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'" _debug "Result of _ISPC_addTxt: '$curResult'" @@ -160,7 +160,7 @@ _ISPC_rmTxt() { *) unset IFS _info "Retrieved Record ID." - curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\"}" + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\",\"update_serial\":true}" curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")" _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'" _debug "Result of _ISPC_rmTxt: '$curResult'" From 360dc140ea101a319973afeaead4cdb2a016f027 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 01:28:56 -0500 Subject: [PATCH 210/231] implement basic haproxy deploy HAProxy requires the certificate chain and key to be concatenated and placed somewhere (can be anywhere). This script expects a single environment variable with the path where the concatenated PEM file should be written --- deploy/haproxy.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 34efbb1f..7eb23e26 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -20,7 +20,16 @@ haproxy_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _err "deploy cert to haproxy server, Not implemented yet" - return 1 + # combine the key and fullchain into a single pem and install + _savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH" + + _pem_full_path="$DEPLOY_HAPROXY_PEM_PATH/$_cdomain.pem" + _info "Full path to PEM $_pem_full_path" + + cat "$_cfullchain" "$_ckey" > "$_pem_full_path" + chmod 600 "$_pem_full_path" + + _info "Certificate successfully deployed" + return 0 } From 1eae73105a04e296e5c3d3524ccb2ab929196cd1 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 01:33:06 -0500 Subject: [PATCH 211/231] add docs for HAProxy deployment --- deploy/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 0b820dff..8fb6595d 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -255,3 +255,17 @@ acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox ```sh acme.sh --deploy -d ftp.example.com --deploy-hook strongswan ``` + +## 10. Deploy the cert to HAProxy + +You must specify the path where you want the concatenated key and certificate chain written. +```sh +export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy +``` + +You can then deploy the certificate as follows +```sh +acme.sh --deploy -d haproxy.example.com --deploy-hook haproxy +``` + +The path for the PEM file will be stored with the domain configuration and will be available when renewing, so that deploy will happen automatically when renewed. From 7573e560b63d009963711ef5df61d41837466a03 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 10:06:05 -0500 Subject: [PATCH 212/231] Add conditional check to ensure path is provided --- deploy/haproxy.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 7eb23e26..c263ab7d 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -23,7 +23,13 @@ haproxy_deploy() { # combine the key and fullchain into a single pem and install _savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH" - _pem_full_path="$DEPLOY_HAPROXY_PEM_PATH/$_cdomain.pem" + _pem_path="${DEPLOY_HAPROXY_PEM_PATH}" + if [ -z "$_pem_path" ]; then + _err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH." + return 1 + fi + + _pem_full_path="$_pem_path/$_cdomain.pem" _info "Full path to PEM $_pem_full_path" cat "$_cfullchain" "$_ckey" > "$_pem_full_path" From ec73aeba169cb2650491931db6fed4e62033ab2e Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 12:17:26 -0500 Subject: [PATCH 213/231] remove whitespace --- deploy/haproxy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index c263ab7d..d5cab9f5 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -32,7 +32,7 @@ haproxy_deploy() { _pem_full_path="$_pem_path/$_cdomain.pem" _info "Full path to PEM $_pem_full_path" - cat "$_cfullchain" "$_ckey" > "$_pem_full_path" + cat "$_cfullchain" "$_ckey" >"$_pem_full_path" chmod 600 "$_pem_full_path" _info "Certificate successfully deployed" From 5f593994c785f74732ef3728d68d86b56713eca4 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Thu, 3 May 2018 12:25:11 -0500 Subject: [PATCH 214/231] remove more whitespace (trying to get TravisCI working) --- deploy/haproxy.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index d5cab9f5..77f9c94f 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -28,7 +28,6 @@ haproxy_deploy() { _err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH." return 1 fi - _pem_full_path="$_pem_path/$_cdomain.pem" _info "Full path to PEM $_pem_full_path" From 681e3785efdbe84b25f9f40f647694bb4fb0f262 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 May 2018 22:23:56 +0800 Subject: [PATCH 215/231] add dns alias mode --- dnsapi/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index a90b3f75..aa8ae6be 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1,5 +1,9 @@ # How to use DNS API +If your dns provider doesn't provide api access, you can use our dns alias mode: + +https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode + ## 1. Use CloudFlare domain API to automatically issue cert First you need to login to your CloudFlare account to get your API key. From e9e999542d62ef30f417f84254264051060068a6 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Fri, 4 May 2018 10:14:31 -0500 Subject: [PATCH 216/231] add reload --- deploy/haproxy.sh | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 77f9c94f..0b89b7ae 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -20,9 +20,18 @@ haproxy_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - # combine the key and fullchain into a single pem and install + # handle reload preference + DEFAULT_HAPROXY_RELOAD="/usr/sbin/service haproxy restart" + if [[ -z "${DEPLOY_HAPROXY_RELOAD}" ]]; then + _reload="${DEFAULT_HAPROXY_RELOAD}" + _cleardomainconf DEPLOY_HAPROXY_RELOAD + else + _reload="${DEPLOY_HAPROXY_RELOAD}" + _savedomainconf DEPLOY_HAPROXY_RELOAD "$DEPLOY_HAPROXY_RELOAD" + fi _savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH" + # work out the path where the PEM file should go _pem_path="${DEPLOY_HAPROXY_PEM_PATH}" if [ -z "$_pem_path" ]; then _err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH." @@ -31,10 +40,19 @@ haproxy_deploy() { _pem_full_path="$_pem_path/$_cdomain.pem" _info "Full path to PEM $_pem_full_path" + # combine the key and fullchain into a single pem and install cat "$_cfullchain" "$_ckey" >"$_pem_full_path" chmod 600 "$_pem_full_path" - _info "Certificate successfully deployed" - return 0 + + # restart HAProxy + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + return 0 + else + _err "Reload error" + return 1 + fi } From afe5cb588d97ba723680c181ec5c1bd69892cd2c Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Fri, 4 May 2018 10:25:54 -0500 Subject: [PATCH 217/231] update for POSIX compliance --- deploy/haproxy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index 0b89b7ae..5c1a40e2 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -22,7 +22,7 @@ haproxy_deploy() { # handle reload preference DEFAULT_HAPROXY_RELOAD="/usr/sbin/service haproxy restart" - if [[ -z "${DEPLOY_HAPROXY_RELOAD}" ]]; then + if [ -z "${DEPLOY_HAPROXY_RELOAD}" ]; then _reload="${DEFAULT_HAPROXY_RELOAD}" _cleardomainconf DEPLOY_HAPROXY_RELOAD else From c9818ea2c46183ba8db09a21fe6308f93a159028 Mon Sep 17 00:00:00 2001 From: Daniel Watrous Date: Fri, 4 May 2018 13:03:27 -0500 Subject: [PATCH 218/231] add documentation for reload command --- deploy/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 8fb6595d..181989da 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -263,6 +263,12 @@ You must specify the path where you want the concatenated key and certificate ch export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy ``` +You may optionally define the command to reload HAProxy. The value shown below will be used as the default if you don't set this environment variable. + +```sh +export DEPLOY_HAPROXY_RELOAD="/usr/sbin/service haproxy restart" +``` + You can then deploy the certificate as follows ```sh acme.sh --deploy -d haproxy.example.com --deploy-hook haproxy From 206be3c1619a699af3e53636935e64f51493cd2f Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 29 May 2018 22:38:52 +0800 Subject: [PATCH 219/231] fix https://github.com/Neilpang/acme.sh/issues/1633 --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 5e794a5a..713170b7 100755 --- a/acme.sh +++ b/acme.sh @@ -4676,19 +4676,19 @@ _installcert() { if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then cp "$_real_cert" "$_backup_path/cert.bak" fi - cat "$CERT_PATH" >"$_real_cert" + cat "$CERT_PATH" >"$_real_cert" || return 1 fi 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" + cat "$CA_CERT_PATH" >>"$_real_ca" || return 1 else if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then cp "$_real_ca" "$_backup_path/ca.bak" fi - cat "$CA_CERT_PATH" >"$_real_ca" + cat "$CA_CERT_PATH" >"$_real_ca" || return 1 fi fi @@ -4698,9 +4698,9 @@ _installcert() { cp "$_real_key" "$_backup_path/key.bak" fi if [ -f "$_real_key" ]; then - cat "$CERT_KEY_PATH" >"$_real_key" + cat "$CERT_KEY_PATH" >"$_real_key" || return 1 else - cat "$CERT_KEY_PATH" >"$_real_key" + cat "$CERT_KEY_PATH" >"$_real_key" || return 1 chmod 600 "$_real_key" fi fi @@ -4710,7 +4710,7 @@ _installcert() { if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then cp "$_real_fullchain" "$_backup_path/fullchain.bak" fi - cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" + cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" || return 1 fi if [ "$_reload_cmd" ]; then From f90a2ae1959ea359412a0b570de99e083babed65 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 12 Jun 2018 21:19:27 +0800 Subject: [PATCH 220/231] check UNABLE_TO_AUTHENTICATE --- dnsapi/dns_gd.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 97902dfe..7cf47386 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -168,5 +168,9 @@ _gd_rest() { return 1 fi _debug2 response "$response" + if _contains "$response" "UNABLE_TO_AUTHENTICATE"; then + _err "It seems that your api key or secret is not correct." + return 1 + fi return 0 } From d987d61ea96da50a2efd733724b7f6b49c8da7df Mon Sep 17 00:00:00 2001 From: Santeri Kannisto Date: Thu, 28 Jun 2018 09:38:14 +0200 Subject: [PATCH 221/231] Issue #1328 bug fix v3 Eliminated php dependency with a private function for urlencode using sed. Php had failed on godaddy due to multiple php instances and naturally cron using the one without the necessary -r option. Compared to previous PR the sed code is now POSIX and should work on all environments. --- deploy/cpanel_uapi.sh | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index 4563b9c4..053a0c92 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -2,8 +2,12 @@ # Here is the script to deploy the cert to your cpanel using the cpanel API. # Uses command line uapi. --user option is needed only if run as root. # Returns 0 when success. -# Written by Santeri Kannisto -# Public domain, 2017 +# +# Please note that I am no longer using Github. If you want to report an issue +# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/ +# +# Written by Santeri Kannisto +# Public domain, 2017-2018 #export DEPLOY_CPANEL_USER=myusername @@ -28,15 +32,9 @@ cpanel_uapi_deploy() { _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") - _cert=$(php -r "echo urlencode(\"$_certstr\");") - _key=$(php -r "echo urlencode(\"$_keystr\");") + _cert=$(cat "$_ccert" | _url_encode) + _key=$(cat "$_ckey" | _url_encode) _debug _cert "$_cert" _debug _key "$_key" From 05dea7b22ac15c6748e79f4beed02c22b39b3784 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 28 Jun 2018 20:34:29 +0800 Subject: [PATCH 222/231] fix warning --- 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 053a0c92..01cb94ee 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -33,8 +33,8 @@ cpanel_uapi_deploy() { return 1 fi # read cert and key files and urlencode both - _cert=$(cat "$_ccert" | _url_encode) - _key=$(cat "$_ckey" | _url_encode) + _cert=$(_url_encode < "$_ccert") + _key=$(_url_encode < "$_ckey") _debug _cert "$_cert" _debug _key "$_key" From 9c545059ae43396c49b35c1870496ec58406b495 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 28 Jun 2018 22:21:22 +0800 Subject: [PATCH 223/231] fix warning --- 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 01cb94ee..44844f79 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -33,8 +33,8 @@ cpanel_uapi_deploy() { return 1 fi # read cert and key files and urlencode both - _cert=$(_url_encode < "$_ccert") - _key=$(_url_encode < "$_ckey") + _cert=$(_url_encode <"$_ccert") + _key=$(_url_encode <"$_ckey") _debug _cert "$_cert" _debug _key "$_key" From 26c669e42da5e87c8d616e6c20c53e26e94d2c21 Mon Sep 17 00:00:00 2001 From: Will Date: Sun, 1 Jul 2018 18:53:47 -0400 Subject: [PATCH 224/231] Update README.md - HTTPS For centminmod.com Link Update README.md - HTTPS For centminmod.com Link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f395e49a..cb2c8cb2 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [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) +- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) From 28e4bcf67f82c9aa6e88224aa528cb629eff5743 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 16:04:18 +0200 Subject: [PATCH 225/231] initial version with Euserv.eu DNS API Support --- dnsapi/dns_euserv.sh | 358 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 dnsapi/dns_euserv.sh diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh new file mode 100644 index 00000000..1a58df51 --- /dev/null +++ b/dnsapi/dns_euserv.sh @@ -0,0 +1,358 @@ +#!/usr/bin/env sh + +#This is the euserv.eu api wrapper for acme.sh +# +#Author: Michael Brueckner +#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de + +# +#EUSERV_Username="username" +# +#EUSERV_Password="password" +# +# Dependencies: +# ------------- +# - none - + +EUSERV_Api="https://api.euserv.net" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_euserv_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_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" + + _info "Adding record" + _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +#fulldomain txtvalue +dns_euserv_rm() { + + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_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" + + xml_content=$(printf ' + + domain.dns_get_active_records + + + + + + login + + %s + + + + password + + %s + + + + domain_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not get txt records" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + +# _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) +# _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + + if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then + _info "Do not need to delete record" + else + # find block where txtvalue is in. the record_id is allways prior this line! + _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) + # record_id is the last entry with a number, identified by the postfix of + _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) + _info "Deleting record" + _euserv_delete_record "$_record_id" + fi + +} + +#################### Private functions below ################################## + +_euserv_get_domain_orders() { +# returns: _euserv_domain_orders + + _debug "get domain_orders" + + xml_content=$(printf ' + + domain.get_domain_orders + + + + + + login + %s + + + password + %s + + + + + + ' "$EUSERV_Username" "$EUSERV_Password") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not get domain orders" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + _euserv_domain_orders="$response" + return 0 +} + +_euserv_get_domain_id() { +# returns: _euserv_domain_id + domain=$1 + _debug "get domain_id" + + _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) + _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + + if [ -z "$_euserv_domain_id" ] ; then + _err "Could not find domain_id for domain $domain" + _debug "_euserv_domain_orders" "$_euserv_domain_orders" + return 1 + fi + return 0 + +} + +_get_root() { + domain=$1 + _debug "get root" + + # Just to read the domain_orders once + + domain=$1 + i=2 + p=1 + _euserv_get_domain_orders + response="$_euserv_domain_orders" + + 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" + if ! _euserv_get_domain_id "$_domain"; then + _err "invalid domain" + return 1 + fi + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +# TODO +_euserv_delete_record() { + record_id=$1 + xml_content=$(printf ' + + domain.dns_delete_record + + + + + + login + + %s + + + + password + + %s + + + + dns_record_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$record_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error deleting record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + return 0 + +} + +_euserv_add_record() { + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + domain.dns_create_record + + + + + + login + + %s + + + + password + + %s + + + domain_id + + %s + + + + dns_record_subdomain + + %s + + + + dns_record_type + + TXT + + + + dns_record_value + + %s + + + + dns_record_ttl + + 300 + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval" ) + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not create record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi +# _dns_record_id="$(echo "$response" | _egrep_o "[\s\S]dns_record_id<\/name>[\s]*?[\s]*?(\K\d*)")" +# _debug "_dns_record_id" "$_dns_record_id" + return 0 +} From 94f91ae6878f8652cc947a98aa7b78dd42334c0c Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 16:04:18 +0200 Subject: [PATCH 226/231] initial version with Euserv.eu DNS API Support - added dnsapi/dns_euserv.sh - modified dnsapi/README.md --- dnsapi/README.md | 25 ++- dnsapi/dns_euserv.sh | 358 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 dnsapi/dns_euserv.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index ef6c9d09..9f60764f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -876,6 +876,29 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com ``` The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. +## 47. euserv.eu API to automatically issue cert + +First you need to login to your euserv.eu account to activate your API Administration (API Verwaltung). +[https://support.euserv.com](https://support.euserv.com) + +Once you've activate, login to your API Admin Interface and create an Account. +Please specify the scope (active groups: domain) and assign the allowed IPs. + +Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates! + +``` +export EUSERV_Username="99999.user123" +export EUSERV_Password="Asbe54gHde" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure +``` + +The `EUSERV_Username` and `EUSERV_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +Please report any issues to https://github.com/initit/acme.sh or to # Use custom API If your API is not supported yet, you can write your own DNS API. @@ -896,4 +919,4 @@ See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide # Use lexicon DNS API -https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api +https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api \ No newline at end of file diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh new file mode 100644 index 00000000..1a58df51 --- /dev/null +++ b/dnsapi/dns_euserv.sh @@ -0,0 +1,358 @@ +#!/usr/bin/env sh + +#This is the euserv.eu api wrapper for acme.sh +# +#Author: Michael Brueckner +#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de + +# +#EUSERV_Username="username" +# +#EUSERV_Password="password" +# +# Dependencies: +# ------------- +# - none - + +EUSERV_Api="https://api.euserv.net" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_euserv_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_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" + + _info "Adding record" + _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +#fulldomain txtvalue +dns_euserv_rm() { + + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_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" + + xml_content=$(printf ' + + domain.dns_get_active_records + + + + + + login + + %s + + + + password + + %s + + + + domain_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not get txt records" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + +# _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) +# _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + + if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then + _info "Do not need to delete record" + else + # find block where txtvalue is in. the record_id is allways prior this line! + _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) + # record_id is the last entry with a number, identified by the postfix of + _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) + _info "Deleting record" + _euserv_delete_record "$_record_id" + fi + +} + +#################### Private functions below ################################## + +_euserv_get_domain_orders() { +# returns: _euserv_domain_orders + + _debug "get domain_orders" + + xml_content=$(printf ' + + domain.get_domain_orders + + + + + + login + %s + + + password + %s + + + + + + ' "$EUSERV_Username" "$EUSERV_Password") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not get domain orders" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + _euserv_domain_orders="$response" + return 0 +} + +_euserv_get_domain_id() { +# returns: _euserv_domain_id + domain=$1 + _debug "get domain_id" + + _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) + _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + + if [ -z "$_euserv_domain_id" ] ; then + _err "Could not find domain_id for domain $domain" + _debug "_euserv_domain_orders" "$_euserv_domain_orders" + return 1 + fi + return 0 + +} + +_get_root() { + domain=$1 + _debug "get root" + + # Just to read the domain_orders once + + domain=$1 + i=2 + p=1 + _euserv_get_domain_orders + response="$_euserv_domain_orders" + + 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" + if ! _euserv_get_domain_id "$_domain"; then + _err "invalid domain" + return 1 + fi + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +# TODO +_euserv_delete_record() { + record_id=$1 + xml_content=$(printf ' + + domain.dns_delete_record + + + + + + login + + %s + + + + password + + %s + + + + dns_record_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$record_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error deleting record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + return 0 + +} + +_euserv_add_record() { + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + domain.dns_create_record + + + + + + login + + %s + + + + password + + %s + + + domain_id + + %s + + + + dns_record_subdomain + + %s + + + + dns_record_type + + TXT + + + + dns_record_value + + %s + + + + dns_record_ttl + + 300 + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval" ) + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + ok="$(printf '%s' "$response" | grep "status100")" + if [ -z "$ok" ]; then + _err "Error could not create record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi +# _dns_record_id="$(echo "$response" | _egrep_o "[\s\S]dns_record_id<\/name>[\s]*?[\s]*?(\K\d*)")" +# _debug "_dns_record_id" "$_dns_record_id" + return 0 +} From d99968ee6d39c759909c8742592c349a00f336fd Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 16:25:35 +0200 Subject: [PATCH 227/231] Modified dnsapi/README.md --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9f60764f..49f2625d 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -878,10 +878,10 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. ## 47. euserv.eu API to automatically issue cert -First you need to login to your euserv.eu account to activate your API Administration (API Verwaltung). +First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung). [https://support.euserv.com](https://support.euserv.com) -Once you've activate, login to your API Admin Interface and create an Account. +Once you've activate, login to your API Admin Interface and create an API account. Please specify the scope (active groups: domain) and assign the allowed IPs. Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates! From 616b0b6baa0eb08670ac0876f6b74a7627076629 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 22:50:52 +0200 Subject: [PATCH 228/231] fixed shfmt related errors in dns_euserv.sh and modified README.md --- README.md | 1 + dnsapi/README.md | 6 +- dnsapi/dns_euserv.sh | 142 +++++++++++++++++++++---------------------- 3 files changed, 74 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index f395e49a..bda7252f 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,7 @@ You don't have to do anything manually! 1. Loopia.se API 1. acme-dns (https://github.com/joohoi/acme-dns) 1. TELE3 (https://www.tele3.cz) +1. EUSERV.EU (https://www.euserv.eu) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 49f2625d..1f394f92 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -876,7 +876,7 @@ acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com ``` The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed. -## 47. euserv.eu API to automatically issue cert +## 47. Use Euserv.eu API First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung). [https://support.euserv.com](https://support.euserv.com) @@ -884,14 +884,12 @@ First you need to login to your euserv.eu account and activate your API Administ Once you've activate, login to your API Admin Interface and create an API account. Please specify the scope (active groups: domain) and assign the allowed IPs. -Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates! - ``` export EUSERV_Username="99999.user123" export EUSERV_Password="Asbe54gHde" ``` -Ok, let's issue a cert now: +Ok, let's issue a cert now: (Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates!) ``` acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure ``` diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh index 1a58df51..cb1e0a4d 100644 --- a/dnsapi/dns_euserv.sh +++ b/dnsapi/dns_euserv.sh @@ -42,11 +42,12 @@ dns_euserv_add() { _err "invalid domain" return 1 fi - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - + _debug "_sub_domain" "$_sub_domain" + _debug "_domain" "$_domain" _info "Adding record" - _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue" + if ! _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue"; then + return 1 + fi } @@ -114,24 +115,20 @@ dns_euserv_rm() { export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" - ok="$(printf '%s' "$response" | grep "status100")" - if [ -z "$ok" ]; then - _err "Error could not get txt records" + if ! _contains "$response" "status100"; then + _err "Error could not get txt records" _debug "xml_content" "$xml_content" _debug "response" "$response" return 1 fi -# _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) -# _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) - if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then _info "Do not need to delete record" else - # find block where txtvalue is in. the record_id is allways prior this line! - _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) - # record_id is the last entry with a number, identified by the postfix of - _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) + # find XML block where txtvalue is in. The record_id is allways prior this line! + _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) + # record_id is the last Tag with a number before the row _endLine, identified by + _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) _info "Deleting record" _euserv_delete_record "$_record_id" fi @@ -140,11 +137,52 @@ dns_euserv_rm() { #################### Private functions below ################################## +_get_root() { + domain=$1 + _debug "get root" + + # Just to read the domain_orders once + + domain=$1 + i=2 + p=1 + + if ! _euserv_get_domain_orders; then + return 1 + fi + + # Get saved response with domain_orders + response="$_euserv_domain_orders" + + 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" + if ! _euserv_get_domain_id "$_domain"; then + _err "invalid domain" + return 1 + fi + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + _euserv_get_domain_orders() { -# returns: _euserv_domain_orders + # returns: _euserv_domain_orders _debug "get domain_orders" - + xml_content=$(printf ' domain.get_domain_orders @@ -165,76 +203,41 @@ _euserv_get_domain_orders() { ' "$EUSERV_Username" "$EUSERV_Password") - + export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" - - ok="$(printf '%s' "$response" | grep "status100")" - if [ -z "$ok" ]; then + + if ! _contains "$response" "status100"; then _err "Error could not get domain orders" _debug "xml_content" "$xml_content" _debug "response" "$response" return 1 fi - + + # save response to reduce API calls _euserv_domain_orders="$response" return 0 } _euserv_get_domain_id() { -# returns: _euserv_domain_id + # returns: _euserv_domain_id domain=$1 _debug "get domain_id" - _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1 ) - _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/' ) + # find line where the domain name is within the $response + _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1) + # next occurency of domain_id after the domain_name is the correct one + _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/') - if [ -z "$_euserv_domain_id" ] ; then + if [ -z "$_euserv_domain_id" ]; then _err "Could not find domain_id for domain $domain" _debug "_euserv_domain_orders" "$_euserv_domain_orders" return 1 fi - return 0 - -} - -_get_root() { - domain=$1 - _debug "get root" - - # Just to read the domain_orders once - - domain=$1 - i=2 - p=1 - _euserv_get_domain_orders - response="$_euserv_domain_orders" - - 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" - if ! _euserv_get_domain_id "$_domain"; then - _err "invalid domain" - return 1 - fi - return 0 - fi - p=$i - i=$(_math "$i" + 1) - done - return 1 + return 0 } -# TODO _euserv_delete_record() { record_id=$1 xml_content=$(printf ' @@ -271,14 +274,13 @@ _euserv_delete_record() { export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" - ok="$(printf '%s' "$response" | grep "status100")" - if [ -z "$ok" ]; then + if ! _contains "$response" "status100"; then _err "Error deleting record" _debug "xml_content" "$xml_content" _debug "response" "$response" return 1 fi - + return 0 } @@ -340,19 +342,17 @@ _euserv_add_record() { - ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval" ) + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval") export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" - ok="$(printf '%s' "$response" | grep "status100")" - if [ -z "$ok" ]; then + if ! _contains "$response" "status100"; then _err "Error could not create record" _debug "xml_content" "$xml_content" _debug "response" "$response" return 1 fi -# _dns_record_id="$(echo "$response" | _egrep_o "[\s\S]dns_record_id<\/name>[\s]*?[\s]*?(\K\d*)")" -# _debug "_dns_record_id" "$_dns_record_id" + return 0 } From 261cc448f78729ec52992b9a010e7eb32daca0e1 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 8 Jul 2018 23:00:26 +0200 Subject: [PATCH 229/231] fixed shfmt related errors in dns_euserv.sh and modified README.md --- dnsapi/dns_euserv.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh index cb1e0a4d..44120a3d 100644 --- a/dnsapi/dns_euserv.sh +++ b/dnsapi/dns_euserv.sh @@ -43,10 +43,10 @@ dns_euserv_add() { return 1 fi _debug "_sub_domain" "$_sub_domain" - _debug "_domain" "$_domain" + _debug "_domain" "$_domain" _info "Adding record" - if ! _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue"; then - return 1 + if ! _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue"; then + return 1 fi } @@ -80,7 +80,7 @@ dns_euserv_rm() { _debug "_domain" "$_domain" _debug "Getting txt records" - + xml_content=$(printf ' domain.dns_get_active_records @@ -111,7 +111,7 @@ dns_euserv_rm() { ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id") - + export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" @@ -126,9 +126,9 @@ dns_euserv_rm() { _info "Do not need to delete record" else # find XML block where txtvalue is in. The record_id is allways prior this line! - _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1 ) + _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1) # record_id is the last Tag with a number before the row _endLine, identified by - _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/' ) + _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/') _info "Deleting record" _euserv_delete_record "$_record_id" fi @@ -168,7 +168,7 @@ _get_root() { if ! _euserv_get_domain_id "$_domain"; then _err "invalid domain" return 1 - fi + fi return 0 fi p=$i @@ -343,7 +343,7 @@ _euserv_add_record() { ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval") - + export _H1="Content-Type: text/xml" response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" From 2945b230e4dd4c03de5c48f1f65ca07fe45045fd Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 9 Jul 2018 22:54:34 +0200 Subject: [PATCH 230/231] replaced tail/head with _tail_n/_head_n and printf with echo --- dnsapi/dns_euserv.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_euserv.sh b/dnsapi/dns_euserv.sh index 44120a3d..38101565 100644 --- a/dnsapi/dns_euserv.sh +++ b/dnsapi/dns_euserv.sh @@ -122,13 +122,13 @@ dns_euserv_rm() { return 1 fi - if ! printf "%s" "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then + if ! echo "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then _info "Do not need to delete record" else # find XML block where txtvalue is in. The record_id is allways prior this line! - _endLine=$(printf '%s' "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1) + _endLine=$(echo "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1) # record_id is the last Tag with a number before the row _endLine, identified by - _record_id=$(printf '%s' "$response" | sed -n '1,'"$_endLine"'p' | grep '' | tail -n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/') + _record_id=$(echo "$response" | sed -n '1,'"$_endLine"'p' | grep '' | _tail_n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/') _info "Deleting record" _euserv_delete_record "$_record_id" fi @@ -155,7 +155,7 @@ _get_root() { response="$_euserv_domain_orders" while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) + h=$(echo "$domain" | cut -d . -f $i-100) _debug h "$h" if [ -z "$h" ]; then #not valid @@ -163,7 +163,7 @@ _get_root() { fi if _contains "$response" "$h"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(echo "$domain" | cut -d . -f 1-$p) _domain="$h" if ! _euserv_get_domain_id "$_domain"; then _err "invalid domain" @@ -225,9 +225,9 @@ _euserv_get_domain_id() { _debug "get domain_id" # find line where the domain name is within the $response - _startLine=$(printf '%s' "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1) + _startLine=$(echo "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1) # next occurency of domain_id after the domain_name is the correct one - _euserv_domain_id=$(printf '%s' "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | head -n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/') + _euserv_domain_id=$(echo "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | _head_n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/') if [ -z "$_euserv_domain_id" ]; then _err "Could not find domain_id for domain $domain" From 9cecd525e20cec8500e33629690fefd8182006d8 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 18 Jul 2018 00:26:21 +0800 Subject: [PATCH 231/231] fix JWS has an invalid anti-replay nonce https://github.com/Neilpang/acme.sh/issues/1630 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 713170b7..c23942fb 100755 --- a/acme.sh +++ b/acme.sh @@ -1607,7 +1607,7 @@ _inithttp() { } -# body url [needbase64] [POST|PUT] [ContentType] +# body url [needbase64] [POST|PUT|DELETE] [ContentType] _post() { body="$1" _post_url="$2" @@ -1897,7 +1897,7 @@ _send_signed_request() { _debug3 _body "$_body" fi - if _contains "$_body" "JWS has invalid anti-replay nonce"; then + if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then _info "It seems the CA server is busy now, let's wait and retry." _sleep 5 continue