Merge pull request #2882 from acmesh-official/dev

sync
This commit is contained in:
neil 2020-04-24 22:10:38 +08:00 committed by GitHub
commit 65c59c8c30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 529 additions and 107 deletions

View File

@ -4,17 +4,23 @@ issuesOpened: >
如果有 bug, 请先更新到最新版试试: 如果有 bug, 请先更新到最新版试试:
```sh ```
acme.sh --upgrade acme.sh --upgrade
``` ```
please also provide the log with `--debug 2`. please also provide the log with `--debug 2`.
同时请提供调试输出 `--debug 2`
see: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh see: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
Without `--debug 2` log, your issue will NEVER get replied.
没有调试输出, 你的 issue 不会得到任何解答.
pullRequestOpened: > pullRequestOpened: >
First, never send a PR to `master` branch, it will never be accepted. Please send to the `dev` branch instead. First, NEVER send a PR to `master` branch, it will NEVER be accepted. Please send to the `dev` branch instead.
If this is a PR to support new DNS API or new notification API, please read this guide first: If this is a PR to support new DNS API or new notification API, please read this guide first:
https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
@ -23,6 +29,12 @@ pullRequestOpened: >
Then add your usage here: Then add your usage here:
https://github.com/acmesh-official/acme.sh/wiki/dnsapi https://github.com/acmesh-official/acme.sh/wiki/dnsapi
Or some other wiki pages:
https://github.com/acmesh-official/acme.sh/wiki/deployhooks
https://github.com/acmesh-official/acme.sh/wiki/notify

24
acme.sh
View File

@ -138,6 +138,8 @@ _NOTIFY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/notify"
_SUDO_WIKI="https://github.com/acmesh-official/acme.sh/wiki/sudo" _SUDO_WIKI="https://github.com/acmesh-official/acme.sh/wiki/sudo"
_REVOKE_WIKI="https://github.com/acmesh-official/acme.sh/wiki/revokecert"
_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_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead."
_DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR"
@ -3512,6 +3514,8 @@ updateaccount() {
if [ "$ACME_VERSION" = "2" ]; then if [ "$ACME_VERSION" = "2" ]; then
if [ "$ACCOUNT_EMAIL" ]; then if [ "$ACCOUNT_EMAIL" ]; then
updjson='{"contact": ["mailto:'$ACCOUNT_EMAIL'"]}' updjson='{"contact": ["mailto:'$ACCOUNT_EMAIL'"]}'
else
updjson='{"contact": []}'
fi fi
else else
# ACMEv1: Updates happen the same way a registration is done. # ACMEv1: Updates happen the same way a registration is done.
@ -5454,6 +5458,7 @@ uninstallcronjob() {
} }
#domain isECC revokeReason
revoke() { revoke() {
Le_Domain="$1" Le_Domain="$1"
if [ -z "$Le_Domain" ]; then if [ -z "$Le_Domain" ]; then
@ -5462,7 +5467,10 @@ revoke() {
fi fi
_isEcc="$2" _isEcc="$2"
_reason="$3"
if [ -z "$_reason" ]; then
_reason="0"
fi
_initpath "$Le_Domain" "$_isEcc" _initpath "$Le_Domain" "$_isEcc"
if [ ! -f "$DOMAIN_CONF" ]; then if [ ! -f "$DOMAIN_CONF" ]; then
_err "$Le_Domain is not a issued domain, skip." _err "$Le_Domain is not a issued domain, skip."
@ -5484,7 +5492,7 @@ revoke() {
_initAPI _initAPI
if [ "$ACME_VERSION" = "2" ]; then if [ "$ACME_VERSION" = "2" ]; then
data="{\"certificate\": \"$cert\"}" data="{\"certificate\": \"$cert\",\"reason\":$_reason}"
else else
data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
fi fi
@ -6293,6 +6301,7 @@ Parameters:
0: Bulk mode. Send all the domain's notifications in one message(mail). 0: Bulk mode. Send all the domain's notifications in one message(mail).
1: Cert mode. Send a message for every single cert. 1: Cert mode. Send a message for every single cert.
--notify-hook [hookname] Set the notify hook --notify-hook [hookname] Set the notify hook
--revoke-reason [0-10] The reason for '--revoke' command. See: $_REVOKE_WIKI
" "
} }
@ -6468,6 +6477,7 @@ _process() {
_notify_hook="" _notify_hook=""
_notify_level="" _notify_level=""
_notify_mode="" _notify_mode=""
_revoke_reason=""
while [ ${#} -gt 0 ]; do while [ ${#} -gt 0 ]; do
case "${1}" in case "${1}" in
@ -6940,6 +6950,14 @@ _process() {
_notify_mode="$_nmode" _notify_mode="$_nmode"
shift shift
;; ;;
--revoke-reason)
_revoke_reason="$2"
if _startswith "$_revoke_reason" "-"; then
_err "'$_revoke_reason' is not a integer for '$1'"
return 1
fi
shift
;;
*) *)
_err "Unknown parameter : $1" _err "Unknown parameter : $1"
return 1 return 1
@ -7027,7 +7045,7 @@ _process() {
renewAll "$_stopRenewOnError" renewAll "$_stopRenewOnError"
;; ;;
revoke) revoke)
revoke "$_domain" "$_ecc" revoke "$_domain" "$_ecc" "$_revoke_reason"
;; ;;
remove) remove)
remove "$_domain" "$_ecc" remove "$_domain" "$_ecc"

View File

@ -12,7 +12,7 @@
# Only a username is required. All others are optional. # Only a username is required. All others are optional.
# #
# The following examples are for QNAP NAS running QTS 4.2 # The following examples are for QNAP NAS running QTS 4.2
# export DEPLOY_SSH_CMD="" # defaults to ssh # export DEPLOY_SSH_CMD="" # defaults to "ssh -T"
# export DEPLOY_SSH_USER="admin" # required # export DEPLOY_SSH_USER="admin" # required
# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name # export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" # export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
@ -20,7 +20,9 @@
# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" # export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
# export DEPLOY_SSH_FULLCHAIN="" # export DEPLOY_SSH_FULLCHAIN=""
# export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" # export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart"
# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes # export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
# export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy
# export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value
# #
######## Public functions ##################### ######## Public functions #####################
@ -31,10 +33,10 @@ ssh_deploy() {
_ccert="$3" _ccert="$3"
_cca="$4" _cca="$4"
_cfullchain="$5" _cfullchain="$5"
_err_code=0
_cmdstr="" _cmdstr=""
_homedir='~' _backupprefix=""
_backupprefix="$_homedir/.acme_ssh_deploy/$_cdomain-backup" _backupdir=""
_backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
if [ -f "$DOMAIN_CONF" ]; then if [ -f "$DOMAIN_CONF" ]; then
# shellcheck disable=SC1090 # shellcheck disable=SC1090
@ -71,18 +73,62 @@ ssh_deploy() {
Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD" Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
_savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd" _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
elif [ -z "$Le_Deploy_ssh_cmd" ]; then elif [ -z "$Le_Deploy_ssh_cmd" ]; then
Le_Deploy_ssh_cmd="ssh" Le_Deploy_ssh_cmd="ssh -T"
fi fi
# BACKUP is optional. If not provided then default to yes # BACKUP is optional. If not provided then default to previously saved value or yes.
if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
Le_Deploy_ssh_backup="no" Le_Deploy_ssh_backup="no"
elif [ -z "$Le_Deploy_ssh_backup" ]; then elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
Le_Deploy_ssh_backup="yes" Le_Deploy_ssh_backup="yes"
fi fi
_savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup" _savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
# BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
fi
_savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
# MULTI_CALL is optional. If not provided then default to previously saved
# value (which may be undefined... equivalent to "no").
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
Le_Deploy_ssh_multi_call="yes"
_savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
Le_Deploy_ssh_multi_call=""
_cleardomainconf Le_Deploy_ssh_multi_call
fi
_info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server" _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
else
_info "Required commands batched and sent in single call to remote host"
fi
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
_backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
_backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
# run cleanup on the backup directory, erase all older
# than 180 days (15552000 seconds).
_cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \
do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \
then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr"
# Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr"
# Create our backup directory for overwritten cert files.
_cmdstr="mkdir -p $_backupdir; $_cmdstr"
_info "Backup of old certificate files will be placed in remote directory $_backupdir"
_info "Backup directories erased after 180 days."
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
if ! _ssh_remote_cmd "$_cmdstr"; then
return $_err_code
fi
_cmdstr=""
fi
fi
# KEYFILE is optional. # KEYFILE is optional.
# If provided then private key will be copied to provided filename. # If provided then private key will be copied to provided filename.
@ -98,6 +144,12 @@ ssh_deploy() {
# copy new certificate into file. # copy new certificate into file.
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;" _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
_info "will copy private key to remote file $Le_Deploy_ssh_keyfile" _info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
if ! _ssh_remote_cmd "$_cmdstr"; then
return $_err_code
fi
_cmdstr=""
fi
fi fi
# CERTFILE is optional. # CERTFILE is optional.
@ -118,6 +170,12 @@ ssh_deploy() {
# copy new certificate into file. # copy new certificate into file.
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;" _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
_info "will copy certificate to remote file $Le_Deploy_ssh_certfile" _info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
if ! _ssh_remote_cmd "$_cmdstr"; then
return $_err_code
fi
_cmdstr=""
fi
fi fi
# CAFILE is optional. # CAFILE is optional.
@ -139,6 +197,12 @@ ssh_deploy() {
# copy new certificate into file. # copy new certificate into file.
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;" _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
_info "will copy CA file to remote file $Le_Deploy_ssh_cafile" _info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
if ! _ssh_remote_cmd "$_cmdstr"; then
return $_err_code
fi
_cmdstr=""
fi
fi fi
# FULLCHAIN is optional. # FULLCHAIN is optional.
@ -161,6 +225,12 @@ ssh_deploy() {
# copy new certificate into file. # copy new certificate into file.
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;" _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
_info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain" _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
if ! _ssh_remote_cmd "$_cmdstr"; then
return $_err_code
fi
_cmdstr=""
fi
fi fi
# REMOTE_CMD is optional. # REMOTE_CMD is optional.
@ -172,34 +242,36 @@ ssh_deploy() {
if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
_cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;" _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
_info "Will execute remote command $Le_Deploy_ssh_remote_cmd" _info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
if ! _ssh_remote_cmd "$_cmdstr"; then
return $_err_code
fi
_cmdstr=""
fi
fi fi
if [ -z "$_cmdstr" ]; then # if commands not all sent in multiple calls then all commands sent in a single SSH call now...
_err "No remote commands to excute. Failed to deploy certificates to remote server" if [ -n "$_cmdstr" ]; then
return 1 if ! _ssh_remote_cmd "$_cmdstr"; then
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then return $_err_code
# run cleanup on the backup directory, erase all older fi
# than 180 days (15552000 seconds).
_cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \
do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \
then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr"
# Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr"
# Create our backup directory for overwritten cert files.
_cmdstr="mkdir -p $_backupdir; $_cmdstr"
_info "Backup of old certificate files will be placed in remote directory $_backupdir"
_info "Backup directories erased after 180 days."
fi fi
return 0
}
_secure_debug "Remote commands to execute: " "$_cmdstr" #cmd
_ssh_remote_cmd() {
_cmd="$1"
_secure_debug "Remote commands to execute: $_cmd"
_info "Submitting sequence of commands to remote server by ssh" _info "Submitting sequence of commands to remote server by ssh"
# quotations in bash cmd below intended. Squash travis spellcheck error # quotations in bash cmd below intended. Squash travis spellcheck error
# shellcheck disable=SC2029 # shellcheck disable=SC2029
$Le_Deploy_ssh_cmd -T "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmdstr'" $Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
_ret="$?" _err_code="$?"
if [ "$_ret" != "0" ]; then if [ "$_err_code" != "0" ]; then
_err "Error code $_ret returned from $Le_Deploy_ssh_cmd" _err "Error code $_err_code returned from ssh"
fi fi
return $_ret return $_err_code
} }

163
dnsapi/dns_arvan.sh Normal file
View File

@ -0,0 +1,163 @@
#!/usr/bin/env sh
#Arvan_Token="xxxx"
ARVAN_API_URL="https://napi.arvancloud.com/cdn/4.0/domains"
#Author: Ehsan Aliakbar
#Report Bugs here: https://github.com/Neilpang/acme.sh
#
######## Public functions #####################
#Usage: dns_arvan_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_arvan_add() {
fulldomain=$1
txtvalue=$2
_info "Using Arvan"
Arvan_Token="${Arvan_Token:-$(_readaccountconf_mutable Arvan_Token)}"
if [ -z "$Arvan_Token" ]; then
_err "You didn't specify \"Arvan_Token\" token yet."
_err "You can get yours from here https://npanel.arvancloud.com/profile/api-keys"
return 1
fi
#save the api token to the account conf file.
_saveaccountconf_mutable Arvan_Token "$Arvan_Token"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_info "Adding record"
if _arvan_rest POST "$_domain/dns-records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":{\"text\":\"$txtvalue\"},\"ttl\":120}"; then
if _contains "$response" "$txtvalue"; then
_info "Added, OK"
return 0
elif _contains "$response" "Record Data is Duplicated"; then
_info "Already exists, OK"
return 0
else
_err "Add txt record error."
return 1
fi
fi
_err "Add txt record error."
return 1
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_arvan_rm() {
fulldomain=$1
txtvalue=$2
_info "Using Arvan"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
Arvan_Token="${Arvan_Token:-$(_readaccountconf_mutable Arvan_Token)}"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_debug "Getting txt records"
shorted_txtvalue=$(printf "%s" "$txtvalue" | cut -d "-" -d "_" -f1)
_arvan_rest GET "${_domain}/dns-records?search=$shorted_txtvalue"
if ! printf "%s" "$response" | grep \"current_page\":1 >/dev/null; then
_err "Error on Arvan Api"
_err "Please create a github issue with debbug log"
return 1
fi
count=$(printf "%s\n" "$response" | _egrep_o "\"total\":[^,]*" | cut -d : -f 2)
_debug count "$count"
if [ "$count" = "0" ]; then
_info "Don't need to remove."
else
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1)
_debug "record_id" "$record_id"
if [ -z "$record_id" ]; then
_err "Can not get record id to remove."
return 1
fi
if ! _arvan_rest "DELETE" "${_domain}/dns-records/$record_id"; then
_err "Delete record error."
return 1
fi
_debug "$response"
_contains "$response" 'dns record deleted'
fi
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
i=1
p=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if ! _arvan_rest GET "?search=$h"; then
return 1
fi
if _contains "$response" "\"domain\":\"$h\"" || _contains "$response" '"total":1'; then
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
return 0
fi
return 1
fi
p=$i
i=$(_math "$i" + 1)
done
return 1
}
_arvan_rest() {
mtd="$1"
ep="$2"
data="$3"
token_trimmed=$(echo "$Arvan_Token" | tr -d '"')
export _H1="Authorization: $token_trimmed"
if [ "$mtd" = "DELETE" ]; then
#DELETE Request shouldn't have Content-Type
_debug data "$data"
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
elif [ "$mtd" = "POST" ]; then
export _H2="Content-Type: application/json"
_debug data "$data"
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
else
response="$(_get "$ARVAN_API_URL/$ep$data")"
fi
}

View File

@ -119,7 +119,7 @@ _ddnss_rest() {
# DDNSS uses GET to update domain info # DDNSS uses GET to update domain info
if [ "$method" = "GET" ]; then if [ "$method" = "GET" ]; then
response="$(_get "$url" | sed 's/<[a-zA-Z\/][^>]*>//g' | _tail_n 1)" response="$(_get "$url" | sed 's/<[a-zA-Z\/][^>]*>//g' | tr -s "\n" | _tail_n 1)"
else else
_err "Unsupported method" _err "Unsupported method"
return 1 return 1

View File

@ -4,8 +4,7 @@
# #
# easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh # easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh
# #
# Please note: # API is currently beta and subject to constant change # API Documentation: https://sandbox.rest.easydns.net:3001/
# http://sandbox.rest.easydns.net:3000/
# #
# Author: wurzelpanzer [wurzelpanzer@maximolider.net] # Author: wurzelpanzer [wurzelpanzer@maximolider.net]
# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647 # Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647
@ -25,7 +24,7 @@ dns_easydns_add() {
EASYDNS_Key="${EASYDNS_Key:-$(_readaccountconf_mutable EASYDNS_Key)}" EASYDNS_Key="${EASYDNS_Key:-$(_readaccountconf_mutable EASYDNS_Key)}"
if [ -z "$EASYDNS_Token" ] || [ -z "$EASYDNS_Key" ]; then if [ -z "$EASYDNS_Token" ] || [ -z "$EASYDNS_Key" ]; then
_err "You didn't specify an easydns.net token or api key. Please sign up at http://docs.sandbox.rest.easydns.net/beta_signup.php" _err "You didn't specify an easydns.net token or api key. Signup at https://cp.easydns.com/manage/security/api/signup.php"
return 1 return 1
else else
_saveaccountconf_mutable EASYDNS_Token "$EASYDNS_Token" _saveaccountconf_mutable EASYDNS_Token "$EASYDNS_Token"

View File

@ -24,7 +24,7 @@ dns_he_add() {
if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then
HE_Username= HE_Username=
HE_Password= HE_Password=
_err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables." _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password environment variables."
return 1 return 1
fi fi
_saveaccountconf_mutable HE_Username "$HE_Username" _saveaccountconf_mutable HE_Username "$HE_Username"

View File

@ -34,6 +34,10 @@ dns_inwx_add() {
_saveaccountconf_mutable INWX_Password "$INWX_Password" _saveaccountconf_mutable INWX_Password "$INWX_Password"
_saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret" _saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret"
if ! _inwx_login; then
return 1
fi
_debug "First detect the root zone" _debug "First detect the root zone"
if ! _get_root "$fulldomain"; then if ! _get_root "$fulldomain"; then
_err "invalid domain" _err "invalid domain"
@ -64,6 +68,10 @@ dns_inwx_rm() {
return 1 return 1
fi fi
if ! _inwx_login; then
return 1
fi
_debug "First detect the root zone" _debug "First detect the root zone"
if ! _get_root "$fulldomain"; then if ! _get_root "$fulldomain"; then
_err "invalid domain" _err "invalid domain"
@ -123,8 +131,42 @@ dns_inwx_rm() {
#################### Private functions below ################################## #################### Private functions below ##################################
_inwx_check_cookie() {
INWX_Cookie="${INWX_Cookie:-$(_readaccountconf_mutable INWX_Cookie)}"
if [ -z "$INWX_Cookie" ]; then
_debug "No cached cookie found"
return 1
fi
_H1="$INWX_Cookie"
export _H1
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>account.info</methodName>
</methodCall>')
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
if _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>"; then
_debug "Cached cookie still valid"
return 0
fi
_debug "Cached cookie no longer valid"
_H1=""
export _H1
INWX_Cookie=""
_saveaccountconf_mutable INWX_Cookie "$INWX_Cookie"
return 1
}
_inwx_login() { _inwx_login() {
if _inwx_check_cookie; then
_debug "Already logged in"
return 0
fi
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?> xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall> <methodCall>
<methodName>account.login</methodName> <methodName>account.login</methodName>
@ -148,17 +190,25 @@ _inwx_login() {
</value> </value>
</param> </param>
</params> </params>
</methodCall>' $INWX_User $INWX_Password) </methodCall>' "$INWX_User" "$INWX_Password")
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
_H1=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')")
INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')")
_H1=$INWX_Cookie
export _H1 export _H1
export INWX_Cookie
_saveaccountconf_mutable INWX_Cookie "$INWX_Cookie"
if ! _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>"; then
_err "INWX API: Authentication error (username/password correct?)"
return 1
fi
#https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71 #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71
if _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>" \ if _contains "$response" "<member><name>tfa</name><value><string>GOOGLE-AUTH</string></value></member>"; then
&& _contains "$response" "<member><name>tfa</name><value><string>GOOGLE-AUTH</string></value></member>"; then
if [ -z "$INWX_Shared_Secret" ]; then if [ -z "$INWX_Shared_Secret" ]; then
_err "Mobile TAN detected." _err "INWX API: Mobile TAN detected."
_err "Please define a shared secret." _err "Please define a shared secret."
return 1 return 1
fi fi
@ -191,6 +241,11 @@ _inwx_login() {
</methodCall>' "$tan") </methodCall>' "$tan")
response="$(_post "$xml_content" "$INWX_Api" "" "POST")" response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
if ! _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>"; then
_err "INWX API: Mobile TAN not correct."
return 1
fi
fi fi
} }
@ -203,8 +258,6 @@ _get_root() {
i=2 i=2
p=1 p=1
_inwx_login
xml_content='<?xml version="1.0" encoding="UTF-8"?> xml_content='<?xml version="1.0" encoding="UTF-8"?>
<methodCall> <methodCall>
<methodName>nameserver.list</methodName> <methodName>nameserver.list</methodName>

View File

@ -5,8 +5,11 @@
# Author: github: @diseq # Author: github: @diseq
# Created: 2019-02-17 # Created: 2019-02-17
# Fixed by: @der-berni # Fixed by: @der-berni
# Modified: 2019-05-31 # Modified: 2020-04-07
# #
# Use ONECOM_KeepCnameProxy to keep the CNAME DNS record
# export ONECOM_KeepCnameProxy="1"
#
# export ONECOM_User="username" # export ONECOM_User="username"
# export ONECOM_Password="password" # export ONECOM_Password="password"
# #
@ -30,32 +33,45 @@ dns_one_add() {
return 1 return 1
fi fi
mysubdomain=$_sub_domain subdomain="${_sub_domain}"
mydomain=$_domain maindomain=${_domain}
_debug mysubdomain "$mysubdomain"
_debug mydomain "$mydomain"
# get entries useProxy=0
response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" if [ "${_sub_domain}" = "_acme-challenge" ]; then
_debug response "$response" subdomain="proxy${_sub_domain}"
useProxy=1
fi
# Update the IP address for domain entry _debug subdomain "$subdomain"
postdata="{\"type\":\"dns_custom_records\",\"attributes\":{\"priority\":0,\"ttl\":600,\"type\":\"TXT\",\"prefix\":\"$mysubdomain\",\"content\":\"$txtvalue\"}}" _debug maindomain "$maindomain"
_debug postdata "$postdata"
response="$(_post "$postdata" "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records" "" "POST" "application/json")"
response="$(echo "$response" | _normalizeJson)"
_debug response "$response"
id=$(echo "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p") if [ $useProxy -eq 1 ]; then
#Check if the CNAME exists
_dns_one_getrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain"
if [ -z "$id" ]; then
_info "$(__red "Add CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")"
_dns_one_addrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain"
if [ -z "$id" ]; then _info "Not valid yet, let's wait 1 hour to take effect."
_err "Add txt record error." _sleep 3600
return 1 fi
else fi
_info "Added, OK ($id)"
#Check if the TXT exists
_dns_one_getrecord "TXT" "$subdomain" "$txtvalue"
if [ -n "$id" ]; then
_info "$(__green "Txt record with the same value found. Skip adding.")"
return 0 return 0
fi fi
_dns_one_addrecord "TXT" "$subdomain" "$txtvalue"
if [ -z "$id" ]; then
_err "Add TXT record error."
return 1
else
_info "$(__green "Added, OK ($id)")"
return 0
fi
} }
dns_one_rm() { dns_one_rm() {
@ -73,36 +89,45 @@ dns_one_rm() {
return 1 return 1
fi fi
mysubdomain=$_sub_domain subdomain="${_sub_domain}"
mydomain=$_domain maindomain=${_domain}
_debug mysubdomain "$mysubdomain"
_debug mydomain "$mydomain"
# get entries useProxy=0
response="$(_get "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records")" if [ "${_sub_domain}" = "_acme-challenge" ]; then
response="$(echo "$response" | _normalizeJson)" subdomain="proxy${_sub_domain}"
_debug response "$response" useProxy=1
fi
id=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$mysubdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}.*/\1/p") _debug subdomain "$subdomain"
_debug maindomain "$maindomain"
if [ $useProxy -eq 1 ]; then
if [ "$ONECOM_KeepCnameProxy" = "1" ]; then
_info "$(__red "Keeping CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")"
else
#Check if the CNAME exists
_dns_one_getrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain"
if [ -n "$id" ]; then
_info "$(__red "Removing CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")"
_dns_one_delrecord "$id"
fi
fi
fi
#Check if the TXT exists
_dns_one_getrecord "TXT" "$subdomain" "$txtvalue"
if [ -z "$id" ]; then if [ -z "$id" ]; then
_err "Txt record not found." _err "Txt record not found."
return 1 return 1
fi fi
# delete entry # delete entry
response="$(_post "$postdata" "https://www.one.com/admin/api/domains/$mydomain/dns/custom_records/$id" "" "DELETE" "application/json")" if _dns_one_delrecord "$id"; then
response="$(echo "$response" | _normalizeJson)" _info "$(__green Removed, OK)"
_debug response "$response"
if [ "$response" = '{"result":null,"metadata":null}' ]; then
_info "Removed, OK"
return 0 return 0
else else
_err "Removing txt record error." _err "Removing txt record error."
return 1 return 1
fi fi
} }
#_acme-challenge.www.domain.com #_acme-challenge.www.domain.com
@ -138,6 +163,8 @@ _get_root() {
_dns_one_login() { _dns_one_login() {
# get credentials # get credentials
ONECOM_KeepCnameProxy="${ONECOM_KeepCnameProxy:-$(_readaccountconf_mutable ONECOM_KeepCnameProxy)}"
ONECOM_KeepCnameProxy="${ONECOM_KeepCnameProxy:-0}"
ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}"
ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}"
if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then
@ -149,6 +176,7 @@ _dns_one_login() {
fi fi
#save the api key and email to the account conf file. #save the api key and email to the account conf file.
_saveaccountconf_mutable ONECOM_KeepCnameProxy "$ONECOM_KeepCnameProxy"
_saveaccountconf_mutable ONECOM_User "$ONECOM_User" _saveaccountconf_mutable ONECOM_User "$ONECOM_User"
_saveaccountconf_mutable ONECOM_Password "$ONECOM_Password" _saveaccountconf_mutable ONECOM_Password "$ONECOM_Password"
@ -177,3 +205,75 @@ _dns_one_login() {
return 0 return 0
} }
_dns_one_getrecord() {
type="$1"
name="$2"
value="$3"
if [ -z "$type" ]; then
type="TXT"
fi
if [ -z "$name" ]; then
_err "Record name is empty."
return 1
fi
response="$(_get "https://www.one.com/admin/api/domains/$maindomain/dns/custom_records")"
response="$(echo "$response" | _normalizeJson)"
_debug response "$response"
if [ -z "${value}" ]; then
id=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"${name}\",\"type\":\"${type}\",\"content\":\"[^\"]*\",\"priority\":0,\"ttl\":600}.*/\1/p")
response=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"[^\"]*\",\"attributes\":{\"prefix\":\"${name}\",\"type\":\"${type}\",\"content\":\"\([^\"]*\)\",\"priority\":0,\"ttl\":600}.*/\1/p")
else
id=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"${name}\",\"type\":\"${type}\",\"content\":\"${value}\",\"priority\":0,\"ttl\":600}.*/\1/p")
fi
if [ -z "$id" ]; then
return 1
fi
return 0
}
_dns_one_addrecord() {
type="$1"
name="$2"
value="$3"
if [ -z "$type" ]; then
type="TXT"
fi
if [ -z "$name" ]; then
_err "Record name is empty."
return 1
fi
postdata="{\"type\":\"dns_custom_records\",\"attributes\":{\"priority\":0,\"ttl\":600,\"type\":\"${type}\",\"prefix\":\"${name}\",\"content\":\"${value}\"}}"
_debug postdata "$postdata"
response="$(_post "$postdata" "https://www.one.com/admin/api/domains/$maindomain/dns/custom_records" "" "POST" "application/json")"
response="$(echo "$response" | _normalizeJson)"
_debug response "$response"
id=$(echo "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$subdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p")
if [ -z "$id" ]; then
return 1
else
return 0
fi
}
_dns_one_delrecord() {
id="$1"
if [ -z "$id" ]; then
return 1
fi
response="$(_post "" "https://www.one.com/admin/api/domains/$maindomain/dns/custom_records/$id" "" "DELETE" "application/json")"
response="$(echo "$response" | _normalizeJson)"
_debug response "$response"
if [ "$response" = '{"result":null,"metadata":null}' ]; then
return 0
else
return 1
fi
}

View File

@ -150,7 +150,7 @@ _get_root() {
return 1 return 1
fi fi
_debug h "$h" _debug h "$h"
id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":\"[^\"]*\",\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2) id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":\"[^\"]*\",\"allownotifyslave\":{\"\":{[^}]*}},\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2)
if [ -n "$id" ]; then if [ -n "$id" ]; then
_debug id "$id" _debug id "$id"

View File

@ -6,6 +6,7 @@
#MAIL_FROM="yyyy@gmail.com" #MAIL_FROM="yyyy@gmail.com"
#MAIL_TO="yyyy@gmail.com" #MAIL_TO="yyyy@gmail.com"
#MAIL_NOVALIDATE="" #MAIL_NOVALIDATE=""
#MAIL_MSMTP_ACCOUNT=""
mail_send() { mail_send() {
_subject="$1" _subject="$1"
@ -76,18 +77,17 @@ mail_send() {
} }
_mail_bin() { _mail_bin() {
if [ -n "$MAIL_BIN" ]; then _MAIL_BIN=""
_MAIL_BIN="$MAIL_BIN"
elif _exists "sendmail"; then for b in "$MAIL_BIN" sendmail ssmtp mutt mail msmtp; do
_MAIL_BIN="sendmail" if _exists "$b"; then
elif _exists "ssmtp"; then _MAIL_BIN="$b"
_MAIL_BIN="ssmtp" break
elif _exists "mutt"; then fi
_MAIL_BIN="mutt" done
elif _exists "mail"; then
_MAIL_BIN="mail" if [ -z "$_MAIL_BIN" ]; then
else _err "Please install sendmail, ssmtp, mutt, mail or msmtp first."
_err "Please install sendmail, ssmtp, mutt or mail first."
return 1 return 1
fi fi
@ -95,30 +95,35 @@ _mail_bin() {
} }
_mail_cmnd() { _mail_cmnd() {
_MAIL_ARGS=""
case $(basename "$_MAIL_BIN") in case $(basename "$_MAIL_BIN") in
sendmail) sendmail)
if [ -n "$MAIL_FROM" ]; then if [ -n "$MAIL_FROM" ]; then
echo "'$_MAIL_BIN' -f '$MAIL_FROM' '$MAIL_TO'" _MAIL_ARGS="-f '$MAIL_FROM'"
else
echo "'$_MAIL_BIN' '$MAIL_TO'"
fi fi
;; ;;
ssmtp)
echo "'$_MAIL_BIN' '$MAIL_TO'"
;;
mutt | mail) mutt | mail)
echo "'$_MAIL_BIN' -s '$_subject' '$MAIL_TO'" _MAIL_ARGS="-s '$_subject'"
;; ;;
*) msmtp)
_err "Command $MAIL_BIN is not supported, use sendmail, ssmtp, mutt or mail." if [ -n "$MAIL_FROM" ]; then
return 1 _MAIL_ARGS="-f '$MAIL_FROM'"
fi
if [ -n "$MAIL_MSMTP_ACCOUNT" ]; then
_MAIL_ARGS="$_MAIL_ARGS -a '$MAIL_MSMTP_ACCOUNT'"
fi
;; ;;
*) ;;
esac esac
echo "'$_MAIL_BIN' $_MAIL_ARGS '$MAIL_TO'"
} }
_mail_body() { _mail_body() {
case $(basename "$_MAIL_BIN") in case $(basename "$_MAIL_BIN") in
sendmail | ssmtp) sendmail | ssmtp | msmtp)
if [ -n "$MAIL_FROM" ]; then if [ -n "$MAIL_FROM" ]; then
echo "From: $MAIL_FROM" echo "From: $MAIL_FROM"
fi fi