mirror of
https://github.com/plantroon/acme.sh.git
synced 2024-11-09 16:01:46 +00:00
Merge branch 'acmesh-official:master' into master
This commit is contained in:
commit
27bbf0ccaf
13
.github/workflows/DNS.yml
vendored
13
.github/workflows/DNS.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
||||
- name: "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
|
||||
run: |
|
||||
echo "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
|
||||
if [ "${{github.actor}}" != "Neilpang" ]; then
|
||||
if [ "${{github.repository_owner}}" != "acmesh-official" ]; then
|
||||
false
|
||||
fi
|
||||
|
||||
@ -49,6 +49,7 @@ jobs:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
@ -87,6 +88,7 @@ jobs:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
@ -124,6 +126,7 @@ jobs:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
@ -176,6 +179,7 @@ jobs:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
@ -186,7 +190,7 @@ jobs:
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/freebsd-vm@v0.1.4
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ 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 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
prepare: pkg install -y socat curl
|
||||
usesh: true
|
||||
run: |
|
||||
@ -215,6 +219,7 @@ jobs:
|
||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||
TestingDomain: ${{ secrets.TestingDomain }}
|
||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
||||
TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
|
||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||
CASE: le_test_dnsapi
|
||||
TEST_LOCAL: 1
|
||||
@ -223,9 +228,9 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/solaris-vm@v0.0.3
|
||||
- uses: vmactions/solaris-vm@v0.0.5
|
||||
with:
|
||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ 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 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||
prepare: pkgutil -y -i socat
|
||||
run: |
|
||||
pkg set-mediator -v -I default@1.1 openssl
|
||||
|
2
.github/workflows/Linux.yml
vendored
2
.github/workflows/Linux.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
Linux:
|
||||
strategy:
|
||||
matrix:
|
||||
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3-amd64"]
|
||||
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:7", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TEST_LOCAL: 1
|
||||
|
2
.github/workflows/Solaris.yml
vendored
2
.github/workflows/Solaris.yml
vendored
@ -49,7 +49,7 @@ jobs:
|
||||
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
||||
- name: Clone acmetest
|
||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||
- uses: vmactions/solaris-vm@v0.0.3
|
||||
- uses: vmactions/solaris-vm@v0.0.5
|
||||
with:
|
||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
|
||||
nat: |
|
||||
|
29
.github/workflows/Ubuntu.yml
vendored
29
.github/workflows/Ubuntu.yml
vendored
@ -30,6 +30,20 @@ jobs:
|
||||
CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||
CA_EMAIL: "githubtest@acme.sh"
|
||||
TEST_PREFERRED_CHAIN: ""
|
||||
- TEST_ACME_Server: "https://localhost:9000/acme/acme/directory"
|
||||
CA_ECDSA: "Smallstep Intermediate CA"
|
||||
CA: "Smallstep Intermediate CA"
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: ""
|
||||
NO_REVOKE: 1
|
||||
- TEST_ACME_Server: "https://localhost:9000/acme/acme/directory"
|
||||
CA_ECDSA: "Smallstep Intermediate CA"
|
||||
CA: "Smallstep Intermediate CA"
|
||||
CA_EMAIL: ""
|
||||
TEST_PREFERRED_CHAIN: ""
|
||||
NO_REVOKE: 1
|
||||
TEST_IPCERT: 1
|
||||
TestingDomain: "172.17.0.1"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
@ -40,10 +54,25 @@ jobs:
|
||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||
NO_ECC_384: ${{ matrix.NO_ECC_384 }}
|
||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||
NO_REVOKE: ${{ matrix.NO_REVOKE }}
|
||||
TEST_IPCERT: ${{ matrix.TEST_IPCERT }}
|
||||
TestingDomain: ${{ matrix.TestingDomain }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install tools
|
||||
run: sudo apt-get install -y socat
|
||||
- name: Start StepCA
|
||||
if: ${{ matrix.TEST_ACME_Server=='https://localhost:9000/acme/acme/directory' }}
|
||||
run: |
|
||||
docker run --rm -d \
|
||||
-p 9000:9000 \
|
||||
-e "DOCKER_STEPCA_INIT_NAME=Smallstep" \
|
||||
-e "DOCKER_STEPCA_INIT_DNS_NAMES=localhost,$(hostname -f)" \
|
||||
--name stepca \
|
||||
smallstep/step-ca \
|
||||
&& sleep 5 && docker exec stepca step ca provisioner add acme --type ACME \
|
||||
&& docker exec stepca kill -1 1 \
|
||||
&& docker exec stepca cat /home/step/certs/root_ca.crt | sudo bash -c "cat - >>/etc/ssl/certs/ca-certificates.crt"
|
||||
- name: Clone acmetest
|
||||
run: |
|
||||
cd .. \
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM alpine:3.12
|
||||
FROM alpine:3.15
|
||||
|
||||
RUN apk --no-cache add -f \
|
||||
openssl \
|
||||
@ -11,7 +11,8 @@ RUN apk --no-cache add -f \
|
||||
tzdata \
|
||||
oath-toolkit-oathtool \
|
||||
tar \
|
||||
libidn
|
||||
libidn \
|
||||
jq
|
||||
|
||||
ENV LE_CONFIG_HOME /acme.sh
|
||||
|
||||
@ -40,6 +41,7 @@ RUN for verb in help \
|
||||
revoke \
|
||||
remove \
|
||||
list \
|
||||
info \
|
||||
showcsr \
|
||||
install-cronjob \
|
||||
uninstall-cronjob \
|
||||
|
180
acme.sh
180
acme.sh
@ -29,7 +29,7 @@ CA_BUYPASS="https://api.buypass.com/acme/directory"
|
||||
CA_BUYPASS_TEST="https://api.test4.buypass.no/acme/directory"
|
||||
|
||||
CA_ZEROSSL="https://acme.zerossl.com/v2/DV90"
|
||||
_ZERO_EAB_ENDPOINT="http://api.zerossl.com/acme/eab-credentials-email"
|
||||
_ZERO_EAB_ENDPOINT="https://api.zerossl.com/acme/eab-credentials-email"
|
||||
|
||||
CA_SSLCOM_RSA="https://acme.ssl.com/sslcom-dv-rsa"
|
||||
CA_SSLCOM_ECC="https://acme.ssl.com/sslcom-dv-ecc"
|
||||
@ -80,8 +80,8 @@ NGINX="nginx:"
|
||||
NGINX_START="#ACME_NGINX_START"
|
||||
NGINX_END="#ACME_NGINX_END"
|
||||
|
||||
BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----"
|
||||
END_CSR="-----END CERTIFICATE REQUEST-----"
|
||||
BEGIN_CSR="-----BEGIN [NEW ]\{0,4\}CERTIFICATE REQUEST-----"
|
||||
END_CSR="-----END [NEW ]\{0,4\}CERTIFICATE REQUEST-----"
|
||||
|
||||
BEGIN_CERT="-----BEGIN CERTIFICATE-----"
|
||||
END_CERT="-----END CERTIFICATE-----"
|
||||
@ -144,6 +144,8 @@ NOTIFY_MODE_CERT=1
|
||||
|
||||
NOTIFY_MODE_DEFAULT=$NOTIFY_MODE_BULK
|
||||
|
||||
_BASE64_ENCODED_CFGS="Le_PreHook Le_PostHook Le_RenewHook Le_Preferred_Chain Le_ReloadCmd"
|
||||
|
||||
_DEBUG_WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh"
|
||||
|
||||
_PREPARE_LINK="https://github.com/acmesh-official/acme.sh/wiki/Install-preparations"
|
||||
@ -1051,9 +1053,9 @@ _sign() {
|
||||
|
||||
_sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile "
|
||||
|
||||
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || grep "BEGIN PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
|
||||
if _isRSA "$keyfile" >/dev/null 2>&1; then
|
||||
$_sign_openssl -$alg | _base64
|
||||
elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
|
||||
elif _isEcc "$keyfile" >/dev/null 2>&1; then
|
||||
if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then
|
||||
_err "Sign failed: $_sign_openssl"
|
||||
_err "Key file: $keyfile"
|
||||
@ -1250,8 +1252,9 @@ _createcsr() {
|
||||
else
|
||||
domainlist="$(_idn "$domainlist")"
|
||||
_debug2 domainlist "$domainlist"
|
||||
alt="$(_getIdType "$domain" | _upper_case):$domain"
|
||||
for dl in $(echo "$domainlist" | tr "," ' '); do
|
||||
alt="$(_getIdType "$domain" | _upper_case):$(_idn "$domain")"
|
||||
for dl in $(echo "'$domainlist'" | sed "s/,/' '/g"); do
|
||||
dl=$(echo "$dl" | tr -d "'")
|
||||
alt="$alt,$(_getIdType "$dl" | _upper_case):$dl"
|
||||
done
|
||||
#multi
|
||||
@ -1270,10 +1273,18 @@ _createcsr() {
|
||||
_csr_cn="$(_idn "$domain")"
|
||||
_debug2 _csr_cn "$_csr_cn"
|
||||
if _contains "$(uname -a)" "MINGW"; then
|
||||
if _isIP "$_csr_cn"; then
|
||||
${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//O=$PROJECT_NAME" -config "$csrconf" -out "$csr"
|
||||
else
|
||||
${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr"
|
||||
fi
|
||||
else
|
||||
if _isIP "$_csr_cn"; then
|
||||
${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/O=$PROJECT_NAME" -config "$csrconf" -out "$csr"
|
||||
else
|
||||
${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#_signcsr key csr conf cert
|
||||
@ -1621,6 +1632,24 @@ _stat() {
|
||||
return 1 #error, 'stat' not found
|
||||
}
|
||||
|
||||
#keyfile
|
||||
_isRSA() {
|
||||
keyfile=$1
|
||||
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || ${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#keyfile
|
||||
_isEcc() {
|
||||
keyfile=$1
|
||||
if grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || ${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#keyfile
|
||||
_calcjwk() {
|
||||
keyfile="$1"
|
||||
@ -1634,7 +1663,7 @@ _calcjwk() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
|
||||
if _isRSA "$keyfile"; then
|
||||
_debug "RSA key"
|
||||
pub_exp=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
|
||||
if [ "${#pub_exp}" = "5" ]; then
|
||||
@ -1656,7 +1685,7 @@ _calcjwk() {
|
||||
JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}'
|
||||
JWK_HEADERPLACE_PART1='{"nonce": "'
|
||||
JWK_HEADERPLACE_PART2='", "alg": "RS256"'
|
||||
elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
|
||||
elif _isEcc "$keyfile"; then
|
||||
_debug "EC key"
|
||||
crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
|
||||
_debug3 crv "$crv"
|
||||
@ -1829,8 +1858,6 @@ _inithttp() {
|
||||
|
||||
}
|
||||
|
||||
_HTTP_MAX_RETRY=8
|
||||
|
||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
||||
_post() {
|
||||
body="$1"
|
||||
@ -1838,33 +1865,6 @@ _post() {
|
||||
needbase64="$3"
|
||||
httpmethod="$4"
|
||||
_postContentType="$5"
|
||||
_sleep_retry_sec=1
|
||||
_http_retry_times=0
|
||||
_hcode=0
|
||||
while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do
|
||||
[ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ]
|
||||
_lastHCode="$?"
|
||||
_debug "Retrying post"
|
||||
_post_impl "$body" "$_post_url" "$needbase64" "$httpmethod" "$_postContentType" "$_lastHCode"
|
||||
_hcode="$?"
|
||||
_debug _hcode "$_hcode"
|
||||
if [ "$_hcode" = "0" ]; then
|
||||
break
|
||||
fi
|
||||
_http_retry_times=$(_math $_http_retry_times + 1)
|
||||
_sleep $_sleep_retry_sec
|
||||
done
|
||||
return $_hcode
|
||||
}
|
||||
|
||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType] [displayError]
|
||||
_post_impl() {
|
||||
body="$1"
|
||||
_post_url="$2"
|
||||
needbase64="$3"
|
||||
httpmethod="$4"
|
||||
_postContentType="$5"
|
||||
displayError="$6"
|
||||
|
||||
if [ -z "$httpmethod" ]; then
|
||||
httpmethod="POST"
|
||||
@ -1916,9 +1916,7 @@ _post_impl() {
|
||||
fi
|
||||
_ret="$?"
|
||||
if [ "$_ret" != "0" ]; then
|
||||
if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
|
||||
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
|
||||
fi
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
||||
_err "Here is the curl dump log:"
|
||||
_err "$(cat "$_CURL_DUMP")"
|
||||
@ -1974,10 +1972,8 @@ _post_impl() {
|
||||
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
|
||||
fi
|
||||
if [ "$_ret" != "0" ]; then
|
||||
if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
|
||||
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
|
||||
fi
|
||||
fi
|
||||
_sed_i "s/^ *//g" "$HTTP_HEADER"
|
||||
else
|
||||
_ret="$?"
|
||||
@ -1990,38 +1986,13 @@ _post_impl() {
|
||||
|
||||
# url getheader timeout
|
||||
_get() {
|
||||
url="$1"
|
||||
onlyheader="$2"
|
||||
t="$3"
|
||||
_sleep_retry_sec=1
|
||||
_http_retry_times=0
|
||||
_hcode=0
|
||||
while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do
|
||||
[ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ]
|
||||
_lastHCode="$?"
|
||||
_debug "Retrying GET"
|
||||
_get_impl "$url" "$onlyheader" "$t" "$_lastHCode"
|
||||
_hcode="$?"
|
||||
_debug _hcode "$_hcode"
|
||||
if [ "$_hcode" = "0" ]; then
|
||||
break
|
||||
fi
|
||||
_http_retry_times=$(_math $_http_retry_times + 1)
|
||||
_sleep $_sleep_retry_sec
|
||||
done
|
||||
return $_hcode
|
||||
}
|
||||
|
||||
# url getheader timeout displayError
|
||||
_get_impl() {
|
||||
_debug GET
|
||||
url="$1"
|
||||
onlyheader="$2"
|
||||
t="$3"
|
||||
displayError="$4"
|
||||
_debug url "$url"
|
||||
_debug "timeout=$t"
|
||||
_debug "displayError" "$displayError"
|
||||
|
||||
_inithttp
|
||||
|
||||
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
|
||||
@ -2040,9 +2011,7 @@ _get_impl() {
|
||||
fi
|
||||
ret=$?
|
||||
if [ "$ret" != "0" ]; then
|
||||
if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
|
||||
_err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
|
||||
fi
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
||||
_err "Here is the curl dump log:"
|
||||
_err "$(cat "$_CURL_DUMP")"
|
||||
@ -2068,10 +2037,8 @@ _get_impl() {
|
||||
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
|
||||
fi
|
||||
if [ "$ret" != "0" ]; then
|
||||
if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
|
||||
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
ret=$?
|
||||
_err "Neither curl nor wget is found, can not do GET."
|
||||
@ -4196,7 +4163,12 @@ _match_issuer() {
|
||||
#ip
|
||||
_isIPv4() {
|
||||
for seg in $(echo "$1" | tr '.' ' '); do
|
||||
if [ $seg -ge 0 ] 2>/dev/null && [ $seg -le 255 ] 2>/dev/null; then
|
||||
_debug2 seg "$seg"
|
||||
if [ "$(echo "$seg" | tr -d [0-9])" ]; then
|
||||
#not all number
|
||||
return 1
|
||||
fi
|
||||
if [ $seg -ge 0 ] && [ $seg -lt 256 ]; then
|
||||
continue
|
||||
fi
|
||||
return 1
|
||||
@ -5149,7 +5121,7 @@ renew() {
|
||||
_isEcc="$2"
|
||||
|
||||
_initpath "$Le_Domain" "$_isEcc"
|
||||
|
||||
_set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT}
|
||||
_info "$(__green "Renew: '$Le_Domain'")"
|
||||
if [ ! -f "$DOMAIN_CONF" ]; then
|
||||
_info "'$Le_Domain' is not an issued domain, skip."
|
||||
@ -5184,6 +5156,11 @@ renew() {
|
||||
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
|
||||
_info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")"
|
||||
_info "Add '$(__red '--force')' to force to renew."
|
||||
if [ -z "$_ACME_IN_RENEWALL" ]; then
|
||||
if [ $_set_level -ge $NOTIFY_LEVEL_SKIP ]; then
|
||||
_send_notify "Renew $Le_Domain skipped" "Good, the cert is skipped." "$NOTIFY_HOOK" "$RENEW_SKIP"
|
||||
fi
|
||||
fi
|
||||
return "$RENEW_SKIP"
|
||||
fi
|
||||
|
||||
@ -5210,6 +5187,17 @@ renew() {
|
||||
fi
|
||||
|
||||
_ACME_IS_RENEW=""
|
||||
if [ -z "$_ACME_IN_RENEWALL" ]; then
|
||||
if [ "$res" = "0" ]; then
|
||||
if [ $_set_level -ge $NOTIFY_LEVEL_RENEW ]; then
|
||||
_send_notify "Renew $d success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0
|
||||
fi
|
||||
else
|
||||
if [ $_set_level -ge $NOTIFY_LEVEL_ERROR ]; then
|
||||
_send_notify "Renew $d error" "There is an error." "$NOTIFY_HOOK" 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
return "$res"
|
||||
}
|
||||
@ -5227,6 +5215,7 @@ renewAll() {
|
||||
_notify_code=$RENEW_SKIP
|
||||
_set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT}
|
||||
_debug "_set_level" "$_set_level"
|
||||
export _ACME_IN_RENEWALL=1
|
||||
for di in "${CERT_HOME}"/*.*/; do
|
||||
_debug di "$di"
|
||||
if ! [ -d "$di" ]; then
|
||||
@ -5249,13 +5238,13 @@ renewAll() {
|
||||
_error_level="$NOTIFY_LEVEL_RENEW"
|
||||
_notify_code=0
|
||||
fi
|
||||
if [ "$_ACME_IN_CRON" ]; then
|
||||
|
||||
if [ $_set_level -ge $NOTIFY_LEVEL_RENEW ]; then
|
||||
if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
|
||||
_send_notify "Renew $d success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
_success_msg="${_success_msg} $d
|
||||
"
|
||||
elif [ "$rc" = "$RENEW_SKIP" ]; then
|
||||
@ -5263,13 +5252,13 @@ renewAll() {
|
||||
_error_level="$NOTIFY_LEVEL_SKIP"
|
||||
_notify_code=$RENEW_SKIP
|
||||
fi
|
||||
if [ "$_ACME_IN_CRON" ]; then
|
||||
|
||||
if [ $_set_level -ge $NOTIFY_LEVEL_SKIP ]; then
|
||||
if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
|
||||
_send_notify "Renew $d skipped" "Good, the cert is skipped." "$NOTIFY_HOOK" "$RENEW_SKIP"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
_info "Skipped $d"
|
||||
_skipped_msg="${_skipped_msg} $d
|
||||
"
|
||||
@ -5278,13 +5267,13 @@ renewAll() {
|
||||
_error_level="$NOTIFY_LEVEL_ERROR"
|
||||
_notify_code=1
|
||||
fi
|
||||
if [ "$_ACME_IN_CRON" ]; then
|
||||
|
||||
if [ $_set_level -ge $NOTIFY_LEVEL_ERROR ]; then
|
||||
if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
|
||||
_send_notify "Renew $d error" "There is an error." "$NOTIFY_HOOK" 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
_error_msg="${_error_msg} $d
|
||||
"
|
||||
if [ "$_stopRenewOnError" ]; then
|
||||
@ -5299,7 +5288,7 @@ renewAll() {
|
||||
done
|
||||
_debug _error_level "$_error_level"
|
||||
_debug _set_level "$_set_level"
|
||||
if [ "$_ACME_IN_CRON" ] && [ $_error_level -le $_set_level ]; then
|
||||
if [ $_error_level -le $_set_level ]; then
|
||||
if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then
|
||||
_msg_subject="Renew"
|
||||
if [ "$_error_msg" ]; then
|
||||
@ -6587,6 +6576,7 @@ Commands:
|
||||
--revoke Revoke a cert.
|
||||
--remove Remove the cert from list of certs known to $PROJECT_NAME.
|
||||
--list List all the certs.
|
||||
--info Show the $PROJECT_NAME configs, or the configs for a domain with [-d domain] parameter.
|
||||
--to-pkcs12 Export the certificate and key to a pfx file.
|
||||
--to-pkcs8 Convert to pkcs8 format.
|
||||
--sign-csr Issue a cert from an existing csr.
|
||||
@ -6904,6 +6894,28 @@ setdefaultchain() {
|
||||
_savecaconf "DEFAULT_PREFERRED_CHAIN" "$_preferred_chain"
|
||||
}
|
||||
|
||||
#domain ecc
|
||||
info() {
|
||||
_domain="$1"
|
||||
_ecc="$2"
|
||||
_initpath
|
||||
if [ -z "$_domain" ]; then
|
||||
_debug "Show global configs"
|
||||
echo "LE_WORKING_DIR=$LE_WORKING_DIR"
|
||||
echo "LE_CONFIG_HOME=$LE_CONFIG_HOME"
|
||||
cat "$ACCOUNT_CONF_PATH"
|
||||
else
|
||||
_debug "Show domain configs"
|
||||
(
|
||||
_initpath "$_domain" "$_ecc"
|
||||
echo "DOMAIN_CONF=$DOMAIN_CONF"
|
||||
for seg in $(cat $DOMAIN_CONF | cut -d = -f 1); do
|
||||
echo "$seg=$(_readdomainconf "$seg")"
|
||||
done
|
||||
)
|
||||
fi
|
||||
}
|
||||
|
||||
_process() {
|
||||
_CMD=""
|
||||
_domain=""
|
||||
@ -7013,6 +7025,9 @@ _process() {
|
||||
--list)
|
||||
_CMD="list"
|
||||
;;
|
||||
--info)
|
||||
_CMD="info"
|
||||
;;
|
||||
--install-cronjob | --installcronjob)
|
||||
_CMD="installcronjob"
|
||||
;;
|
||||
@ -7564,6 +7579,9 @@ _process() {
|
||||
list)
|
||||
list "$_listraw" "$_domain"
|
||||
;;
|
||||
info)
|
||||
info "$_domain" "$_ecc"
|
||||
;;
|
||||
installcronjob) installcronjob "$_confighome" ;;
|
||||
uninstallcronjob) uninstallcronjob ;;
|
||||
cron) cron ;;
|
||||
|
@ -36,43 +36,51 @@ fritzbox_deploy() {
|
||||
fi
|
||||
fi
|
||||
|
||||
_fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}"
|
||||
_fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}"
|
||||
_fritzbox_url="${DEPLOY_FRITZBOX_URL}"
|
||||
# Clear traces of incorrectly stored values
|
||||
_clearaccountconf DEPLOY_FRITZBOX_USERNAME
|
||||
_clearaccountconf DEPLOY_FRITZBOX_PASSWORD
|
||||
_clearaccountconf DEPLOY_FRITZBOX_URL
|
||||
|
||||
_debug _fritzbox_url "$_fritzbox_url"
|
||||
_debug _fritzbox_username "$_fritzbox_username"
|
||||
_secure_debug _fritzbox_password "$_fritzbox_password"
|
||||
if [ -z "$_fritzbox_username" ]; then
|
||||
# Read config from saved values or env
|
||||
_getdeployconf DEPLOY_FRITZBOX_USERNAME
|
||||
_getdeployconf DEPLOY_FRITZBOX_PASSWORD
|
||||
_getdeployconf DEPLOY_FRITZBOX_URL
|
||||
|
||||
_debug DEPLOY_FRITZBOX_URL "$DEPLOY_FRITZBOX_URL"
|
||||
_debug DEPLOY_FRITZBOX_USERNAME "$DEPLOY_FRITZBOX_USERNAME"
|
||||
_secure_debug DEPLOY_FRITZBOX_PASSWORD "$DEPLOY_FRITZBOX_PASSWORD"
|
||||
|
||||
if [ -z "$DEPLOY_FRITZBOX_USERNAME" ]; then
|
||||
_err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME."
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$_fritzbox_password" ]; then
|
||||
if [ -z "$DEPLOY_FRITZBOX_PASSWORD" ]; then
|
||||
_err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD."
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$_fritzbox_url" ]; then
|
||||
if [ -z "$DEPLOY_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}"
|
||||
# Save current values
|
||||
_savedeployconf DEPLOY_FRITZBOX_USERNAME "$DEPLOY_FRITZBOX_USERNAME"
|
||||
_savedeployconf DEPLOY_FRITZBOX_PASSWORD "$DEPLOY_FRITZBOX_PASSWORD"
|
||||
_savedeployconf DEPLOY_FRITZBOX_URL "$DEPLOY_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_challenge="$(_get "${DEPLOY_FRITZBOX_URL}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
|
||||
if _exists iconv; then
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | iconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
||||
elif _exists uconv; then
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | uconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | uconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
||||
else
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | _digest md5 hex)"
|
||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | _digest md5 hex)"
|
||||
fi
|
||||
_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>.*$//')"
|
||||
_fritzbox_sid="$(_get "${DEPLOY_FRITZBOX_URL}/login_sid.lua?sid=0000000000000000&username=${DEPLOY_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."
|
||||
@ -104,7 +112,7 @@ fritzbox_deploy() {
|
||||
_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
|
||||
_post "$(cat "${_post_request}")" "${DEPLOY_FRITZBOX_URL}/cgi-bin/firmwarecfg" | grep SSL
|
||||
|
||||
retval=$?
|
||||
if [ $retval = 0 ]; then
|
||||
|
156
deploy/openmediavault.sh
Normal file
156
deploy/openmediavault.sh
Normal file
@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# This deploy hook is tested on OpenMediaVault 5.x. It supports both local and remote deployment.
|
||||
# The way it works is that if a cert with the matching domain name is not found, it will firstly create a dummy cert to get its uuid, and then replace it with your cert.
|
||||
#
|
||||
# DEPLOY_OMV_WEBUI_ADMIN - This is OMV web gui admin account. Default value is admin. It's required as the user parameter (-u) for the omv-rpc command.
|
||||
# DEPLOY_OMV_HOST and DEPLOY_OMV_SSH_USER are optional. They are used for remote deployment through ssh (support public key authentication only). Per design, OMV web gui admin doesn't have ssh permission, so another account is needed for ssh.
|
||||
#
|
||||
# returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
openmediavault_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"
|
||||
|
||||
_getdeployconf DEPLOY_OMV_WEBUI_ADMIN
|
||||
|
||||
if [ -z "$DEPLOY_OMV_WEBUI_ADMIN" ]; then
|
||||
DEPLOY_OMV_WEBUI_ADMIN="admin"
|
||||
fi
|
||||
|
||||
_savedeployconf DEPLOY_OMV_WEBUI_ADMIN "$DEPLOY_OMV_WEBUI_ADMIN"
|
||||
|
||||
_getdeployconf DEPLOY_OMV_HOST
|
||||
_getdeployconf DEPLOY_OMV_SSH_USER
|
||||
|
||||
if [ -n "$DEPLOY_OMV_HOST" ] && [ -n "$DEPLOY_OMV_SSH_USER" ]; then
|
||||
_info "[OMV deploy-hook] Deploy certificate remotely through ssh."
|
||||
_savedeployconf DEPLOY_OMV_HOST "$DEPLOY_OMV_HOST"
|
||||
_savedeployconf DEPLOY_OMV_SSH_USER "$DEPLOY_OMV_SSH_USER"
|
||||
else
|
||||
_info "[OMV deploy-hook] Deploy certificate locally."
|
||||
fi
|
||||
|
||||
if [ -n "$DEPLOY_OMV_HOST" ] && [ -n "$DEPLOY_OMV_SSH_USER" ]; then
|
||||
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'getList' '{\"start\": 0, \"limit\": -1}' | jq -r '.data[] | select(.name==\"/CN='$_cdomain'\") | .uuid'"
|
||||
# shellcheck disable=SC2029
|
||||
_uuid=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
_debug _command "$_command"
|
||||
|
||||
if [ -z "$_uuid" ]; then
|
||||
_info "[OMV deploy-hook] Domain $_cdomain has no certificate in openmediavault, creating it!"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'create' '{\"cn\": \"test.example.com\", \"size\": 4096, \"days\": 3650, \"c\": \"\", \"st\": \"\", \"l\": \"\", \"o\": \"\", \"ou\": \"\", \"email\": \"\"}' | jq -r '.uuid'"
|
||||
# shellcheck disable=SC2029
|
||||
_uuid=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
_debug _command "$_command"
|
||||
|
||||
if [ -z "$_uuid" ]; then
|
||||
_err "[OMV deploy-hook] An error occured while creating the certificate"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_info "[OMV deploy-hook] Domain $_cdomain has uuid: $_uuid"
|
||||
_fullchain=$(jq <"$_cfullchain" -aRs .)
|
||||
_key=$(jq <"$_ckey" -aRs .)
|
||||
|
||||
_debug _fullchain "$_fullchain"
|
||||
_debug _key "$_key"
|
||||
|
||||
_info "[OMV deploy-hook] Updating key and certificate in openmediavault"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'set' '{\"uuid\":\"$_uuid\", \"certificate\":$_fullchain, \"privatekey\":$_key, \"comment\":\"acme.sh deployed $(date)\"}'"
|
||||
# shellcheck disable=SC2029
|
||||
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'setSettings' \$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'getSettings' | jq -c '.sslcertificateref=\"$_uuid\"')"
|
||||
# shellcheck disable=SC2029
|
||||
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_info "[OMV deploy-hook] Asking openmediavault to apply changes... (this could take some time, hang in there)"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'Config' 'applyChanges' '{\"modules\":[], \"force\": false}'"
|
||||
# shellcheck disable=SC2029
|
||||
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_info "[OMV deploy-hook] Asking nginx to reload"
|
||||
_command="nginx -s reload"
|
||||
# shellcheck disable=SC2029
|
||||
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
else
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
_uuid=$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'getList' '{"start": 0, "limit": -1}' | jq -r '.data[] | select(.name=="/CN='$_cdomain'") | .uuid')
|
||||
if [ -z "$_uuid" ]; then
|
||||
_info "[OMV deploy-hook] Domain $_cdomain has no certificate in openmediavault, creating it!"
|
||||
# shellcheck disable=SC2086
|
||||
_uuid=$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'create' '{"cn": "test.example.com", "size": 4096, "days": 3650, "c": "", "st": "", "l": "", "o": "", "ou": "", "email": ""}' | jq -r '.uuid')
|
||||
|
||||
if [ -z "$_uuid" ]; then
|
||||
_err "[OMB deploy-hook] An error occured while creating the certificate"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_info "[OMV deploy-hook] Domain $_cdomain has uuid: $_uuid"
|
||||
_fullchain=$(jq <"$_cfullchain" -aRs .)
|
||||
_key=$(jq <"$_ckey" -aRs .)
|
||||
|
||||
_debug _fullchain "$_fullchain"
|
||||
_debug _key "$_key"
|
||||
|
||||
_info "[OMV deploy-hook] Updating key and certificate in openmediavault"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'set' '{\"uuid\":\"$_uuid\", \"certificate\":$_fullchain, \"privatekey\":$_key, \"comment\":\"acme.sh deployed $(date)\"}'"
|
||||
_result=$(eval "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'setSettings' \$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'getSettings' | jq -c '.sslcertificateref=\"$_uuid\"')"
|
||||
_result=$(eval "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_info "[OMV deploy-hook] Asking openmediavault to apply changes... (this could take some time, hang in there)"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'Config' 'applyChanges' '{\"modules\":[], \"force\": false}'"
|
||||
_result=$(eval "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_info "[OMV deploy-hook] Asking nginx to reload"
|
||||
_command="nginx -s reload"
|
||||
_result=$(eval "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
@ -66,21 +66,31 @@ routeros_deploy() {
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
_getdeployconf ROUTER_OS_HOST
|
||||
|
||||
if [ -z "$ROUTER_OS_HOST" ]; then
|
||||
_debug "Using _cdomain as ROUTER_OS_HOST, please set if not correct."
|
||||
ROUTER_OS_HOST="$_cdomain"
|
||||
fi
|
||||
|
||||
_getdeployconf ROUTER_OS_USERNAME
|
||||
|
||||
if [ -z "$ROUTER_OS_USERNAME" ]; then
|
||||
_err "Need to set the env variable ROUTER_OS_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_getdeployconf ROUTER_OS_ADDITIONAL_SERVICES
|
||||
|
||||
if [ -z "$ROUTER_OS_ADDITIONAL_SERVICES" ]; then
|
||||
_debug "Not enabling additional services"
|
||||
ROUTER_OS_ADDITIONAL_SERVICES=""
|
||||
fi
|
||||
|
||||
_savedeployconf ROUTER_OS_HOST "$ROUTER_OS_HOST"
|
||||
_savedeployconf ROUTER_OS_USERNAME "$ROUTER_OS_USERNAME"
|
||||
_savedeployconf ROUTER_OS_ADDITIONAL_SERVICES "$ROUTER_OS_ADDITIONAL_SERVICES"
|
||||
|
||||
_info "Trying to push key '$_ckey' to router"
|
||||
scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"
|
||||
_info "Trying to push cert '$_cfullchain' to router"
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
# Here is a script to deploy cert to Synology DSM
|
||||
#
|
||||
# it requires the jq and curl are in the $PATH and the following
|
||||
# environment variables must be set:
|
||||
# It requires following environment variables:
|
||||
#
|
||||
# SYNO_Username - Synology Username to login (must be an administrator)
|
||||
# SYNO_Password - Synology Password to login
|
||||
@ -16,6 +15,12 @@
|
||||
# SYNO_Hostname - defaults to localhost
|
||||
# SYNO_Port - defaults to 5000
|
||||
# SYNO_DID - device ID to skip OTP - defaults to empty
|
||||
# SYNO_TOTP_SECRET - TOTP secret to generate OTP - defaults to empty
|
||||
#
|
||||
# Dependencies:
|
||||
# -------------
|
||||
# - jq and curl
|
||||
# - oathtool (When using 2 Factor Authentication and SYNO_TOTP_SECRET is set)
|
||||
#
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
@ -36,6 +41,7 @@ synology_dsm_deploy() {
|
||||
_getdeployconf SYNO_Password
|
||||
_getdeployconf SYNO_Create
|
||||
_getdeployconf SYNO_DID
|
||||
_getdeployconf SYNO_TOTP_SECRET
|
||||
if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then
|
||||
_err "SYNO_Username & SYNO_Password must be set"
|
||||
return 1
|
||||
@ -86,13 +92,18 @@ synology_dsm_deploy() {
|
||||
encoded_username="$(printf "%s" "$SYNO_Username" | _url_encode)"
|
||||
encoded_password="$(printf "%s" "$SYNO_Password" | _url_encode)"
|
||||
|
||||
otp_code=""
|
||||
if [ -n "$SYNO_TOTP_SECRET" ]; then
|
||||
otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
if [ -n "$SYNO_DID" ]; then
|
||||
_H1="Cookie: did=$SYNO_DID"
|
||||
export _H1
|
||||
_debug3 H1 "${_H1}"
|
||||
fi
|
||||
|
||||
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
|
||||
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$otp_code" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
|
||||
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
||||
_debug3 response "$response"
|
||||
_debug token "$token"
|
||||
@ -100,7 +111,7 @@ synology_dsm_deploy() {
|
||||
if [ -z "$token" ]; then
|
||||
_err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
|
||||
_err "Check your username and password."
|
||||
_err "If two-factor authentication is enabled for the user, you have to choose another user."
|
||||
_err "If two-factor authentication is enabled for the user, set SYNO_TOTP_SECRET."
|
||||
return 1
|
||||
fi
|
||||
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
||||
@ -113,6 +124,7 @@ synology_dsm_deploy() {
|
||||
_savedeployconf SYNO_Username "$SYNO_Username"
|
||||
_savedeployconf SYNO_Password "$SYNO_Password"
|
||||
_savedeployconf SYNO_DID "$SYNO_DID"
|
||||
_savedeployconf SYNO_TOTP_SECRET "$SYNO_TOTP_SECRET"
|
||||
|
||||
_info "Getting certificates in Synology DSM"
|
||||
response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid=$sid" "$_base_url/webapi/entry.cgi")
|
||||
|
180
deploy/truenas.sh
Normal file
180
deploy/truenas.sh
Normal file
@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Here is a scipt to deploy the cert to your TrueNAS using the REST API.
|
||||
# https://www.truenas.com/docs/hub/additional-topics/api/rest_api.html
|
||||
#
|
||||
# Written by Frank Plass github@f-plass.de
|
||||
# https://github.com/danb35/deploy-freenas/blob/master/deploy_freenas.py
|
||||
# Thanks to danb35 for your template!
|
||||
#
|
||||
# Following environment variables must be set:
|
||||
#
|
||||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
|
||||
#
|
||||
# The following environmental variables may be set if you don't like their
|
||||
# default values:
|
||||
#
|
||||
# DEPLOY_TRUENAS_HOSTNAME - defaults to localhost
|
||||
# DEPLOY_TRUENAS_SCHEME - defaults to http, set alternatively to https
|
||||
#
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
truenas_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"
|
||||
|
||||
_getdeployconf DEPLOY_TRUENAS_APIKEY
|
||||
|
||||
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then
|
||||
_err "TrueNAS Api Key is not found, please define DEPLOY_TRUENAS_APIKEY."
|
||||
return 1
|
||||
fi
|
||||
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
|
||||
|
||||
# Optional hostname, scheme for TrueNAS
|
||||
_getdeployconf DEPLOY_TRUENAS_HOSTNAME
|
||||
_getdeployconf DEPLOY_TRUENAS_SCHEME
|
||||
|
||||
# default values for hostname and scheme
|
||||
[ -n "${DEPLOY_TRUENAS_HOSTNAME}" ] || DEPLOY_TRUENAS_HOSTNAME="localhost"
|
||||
[ -n "${DEPLOY_TRUENAS_SCHEME}" ] || DEPLOY_TRUENAS_SCHEME="http"
|
||||
|
||||
_debug2 DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
|
||||
_debug2 DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
||||
|
||||
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
|
||||
_debug _api_url "$_api_url"
|
||||
|
||||
_H1="Authorization: Bearer $DEPLOY_TRUENAS_APIKEY"
|
||||
_secure_debug3 _H1 "$_H1"
|
||||
|
||||
_info "Testing Connection TrueNAS"
|
||||
_response=$(_get "$_api_url/system/state")
|
||||
_info "TrueNAS System State: $_response."
|
||||
|
||||
if [ -z "$_response" ]; then
|
||||
_err "Unable to authenticate to $_api_url."
|
||||
_err 'Check your Connection and set DEPLOY_TRUENAS_HOSTNAME="192.168.178.x".'
|
||||
_err 'or'
|
||||
_err 'set DEPLOY_TRUENAS_HOSTNAME="<truenas_dnsname>".'
|
||||
_err 'Check your Connection and set DEPLOY_TRUENAS_SCHEME="https".'
|
||||
_err "Check your Api Key."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_savedeployconf DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
|
||||
_savedeployconf DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
|
||||
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
||||
|
||||
_info "Getting active certificate from TrueNAS"
|
||||
_response=$(_get "$_api_url/system/general")
|
||||
_active_cert_id=$(echo "$_response" | grep -B2 '"name":' | grep 'id' | tr -d -- '"id: ,')
|
||||
_active_cert_name=$(echo "$_response" | grep '"name":' | sed -n 's/.*: "\(.\{1,\}\)",$/\1/p')
|
||||
_param_httpsredirect=$(echo "$_response" | grep '"ui_httpsredirect":' | sed -n 's/.*": \(.\{1,\}\),$/\1/p')
|
||||
_debug Active_UI_Certificate_ID "$_active_cert_id"
|
||||
_debug Active_UI_Certificate_Name "$_active_cert_name"
|
||||
_debug Active_UI_http_redirect "$_param_httpsredirect"
|
||||
|
||||
if [ "$DEPLOY_TRUENAS_SCHEME" = "http" ] && [ "$_param_httpsredirect" = "true" ]; then
|
||||
_info "http Redirect active"
|
||||
_info "Setting DEPLOY_TRUENAS_SCHEME to 'https'"
|
||||
DEPLOY_TRUENAS_SCHEME="https"
|
||||
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
|
||||
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
||||
fi
|
||||
|
||||
_info "Upload new certifikate to TrueNAS"
|
||||
_certname="Letsencrypt_$(_utc_date | tr ' ' '_' | tr -d -- ':')"
|
||||
_debug3 _certname "$_certname"
|
||||
|
||||
_certData="{\"create_type\": \"CERTIFICATE_CREATE_IMPORTED\", \"name\": \"${_certname}\", \"certificate\": \"$(_json_encode <"$_cfullchain")\", \"privatekey\": \"$(_json_encode <"$_ckey")\"}"
|
||||
_add_cert_result="$(_post "$_certData" "$_api_url/certificate" "" "POST" "application/json")"
|
||||
|
||||
_debug3 _add_cert_result "$_add_cert_result"
|
||||
|
||||
_info "Getting Certificate list to get new Cert ID"
|
||||
_cert_list=$(_get "$_api_url/system/general/ui_certificate_choices")
|
||||
_cert_id=$(echo "$_cert_list" | grep "$_certname" | sed -n 's/.*"\([0-9]\{1,\}\)".*$/\1/p')
|
||||
|
||||
_debug3 _cert_id "$_cert_id"
|
||||
|
||||
_info "Activate Certificate ID: $_cert_id"
|
||||
_activateData="{\"ui_certificate\": \"${_cert_id}\"}"
|
||||
_activate_result="$(_post "$_activateData" "$_api_url/system/general" "" "PUT" "application/json")"
|
||||
|
||||
_debug3 _activate_result "$_activate_result"
|
||||
|
||||
_info "Check if WebDAV certificate is the same as the WEB UI"
|
||||
_webdav_list=$(_get "$_api_url/webdav")
|
||||
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
|
||||
|
||||
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
|
||||
_info "Update the WebDAV Certificate"
|
||||
_debug _webdav_cert_id "$_webdav_cert_id"
|
||||
_webdav_data="{\"certssl\": \"${_cert_id}\"}"
|
||||
_activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
|
||||
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | sed -n 's/.*: \([0-9]\{1,\}\) }$/\1/p')
|
||||
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
|
||||
_info "WebDAV Certificate update successfully"
|
||||
else
|
||||
_err "Unable to set WebDAV certificate"
|
||||
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
|
||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
||||
return 1
|
||||
fi
|
||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
||||
else
|
||||
_info "WebDAV certificate not set or not the same as Web UI"
|
||||
fi
|
||||
|
||||
_info "Check if FTP certificate is the same as the WEB UI"
|
||||
_ftp_list=$(_get "$_api_url/ftp")
|
||||
_ftp_cert_id=$(echo "$_ftp_list" | grep '"ssltls_certificate":' | tr -d -- '"certislfa:_ ,')
|
||||
|
||||
if [ "$_ftp_cert_id" = "$_active_cert_id" ]; then
|
||||
_info "Update the FTP Certificate"
|
||||
_debug _ftp_cert_id "$_ftp_cert_id"
|
||||
_ftp_data="{\"ssltls_certificate\": \"${_cert_id}\"}"
|
||||
_activate_ftp_cert="$(_post "$_ftp_data" "$_api_url/ftp" "" "PUT" "application/json")"
|
||||
_ftp_new_cert_id=$(echo "$_activate_ftp_cert" | _json_decode | sed -n 's/.*: \([0-9]\{1,\}\) }$/\1/p')
|
||||
if [ "$_ftp_new_cert_id" -eq "$_cert_id" ]; then
|
||||
_info "FTP Certificate update successfully"
|
||||
else
|
||||
_err "Unable to set FTP certificate"
|
||||
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
||||
_debug3 _ftp_new_cert_id "$_ftp_new_cert_id"
|
||||
return 1
|
||||
fi
|
||||
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
||||
else
|
||||
_info "FTP certificate not set or not the same as Web UI"
|
||||
fi
|
||||
|
||||
_info "Delete old Certificate"
|
||||
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
|
||||
|
||||
_debug3 _delete_result "$_delete_result"
|
||||
|
||||
_info "Reload WebUI from TrueNAS"
|
||||
_restart_UI=$(_get "$_api_url/system/general/ui_restart")
|
||||
_debug2 _restart_UI "$_restart_UI"
|
||||
|
||||
if [ -n "$_add_cert_result" ] && [ -n "$_activate_result" ]; then
|
||||
return 0
|
||||
else
|
||||
_err "Certupdate was not succesfull, please use --debug"
|
||||
return 1
|
||||
fi
|
||||
}
|
@ -56,12 +56,23 @@ vault_deploy() {
|
||||
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL"
|
||||
else
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
|
||||
fi
|
||||
else
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key"
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem"
|
||||
else
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
63
dnsapi/dns_acmedns.sh
Normal file → Executable file
63
dnsapi/dns_acmedns.sh
Normal file → Executable file
@ -1,31 +1,70 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
#Author: Wolfgang Ebner
|
||||
#Report Bugs here: https://github.com/webner/acme.sh
|
||||
#Author: Sven Neubuaer
|
||||
#Report Bugs here: https://github.com/dampfklon/acme.sh
|
||||
#
|
||||
# Usage:
|
||||
# export ACMEDNS_BASE_URL="https://auth.acme-dns.io"
|
||||
#
|
||||
# You can optionally define an already existing account:
|
||||
#
|
||||
# export ACMEDNS_USERNAME="<username>"
|
||||
# export ACMEDNS_PASSWORD="<password>"
|
||||
# export ACMEDNS_SUBDOMAIN="<subdomain>"
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
dns_acmedns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using acme-dns"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_debug "fulldomain $fulldomain"
|
||||
_debug "txtvalue $txtvalue"
|
||||
|
||||
ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}"
|
||||
#for compatiblity from account conf
|
||||
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}"
|
||||
_clearaccountconf_mutable ACMEDNS_USERNAME
|
||||
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}"
|
||||
_clearaccountconf_mutable ACMEDNS_PASSWORD
|
||||
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}"
|
||||
_clearaccountconf_mutable ACMEDNS_SUBDOMAIN
|
||||
|
||||
if [ "$ACMEDNS_UPDATE_URL" = "" ]; then
|
||||
ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update"
|
||||
ACMEDNS_BASE_URL="${ACMEDNS_BASE_URL:-$(_readdomainconf ACMEDNS_BASE_URL)}"
|
||||
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readdomainconf ACMEDNS_USERNAME)}"
|
||||
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readdomainconf ACMEDNS_PASSWORD)}"
|
||||
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readdomainconf ACMEDNS_SUBDOMAIN)}"
|
||||
|
||||
if [ "$ACMEDNS_BASE_URL" = "" ]; then
|
||||
ACMEDNS_BASE_URL="https://auth.acme-dns.io"
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL"
|
||||
_saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME"
|
||||
_saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD"
|
||||
_saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN"
|
||||
ACMEDNS_UPDATE_URL="$ACMEDNS_BASE_URL/update"
|
||||
ACMEDNS_REGISTER_URL="$ACMEDNS_BASE_URL/register"
|
||||
|
||||
if [ -z "$ACMEDNS_USERNAME" ] || [ -z "$ACMEDNS_PASSWORD" ]; then
|
||||
response="$(_post "" "$ACMEDNS_REGISTER_URL" "" "POST")"
|
||||
_debug response "$response"
|
||||
ACMEDNS_USERNAME=$(echo "$response" | sed -n 's/^{.*\"username\":[ ]*\"\([^\"]*\)\".*}/\1/p')
|
||||
_debug "received username: $ACMEDNS_USERNAME"
|
||||
ACMEDNS_PASSWORD=$(echo "$response" | sed -n 's/^{.*\"password\":[ ]*\"\([^\"]*\)\".*}/\1/p')
|
||||
_debug "received password: $ACMEDNS_PASSWORD"
|
||||
ACMEDNS_SUBDOMAIN=$(echo "$response" | sed -n 's/^{.*\"subdomain\":[ ]*\"\([^\"]*\)\".*}/\1/p')
|
||||
_debug "received subdomain: $ACMEDNS_SUBDOMAIN"
|
||||
ACMEDNS_FULLDOMAIN=$(echo "$response" | sed -n 's/^{.*\"fulldomain\":[ ]*\"\([^\"]*\)\".*}/\1/p')
|
||||
_info "##########################################################"
|
||||
_info "# Create $fulldomain CNAME $ACMEDNS_FULLDOMAIN DNS entry #"
|
||||
_info "##########################################################"
|
||||
_info "Press enter to continue... "
|
||||
read -r _
|
||||
fi
|
||||
|
||||
_savedomainconf ACMEDNS_BASE_URL "$ACMEDNS_BASE_URL"
|
||||
_savedomainconf ACMEDNS_USERNAME "$ACMEDNS_USERNAME"
|
||||
_savedomainconf ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD"
|
||||
_savedomainconf ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN"
|
||||
|
||||
export _H1="X-Api-User: $ACMEDNS_USERNAME"
|
||||
export _H2="X-Api-Key: $ACMEDNS_PASSWORD"
|
||||
@ -48,8 +87,8 @@ dns_acmedns_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using acme-dns"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
_debug "fulldomain $fulldomain"
|
||||
_debug "txtvalue $txtvalue"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
@ -9,15 +9,12 @@ WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
|
||||
#
|
||||
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate
|
||||
#
|
||||
|
||||
dns_azure_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
|
||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||
|
||||
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
@ -26,6 +23,22 @@ dns_azure_add() {
|
||||
_err "You didn't specify the Azure Subscription ID"
|
||||
return 1
|
||||
fi
|
||||
#save subscription id to account conf file.
|
||||
_saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID"
|
||||
|
||||
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
|
||||
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
||||
_info "Using Azure managed identity"
|
||||
#save managed identity as preferred authentication method, clear service principal credentials from conf file.
|
||||
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "$AZUREDNS_MANAGEDIDENTITY"
|
||||
_saveaccountconf_mutable AZUREDNS_TENANTID ""
|
||||
_saveaccountconf_mutable AZUREDNS_APPID ""
|
||||
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET ""
|
||||
else
|
||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
@ -53,13 +66,15 @@ dns_azure_add() {
|
||||
_err "You didn't specify the Azure Client Secret"
|
||||
return 1
|
||||
fi
|
||||
#save account details to account conf file.
|
||||
_saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID"
|
||||
|
||||
#save account details to account conf file, don't opt in for azure manages identity check.
|
||||
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "false"
|
||||
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
|
||||
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
|
||||
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
|
||||
fi
|
||||
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
|
||||
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
@ -116,10 +131,6 @@ dns_azure_rm() {
|
||||
txtvalue=$2
|
||||
|
||||
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
|
||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||
|
||||
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
@ -129,6 +140,15 @@ dns_azure_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
|
||||
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
||||
_info "Using Azure managed identity"
|
||||
else
|
||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
@ -155,8 +175,9 @@ dns_azure_rm() {
|
||||
_err "You didn't specify the Azure Client Secret"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
|
||||
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
@ -258,9 +279,10 @@ _azure_rest() {
|
||||
|
||||
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
|
||||
_azure_getaccess_token() {
|
||||
tenantID=$1
|
||||
clientID=$2
|
||||
clientSecret=$3
|
||||
managedIdentity=$1
|
||||
tenantID=$2
|
||||
clientID=$3
|
||||
clientSecret=$4
|
||||
|
||||
accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
|
||||
expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}"
|
||||
@ -278,9 +300,16 @@ _azure_getaccess_token() {
|
||||
fi
|
||||
_debug "getting new bearer token"
|
||||
|
||||
if [ "$managedIdentity" = true ]; then
|
||||
# https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
|
||||
export _H1="Metadata: true"
|
||||
response="$(_get http://169.254.169.254/metadata/identity/oauth2/token\?api-version=2018-02-01\&resource=https://management.azure.com/)"
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
else
|
||||
export _H1="accept: application/json"
|
||||
export _H2="Content-Type: application/x-www-form-urlencoded"
|
||||
|
||||
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
|
||||
_secure_debug2 "data $body"
|
||||
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
|
||||
@ -289,6 +318,7 @@ _azure_getaccess_token() {
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
fi
|
||||
|
||||
if [ -z "$accesstoken" ]; then
|
||||
_err "no acccess token received. Check your Azure settings see $WIKI"
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
# Author: Boyan Peychev <boyan at cloudns dot net>
|
||||
# Repository: https://github.com/ClouDNS/acme.sh/
|
||||
# Editor: I Komang Suryadana
|
||||
|
||||
#CLOUDNS_AUTH_ID=XXXXX
|
||||
#CLOUDNS_SUB_AUTH_ID=XXXXX
|
||||
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
||||
CLOUDNS_API="https://api.cloudns.net"
|
||||
DOMAIN_TYPE=
|
||||
DOMAIN_MASTER=
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -61,6 +64,15 @@ dns_cloudns_rm() {
|
||||
host="$(echo "$1" | sed "s/\.$zone\$//")"
|
||||
record=$2
|
||||
|
||||
_dns_cloudns_get_zone_info "$zone"
|
||||
|
||||
_debug "Type" "$DOMAIN_TYPE"
|
||||
_debug "Cloud Master" "$DOMAIN_MASTER"
|
||||
if _contains "$DOMAIN_TYPE" "cloud"; then
|
||||
zone=$DOMAIN_MASTER
|
||||
fi
|
||||
_debug "ZONE" "$zone"
|
||||
|
||||
_dns_cloudns_http_api_call "dns/records.json" "domain-name=$zone&host=$host&type=TXT"
|
||||
if ! _contains "$response" "\"id\":"; then
|
||||
return 1
|
||||
@ -134,6 +146,18 @@ _dns_cloudns_init_check() {
|
||||
return 0
|
||||
}
|
||||
|
||||
_dns_cloudns_get_zone_info() {
|
||||
zone=$1
|
||||
_dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zone"
|
||||
if ! _contains "$response" "\"status\":\"Failed\""; then
|
||||
DOMAIN_TYPE=$(echo "$response" | _egrep_o '"type":"[^"]*"' | cut -d : -f 2 | tr -d '"')
|
||||
if _contains "$DOMAIN_TYPE" "cloud"; then
|
||||
DOMAIN_MASTER=$(echo "$response" | _egrep_o '"cloud-master":"[^"]*"' | cut -d : -f 2 | tr -d '"')
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_dns_cloudns_get_zone_name() {
|
||||
i=2
|
||||
while true; do
|
||||
|
@ -12,7 +12,7 @@
|
||||
# --
|
||||
#
|
||||
|
||||
DDNSS_DNS_API="https://ip4.ddnss.de/upd.php"
|
||||
DDNSS_DNS_API="https://ddnss.de/upd.php"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -77,7 +77,7 @@ dns_ddnss_rm() {
|
||||
|
||||
# Now remove the TXT record from DDNS DNS
|
||||
_info "Trying to remove TXT record"
|
||||
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=."; then
|
||||
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=2"; then
|
||||
if [ "$response" = "Updated 1 hostname." ]; then
|
||||
_info "TXT record has been successfully removed from your DDNSS domain."
|
||||
return 0
|
||||
|
87
dnsapi/dns_dnshome.sh
Executable file
87
dnsapi/dns_dnshome.sh
Executable file
@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# dnsHome.de API for acme.sh
|
||||
#
|
||||
# This Script adds the necessary TXT record to a Subdomain
|
||||
#
|
||||
# Author dnsHome.de (https://github.com/dnsHome-de)
|
||||
#
|
||||
# Report Bugs to https://github.com/acmesh-official/acme.sh/issues/3819
|
||||
#
|
||||
# export DNSHOME_Subdomain=""
|
||||
# export DNSHOME_SubdomainPassword=""
|
||||
|
||||
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
dns_dnshome_add() {
|
||||
txtvalue=$2
|
||||
|
||||
DNSHOME_Subdomain="${DNSHOME_Subdomain:-$(_readdomainconf DNSHOME_Subdomain)}"
|
||||
DNSHOME_SubdomainPassword="${DNSHOME_SubdomainPassword:-$(_readdomainconf DNSHOME_SubdomainPassword)}"
|
||||
|
||||
if [ -z "$DNSHOME_Subdomain" ] || [ -z "$DNSHOME_SubdomainPassword" ]; then
|
||||
DNSHOME_Subdomain=""
|
||||
DNSHOME_SubdomainPassword=""
|
||||
_err "Please specify/export your dnsHome.de Subdomain and Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_savedomainconf DNSHOME_Subdomain "$DNSHOME_Subdomain"
|
||||
_savedomainconf DNSHOME_SubdomainPassword "$DNSHOME_SubdomainPassword"
|
||||
|
||||
DNSHOME_Api="https://$DNSHOME_Subdomain:$DNSHOME_SubdomainPassword@www.dnshome.de/dyndns.php"
|
||||
|
||||
_DNSHOME_rest POST "acme=add&txt=$txtvalue"
|
||||
if ! echo "$response" | grep 'successfully' >/dev/null; then
|
||||
_err "Error"
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Usage: txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
dns_dnshome_rm() {
|
||||
txtvalue=$2
|
||||
|
||||
DNSHOME_Subdomain="${DNSHOME_Subdomain:-$(_readdomainconf DNSHOME_Subdomain)}"
|
||||
DNSHOME_SubdomainPassword="${DNSHOME_SubdomainPassword:-$(_readdomainconf DNSHOME_SubdomainPassword)}"
|
||||
|
||||
DNSHOME_Api="https://$DNSHOME_Subdomain:$DNSHOME_SubdomainPassword@www.dnshome.de/dyndns.php"
|
||||
|
||||
if [ -z "$DNSHOME_Subdomain" ] || [ -z "$DNSHOME_SubdomainPassword" ]; then
|
||||
DNSHOME_Subdomain=""
|
||||
DNSHOME_SubdomainPassword=""
|
||||
_err "Please specify/export your dnsHome.de Subdomain and Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_DNSHOME_rest POST "acme=rm&txt=$txtvalue"
|
||||
if ! echo "$response" | grep 'successfully' >/dev/null; then
|
||||
_err "Error"
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_DNSHOME_rest() {
|
||||
method=$1
|
||||
data="$2"
|
||||
_debug "$data"
|
||||
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$DNSHOME_Api" "" "$method")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $data"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
@ -35,7 +35,7 @@ dns_huaweicloud_add() {
|
||||
_err "dns_api(dns_huaweicloud): Error getting token."
|
||||
return 1
|
||||
fi
|
||||
_debug "Access token is: ${token}"
|
||||
_secure_debug "Access token is:" "${token}"
|
||||
|
||||
unset zoneid
|
||||
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
|
||||
@ -43,7 +43,7 @@ dns_huaweicloud_add() {
|
||||
_err "dns_api(dns_huaweicloud): Error getting zone id."
|
||||
return 1
|
||||
fi
|
||||
_debug "Zone ID is: ${zoneid}"
|
||||
_debug "Zone ID is:" "${zoneid}"
|
||||
|
||||
_debug "Adding Record"
|
||||
_add_record "${token}" "${fulldomain}" "${txtvalue}"
|
||||
@ -86,7 +86,7 @@ dns_huaweicloud_rm() {
|
||||
_err "dns_api(dns_huaweicloud): Error getting token."
|
||||
return 1
|
||||
fi
|
||||
_debug "Access token is: ${token}"
|
||||
_secure_debug "Access token is:" "${token}"
|
||||
|
||||
unset zoneid
|
||||
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
|
||||
@ -94,7 +94,7 @@ dns_huaweicloud_rm() {
|
||||
_err "dns_api(dns_huaweicloud): Error getting zone id."
|
||||
return 1
|
||||
fi
|
||||
_debug "Zone ID is: ${zoneid}"
|
||||
_debug "Zone ID is:" "${zoneid}"
|
||||
|
||||
# Remove all records
|
||||
# Therotically HuaweiCloud does not allow more than one record set
|
||||
@ -129,14 +129,28 @@ _get_zoneid() {
|
||||
fi
|
||||
_debug "$h"
|
||||
response=$(_get "${dns_api}/v2/zones?name=${h}")
|
||||
|
||||
if _contains "${response}" "id"; then
|
||||
_debug2 "$response"
|
||||
if _contains "${response}" '"id"'; then
|
||||
zoneidlist=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
zonenamelist=$(echo "${response}" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
_debug2 "Return Zone ID(s):" "${zoneidlist}"
|
||||
_debug2 "Return Zone Name(s):" "${zonenamelist}"
|
||||
zoneidnum=0
|
||||
zoneidcount=$(echo "${zoneidlist}" | grep -c '^')
|
||||
_debug "Retund Zone ID(s) Count:" "${zoneidcount}"
|
||||
while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do
|
||||
zoneidnum=$(_math "$zoneidnum" + 1)
|
||||
_zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p")
|
||||
zonename=$(echo "${zonenamelist}" | sed -n "${zoneidnum}p")
|
||||
_debug "Check Zone Name" "${zonename}"
|
||||
if [ "${zonename}" = "${h}." ]; then
|
||||
_debug "Get Zone ID Success."
|
||||
_zoneid=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||
_debug "ZoneID:" "${_zoneid}"
|
||||
printf "%s" "${_zoneid}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
done
|
||||
fi
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
@ -149,7 +163,7 @@ _get_recordset_id() {
|
||||
export _H1="X-Auth-Token: ${_token}"
|
||||
|
||||
response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}")
|
||||
if _contains "${response}" "id"; then
|
||||
if _contains "${response}" '"id"'; then
|
||||
_id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")"
|
||||
printf "%s" "${_id}"
|
||||
return 0
|
||||
@ -197,7 +211,7 @@ _add_record() {
|
||||
fi
|
||||
|
||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||
_debug "Record Set ID is: ${_record_id}"
|
||||
_debug "Record Set ID is:" "${_record_id}"
|
||||
|
||||
# Remove all records
|
||||
while [ "${_record_id}" != "0" ]; do
|
||||
@ -269,7 +283,7 @@ _get_token() {
|
||||
_post "${body}" "${iam_api}/v3/auth/tokens" >/dev/null
|
||||
_code=$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")
|
||||
_token=$(grep "^X-Subject-Token" "$HTTP_HEADER" | cut -d " " -f 2-)
|
||||
_debug2 "${_code}"
|
||||
_secure_debug "${_code}"
|
||||
printf "%s" "${_token}"
|
||||
return 0
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ dns_ispconfig_rm() {
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_ISPC_credentials() {
|
||||
if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then
|
||||
if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -n "${ISPC_Api_Insecure}" ]; then
|
||||
ISPC_User=""
|
||||
ISPC_Password=""
|
||||
ISPC_Api=""
|
||||
|
@ -19,8 +19,9 @@ dns_knot_add() {
|
||||
|
||||
_info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\""
|
||||
|
||||
knsupdate -y "${KNOT_KEY}" <<EOF
|
||||
knsupdate <<EOF
|
||||
server ${KNOT_SERVER}
|
||||
key ${KNOT_KEY}
|
||||
zone ${_domain}.
|
||||
update add ${fulldomain}. 60 TXT "${txtvalue}"
|
||||
send
|
||||
@ -49,8 +50,9 @@ dns_knot_rm() {
|
||||
|
||||
_info "Removing ${fulldomain}. TXT"
|
||||
|
||||
knsupdate -y "${KNOT_KEY}" <<EOF
|
||||
knsupdate <<EOF
|
||||
server ${KNOT_SERVER}
|
||||
key ${KNOT_KEY}
|
||||
zone ${_domain}.
|
||||
update del ${fulldomain}. TXT
|
||||
send
|
||||
|
261
dnsapi/dns_mythic_beasts.sh
Executable file
261
dnsapi/dns_mythic_beasts.sh
Executable file
@ -0,0 +1,261 @@
|
||||
#!/usr/bin/env sh
|
||||
# Mythic Beasts is a long-standing UK service provider using standards-based OAuth2 authentication
|
||||
# To test: ./acme.sh --dns dns_mythic_beasts --test --debug 1 --output-insecure --issue --domain domain.com
|
||||
# Cannot retest once cert is issued
|
||||
# OAuth2 tokens only valid for 300 seconds so we do not store
|
||||
# NOTE: This will remove all TXT records matching the fulldomain, not just the added ones (_acme-challenge.www.domain.com)
|
||||
|
||||
# Test OAuth2 credentials
|
||||
#MB_AK="aaaaaaaaaaaaaaaa"
|
||||
#MB_AS="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
||||
|
||||
# URLs
|
||||
MB_API='https://api.mythic-beasts.com/dns/v2/zones'
|
||||
MB_AUTH='https://auth.mythic-beasts.com/login'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_mythic_beasts_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "MYTHIC BEASTS Adding record $fulldomain = $txtvalue"
|
||||
if ! _initAuth; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# method path body_data
|
||||
if _mb_rest POST "$_domain/records/$_sub_domain/TXT" "$txtvalue"; then
|
||||
|
||||
if _contains "$response" "1 records added"; then
|
||||
_info "Added, verifying..."
|
||||
# Max 120 seconds to publish
|
||||
for i in $(seq 1 6); do
|
||||
# Retry on error
|
||||
if ! _mb_rest GET "$_domain/records/$_sub_domain/TXT?verify"; then
|
||||
_sleep 20
|
||||
else
|
||||
_info "Record published!"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
else
|
||||
_err "\n$response"
|
||||
fi
|
||||
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_mythic_beasts_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "MYTHIC BEASTS Removing record $fulldomain = $txtvalue"
|
||||
if ! _initAuth; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# method path body_data
|
||||
if _mb_rest DELETE "$_domain/records/$_sub_domain/TXT" "$txtvalue"; then
|
||||
_info "Record removed"
|
||||
return 0
|
||||
fi
|
||||
_err "Remove txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
#Possible formats:
|
||||
# _acme-challenge.www.example.com
|
||||
# _acme-challenge.example.com
|
||||
# _acme-challenge.example.co.uk
|
||||
# _acme-challenge.www.example.co.uk
|
||||
# _acme-challenge.sub1.sub2.www.example.co.uk
|
||||
# sub1.sub2.example.co.uk
|
||||
# example.com
|
||||
# example.co.uk
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
_debug "Detect the root zone"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
_err "Domain exhausted"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Use the status errors to find the domain, continue on 403 Access denied
|
||||
# method path body_data
|
||||
_mb_rest GET "$h/records"
|
||||
ret="$?"
|
||||
if [ "$ret" -eq 0 ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
return 0
|
||||
elif [ "$ret" -eq 1 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
|
||||
if [ "$i" -gt 50 ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
_err "Domain too long"
|
||||
return 1
|
||||
}
|
||||
|
||||
_initAuth() {
|
||||
MB_AK="${MB_AK:-$(_readaccountconf_mutable MB_AK)}"
|
||||
MB_AS="${MB_AS:-$(_readaccountconf_mutable MB_AS)}"
|
||||
|
||||
if [ -z "$MB_AK" ] || [ -z "$MB_AS" ]; then
|
||||
MB_AK=""
|
||||
MB_AS=""
|
||||
_err "Please specify an OAuth2 Key & Secret"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable MB_AK "$MB_AK"
|
||||
_saveaccountconf_mutable MB_AS "$MB_AS"
|
||||
|
||||
if ! _oauth2; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Checking authentication"
|
||||
_secure_debug access_token "$MB_TK"
|
||||
_sleep 1
|
||||
|
||||
# GET a list of zones
|
||||
# method path body_data
|
||||
if ! _mb_rest GET ""; then
|
||||
_err "The token is invalid"
|
||||
return 1
|
||||
fi
|
||||
_info "Token OK"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Github appears to use an outbound proxy for requests which means subsequent requests may not have the same
|
||||
# source IP. The standard Mythic Beasts OAuth2 tokens are tied to an IP, meaning github test requests fail
|
||||
# authentication. This is a work around using an undocumented MB API to obtain a token not tied to an
|
||||
# IP just for the github tests.
|
||||
_oauth2() {
|
||||
if [ "$GITHUB_ACTIONS" = "true" ]; then
|
||||
_oauth2_github
|
||||
else
|
||||
_oauth2_std
|
||||
fi
|
||||
return $?
|
||||
}
|
||||
|
||||
_oauth2_std() {
|
||||
# HTTP Basic Authentication
|
||||
_H1="Authorization: Basic $(echo "$MB_AK:$MB_AS" | _base64)"
|
||||
_H2="Accepts: application/json"
|
||||
export _H1 _H2
|
||||
body="grant_type=client_credentials"
|
||||
|
||||
_info "Getting OAuth2 token..."
|
||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
||||
response="$(_post "$body" "$MB_AUTH" "" "POST" "application/x-www-form-urlencoded")"
|
||||
if _contains "$response" "\"token_type\":\"bearer\""; then
|
||||
MB_TK="$(echo "$response" | _egrep_o "access_token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')"
|
||||
if [ -z "$MB_TK" ]; then
|
||||
_err "Unable to get access_token"
|
||||
_err "\n$response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "OAuth2 token_type not Bearer"
|
||||
_err "\n$response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_oauth2_github() {
|
||||
_H1="Accepts: application/json"
|
||||
export _H1
|
||||
body="{\"login\":{\"handle\":\"$MB_AK\",\"pass\":\"$MB_AS\",\"floating\":1}}"
|
||||
|
||||
_info "Getting Floating token..."
|
||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
||||
response="$(_post "$body" "$MB_AUTH" "" "POST" "application/json")"
|
||||
MB_TK="$(echo "$response" | _egrep_o "\"token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')"
|
||||
if [ -z "$MB_TK" ]; then
|
||||
_err "Unable to get token"
|
||||
_err "\n$response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
# method path body_data
|
||||
_mb_rest() {
|
||||
# URL encoded body for single API operations
|
||||
m="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
|
||||
if [ -z "$ep" ]; then
|
||||
_mb_url="$MB_API"
|
||||
else
|
||||
_mb_url="$MB_API/$ep"
|
||||
fi
|
||||
|
||||
_H1="Authorization: Bearer $MB_TK"
|
||||
_H2="Accepts: application/json"
|
||||
export _H1 _H2
|
||||
if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then
|
||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
||||
response="$(_post "data=$data" "$_mb_url" "" "$m" "application/x-www-form-urlencoded")"
|
||||
else
|
||||
response="$(_get "$_mb_url")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Request error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
header="$(cat "$HTTP_HEADER")"
|
||||
status="$(echo "$header" | _egrep_o "^HTTP[^ ]* .*$" | cut -d " " -f 2-100 | tr -d "\f\n")"
|
||||
code="$(echo "$status" | _egrep_o "^[0-9]*")"
|
||||
if [ "$code" -ge 400 ] || _contains "$response" "\"error\"" || _contains "$response" "invalid_client"; then
|
||||
_err "error $status"
|
||||
_err "\n$response"
|
||||
_debug "\n$header"
|
||||
return 2
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
@ -150,7 +150,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
_debug h "$h"
|
||||
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)
|
||||
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
|
||||
_debug id "$id"
|
||||
|
@ -92,9 +92,10 @@ _get_root() {
|
||||
domains_list=$(echo "${response}" | grep dname | sed -r "s/.*dname=\"([^\"]+)\".*/\\1/g")
|
||||
|
||||
for ITEM in ${domains_list}; do
|
||||
IDN_ITEM="$(_idn "${ITEM}")"
|
||||
case "${domain}" in
|
||||
*${ITEM}*)
|
||||
_domain=${ITEM}
|
||||
*${IDN_ITEM}*)
|
||||
_domain=${IDN_ITEM}
|
||||
_debug _domain "${_domain}"
|
||||
return 0
|
||||
;;
|
||||
|
@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# API-integration for Simply.com (https://www.simply.com)
|
||||
|
||||
#SIMPLY_AccountName="accountname"
|
||||
#
|
||||
#SIMPLY_ApiKey="apikey"
|
||||
#
|
||||
#SIMPLY_Api="https://api.simply.com/1/[ACCOUNTNAME]/[APIKEY]"
|
||||
@ -51,7 +51,7 @@ dns_simply_rm() {
|
||||
|
||||
_simply_save_config
|
||||
|
||||
_debug "First detect the root zone"
|
||||
_debug "Find the DNS zone"
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
@ -77,8 +77,8 @@ dns_simply_rm() {
|
||||
for record in $records; do
|
||||
_debug record "$record"
|
||||
|
||||
record_data=$(echo "$record" | cut -d "," -f 3 | sed 's/"//g' | grep "data" | cut -d ":" -f 2)
|
||||
record_type=$(echo "$record" | cut -d "," -f 4 | sed 's/"//g' | grep "type" | cut -d ":" -f 2)
|
||||
record_data=$(echo "$record" | sed -n "s/.*\"data\":\"\([^\"]*\)\".*/\1/p")
|
||||
record_type=$(echo "$record" | sed -n "s/.*\"type\":\"\([^\"]*\)\".*/\1/p")
|
||||
|
||||
_debug2 record_data "$record_data"
|
||||
_debug2 record_type "$record_type"
|
||||
@ -151,7 +151,7 @@ _simply_save_config() {
|
||||
_simply_get_all_records() {
|
||||
domain=$1
|
||||
|
||||
if ! _simply_rest GET "my/products/$domain/dns/records"; then
|
||||
if ! _simply_rest GET "my/products/$domain/dns/records/"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
@ -169,7 +169,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _simply_rest GET "my/products/$h/dns"; then
|
||||
if ! _simply_rest GET "my/products/$h/dns/"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
@ -193,7 +193,7 @@ _simply_add_record() {
|
||||
|
||||
data="{\"name\": \"$sub_domain\", \"type\":\"TXT\", \"data\": \"$txtval\", \"priority\":0, \"ttl\": 3600}"
|
||||
|
||||
if ! _simply_rest POST "my/products/$domain/dns/records" "$data"; then
|
||||
if ! _simply_rest POST "my/products/$domain/dns/records/" "$data"; then
|
||||
_err "Adding record not successfull!"
|
||||
return 1
|
||||
fi
|
||||
@ -214,7 +214,7 @@ _simply_delete_record() {
|
||||
|
||||
_debug record_id "Delete record with id $record_id"
|
||||
|
||||
if ! _simply_rest DELETE "my/products/$domain/dns/records/$record_id"; then
|
||||
if ! _simply_rest DELETE "my/products/$domain/dns/records/$record_id/"; then
|
||||
_err "Deleting record not successfull!"
|
||||
return 1
|
||||
fi
|
||||
@ -250,6 +250,8 @@ _simply_rest() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
|
||||
_debug2 response "$response"
|
||||
|
||||
if _contains "$response" "Invalid account authorization"; then
|
||||
|
62
notify/gotify.sh
Normal file
62
notify/gotify.sh
Normal file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Support Gotify
|
||||
|
||||
#GOTIFY_URL="https://gotify.example.com"
|
||||
#GOTIFY_TOKEN="123456789ABCDEF"
|
||||
|
||||
#optional
|
||||
#GOTIFY_PRIORITY=0
|
||||
|
||||
# subject content statusCode
|
||||
gotify_send() {
|
||||
_subject="$1"
|
||||
_content="$2"
|
||||
_statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
|
||||
_debug "_subject" "$_subject"
|
||||
_debug "_content" "$_content"
|
||||
_debug "_statusCode" "$_statusCode"
|
||||
|
||||
GOTIFY_URL="${GOTIFY_URL:-$(_readaccountconf_mutable GOTIFY_URL)}"
|
||||
if [ -z "$GOTIFY_URL" ]; then
|
||||
GOTIFY_URL=""
|
||||
_err "You didn't specify the gotify server url GOTIFY_URL."
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable GOTIFY_URL "$GOTIFY_URL"
|
||||
|
||||
GOTIFY_TOKEN="${GOTIFY_TOKEN:-$(_readaccountconf_mutable GOTIFY_TOKEN)}"
|
||||
if [ -z "$GOTIFY_TOKEN" ]; then
|
||||
GOTIFY_TOKEN=""
|
||||
_err "You didn't specify the gotify token GOTIFY_TOKEN."
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable GOTIFY_TOKEN "$GOTIFY_TOKEN"
|
||||
|
||||
GOTIFY_PRIORITY="${GOTIFY_PRIORITY:-$(_readaccountconf_mutable GOTIFY_PRIORITY)}"
|
||||
if [ -z "$GOTIFY_PRIORITY" ]; then
|
||||
GOTIFY_PRIORITY=0
|
||||
else
|
||||
_saveaccountconf_mutable GOTIFY_PRIORITY "$GOTIFY_PRIORITY"
|
||||
fi
|
||||
|
||||
export _H1="X-Gotify-Key: ${GOTIFY_TOKEN}"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
_content=$(echo "$_content" | _json_encode)
|
||||
_subject=$(echo "$_subject" | _json_encode)
|
||||
|
||||
_data="{\"title\": \"${_subject}\", \"message\": \"${_content}\", \"priority\": ${GOTIFY_PRIORITY}}"
|
||||
|
||||
response="$(_post "${_data}" "${GOTIFY_URL}/message" "" "POST" "application/json")"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Failed to send message"
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
|
||||
return 0
|
||||
}
|
Loading…
Reference in New Issue
Block a user