Merge remote-tracking branch 'upstream/master' into ssh-deploy

This commit is contained in:
David Kerr 2017-02-20 15:27:10 -05:00
commit e0b00ee11a
16 changed files with 873 additions and 195 deletions

View File

@ -292,6 +292,7 @@ You don't have to do anything manually!
1. Alwaysdata.com API 1. Alwaysdata.com API
1. Linode.com API 1. Linode.com API
1. FreeDNS (https://freedns.afraid.org/) 1. FreeDNS (https://freedns.afraid.org/)
1. cyon.ch
**More APIs coming soon...** **More APIs coming soon...**
@ -378,21 +379,21 @@ acme.sh --upgrade --auto-upgrade 0
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
# Under the Hood # 14. Under the Hood
Speak ACME language using shell, directly to "Let's Encrypt". Speak ACME language using shell, directly to "Let's Encrypt".
TODO: TODO:
# Acknowledgments # 15. Acknowledgments
1. Acme-tiny: https://github.com/diafygi/acme-tiny 1. Acme-tiny: https://github.com/diafygi/acme-tiny
2. ACME protocol: https://github.com/ietf-wg-acme/acme 2. ACME protocol: https://github.com/ietf-wg-acme/acme
3. Certbot: https://github.com/certbot/certbot 3. Certbot: https://github.com/certbot/certbot
# License & Others # 16. License & Others
License is GPLv3 License is GPLv3
@ -401,8 +402,9 @@ 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. [Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
# Donate # 17. Donate
Your donation makes **acme.sh** better:
1. PayPal: donate@acme.sh
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
[Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) [Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list)

458
acme.sh
View File

@ -71,6 +71,8 @@ DEBUG_LEVEL_3=3
DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1
DEBUG_LEVEL_NONE=0 DEBUG_LEVEL_NONE=0
HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)"
SYSLOG_ERROR="user.error" SYSLOG_ERROR="user.error"
SYSLOG_INFO="user.info" SYSLOG_INFO="user.info"
SYSLOG_DEBUG="user.debug" SYSLOG_DEBUG="user.debug"
@ -212,6 +214,27 @@ _debug() {
fi fi
} }
#output the sensitive messages
_secure_debug() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_debug2() { _debug2() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then
_log "$@" _log "$@"
@ -224,6 +247,26 @@ _debug2() {
fi fi
} }
_secure_debug2() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_debug3() { _debug3() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then
_log "$@" _log "$@"
@ -236,6 +279,26 @@ _debug3() {
fi fi
} }
_secure_debug3() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_startswith() { _startswith() {
_str="$1" _str="$1"
_sub="$2" _sub="$2"
@ -1025,7 +1088,7 @@ _readKeyLengthFromCSR() {
echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
else else
_debug "RSA CSR" _debug "RSA CSR"
echo "$_outcsr" | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 echo "$_outcsr" | _egrep_o "(^ *|^RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
fi fi
} }
@ -1667,7 +1730,7 @@ _setopt() {
_debug3 APP _debug3 APP
echo "$__opt$__sep$__val$__end" >>"$__conf" echo "$__opt$__sep$__val$__end" >>"$__conf"
fi fi
_debug2 "$(grep -n "^$__opt$__sep" "$__conf")" _debug3 "$(grep -n "^$__opt$__sep" "$__conf")"
} }
#_save_conf file key value #_save_conf file key value
@ -2644,34 +2707,39 @@ _clearupwebbroot() {
} }
_on_before_issue() { _on_before_issue() {
_chk_web_roots="$1"
_chk_main_domain="$2"
_chk_alt_domains="$3"
_chk_pre_hook="$4"
_chk_local_addr="$5"
_debug _on_before_issue _debug _on_before_issue
#run pre hook #run pre hook
if [ "$Le_PreHook" ]; then if [ "$_chk_pre_hook" ]; then
_info "Run pre hook:'$Le_PreHook'" _info "Run pre hook:'$_chk_pre_hook'"
if ! ( if ! (
cd "$DOMAIN_PATH" && eval "$Le_PreHook" cd "$DOMAIN_PATH" && eval "$_chk_pre_hook"
); then ); then
_err "Error when run pre hook." _err "Error when run pre hook."
return 1 return 1
fi fi
fi fi
if _hasfield "$Le_Webroot" "$NO_VALUE"; then if _hasfield "$_chk_web_roots" "$NO_VALUE"; then
if ! _exists "nc"; then if ! _exists "nc"; then
_err "Please install netcat(nc) tools first." _err "Please install netcat(nc) tools first."
return 1 return 1
fi fi
fi fi
_debug Le_LocalAddress "$Le_LocalAddress" _debug Le_LocalAddress "$_chk_local_addr"
alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ')
_index=1 _index=1
_currentRoot="" _currentRoot=""
_addrIndex=1 _addrIndex=1
for d in $alldomains; do for d in $alldomains; do
_debug "Check for domain" "$d" _debug "Check for domain" "$d"
_currentRoot="$(_getfield "$Le_Webroot" $_index)" _currentRoot="$(_getfield "$_chk_web_roots" $_index)"
_debug "_currentRoot" "$_currentRoot" _debug "_currentRoot" "$_currentRoot"
_index=$(_math $_index + 1) _index=$(_math $_index + 1)
_checkport="" _checkport=""
@ -2695,7 +2763,7 @@ _on_before_issue() {
if [ "$_checkport" ]; then if [ "$_checkport" ]; then
_debug _checkport "$_checkport" _debug _checkport "$_checkport"
_checkaddr="$(_getfield "$Le_LocalAddress" $_addrIndex)" _checkaddr="$(_getfield "$_chk_local_addr" $_addrIndex)"
_debug _checkaddr "$_checkaddr" _debug _checkaddr "$_checkaddr"
_addrIndex="$(_math $_addrIndex + 1)" _addrIndex="$(_math $_addrIndex + 1)"
@ -2714,7 +2782,7 @@ _on_before_issue() {
fi fi
done done
if _hasfield "$Le_Webroot" "apache"; then if _hasfield "$_chk_web_roots" "apache"; then
if ! _setApache; then if ! _setApache; then
_err "set up apache error. Report error to me." _err "set up apache error. Report error to me."
return 1 return 1
@ -2726,6 +2794,7 @@ _on_before_issue() {
} }
_on_issue_err() { _on_issue_err() {
_chk_post_hook="$1"
_debug _on_issue_err _debug _on_issue_err
if [ "$LOG_FILE" ]; then if [ "$LOG_FILE" ]; then
_err "Please check log file for more details: $LOG_FILE" _err "Please check log file for more details: $LOG_FILE"
@ -2739,10 +2808,10 @@ _on_issue_err() {
fi fi
#run the post hook #run the post hook
if [ "$Le_PostHook" ]; then if [ "$_chk_post_hook" ]; then
_info "Run post hook:'$Le_PostHook'" _info "Run post hook:'$_chk_post_hook'"
if ! ( if ! (
cd "$DOMAIN_PATH" && eval "$Le_PostHook" cd "$DOMAIN_PATH" && eval "$_chk_post_hook"
); then ); then
_err "Error when run post hook." _err "Error when run post hook."
return 1 return 1
@ -2751,12 +2820,14 @@ _on_issue_err() {
} }
_on_issue_success() { _on_issue_success() {
_chk_post_hook="$1"
_chk_renew_hook="$2"
_debug _on_issue_success _debug _on_issue_success
#run the post hook #run the post hook
if [ "$Le_PostHook" ]; then if [ "$_chk_post_hook" ]; then
_info "Run post hook:'$Le_PostHook'" _info "Run post hook:'$_chk_post_hook'"
if ! ( if ! (
cd "$DOMAIN_PATH" && eval "$Le_PostHook" cd "$DOMAIN_PATH" && eval "$_chk_post_hook"
); then ); then
_err "Error when run post hook." _err "Error when run post hook."
return 1 return 1
@ -2764,10 +2835,10 @@ _on_issue_success() {
fi fi
#run renew hook #run renew hook
if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ]; then if [ "$IS_RENEW" ] && [ "$_chk_renew_hook" ]; then
_info "Run renew hook:'$Le_RenewHook'" _info "Run renew hook:'$_chk_renew_hook'"
if ! ( if ! (
cd "$DOMAIN_PATH" && eval "$Le_RenewHook" cd "$DOMAIN_PATH" && eval "$_chk_renew_hook"
); then ); then
_err "Error when run renew hook." _err "Error when run renew hook."
return 1 return 1
@ -2964,38 +3035,38 @@ issue() {
_usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
return 1 return 1
fi fi
Le_Webroot="$1" _web_roots="$1"
Le_Domain="$2" _main_domain="$2"
Le_Alt="$3" _alt_domains="$3"
if _contains "$Le_Domain" ","; then if _contains "$_main_domain" ","; then
Le_Domain=$(echo "$2,$3" | cut -d , -f 1) _main_domain=$(echo "$2,$3" | cut -d , -f 1)
Le_Alt=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//")
fi fi
Le_Keylength="$4" _key_length="$4"
Le_RealCertPath="$5" _real_cert="$5"
Le_RealKeyPath="$6" _real_key="$6"
Le_RealCACertPath="$7" _real_ca="$7"
Le_ReloadCmd="$8" _reload_cmd="$8"
Le_RealFullChainPath="$9" _real_fullchain="$9"
Le_PreHook="${10}" _pre_hook="${10}"
Le_PostHook="${11}" _post_hook="${11}"
Le_RenewHook="${12}" _renew_hook="${12}"
Le_LocalAddress="${13}" _local_addr="${13}"
#remove these later. #remove these later.
if [ "$Le_Webroot" = "dns-cf" ]; then if [ "$_web_roots" = "dns-cf" ]; then
Le_Webroot="dns_cf" _web_roots="dns_cf"
fi fi
if [ "$Le_Webroot" = "dns-dp" ]; then if [ "$_web_roots" = "dns-dp" ]; then
Le_Webroot="dns_dp" _web_roots="dns_dp"
fi fi
if [ "$Le_Webroot" = "dns-cx" ]; then if [ "$_web_roots" = "dns-cx" ]; then
Le_Webroot="dns_cx" _web_roots="dns_cx"
fi fi
_debug "Using api: $API" _debug "Using api: $API"
if [ ! "$IS_RENEW" ]; then if [ ! "$IS_RENEW" ]; then
_initpath "$Le_Domain" "$Le_Keylength" _initpath "$_main_domain" "$_key_length"
mkdir -p "$DOMAIN_PATH" mkdir -p "$DOMAIN_PATH"
fi fi
@ -3007,7 +3078,7 @@ issue() {
_debug _saved_domain "$_saved_domain" _debug _saved_domain "$_saved_domain"
_saved_alt=$(_readdomainconf Le_Alt) _saved_alt=$(_readdomainconf Le_Alt)
_debug _saved_alt "$_saved_alt" _debug _saved_alt "$_saved_alt"
if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ]; then if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then
_info "Domains not changed." _info "Domains not changed."
_info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")"
_info "Add '$(__red '--force')' to force to renew." _info "Add '$(__red '--force')' to force to renew."
@ -3018,16 +3089,16 @@ issue() {
fi fi
fi fi
_savedomainconf "Le_Domain" "$Le_Domain" _savedomainconf "Le_Domain" "$_main_domain"
_savedomainconf "Le_Alt" "$Le_Alt" _savedomainconf "Le_Alt" "$_alt_domains"
_savedomainconf "Le_Webroot" "$Le_Webroot" _savedomainconf "Le_Webroot" "$_web_roots"
_savedomainconf "Le_PreHook" "$Le_PreHook" _savedomainconf "Le_PreHook" "$_pre_hook"
_savedomainconf "Le_PostHook" "$Le_PostHook" _savedomainconf "Le_PostHook" "$_post_hook"
_savedomainconf "Le_RenewHook" "$Le_RenewHook" _savedomainconf "Le_RenewHook" "$_renew_hook"
if [ "$Le_LocalAddress" ]; then if [ "$_local_addr" ]; then
_savedomainconf "Le_LocalAddress" "$Le_LocalAddress" _savedomainconf "Le_LocalAddress" "$_local_addr"
else else
_cleardomainconf "Le_LocalAddress" _cleardomainconf "Le_LocalAddress"
fi fi
@ -3035,15 +3106,15 @@ issue() {
Le_API="$API" Le_API="$API"
_savedomainconf "Le_API" "$Le_API" _savedomainconf "Le_API" "$Le_API"
if [ "$Le_Alt" = "$NO_VALUE" ]; then if [ "$_alt_domains" = "$NO_VALUE" ]; then
Le_Alt="" _alt_domains=""
fi fi
if [ "$Le_Keylength" = "$NO_VALUE" ]; then if [ "$_key_length" = "$NO_VALUE" ]; then
Le_Keylength="" _key_length=""
fi fi
if ! _on_before_issue; then if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then
_err "_on_before_issue." _err "_on_before_issue."
return 1 return 1
fi fi
@ -3053,7 +3124,7 @@ issue() {
if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
if ! _regAccount "$_accountkeylength"; then if ! _regAccount "$_accountkeylength"; then
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
else else
@ -3065,24 +3136,24 @@ issue() {
else else
_key=$(_readdomainconf Le_Keylength) _key=$(_readdomainconf Le_Keylength)
_debug "Read key length:$_key" _debug "Read key length:$_key"
if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ]; then
if ! createDomainKey "$Le_Domain" "$Le_Keylength"; then if ! createDomainKey "$_main_domain" "$_key_length"; then
_err "Create domain key error." _err "Create domain key error."
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
fi fi
if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then
_err "Create CSR error." _err "Create CSR error."
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
fi fi
_savedomainconf "Le_Keylength" "$Le_Keylength" _savedomainconf "Le_Keylength" "$_key_length"
vlist="$Le_Vlist" vlist="$Le_Vlist"
@ -3090,12 +3161,12 @@ issue() {
sep='#' sep='#'
dvsep=',' dvsep=','
if [ -z "$vlist" ]; then if [ -z "$vlist" ]; then
alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ')
_index=1 _index=1
_currentRoot="" _currentRoot=""
for d in $alldomains; do for d in $alldomains; do
_info "Getting webroot for domain" "$d" _info "Getting webroot for domain" "$d"
_w="$(echo $Le_Webroot | cut -d , -f $_index)" _w="$(echo $_web_roots | cut -d , -f $_index)"
_debug _w "$_w" _debug _w "$_w"
if [ "$_w" ]; then if [ "$_w" ]; then
_currentRoot="$_w" _currentRoot="$_w"
@ -3114,7 +3185,7 @@ issue() {
if ! __get_domain_new_authz "$d"; then if ! __get_domain_new_authz "$d"; then
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3127,7 +3198,7 @@ issue() {
if [ -z "$entry" ]; then if [ -z "$entry" ]; then
_err "Error, can not get domain token $d" _err "Error, can not get domain token $d"
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
@ -3208,7 +3279,7 @@ issue() {
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
dnsadded='1' dnsadded='1'
@ -3220,7 +3291,7 @@ issue() {
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _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 retry again."
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3266,12 +3337,12 @@ issue() {
if [ "$vtype" = "$VTYPE_HTTP" ]; then if [ "$vtype" = "$VTYPE_HTTP" ]; then
if [ "$_currentRoot" = "$NO_VALUE" ]; then if [ "$_currentRoot" = "$NO_VALUE" ]; then
_info "Standalone mode server" _info "Standalone mode server"
_ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")"
_ncIndex="$(_math $_ncIndex + 1)" _ncIndex="$(_math $_ncIndex + 1)"
_startserver "$keyauthorization" "$_ncaddr" & _startserver "$keyauthorization" "$_ncaddr" &
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
serverproc="$!" serverproc="$!"
@ -3287,7 +3358,7 @@ issue() {
BACKUP_NGINX_CONF="" BACKUP_NGINX_CONF=""
if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3322,7 +3393,7 @@ issue() {
_err "$d:Can not write token to file : $wellknown_path/$token" _err "$d:Can not write token to file : $wellknown_path/$token"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3361,13 +3432,13 @@ issue() {
_SAN_B="$_x.$_y.acme.invalid" _SAN_B="$_x.$_y.acme.invalid"
_debug2 _SAN_B "$_SAN_B" _debug2 _SAN_B "$_SAN_B"
_ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")"
_ncIndex="$(_math "$_ncIndex" + 1)" _ncIndex="$(_math "$_ncIndex" + 1)"
if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then
_err "Start tls server error." _err "Start tls server error."
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
fi fi
@ -3376,7 +3447,7 @@ issue() {
_err "$d:Can not get challenge: $response" _err "$d:Can not get challenge: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3384,7 +3455,7 @@ issue() {
_err "$d:Challenge error: $response" _err "$d:Challenge error: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3411,7 +3482,7 @@ issue() {
_err "$d:Verify error:$response" _err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
_debug2 original "$response" _debug2 original "$response"
@ -3446,7 +3517,7 @@ issue() {
fi fi
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3456,7 +3527,7 @@ issue() {
_err "$d:Verify error:$response" _err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3470,7 +3541,7 @@ issue() {
if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then
_err "Sign failed." _err "Sign failed."
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3512,7 +3583,7 @@ issue() {
if [ -z "$Le_LinkCert" ]; then if [ -z "$Le_LinkCert" ]; then
response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)" response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)"
_err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')"
_on_issue_err _on_issue_err "$_post_hook"
return 1 return 1
fi fi
@ -3574,10 +3645,15 @@ issue() {
Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
_savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
_on_issue_success _on_issue_success "$_post_hook" "$_renew_hook"
if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ]; then if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then
_installcert _savedomainconf "Le_RealCertPath" "$_real_cert"
_savedomainconf "Le_RealCACertPath" "$_real_ca"
_savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd"
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain"
fi fi
} }
@ -3630,7 +3706,7 @@ renew() {
fi fi
if [ "$Le_DeployHook" ]; then if [ "$Le_DeployHook" ]; then
deploy "$Le_Domain" "$Le_DeployHook" "$Le_Keylength" _deploy "$Le_Domain" "$Le_DeployHook"
res="$?" res="$?"
fi fi
@ -3802,155 +3878,168 @@ list() {
} }
_deploy() {
_d="$1"
_hooks="$2"
for _d_api in $(echo "$_hooks" | tr ',' " "); do
_deployApi="$(_findHook "$_d" deploy "$_d_api")"
if [ -z "$_deployApi" ]; then
_err "The deploy hook $_d_api is not found."
return 1
fi
_debug _deployApi "$_deployApi"
if ! (
if ! . "$_deployApi"; then
_err "Load file $_deployApi error. Please check your api file and try again."
return 1
fi
d_command="${_d_api}_deploy"
if ! _exists "$d_command"; then
_err "It seems that your api file is not correct, it must have a function named: $d_command"
return 1
fi
if ! $d_command "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then
_err "Error deploy for domain:$_d"
return 1
fi
); then
_err "Deploy error."
return 1
else
_info "$(__green Success)"
fi
done
}
#domain hooks
deploy() { deploy() {
Le_Domain="$1" _d="$1"
Le_DeployHook="$2" _hooks="$2"
_isEcc="$3" _isEcc="$3"
if [ -z "$Le_DeployHook" ]; then if [ -z "$_hooks" ]; then
_usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] " _usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] "
return 1 return 1
fi fi
_initpath "$Le_Domain" "$_isEcc" _initpath "$_d" "$_isEcc"
if [ ! -d "$DOMAIN_PATH" ]; then if [ ! -d "$DOMAIN_PATH" ]; then
_err "Domain is not valid:'$Le_Domain'" _err "Domain is not valid:'$_d'"
return 1 return 1
fi fi
_deployApi="$(_findHook "$Le_Domain" deploy "$Le_DeployHook")" . "$DOMAIN_CONF"
if [ -z "$_deployApi" ]; then
_err "The deploy hook $Le_DeployHook is not found."
return 1
fi
_debug _deployApi "$_deployApi"
_savedomainconf Le_DeployHook "$Le_DeployHook" _savedomainconf Le_DeployHook "$_hooks"
if ! (
if ! . "$_deployApi"; then
_err "Load file $_deployApi error. Please check your api file and try again."
return 1
fi
d_command="${Le_DeployHook}_deploy"
if ! _exists "$d_command"; then
_err "It seems that your api file is not correct, it must have a function named: $d_command"
return 1
fi
if ! $d_command "$Le_Domain" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then
_err "Error deploy for domain:$Le_Domain"
_on_issue_err
return 1
fi
); then
_err "Deploy error."
return 1
else
_info "$(__green Success)"
fi
_deploy "$_d" "$_hooks"
} }
installcert() { installcert() {
Le_Domain="$1" _main_domain="$1"
if [ -z "$Le_Domain" ]; then if [ -z "$_main_domain" ]; then
_usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]"
return 1 return 1
fi fi
Le_RealCertPath="$2" _real_cert="$2"
Le_RealKeyPath="$3" _real_key="$3"
Le_RealCACertPath="$4" _real_ca="$4"
Le_ReloadCmd="$5" _reload_cmd="$5"
Le_RealFullChainPath="$6" _real_fullchain="$6"
_isEcc="$7" _isEcc="$7"
_initpath "$Le_Domain" "$_isEcc" _initpath "$_main_domain" "$_isEcc"
if [ ! -d "$DOMAIN_PATH" ]; then if [ ! -d "$DOMAIN_PATH" ]; then
_err "Domain is not valid:'$Le_Domain'" _err "Domain is not valid:'$_main_domain'"
return 1 return 1
fi fi
_installcert _savedomainconf "Le_RealCertPath" "$_real_cert"
_savedomainconf "Le_RealCACertPath" "$_real_ca"
_savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd"
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain"
} }
_installcert() { _installcert() {
_savedomainconf "Le_RealCertPath" "$Le_RealCertPath" _main_domain="$1"
_savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath" _real_cert="$2"
_savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath" _real_key="$3"
_savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd" _real_ca="$4"
_savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath" _reload_cmd="$5"
_real_fullchain="$6"
if [ "$Le_RealCertPath" = "$NO_VALUE" ]; then if [ "$_real_cert" = "$NO_VALUE" ]; then
Le_RealCertPath="" _real_cert=""
fi fi
if [ "$Le_RealKeyPath" = "$NO_VALUE" ]; then if [ "$_real_key" = "$NO_VALUE" ]; then
Le_RealKeyPath="" _real_key=""
fi fi
if [ "$Le_RealCACertPath" = "$NO_VALUE" ]; then if [ "$_real_ca" = "$NO_VALUE" ]; then
Le_RealCACertPath="" _real_ca=""
fi fi
if [ "$Le_ReloadCmd" = "$NO_VALUE" ]; then if [ "$_reload_cmd" = "$NO_VALUE" ]; then
Le_ReloadCmd="" _reload_cmd=""
fi fi
if [ "$Le_RealFullChainPath" = "$NO_VALUE" ]; then if [ "$_real_fullchain" = "$NO_VALUE" ]; then
Le_RealFullChainPath="" _real_fullchain=""
fi fi
if [ "$Le_RealCertPath" ]; then if [ "$_real_cert" ]; then
_info "Installing cert to:$_real_cert"
_info "Installing cert to:$Le_RealCertPath" if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then
if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then
mkdir -p "$DOMAIN_BACKUP_PATH" mkdir -p "$DOMAIN_BACKUP_PATH"
cp "$Le_RealCertPath" "$DOMAIN_BACKUP_PATH/cert.bak" cp "$_real_cert" "$DOMAIN_BACKUP_PATH/cert.bak"
fi fi
cat "$CERT_PATH" >"$Le_RealCertPath" cat "$CERT_PATH" >"$_real_cert"
fi fi
if [ "$Le_RealCACertPath" ]; then if [ "$_real_ca" ]; then
_info "Installing CA to:$_real_ca"
_info "Installing CA to:$Le_RealCACertPath" if [ "$_real_ca" = "$_real_cert" ]; then
if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ]; then echo "" >>"$_real_ca"
echo "" >>"$Le_RealCACertPath" cat "$CA_CERT_PATH" >>"$_real_ca"
cat "$CA_CERT_PATH" >>"$Le_RealCACertPath"
else else
if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then
mkdir -p "$DOMAIN_BACKUP_PATH" mkdir -p "$DOMAIN_BACKUP_PATH"
cp "$Le_RealCACertPath" "$DOMAIN_BACKUP_PATH/ca.bak" cp "$_real_ca" "$DOMAIN_BACKUP_PATH/ca.bak"
fi fi
cat "$CA_CERT_PATH" >"$Le_RealCACertPath" cat "$CA_CERT_PATH" >"$_real_ca"
fi fi
fi fi
if [ "$Le_RealKeyPath" ]; then if [ "$_real_key" ]; then
_info "Installing key to:$_real_key"
_info "Installing key to:$Le_RealKeyPath" if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then
if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then
mkdir -p "$DOMAIN_BACKUP_PATH" mkdir -p "$DOMAIN_BACKUP_PATH"
cp "$Le_RealKeyPath" "$DOMAIN_BACKUP_PATH/key.bak" cp "$_real_key" "$DOMAIN_BACKUP_PATH/key.bak"
fi fi
cat "$CERT_KEY_PATH" >"$Le_RealKeyPath" cat "$CERT_KEY_PATH" >"$_real_key"
fi fi
if [ "$Le_RealFullChainPath" ]; then if [ "$_real_fullchain" ]; then
_info "Installing full chain to:$_real_fullchain"
_info "Installing full chain to:$Le_RealFullChainPath" if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then
if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then
mkdir -p "$DOMAIN_BACKUP_PATH" mkdir -p "$DOMAIN_BACKUP_PATH"
cp "$Le_RealFullChainPath" "$DOMAIN_BACKUP_PATH/fullchain.bak" cp "$_real_fullchain" "$DOMAIN_BACKUP_PATH/fullchain.bak"
fi fi
cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath" cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain"
fi fi
if [ "$Le_ReloadCmd" ]; then if [ "$_reload_cmd" ]; then
_info "Run Le_ReloadCmd: $Le_ReloadCmd" _info "Run reload cmd: $_reload_cmd"
if ( if (
export CERT_PATH export CERT_PATH
export CERT_KEY_PATH export CERT_KEY_PATH
export CA_CERT_PATH export CA_CERT_PATH
export CERT_FULLCHAIN_PATH export CERT_FULLCHAIN_PATH
cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" cd "$DOMAIN_PATH" && eval "$_reload_cmd"
); then ); then
_info "$(__green "Reload success")" _info "$(__green "Reload success")"
else else
@ -4583,7 +4672,7 @@ Parameters:
--force, -f Used to force to install or force to renew a cert immediately. --force, -f Used to force to install or force to renew a cert immediately.
--staging, --test Use staging server, just for test. --staging, --test Use staging server, just for test.
--debug Output debug info. --debug Output debug info.
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure.
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode. --standalone Use standalone mode.
--stateless Use stateless mode, see: $_STATELESS_WIKI --stateless Use stateless mode, see: $_STATELESS_WIKI
@ -4596,7 +4685,7 @@ Parameters:
--accountkeylength, -ak [2048] Specifies the account key length. --accountkeylength, -ak [2048] Specifies the account key length.
--log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here.
--log-level 1|2 Specifies the log level, default is 1. --log-level 1|2 Specifies the log level, default is 1.
--syslog [1|0] Enable/Disable syslog. --syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
@ -4877,6 +4966,9 @@ _process() {
shift shift
fi fi
;; ;;
--output-insecure)
export OUTPUT_INSECURE=1
;;
--webroot | -w) --webroot | -w)
wvalue="$2" wvalue="$2"
if [ -z "$_webroot" ]; then if [ -z "$_webroot" ]; then
@ -5070,7 +5162,11 @@ _process() {
shift shift
;; ;;
--deploy-hook) --deploy-hook)
_deploy_hook="$2" if [ -z "$2" ] || _startswith "$2" "-"; then
_usage "Please specify a value for '--deploy-hook'"
return 1
fi
_deploy_hook="$_deploy_hook$2,"
shift shift
;; ;;
--ocsp-must-staple | --ocsp) --ocsp-must-staple | --ocsp)

26
deploy/apache.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to dovecot server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
apache_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "Deploy cert to apache server, Not implemented yet"
return 1
}

26
deploy/dovecot.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to dovecot server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
dovecot_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "Not implemented yet"
return 1
}

26
deploy/exim4.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to exim4 server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
exim4_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to exim4 server, Not implemented yet"
return 1
}

26
deploy/haproxy.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to haproxy server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
haproxy_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to haproxy server, Not implemented yet"
return 1
}

26
deploy/mysqld.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to mysqld server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
mysqld_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to mysqld server, Not implemented yet"
return 1
}

26
deploy/nginx.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to nginx server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
nginx_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to nginx server, Not implemented yet"
return 1
}

26
deploy/opensshd.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to opensshd server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
opensshd_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to opensshd server, Not implemented yet"
return 1
}

26
deploy/pureftpd.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to pureftpd server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
pureftpd_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to pureftpd server, Not implemented yet"
return 1
}

26
deploy/vsftpd.sh Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env sh
#Here is a script to deploy cert to vsftpd server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
vsftpd_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to vsftpd server, Not implemented yet"
return 1
}

View File

@ -305,6 +305,24 @@ Note that you cannot use acme.sh automatic DNS validation for FreeDNS public dom
you create under a FreeDNS public domain. You must own the top level domain in order to automaitcally you create under a FreeDNS public domain. You must own the top level domain in order to automaitcally
validate with acme.sh at FreeDNS. validate with acme.sh at FreeDNS.
## 16. Use cyon.ch
You only need to set your cyon.ch login credentials.
If you also have 2 Factor Authentication (OTP) enabled, you need to set your secret token too and have `oathtool` installed.
```
export CY_Username="your_cyon_username"
export CY_Password="your_cyon_password"
export CY_OTP_Secret="your_otp_secret" # Only required if using 2FA
```
To issue a cert:
```
acme.sh --issue --dns dns_cyon -d example.com -d www.example.com
```
The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
# Use custom API # Use custom API
If your API is not supported yet, you can write your own DNS API. If your API is not supported yet, you can write your own DNS API.

View File

@ -181,10 +181,10 @@ aws_rest() {
#kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################ #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################
_debug2 kSecret "$kSecret" _secure_debug2 kSecret "$kSecret"
kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")"
_debug2 kSecretH "$kSecretH" _secure_debug2 kSecretH "$kSecretH"
kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)"
_debug2 kDateH "$kDateH" _debug2 kDateH "$kDateH"

328
dnsapi/dns_cyon.sh Normal file
View File

@ -0,0 +1,328 @@
#!/usr/bin/env sh
########
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/Neilpang/acme.sh)
#
# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com
#
# Dependencies:
# -------------
# - oathtool (When using 2 Factor Authentication)
#
# Issues:
# -------
# Any issues / questions / suggestions can be posted here:
# https://github.com/noplanman/cyon-api/issues
#
# Author: Armando Lüscher <armando@noplanman.ch>
########
dns_cyon_add() {
_cyon_load_credentials \
&& _cyon_load_parameters "$@" \
&& _cyon_print_header "add" \
&& _cyon_login \
&& _cyon_change_domain_env \
&& _cyon_add_txt \
&& _cyon_logout
}
dns_cyon_rm() {
_cyon_load_credentials \
&& _cyon_load_parameters "$@" \
&& _cyon_print_header "delete" \
&& _cyon_login \
&& _cyon_change_domain_env \
&& _cyon_delete_txt \
&& _cyon_logout
}
#########################
### PRIVATE FUNCTIONS ###
#########################
_cyon_load_credentials() {
# Convert loaded password to/from base64 as needed.
if [ "${CY_Password_B64}" ]; then
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")"
elif [ "${CY_Password}" ]; then
CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)"
fi
if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then
# Dummy entries to satify script checker.
CY_Username=""
CY_Password=""
CY_OTP_Secret=""
_err ""
_err "You haven't set your cyon.ch login credentials yet."
_err "Please set the required cyon environment variables."
_err ""
return 1
fi
# Save the login credentials to the account.conf file.
_debug "Save credentials to account.conf"
_saveaccountconf CY_Username "${CY_Username}"
_saveaccountconf CY_Password_B64 "$CY_Password_B64"
if [ ! -z "${CY_OTP_Secret}" ]; then
_saveaccountconf CY_OTP_Secret "$CY_OTP_Secret"
else
_clearaccountconf CY_OTP_Secret
fi
}
_cyon_is_idn() {
_idn_temp="$(printf "%s" "${1}" | tr -d "0-9a-zA-Z.,-_")"
_idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")"
[ "$_idn_temp" ] || [ "$_idn_temp2" ]
}
_cyon_load_parameters() {
# Read the required parameters to add the TXT entry.
# shellcheck disable=SC2018,SC2019
fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")"
fulldomain_idn="${fulldomain}"
# Special case for IDNs, as cyon needs a domain environment change,
# which uses the "pretty" instead of the punycode version.
if _cyon_is_idn "${fulldomain}"; then
if ! _exists idn; then
_err "Please install idn to process IDN names."
_err ""
return 1
fi
fulldomain="$(idn -u "${fulldomain}")"
fulldomain_idn="$(idn -a "${fulldomain}")"
fi
_debug fulldomain "${fulldomain}"
_debug fulldomain_idn "${fulldomain_idn}"
txtvalue="${2}"
_debug txtvalue "${txtvalue}"
# This header is required for curl calls.
_H1="X-Requested-With: XMLHttpRequest"
export _H1
}
_cyon_print_header() {
if [ "${1}" = "add" ]; then
_info ""
_info "+---------------------------------------------+"
_info "| Adding DNS TXT entry to your cyon.ch domain |"
_info "+---------------------------------------------+"
_info ""
_info " * Full Domain: ${fulldomain}"
_info " * TXT Value: ${txtvalue}"
_info ""
elif [ "${1}" = "delete" ]; then
_info ""
_info "+-------------------------------------------------+"
_info "| Deleting DNS TXT entry from your cyon.ch domain |"
_info "+-------------------------------------------------+"
_info ""
_info " * Full Domain: ${fulldomain}"
_info ""
fi
}
_cyon_get_cookie_header() {
printf "Cookie: %s" "$(grep "cyon=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')"
}
_cyon_login() {
_info " - Logging in..."
username_encoded="$(printf "%s" "${CY_Username}" | _url_encode)"
password_encoded="$(printf "%s" "${CY_Password}" | _url_encode)"
login_url="https://my.cyon.ch/auth/index/dologin-async"
login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")"
login_response="$(_post "$login_data" "$login_url")"
_debug login_response "${login_response}"
# Bail if login fails.
if [ "$(printf "%s" "${login_response}" | _cyon_get_response_success)" != "success" ]; then
_err " $(printf "%s" "${login_response}" | _cyon_get_response_message)"
_err ""
return 1
fi
_info " success"
# NECESSARY!! Load the main page after login, to get the new cookie.
_H2="$(_cyon_get_cookie_header)"
export _H2
_get "https://my.cyon.ch/" >/dev/null
# todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request.
# 2FA authentication with OTP?
if [ ! -z "${CY_OTP_Secret}" ]; then
_info " - Authorising with OTP code..."
if ! _exists oathtool; then
_err "Please install oathtool to use 2 Factor Authentication."
_err ""
return 1
fi
# Get OTP code with the defined secret.
otp_code="$(oathtool --base32 --totp "${CY_OTP_Secret}" 2>/dev/null)"
login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async"
login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0"
login_otp_response="$(_post "$login_otp_data" "$login_otp_url")"
_debug login_otp_response "${login_otp_response}"
# Bail if OTP authentication fails.
if [ "$(printf "%s" "${login_otp_response}" | _cyon_get_response_success)" != "success" ]; then
_err " $(printf "%s" "${login_otp_response}" | _cyon_get_response_message)"
_err ""
return 1
fi
_info " success"
fi
_info ""
}
_cyon_logout() {
_info " - Logging out..."
_get "https://my.cyon.ch/auth/index/dologout" >/dev/null
_info " success"
_info ""
}
_cyon_change_domain_env() {
_info " - Changing domain environment..."
# Get the "example.com" part of the full domain name.
domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')"
_debug "Changing domain environment to ${domain_env}"
gloo_item_key="$(_get "https://my.cyon.ch/domain/" | tr '\n' ' ' | sed -E -e "s/.*data-domain=\"${domain_env}\"[^<]*data-itemkey=\"([^\"]*).*/\1/")"
_debug gloo_item_key "${gloo_item_key}"
domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/${gloo_item_key}"
domain_env_response="$(_get "${domain_env_url}")"
_debug domain_env_response "${domain_env_response}"
if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi
domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)"
# Bail if domain environment change fails.
if [ "${domain_env_success}" != "true" ]; then
_err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)"
_err ""
return 1
fi
_info " success"
_info ""
}
_cyon_add_txt() {
_info " - Adding DNS TXT entry..."
add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async"
add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}"
add_txt_response="$(_post "$add_txt_data" "$add_txt_url")"
_debug add_txt_response "${add_txt_response}"
if ! _cyon_check_if_2fa_missed "${add_txt_response}"; then return 1; fi
add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)"
add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)"
# Bail if adding TXT entry fails.
if [ "${add_txt_status}" != "true" ]; then
_err " ${add_txt_message}"
_err ""
return 1
fi
_info " success (TXT|${fulldomain_idn}.|${txtvalue})"
_info ""
}
_cyon_delete_txt() {
_info " - Deleting DNS TXT entry..."
list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async"
list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')"
_debug list_txt_response "${list_txt_response}"
if ! _cyon_check_if_2fa_missed "${list_txt_response}"; then return 1; fi
# Find and delete all acme challenge entries for the $fulldomain.
_dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')"
printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do
dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)"
dns_domain="$(printf "%s" "$_identifier" | cut -d'|' -f2)"
if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then
continue
fi
hash_encoded="$(printf "%s" "${_hash}" | _url_encode)"
identifier_encoded="$(printf "%s" "${_identifier}" | _url_encode)"
delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async"
delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")"
delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")"
_debug delete_txt_response "${delete_txt_response}"
if ! _cyon_check_if_2fa_missed "${delete_txt_response}"; then return 1; fi
delete_txt_message="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_message)"
delete_txt_status="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_status)"
# Skip if deleting TXT entry fails.
if [ "${delete_txt_status}" != "true" ]; then
_err " ${delete_txt_message} (${_identifier})"
else
_info " success (${_identifier})"
fi
done
_info " done"
_info ""
}
_cyon_get_response_message() {
_egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"'
}
_cyon_get_response_status() {
_egrep_o '"status":\w*' | cut -d : -f 2
}
_cyon_get_response_success() {
_egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"'
}
_cyon_check_if_2fa_missed() {
# Did we miss the 2FA?
if test "${1#*multi_factor_form}" != "${1}"; then
_err " Missed OTP authentication!"
_err ""
return 1
fi
}

View File

@ -34,7 +34,7 @@ dns_lexicon_add() {
# shellcheck disable=SC2018,SC2019 # shellcheck disable=SC2018,SC2019
Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z')
Lx_name_v=$(eval echo \$"$Lx_name") Lx_name_v=$(eval echo \$"$Lx_name")
_debug "$Lx_name" "$Lx_name_v" _secure_debug "$Lx_name" "$Lx_name_v"
if [ "$Lx_name_v" ]; then if [ "$Lx_name_v" ]; then
_saveaccountconf "$Lx_name" "$Lx_name_v" _saveaccountconf "$Lx_name" "$Lx_name_v"
eval export "$Lx_name" eval export "$Lx_name"
@ -43,7 +43,7 @@ dns_lexicon_add() {
# shellcheck disable=SC2018,SC2019 # shellcheck disable=SC2018,SC2019
Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z')
Lx_token_v=$(eval echo \$"$Lx_token") Lx_token_v=$(eval echo \$"$Lx_token")
_debug "$Lx_token" "$Lx_token_v" _secure_debug "$Lx_token" "$Lx_token_v"
if [ "$Lx_token_v" ]; then if [ "$Lx_token_v" ]; then
_saveaccountconf "$Lx_token" "$Lx_token_v" _saveaccountconf "$Lx_token" "$Lx_token_v"
eval export "$Lx_token" eval export "$Lx_token"
@ -52,7 +52,7 @@ dns_lexicon_add() {
# shellcheck disable=SC2018,SC2019 # shellcheck disable=SC2018,SC2019
Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z')
Lx_password_v=$(eval echo \$"$Lx_password") Lx_password_v=$(eval echo \$"$Lx_password")
_debug "$Lx_password" "$Lx_password_v" _secure_debug "$Lx_password" "$Lx_password_v"
if [ "$Lx_password_v" ]; then if [ "$Lx_password_v" ]; then
_saveaccountconf "$Lx_password" "$Lx_password_v" _saveaccountconf "$Lx_password" "$Lx_password_v"
eval export "$Lx_password" eval export "$Lx_password"
@ -61,7 +61,7 @@ dns_lexicon_add() {
# shellcheck disable=SC2018,SC2019 # shellcheck disable=SC2018,SC2019
Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z')
Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken")
_debug "$Lx_domaintoken" "$Lx_domaintoken_v" _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v"
if [ "$Lx_domaintoken_v" ]; then if [ "$Lx_domaintoken_v" ]; then
eval export "$Lx_domaintoken" eval export "$Lx_domaintoken"
_saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v"

View File

@ -207,7 +207,7 @@ _ovh_authentication() {
_err "Unable to get consumerKey" _err "Unable to get consumerKey"
return 1 return 1
fi fi
_debug consumerKey "$consumerKey" _secure_debug consumerKey "$consumerKey"
OVH_CK="$consumerKey" OVH_CK="$consumerKey"
_saveaccountconf OVH_CK "$OVH_CK" _saveaccountconf OVH_CK "$OVH_CK"
@ -269,7 +269,7 @@ _ovh_rest() {
_ovh_t="$(_ovh_timestamp)" _ovh_t="$(_ovh_timestamp)"
_debug2 _ovh_t "$_ovh_t" _debug2 _ovh_t "$_ovh_t"
_ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t" _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t"
_debug _ovh_p "$_ovh_p" _secure_debug _ovh_p "$_ovh_p"
_ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)"
_debug2 _ovh_hex "$_ovh_hex" _debug2 _ovh_hex "$_ovh_hex"