Merge branch 'dev' into syno-patch
This commit is contained in:
commit
f7f3a0bf0d
2
.github/workflows/DNS.yml
vendored
2
.github/workflows/DNS.yml
vendored
@ -384,7 +384,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||||
prepare: |
|
prepare: |
|
||||||
pkg install -y curl socat
|
pkg install -y curl socat libnghttp2
|
||||||
usesh: true
|
usesh: true
|
||||||
copyback: false
|
copyback: false
|
||||||
run: |
|
run: |
|
||||||
|
2
.github/workflows/DragonFlyBSD.yml
vendored
2
.github/workflows/DragonFlyBSD.yml
vendored
@ -62,7 +62,7 @@ jobs:
|
|||||||
nat: |
|
nat: |
|
||||||
"8080": "80"
|
"8080": "80"
|
||||||
prepare: |
|
prepare: |
|
||||||
pkg install -y curl socat
|
pkg install -y curl socat libnghttp2
|
||||||
usesh: true
|
usesh: true
|
||||||
run: |
|
run: |
|
||||||
cd ../acmetest \
|
cd ../acmetest \
|
||||||
|
2
.github/workflows/OpenBSD.yml
vendored
2
.github/workflows/OpenBSD.yml
vendored
@ -66,7 +66,7 @@ jobs:
|
|||||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||||
nat: |
|
nat: |
|
||||||
"8080": "80"
|
"8080": "80"
|
||||||
prepare: pkg_add socat curl wget
|
prepare: pkg_add socat curl wget libnghttp2
|
||||||
usesh: true
|
usesh: true
|
||||||
copyback: false
|
copyback: false
|
||||||
run: |
|
run: |
|
||||||
|
@ -506,10 +506,6 @@ Support this project with your organization. Your logo will show up here with a
|
|||||||
<a href="https://opencollective.com/acmesh/organization/9/website"><img src="https://opencollective.com/acmesh/organization/9/avatar.svg"></a>
|
<a href="https://opencollective.com/acmesh/organization/9/website"><img src="https://opencollective.com/acmesh/organization/9/avatar.svg"></a>
|
||||||
|
|
||||||
|
|
||||||
#### Sponsors
|
|
||||||
|
|
||||||
[![quantumca-acmesh-logo](https://user-images.githubusercontent.com/8305679/183255712-634ee1db-bb61-4c03-bca0-bacce99e078c.svg)](https://www.quantumca.com.cn/?__utm_source=acmesh-donation)
|
|
||||||
|
|
||||||
|
|
||||||
# 19. License & Others
|
# 19. License & Others
|
||||||
|
|
||||||
|
50
acme.sh
50
acme.sh
@ -102,12 +102,12 @@ ECC_SUFFIX="${ECC_SEP}ecc"
|
|||||||
LOG_LEVEL_1=1
|
LOG_LEVEL_1=1
|
||||||
LOG_LEVEL_2=2
|
LOG_LEVEL_2=2
|
||||||
LOG_LEVEL_3=3
|
LOG_LEVEL_3=3
|
||||||
DEFAULT_LOG_LEVEL="$LOG_LEVEL_1"
|
DEFAULT_LOG_LEVEL="$LOG_LEVEL_2"
|
||||||
|
|
||||||
DEBUG_LEVEL_1=1
|
DEBUG_LEVEL_1=1
|
||||||
DEBUG_LEVEL_2=2
|
DEBUG_LEVEL_2=2
|
||||||
DEBUG_LEVEL_3=3
|
DEBUG_LEVEL_3=3
|
||||||
DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1
|
DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_2
|
||||||
DEBUG_LEVEL_NONE=0
|
DEBUG_LEVEL_NONE=0
|
||||||
|
|
||||||
DOH_CLOUDFLARE=1
|
DOH_CLOUDFLARE=1
|
||||||
@ -923,8 +923,16 @@ _sed_i() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if [ "$(echo abc | egrep -o b 2>/dev/null)" = "b" ]; then
|
||||||
|
__USE_EGREP=1
|
||||||
|
else
|
||||||
|
__USE_EGREP=""
|
||||||
|
fi
|
||||||
|
|
||||||
_egrep_o() {
|
_egrep_o() {
|
||||||
if ! egrep -o "$1" 2>/dev/null; then
|
if [ "$__USE_EGREP" ]; then
|
||||||
|
egrep -o -- "$1"
|
||||||
|
else
|
||||||
sed -n 's/.*\('"$1"'\).*/\1/p'
|
sed -n 's/.*\('"$1"'\).*/\1/p'
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -1553,7 +1561,7 @@ createDomainKey() {
|
|||||||
createCSR() {
|
createCSR() {
|
||||||
_info "Creating csr"
|
_info "Creating csr"
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
_usage "Usage: $PROJECT_ENTRY --create-csr --domain <domain.tld> [--domain <domain2.tld> ...]"
|
_usage "Usage: $PROJECT_ENTRY --create-csr --domain <domain.tld> [--domain <domain2.tld> ...] [--ecc]"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -2101,9 +2109,20 @@ _head_n() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_tail_n() {
|
_tail_n() {
|
||||||
if ! tail -n "$1" 2>/dev/null; then
|
if _is_solaris; then
|
||||||
#fix for solaris
|
#fix for solaris
|
||||||
tail -"$1"
|
tail -"$1"
|
||||||
|
else
|
||||||
|
tail -n "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_tail_c() {
|
||||||
|
if _is_solaris; then
|
||||||
|
#fix for solaris
|
||||||
|
tail -"$1"c
|
||||||
|
else
|
||||||
|
tail -c "$1"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2278,7 +2297,7 @@ _setopt() {
|
|||||||
if [ ! -f "$__conf" ]; then
|
if [ ! -f "$__conf" ]; then
|
||||||
touch "$__conf"
|
touch "$__conf"
|
||||||
fi
|
fi
|
||||||
if [ -n "$(tail -c1 <"$__conf")" ]; then
|
if [ -n "$(_tail_c 1 <"$__conf")" ]; then
|
||||||
echo >>"$__conf"
|
echo >>"$__conf"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -3111,7 +3130,7 @@ _setNginx() {
|
|||||||
_err "nginx command is not found."
|
_err "nginx command is not found."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")"
|
NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "\-\-conf-path=[^ ]* " | tr -d " ")"
|
||||||
_debug NGINX_CONF "$NGINX_CONF"
|
_debug NGINX_CONF "$NGINX_CONF"
|
||||||
NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)"
|
NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)"
|
||||||
_debug NGINX_CONF "$NGINX_CONF"
|
_debug NGINX_CONF "$NGINX_CONF"
|
||||||
@ -4996,9 +5015,9 @@ $_authorizations_map"
|
|||||||
errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)"
|
errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)"
|
||||||
_debug2 errordetail "$errordetail"
|
_debug2 errordetail "$errordetail"
|
||||||
if [ "$errordetail" ]; then
|
if [ "$errordetail" ]; then
|
||||||
_err "$d:Verify error:$errordetail"
|
_err "Invalid status, $d:Verify error detail:$errordetail"
|
||||||
else
|
else
|
||||||
_err "$d:Verify error:$error"
|
_err "Invalid status, $d:Verify error:$error"
|
||||||
fi
|
fi
|
||||||
if [ "$DEBUG" ]; then
|
if [ "$DEBUG" ]; then
|
||||||
if [ "$vtype" = "$VTYPE_HTTP" ]; then
|
if [ "$vtype" = "$VTYPE_HTTP" ]; then
|
||||||
@ -5025,7 +5044,7 @@ $_authorizations_map"
|
|||||||
elif _contains "$status" "processing"; then
|
elif _contains "$status" "processing"; then
|
||||||
_info "Processing, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
|
_info "Processing, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
|
||||||
else
|
else
|
||||||
_err "$d:Verify error:$response"
|
_err "Unknown status: $status, $d:Verify error:$response"
|
||||||
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
||||||
_clearup
|
_clearup
|
||||||
_on_issue_err "$_post_hook" "$vlist"
|
_on_issue_err "$_post_hook" "$vlist"
|
||||||
@ -5038,7 +5057,7 @@ $_authorizations_map"
|
|||||||
_send_signed_request "$_authz_url"
|
_send_signed_request "$_authz_url"
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
if [ "$?" != "0" ]; then
|
||||||
_err "$d:Verify error:$response"
|
_err "Invalid code, $d:Verify error:$response"
|
||||||
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
||||||
_clearup
|
_clearup
|
||||||
_on_issue_err "$_post_hook" "$vlist"
|
_on_issue_err "$_post_hook" "$vlist"
|
||||||
@ -6880,7 +6899,7 @@ Parameters:
|
|||||||
|
|
||||||
-f, --force Force install, force cert renewal or override sudo restrictions.
|
-f, --force Force install, force cert renewal or override sudo restrictions.
|
||||||
--staging, --test Use staging server, for testing.
|
--staging, --test Use staging server, for testing.
|
||||||
--debug [0|1|2|3] Output debug info. Defaults to 1 if argument is omitted.
|
--debug [0|1|2|3] Output debug info. Defaults to $DEBUG_LEVEL_DEFAULT if argument is omitted.
|
||||||
--output-insecure Output all the sensitive messages.
|
--output-insecure Output all the sensitive messages.
|
||||||
By default all the credentials/sensitive messages are hidden from the output/debug/log for security.
|
By default all the credentials/sensitive messages are hidden from the output/debug/log for security.
|
||||||
-w, --webroot <directory> Specifies the web root folder for web root mode.
|
-w, --webroot <directory> Specifies the web root folder for web root mode.
|
||||||
@ -6898,7 +6917,7 @@ Parameters:
|
|||||||
-k, --keylength <bits> Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521.
|
-k, --keylength <bits> Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521.
|
||||||
-ak, --accountkeylength <bits> Specifies the account key length: 2048, 3072, 4096
|
-ak, --accountkeylength <bits> Specifies the account key length: 2048, 3072, 4096
|
||||||
--log [file] Specifies the log file. Defaults to \"$DEFAULT_LOG_FILE\" if argument is omitted.
|
--log [file] Specifies the log file. Defaults to \"$DEFAULT_LOG_FILE\" if argument is omitted.
|
||||||
--log-level <1|2> Specifies the log level, default is 1.
|
--log-level <1|2> Specifies the log level, default is $DEFAULT_LOG_LEVEL.
|
||||||
--syslog <0|3|6|7> Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
|
--syslog <0|3|6|7> Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
|
||||||
--eab-kid <eab_key_id> Key Identifier for External Account Binding.
|
--eab-kid <eab_key_id> Key Identifier for External Account Binding.
|
||||||
--eab-hmac-key <eab_hmac_key> HMAC key for External Account Binding.
|
--eab-hmac-key <eab_hmac_key> HMAC key for External Account Binding.
|
||||||
@ -6906,7 +6925,7 @@ Parameters:
|
|||||||
|
|
||||||
These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert:
|
These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert:
|
||||||
|
|
||||||
--cert-file <file> Path to copy the cert file to after issue/renew..
|
--cert-file <file> Path to copy the cert file to after issue/renew.
|
||||||
--key-file <file> Path to copy the key file to after issue/renew.
|
--key-file <file> Path to copy the key file to after issue/renew.
|
||||||
--ca-file <file> Path to copy the intermediate cert file to after issue/renew.
|
--ca-file <file> Path to copy the intermediate cert file to after issue/renew.
|
||||||
--fullchain-file <file> Path to copy the fullchain cert file to after issue/renew.
|
--fullchain-file <file> Path to copy the fullchain cert file to after issue/renew.
|
||||||
@ -6936,7 +6955,8 @@ Parameters:
|
|||||||
--no-profile Only valid for '--install' command, which means: do not install aliases to user profile.
|
--no-profile Only valid for '--install' command, which means: do not install aliases to user profile.
|
||||||
--no-color Do not output color text.
|
--no-color Do not output color text.
|
||||||
--force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails.
|
--force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails.
|
||||||
--ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--to-pkcs12' and '--create-csr'
|
--ecc Specifies use of the ECC cert. Only valid for '--install-cert', '--renew', '--remove ', '--revoke',
|
||||||
|
'--deploy', '--to-pkcs8', '--to-pkcs12' and '--create-csr'.
|
||||||
--csr <file> Specifies the input csr.
|
--csr <file> Specifies the input csr.
|
||||||
--pre-hook <command> Command to be run before obtaining any certificates.
|
--pre-hook <command> Command to be run before obtaining any certificates.
|
||||||
--post-hook <command> Command to be run after attempting to obtain/renew certificates. Runs regardless of whether obtain/renew succeeded or failed.
|
--post-hook <command> Command to be run after attempting to obtain/renew certificates. Runs regardless of whether obtain/renew succeeded or failed.
|
||||||
|
160
deploy/panos.sh
160
deploy/panos.sh
@ -7,11 +7,15 @@
|
|||||||
#
|
#
|
||||||
# Firewall admin with superuser and IP address is required.
|
# Firewall admin with superuser and IP address is required.
|
||||||
#
|
#
|
||||||
# export PANOS_USER="" # required
|
# REQURED:
|
||||||
# export PANOS_PASS="" # required
|
# export PANOS_HOST=""
|
||||||
# export PANOS_HOST="" # required
|
# export PANOS_USER="" #User *MUST* have Commit and Import Permissions in XML API for Admin Role
|
||||||
|
# export PANOS_PASS=""
|
||||||
|
#
|
||||||
|
# The script will automatically generate a new API key if
|
||||||
|
# no key is found, or if a saved key has expired or is invalid.
|
||||||
|
|
||||||
# This function is to parse the XML
|
# This function is to parse the XML response from the firewall
|
||||||
parse_response() {
|
parse_response() {
|
||||||
type=$2
|
type=$2
|
||||||
if [ "$type" = 'keygen' ]; then
|
if [ "$type" = 'keygen' ]; then
|
||||||
@ -23,25 +27,46 @@ parse_response() {
|
|||||||
message="PAN-OS Key could not be set."
|
message="PAN-OS Key could not be set."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
status=$(echo "$1" | tr -d '\n' | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
||||||
message=$(echo "$1" | sed 's/^.*<result>\(.*\)<\/result.*/\1/g')
|
message=$(echo "$1" | tr -d '\n' | sed 's/.*\(<result>\|<msg>\|<line>\)\([^<]*\).*/\2/g')
|
||||||
|
_debug "Firewall message: $message"
|
||||||
|
if [ "$type" = 'keytest' ] && [ "$status" != "success" ]; then
|
||||||
|
_debug "**** API Key has EXPIRED or is INVALID ****"
|
||||||
|
unset _panos_key
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#This function is used to deploy to the firewall
|
||||||
deployer() {
|
deployer() {
|
||||||
content=""
|
content=""
|
||||||
type=$1 # Types are keygen, cert, key, commit
|
type=$1 # Types are keytest, keygen, cert, key, commit
|
||||||
_debug "**** Deploying $type *****"
|
|
||||||
panos_url="https://$_panos_host/api/"
|
panos_url="https://$_panos_host/api/"
|
||||||
|
|
||||||
|
#Test API Key by performing a lookup
|
||||||
|
if [ "$type" = 'keytest' ]; then
|
||||||
|
_debug "**** Testing saved API Key ****"
|
||||||
|
_H1="Content-Type: application/x-www-form-urlencoded"
|
||||||
|
# Get Version Info to test key
|
||||||
|
content="type=version&key=$_panos_key"
|
||||||
|
## Exclude all scopes for the empty commit
|
||||||
|
#_exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network><shared-object>exclude</shared-object>"
|
||||||
|
#content="type=commit&action=partial&key=$_panos_key&cmd=<commit><partial>$_exclude_scope<admin><member>acmekeytest</member></admin></partial></commit>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate API Key
|
||||||
if [ "$type" = 'keygen' ]; then
|
if [ "$type" = 'keygen' ]; then
|
||||||
|
_debug "**** Generating new API Key ****"
|
||||||
_H1="Content-Type: application/x-www-form-urlencoded"
|
_H1="Content-Type: application/x-www-form-urlencoded"
|
||||||
content="type=keygen&user=$_panos_user&password=$_panos_pass"
|
content="type=keygen&user=$_panos_user&password=$_panos_pass"
|
||||||
# content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}"
|
# content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Deploy Cert or Key
|
||||||
if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then
|
if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then
|
||||||
#Generate DEIM
|
_debug "**** Deploying $type ****"
|
||||||
|
#Generate DELIM
|
||||||
delim="-----MultipartDelimiter$(date "+%s%N")"
|
delim="-----MultipartDelimiter$(date "+%s%N")"
|
||||||
nl="\015\012"
|
nl="\015\012"
|
||||||
#Set Header
|
#Set Header
|
||||||
@ -61,7 +86,7 @@ deployer() {
|
|||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cdomain.key")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||||
fi
|
fi
|
||||||
#Close multipart
|
#Close multipart
|
||||||
content="$content${nl}--$delim--${nl}${nl}"
|
content="$content${nl}--$delim--${nl}${nl}"
|
||||||
@ -69,16 +94,25 @@ deployer() {
|
|||||||
content=$(printf %b "$content")
|
content=$(printf %b "$content")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Commit changes
|
||||||
if [ "$type" = 'commit' ]; then
|
if [ "$type" = 'commit' ]; then
|
||||||
|
_debug "**** Committing changes ****"
|
||||||
export _H1="Content-Type: application/x-www-form-urlencoded"
|
export _H1="Content-Type: application/x-www-form-urlencoded"
|
||||||
cmd=$(printf "%s" "<commit><partial><$_panos_user></$_panos_user></partial></commit>" | _url_encode)
|
#Check for force commit - will commit ALL uncommited changes to the firewall. Use with caution!
|
||||||
content="type=commit&key=$_panos_key&cmd=$cmd"
|
if [ "$FORCE" ]; then
|
||||||
|
_debug "Force switch detected. Committing ALL changes to the firewall."
|
||||||
|
cmd=$(printf "%s" "<commit><partial><force><admin><member>$_panos_user</member></admin></force></partial></commit>" | _url_encode)
|
||||||
|
else
|
||||||
|
_exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network>"
|
||||||
|
cmd=$(printf "%s" "<commit><partial>$_exclude_scope<admin><member>$_panos_user</member></admin></partial></commit>" | _url_encode)
|
||||||
fi
|
fi
|
||||||
|
content="type=commit&action=partial&key=$_panos_key&cmd=$cmd"
|
||||||
|
fi
|
||||||
|
|
||||||
response=$(_post "$content" "$panos_url" "" "POST")
|
response=$(_post "$content" "$panos_url" "" "POST")
|
||||||
parse_response "$response" "$type"
|
parse_response "$response" "$type"
|
||||||
# Saving response to variables
|
# Saving response to variables
|
||||||
response_status=$status
|
response_status=$status
|
||||||
#DEBUG
|
|
||||||
_debug response_status "$response_status"
|
_debug response_status "$response_status"
|
||||||
if [ "$response_status" = "success" ]; then
|
if [ "$response_status" = "success" ]; then
|
||||||
_debug "Successfully deployed $type"
|
_debug "Successfully deployed $type"
|
||||||
@ -92,43 +126,85 @@ deployer() {
|
|||||||
|
|
||||||
# This is the main function that will call the other functions to deploy everything.
|
# This is the main function that will call the other functions to deploy everything.
|
||||||
panos_deploy() {
|
panos_deploy() {
|
||||||
_cdomain="$1"
|
_cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename
|
||||||
_ckey="$2"
|
_ckey="$2"
|
||||||
_cfullchain="$5"
|
_cfullchain="$5"
|
||||||
# PANOS ENV VAR check
|
|
||||||
if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then
|
# VALID FILE CHECK
|
||||||
_debug "No ENV variables found lets check for saved variables"
|
if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then
|
||||||
_getdeployconf PANOS_USER
|
_err "Unable to find a valid key and/or cert. If this is an ECDSA/ECC cert, use the --ecc flag when deploying."
|
||||||
_getdeployconf PANOS_PASS
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS_HOST
|
||||||
|
if [ "$PANOS_HOST" ]; then
|
||||||
|
_debug "Detected ENV variable PANOS_HOST. Saving to file."
|
||||||
|
_savedeployconf PANOS_HOST "$PANOS_HOST" 1
|
||||||
|
else
|
||||||
|
_debug "Attempting to load variable PANOS_HOST from file."
|
||||||
_getdeployconf PANOS_HOST
|
_getdeployconf PANOS_HOST
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS USER
|
||||||
|
if [ "$PANOS_USER" ]; then
|
||||||
|
_debug "Detected ENV variable PANOS_USER. Saving to file."
|
||||||
|
_savedeployconf PANOS_USER "$PANOS_USER" 1
|
||||||
|
else
|
||||||
|
_debug "Attempting to load variable PANOS_USER from file."
|
||||||
|
_getdeployconf PANOS_USER
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS_PASS
|
||||||
|
if [ "$PANOS_PASS" ]; then
|
||||||
|
_debug "Detected ENV variable PANOS_PASS. Saving to file."
|
||||||
|
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
|
||||||
|
else
|
||||||
|
_debug "Attempting to load variable PANOS_PASS from file."
|
||||||
|
_getdeployconf PANOS_PASS
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS_KEY
|
||||||
|
_getdeployconf PANOS_KEY
|
||||||
|
if [ "$PANOS_KEY" ]; then
|
||||||
|
_debug "Detected saved key."
|
||||||
|
_panos_key=$PANOS_KEY
|
||||||
|
else
|
||||||
|
_debug "No key detected"
|
||||||
|
unset _panos_key
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Store variables
|
||||||
|
_panos_host=$PANOS_HOST
|
||||||
_panos_user=$PANOS_USER
|
_panos_user=$PANOS_USER
|
||||||
_panos_pass=$PANOS_PASS
|
_panos_pass=$PANOS_PASS
|
||||||
_panos_host=$PANOS_HOST
|
|
||||||
if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then
|
#Test API Key if found. If the key is invalid, the variable _panos_key will be unset.
|
||||||
_err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs."
|
if [ "$_panos_host" ] && [ "$_panos_key" ]; then
|
||||||
|
_debug "**** Testing API KEY ****"
|
||||||
|
deployer keytest
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for valid variables
|
||||||
|
if [ -z "$_panos_host" ]; then
|
||||||
|
_err "No host found. If this is your first time deploying, please set PANOS_HOST in ENV variables. You can delete it after you have successfully deployed the certs."
|
||||||
|
return 1
|
||||||
|
elif [ -z "$_panos_user" ]; then
|
||||||
|
_err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs."
|
||||||
|
return 1
|
||||||
|
elif [ -z "$_panos_pass" ]; then
|
||||||
|
_err "No password found. If this is your first time deploying, please set PANOS_PASS in ENV variables. You can delete it after you have successfully deployed the certs."
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
_debug "Using saved env variables."
|
# Generate a new API key if no valid API key is found
|
||||||
fi
|
|
||||||
else
|
|
||||||
_debug "Detected ENV variables to be saved to the deploy conf."
|
|
||||||
# Encrypt and save user
|
|
||||||
_savedeployconf PANOS_USER "$PANOS_USER" 1
|
|
||||||
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
|
|
||||||
_savedeployconf PANOS_HOST "$PANOS_HOST" 1
|
|
||||||
_panos_user="$PANOS_USER"
|
|
||||||
_panos_pass="$PANOS_PASS"
|
|
||||||
_panos_host="$PANOS_HOST"
|
|
||||||
fi
|
|
||||||
_debug "Let's use username and pass to generate token."
|
|
||||||
if [ -z "$_panos_user" ] || [ -z "$_panos_pass" ] || [ -z "$_panos_host" ]; then
|
|
||||||
_err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST"
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
_debug "Getting PANOS KEY"
|
|
||||||
deployer keygen
|
|
||||||
if [ -z "$_panos_key" ]; then
|
if [ -z "$_panos_key" ]; then
|
||||||
_err "Missing apikey."
|
_debug "**** Generating new PANOS API KEY ****"
|
||||||
|
deployer keygen
|
||||||
|
_savedeployconf PANOS_KEY "$_panos_key" 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Confirm that a valid key was generated
|
||||||
|
if [ -z "$_panos_key" ]; then
|
||||||
|
_err "Unable to generate an API key. The user and pass may be invalid or not authorized to generate a new key. Please check the PANOS_USER and PANOS_PASS credentials and try again"
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
deployer cert
|
deployer cert
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
# 1. export SYNO_Username="adminUser"
|
# 1. export SYNO_Username="adminUser"
|
||||||
# 2. export SYNO_Password="adminPassword"
|
# 2. export SYNO_Password="adminPassword"
|
||||||
# Optional exports (shown values are the defaults):
|
# Optional exports (shown values are the defaults):
|
||||||
# - export SYNO_Certificate="" to replace a specific certificate via description
|
# - export SYNO_Certificate="" - to replace a specific certificate via description
|
||||||
# - export SYNO_Scheme="http"
|
# - export SYNO_Scheme="http"
|
||||||
# - export SYNO_Hostname="localhost"
|
# - export SYNO_Hostname="localhost"
|
||||||
# - export SYNO_Port="5000"
|
# - export SYNO_Port="5000"
|
||||||
# - export SYNO_Device_Name="CertRenewal" - required for skipping 2FA-OTP
|
# - export SYNO_Create=1 to allow creating the certificate if it doesn't exist
|
||||||
|
# - export SYNO_Device_Name="CertRenewal" - required if 2FA-OTP enabled
|
||||||
# - export SYNO_Device_ID="" - required for skipping 2FA-OTP
|
# - export SYNO_Device_ID="" - required for skipping 2FA-OTP
|
||||||
# 3. acme.sh --deploy --deploy-hook synology_dsm -d example.com
|
# 3. acme.sh --deploy --deploy-hook synology_dsm -d example.com
|
||||||
################################################################################
|
################################################################################
|
||||||
@ -110,8 +111,10 @@ synology_dsm_deploy() {
|
|||||||
|
|
||||||
_debug "Getting API version"
|
_debug "Getting API version"
|
||||||
response=$(_get "$_base_url/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth")
|
response=$(_get "$_base_url/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth")
|
||||||
|
api_path=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"path" *: *"\([0-9]*\)".*/\1/p')
|
||||||
api_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p')
|
api_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p')
|
||||||
_debug3 response "$response"
|
_debug3 response "$response"
|
||||||
|
_debug3 api_path "$api_path"
|
||||||
_debug3 api_version "$api_version"
|
_debug3 api_version "$api_version"
|
||||||
|
|
||||||
# Login, get the session ID & SynoToken from JSON
|
# Login, get the session ID & SynoToken from JSON
|
||||||
@ -151,21 +154,26 @@ synology_dsm_deploy() {
|
|||||||
response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
|
response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
|
||||||
_debug3 response "$response"
|
_debug3 response "$response"
|
||||||
# Get device ID if still empty first, otherwise log in right away
|
# Get device ID if still empty first, otherwise log in right away
|
||||||
|
# If SYNO_Device_Name is set, we treat that account enabled two-factor authorization, consider SYNO_Device_ID is not set, so it won't be able to login without requiring the OTP code.
|
||||||
elif [ -n "${SYNO_Device_Name:-}" ] && [ -z "${SYNO_Device_ID:-}" ]; then
|
elif [ -n "${SYNO_Device_Name:-}" ] && [ -z "${SYNO_Device_ID:-}" ]; then
|
||||||
printf "Enter OTP code for user '%s': " "$SYNO_Username"
|
printf "Enter OTP code for user '%s': " "$SYNO_Username"
|
||||||
read -r otp_code
|
read -r otp_code
|
||||||
response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&otp_code=$otp_code&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_Device_Name")
|
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&otp_code=$otp_code&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_Device_Name")
|
||||||
_debug3 response "$response"
|
_secure_debug3 response "$response"
|
||||||
SYNO_Device_ID=$(echo "$response" | grep "device_id" | sed -n 's/.*"device_id" *: *"\([^"]*\).*/\1/p')
|
|
||||||
|
id_property='device_id'
|
||||||
|
[ "${api_version}" -gt '6' ] || id_property='did'
|
||||||
|
SYNO_Device_ID=$(echo "$response" | grep "$id_property" | sed -n 's/.*"'$id_property'" *: *"\([^"]*\).*/\1/p')
|
||||||
_secure_debug2 SYNO_Device_ID "$SYNO_Device_ID"
|
_secure_debug2 SYNO_Device_ID "$SYNO_Device_ID"
|
||||||
|
# Otherwise, if SYNO_Device_ID is set, we can just use it to login.
|
||||||
else
|
else
|
||||||
if [ -z "${SYNO_Device_Name:-}" ]; then
|
if [ -z "${SYNO_Device_Name:-}" ]; then
|
||||||
printf "Enter device name or leave empty for default (CertRenewal): "
|
printf "Enter device name or leave empty for default (CertRenewal): "
|
||||||
read -r SYNO_Device_Name
|
read -r SYNO_Device_Name
|
||||||
[ -n "${SYNO_Device_Name}" ] || SYNO_Device_Name="CertRenewal"
|
[ -n "${SYNO_Device_Name}" ] || SYNO_Device_Name="CertRenewal"
|
||||||
fi
|
fi
|
||||||
response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_Device_Name&device_id=$SYNO_Device_ID")
|
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_Device_Name&device_id=$SYNO_Device_ID")
|
||||||
_debug3 response "$response"
|
_secure_debug3 response "$response"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
||||||
|
@ -117,7 +117,7 @@ _ali_urlencode() {
|
|||||||
_ali_nonce() {
|
_ali_nonce() {
|
||||||
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
|
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
|
||||||
#Not so good...
|
#Not so good...
|
||||||
date +"%s%N"
|
date +"%s%N" | sed 's/%N//g'
|
||||||
}
|
}
|
||||||
|
|
||||||
_check_exist_query() {
|
_check_exist_query() {
|
||||||
|
180
dnsapi/dns_artfiles.sh
Normal file
180
dnsapi/dns_artfiles.sh
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# ACME.sh 3rd party DNS API plugin for ArtFiles.de
|
||||||
|
################################################################################
|
||||||
|
# Author: Martin Arndt, https://troublezone.net/
|
||||||
|
# Released: 2022-02-27
|
||||||
|
# Issues: https://github.com/acmesh-official/acme.sh/issues/4718
|
||||||
|
################################################################################
|
||||||
|
# Usage:
|
||||||
|
# 1. export AF_API_USERNAME='api12345678'
|
||||||
|
# 2. export AF_API_PASSWORD='apiPassword'
|
||||||
|
# 3. acme.sh --issue -d example.com --dns dns_artfiles
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
########## API configuration ###################################################
|
||||||
|
|
||||||
|
AF_API_SUCCESS='status":"OK'
|
||||||
|
AF_URL_DCP='https://dcp.c.artfiles.de/api/'
|
||||||
|
AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain='
|
||||||
|
AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html'
|
||||||
|
|
||||||
|
########## Public functions ####################################################
|
||||||
|
|
||||||
|
# Adds a new TXT record for given ACME challenge value & domain.
|
||||||
|
# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value"
|
||||||
|
dns_artfiles_add() {
|
||||||
|
domain="$1"
|
||||||
|
txtValue="$2"
|
||||||
|
_info 'Using ArtFiles.de DNS addition API…'
|
||||||
|
_debug 'Domain' "$domain"
|
||||||
|
_debug 'txtValue' "$txtValue"
|
||||||
|
|
||||||
|
_set_credentials
|
||||||
|
_saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME"
|
||||||
|
_saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD"
|
||||||
|
|
||||||
|
_set_headers
|
||||||
|
_get_zone "$domain"
|
||||||
|
_dns 'GET'
|
||||||
|
if ! _contains "$response" 'TXT'; then
|
||||||
|
_err 'Retrieving TXT records failed.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_clean_records
|
||||||
|
_dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")"
|
||||||
|
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||||
|
_err 'Adding ACME challenge value failed.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Removes the existing TXT record for given ACME challenge value & domain.
|
||||||
|
# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value"
|
||||||
|
dns_artfiles_rm() {
|
||||||
|
domain="$1"
|
||||||
|
txtValue="$2"
|
||||||
|
_info 'Using ArtFiles.de DNS removal API…'
|
||||||
|
_debug 'Domain' "$domain"
|
||||||
|
_debug 'txtValue' "$txtValue"
|
||||||
|
|
||||||
|
_set_credentials
|
||||||
|
_set_headers
|
||||||
|
_get_zone "$domain"
|
||||||
|
if ! _dns 'GET'; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$response" "$txtValue"; then
|
||||||
|
_err 'Retrieved TXT records are missing given ACME challenge value.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_clean_records
|
||||||
|
response="$(printf -- '%s' "$response" | sed '/_acme-challenge "'"$txtValue"'"/d')"
|
||||||
|
_dns 'SET' "$response"
|
||||||
|
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||||
|
_err 'Removing ACME challenge value failed.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
########## Private functions ###################################################
|
||||||
|
|
||||||
|
# Cleans awful TXT records response of ArtFiles's API & pretty prints it.
|
||||||
|
# Usage: _clean_records
|
||||||
|
_clean_records() {
|
||||||
|
_info 'Cleaning TXT records…'
|
||||||
|
# Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid
|
||||||
|
# usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\'
|
||||||
|
# from '\"' & turn '\n' into real LF characters.
|
||||||
|
# Yup, awful API to use - but that's all we got to get this working, so… ;)
|
||||||
|
_debug2 'Raw ' "$response"
|
||||||
|
response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')"
|
||||||
|
_debug2 'Clean' "$response"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Executes an HTTP GET or POST request for getting or setting DNS records,
|
||||||
|
# containing given payload upon POST.
|
||||||
|
# Usage: _dns [GET | SET] [payload]
|
||||||
|
_dns() {
|
||||||
|
_info 'Executing HTTP request…'
|
||||||
|
action="$1"
|
||||||
|
payload="$(printf -- '%s' "$2" | _url_encode)"
|
||||||
|
url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')"
|
||||||
|
|
||||||
|
if [ "$action" = 'SET' ]; then
|
||||||
|
_debug2 'Payload' "$payload"
|
||||||
|
response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')"
|
||||||
|
else
|
||||||
|
response="$(_get "$url" '' 10)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||||
|
_err "DNS API error: $response"
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug 'Response' "$response"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gets the root domain zone for given domain.
|
||||||
|
# Usage: _get_zone _acme-challenge.www.example.com
|
||||||
|
_get_zone() {
|
||||||
|
fqdn="$1"
|
||||||
|
domains="$(_get "$AF_URL_DOMAINS" '' 10)"
|
||||||
|
_info 'Getting domain zone…'
|
||||||
|
_debug2 'FQDN' "$fqdn"
|
||||||
|
_debug2 'Domains' "$domains"
|
||||||
|
|
||||||
|
while _contains "$fqdn" "."; do
|
||||||
|
if _contains "$domains" "$fqdn"; then
|
||||||
|
domain="$fqdn"
|
||||||
|
_info "Found root domain zone: $domain"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
fqdn="${fqdn#*.}"
|
||||||
|
_debug2 'FQDN' "$fqdn"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$domain" = "$fqdn" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_err 'Couldn'\''t find root domain zone.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sets the credentials for accessing ArtFiles's API
|
||||||
|
# Usage: _set_credentials
|
||||||
|
_set_credentials() {
|
||||||
|
_info 'Setting credentials…'
|
||||||
|
AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}"
|
||||||
|
AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}"
|
||||||
|
if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then
|
||||||
|
_err 'Missing ArtFiles.de username and/or password.'
|
||||||
|
_err 'Please ensure both are set via export command & try again.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Adds the HTTP Authorization & Content-Type headers to a follow-up request.
|
||||||
|
# Usage: _set_headers
|
||||||
|
_set_headers() {
|
||||||
|
_info 'Setting headers…'
|
||||||
|
encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)"
|
||||||
|
export _H1="Authorization: Basic $encoded"
|
||||||
|
export _H2='Content-Type: application/json'
|
||||||
|
}
|
185
dnsapi/dns_dnsexit.sh
Normal file
185
dnsapi/dns_dnsexit.sh
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#use dns-01 at DNSExit.com
|
||||||
|
|
||||||
|
#Author: Samuel Jimenez
|
||||||
|
#Report Bugs here: https://github.com/acmesh-official/acme.sh
|
||||||
|
|
||||||
|
#DNSEXIT_API_KEY=ABCDEFGHIJ0123456789abcdefghij
|
||||||
|
#DNSEXIT_AUTH_USER=login@email.address
|
||||||
|
#DNSEXIT_AUTH_PASS=aStrongPassword
|
||||||
|
DNSEXIT_API_URL="https://api.dnsexit.com/dns/"
|
||||||
|
DNSEXIT_HOSTS_URL="https://update.dnsexit.com/ipupdate/hosts.jsp"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
#Usage: dns_dnsexit_add _acme-challenge.*.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_dnsexit_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
_info "Using DNSExit.com"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
_debug 'Load account auth'
|
||||||
|
if ! get_account_info; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug 'First detect the root zone'
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"add\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":0,\"overwrite\":false}}"; then
|
||||||
|
_err "$response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 _response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: fulldomain txtvalue
|
||||||
|
#Remove the txt record after validation.
|
||||||
|
dns_dnsexit_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
_info "Using DNSExit.com"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
_debug 'Load account auth'
|
||||||
|
if ! get_account_info; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug 'First detect the root zone'
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "$response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"delete\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\"}}"; then
|
||||||
|
_err "$response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 _response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
#_acme-challenge.www.domain.com
|
||||||
|
#returns
|
||||||
|
# _sub_domain=_acme-challenge.www
|
||||||
|
# _domain=domain.com
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
i=1
|
||||||
|
while true; do
|
||||||
|
_domain=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug h "$_domain"
|
||||||
|
if [ -z "$_domain" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug login "$DNSEXIT_AUTH_USER"
|
||||||
|
_debug password "$DNSEXIT_AUTH_PASS"
|
||||||
|
_debug domain "$_domain"
|
||||||
|
|
||||||
|
_dnsexit_http "login=$DNSEXIT_AUTH_USER&password=$DNSEXIT_AUTH_PASS&domain=$_domain"
|
||||||
|
|
||||||
|
if _contains "$response" "0=$_domain"; then
|
||||||
|
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_debug "Go to next level of $_domain"
|
||||||
|
fi
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_dnsexit_rest() {
|
||||||
|
m=POST
|
||||||
|
ep=""
|
||||||
|
data="$1"
|
||||||
|
_debug _dnsexit_rest "$ep"
|
||||||
|
_debug data "$data"
|
||||||
|
|
||||||
|
api_key_trimmed=$(echo "$DNSEXIT_API_KEY" | tr -d '"')
|
||||||
|
|
||||||
|
export _H1="apikey: $api_key_trimmed"
|
||||||
|
export _H2='Content-Type: application/json'
|
||||||
|
|
||||||
|
if [ "$m" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$DNSEXIT_API_URL/$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$DNSEXIT_API_URL/$ep")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "Error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_dnsexit_http() {
|
||||||
|
m=GET
|
||||||
|
param="$1"
|
||||||
|
_debug param "$param"
|
||||||
|
_debug get "$DNSEXIT_HOSTS_URL?$param"
|
||||||
|
|
||||||
|
response="$(_get "$DNSEXIT_HOSTS_URL?$param")"
|
||||||
|
|
||||||
|
_debug response "$response"
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "Error $param"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
get_account_info() {
|
||||||
|
|
||||||
|
DNSEXIT_API_KEY="${DNSEXIT_API_KEY:-$(_readaccountconf_mutable DNSEXIT_API_KEY)}"
|
||||||
|
if test -z "$DNSEXIT_API_KEY"; then
|
||||||
|
DNSEXIT_API_KEY=''
|
||||||
|
_err 'DNSEXIT_API_KEY was not exported'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable DNSEXIT_API_KEY "$DNSEXIT_API_KEY"
|
||||||
|
|
||||||
|
DNSEXIT_AUTH_USER="${DNSEXIT_AUTH_USER:-$(_readaccountconf_mutable DNSEXIT_AUTH_USER)}"
|
||||||
|
if test -z "$DNSEXIT_AUTH_USER"; then
|
||||||
|
DNSEXIT_AUTH_USER=""
|
||||||
|
_err 'DNSEXIT_AUTH_USER was not exported'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable DNSEXIT_AUTH_USER "$DNSEXIT_AUTH_USER"
|
||||||
|
|
||||||
|
DNSEXIT_AUTH_PASS="${DNSEXIT_AUTH_PASS:-$(_readaccountconf_mutable DNSEXIT_AUTH_PASS)}"
|
||||||
|
if test -z "$DNSEXIT_AUTH_PASS"; then
|
||||||
|
DNSEXIT_AUTH_PASS=""
|
||||||
|
_err 'DNSEXIT_AUTH_PASS was not exported'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable DNSEXIT_AUTH_PASS "$DNSEXIT_AUTH_PASS"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
@ -194,7 +194,7 @@ _inwx_login() {
|
|||||||
|
|
||||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||||
|
|
||||||
INWX_Cookie=$(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 -i "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')")
|
||||||
_H1=$INWX_Cookie
|
_H1=$INWX_Cookie
|
||||||
export _H1
|
export _H1
|
||||||
export INWX_Cookie
|
export INWX_Cookie
|
||||||
|
@ -45,8 +45,8 @@ dns_kappernet_add() {
|
|||||||
if _kappernet_api GET "action=new&subject=$_domain&data=$data"; then
|
if _kappernet_api GET "action=new&subject=$_domain&data=$data"; then
|
||||||
|
|
||||||
if _contains "$response" "{\"OK\":true"; then
|
if _contains "$response" "{\"OK\":true"; then
|
||||||
_info "Waiting 120 seconds for DNS to spread the new record"
|
_info "Waiting 1 second for DNS to spread the new record"
|
||||||
_sleep 120
|
_sleep 1
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
_err "Error creating a TXT DNS Record: $fullhostname TXT $txtvalue"
|
_err "Error creating a TXT DNS Record: $fullhostname TXT $txtvalue"
|
||||||
|
@ -46,6 +46,10 @@ pleskxml_tplt_get_domains="<packet><webspace><get><filter/><dataset><gen_info/><
|
|||||||
# Also used to test credentials and URI.
|
# Also used to test credentials and URI.
|
||||||
# No params.
|
# No params.
|
||||||
|
|
||||||
|
pleskxml_tplt_get_additional_domains="<packet><site><get><filter/><dataset><gen_info/></dataset></get></site></packet>"
|
||||||
|
# Get a list of additional domains that PLESK can manage, so we can check root domain + host for acme.sh
|
||||||
|
# No params.
|
||||||
|
|
||||||
pleskxml_tplt_get_dns_records="<packet><dns><get_rec><filter><site-id>%s</site-id></filter></get_rec></dns></packet>"
|
pleskxml_tplt_get_dns_records="<packet><dns><get_rec><filter><site-id>%s</site-id></filter></get_rec></dns></packet>"
|
||||||
# Get all DNS records for a Plesk domain ID.
|
# Get all DNS records for a Plesk domain ID.
|
||||||
# PARAM = Plesk domain id to query
|
# PARAM = Plesk domain id to query
|
||||||
@ -375,16 +379,44 @@ _pleskxml_get_root_domain() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate a crude list of domains known to this Plesk account.
|
# Generate a crude list of domains known to this Plesk account based on subscriptions.
|
||||||
# We convert <ascii-name> tags to <name> so it'll flag on a hit with either <name> or <ascii-name> fields,
|
# We convert <ascii-name> tags to <name> so it'll flag on a hit with either <name> or <ascii-name> fields,
|
||||||
# for non-Western character sets.
|
# for non-Western character sets.
|
||||||
# Output will be one line per known domain, containing 2 <name> tages and a single <id> tag
|
# Output will be one line per known domain, containing 2 <name> tages and a single <id> tag
|
||||||
# We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned.
|
# We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned.
|
||||||
|
|
||||||
output="$(_api_response_split "$pleskxml_prettyprint_result" 'result' '<status>ok</status>' | sed 's/<ascii-name>/<name>/g;s/<\/ascii-name>/<\/name>/g' | grep '<name>' | grep '<id>')"
|
output="$(_api_response_split "$pleskxml_prettyprint_result" 'result' '<status>ok</status>' | sed 's/<ascii-name>/<name>/g;s/<\/ascii-name>/<\/name>/g' | grep '<name>' | grep '<id>')"
|
||||||
|
debug_output="$(printf "%s" "$output" | sed -n 's:.*<name>\(.*\)</name>.*:\1:p')"
|
||||||
|
|
||||||
_debug 'Domains managed by Plesk server are (ignore the hacked output):'
|
_debug 'Domains managed by Plesk server are:'
|
||||||
_debug "$output"
|
_debug "$debug_output"
|
||||||
|
|
||||||
|
_debug "Querying Plesk server for list of additional managed domains..."
|
||||||
|
|
||||||
|
_call_api "$pleskxml_tplt_get_additional_domains"
|
||||||
|
if [ "$pleskxml_retcode" -ne 0 ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate a crude list of additional domains known to this Plesk account based on sites.
|
||||||
|
# We convert <ascii-name> tags to <name> so it'll flag on a hit with either <name> or <ascii-name> fields,
|
||||||
|
# for non-Western character sets.
|
||||||
|
# Output will be one line per known domain, containing 2 <name> tages and a single <id> tag
|
||||||
|
# We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned.
|
||||||
|
|
||||||
|
output_additional="$(_api_response_split "$pleskxml_prettyprint_result" 'result' '<status>ok</status>' | sed 's/<ascii-name>/<name>/g;s/<\/ascii-name>/<\/name>/g' | grep '<name>' | grep '<id>')"
|
||||||
|
debug_additional="$(printf "%s" "$output_additional" | sed -n 's:.*<name>\(.*\)</name>.*:\1:p')"
|
||||||
|
|
||||||
|
_debug 'Additional domains managed by Plesk server are:'
|
||||||
|
_debug "$debug_additional"
|
||||||
|
|
||||||
|
# Concate the two outputs together.
|
||||||
|
|
||||||
|
output="$(printf "%s" "$output $NEWLINE $output_additional")"
|
||||||
|
debug_output="$(printf "%s" "$output" | sed -n 's:.*<name>\(.*\)</name>.*:\1:p')"
|
||||||
|
|
||||||
|
_debug 'Domains (including additional) managed by Plesk server are:'
|
||||||
|
_debug "$debug_output"
|
||||||
|
|
||||||
# loop and test if domain, or any parent domain, is managed by Plesk
|
# loop and test if domain, or any parent domain, is managed by Plesk
|
||||||
# Loop until we don't have any '.' in the string we're testing as a candidate Plesk-managed domain
|
# Loop until we don't have any '.' in the string we're testing as a candidate Plesk-managed domain
|
||||||
|
Loading…
Reference in New Issue
Block a user