mirror of
https://github.com/plantroon/acme.sh.git
synced 2024-11-18 04:11:46 +00:00
commit
8ded524236
101
.github/workflows/DNS.yml
vendored
101
.github/workflows/DNS.yml
vendored
@ -81,9 +81,7 @@ jobs:
|
|||||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||||
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> docker.env
|
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> docker.env
|
||||||
fi
|
fi
|
||||||
echo "TEST_DNS_NO_WILDCARD" >> docker.env
|
|
||||||
echo "http_proxy" >> docker.env
|
|
||||||
echo "https_proxy" >> docker.env
|
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
run: cd ../acmetest && ./rundocker.sh testall
|
run: cd ../acmetest && ./rundocker.sh testall
|
||||||
|
|
||||||
@ -236,56 +234,9 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Solaris:
|
|
||||||
runs-on: macos-12
|
|
||||||
needs: FreeBSD
|
|
||||||
env:
|
|
||||||
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
|
|
||||||
DEBUG: ${{ secrets.DEBUG }}
|
|
||||||
http_proxy: ${{ secrets.http_proxy }}
|
|
||||||
https_proxy: ${{ secrets.https_proxy }}
|
|
||||||
steps:
|
|
||||||
- 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
|
|
||||||
with:
|
|
||||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
|
||||||
copyback: false
|
|
||||||
prepare: pkgutil -y -i socat
|
|
||||||
run: |
|
|
||||||
pkg set-mediator -v -I default@1.1 openssl
|
|
||||||
export PATH=/usr/gnu/bin:$PATH
|
|
||||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
|
||||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
|
||||||
fi
|
|
||||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
|
||||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
|
||||||
fi
|
|
||||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
|
||||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
|
||||||
fi
|
|
||||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
|
||||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
|
||||||
fi
|
|
||||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
|
||||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
|
||||||
fi
|
|
||||||
cd ../acmetest
|
|
||||||
./letest.sh
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
OpenBSD:
|
OpenBSD:
|
||||||
runs-on: macos-12
|
runs-on: macos-12
|
||||||
needs: Solaris
|
needs: FreeBSD
|
||||||
env:
|
env:
|
||||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||||
TestingDomain: ${{ secrets.TestingDomain }}
|
TestingDomain: ${{ secrets.TestingDomain }}
|
||||||
@ -424,3 +375,51 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Solaris:
|
||||||
|
runs-on: macos-12
|
||||||
|
needs: DragonFlyBSD
|
||||||
|
env:
|
||||||
|
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
|
||||||
|
DEBUG: ${{ secrets.DEBUG }}
|
||||||
|
http_proxy: ${{ secrets.http_proxy }}
|
||||||
|
https_proxy: ${{ secrets.https_proxy }}
|
||||||
|
HTTPS_INSECURE: 1 # always set to 1 to ignore https error, sincc Solaris doesn't accept the expired ISRG X1 root
|
||||||
|
steps:
|
||||||
|
- 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
|
||||||
|
with:
|
||||||
|
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||||
|
copyback: false
|
||||||
|
prepare: pkgutil -y -i socat
|
||||||
|
run: |
|
||||||
|
pkg set-mediator -v -I default@1.1 openssl
|
||||||
|
export PATH=/usr/gnu/bin:$PATH
|
||||||
|
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||||
|
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
||||||
|
fi
|
||||||
|
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||||
|
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
||||||
|
fi
|
||||||
|
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||||
|
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
||||||
|
fi
|
||||||
|
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||||
|
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
||||||
|
fi
|
||||||
|
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||||
|
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
||||||
|
fi
|
||||||
|
cd ../acmetest
|
||||||
|
./letest.sh
|
||||||
|
|
||||||
|
|
||||||
|
12
acme.sh
12
acme.sh
@ -2561,7 +2561,7 @@ __initHome() {
|
|||||||
_script_home="$(dirname "$_script")"
|
_script_home="$(dirname "$_script")"
|
||||||
_debug "_script_home" "$_script_home"
|
_debug "_script_home" "$_script_home"
|
||||||
if [ -d "$_script_home" ]; then
|
if [ -d "$_script_home" ]; then
|
||||||
_SCRIPT_HOME="$_script_home"
|
export _SCRIPT_HOME="$_script_home"
|
||||||
else
|
else
|
||||||
_err "It seems the script home is not correct:$_script_home"
|
_err "It seems the script home is not correct:$_script_home"
|
||||||
fi
|
fi
|
||||||
@ -6557,7 +6557,7 @@ install() {
|
|||||||
if [ "$_accountemail" ]; then
|
if [ "$_accountemail" ]; then
|
||||||
_saveaccountconf "ACCOUNT_EMAIL" "$_accountemail"
|
_saveaccountconf "ACCOUNT_EMAIL" "$_accountemail"
|
||||||
fi
|
fi
|
||||||
|
_saveaccountconf "UPGRADE_HASH" "$(_getUpgradeHash)"
|
||||||
_info OK
|
_info OK
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6921,8 +6921,6 @@ installOnline() {
|
|||||||
chmod +x $PROJECT_ENTRY
|
chmod +x $PROJECT_ENTRY
|
||||||
if ./$PROJECT_ENTRY --install "$@"; then
|
if ./$PROJECT_ENTRY --install "$@"; then
|
||||||
_info "Install success!"
|
_info "Install success!"
|
||||||
_initpath
|
|
||||||
_saveaccountconf "UPGRADE_HASH" "$(_getUpgradeHash)"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
@ -7442,17 +7440,17 @@ _process() {
|
|||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--home)
|
--home)
|
||||||
LE_WORKING_DIR="$2"
|
export LE_WORKING_DIR="$2"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--cert-home | --certhome)
|
--cert-home | --certhome)
|
||||||
_certhome="$2"
|
_certhome="$2"
|
||||||
CERT_HOME="$_certhome"
|
export CERT_HOME="$_certhome"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--config-home)
|
--config-home)
|
||||||
_confighome="$2"
|
_confighome="$2"
|
||||||
LE_CONFIG_HOME="$_confighome"
|
export LE_CONFIG_HOME="$_confighome"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--useragent)
|
--useragent)
|
||||||
|
248
dnsapi/dns_bunny.sh
Normal file
248
dnsapi/dns_bunny.sh
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
## Will be called by acme.sh to add the TXT record via the Bunny DNS API.
|
||||||
|
## returns 0 means success, otherwise error.
|
||||||
|
|
||||||
|
## Author: nosilver4u <nosilver4u at ewww.io>
|
||||||
|
## GitHub: https://github.com/nosilver4u/acme.sh
|
||||||
|
|
||||||
|
##
|
||||||
|
## Environment Variables Required:
|
||||||
|
##
|
||||||
|
## BUNNY_API_KEY="75310dc4-ca77-9ac3-9a19-f6355db573b49ce92ae1-2655-3ebd-61ac-3a3ae34834cc"
|
||||||
|
##
|
||||||
|
|
||||||
|
##################### Public functions #####################
|
||||||
|
|
||||||
|
## Create the text record for validation.
|
||||||
|
## Usage: fulldomain txtvalue
|
||||||
|
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
|
||||||
|
dns_bunny_add() {
|
||||||
|
fulldomain="$(echo "$1" | _lower_case)"
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
|
||||||
|
# Check if API Key is set
|
||||||
|
if [ -z "$BUNNY_API_KEY" ]; then
|
||||||
|
BUNNY_API_KEY=""
|
||||||
|
_err "You did not specify Bunny.net API key."
|
||||||
|
_err "Please export BUNNY_API_KEY and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Using Bunny.net dns validation - add record"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
## save the env vars (key and domain split location) for later automated use
|
||||||
|
_saveaccountconf_mutable BUNNY_API_KEY "$BUNNY_API_KEY"
|
||||||
|
|
||||||
|
## split the domain for Bunny API
|
||||||
|
if ! _get_base_domain "$fulldomain"; then
|
||||||
|
_err "domain not found in your account for addition"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
|
||||||
|
## Set the header with our post type and auth key
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||||
|
export _H3="Content-Type: application/json"
|
||||||
|
PURL="https://api.bunny.net/dnszone/$_domain_id/records"
|
||||||
|
PBODY='{"Id":'$_domain_id',"Type":3,"Name":"'$_sub_domain'","Value":"'$txtvalue'","ttl":120}'
|
||||||
|
|
||||||
|
_debug PURL "$PURL"
|
||||||
|
_debug PBODY "$PBODY"
|
||||||
|
|
||||||
|
## the create request - POST
|
||||||
|
## args: BODY, URL, [need64, httpmethod]
|
||||||
|
response="$(_post "$PBODY" "$PURL" "" "PUT")"
|
||||||
|
|
||||||
|
## check response
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error in response: $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
|
||||||
|
## finished correctly
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
## Remove the txt record after validation.
|
||||||
|
## Usage: fulldomain txtvalue
|
||||||
|
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
|
||||||
|
dns_bunny_rm() {
|
||||||
|
fulldomain="$(echo "$1" | _lower_case)"
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
|
||||||
|
# Check if API Key Exists
|
||||||
|
if [ -z "$BUNNY_API_KEY" ]; then
|
||||||
|
BUNNY_API_KEY=""
|
||||||
|
_err "You did not specify Bunny.net API key."
|
||||||
|
_err "Please export BUNNY_API_KEY and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Using Bunny.net dns validation - remove record"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
## split the domain for Bunny API
|
||||||
|
if ! _get_base_domain "$fulldomain"; then
|
||||||
|
_err "Domain not found in your account for TXT record removal"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
|
||||||
|
## Set the header with our post type and key auth key
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||||
|
## get URL for the list of DNS records
|
||||||
|
GURL="https://api.bunny.net/dnszone/$_domain_id"
|
||||||
|
|
||||||
|
## 1) Get the domain/zone records
|
||||||
|
## the fetch request - GET
|
||||||
|
## args: URL, [onlyheader, timeout]
|
||||||
|
domain_list="$(_get "$GURL")"
|
||||||
|
|
||||||
|
## check response
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error in domain_list response: $domain_list"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 domain_list "$domain_list"
|
||||||
|
|
||||||
|
## 2) search through records
|
||||||
|
## check for what we are looking for: "Type":3,"Value":"$txtvalue","Name":"$_sub_domain"
|
||||||
|
record="$(echo "$domain_list" | _egrep_o "\"Id\"\s*\:\s*\"*[0-9]+\"*,\s*\"Type\"[^}]*\"Value\"\s*\:\s*\"$txtvalue\"[^}]*\"Name\"\s*\:\s*\"$_sub_domain\"")"
|
||||||
|
|
||||||
|
if [ -n "$record" ]; then
|
||||||
|
|
||||||
|
## We found records
|
||||||
|
rec_ids="$(echo "$record" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||||
|
_debug rec_ids "$rec_ids"
|
||||||
|
if [ -n "$rec_ids" ]; then
|
||||||
|
echo "$rec_ids" | while IFS= read -r rec_id; do
|
||||||
|
## delete the record
|
||||||
|
## delete URL for removing the one we dont want
|
||||||
|
DURL="https://api.bunny.net/dnszone/$_domain_id/records/$rec_id"
|
||||||
|
|
||||||
|
## the removal request - DELETE
|
||||||
|
## args: BODY, URL, [need64, httpmethod]
|
||||||
|
response="$(_post "" "$DURL" "" "DELETE")"
|
||||||
|
|
||||||
|
## check response (sort of)
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error in remove response: $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
## finished correctly
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
##################### Private functions below #####################
|
||||||
|
|
||||||
|
## Split the domain provided into the "base domain" and the "start prefix".
|
||||||
|
## This function searches for the longest subdomain in your account
|
||||||
|
## for the full domain given and splits it into the base domain (zone)
|
||||||
|
## and the prefix/record to be added/removed
|
||||||
|
## USAGE: fulldomain
|
||||||
|
## EG: "_acme-challenge.two.three.four.domain.com"
|
||||||
|
## returns
|
||||||
|
## _sub_domain="_acme-challenge.two"
|
||||||
|
## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists
|
||||||
|
## _domain_id=234
|
||||||
|
## if only "domain.com" exists it will return
|
||||||
|
## _sub_domain="_acme-challenge.two.three.four"
|
||||||
|
## _domain="domain.com"
|
||||||
|
## _domain_id=234
|
||||||
|
_get_base_domain() {
|
||||||
|
# args
|
||||||
|
fulldomain="$(echo "$1" | _lower_case)"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
|
||||||
|
# domain max legal length = 253
|
||||||
|
MAX_DOM=255
|
||||||
|
page=1
|
||||||
|
|
||||||
|
## get a list of domains for the account to check thru
|
||||||
|
## Set the headers
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||||
|
_debug BUNNY_API_KEY "$BUNNY_API_KEY"
|
||||||
|
## get URL for the list of domains
|
||||||
|
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||||
|
DOMURL="https://api.bunny.net/dnszone"
|
||||||
|
|
||||||
|
## while we dont have a matching domain we keep going
|
||||||
|
while [ -z "$found" ]; do
|
||||||
|
## get the domain list (current page)
|
||||||
|
domain_list="$(_get "$DOMURL")"
|
||||||
|
|
||||||
|
## check response
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error in domain_list response: $domain_list"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 domain_list "$domain_list"
|
||||||
|
|
||||||
|
i=1
|
||||||
|
while [ $i -gt 0 ]; do
|
||||||
|
## get next longest domain
|
||||||
|
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||||
|
## check we got something back from our cut (or are we at the end)
|
||||||
|
if [ -z "$_domain" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
## we got part of a domain back - grep it out
|
||||||
|
found="$(echo "$domain_list" | _egrep_o "\"Id\"\s*:\s*\"*[0-9]+\"*,\s*\"Domain\"\s*\:\s*\"$_domain\"")"
|
||||||
|
## check if it exists
|
||||||
|
if [ -n "$found" ]; then
|
||||||
|
## exists - exit loop returning the parts
|
||||||
|
sub_point=$(_math $i - 1)
|
||||||
|
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
|
||||||
|
_domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
found=""
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
## increment cut point $i
|
||||||
|
i=$(_math $i + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$found" ]; then
|
||||||
|
page=$(_math $page + 1)
|
||||||
|
nextpage="https://api.bunny.net/dnszone?page=$page"
|
||||||
|
## Find the next page if we don't have a match.
|
||||||
|
hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")"
|
||||||
|
if [ -z "$hasnextpage" ]; then
|
||||||
|
_err "No record and no nextpage in Bunny.net domain search."
|
||||||
|
found=""
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 nextpage "$nextpage"
|
||||||
|
DOMURL="$nextpage"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
## We went through the entire domain zone list and didn't find one that matched.
|
||||||
|
## If we ever get here, something is broken in the code...
|
||||||
|
_err "Domain not found in Bunny.net account, but we should never get here!"
|
||||||
|
found=""
|
||||||
|
return 1
|
||||||
|
}
|
@ -13,6 +13,7 @@
|
|||||||
# cPanel_Hostname=hostname
|
# cPanel_Hostname=hostname
|
||||||
#
|
#
|
||||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
|
||||||
# Used to add txt record
|
# Used to add txt record
|
||||||
dns_cpanel_add() {
|
dns_cpanel_add() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
@ -120,7 +121,7 @@ _myget() {
|
|||||||
|
|
||||||
_get_root() {
|
_get_root() {
|
||||||
_myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
|
_myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
|
||||||
_domains=$(echo "$_result" | sed 's/.*\(zones.*\[\).*/\1/' | cut -d':' -f2 | sed 's/"//g' | sed 's/{//g')
|
_domains=$(echo "$_result" | _egrep_o '"[a-z0-9\.\-]*":\["; cPanel first' | cut -d':' -f1 | sed 's/"//g' | sed 's/{//g')
|
||||||
_debug "_result is: $_result"
|
_debug "_result is: $_result"
|
||||||
_debug "_domains is: $_domains"
|
_debug "_domains is: $_domains"
|
||||||
if [ -z "$_domains" ]; then
|
if [ -z "$_domains" ]; then
|
||||||
@ -146,7 +147,7 @@ _findentry() {
|
|||||||
_debug "In _findentry"
|
_debug "In _findentry"
|
||||||
#returns id of dns entry, if it exists
|
#returns id of dns entry, if it exists
|
||||||
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone_records&domain=$_domain"
|
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone_records&domain=$_domain"
|
||||||
_id=$(echo "$_result" | sed "s/.*\(line.*$fulldomain.*$txtvalue\).*/\1/" | cut -d ':' -f 2 | cut -d ',' -f 1)
|
_id=$(echo "$_result" | sed -e "s/},{/},\n{/g" | grep "$fulldomain" | grep "$txtvalue" | _egrep_o 'line":[0-9]+' | cut -d ':' -f 2)
|
||||||
_debug "_result is: $_result"
|
_debug "_result is: $_result"
|
||||||
_debug "fulldomain. is $fulldomain."
|
_debug "fulldomain. is $fulldomain."
|
||||||
_debug "txtvalue is $txtvalue"
|
_debug "txtvalue is $txtvalue"
|
||||||
|
@ -192,6 +192,7 @@ _get_base_domain() {
|
|||||||
## get URL for the list of domains
|
## get URL for the list of domains
|
||||||
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||||
DOMURL="https://api.digitalocean.com/v2/domains"
|
DOMURL="https://api.digitalocean.com/v2/domains"
|
||||||
|
found=""
|
||||||
|
|
||||||
## while we dont have a matching domain we keep going
|
## while we dont have a matching domain we keep going
|
||||||
while [ -z "$found" ]; do
|
while [ -z "$found" ]; do
|
||||||
@ -205,9 +206,7 @@ _get_base_domain() {
|
|||||||
fi
|
fi
|
||||||
_debug2 domain_list "$domain_list"
|
_debug2 domain_list "$domain_list"
|
||||||
|
|
||||||
## for each shortening of our $fulldomain, check if it exists in the $domain_list
|
i=1
|
||||||
## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
|
|
||||||
i=2
|
|
||||||
while [ $i -gt 0 ]; do
|
while [ $i -gt 0 ]; do
|
||||||
## get next longest domain
|
## get next longest domain
|
||||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||||
|
@ -13,8 +13,8 @@ DNSServices_API=https://dns.services/api
|
|||||||
|
|
||||||
#Usage: dns_dnsservices_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
#Usage: dns_dnsservices_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
dns_dnsservices_add() {
|
dns_dnsservices_add() {
|
||||||
fulldomain=$1
|
fulldomain="$1"
|
||||||
txtvalue=$2
|
txtvalue="$2"
|
||||||
|
|
||||||
_info "Using dns.services to create ACME DNS challenge"
|
_info "Using dns.services to create ACME DNS challenge"
|
||||||
_debug2 add_fulldomain "$fulldomain"
|
_debug2 add_fulldomain "$fulldomain"
|
||||||
@ -61,8 +61,8 @@ dns_dnsservices_add() {
|
|||||||
#Usage: fulldomain txtvalue
|
#Usage: fulldomain txtvalue
|
||||||
#Description: Remove the txt record after validation.
|
#Description: Remove the txt record after validation.
|
||||||
dns_dnsservices_rm() {
|
dns_dnsservices_rm() {
|
||||||
fulldomain=$1
|
fulldomain="$1"
|
||||||
txtvalue=$2
|
txtvalue="$2"
|
||||||
|
|
||||||
_info "Using dns.services to remove DNS record $fulldomain TXT $txtvalue"
|
_info "Using dns.services to remove DNS record $fulldomain TXT $txtvalue"
|
||||||
_debug rm_fulldomain "$fulldomain"
|
_debug rm_fulldomain "$fulldomain"
|
||||||
@ -117,36 +117,40 @@ _setup_headers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_get_root() {
|
_get_root() {
|
||||||
domain=$1
|
domain="$1"
|
||||||
_debug2 _get_root "Get the root domain of ${domain} for DNS API"
|
_debug2 _get_root "Get the root domain of ${domain} for DNS API"
|
||||||
|
|
||||||
# Setup _get() and _post() headers
|
# Setup _get() and _post() headers
|
||||||
#_setup_headers
|
#_setup_headers
|
||||||
|
|
||||||
result=$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/dns")
|
result=$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/dns")
|
||||||
|
result2="$(printf "%s\n" "$result" | tr '[' '\n' | grep '"name"')"
|
||||||
|
result3="$(printf "%s\n" "$result2" | tr '}' '\n' | grep '"name"' | sed "s,^\,,,g" | sed "s,$,},g")"
|
||||||
|
useResult=""
|
||||||
_debug2 _get_root "Got the following root domain(s) $result"
|
_debug2 _get_root "Got the following root domain(s) $result"
|
||||||
_debug2 _get_root "- JSON: $result"
|
_debug2 _get_root "- JSON: $result"
|
||||||
|
|
||||||
if [ "$(echo "$result" | grep -c '"name"')" -gt "1" ]; then
|
if [ "$(printf "%s\n" "$result" | tr '}' '\n' | grep -c '"name"')" -gt "1" ]; then
|
||||||
checkMultiZones="true"
|
checkMultiZones="true"
|
||||||
_debug2 _get_root "- multiple zones found"
|
_debug2 _get_root "- multiple zones found"
|
||||||
else
|
else
|
||||||
checkMultiZones="false"
|
checkMultiZones="false"
|
||||||
|
_debug2 _get_root "- single zone found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Find/isolate the root zone to work with in createRecord() and deleteRecord()
|
# Find/isolate the root zone to work with in createRecord() and deleteRecord()
|
||||||
rootZone=""
|
rootZone=""
|
||||||
if [ "$checkMultiZones" = "true" ]; then
|
if [ "$checkMultiZones" = "true" ]; then
|
||||||
rootZone=$(for zone in $(echo "$result" | tr -d '\n' ' '); do
|
#rootZone=$(for x in $(printf "%s" "${result3}" | tr ',' '\n' | sed -n 's/.*"name":"\(.*\)",.*/\1/p'); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
|
||||||
if [ "$(echo "$domain" | grep "$zone")" != "" ]; then
|
rootZone=$(for x in $(printf "%s\n" "${result3}" | tr ',' '\n' | grep name | cut -d'"' -f4); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
|
||||||
_debug2 _get_root "- trying to figure out if $zone is in $domain"
|
if [ "$rootZone" != "" ]; then
|
||||||
echo "$zone"
|
_debug2 _rootZone "- root zone for $domain is $rootZone"
|
||||||
break
|
|
||||||
fi
|
|
||||||
done)
|
|
||||||
else
|
else
|
||||||
rootZone=$(echo "$result" | _egrep_o '"name":"[^"]*' | cut -d'"' -f4)
|
_err "Could not find root zone for $domain, is it correctly typed?"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
rootZone=$(echo "$result" | tr '}' '\n' | _egrep_o '"name":"[^"]*' | cut -d'"' -f4)
|
||||||
_debug2 _get_root "- only found 1 domain in API: $rootZone"
|
_debug2 _get_root "- only found 1 domain in API: $rootZone"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -155,14 +159,18 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Make sure we use the correct API zone data
|
||||||
|
useResult="$(printf "%s\n" "${result3}" tr ',' '\n' | grep "$rootZone")"
|
||||||
|
_debug2 _useResult "useResult=$useResult"
|
||||||
|
|
||||||
# Setup variables used by other functions to communicate with DNS.Services API
|
# Setup variables used by other functions to communicate with DNS.Services API
|
||||||
#zoneInfo=$(echo "$result" | sed "s,\"zones,\n&,g" | grep zones | cut -d'[' -f2 | cut -d']' -f1 | tr '}' '\n' | grep "\"$rootZone\"")
|
#zoneInfo=$(printf "%s\n" "$useResult" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"name":")([^"]*)"(.*)$,\2,g')
|
||||||
zoneInfo=$(echo "$result" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"name":")([^"]*)"(.*)$,\2,g' | grep "\"$rootZone\"")
|
zoneInfo=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep '"name"' | cut -d'"' -f4)
|
||||||
rootZoneName="$rootZone"
|
rootZoneName="$rootZone"
|
||||||
subDomainName="$(echo "$domain" | sed "s,\.$rootZone,,g")"
|
subDomainName="$(printf "%s\n" "$domain" | sed "s,\.$rootZone,,g")"
|
||||||
subDomainNameClean="$(echo "$domain" | sed "s,_acme-challenge.,,g")"
|
subDomainNameClean="$(printf "%s\n" "$domain" | sed "s,_acme-challenge.,,g")"
|
||||||
rootZoneDomainID=$(echo "$result" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"domain_id":")([^"]*)"(.*)$,\2,g')
|
rootZoneDomainID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep domain_id | cut -d'"' -f4)
|
||||||
rootZoneServiceID=$(echo "$result" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"service_id":")([^"]*)"(.*)$,\2,g')
|
rootZoneServiceID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep service_id | cut -d'"' -f4)
|
||||||
|
|
||||||
_debug2 _zoneInfo "Zone info from API : $zoneInfo"
|
_debug2 _zoneInfo "Zone info from API : $zoneInfo"
|
||||||
_debug2 _get_root "Root zone name : $rootZoneName"
|
_debug2 _get_root "Root zone name : $rootZoneName"
|
||||||
@ -175,13 +183,17 @@ _get_root() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createRecord() {
|
createRecord() {
|
||||||
fulldomain=$1
|
fulldomain="$1"
|
||||||
txtvalue="$2"
|
txtvalue="$2"
|
||||||
|
|
||||||
# Get root domain information - needed for DNS.Services API communication
|
# Get root domain information - needed for DNS.Services API communication
|
||||||
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||||
_get_root "$fulldomain"
|
_get_root "$fulldomain"
|
||||||
fi
|
fi
|
||||||
|
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||||
|
_err "Something happend - could not get the API zone information"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
_debug2 createRecord "CNAME TXT value is: $txtvalue"
|
_debug2 createRecord "CNAME TXT value is: $txtvalue"
|
||||||
|
|
||||||
@ -203,8 +215,8 @@ createRecord() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deleteRecord() {
|
deleteRecord() {
|
||||||
fulldomain=$1
|
fulldomain="$1"
|
||||||
txtvalue=$2
|
txtvalue="$2"
|
||||||
|
|
||||||
_log deleteRecord "Deleting $fulldomain TXT $txtvalue record"
|
_log deleteRecord "Deleting $fulldomain TXT $txtvalue record"
|
||||||
|
|
||||||
@ -213,8 +225,10 @@ deleteRecord() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
result="$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID")"
|
result="$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID")"
|
||||||
recordInfo="$(echo "$result" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}")"
|
#recordInfo="$(echo "$result" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}")"
|
||||||
recordID="$(echo "$recordInfo" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"id":")([^"]*)"(.*)$,\2,g')"
|
#recordID="$(echo "$recordInfo" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"id":")([^"]*)"(.*)$,\2,g')"
|
||||||
|
recordID="$(printf "%s\n" "$result" | tr '}' '\n' | grep -- "$txtvalue" | tr ',' '\n' | grep '"id"' | cut -d'"' -f4)"
|
||||||
|
_debug2 _recordID "recordID used for deletion of record: $recordID"
|
||||||
|
|
||||||
if [ -z "$recordID" ]; then
|
if [ -z "$recordID" ]; then
|
||||||
_info "Record $fulldomain TXT $txtvalue not found or already deleted"
|
_info "Record $fulldomain TXT $txtvalue not found or already deleted"
|
||||||
|
@ -137,7 +137,7 @@ _get_root() {
|
|||||||
domain=$1
|
domain=$1
|
||||||
i=2
|
i=2
|
||||||
p=1
|
p=1
|
||||||
if _opns_rest "GET" "/domain/searchDomain"; then
|
if _opns_rest "GET" "/domain/searchMasterDomain"; then
|
||||||
_domain_response="$response"
|
_domain_response="$response"
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
@ -150,7 +150,7 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug h "$h"
|
_debug h "$h"
|
||||||
id=$(echo "$_domain_response" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"master\",[^.]*,\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
id=$(echo "$_domain_response" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"master\",\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
|
||||||
if [ -n "$id" ]; then
|
if [ -n "$id" ]; then
|
||||||
_debug id "$id"
|
_debug id "$id"
|
||||||
_host=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
_host=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
|
94
dnsapi/dns_selfhost.sh
Normal file
94
dnsapi/dns_selfhost.sh
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
#
|
||||||
|
# Author: Marvin Edeler
|
||||||
|
# Report Bugs here: https://github.com/Marvo2011/acme.sh/issues/1
|
||||||
|
# Last Edit: 17.02.2022
|
||||||
|
|
||||||
|
dns_selfhost_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txt=$2
|
||||||
|
_info "Calling acme-dns on selfhost"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txt"
|
||||||
|
|
||||||
|
SELFHOSTDNS_UPDATE_URL="https://selfhost.de/cgi-bin/api.pl"
|
||||||
|
|
||||||
|
# Get values, but don't save until we successfully validated
|
||||||
|
SELFHOSTDNS_USERNAME="${SELFHOSTDNS_USERNAME:-$(_readaccountconf_mutable SELFHOSTDNS_USERNAME)}"
|
||||||
|
SELFHOSTDNS_PASSWORD="${SELFHOSTDNS_PASSWORD:-$(_readaccountconf_mutable SELFHOSTDNS_PASSWORD)}"
|
||||||
|
# These values are domain dependent, so read them from there
|
||||||
|
SELFHOSTDNS_MAP="${SELFHOSTDNS_MAP:-$(_readdomainconf SELFHOSTDNS_MAP)}"
|
||||||
|
# Selfhost api can't dynamically add TXT record,
|
||||||
|
# so we have to store the last used RID of the domain to support a second RID for wildcard domains
|
||||||
|
# (format: 'fulldomainA:lastRid fulldomainB:lastRid ...')
|
||||||
|
SELFHOSTDNS_MAP_LAST_USED_INTERNAL=$(_readdomainconf SELFHOSTDNS_MAP_LAST_USED_INTERNAL)
|
||||||
|
|
||||||
|
if [ -z "${SELFHOSTDNS_USERNAME:-}" ] || [ -z "${SELFHOSTDNS_PASSWORD:-}" ]; then
|
||||||
|
_err "SELFHOSTDNS_USERNAME and SELFHOSTDNS_PASSWORD must be set"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# get the domain entry from SELFHOSTDNS_MAP
|
||||||
|
# only match full domains (at the beginning of the string or with a leading whitespace),
|
||||||
|
# e.g. don't match mytest.example.com or sub.test.example.com for test.example.com
|
||||||
|
# if the domain is defined multiple times only the last occurance will be matched
|
||||||
|
mapEntry=$(echo "$SELFHOSTDNS_MAP" | sed -n -E "s/(^|^.*[[:space:]])($fulldomain)(:[[:digit:]]+)([:]?[[:digit:]]*)(.*)/\2\3\4/p")
|
||||||
|
_debug2 mapEntry "$mapEntry"
|
||||||
|
if test -z "$mapEntry"; then
|
||||||
|
_err "SELFHOSTDNS_MAP must contain the fulldomain incl. prefix and at least one RID"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# get the RIDs from the map entry
|
||||||
|
rid1=$(echo "$mapEntry" | cut -d: -f2)
|
||||||
|
rid2=$(echo "$mapEntry" | cut -d: -f3)
|
||||||
|
|
||||||
|
# read last used rid domain
|
||||||
|
lastUsedRidForDomainEntry=$(echo "$SELFHOSTDNS_MAP_LAST_USED_INTERNAL" | sed -n -E "s/(^|^.*[[:space:]])($fulldomain:[[:digit:]]+)(.*)/\2/p")
|
||||||
|
_debug2 lastUsedRidForDomainEntry "$lastUsedRidForDomainEntry"
|
||||||
|
lastUsedRidForDomain=$(echo "$lastUsedRidForDomainEntry" | cut -d: -f2)
|
||||||
|
|
||||||
|
rid="$rid1"
|
||||||
|
if [ "$lastUsedRidForDomain" = "$rid" ] && ! test -z "$rid2"; then
|
||||||
|
rid="$rid2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Trying to add $txt on selfhost for rid: $rid"
|
||||||
|
|
||||||
|
data="?username=$SELFHOSTDNS_USERNAME&password=$SELFHOSTDNS_PASSWORD&rid=$rid&content=$txt"
|
||||||
|
response="$(_get "$SELFHOSTDNS_UPDATE_URL$data")"
|
||||||
|
|
||||||
|
if ! echo "$response" | grep "200 OK" >/dev/null; then
|
||||||
|
_err "Invalid response of acme-dns for selfhost"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# write last used rid domain
|
||||||
|
newLastUsedRidForDomainEntry="$fulldomain:$rid"
|
||||||
|
if ! test -z "$lastUsedRidForDomainEntry"; then
|
||||||
|
# replace last used rid entry for domain
|
||||||
|
SELFHOSTDNS_MAP_LAST_USED_INTERNAL=$(echo "$SELFHOSTDNS_MAP_LAST_USED_INTERNAL" | sed -n -E "s/$lastUsedRidForDomainEntry/$newLastUsedRidForDomainEntry/p")
|
||||||
|
else
|
||||||
|
# add last used rid entry for domain
|
||||||
|
if test -z "$SELFHOSTDNS_MAP_LAST_USED_INTERNAL"; then
|
||||||
|
SELFHOSTDNS_MAP_LAST_USED_INTERNAL="$newLastUsedRidForDomainEntry"
|
||||||
|
else
|
||||||
|
SELFHOSTDNS_MAP_LAST_USED_INTERNAL="$SELFHOSTDNS_MAP_LAST_USED_INTERNAL $newLastUsedRidForDomainEntry"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Now that we know the values are good, save them
|
||||||
|
_saveaccountconf_mutable SELFHOSTDNS_USERNAME "$SELFHOSTDNS_USERNAME"
|
||||||
|
_saveaccountconf_mutable SELFHOSTDNS_PASSWORD "$SELFHOSTDNS_PASSWORD"
|
||||||
|
# These values are domain dependent, so store them there
|
||||||
|
_savedomainconf SELFHOSTDNS_MAP "$SELFHOSTDNS_MAP"
|
||||||
|
_savedomainconf SELFHOSTDNS_MAP_LAST_USED_INTERNAL "$SELFHOSTDNS_MAP_LAST_USED_INTERNAL"
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_selfhost_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txt=$2
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txt"
|
||||||
|
_info "Creating and removing of records is not supported by selfhost API, will not delete anything."
|
||||||
|
}
|
@ -195,7 +195,7 @@ _get_paketnr() {
|
|||||||
fqdn="$1"
|
fqdn="$1"
|
||||||
form="$2"
|
form="$2"
|
||||||
|
|
||||||
domains=$(echo "$form" | grep 'header-paket-domain' | sed 's/<[^>]*>//g' | sed 's/^.*>\([^>]*\)$/\1/')
|
domains=$(echo "$form" | grep '<ul class="nav header-paket-list">' | sed 's/<li/\n<li/g' | sed 's/<[^>]*>/ /g' | sed 's/^.*>\([^>]*\)$/\1/')
|
||||||
domain=''
|
domain=''
|
||||||
for domain in $domains; do
|
for domain in $domains; do
|
||||||
if _contains "$fqdn" "$domain\$"; then
|
if _contains "$fqdn" "$domain\$"; then
|
||||||
@ -210,7 +210,7 @@ _get_paketnr() {
|
|||||||
TLD="$domain"
|
TLD="$domain"
|
||||||
_debug domain "$domain"
|
_debug domain "$domain"
|
||||||
RECORD=$(echo "$fqdn" | cut -c"1-$((${#fqdn} - ${#TLD} - 1))")
|
RECORD=$(echo "$fqdn" | cut -c"1-$((${#fqdn} - ${#TLD} - 1))")
|
||||||
PAKETNR=$(echo "$form" | grep "data-textfilter=\".* $domain " | _tail_n 1 | sed "s|.*$WORLD4YOU_API/\\([0-9]*\\)/.*|\\1|")
|
PAKETNR=$(echo "$domains" | grep "$domain" | sed 's/^[^,]*, *\([0-9]*\).*$/\1/')
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
264
dnsapi/dns_yc.sh
Normal file
264
dnsapi/dns_yc.sh
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#YC_Zone_ID="" # DNS Zone ID
|
||||||
|
#YC_Folder_ID="" # YC Folder ID
|
||||||
|
#YC_SA_ID="" # Service Account ID
|
||||||
|
#YC_SA_Key_ID="" # Service Account IAM Key ID
|
||||||
|
#YC_SA_Key_File_Path="/path/to/private.key" # Path to private.key use instead of YC_SA_Key_File_PEM_b64
|
||||||
|
#YC_SA_Key_File_PEM_b64="" # Base64 content of private.key use instead of YC_SA_Key_File_Path
|
||||||
|
YC_Api="https://dns.api.cloud.yandex.net/dns/v1"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_yc_add() {
|
||||||
|
fulldomain="$(echo "$1". | _lower_case)" # Add dot at end of domain name
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
YC_SA_Key_File_PEM_b64="${YC_SA_Key_File_PEM_b64:-$(_readaccountconf_mutable YC_SA_Key_File_PEM_b64)}"
|
||||||
|
YC_SA_Key_File_Path="${YC_SA_Key_File_Path:-$(_readaccountconf_mutable YC_SA_Key_File_Path)}"
|
||||||
|
|
||||||
|
if [ "$YC_SA_Key_File_PEM_b64" ]; then
|
||||||
|
echo "$YC_SA_Key_File_PEM_b64" | _dbase64 >private.key
|
||||||
|
YC_SA_Key_File="private.key"
|
||||||
|
_savedomainconf YC_SA_Key_File_PEM_b64 "$YC_SA_Key_File_PEM_b64"
|
||||||
|
else
|
||||||
|
YC_SA_Key_File="$YC_SA_Key_File_Path"
|
||||||
|
_savedomainconf YC_SA_Key_File_Path "$YC_SA_Key_File_Path"
|
||||||
|
fi
|
||||||
|
|
||||||
|
YC_Zone_ID="${YC_Zone_ID:-$(_readaccountconf_mutable YC_Zone_ID)}"
|
||||||
|
YC_Folder_ID="${YC_Folder_ID:-$(_readaccountconf_mutable YC_Folder_ID)}"
|
||||||
|
YC_SA_ID="${YC_SA_ID:-$(_readaccountconf_mutable YC_SA_ID)}"
|
||||||
|
YC_SA_Key_ID="${YC_SA_Key_ID:-$(_readaccountconf_mutable YC_SA_Key_ID)}"
|
||||||
|
|
||||||
|
if [ "$YC_SA_ID" ] && [ "$YC_SA_Key_ID" ] && [ "$YC_SA_Key_File" ]; then
|
||||||
|
if [ -f "$YC_SA_Key_File" ]; then
|
||||||
|
if _isRSA "$YC_SA_Key_File" >/dev/null 2>&1; then
|
||||||
|
if [ "$YC_Zone_ID" ]; then
|
||||||
|
_savedomainconf YC_Zone_ID "$YC_Zone_ID"
|
||||||
|
_savedomainconf YC_SA_ID "$YC_SA_ID"
|
||||||
|
_savedomainconf YC_SA_Key_ID "$YC_SA_Key_ID"
|
||||||
|
elif [ "$YC_Folder_ID" ]; then
|
||||||
|
_savedomainconf YC_Folder_ID "$YC_Folder_ID"
|
||||||
|
_saveaccountconf_mutable YC_SA_ID "$YC_SA_ID"
|
||||||
|
_saveaccountconf_mutable YC_SA_Key_ID "$YC_SA_Key_ID"
|
||||||
|
_clearaccountconf_mutable YC_Zone_ID
|
||||||
|
_clearaccountconf YC_Zone_ID
|
||||||
|
else
|
||||||
|
_err "You didn't specify a Yandex Cloud Zone ID or Folder ID yet."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_err "YC_SA_Key_File not a RSA file(_isRSA function return false)."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_err "YC_SA_Key_File not found in path $YC_SA_Key_File."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_clearaccountconf YC_Zone_ID
|
||||||
|
_clearaccountconf YC_Folder_ID
|
||||||
|
_clearaccountconf YC_SA_ID
|
||||||
|
_clearaccountconf YC_SA_Key_ID
|
||||||
|
_clearaccountconf YC_SA_Key_File_PEM_b64
|
||||||
|
_clearaccountconf YC_SA_Key_File_Path
|
||||||
|
_err "You didn't specify a YC_SA_ID or YC_SA_Key_ID or YC_SA_Key_File."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_debug "Getting txt records"
|
||||||
|
if ! _yc_rest GET "zones/${_domain_id}:getRecordSet?type=TXT&name=$_sub_domain"; then
|
||||||
|
_err "Error: $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Adding record"
|
||||||
|
if _yc_rest POST "zones/$_domain_id:upsertRecordSets" "{\"merges\": [ { \"name\":\"$_sub_domain\",\"type\":\"TXT\",\"ttl\":\"120\",\"data\":[\"$txtvalue\"]}]}"; then
|
||||||
|
if _contains "$response" "\"done\": true"; then
|
||||||
|
_info "Added, OK"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#fulldomain txtvalue
|
||||||
|
dns_yc_rm() {
|
||||||
|
fulldomain="$(echo "$1". | _lower_case)" # Add dot at end of domain name
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
YC_Zone_ID="${YC_Zone_ID:-$(_readaccountconf_mutable YC_Zone_ID)}"
|
||||||
|
YC_Folder_ID="${YC_Folder_ID:-$(_readaccountconf_mutable YC_Folder_ID)}"
|
||||||
|
YC_SA_ID="${YC_SA_ID:-$(_readaccountconf_mutable YC_SA_ID)}"
|
||||||
|
YC_SA_Key_ID="${YC_SA_Key_ID:-$(_readaccountconf_mutable YC_SA_Key_ID)}"
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_debug "Getting txt records"
|
||||||
|
if _yc_rest GET "zones/${_domain_id}:getRecordSet?type=TXT&name=$_sub_domain"; then
|
||||||
|
exists_txtvalue=$(echo "$response" | _normalizeJson | _egrep_o "\"data\".*\][^,]*" | _egrep_o "[^:]*$")
|
||||||
|
_debug exists_txtvalue "$exists_txtvalue"
|
||||||
|
else
|
||||||
|
_err "Error: $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _yc_rest POST "zones/$_domain_id:updateRecordSets" "{\"deletions\": [ { \"name\":\"$_sub_domain\",\"type\":\"TXT\",\"ttl\":\"120\",\"data\":$exists_txtvalue}]}"; then
|
||||||
|
if _contains "$response" "\"done\": true"; then
|
||||||
|
_info "Delete, OK"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_err "Delete record error."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
_err "Delete record error."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
#_acme-challenge.www.domain.com
|
||||||
|
#returns
|
||||||
|
# _sub_domain=_acme-challenge.www
|
||||||
|
# _domain=domain.com
|
||||||
|
# _domain_id=sdjkglgdfewsdfg
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
i=1
|
||||||
|
p=1
|
||||||
|
|
||||||
|
# Use Zone ID directly if provided
|
||||||
|
if [ "$YC_Zone_ID" ]; then
|
||||||
|
if ! _yc_rest GET "zones/$YC_Zone_ID"; then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
if echo "$response" | tr -d " " | _egrep_o "\"id\":\"$YC_Zone_ID\"" >/dev/null; then
|
||||||
|
_domain=$(echo "$response" | _egrep_o "\"zone\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ")
|
||||||
|
if [ "$_domain" ]; then
|
||||||
|
_cutlength=$((${#domain} - ${#_domain}))
|
||||||
|
_sub_domain=$(printf "%s" "$domain" | cut -c "1-$_cutlength")
|
||||||
|
_domain_id=$YC_Zone_ID
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug h "$h"
|
||||||
|
if [ -z "$h" ]; then
|
||||||
|
#not valid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$YC_Folder_ID" ]; then
|
||||||
|
if ! _yc_rest GET "zones?folderId=$YC_Folder_ID"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "You didn't specify a Yandex Cloud Folder ID."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if _contains "$response" "\"zone\": \"$h\""; then
|
||||||
|
_domain_id=$(echo "$response" | _normalizeJson | _egrep_o "[^{]*\"zone\":\"$h\"[^}]*" | _egrep_o "\"id\"[^,]*" | _egrep_o "[^:]*$" | tr -d '"')
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
if [ "$_domain_id" ]; then
|
||||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
|
_domain=$h
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_yc_rest() {
|
||||||
|
m=$1
|
||||||
|
ep="$2"
|
||||||
|
data="$3"
|
||||||
|
_debug "$ep"
|
||||||
|
|
||||||
|
if [ ! "$YC_Token" ]; then
|
||||||
|
_debug "Login"
|
||||||
|
_yc_login
|
||||||
|
else
|
||||||
|
_debug "Token already exists. Skip Login."
|
||||||
|
fi
|
||||||
|
|
||||||
|
token_trimmed=$(echo "$YC_Token" | tr -d '"')
|
||||||
|
|
||||||
|
export _H1="Content-Type: application/json"
|
||||||
|
export _H2="Authorization: Bearer $token_trimmed"
|
||||||
|
|
||||||
|
if [ "$m" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$YC_Api/$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$YC_Api/$ep")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_yc_login() {
|
||||||
|
header=$(echo "{\"typ\":\"JWT\",\"alg\":\"PS256\",\"kid\":\"$YC_SA_Key_ID\"}" | _normalizeJson | _base64 | _url_replace)
|
||||||
|
_debug header "$header"
|
||||||
|
|
||||||
|
_current_timestamp=$(_time)
|
||||||
|
_expire_timestamp=$(_math "$_current_timestamp" + 1200) # 20 minutes
|
||||||
|
payload=$(echo "{\"iss\":\"$YC_SA_ID\",\"aud\":\"https://iam.api.cloud.yandex.net/iam/v1/tokens\",\"iat\":$_current_timestamp,\"exp\":$_expire_timestamp}" | _normalizeJson | _base64 | _url_replace)
|
||||||
|
_debug payload "$payload"
|
||||||
|
|
||||||
|
#signature=$(printf "%s.%s" "$header" "$payload" | ${ACME_OPENSSL_BIN:-openssl} dgst -sign "$YC_SA_Key_File -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1" | _base64 | _url_replace )
|
||||||
|
_signature=$(printf "%s.%s" "$header" "$payload" | _sign "$YC_SA_Key_File" "sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1" | _url_replace)
|
||||||
|
_debug2 _signature "$_signature"
|
||||||
|
|
||||||
|
rm -rf "$YC_SA_Key_File"
|
||||||
|
|
||||||
|
_jwt=$(printf "{\"jwt\": \"%s.%s.%s\"}" "$header" "$payload" "$_signature")
|
||||||
|
_debug2 _jwt "$_jwt"
|
||||||
|
|
||||||
|
export _H1="Content-Type: application/json"
|
||||||
|
_iam_response="$(_post "$_jwt" "https://iam.api.cloud.yandex.net/iam/v1/tokens" "" "POST")"
|
||||||
|
_debug3 _iam_response "$(echo "$_iam_response" | _normalizeJson)"
|
||||||
|
|
||||||
|
YC_Token="$(echo "$_iam_response" | _normalizeJson | _egrep_o "\"iamToken\"[^,]*" | _egrep_o "[^:]*$" | tr -d '"')"
|
||||||
|
_debug3 YC_Token
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user