mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-05-09 02:42:43 +00:00
Merge remote-tracking branch 'upstream/master'
Manually changed $_CRONTAB
This commit is contained in:
commit
9391d2d9ac
@ -18,7 +18,7 @@ addons:
|
||||
|
||||
install:
|
||||
- if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
|
||||
brew update && brew install openssl;
|
||||
brew update && brew install openssl socat;
|
||||
brew info openssl;
|
||||
ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/;
|
||||
ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/;
|
||||
@ -30,6 +30,7 @@ install:
|
||||
openssl version 2>&1 || true;
|
||||
$ACME_OPENSSL_BIN version 2>&1 || true;
|
||||
export PATH="$_old_path";
|
||||
else sudo apt-get install socat;
|
||||
fi
|
||||
|
||||
script:
|
||||
|
@ -4,7 +4,7 @@ RUN apk update -f \
|
||||
&& apk --no-cache add -f \
|
||||
openssl \
|
||||
curl \
|
||||
netcat-openbsd \
|
||||
socat \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
ENV LE_CONFIG_HOME /acme.sh
|
||||
@ -16,7 +16,7 @@ ADD ./ /install_acme.sh/
|
||||
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
|
||||
|
||||
|
||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | sed 's#> /dev/null##' | crontab -
|
||||
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab -
|
||||
|
||||
RUN for verb in help \
|
||||
version \
|
||||
|
@ -338,6 +338,7 @@ You don't have to do anything manually!
|
||||
1. Name.com API
|
||||
1. Dyn Managed DNS API
|
||||
1. Yandex PDD API (https://pdd.yandex.ru)
|
||||
1. Hurricane Electric DNS service (https://dns.he.net)
|
||||
|
||||
|
||||
And:
|
||||
|
213
acme.sh
213
acme.sh
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
VER=2.7.3
|
||||
VER=2.7.5
|
||||
|
||||
PROJECT_NAME="acme.sh"
|
||||
|
||||
@ -100,6 +100,10 @@ _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations"
|
||||
|
||||
_STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode"
|
||||
|
||||
_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead."
|
||||
|
||||
_DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR"
|
||||
|
||||
__INTERACTIVE=""
|
||||
if [ -t 1 ]; then
|
||||
__INTERACTIVE="1"
|
||||
@ -160,11 +164,11 @@ _dlg_versions() {
|
||||
echo "nginx doesn't exists."
|
||||
fi
|
||||
|
||||
echo "nc:"
|
||||
if _exists "nc"; then
|
||||
nc -h 2>&1
|
||||
echo "socat:"
|
||||
if _exists "socat"; then
|
||||
socat -h 2>&1
|
||||
else
|
||||
_debug "nc doesn't exists."
|
||||
_debug "socat doesn't exists."
|
||||
fi
|
||||
}
|
||||
|
||||
@ -926,7 +930,7 @@ _sign() {
|
||||
|
||||
}
|
||||
|
||||
#keylength
|
||||
#keylength or isEcc flag (empty str => not ecc)
|
||||
_isEccKey() {
|
||||
_length="$1"
|
||||
|
||||
@ -1182,6 +1186,28 @@ _ss() {
|
||||
return 1
|
||||
}
|
||||
|
||||
#outfile key cert cacert [password [name [caname]]]
|
||||
_toPkcs() {
|
||||
_cpfx="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
pfxPassword="$5"
|
||||
pfxName="$6"
|
||||
pfxCaname="$7"
|
||||
|
||||
if [ "$pfxCaname" ]; then
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" -caname "$pfxCaname"
|
||||
elif [ "$pfxName" ]; then
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName"
|
||||
elif [ "$pfxPassword" ]; then
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword"
|
||||
else
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#domain [password] [isEcc]
|
||||
toPkcs() {
|
||||
domain="$1"
|
||||
@ -1195,11 +1221,7 @@ toPkcs() {
|
||||
|
||||
_initpath "$domain" "$_isEcc"
|
||||
|
||||
if [ "$pfxPassword" ]; then
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
|
||||
else
|
||||
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
|
||||
fi
|
||||
_toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$pfxPassword"
|
||||
|
||||
if [ "$?" = "0" ]; then
|
||||
_info "Success, Pfx is exported to: $CERT_PFX_PATH"
|
||||
@ -1349,6 +1371,10 @@ _time2str() {
|
||||
echo "$_t_s_a"
|
||||
fi
|
||||
|
||||
#Busybox
|
||||
if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
_normalizeJson() {
|
||||
@ -1788,7 +1814,13 @@ _send_signed_request() {
|
||||
|
||||
_CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
|
||||
|
||||
if _contains "$response" "JWS has invalid anti-replay nonce"; then
|
||||
_body="$response"
|
||||
if [ "$needbase64" ]; then
|
||||
_body="$(echo "$_body" | _dbase64)"
|
||||
_debug2 _body "$_body"
|
||||
fi
|
||||
|
||||
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
|
||||
@ -1941,68 +1973,22 @@ _startserver() {
|
||||
_debug "ncaddr" "$ncaddr"
|
||||
|
||||
_debug "startserver: $$"
|
||||
nchelp="$(nc -h 2>&1)"
|
||||
|
||||
_debug Le_HTTPPort "$Le_HTTPPort"
|
||||
_debug Le_Listen_V4 "$Le_Listen_V4"
|
||||
_debug Le_Listen_V6 "$Le_Listen_V6"
|
||||
_NC="nc"
|
||||
|
||||
_NC="socat"
|
||||
if [ "$Le_Listen_V4" ]; then
|
||||
_NC="$_NC -4"
|
||||
elif [ "$Le_Listen_V6" ]; then
|
||||
_NC="$_NC -6"
|
||||
fi
|
||||
|
||||
if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then
|
||||
if ! _contains "$nchelp" "-4"; then
|
||||
_err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again."
|
||||
_err "See $(__green $_PREPARE_LINK)"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then
|
||||
_NC="$_NC -q 1 -l $ncaddr"
|
||||
else
|
||||
if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null; then
|
||||
_NC="$_NC -c -l $ncaddr"
|
||||
elif echo "$nchelp" | grep "\-N" | grep "Shutdown the network socket after EOF on stdin" >/dev/null; then
|
||||
_NC="$_NC -N -l $ncaddr"
|
||||
else
|
||||
_NC="$_NC -l $ncaddr"
|
||||
fi
|
||||
fi
|
||||
|
||||
_debug "_NC" "$_NC"
|
||||
|
||||
#for centos ncat
|
||||
if _contains "$nchelp" "nmap.org"; then
|
||||
_debug "Using ncat: nmap.org"
|
||||
if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"; then
|
||||
_exec_err
|
||||
return 1
|
||||
fi
|
||||
if [ "$DEBUG" ]; then
|
||||
_exec_err
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
# while true ; do
|
||||
if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC -p \"$Le_HTTPPort\" >&2"; then
|
||||
_exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "nc listen error."
|
||||
_exec_err
|
||||
exit 1
|
||||
fi
|
||||
if [ "$DEBUG" ]; then
|
||||
_exec_err
|
||||
fi
|
||||
# done
|
||||
#todo listen address
|
||||
$_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK; echo ; echo $content; echo;" &
|
||||
serverproc="$!"
|
||||
}
|
||||
|
||||
_stopserver() {
|
||||
@ -2012,25 +1998,8 @@ _stopserver() {
|
||||
return
|
||||
fi
|
||||
|
||||
_debug2 "Le_HTTPPort" "$Le_HTTPPort"
|
||||
if [ "$Le_HTTPPort" ]; then
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then
|
||||
_get "http://localhost:$Le_HTTPPort" "" 1
|
||||
else
|
||||
_get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
kill $pid
|
||||
|
||||
_debug2 "Le_TLSPort" "$Le_TLSPort"
|
||||
if [ "$Le_TLSPort" ]; then
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then
|
||||
_get "https://localhost:$Le_TLSPort" "" 1
|
||||
_get "https://localhost:$Le_TLSPort" "" 1
|
||||
else
|
||||
_get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
|
||||
_get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# sleep sec
|
||||
@ -2085,7 +2054,7 @@ _starttlsserver() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
__S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -cert $TLS_CERT -key $TLS_KEY "
|
||||
__S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY "
|
||||
if [ "$opaddr" ]; then
|
||||
__S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port"
|
||||
else
|
||||
@ -2102,9 +2071,9 @@ _starttlsserver() {
|
||||
|
||||
_debug "$__S_OPENSSL"
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
||||
(printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) &
|
||||
$__S_OPENSSL -tlsextdebug &
|
||||
else
|
||||
(printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL >/dev/null 2>&1) &
|
||||
$__S_OPENSSL >/dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
serverproc="$!"
|
||||
@ -2251,7 +2220,7 @@ _initAPI() {
|
||||
_debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT"
|
||||
}
|
||||
|
||||
#[domain] [keylength]
|
||||
#[domain] [keylength or isEcc flag]
|
||||
_initpath() {
|
||||
|
||||
__initHome
|
||||
@ -2280,6 +2249,7 @@ _initpath() {
|
||||
fi
|
||||
fi
|
||||
|
||||
_debug2 ACME_DIRECTORY "$ACME_DIRECTORY"
|
||||
_ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)"
|
||||
_debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST"
|
||||
|
||||
@ -2917,8 +2887,8 @@ _on_before_issue() {
|
||||
fi
|
||||
|
||||
if _hasfield "$_chk_web_roots" "$NO_VALUE"; then
|
||||
if ! _exists "nc"; then
|
||||
_err "Please install netcat(nc) tools first."
|
||||
if ! _exists "socat"; then
|
||||
_err "Please install socat tools first."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
@ -3024,6 +2994,10 @@ _on_issue_err() {
|
||||
)
|
||||
fi
|
||||
|
||||
if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "dns"; then
|
||||
_err "$_DNS_MANUAL_ERR"
|
||||
fi
|
||||
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
|
||||
_debug "$(_dlg_versions)"
|
||||
fi
|
||||
@ -3056,6 +3030,10 @@ _on_issue_success() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if _hasfield "$Le_Webroot" "dns"; then
|
||||
_err "$_DNS_MANUAL_WARN"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
updateaccount() {
|
||||
@ -3157,7 +3135,7 @@ _regAccount() {
|
||||
fi
|
||||
if [ "$code" = '202' ]; then
|
||||
_info "Update account tos info success."
|
||||
|
||||
echo "$response" >"$ACCOUNT_JSON_PATH"
|
||||
CA_KEY_HASH="$(__calcAccountKeyHash)"
|
||||
_debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
|
||||
_savecaconf CA_KEY_HASH "$CA_KEY_HASH"
|
||||
@ -3496,7 +3474,7 @@ issue() {
|
||||
token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
|
||||
_debug token "$token"
|
||||
|
||||
uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
|
||||
uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
|
||||
_debug uri "$uri"
|
||||
|
||||
keyauthorization="$token.$thumbprint"
|
||||
@ -3631,13 +3609,12 @@ issue() {
|
||||
_info "Standalone mode server"
|
||||
_ncaddr="$(_getfield "$_local_addr" "$_ncIndex")"
|
||||
_ncIndex="$(_math $_ncIndex + 1)"
|
||||
_startserver "$keyauthorization" "$_ncaddr" &
|
||||
_startserver "$keyauthorization" "$_ncaddr"
|
||||
if [ "$?" != "0" ]; then
|
||||
_clearup
|
||||
_on_issue_err "$_post_hook" "$vlist"
|
||||
return 1
|
||||
fi
|
||||
serverproc="$!"
|
||||
sleep 1
|
||||
_debug serverproc "$serverproc"
|
||||
elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then
|
||||
@ -3972,7 +3949,10 @@ issue() {
|
||||
Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
|
||||
_savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
|
||||
|
||||
_on_issue_success "$_post_hook" "$_renew_hook"
|
||||
if ! _on_issue_success "$_post_hook" "$_renew_hook"; then
|
||||
_err "Call hook error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then
|
||||
_savedomainconf "Le_RealCertPath" "$_real_cert"
|
||||
@ -4399,15 +4379,19 @@ _installcert() {
|
||||
installcronjob() {
|
||||
_c_home="$1"
|
||||
_initpath
|
||||
if ! _exists "crontab"; then
|
||||
_err "crontab doesn't exist, so, we can not install cron jobs."
|
||||
_CRONTAB="crontab"
|
||||
if ! _exists "$_CRONTAB" && _exists "fcrontab"; then
|
||||
_CRONTAB="fcrontab"
|
||||
fi
|
||||
if ! _exists "$_CRONTAB"; then
|
||||
_err "crontab/fcrontab doesn't exist, so, we can not install cron jobs."
|
||||
_err "All your certs will not be renewed automatically."
|
||||
_err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Installing cron job"
|
||||
if ! crontab -l | grep "$PROJECT_ENTRY --cron"; then
|
||||
if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then
|
||||
if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then
|
||||
lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
|
||||
else
|
||||
@ -4427,10 +4411,10 @@ installcronjob() {
|
||||
else
|
||||
ct_stdin=-
|
||||
fi
|
||||
crontab -l | {
|
||||
$_CRONTAB -l | {
|
||||
cat
|
||||
echo "$random_minute $random_hour1,$random_hour2 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
|
||||
} | crontab $ct_stdin
|
||||
} | $_CRONTAB $ct_stdin
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Install cron job failed. You need to manually renew your certs."
|
||||
@ -4441,16 +4425,21 @@ installcronjob() {
|
||||
}
|
||||
|
||||
uninstallcronjob() {
|
||||
if ! _exists "crontab"; then
|
||||
_CRONTAB="crontab"
|
||||
if ! _exists "$_CRONTAB" && _exists "fcrontab"; then
|
||||
_CRONTAB="fcrontab"
|
||||
fi
|
||||
|
||||
if ! _exists "$_CRONTAB"; then
|
||||
return
|
||||
fi
|
||||
_info "Removing cron job"
|
||||
cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")"
|
||||
cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")"
|
||||
if [ "$cr" ]; then
|
||||
if _exists uname && uname -a | grep solaris >/dev/null; then
|
||||
crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab --
|
||||
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB --
|
||||
else
|
||||
crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -
|
||||
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -
|
||||
fi
|
||||
LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')"
|
||||
_info LE_WORKING_DIR "$LE_WORKING_DIR"
|
||||
@ -4727,7 +4716,7 @@ _precheck() {
|
||||
fi
|
||||
|
||||
if [ -z "$_nocron" ]; then
|
||||
if ! _exists "crontab"; then
|
||||
if ! _exists "crontab" && ! _exists "fcrontab"; then
|
||||
_err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
|
||||
_err "We need to set cron job to renew the certs automatically."
|
||||
_err "Otherwise, your certs will not be able to be renewed automatically."
|
||||
@ -4745,9 +4734,9 @@ _precheck() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _exists "nc"; then
|
||||
_err "It is recommended to install nc first, try to install 'nc' or 'netcat'."
|
||||
_err "We use nc for standalone server if you use standalone mode."
|
||||
if ! _exists "socat"; then
|
||||
_err "It is recommended to install socat first."
|
||||
_err "We use socat for standalone server if you use standalone mode."
|
||||
_err "If you don't use standalone mode, just ignore this warning."
|
||||
fi
|
||||
|
||||
@ -4847,9 +4836,11 @@ install() {
|
||||
_debug "Skip install cron job"
|
||||
fi
|
||||
|
||||
if ! _precheck "$_nocron"; then
|
||||
_err "Pre-check failed, can not install."
|
||||
return 1
|
||||
if [ "$IN_CRON" != "1" ]; then
|
||||
if ! _precheck "$_nocron"; then
|
||||
_err "Pre-check failed, can not install."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then
|
||||
@ -4902,7 +4893,9 @@ install() {
|
||||
|
||||
_info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY"
|
||||
|
||||
_installalias "$_c_home"
|
||||
if [ "$IN_CRON" != "1" ]; then
|
||||
_installalias "$_c_home"
|
||||
fi
|
||||
|
||||
for subf in $_SUB_FOLDERS; do
|
||||
if [ -d "$subf" ]; then
|
||||
@ -4992,7 +4985,7 @@ _uninstallalias() {
|
||||
}
|
||||
|
||||
cron() {
|
||||
IN_CRON=1
|
||||
export IN_CRON=1
|
||||
_initpath
|
||||
_info "$(__green "===Starting cron===")"
|
||||
if [ "$AUTO_UPGRADE" = "1" ]; then
|
||||
@ -5440,7 +5433,7 @@ _process() {
|
||||
;;
|
||||
--dns)
|
||||
wvalue="dns"
|
||||
if ! _startswith "$2" "-"; then
|
||||
if [ "$2" ] && ! _startswith "$2" "-"; then
|
||||
wvalue="$2"
|
||||
shift
|
||||
fi
|
||||
|
@ -4,7 +4,9 @@ Before you can deploy your cert, you must [issue the cert first](https://github.
|
||||
|
||||
Here are the scripts to deploy the certs/key to the server/services.
|
||||
|
||||
## 1. Deploy the certs to your cpanel host.
|
||||
## 1. Deploy the certs to your cpanel host
|
||||
|
||||
If you want to deploy using cpanel UAPI see 7.
|
||||
|
||||
(cpanel deploy hook is not finished yet, this is just an example.)
|
||||
|
||||
@ -18,7 +20,7 @@ export DEPLOY_CPANEL_PASSWORD=PASSWORD
|
||||
acme.sh --deploy -d example.com --deploy-hook cpanel
|
||||
```
|
||||
|
||||
## 2. Deploy ssl cert on kong proxy engine based on api.
|
||||
## 2. Deploy ssl cert on kong proxy engine based on api
|
||||
|
||||
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
|
||||
Currently supports Kong-v0.10.x.
|
||||
@ -27,11 +29,11 @@ Currently supports Kong-v0.10.x.
|
||||
acme.sh --deploy -d ftp.example.com --deploy-hook kong
|
||||
```
|
||||
|
||||
## 3. Deploy the cert to remote server through SSH access.
|
||||
## 3. Deploy the cert to remote server through SSH access
|
||||
|
||||
(TODO)
|
||||
|
||||
## 4. Deploy the cert to local vsftpd server.
|
||||
## 4. Deploy the cert to local vsftpd server
|
||||
|
||||
```sh
|
||||
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
|
||||
@ -53,7 +55,7 @@ export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart"
|
||||
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
|
||||
```
|
||||
|
||||
## 5. Deploy the cert to local exim4 server.
|
||||
## 5. Deploy the cert to local exim4 server
|
||||
|
||||
```sh
|
||||
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
|
||||
@ -80,3 +82,37 @@ acme.sh --deploy -d ftp.example.com --deploy-hook exim4
|
||||
```sh
|
||||
acme.sh --deploy -d ftp.example.com --deploy-hook keychain
|
||||
```
|
||||
|
||||
## 7. Deploy to cpanel host using UAPI
|
||||
|
||||
This hook is using UAPI and works in cPanel & WHM version 56 or newer.
|
||||
```
|
||||
acme.sh --deploy -d example.com --deploy-hook cpanel_uapi
|
||||
```
|
||||
DEPLOY_CPANEL_USER is required only if you run the script as root and it should contain cpanel username.
|
||||
```sh
|
||||
export DEPLOY_CPANEL_USER=username
|
||||
acme.sh --deploy -d example.com --deploy-hook cpanel_uapi
|
||||
```
|
||||
Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain.
|
||||
|
||||
## 8. Deploy the cert to your FRITZ!Box router
|
||||
|
||||
You must specify the credentials that have administrative privileges on the FRITZ!Box in order to deploy the certificate, plus the URL of your FRITZ!Box, through the following environment variables:
|
||||
```sh
|
||||
$ export DEPLOY_FRITZBOX_USERNAME=my_username
|
||||
$ export DEPLOY_FRITZBOX_PASSWORD=the_password
|
||||
$ export DEPLOY_FRITZBOX_URL=https://fritzbox.example.com
|
||||
```
|
||||
|
||||
After the first deployment, these values will be stored in your $HOME/.acme.sh/account.conf. You may now deploy the certificate like this:
|
||||
|
||||
```sh
|
||||
acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox
|
||||
```
|
||||
|
||||
## 9. Deploy the cert to strongswan
|
||||
|
||||
```sh
|
||||
acme.sh --deploy -d ftp.example.com --deploy-hook strongswan
|
||||
```
|
||||
|
@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is the script to deploy the cert to your cpanel account by the cpanel APIs.
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
#export DEPLOY_CPANEL_USER=myusername
|
||||
#export DEPLOY_CPANEL_PASSWORD=PASSWORD
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
cpanel_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
_err "Not implemented yet"
|
||||
return 1
|
||||
|
||||
}
|
64
deploy/cpanel_uapi.sh
Normal file
64
deploy/cpanel_uapi.sh
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env sh
|
||||
# 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 <santeri.kannisto@2globalnomads.info>
|
||||
# Public domain, 2017
|
||||
|
||||
#export DEPLOY_CPANEL_USER=myusername
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
|
||||
cpanel_uapi_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if ! _exists uapi; then
|
||||
_err "The command uapi is not found."
|
||||
return 1
|
||||
fi
|
||||
if ! _exists php; then
|
||||
_err "The command php is not found."
|
||||
return 1
|
||||
fi
|
||||
# read cert and key files and urlencode both
|
||||
_certstr=$(cat "$_ccert")
|
||||
_keystr=$(cat "$_ckey")
|
||||
_cert=$(php -r "echo urlencode(\"$_certstr\");")
|
||||
_key=$(php -r "echo urlencode(\"$_keystr\");")
|
||||
|
||||
_debug _cert "$_cert"
|
||||
_debug _key "$_key"
|
||||
|
||||
if [ "$(id -u)" = 0 ]; then
|
||||
if [ -z "$DEPLOY_CPANEL_USER" ]; then
|
||||
_err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username"
|
||||
return 1
|
||||
fi
|
||||
_savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||
_response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
else
|
||||
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
fi
|
||||
error_response="status: 0"
|
||||
if test "${_response#*$error_response}" != "$_response"; then
|
||||
_err "Error in deploying certificate:"
|
||||
_err "$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug response "$_response"
|
||||
_info "Certificate successfully deployed"
|
||||
return 0
|
||||
}
|
108
deploy/fritzbox.sh
Normal file
108
deploy/fritzbox.sh
Normal file
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is a script to deploy cert to an AVM FRITZ!Box router.
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
#DEPLOY_FRITZBOX_USERNAME="username"
|
||||
#DEPLOY_FRITZBOX_PASSWORD="password"
|
||||
#DEPLOY_FRITZBOX_URL="https://fritz.box"
|
||||
|
||||
# Kudos to wikrie at Github for his FRITZ!Box update script:
|
||||
# https://gist.github.com/wikrie/f1d5747a714e0a34d0582981f7cb4cfb
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
fritzbox_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if ! _exists iconv; then
|
||||
_err "iconv not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}"
|
||||
_fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}"
|
||||
_fritzbox_url="${DEPLOY_FRITZBOX_URL}"
|
||||
|
||||
_debug _fritzbox_url "$_fritzbox_url"
|
||||
_debug _fritzbox_username "$_fritzbox_username"
|
||||
_secure_debug _fritzbox_password "$_fritzbox_password"
|
||||
if [ -z "$_fritzbox_username" ]; then
|
||||
_err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME."
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$_fritzbox_password" ]; then
|
||||
_err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD."
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$_fritzbox_url" ]; then
|
||||
_err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}"
|
||||
_saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}"
|
||||
_saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}"
|
||||
|
||||
# Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate
|
||||
export HTTPS_INSECURE=1
|
||||
|
||||
_info "Log in to the FRITZ!Box"
|
||||
_fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')"
|
||||
_fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
|
||||
|
||||
if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then
|
||||
_err "Logging in to the FRITZ!Box failed. Please check username, password and URL."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Generate form POST request"
|
||||
_post_request="$(_mktemp)"
|
||||
_post_boundary="---------------------------$(date +%Y%m%d%H%M%S)"
|
||||
# _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it!
|
||||
_CERTPASSWORD_=
|
||||
{
|
||||
printf -- "--"
|
||||
printf -- "%s\r\n" "${_post_boundary}"
|
||||
printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}"
|
||||
printf -- "--"
|
||||
printf -- "%s\r\n" "${_post_boundary}"
|
||||
printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}"
|
||||
printf -- "--"
|
||||
printf -- "%s\r\n" "${_post_boundary}"
|
||||
printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n"
|
||||
printf "Content-Type: application/octet-stream\r\n\r\n"
|
||||
cat "${_ckey}" "${_cfullchain}"
|
||||
printf "\r\n"
|
||||
printf -- "--"
|
||||
printf -- "%s--" "${_post_boundary}"
|
||||
} >>"${_post_request}"
|
||||
|
||||
_info "Upload certificate to the FRITZ!Box"
|
||||
|
||||
export _H1="Content-type: multipart/form-data boundary=${_post_boundary}"
|
||||
_post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL
|
||||
|
||||
retval=$?
|
||||
if [ $retval = 0 ]; then
|
||||
_info "Upload successful"
|
||||
else
|
||||
_err "Upload failed"
|
||||
fi
|
||||
rm "${_post_request}"
|
||||
|
||||
return $retval
|
||||
}
|
32
deploy/strongswan.sh
Normal file
32
deploy/strongswan.sh
Normal file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is a sample custom api script.
|
||||
#This file name is "myapi.sh"
|
||||
#So, here must be a method myapi_deploy()
|
||||
#Which will be called by acme.sh to deploy the cert
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
strongswan_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
cat "$_ckey" >"/etc/ipsec.d/private/$(basename "$_ckey")"
|
||||
cat "$_ccert" >"/etc/ipsec.d/certs/$(basename "$_ccert")"
|
||||
cat "$_cca" >"/etc/ipsec.d/cacerts/$(basename "$_cca")"
|
||||
cat "$_cfullchain" >"/etc/ipsec.d/cacerts/$(basename "$_cfullchain")"
|
||||
|
||||
ipsec reload
|
||||
|
||||
}
|
100
deploy/unifi.sh
Normal file
100
deploy/unifi.sh
Normal file
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is a script to deploy cert to unifi server.
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
#DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore"
|
||||
#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise"
|
||||
#DEPLOY_UNIFI_RELOAD="service unifi restart"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
unifi_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
if ! _exists keytool; then
|
||||
_err "keytool not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore"
|
||||
_unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}"
|
||||
DEFAULT_UNIFI_KEYPASS="aircontrolenterprise"
|
||||
_unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}"
|
||||
DEFAULT_UNIFI_RELOAD="service unifi restart"
|
||||
_reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}"
|
||||
|
||||
_debug _unifi_keystore "$_unifi_keystore"
|
||||
if [ ! -f "$_unifi_keystore" ]; then
|
||||
if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then
|
||||
_err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE"
|
||||
return 1
|
||||
else
|
||||
_err "It seems that the specified unifi keystore is not valid, please check."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if [ ! -w "$_unifi_keystore" ]; then
|
||||
_err "The file $_unifi_keystore is not writable, please change the permission."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Generate import pkcs12"
|
||||
_import_pkcs12="$(_mktemp)"
|
||||
_toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Oops, error creating import pkcs12, please report bug to us."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Modify unifi keystore: $_unifi_keystore"
|
||||
if keytool -importkeystore \
|
||||
-deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \
|
||||
-srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \
|
||||
-alias unifi -noprompt; then
|
||||
_info "Import keystore success!"
|
||||
rm "$_import_pkcs12"
|
||||
else
|
||||
_err "Import unifi keystore error, please report bug to us."
|
||||
rm "$_import_pkcs12"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Run reload: $_reload"
|
||||
if eval "$_reload"; then
|
||||
_info "Reload success!"
|
||||
if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_KEYSTORE
|
||||
fi
|
||||
if [ "$DEPLOY_UNIFI_KEYPASS" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_KEYPASS
|
||||
fi
|
||||
if [ "$DEPLOY_UNIFI_RELOAD" ]; then
|
||||
_savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD"
|
||||
else
|
||||
_cleardomainconf DEPLOY_UNIFI_RELOAD
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
_err "Reload error"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
@ -420,6 +420,7 @@ Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com
|
||||
```
|
||||
The `CLOUDNS_AUTH_ID` and `CLOUDNS_AUTH_PASSWORD` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 22. Use Infoblox API
|
||||
|
||||
@ -512,14 +513,11 @@ export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
```
|
||||
|
||||
Please note that since DuckDNS uses StartSSL as their cert provider, thus
|
||||
--insecure must be used when issuing certs:
|
||||
--insecure may need to be used when issuing certs:
|
||||
```
|
||||
acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org
|
||||
```
|
||||
|
||||
Also, DuckDNS uses the domain name as username for recording changing, so the
|
||||
account file will always store the lastly used domain name.
|
||||
|
||||
For issues, please report to https://github.com/raidenii/acme.sh/issues.
|
||||
|
||||
## 28. Use Name.com API
|
||||
@ -585,6 +583,25 @@ acme.sh --issue --dns dns_yandex -d mydomain.example.org
|
||||
|
||||
For issues, please report to https://github.com/non7top/acme.sh/issues.
|
||||
|
||||
## 31. Use Hurricane Electric
|
||||
|
||||
Hurricane Electric doesn't have an API so just set your login credentials like so:
|
||||
|
||||
```
|
||||
export HE_Username="yourusername"
|
||||
export HE_Password="password"
|
||||
```
|
||||
|
||||
Then you can issue your certificate:
|
||||
|
||||
```
|
||||
acme.sh --issue --dns dns_he -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
Please report any issues to https://github.com/angel333/acme.sh or to <me@ondrejsimek.com>.
|
||||
|
||||
# Use custom API
|
||||
|
||||
If your API is not supported yet, you can write your own DNS API.
|
||||
@ -601,6 +618,7 @@ acme.sh --issue --dns dns_myapi -d example.com -d www.example.com
|
||||
|
||||
For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh)
|
||||
|
||||
See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
|
||||
|
||||
# Use lexicon DNS API
|
||||
|
||||
|
@ -87,6 +87,7 @@ _get_root() {
|
||||
_debug "response" "$response"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug2 "Checking domain: $h"
|
||||
if [ -z "$h" ]; then
|
||||
if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
|
||||
_debug "IsTruncated"
|
||||
@ -102,23 +103,23 @@ _get_root() {
|
||||
fi
|
||||
fi
|
||||
#not valid
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "<Name>$h.</Name>"; then
|
||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
||||
_debug hostedzone "$hostedzone"
|
||||
if [ -z "$hostedzone" ]; then
|
||||
_err "Error, can not get hostedzone."
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
_err "Can not find domain id: $h"
|
||||
return 1
|
||||
fi
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
|
@ -96,6 +96,16 @@ _dns_cloudns_init_check() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}"
|
||||
CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}"
|
||||
if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then
|
||||
CLOUDNS_AUTH_ID=""
|
||||
CLOUDNS_AUTH_PASSWORD=""
|
||||
_err "You don't specify cloudns api id and password yet."
|
||||
_err "Please create you id and password and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$CLOUDNS_AUTH_ID" ]; then
|
||||
_err "CLOUDNS_AUTH_ID is not configured"
|
||||
return 1
|
||||
@ -113,6 +123,10 @@ _dns_cloudns_init_check() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api id and password to the account conf file.
|
||||
_saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
|
||||
_saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
|
||||
|
||||
CLOUDNS_INIT_CHECK_COMPLETED=1
|
||||
|
||||
return 0
|
||||
|
@ -3,11 +3,14 @@
|
||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
||||
#06/27/2017
|
||||
|
||||
# Currently only support single domain access
|
||||
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure must be used with acme.sh
|
||||
# Pass credentials before "acme.sh --issue --dns dns_duckdns ..."
|
||||
# --
|
||||
# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
# --
|
||||
#
|
||||
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh
|
||||
|
||||
DuckDNS_API="https://www.duckdns.org/update"
|
||||
API_Params="domains=$DuckDNS_Domain&token=$DuckDNS_Token"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -16,35 +19,36 @@ dns_duckdns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
# We'll extract the domain/username from full domain
|
||||
DuckDNS_Domain=$(echo "$fulldomain" | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2)
|
||||
|
||||
if [ -z "$DuckDNS_Domain" ]; then
|
||||
_err "Error extracting the domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}"
|
||||
if [ -z "$DuckDNS_Token" ]; then
|
||||
DuckDNS_Token=""
|
||||
_err "You must export variable: DuckDNS_Token"
|
||||
_err "The token for your DuckDNS account is necessary."
|
||||
_err "You can look it up in your DuckDNS account."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now save the credentials.
|
||||
_saveaccountconf DuckDNS_Domain "$DuckDNS_Domain"
|
||||
_saveaccountconf DuckDNS_Token "$DuckDNS_Token"
|
||||
_saveaccountconf_mutable DuckDNS_Token "$DuckDNS_Token"
|
||||
|
||||
# Unfortunately, DuckDNS does not seems to support lookup domain through API
|
||||
# So I assume your credentials (which are your domain and token) are correct
|
||||
# If something goes wrong, we will get a KO response from DuckDNS
|
||||
|
||||
if ! _duckdns_get_domain; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now add the TXT record to DuckDNS
|
||||
_info "Trying to add TXT record"
|
||||
if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" = "OK" ]; then
|
||||
_info "TXT record has been successfully added to your DuckDNS domain."
|
||||
_info "Note that all subdomains under this domain uses the same TXT record."
|
||||
return 0
|
||||
if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=$txtvalue"; then
|
||||
if [ "$response" = "OK" ]; then
|
||||
_info "TXT record has been successfully added to your DuckDNS domain."
|
||||
_info "Note that all subdomains under this domain uses the same TXT record."
|
||||
return 0
|
||||
else
|
||||
_err "Errors happened during adding the TXT record, response=$response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Errors happened during adding the TXT record."
|
||||
return 1
|
||||
@ -57,11 +61,28 @@ dns_duckdns_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}"
|
||||
if [ -z "$DuckDNS_Token" ]; then
|
||||
_err "You must export variable: DuckDNS_Token"
|
||||
_err "The token for your DuckDNS account is necessary."
|
||||
_err "You can look it up in your DuckDNS account."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _duckdns_get_domain; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now remove the TXT record from DuckDNS
|
||||
_info "Trying to remove TXT record"
|
||||
if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" = "OK" ]; then
|
||||
_info "TXT record has been successfully removed from your DuckDNS domain."
|
||||
return 0
|
||||
if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=&clear=true"; then
|
||||
if [ "$response" = "OK" ]; then
|
||||
_info "TXT record has been successfully removed from your DuckDNS domain."
|
||||
return 0
|
||||
else
|
||||
_err "Errors happened during removing the TXT record, response=$response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Errors happened during removing the TXT record."
|
||||
return 1
|
||||
@ -70,6 +91,22 @@ dns_duckdns_rm() {
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
#fulldomain=_acme-challenge.domain.duckdns.org
|
||||
#returns
|
||||
# _duckdns_domain=domain
|
||||
_duckdns_get_domain() {
|
||||
|
||||
# We'll extract the domain/username from full domain
|
||||
_duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.]duckdns.org' | cut -d . -f 2)"
|
||||
|
||||
if [ -z "$_duckdns_domain" ]; then
|
||||
_err "Error extracting the domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: method URI
|
||||
_duckdns_rest() {
|
||||
method=$1
|
||||
|
@ -11,7 +11,7 @@
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5"
|
||||
GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5"
|
||||
|
||||
#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gandi_livedns_add() {
|
||||
|
175
dnsapi/dns_he.sh
Executable file
175
dnsapi/dns_he.sh
Executable file
@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
########################################################################
|
||||
# Hurricane Electric hook script for acme.sh
|
||||
#
|
||||
# Environment variables:
|
||||
#
|
||||
# - $HE_Username (your dns.he.net username)
|
||||
# - $HE_Password (your dns.he.net password)
|
||||
#
|
||||
# Author: Ondrej Simek <me@ondrejsimek.com>
|
||||
# Git repo: https://github.com/angel333/acme.sh
|
||||
|
||||
#-- dns_he_add() - Add TXT record --------------------------------------
|
||||
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
|
||||
dns_he_add() {
|
||||
_full_domain=$1
|
||||
_txt_value=$2
|
||||
_info "Using DNS-01 Hurricane Electric hook"
|
||||
|
||||
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"
|
||||
|
||||
# Fills in the $_zone_id
|
||||
_find_zone "$_full_domain" || return 1
|
||||
_debug "Zone id \"$_zone_id\" will be used."
|
||||
|
||||
body="email=${HE_Username}&pass=${HE_Password}"
|
||||
body="$body&account="
|
||||
body="$body&menu=edit_zone"
|
||||
body="$body&Type=TXT"
|
||||
body="$body&hosted_dns_zoneid=$_zone_id"
|
||||
body="$body&hosted_dns_recordid="
|
||||
body="$body&hosted_dns_editzone=1"
|
||||
body="$body&Priority="
|
||||
body="$body&Name=$_full_domain"
|
||||
body="$body&Content=$_txt_value"
|
||||
body="$body&TTL=300"
|
||||
body="$body&hosted_dns_editrecord=Submit"
|
||||
response="$(_post "$body" "https://dns.he.net/")"
|
||||
exit_code="$?"
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
_info "TXT record added successfully."
|
||||
else
|
||||
_err "Couldn't add the TXT record."
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return "$exit_code"
|
||||
}
|
||||
|
||||
#-- dns_he_rm() - Remove TXT record ------------------------------------
|
||||
# Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
|
||||
dns_he_rm() {
|
||||
_full_domain=$1
|
||||
_txt_value=$2
|
||||
_info "Cleaning up after DNS-01 Hurricane Electric hook"
|
||||
|
||||
# fills in the $_zone_id
|
||||
_find_zone "$_full_domain" || return 1
|
||||
_debug "Zone id \"$_zone_id\" will be used."
|
||||
|
||||
# Find the record id to clean
|
||||
body="email=${HE_Username}&pass=${HE_Password}"
|
||||
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).
|
||||
|
||||
# Remove the record
|
||||
body="email=${HE_Username}&pass=${HE_Password}"
|
||||
body="$body&menu=edit_zone"
|
||||
body="$body&hosted_dns_zoneid=$_zone_id"
|
||||
body="$body&hosted_dns_recordid=$_record_id"
|
||||
body="$body&hosted_dns_editzone=1"
|
||||
body="$body&hosted_dns_delrecord=1"
|
||||
body="$body&hosted_dns_delconfirm=delete"
|
||||
_post "$body" "https://dns.he.net/" \
|
||||
| grep '<div id="dns_status" onClick="hideThis(this);">Successfully removed record.</div>' \
|
||||
>/dev/null
|
||||
exit_code="$?"
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
_info "Record removed successfully."
|
||||
else
|
||||
_err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand."
|
||||
return "$exit_code"
|
||||
fi
|
||||
}
|
||||
|
||||
########################## PRIVATE FUNCTIONS ###########################
|
||||
|
||||
#-- _find_zone() -------------------------------------------------------
|
||||
# Returns the most specific zone found in administration interface.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# _find_zone first.second.third.co.uk
|
||||
#
|
||||
# ... will return the first zone that exists in admin out of these:
|
||||
# - "first.second.third.co.uk"
|
||||
# - "second.third.co.uk"
|
||||
# - "third.co.uk"
|
||||
# - "co.uk" <-- unlikely
|
||||
# - "uk" <-'
|
||||
#
|
||||
# (another approach would be something like this:
|
||||
# https://github.com/hlandau/acme/blob/master/_doc/dns.hook
|
||||
# - that's better if there are multiple pages. It's so much simpler.
|
||||
# )
|
||||
|
||||
_find_zone() {
|
||||
|
||||
_domain="$1"
|
||||
|
||||
body="email=${HE_Username}&pass=${HE_Password}"
|
||||
_matches=$(_post "$body" "https://dns.he.net/" \
|
||||
| _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+"
|
||||
)
|
||||
# Zone names and zone IDs are in same order
|
||||
_zone_ids=$(echo "$_matches" | cut -d '"' -f 5)
|
||||
_zone_names=$(echo "$_matches" | cut -d '"' -f 3)
|
||||
_debug2 "These are the zones on this HE account:"
|
||||
_debug2 "$_zone_names"
|
||||
_debug2 "And these are their respective IDs:"
|
||||
_debug2 "$_zone_ids"
|
||||
|
||||
# Walk through all possible zone names
|
||||
_strip_counter=1
|
||||
while true; do
|
||||
_attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-)
|
||||
|
||||
# All possible zone names have been tried
|
||||
if [ -z "$_attempted_zone" ]; then
|
||||
_err "No zone for domain \"$_domain\" found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Looking for zone \"${_attempted_zone}\""
|
||||
|
||||
# Take care of "." and only match whole lines. Note that grep -F
|
||||
# cannot be used because there's no way to make it match whole
|
||||
# lines.
|
||||
regex="^$(echo "$_attempted_zone" | sed 's/\./\\./g')$"
|
||||
line_num=$(echo "$_zone_names" \
|
||||
| grep -n "$regex" \
|
||||
| cut -d : -f 1
|
||||
)
|
||||
|
||||
if [ -n "$line_num" ]; then
|
||||
_zone_id=$(echo "$_zone_ids" | sed "${line_num}q;d")
|
||||
_debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone."
|
||||
_strip_counter=$(_math "$_strip_counter" + 1)
|
||||
done
|
||||
}
|
||||
# vim: et:ts=2:sw=2:
|
@ -68,7 +68,7 @@ dns_linode_rm() {
|
||||
_parameters="&DomainID=$_domain_id"
|
||||
|
||||
if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then
|
||||
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
|
||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||
|
||||
resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")"
|
||||
if [ "$resource" ]; then
|
||||
@ -128,7 +128,7 @@ _get_root() {
|
||||
p=1
|
||||
|
||||
if _rest GET "domain.list"; then
|
||||
response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')"
|
||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
|
Loading…
x
Reference in New Issue
Block a user