committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
62 changed files with 2468 additions and 185 deletions
-
2.github/workflows/Linux.yml
-
2.github/workflows/PebbleStrict.yml
-
62.github/workflows/wiki-monitor.yml
-
10Dockerfile
-
57README.md
-
224acme.sh
-
56deploy/cachefly.sh
-
86deploy/directadmin.sh
-
86deploy/edgio.sh
-
98deploy/kemplm.sh
-
131deploy/keyhelp.sh
-
86deploy/keyhelp_api.sh
-
69deploy/netlify.sh
-
102deploy/panos.sh
-
12deploy/proxmoxbs.sh
-
12deploy/proxmoxve.sh
-
32deploy/truenas_ws.sh
-
6deploy/unifi.sh
-
2dnsapi/dns_aws.sh
-
2dnsapi/dns_beget.sh
-
2dnsapi/dns_bookmyname.sh
-
4dnsapi/dns_cf.sh
-
5dnsapi/dns_cloudns.sh
-
5dnsapi/dns_constellix.sh
-
4dnsapi/dns_curanet.sh
-
2dnsapi/dns_ddnss.sh
-
2dnsapi/dns_dnshome.sh
-
2dnsapi/dns_duckdns.sh
-
2dnsapi/dns_dyn.sh
-
2dnsapi/dns_dynv6.sh
-
2dnsapi/dns_easydns.sh
-
2dnsapi/dns_fornex.sh
-
2dnsapi/dns_freedns.sh
-
1dnsapi/dns_he_ddns.sh
-
593dnsapi/dns_hetznercloud.sh
-
244dnsapi/dns_infoblox_uddi.sh
-
2dnsapi/dns_joker.sh
-
96dnsapi/dns_la.sh
-
9dnsapi/dns_mijnhost.sh
-
2dnsapi/dns_mydnsjp.sh
-
2dnsapi/dns_namecom.sh
-
2dnsapi/dns_namesilo.sh
-
62dnsapi/dns_nanelo.sh
-
186dnsapi/dns_openprovider_rest.sh
-
16dnsapi/dns_opnsense.sh
-
2dnsapi/dns_ovh.sh
-
2dnsapi/dns_pleskxml.sh
-
18dnsapi/dns_rage4.sh
-
2dnsapi/dns_schlundtech.sh
-
38dnsapi/dns_selectel.sh
-
8dnsapi/dns_spaceship.sh
-
2dnsapi/dns_tele3.sh
-
2dnsapi/dns_timeweb.sh
-
2dnsapi/dns_udr.sh
-
2dnsapi/dns_variomedia.sh
-
2dnsapi/dns_vscale.sh
-
1dnsapi/dns_vultr.sh
-
2dnsapi/dns_websupport.sh
-
2dnsapi/dns_world4you.sh
-
28notify/ntfy.sh
-
130notify/opsgenie.sh
-
4notify/telegram.sh
@ -0,0 +1,62 @@ |
|||||
|
name: Notify via Issue on Wiki Edit |
||||
|
|
||||
|
on: |
||||
|
gollum: |
||||
|
|
||||
|
jobs: |
||||
|
notify: |
||||
|
runs-on: ubuntu-latest |
||||
|
steps: |
||||
|
- name: Checkout wiki repository |
||||
|
uses: actions/checkout@v4 |
||||
|
with: |
||||
|
repository: ${{ github.repository }}.wiki |
||||
|
path: wiki |
||||
|
fetch-depth: 0 |
||||
|
|
||||
|
- name: Generate wiki change message |
||||
|
run: | |
||||
|
actor="${{ github.actor }}" |
||||
|
sender_url=$(jq -r '.sender.html_url' "$GITHUB_EVENT_PATH") |
||||
|
page_name=$(jq -r '.pages[0].page_name' "$GITHUB_EVENT_PATH") |
||||
|
page_sha=$(jq -r '.pages[0].sha' "$GITHUB_EVENT_PATH") |
||||
|
page_url=$(jq -r '.pages[0].html_url' "$GITHUB_EVENT_PATH") |
||||
|
page_action=$(jq -r '.pages[0].action' "$GITHUB_EVENT_PATH") |
||||
|
now="$(date '+%Y-%m-%d %H:%M:%S')" |
||||
|
|
||||
|
cd wiki |
||||
|
prev_sha=$(git rev-list $page_sha^ -- "$page_name.md" | head -n 1) |
||||
|
if [ -n "$prev_sha" ]; then |
||||
|
git diff $prev_sha $page_sha -- "$page_name.md" > ../wiki.diff || echo "(No diff found)" > ../wiki.diff |
||||
|
else |
||||
|
echo "(no diff)" > ../wiki.diff |
||||
|
fi |
||||
|
cd .. |
||||
|
{ |
||||
|
echo "Wiki edited" |
||||
|
echo -n "User: " |
||||
|
echo "[$actor]($sender_url)" |
||||
|
echo "Time: $now" |
||||
|
echo "Page: [$page_name]($page_url) (Action: $page_action)" |
||||
|
echo "" |
||||
|
echo "----" |
||||
|
echo "### diff:" |
||||
|
echo '```diff' |
||||
|
cat wiki.diff |
||||
|
echo '```' |
||||
|
} > wiki-change-msg.txt |
||||
|
|
||||
|
- name: Create issue to notify Neilpang |
||||
|
uses: peter-evans/create-issue-from-file@v5 |
||||
|
with: |
||||
|
title: "Wiki edited" |
||||
|
content-filepath: ./wiki-change-msg.txt |
||||
|
assignees: Neilpang |
||||
|
env: |
||||
|
TZ: Asia/Shanghai |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
@ -0,0 +1,56 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# Script to deploy certificate to CacheFly |
||||
|
# https://api.cachefly.com/api/2.5/docs#tag/Certificates/paths/~1certificates/post |
||||
|
|
||||
|
# This deployment required following variables |
||||
|
# export CACHEFLY_TOKEN="Your CacheFly API Token" |
||||
|
|
||||
|
# returns 0 means success, otherwise error. |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
CACHEFLY_API_BASE="https://api.cachefly.com/api/2.5" |
||||
|
|
||||
|
cachefly_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
if [ -z "$CACHEFLY_TOKEN" ]; then |
||||
|
_err "CACHEFLY_TOKEN is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf CACHEFLY_TOKEN "$CACHEFLY_TOKEN" |
||||
|
fi |
||||
|
|
||||
|
_info "Deploying certificate to CacheFly..." |
||||
|
|
||||
|
## upload certificate |
||||
|
string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') |
||||
|
string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') |
||||
|
|
||||
|
_request_body="{\"certificate\":\"$string_fullchain\",\"certificateKey\":\"$string_key\"}" |
||||
|
_debug _request_body "$_request_body" |
||||
|
_debug CACHEFLY_TOKEN "$CACHEFLY_TOKEN" |
||||
|
export _H1="Authorization: Bearer $CACHEFLY_TOKEN" |
||||
|
_response=$(_post "$_request_body" "$CACHEFLY_API_BASE/certificates" "" "POST" "application/json") |
||||
|
|
||||
|
if _contains "$_response" "message"; then |
||||
|
_err "Error in deploying $_cdomain certificate to CacheFly." |
||||
|
_err "$_response" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug response "$_response" |
||||
|
_info "Domain $_cdomain certificate successfully deployed to CacheFly." |
||||
|
return 0 |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# Script to deploy certificate to DirectAdmin |
||||
|
# https://docs.directadmin.com/directadmin/customizing-workflow/api-all-about.html#creating-a-login-key |
||||
|
# https://docs.directadmin.com/changelog/version-1.24.4.html#cmd-api-catch-all-pop-passwords-frontpage-protected-dirs-ssl-certs |
||||
|
|
||||
|
# This deployment required following variables |
||||
|
# export DirectAdmin_SCHEME="https" # Optional, https or http, defaults to https |
||||
|
# export DirectAdmin_ENDPOINT="example.com:2222" |
||||
|
# export DirectAdmin_USERNAME="Your DirectAdmin Username" |
||||
|
# export DirectAdmin_KEY="Your DirectAdmin Login Key or Password" |
||||
|
# export DirectAdmin_MAIN_DOMAIN="Your DirectAdmin Main Domain, NOT Subdomain" |
||||
|
|
||||
|
# returns 0 means success, otherwise error. |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
directadmin_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
if [ -z "$DirectAdmin_ENDPOINT" ]; then |
||||
|
_err "DirectAdmin_ENDPOINT is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf DirectAdmin_ENDPOINT "$DirectAdmin_ENDPOINT" |
||||
|
fi |
||||
|
if [ -z "$DirectAdmin_USERNAME" ]; then |
||||
|
_err "DirectAdmin_USERNAME is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf DirectAdmin_USERNAME "$DirectAdmin_USERNAME" |
||||
|
fi |
||||
|
if [ -z "$DirectAdmin_KEY" ]; then |
||||
|
_err "DirectAdmin_KEY is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf DirectAdmin_KEY "$DirectAdmin_KEY" |
||||
|
fi |
||||
|
if [ -z "$DirectAdmin_MAIN_DOMAIN" ]; then |
||||
|
_err "DirectAdmin_MAIN_DOMAIN is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf DirectAdmin_MAIN_DOMAIN "$DirectAdmin_MAIN_DOMAIN" |
||||
|
fi |
||||
|
|
||||
|
# Optional SCHEME |
||||
|
_getdeployconf DirectAdmin_SCHEME |
||||
|
# set default values for DirectAdmin_SCHEME |
||||
|
[ -n "${DirectAdmin_SCHEME}" ] || DirectAdmin_SCHEME="https" |
||||
|
|
||||
|
_info "Deploying certificate to DirectAdmin..." |
||||
|
|
||||
|
# upload certificate |
||||
|
string_cfullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') |
||||
|
string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') |
||||
|
|
||||
|
_request_body="{\"domain\":\"$DirectAdmin_MAIN_DOMAIN\",\"action\":\"save\",\"type\":\"paste\",\"certificate\":\"$string_key\n$string_cfullchain\n\"}" |
||||
|
_debug _request_body "$_request_body" |
||||
|
_debug DirectAdmin_ENDPOINT "$DirectAdmin_ENDPOINT" |
||||
|
_debug DirectAdmin_USERNAME "$DirectAdmin_USERNAME" |
||||
|
_debug DirectAdmin_KEY "$DirectAdmin_KEY" |
||||
|
_debug DirectAdmin_MAIN_DOMAIN "$DirectAdmin_MAIN_DOMAIN" |
||||
|
_response=$(_post "$_request_body" "$DirectAdmin_SCHEME://$DirectAdmin_USERNAME:$DirectAdmin_KEY@$DirectAdmin_ENDPOINT/CMD_API_SSL" "" "POST" "application/json") |
||||
|
|
||||
|
if _contains "$_response" "error=1"; then |
||||
|
_err "Error in deploying $_cdomain certificate to DirectAdmin Domain $DirectAdmin_MAIN_DOMAIN." |
||||
|
_err "$_response" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info "$_response" |
||||
|
_info "Domain $_cdomain certificate successfully deployed to DirectAdmin Domain $DirectAdmin_MAIN_DOMAIN." |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# Here is a script to deploy cert to edgio using its API |
||||
|
# https://docs.edg.io/guides/v7/develop/rest_api/authentication |
||||
|
# https://docs.edg.io/rest_api/#tag/tls-certs/operation/postConfigV01TlsCerts |
||||
|
|
||||
|
# This deployment required following variables |
||||
|
# export EDGIO_CLIENT_ID="Your Edgio Client ID" |
||||
|
# export EDGIO_CLIENT_SECRET="Your Edgio Client Secret" |
||||
|
# export EDGIO_ENVIRONMENT_ID="Your Edgio Environment ID" |
||||
|
|
||||
|
# If have more than one Environment ID |
||||
|
# export EDGIO_ENVIRONMENT_ID="ENVIRONMENT_ID_1 ENVIRONMENT_ID_2" |
||||
|
|
||||
|
# returns 0 means success, otherwise error. |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
edgio_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
if [ -z "$EDGIO_CLIENT_ID" ]; then |
||||
|
_err "EDGIO_CLIENT_ID is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf EDGIO_CLIENT_ID "$EDGIO_CLIENT_ID" |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$EDGIO_CLIENT_SECRET" ]; then |
||||
|
_err "EDGIO_CLIENT_SECRET is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf EDGIO_CLIENT_SECRET "$EDGIO_CLIENT_SECRET" |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$EDGIO_ENVIRONMENT_ID" ]; then |
||||
|
_err "EDGIO_ENVIRONMENT_ID is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf EDGIO_ENVIRONMENT_ID "$EDGIO_ENVIRONMENT_ID" |
||||
|
fi |
||||
|
|
||||
|
_info "Getting access token" |
||||
|
_data="client_id=$EDGIO_CLIENT_ID&client_secret=$EDGIO_CLIENT_SECRET&grant_type=client_credentials&scope=app.config" |
||||
|
_debug Get_access_token_data "$_data" |
||||
|
_response=$(_post "$_data" "https://id.edgio.app/connect/token" "" "POST" "application/x-www-form-urlencoded") |
||||
|
_debug Get_access_token_response "$_response" |
||||
|
_access_token=$(echo "$_response" | _json_decode | _egrep_o '"access_token":"[^"]*' | cut -d : -f 2 | tr -d '"') |
||||
|
_debug _access_token "$_access_token" |
||||
|
if [ -z "$_access_token" ]; then |
||||
|
_err "Error in getting access token" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info "Uploading certificate" |
||||
|
string_ccert=$(sed 's/$/\\n/' "$_ccert" | tr -d '\n') |
||||
|
string_cca=$(sed 's/$/\\n/' "$_cca" | tr -d '\n') |
||||
|
string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') |
||||
|
|
||||
|
for ENVIRONMENT_ID in $EDGIO_ENVIRONMENT_ID; do |
||||
|
_data="{\"environment_id\":\"$ENVIRONMENT_ID\",\"primary_cert\":\"$string_ccert\",\"intermediate_cert\":\"$string_cca\",\"private_key\":\"$string_key\"}" |
||||
|
_debug Upload_certificate_data "$_data" |
||||
|
_H1="Authorization: Bearer $_access_token" |
||||
|
_response=$(_post "$_data" "https://edgioapis.com/config/v0.1/tls-certs" "" "POST" "application/json") |
||||
|
if _contains "$_response" "message"; then |
||||
|
_err "Error in deploying $_cdomain certificate to Edgio ENVIRONMENT_ID $ENVIRONMENT_ID." |
||||
|
_err "$_response" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug Upload_certificate_response "$_response" |
||||
|
_info "Domain $_cdomain certificate successfully deployed to Edgio ENVIRONMENT_ID $ENVIRONMENT_ID." |
||||
|
done |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
@ -0,0 +1,98 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
#Here is a script to deploy cert to a Kemp Loadmaster. |
||||
|
|
||||
|
#returns 0 means success, otherwise error. |
||||
|
|
||||
|
#DEPLOY_KEMP_TOKEN="token" |
||||
|
#DEPLOY_KEMP_URL="https://kemplm.example.com" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
kemplm_deploy() { |
||||
|
_domain="$1" |
||||
|
_key_file="$2" |
||||
|
_cert_file="$3" |
||||
|
_ca_file="$4" |
||||
|
_fullchain_file="$5" |
||||
|
|
||||
|
_debug _domain "$_domain" |
||||
|
_debug _key_file "$_key_file" |
||||
|
_debug _cert_file "$_cert_file" |
||||
|
_debug _ca_file "$_ca_file" |
||||
|
_debug _fullchain_file "$_fullchain_file" |
||||
|
|
||||
|
if ! _exists jq; then |
||||
|
_err "jq not found" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
# Rename wildcard certs, kemp accepts only alphanumeric names so we delete '*.' from filename |
||||
|
_kemp_domain=$(echo "${_domain}" | sed 's/\*\.//') |
||||
|
_debug _kemp_domain "$_kemp_domain" |
||||
|
|
||||
|
# Read config from saved values or env |
||||
|
_getdeployconf DEPLOY_KEMP_TOKEN |
||||
|
_getdeployconf DEPLOY_KEMP_URL |
||||
|
|
||||
|
_debug DEPLOY_KEMP_URL "$DEPLOY_KEMP_URL" |
||||
|
_secure_debug DEPLOY_KEMP_TOKEN "$DEPLOY_KEMP_TOKEN" |
||||
|
|
||||
|
if [ -z "$DEPLOY_KEMP_TOKEN" ]; then |
||||
|
_err "Kemp Loadmaster token is not found, please define DEPLOY_KEMP_TOKEN." |
||||
|
return 1 |
||||
|
fi |
||||
|
if [ -z "$DEPLOY_KEMP_URL" ]; then |
||||
|
_err "Kemp Loadmaster URL is not found, please define DEPLOY_KEMP_URL." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
# Save current values |
||||
|
_savedeployconf DEPLOY_KEMP_TOKEN "$DEPLOY_KEMP_TOKEN" |
||||
|
_savedeployconf DEPLOY_KEMP_URL "$DEPLOY_KEMP_URL" |
||||
|
|
||||
|
# Check if certificate is already installed |
||||
|
_info "Check if certificate is already present" |
||||
|
_list_request="{\"cmd\": \"listcert\", \"apikey\": \"${DEPLOY_KEMP_TOKEN}\"}" |
||||
|
_debug3 _list_request "${_list_request}" |
||||
|
_kemp_cert_count=$(HTTPS_INSECURE=1 _post "${_list_request}" "${DEPLOY_KEMP_URL}/accessv2" | jq -r '.cert[] | .name' | grep -c "${_kemp_domain}") |
||||
|
_debug2 _kemp_cert_count "${_kemp_cert_count}" |
||||
|
|
||||
|
_kemp_replace_cert=1 |
||||
|
if [ "${_kemp_cert_count}" -eq 0 ]; then |
||||
|
_kemp_replace_cert=0 |
||||
|
_info "Certificate does not exist on Kemp Loadmaster" |
||||
|
else |
||||
|
_info "Certificate already exists on Kemp Loadmaster" |
||||
|
fi |
||||
|
_debug _kemp_replace_cert "${_kemp_replace_cert}" |
||||
|
|
||||
|
# Upload new certificate to Kemp Loadmaster |
||||
|
_kemp_upload_cert=$(_mktemp) |
||||
|
cat "${_fullchain_file}" "${_key_file}" | base64 | tr -d '\n' >"${_kemp_upload_cert}" |
||||
|
|
||||
|
_info "Uploading certificate to Kemp Loadmaster" |
||||
|
_add_data=$(cat "${_kemp_upload_cert}") |
||||
|
_add_request="{\"cmd\": \"addcert\", \"apikey\": \"${DEPLOY_KEMP_TOKEN}\", \"replace\": ${_kemp_replace_cert}, \"cert\": \"${_kemp_domain}\", \"data\": \"${_add_data}\"}" |
||||
|
_debug3 _add_request "${_add_request}" |
||||
|
_kemp_post_result=$(HTTPS_INSECURE=1 _post "${_add_request}" "${DEPLOY_KEMP_URL}/accessv2") |
||||
|
_retval=$? |
||||
|
_debug2 _kemp_post_result "${_kemp_post_result}" |
||||
|
if [ "${_retval}" -eq 0 ]; then |
||||
|
_kemp_post_status=$(echo "${_kemp_post_result}" | jq -r '.status') |
||||
|
_kemp_post_message=$(echo "${_kemp_post_result}" | jq -r '.message') |
||||
|
if [ "${_kemp_post_status}" = "ok" ]; then |
||||
|
_info "Upload successful" |
||||
|
else |
||||
|
_err "Upload failed: ${_kemp_post_message}" |
||||
|
fi |
||||
|
else |
||||
|
_err "Upload failed" |
||||
|
_retval=1 |
||||
|
fi |
||||
|
|
||||
|
rm "${_kemp_upload_cert}" |
||||
|
|
||||
|
return $_retval |
||||
|
} |
||||
@ -0,0 +1,131 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# Script to deploy certificate to KeyHelp |
||||
|
# This deployment required following variables |
||||
|
# export DEPLOY_KEYHELP_BASEURL="https://keyhelp.example.com" |
||||
|
# export DEPLOY_KEYHELP_USERNAME="Your KeyHelp Username" |
||||
|
# export DEPLOY_KEYHELP_PASSWORD="Your KeyHelp Password" |
||||
|
# export DEPLOY_KEYHELP_DOMAIN_ID="Depoly certificate to this Domain ID" |
||||
|
|
||||
|
# Open the 'Edit domain' page, and you will see id=xxx at the end of the URL. This is the Domain ID. |
||||
|
# https://DEPLOY_KEYHELP_BASEURL/index.php?page=domains&action=edit&id=xxx |
||||
|
|
||||
|
# If have more than one domain name |
||||
|
# export DEPLOY_KEYHELP_DOMAIN_ID="111 222 333" |
||||
|
|
||||
|
keyhelp_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
if [ -z "$DEPLOY_KEYHELP_BASEURL" ]; then |
||||
|
_err "DEPLOY_KEYHELP_BASEURL is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf DEPLOY_KEYHELP_BASEURL "$DEPLOY_KEYHELP_BASEURL" |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$DEPLOY_KEYHELP_USERNAME" ]; then |
||||
|
_err "DEPLOY_KEYHELP_USERNAME is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf DEPLOY_KEYHELP_USERNAME "$DEPLOY_KEYHELP_USERNAME" |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$DEPLOY_KEYHELP_PASSWORD" ]; then |
||||
|
_err "DEPLOY_KEYHELP_PASSWORD is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf DEPLOY_KEYHELP_PASSWORD "$DEPLOY_KEYHELP_PASSWORD" |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$DEPLOY_KEYHELP_DOMAIN_ID" ]; then |
||||
|
_err "DEPLOY_KEYHELP_DOMAIN_ID is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf DEPLOY_KEYHELP_DOMAIN_ID "$DEPLOY_KEYHELP_DOMAIN_ID" |
||||
|
fi |
||||
|
|
||||
|
# Optional DEPLOY_KEYHELP_ENFORCE_HTTPS |
||||
|
_getdeployconf DEPLOY_KEYHELP_ENFORCE_HTTPS |
||||
|
# set default values for DEPLOY_KEYHELP_ENFORCE_HTTPS |
||||
|
[ -n "${DEPLOY_KEYHELP_ENFORCE_HTTPS}" ] || DEPLOY_KEYHELP_ENFORCE_HTTPS="1" |
||||
|
|
||||
|
_info "Logging in to keyhelp panel" |
||||
|
username_encoded="$(printf "%s" "${DEPLOY_KEYHELP_USERNAME}" | _url_encode)" |
||||
|
password_encoded="$(printf "%s" "${DEPLOY_KEYHELP_PASSWORD}" | _url_encode)" |
||||
|
_H1="Content-Type: application/x-www-form-urlencoded" |
||||
|
_response=$(_get "$DEPLOY_KEYHELP_BASEURL/index.php?submit=1&username=$username_encoded&password=$password_encoded" "TRUE") |
||||
|
_cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)" |
||||
|
|
||||
|
# If cookies is not empty then logon successful |
||||
|
if [ -z "$_cookie" ]; then |
||||
|
_err "Fail to get cookie." |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug "cookie" "$_cookie" |
||||
|
|
||||
|
_info "Uploading certificate" |
||||
|
_date=$(date +"%Y%m%d") |
||||
|
encoded_key="$(_url_encode <"$_ckey")" |
||||
|
encoded_ccert="$(_url_encode <"$_ccert")" |
||||
|
encoded_cca="$(_url_encode <"$_cca")" |
||||
|
certificate_name="$_cdomain-$_date" |
||||
|
|
||||
|
_request_body="submit=1&certificate_name=$certificate_name&add_type=upload&text_private_key=$encoded_key&text_certificate=$encoded_ccert&text_ca_certificate=$encoded_cca" |
||||
|
_H1="Cookie: $_cookie" |
||||
|
_response=$(_post "$_request_body" "$DEPLOY_KEYHELP_BASEURL/index.php?page=ssl_certificates&action=add" "" "POST") |
||||
|
_message=$(echo "$_response" | grep -A 2 'message-body' | sed -n '/<div class="message-body ">/,/<\/div>/{//!p;}' | sed 's/<[^>]*>//g' | sed 's/^ *//;s/ *$//') |
||||
|
_info "_message" "$_message" |
||||
|
if [ -z "$_message" ]; then |
||||
|
_err "Fail to upload certificate." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
for DOMAIN_ID in $DEPLOY_KEYHELP_DOMAIN_ID; do |
||||
|
_info "Apply certificate to domain id $DOMAIN_ID" |
||||
|
_response=$(_get "$DEPLOY_KEYHELP_BASEURL/index.php?page=domains&action=edit&id=$DOMAIN_ID") |
||||
|
cert_value=$(echo "$_response" | grep "$certificate_name" | sed -n 's/.*value="\([^"]*\).*/\1/p') |
||||
|
target_type=$(echo "$_response" | grep 'target_type' | grep 'checked' | sed -n 's/.*value="\([^"]*\).*/\1/p') |
||||
|
if [ "$target_type" = "directory" ]; then |
||||
|
path=$(echo "$_response" | awk '/name="path"/{getline; print}' | sed -n 's/.*value="\([^"]*\).*/\1/p') |
||||
|
fi |
||||
|
echo "$_response" | grep "is_prefer_https" | grep "checked" >/dev/null |
||||
|
if [ $? -eq 0 ]; then |
||||
|
is_prefer_https=1 |
||||
|
else |
||||
|
is_prefer_https=0 |
||||
|
fi |
||||
|
echo "$_response" | grep "hsts_enabled" | grep "checked" >/dev/null |
||||
|
if [ $? -eq 0 ]; then |
||||
|
hsts_enabled=1 |
||||
|
else |
||||
|
hsts_enabled=0 |
||||
|
fi |
||||
|
_debug "cert_value" "$cert_value" |
||||
|
if [ -z "$cert_value" ]; then |
||||
|
_err "Fail to get certificate id." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_request_body="submit=1&id=$DOMAIN_ID&target_type=$target_type&path=$path&is_prefer_https=$is_prefer_https&hsts_enabled=$hsts_enabled&certificate_type=custom&certificate_id=$cert_value&enforce_https=$DEPLOY_KEYHELP_ENFORCE_HTTPS" |
||||
|
_response=$(_post "$_request_body" "$DEPLOY_KEYHELP_BASEURL/index.php?page=domains&action=edit" "" "POST") |
||||
|
_message=$(echo "$_response" | grep -A 2 'message-body' | sed -n '/<div class="message-body ">/,/<\/div>/{//!p;}' | sed 's/<[^>]*>//g' | sed 's/^ *//;s/ *$//') |
||||
|
_info "_message" "$_message" |
||||
|
if [ -z "$_message" ]; then |
||||
|
_err "Fail to apply certificate." |
||||
|
return 1 |
||||
|
fi |
||||
|
done |
||||
|
|
||||
|
_info "Domain $_cdomain certificate successfully deployed to KeyHelp Domain ID $DEPLOY_KEYHELP_DOMAIN_ID." |
||||
|
return 0 |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
keyhelp_api_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
|
||||
|
# Read config from saved values or env |
||||
|
_getdeployconf DEPLOY_KEYHELP_HOST |
||||
|
_getdeployconf DEPLOY_KEYHELP_API_KEY |
||||
|
|
||||
|
_debug DEPLOY_KEYHELP_HOST "$DEPLOY_KEYHELP_HOST" |
||||
|
_secure_debug DEPLOY_KEYHELP_API_KEY "$DEPLOY_KEYHELP_API_KEY" |
||||
|
|
||||
|
if [ -z "$DEPLOY_KEYHELP_HOST" ]; then |
||||
|
_err "KeyHelp host not found, please define DEPLOY_KEYHELP_HOST." |
||||
|
return 1 |
||||
|
fi |
||||
|
if [ -z "$DEPLOY_KEYHELP_API_KEY" ]; then |
||||
|
_err "KeyHelp api key not found, please define DEPLOY_KEYHELP_API_KEY." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
# Save current values |
||||
|
_savedeployconf DEPLOY_KEYHELP_HOST "$DEPLOY_KEYHELP_HOST" |
||||
|
_savedeployconf DEPLOY_KEYHELP_API_KEY "$DEPLOY_KEYHELP_API_KEY" |
||||
|
|
||||
|
_request_key="$(tr '\n' ':' <"$_ckey" | sed 's/:/\\n/g')" |
||||
|
_request_cert="$(tr '\n' ':' <"$_ccert" | sed 's/:/\\n/g')" |
||||
|
_request_ca="$(tr '\n' ':' <"$_cca" | sed 's/:/\\n/g')" |
||||
|
|
||||
|
_request_body="{ |
||||
|
\"name\": \"$_cdomain\", |
||||
|
\"components\": { |
||||
|
\"private_key\": \"$_request_key\", |
||||
|
\"certificate\": \"$_request_cert\", |
||||
|
\"ca_certificate\": \"$_request_ca\" |
||||
|
} |
||||
|
}" |
||||
|
|
||||
|
_hosts="$(echo "$DEPLOY_KEYHELP_HOST" | tr "," " ")" |
||||
|
_keys="$(echo "$DEPLOY_KEYHELP_API_KEY" | tr "," " ")" |
||||
|
_i=1 |
||||
|
|
||||
|
for _host in $_hosts; do |
||||
|
_key="$(_getfield "$_keys" "$_i" " ")" |
||||
|
_i="$(_math "$_i" + 1)" |
||||
|
|
||||
|
export _H1="X-API-Key: $_key" |
||||
|
|
||||
|
_put_url="$_host/api/v2/certificates/name/$_cdomain" |
||||
|
if _post "$_request_body" "$_put_url" "" "PUT" "application/json" >/dev/null; then |
||||
|
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" |
||||
|
else |
||||
|
_err "Cannot make PUT request to $_put_url" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ "$_code" = "404" ]; then |
||||
|
_info "$_cdomain not found, creating new entry at $_host" |
||||
|
|
||||
|
_post_url="$_host/api/v2/certificates" |
||||
|
if _post "$_request_body" "$_post_url" "" "POST" "application/json" >/dev/null; then |
||||
|
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" |
||||
|
else |
||||
|
_err "Cannot make POST request to $_post_url" |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
if _startswith "$_code" "2"; then |
||||
|
_info "$_cdomain set at $_host" |
||||
|
else |
||||
|
_err "HTTP status code is $_code" |
||||
|
return 1 |
||||
|
fi |
||||
|
done |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
# Script to deploy certificate to Netlify |
||||
|
# https://docs.netlify.com/api/get-started/#authentication |
||||
|
# https://open-api.netlify.com/#tag/sniCertificate |
||||
|
|
||||
|
# This deployment required following variables |
||||
|
# export Netlify_ACCESS_TOKEN="Your Netlify Access Token" |
||||
|
# export Netlify_SITE_ID="Your Netlify Site ID" |
||||
|
|
||||
|
# If have more than one SITE ID |
||||
|
# export Netlify_SITE_ID="SITE_ID_1 SITE_ID_2" |
||||
|
|
||||
|
# returns 0 means success, otherwise error. |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#domain keyfile certfile cafile fullchain |
||||
|
netlify_deploy() { |
||||
|
_cdomain="$1" |
||||
|
_ckey="$2" |
||||
|
_ccert="$3" |
||||
|
_cca="$4" |
||||
|
_cfullchain="$5" |
||||
|
|
||||
|
_debug _cdomain "$_cdomain" |
||||
|
_debug _ckey "$_ckey" |
||||
|
_debug _ccert "$_ccert" |
||||
|
_debug _cca "$_cca" |
||||
|
_debug _cfullchain "$_cfullchain" |
||||
|
|
||||
|
if [ -z "$Netlify_ACCESS_TOKEN" ]; then |
||||
|
_err "Netlify_ACCESS_TOKEN is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf Netlify_ACCESS_TOKEN "$Netlify_ACCESS_TOKEN" |
||||
|
fi |
||||
|
if [ -z "$Netlify_SITE_ID" ]; then |
||||
|
_err "Netlify_SITE_ID is not defined." |
||||
|
return 1 |
||||
|
else |
||||
|
_savedomainconf Netlify_SITE_ID "$Netlify_SITE_ID" |
||||
|
fi |
||||
|
|
||||
|
_info "Deploying certificate to Netlify..." |
||||
|
|
||||
|
## upload certificate |
||||
|
string_ccert=$(sed 's/$/\\n/' "$_ccert" | tr -d '\n') |
||||
|
string_cca=$(sed 's/$/\\n/' "$_cca" | tr -d '\n') |
||||
|
string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') |
||||
|
|
||||
|
for SITE_ID in $Netlify_SITE_ID; do |
||||
|
_request_body="{\"certificate\":\"$string_ccert\",\"key\":\"$string_key\",\"ca_certificates\":\"$string_cca\"}" |
||||
|
_debug _request_body "$_request_body" |
||||
|
_debug Netlify_ACCESS_TOKEN "$Netlify_ACCESS_TOKEN" |
||||
|
export _H1="Authorization: Bearer $Netlify_ACCESS_TOKEN" |
||||
|
_response=$(_post "$_request_body" "https://api.netlify.com/api/v1/sites/$SITE_ID/ssl" "" "POST" "application/json") |
||||
|
|
||||
|
if _contains "$_response" "\"error\""; then |
||||
|
_err "Error in deploying $_cdomain certificate to Netlify SITE_ID $SITE_ID." |
||||
|
_err "$_response" |
||||
|
return 1 |
||||
|
fi |
||||
|
_debug response "$_response" |
||||
|
_info "Domain $_cdomain certificate successfully deployed to Netlify SITE_ID $SITE_ID." |
||||
|
done |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
@ -0,0 +1,593 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
# shellcheck disable=SC2034 |
||||
|
dns_hetznercloud_info='Hetzner Cloud DNS |
||||
|
Site: Hetzner.com |
||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_hetznercloud |
||||
|
Options: |
||||
|
HETZNER_TOKEN API token for the Hetzner Cloud DNS API |
||||
|
Optional: |
||||
|
HETZNER_TTL Custom TTL for new TXT rrsets (default 120) |
||||
|
HETZNER_API Override API endpoint (default https://api.hetzner.cloud/v1) |
||||
|
HETZNER_MAX_ATTEMPTS Number of 1s polls to wait for async actions (default 120) |
||||
|
Issues: github.com/acmesh-official/acme.sh/issues |
||||
|
' |
||||
|
|
||||
|
HETZNERCLOUD_API_DEFAULT="https://api.hetzner.cloud/v1" |
||||
|
HETZNERCLOUD_TTL_DEFAULT=120 |
||||
|
HETZNER_MAX_ATTEMPTS_DEFAULT=120 |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
dns_hetznercloud_add() { |
||||
|
fulldomain="$(_idn "${1}")" |
||||
|
txtvalue="${2}" |
||||
|
|
||||
|
_info "Using Hetzner Cloud DNS API to add record" |
||||
|
|
||||
|
if ! _hetznercloud_init; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _hetznercloud_prepare_zone "${fulldomain}"; then |
||||
|
_err "Unable to determine Hetzner Cloud zone for ${fulldomain}" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _hetznercloud_get_rrset; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ "${_hetznercloud_last_http_code}" = "200" ]; then |
||||
|
if _hetznercloud_rrset_contains_value "${txtvalue}"; then |
||||
|
_info "TXT record already present; nothing to do." |
||||
|
return 0 |
||||
|
fi |
||||
|
elif [ "${_hetznercloud_last_http_code}" != "404" ]; then |
||||
|
_hetznercloud_log_http_error "Failed to query existing TXT rrset" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
add_payload="$(_hetznercloud_build_add_payload "${txtvalue}")" |
||||
|
if [ -z "${add_payload}" ]; then |
||||
|
_err "Failed to build request payload." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _hetznercloud_api POST "${_hetznercloud_rrset_action_add}" "${add_payload}"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
case "${_hetznercloud_last_http_code}" in |
||||
|
200 | 201 | 202 | 204) |
||||
|
if ! _hetznercloud_handle_action_response "TXT record add"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
_info "Hetzner Cloud TXT record added." |
||||
|
return 0 |
||||
|
;; |
||||
|
401 | 403) |
||||
|
_err "Hetzner Cloud DNS API authentication failed (HTTP ${_hetznercloud_last_http_code}). Check HETZNER_TOKEN for the new API." |
||||
|
_hetznercloud_log_http_error "" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
;; |
||||
|
409 | 422) |
||||
|
_hetznercloud_log_http_error "Hetzner Cloud DNS rejected the add_records request" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
;; |
||||
|
*) |
||||
|
_hetznercloud_log_http_error "Hetzner Cloud DNS add_records request failed" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
;; |
||||
|
esac |
||||
|
} |
||||
|
|
||||
|
dns_hetznercloud_rm() { |
||||
|
fulldomain="$(_idn "${1}")" |
||||
|
txtvalue="${2}" |
||||
|
|
||||
|
_info "Using Hetzner Cloud DNS API to remove record" |
||||
|
|
||||
|
if ! _hetznercloud_init; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _hetznercloud_prepare_zone "${fulldomain}"; then |
||||
|
_err "Unable to determine Hetzner Cloud zone for ${fulldomain}" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _hetznercloud_get_rrset; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ "${_hetznercloud_last_http_code}" = "404" ]; then |
||||
|
_info "TXT rrset does not exist; nothing to remove." |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
if [ "${_hetznercloud_last_http_code}" != "200" ]; then |
||||
|
_hetznercloud_log_http_error "Failed to query existing TXT rrset" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _hetznercloud_rrset_contains_value "${txtvalue}"; then |
||||
|
remove_payload="$(_hetznercloud_build_remove_payload "${txtvalue}")" |
||||
|
if [ -z "${remove_payload}" ]; then |
||||
|
_err "Failed to build remove_records payload." |
||||
|
return 1 |
||||
|
fi |
||||
|
if ! _hetznercloud_api POST "${_hetznercloud_rrset_action_remove}" "${remove_payload}"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
case "${_hetznercloud_last_http_code}" in |
||||
|
200 | 201 | 202 | 204) |
||||
|
if ! _hetznercloud_handle_action_response "TXT record remove"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
_info "Hetzner Cloud TXT record removed." |
||||
|
return 0 |
||||
|
;; |
||||
|
401 | 403) |
||||
|
_err "Hetzner Cloud DNS API authentication failed (HTTP ${_hetznercloud_last_http_code}). Check HETZNER_TOKEN for the new API." |
||||
|
_hetznercloud_log_http_error "" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
;; |
||||
|
404) |
||||
|
_info "TXT rrset already absent after remove action." |
||||
|
return 0 |
||||
|
;; |
||||
|
409 | 422) |
||||
|
_hetznercloud_log_http_error "Hetzner Cloud DNS rejected the remove_records request" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
;; |
||||
|
*) |
||||
|
_hetznercloud_log_http_error "Hetzner Cloud DNS remove_records request failed" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
;; |
||||
|
esac |
||||
|
else |
||||
|
_info "TXT value not present; nothing to remove." |
||||
|
return 0 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
#################### Private functions ################################## |
||||
|
|
||||
|
_hetznercloud_init() { |
||||
|
HETZNER_TOKEN="${HETZNER_TOKEN:-$(_readaccountconf_mutable HETZNER_TOKEN)}" |
||||
|
if [ -z "${HETZNER_TOKEN}" ]; then |
||||
|
_err "The environment variable HETZNER_TOKEN must be set for the Hetzner Cloud DNS API." |
||||
|
return 1 |
||||
|
fi |
||||
|
HETZNER_TOKEN=$(echo "${HETZNER_TOKEN}" | tr -d '"') |
||||
|
_saveaccountconf_mutable HETZNER_TOKEN "${HETZNER_TOKEN}" |
||||
|
|
||||
|
HETZNER_API="${HETZNER_API:-$(_readaccountconf_mutable HETZNER_API)}" |
||||
|
if [ -z "${HETZNER_API}" ]; then |
||||
|
HETZNER_API="${HETZNERCLOUD_API_DEFAULT}" |
||||
|
fi |
||||
|
_saveaccountconf_mutable HETZNER_API "${HETZNER_API}" |
||||
|
|
||||
|
HETZNER_TTL="${HETZNER_TTL:-$(_readaccountconf_mutable HETZNER_TTL)}" |
||||
|
if [ -z "${HETZNER_TTL}" ]; then |
||||
|
HETZNER_TTL="${HETZNERCLOUD_TTL_DEFAULT}" |
||||
|
fi |
||||
|
ttl_check=$(printf "%s" "${HETZNER_TTL}" | tr -d '0-9') |
||||
|
if [ -n "${ttl_check}" ]; then |
||||
|
_err "HETZNER_TTL must be an integer value." |
||||
|
return 1 |
||||
|
fi |
||||
|
_saveaccountconf_mutable HETZNER_TTL "${HETZNER_TTL}" |
||||
|
|
||||
|
HETZNER_MAX_ATTEMPTS="${HETZNER_MAX_ATTEMPTS:-$(_readaccountconf_mutable HETZNER_MAX_ATTEMPTS)}" |
||||
|
if [ -z "${HETZNER_MAX_ATTEMPTS}" ]; then |
||||
|
HETZNER_MAX_ATTEMPTS="${HETZNER_MAX_ATTEMPTS_DEFAULT}" |
||||
|
fi |
||||
|
attempts_check=$(printf "%s" "${HETZNER_MAX_ATTEMPTS}" | tr -d '0-9') |
||||
|
if [ -n "${attempts_check}" ]; then |
||||
|
_err "HETZNER_MAX_ATTEMPTS must be an integer value." |
||||
|
return 1 |
||||
|
fi |
||||
|
_saveaccountconf_mutable HETZNER_MAX_ATTEMPTS "${HETZNER_MAX_ATTEMPTS}" |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_prepare_zone() { |
||||
|
_hetznercloud_zone_id="" |
||||
|
_hetznercloud_zone_name="" |
||||
|
_hetznercloud_zone_name_lc="" |
||||
|
_hetznercloud_rr_name="" |
||||
|
_hetznercloud_rrset_path="" |
||||
|
_hetznercloud_rrset_action_add="" |
||||
|
_hetznercloud_rrset_action_remove="" |
||||
|
fulldomain_lc=$(printf "%s" "${1}" | sed 's/\.$//' | _lower_case) |
||||
|
|
||||
|
i=2 |
||||
|
p=1 |
||||
|
while true; do |
||||
|
candidate=$(printf "%s" "${fulldomain_lc}" | cut -d . -f "${i}"-100) |
||||
|
if [ -z "${candidate}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _hetznercloud_get_zone_by_candidate "${candidate}"; then |
||||
|
zone_name_lc="${_hetznercloud_zone_name_lc}" |
||||
|
if [ "${fulldomain_lc}" = "${zone_name_lc}" ]; then |
||||
|
_hetznercloud_rr_name="@" |
||||
|
else |
||||
|
suffix=".${zone_name_lc}" |
||||
|
if _endswith "${fulldomain_lc}" "${suffix}"; then |
||||
|
_hetznercloud_rr_name="${fulldomain_lc%"${suffix}"}" |
||||
|
else |
||||
|
_hetznercloud_rr_name="${fulldomain_lc}" |
||||
|
fi |
||||
|
fi |
||||
|
_hetznercloud_rrset_path=$(printf "%s" "${_hetznercloud_rr_name}" | _url_encode) |
||||
|
_hetznercloud_rrset_action_add="/zones/${_hetznercloud_zone_id}/rrsets/${_hetznercloud_rrset_path}/TXT/actions/add_records" |
||||
|
_hetznercloud_rrset_action_remove="/zones/${_hetznercloud_zone_id}/rrsets/${_hetznercloud_rrset_path}/TXT/actions/remove_records" |
||||
|
return 0 |
||||
|
fi |
||||
|
p=${i} |
||||
|
i=$(_math "${i}" + 1) |
||||
|
done |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_get_zone_by_candidate() { |
||||
|
candidate="${1}" |
||||
|
zone_key=$(printf "%s" "${candidate}" | sed 's/[^A-Za-z0-9]/_/g') |
||||
|
zone_conf_key="HETZNERCLOUD_ZONE_ID_for_${zone_key}" |
||||
|
|
||||
|
cached_zone_id=$(_readdomainconf "${zone_conf_key}") |
||||
|
if [ -n "${cached_zone_id}" ]; then |
||||
|
if _hetznercloud_api GET "/zones/${cached_zone_id}"; then |
||||
|
if [ "${_hetznercloud_last_http_code}" = "200" ]; then |
||||
|
zone_data=$(printf "%s" "${response}" | _normalizeJson | sed 's/^{"zone"://' | sed 's/}$//') |
||||
|
if _hetznercloud_parse_zone_fields "${zone_data}"; then |
||||
|
zone_name_lc=$(printf "%s" "${_hetznercloud_zone_name}" | _lower_case) |
||||
|
if [ "${zone_name_lc}" = "${candidate}" ]; then |
||||
|
return 0 |
||||
|
fi |
||||
|
fi |
||||
|
elif [ "${_hetznercloud_last_http_code}" = "404" ]; then |
||||
|
_cleardomainconf "${zone_conf_key}" |
||||
|
fi |
||||
|
else |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
if _hetznercloud_api GET "/zones/${candidate}"; then |
||||
|
if [ "${_hetznercloud_last_http_code}" = "200" ]; then |
||||
|
zone_data=$(printf "%s" "${response}" | _normalizeJson | sed 's/^{"zone"://' | sed 's/}$//') |
||||
|
if _hetznercloud_parse_zone_fields "${zone_data}"; then |
||||
|
zone_name_lc=$(printf "%s" "${_hetznercloud_zone_name}" | _lower_case) |
||||
|
if [ "${zone_name_lc}" = "${candidate}" ]; then |
||||
|
_savedomainconf "${zone_conf_key}" "${_hetznercloud_zone_id}" |
||||
|
return 0 |
||||
|
fi |
||||
|
fi |
||||
|
elif [ "${_hetznercloud_last_http_code}" != "404" ]; then |
||||
|
_hetznercloud_log_http_error "Hetzner Cloud zone lookup failed" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
fi |
||||
|
else |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
encoded_candidate=$(printf "%s" "${candidate}" | _url_encode) |
||||
|
if ! _hetznercloud_api GET "/zones?name=${encoded_candidate}"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
if [ "${_hetznercloud_last_http_code}" != "200" ]; then |
||||
|
if [ "${_hetznercloud_last_http_code}" = "404" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
_hetznercloud_log_http_error "Hetzner Cloud zone search failed" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
zone_data=$(_hetznercloud_extract_zone_from_list "${response}" "${candidate}") |
||||
|
if [ -z "${zone_data}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
if ! _hetznercloud_parse_zone_fields "${zone_data}"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
_savedomainconf "${zone_conf_key}" "${_hetznercloud_zone_id}" |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_parse_zone_fields() { |
||||
|
zone_json="${1}" |
||||
|
if [ -z "${zone_json}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
normalized=$(printf "%s" "${zone_json}" | _normalizeJson) |
||||
|
zone_id=$(printf "%s" "${normalized}" | _egrep_o '"id":[^,}]*' | _head_n 1 | cut -d : -f 2 | tr -d ' "') |
||||
|
zone_name=$(printf "%s" "${normalized}" | _egrep_o '"name":"[^"]*"' | _head_n 1 | cut -d : -f 2 | tr -d '"') |
||||
|
if [ -z "${zone_id}" ] || [ -z "${zone_name}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
zone_name_trimmed=$(printf "%s" "${zone_name}" | sed 's/\.$//') |
||||
|
if zone_name_ascii=$(_idn "${zone_name_trimmed}"); then |
||||
|
zone_name="${zone_name_ascii}" |
||||
|
else |
||||
|
zone_name="${zone_name_trimmed}" |
||||
|
fi |
||||
|
_hetznercloud_zone_id="${zone_id}" |
||||
|
_hetznercloud_zone_name="${zone_name}" |
||||
|
_hetznercloud_zone_name_lc=$(printf "%s" "${zone_name}" | _lower_case) |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_extract_zone_from_list() { |
||||
|
list_response=$(printf "%s" "${1}" | _normalizeJson) |
||||
|
candidate="${2}" |
||||
|
escaped_candidate=$(_hetznercloud_escape_regex "${candidate}") |
||||
|
printf "%s" "${list_response}" | _egrep_o "{[^{}]*\"name\":\"${escaped_candidate}\"[^{}]*}" | _head_n 1 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_escape_regex() { |
||||
|
printf "%s" "${1}" | sed 's/\\/\\\\/g' | sed 's/\./\\./g' | sed 's/-/\\-/g' |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_get_rrset() { |
||||
|
if [ -z "${_hetznercloud_zone_id}" ] || [ -z "${_hetznercloud_rrset_path}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
if ! _hetznercloud_api GET "/zones/${_hetznercloud_zone_id}/rrsets/${_hetznercloud_rrset_path}/TXT"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_rrset_contains_value() { |
||||
|
wanted_value="${1}" |
||||
|
normalized=$(printf "%s" "${response}" | _normalizeJson) |
||||
|
escaped_value=$(_hetznercloud_escape_value "${wanted_value}") |
||||
|
search_pattern="\"value\":\"\\\\\"${escaped_value}\\\\\"\"" |
||||
|
if _contains "${normalized}" "${search_pattern}"; then |
||||
|
return 0 |
||||
|
fi |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_build_add_payload() { |
||||
|
value="${1}" |
||||
|
escaped_value=$(_hetznercloud_escape_value "${value}") |
||||
|
printf '{"ttl":%s,"records":[{"value":"\\"%s\\""}]}' "${HETZNER_TTL}" "${escaped_value}" |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_build_remove_payload() { |
||||
|
value="${1}" |
||||
|
escaped_value=$(_hetznercloud_escape_value "${value}") |
||||
|
printf '{"records":[{"value":"\\"%s\\""}]}' "${escaped_value}" |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_escape_value() { |
||||
|
printf "%s" "${1}" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_error_message() { |
||||
|
if [ -z "${response}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
message=$(printf "%s" "${response}" | _normalizeJson | _egrep_o '"message":"[^"]*"' | _head_n 1 | cut -d : -f 2 | tr -d '"') |
||||
|
if [ -n "${message}" ]; then |
||||
|
printf "%s" "${message}" |
||||
|
return 0 |
||||
|
fi |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_log_http_error() { |
||||
|
context="${1}" |
||||
|
code="${2}" |
||||
|
message="$(_hetznercloud_error_message)" |
||||
|
if [ -n "${context}" ]; then |
||||
|
if [ -n "${message}" ]; then |
||||
|
_err "${context} (HTTP ${code}): ${message}" |
||||
|
else |
||||
|
_err "${context} (HTTP ${code})" |
||||
|
fi |
||||
|
else |
||||
|
if [ -n "${message}" ]; then |
||||
|
_err "Hetzner Cloud DNS API error (HTTP ${code}): ${message}" |
||||
|
else |
||||
|
_err "Hetzner Cloud DNS API error (HTTP ${code})" |
||||
|
fi |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_api() { |
||||
|
method="${1}" |
||||
|
ep="${2}" |
||||
|
data="${3}" |
||||
|
retried="${4}" |
||||
|
|
||||
|
if [ -z "${method}" ]; then |
||||
|
method="GET" |
||||
|
fi |
||||
|
|
||||
|
if ! _startswith "${ep}" "/"; then |
||||
|
ep="/${ep}" |
||||
|
fi |
||||
|
url="${HETZNER_API}${ep}" |
||||
|
|
||||
|
export _H1="Authorization: Bearer ${HETZNER_TOKEN}" |
||||
|
export _H2="Accept: application/json" |
||||
|
export _H3="" |
||||
|
export _H4="" |
||||
|
export _H5="" |
||||
|
|
||||
|
: >"${HTTP_HEADER}" |
||||
|
|
||||
|
if [ "${method}" = "GET" ]; then |
||||
|
response="$(_get "${url}")" |
||||
|
else |
||||
|
if [ -z "${data}" ]; then |
||||
|
data="{}" |
||||
|
fi |
||||
|
response="$(_post "${data}" "${url}" "" "${method}" "application/json")" |
||||
|
fi |
||||
|
ret="${?}" |
||||
|
|
||||
|
_hetznercloud_last_http_code=$(grep "^HTTP" "${HTTP_HEADER}" | _tail_n 1 | cut -d " " -f 2 | tr -d '\r\n') |
||||
|
|
||||
|
if [ "${ret}" != "0" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ "${_hetznercloud_last_http_code}" = "429" ] && [ "${retried}" != "retried" ]; then |
||||
|
retry_after=$(grep -i "^Retry-After" "${HTTP_HEADER}" | _tail_n 1 | cut -d : -f 2 | tr -d ' \r') |
||||
|
if [ -z "${retry_after}" ]; then |
||||
|
retry_after=1 |
||||
|
fi |
||||
|
_info "Hetzner Cloud DNS API rate limit hit; retrying in ${retry_after} seconds." |
||||
|
_sleep "${retry_after}" |
||||
|
if ! _hetznercloud_api "${method}" "${ep}" "${data}" "retried"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_handle_action_response() { |
||||
|
context="${1}" |
||||
|
if [ -z "${response}" ]; then |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
normalized=$(printf "%s" "${response}" | _normalizeJson) |
||||
|
|
||||
|
failed_message="" |
||||
|
if failed_message=$(_hetznercloud_extract_failed_action_message "${normalized}"); then |
||||
|
if [ -n "${failed_message}" ]; then |
||||
|
_err "Hetzner Cloud DNS ${context} failed: ${failed_message}" |
||||
|
else |
||||
|
_err "Hetzner Cloud DNS ${context} failed." |
||||
|
fi |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
action_ids="" |
||||
|
if action_ids=$(_hetznercloud_extract_action_ids "${normalized}"); then |
||||
|
for action_id in ${action_ids}; do |
||||
|
if [ -z "${action_id}" ]; then |
||||
|
continue |
||||
|
fi |
||||
|
if ! _hetznercloud_wait_for_action "${action_id}" "${context}"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
done |
||||
|
fi |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_extract_failed_action_message() { |
||||
|
normalized="${1}" |
||||
|
failed_section=$(printf "%s" "${normalized}" | _egrep_o '"failed_actions":\[[^]]*\]') |
||||
|
if [ -z "${failed_section}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
if _contains "${failed_section}" '"failed_actions":[]'; then |
||||
|
return 1 |
||||
|
fi |
||||
|
message=$(printf "%s" "${failed_section}" | _egrep_o '"message":"[^"]*"' | _head_n 1 | cut -d : -f 2 | tr -d '"') |
||||
|
if [ -n "${message}" ]; then |
||||
|
printf "%s" "${message}" |
||||
|
else |
||||
|
printf "%s" "${failed_section}" |
||||
|
fi |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_extract_action_ids() { |
||||
|
normalized="${1}" |
||||
|
actions_section=$(printf "%s" "${normalized}" | _egrep_o '"actions":\[[^]]*\]') |
||||
|
if [ -z "${actions_section}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
action_ids=$(printf "%s" "${actions_section}" | _egrep_o '"id":[0-9]*' | cut -d : -f 2 | tr -d '"' | tr '\n' ' ') |
||||
|
action_ids=$(printf "%s" "${action_ids}" | tr -s ' ') |
||||
|
action_ids=$(printf "%s" "${action_ids}" | sed 's/^ //;s/ $//') |
||||
|
if [ -z "${action_ids}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
printf "%s" "${action_ids}" |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_wait_for_action() { |
||||
|
action_id="${1}" |
||||
|
context="${2}" |
||||
|
attempts="0" |
||||
|
|
||||
|
while true; do |
||||
|
if ! _hetznercloud_api GET "/actions/${action_id}"; then |
||||
|
return 1 |
||||
|
fi |
||||
|
if [ "${_hetznercloud_last_http_code}" != "200" ]; then |
||||
|
_hetznercloud_log_http_error "Hetzner Cloud DNS action ${action_id} query failed" "${_hetznercloud_last_http_code}" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
normalized=$(printf "%s" "${response}" | _normalizeJson) |
||||
|
action_status=$(_hetznercloud_action_status_from_normalized "${normalized}") |
||||
|
|
||||
|
if [ -z "${action_status}" ]; then |
||||
|
_err "Hetzner Cloud DNS ${context} action ${action_id} returned no status." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ "${action_status}" = "success" ]; then |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
if [ "${action_status}" = "error" ]; then |
||||
|
if action_error=$(_hetznercloud_action_error_from_normalized "${normalized}"); then |
||||
|
_err "Hetzner Cloud DNS ${context} action ${action_id} failed: ${action_error}" |
||||
|
else |
||||
|
_err "Hetzner Cloud DNS ${context} action ${action_id} failed." |
||||
|
fi |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
attempts=$(_math "${attempts}" + 1) |
||||
|
if [ "${attempts}" -ge "${HETZNER_MAX_ATTEMPTS}" ]; then |
||||
|
_err "Hetzner Cloud DNS ${context} action ${action_id} did not complete after ${HETZNER_MAX_ATTEMPTS} attempts." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_sleep 1 |
||||
|
done |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_action_status_from_normalized() { |
||||
|
normalized="${1}" |
||||
|
status=$(printf "%s" "${normalized}" | _egrep_o '"status":"[^"]*"' | _head_n 1 | cut -d : -f 2 | tr -d '"') |
||||
|
printf "%s" "${status}" |
||||
|
} |
||||
|
|
||||
|
_hetznercloud_action_error_from_normalized() { |
||||
|
normalized="${1}" |
||||
|
error_section=$(printf "%s" "${normalized}" | _egrep_o '"error":{[^}]*}') |
||||
|
if [ -z "${error_section}" ]; then |
||||
|
return 1 |
||||
|
fi |
||||
|
message=$(printf "%s" "${error_section}" | _egrep_o '"message":"[^"]*"' | _head_n 1 | cut -d : -f 2 | tr -d '"') |
||||
|
if [ -n "${message}" ]; then |
||||
|
printf "%s" "${message}" |
||||
|
return 0 |
||||
|
fi |
||||
|
code=$(printf "%s" "${error_section}" | _egrep_o '"code":"[^"]*"' | _head_n 1 | cut -d : -f 2 | tr -d '"') |
||||
|
if [ -n "${code}" ]; then |
||||
|
printf "%s" "${code}" |
||||
|
return 0 |
||||
|
fi |
||||
|
return 1 |
||||
|
} |
||||
@ -0,0 +1,244 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
# shellcheck disable=SC2034 |
||||
|
dns_infoblox_uddi_info='Infoblox UDDI |
||||
|
Site: Infoblox.com |
||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_infoblox_uddi |
||||
|
Options: |
||||
|
Infoblox_UDDI_Key API Key for Infoblox UDDI |
||||
|
Infoblox_Portal URL, e.g. "csp.infoblox.com" or "csp.eu.infoblox.com" |
||||
|
Issues: github.com/acmesh-official/acme.sh/issues |
||||
|
Author: Stefan Riegel |
||||
|
' |
||||
|
|
||||
|
Infoblox_UDDI_Api="https://" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
#Usage: dns_infoblox_uddi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_infoblox_uddi_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
Infoblox_UDDI_Key="${Infoblox_UDDI_Key:-$(_readaccountconf_mutable Infoblox_UDDI_Key)}" |
||||
|
Infoblox_Portal="${Infoblox_Portal:-$(_readaccountconf_mutable Infoblox_Portal)}" |
||||
|
|
||||
|
_info "Using Infoblox UDDI API" |
||||
|
_debug fulldomain "$fulldomain" |
||||
|
_debug txtvalue "$txtvalue" |
||||
|
|
||||
|
if [ -z "$Infoblox_UDDI_Key" ] || [ -z "$Infoblox_Portal" ]; then |
||||
|
Infoblox_UDDI_Key="" |
||||
|
Infoblox_Portal="" |
||||
|
_err "You didn't specify the Infoblox UDDI key or server (Infoblox_UDDI_Key; Infoblox_Portal)." |
||||
|
_err "Please set them via EXPORT Infoblox_UDDI_Key=your_key, EXPORT Infoblox_Portal=csp.infoblox.com and try again." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_saveaccountconf_mutable Infoblox_UDDI_Key "$Infoblox_UDDI_Key" |
||||
|
_saveaccountconf_mutable Infoblox_Portal "$Infoblox_Portal" |
||||
|
|
||||
|
export _H1="Authorization: Token $Infoblox_UDDI_Key" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
_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 existing txt records" |
||||
|
_infoblox_rest GET "dns/record?_filter=type%20eq%20'TXT'%20and%20name_in_zone%20eq%20'$_sub_domain'%20and%20zone%20eq%20'$_domain_id'" |
||||
|
|
||||
|
_info "Adding record" |
||||
|
body="{\"type\":\"TXT\",\"name_in_zone\":\"$_sub_domain\",\"zone\":\"$_domain_id\",\"ttl\":120,\"inheritance_sources\":{\"ttl\":{\"action\":\"override\"}},\"rdata\":{\"text\":\"$txtvalue\"}}" |
||||
|
|
||||
|
if _infoblox_rest POST "dns/record" "$body"; then |
||||
|
if _contains "$response" "$txtvalue"; then |
||||
|
_info "Added, OK" |
||||
|
return 0 |
||||
|
elif _contains "$response" '"error"'; then |
||||
|
# Check if record already exists |
||||
|
if _contains "$response" "already exists" || _contains "$response" "duplicate"; then |
||||
|
_info "Already exists, OK" |
||||
|
return 0 |
||||
|
else |
||||
|
_err "Add txt record error." |
||||
|
_err "Response: $response" |
||||
|
return 1 |
||||
|
fi |
||||
|
else |
||||
|
_info "Added, OK" |
||||
|
return 0 |
||||
|
fi |
||||
|
fi |
||||
|
_err "Add txt record error." |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#Usage: dns_infoblox_uddi_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
dns_infoblox_uddi_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
Infoblox_UDDI_Key="${Infoblox_UDDI_Key:-$(_readaccountconf_mutable Infoblox_UDDI_Key)}" |
||||
|
Infoblox_Portal="${Infoblox_Portal:-$(_readaccountconf_mutable Infoblox_Portal)}" |
||||
|
|
||||
|
if [ -z "$Infoblox_UDDI_Key" ] || [ -z "$Infoblox_Portal" ]; then |
||||
|
_err "Credentials not found" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info "Using Infoblox UDDI API" |
||||
|
_debug fulldomain "$fulldomain" |
||||
|
_debug txtvalue "$txtvalue" |
||||
|
|
||||
|
export _H1="Authorization: Token $Infoblox_UDDI_Key" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
_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 to delete" |
||||
|
# Filter by txtvalue to support wildcard certs (multiple TXT records) |
||||
|
filter="type%20eq%20'TXT'%20and%20name_in_zone%20eq%20'$_sub_domain'%20and%20zone%20eq%20'$_domain_id'%20and%20rdata.text%20eq%20'$txtvalue'" |
||||
|
_infoblox_rest GET "dns/record?_filter=$filter" |
||||
|
|
||||
|
if ! _contains "$response" '"results"'; then |
||||
|
_info "Don't need to remove, record not found." |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
record_id=$(echo "$response" | _egrep_o '"id":[[:space:]]*"[^"]*"' | _head_n 1 | cut -d '"' -f 4) |
||||
|
_debug "record_id" "$record_id" |
||||
|
|
||||
|
if [ -z "$record_id" ]; then |
||||
|
_info "Don't need to remove, record not found." |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
# Extract UUID from the full record ID (format: dns/record/uuid) |
||||
|
record_uuid=$(echo "$record_id" | sed 's|.*/||') |
||||
|
_debug "record_uuid" "$record_uuid" |
||||
|
|
||||
|
if ! _infoblox_rest DELETE "dns/record/$record_uuid"; then |
||||
|
_err "Delete record error." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_info "Removed record successfully" |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
#################### Private functions below ################################## |
||||
|
|
||||
|
#_acme-challenge.www.domain.com |
||||
|
#returns |
||||
|
# _sub_domain=_acme-challenge.www |
||||
|
# _domain=domain.com |
||||
|
# _domain_id=dns/auth_zone/xxxx-xxxx |
||||
|
_get_root() { |
||||
|
domain=$1 |
||||
|
i=1 |
||||
|
p=1 |
||||
|
|
||||
|
# Remove _acme-challenge prefix if present |
||||
|
domain_no_acme=$(echo "$domain" | sed 's/^_acme-challenge\.//') |
||||
|
|
||||
|
while true; do |
||||
|
h=$(printf "%s" "$domain_no_acme" | cut -d . -f "$i"-100) |
||||
|
_debug h "$h" |
||||
|
if [ -z "$h" ]; then |
||||
|
# not valid |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
# Query for the zone with both trailing dot and without |
||||
|
filter="fqdn%20eq%20'$h.'%20or%20fqdn%20eq%20'$h'" |
||||
|
if ! _infoblox_rest GET "dns/auth_zone?_filter=$filter"; then |
||||
|
# API error - don't continue if we get auth errors |
||||
|
if _contains "$response" "401" || _contains "$response" "Authorization"; then |
||||
|
_err "Authentication failed. Please check your Infoblox_UDDI_Key." |
||||
|
return 1 |
||||
|
fi |
||||
|
# For other errors, continue to parent domain |
||||
|
p=$i |
||||
|
i=$((i + 1)) |
||||
|
continue |
||||
|
fi |
||||
|
|
||||
|
# Check if response contains results (even if empty) |
||||
|
if _contains "$response" '"results"'; then |
||||
|
# Extract zone ID - must match the pattern dns/auth_zone/... |
||||
|
zone_id=$(echo "$response" | _egrep_o '"id":[[:space:]]*"dns/auth_zone/[^"]*"' | _head_n 1 | cut -d '"' -f 4) |
||||
|
if [ -n "$zone_id" ]; then |
||||
|
# Found the zone |
||||
|
_domain="$h" |
||||
|
_domain_id="$zone_id" |
||||
|
|
||||
|
# Calculate subdomain |
||||
|
if [ "$_domain" = "$domain" ]; then |
||||
|
_sub_domain="" |
||||
|
else |
||||
|
_cutlength=$((${#domain} - ${#_domain} - 1)) |
||||
|
_sub_domain=$(printf "%s" "$domain" | cut -c "1-$_cutlength") |
||||
|
fi |
||||
|
|
||||
|
return 0 |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
p=$i |
||||
|
i=$((i + 1)) |
||||
|
done |
||||
|
|
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
# _infoblox_rest GET "dns/record?_filter=..." |
||||
|
# _infoblox_rest POST "dns/record" "{json body}" |
||||
|
# _infoblox_rest DELETE "dns/record/uuid" |
||||
|
_infoblox_rest() { |
||||
|
method=$1 |
||||
|
ep="$2" |
||||
|
data="$3" |
||||
|
|
||||
|
_debug "$ep" |
||||
|
|
||||
|
# Ensure credentials are available (when called from _get_root) |
||||
|
Infoblox_UDDI_Key="${Infoblox_UDDI_Key:-$(_readaccountconf_mutable Infoblox_UDDI_Key)}" |
||||
|
Infoblox_Portal="${Infoblox_Portal:-$(_readaccountconf_mutable Infoblox_Portal)}" |
||||
|
|
||||
|
Infoblox_UDDI_Api="https://$Infoblox_Portal/api/ddi/v1" |
||||
|
export _H1="Authorization: Token $Infoblox_UDDI_Key" |
||||
|
export _H2="Content-Type: application/json" |
||||
|
|
||||
|
# Debug (masked) |
||||
|
_tok_len=$(printf "%s" "$Infoblox_UDDI_Key" | wc -c | tr -d ' \n') |
||||
|
_debug2 "Auth header set" "Token len=${_tok_len} on $Infoblox_Portal" |
||||
|
|
||||
|
if [ "$method" != "GET" ]; then |
||||
|
_debug data "$data" |
||||
|
response="$(_post "$data" "$Infoblox_UDDI_Api/$ep" "" "$method")" |
||||
|
else |
||||
|
response="$(_get "$Infoblox_UDDI_Api/$ep")" |
||||
|
fi |
||||
|
|
||||
|
_ret="$?" |
||||
|
_debug2 response "$response" |
||||
|
|
||||
|
if [ "$_ret" != "0" ]; then |
||||
|
_err "Error: $ep" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
@ -0,0 +1,186 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
# shellcheck disable=SC2034 |
||||
|
dns_openprovider_rest_info='OpenProvider (REST) |
||||
|
Domains: OpenProvider.com |
||||
|
Site: OpenProvider.eu |
||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_openprovider_rest |
||||
|
Options: |
||||
|
OPENPROVIDER_REST_USERNAME Openprovider Account Username |
||||
|
OPENPROVIDER_REST_PASSWORD Openprovider Account Password |
||||
|
Issues: github.com/acmesh-official/acme.sh/issues/6122 |
||||
|
Author: Lambiek12 |
||||
|
' |
||||
|
|
||||
|
OPENPROVIDER_API_URL="https://api.openprovider.eu/v1beta" |
||||
|
|
||||
|
######## Public functions ##################### |
||||
|
|
||||
|
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
# Used to add txt record |
||||
|
dns_openprovider_rest_add() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
_openprovider_prepare_credentials || return 1 |
||||
|
|
||||
|
_debug "Try fetch OpenProvider DNS zone details" |
||||
|
if ! _get_dns_zone "$fulldomain"; then |
||||
|
_err "DNS zone not found within configured OpenProvider account." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -n "$_domain_id" ]; then |
||||
|
addzonerecordrequestparameters="dns/zones/$_domain_name" |
||||
|
addzonerecordrequestbody="{\"id\":$_domain_id,\"name\":\"$_domain_name\",\"records\":{\"add\":[{\"name\":\"$_sub_domain\",\"ttl\":900,\"type\":\"TXT\",\"value\":\"$txtvalue\"}]}}" |
||||
|
|
||||
|
if _openprovider_rest PUT "$addzonerecordrequestparameters" "$addzonerecordrequestbody"; then |
||||
|
if _contains "$response" "\"success\":true"; then |
||||
|
return 0 |
||||
|
elif _contains "$response" "\"Duplicate record\""; then |
||||
|
_debug "Record already existed" |
||||
|
return 0 |
||||
|
else |
||||
|
_err "Adding TXT record failed due to errors." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
_err "Adding TXT record failed due to errors." |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
# Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
||||
|
# Used to remove the txt record after validation |
||||
|
dns_openprovider_rest_rm() { |
||||
|
fulldomain=$1 |
||||
|
txtvalue=$2 |
||||
|
|
||||
|
_openprovider_prepare_credentials || return 1 |
||||
|
|
||||
|
_debug "Try fetch OpenProvider DNS zone details" |
||||
|
if ! _get_dns_zone "$fulldomain"; then |
||||
|
_err "DNS zone not found within configured OpenProvider account." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if [ -n "$_domain_id" ]; then |
||||
|
removezonerecordrequestparameters="dns/zones/$_domain_name" |
||||
|
removezonerecordrequestbody="{\"id\":$_domain_id,\"name\":\"$_domain_name\",\"records\":{\"remove\":[{\"name\":\"$_sub_domain\",\"ttl\":900,\"type\":\"TXT\",\"value\":\"\\\"$txtvalue\\\"\"}]}}" |
||||
|
|
||||
|
if _openprovider_rest PUT "$removezonerecordrequestparameters" "$removezonerecordrequestbody"; then |
||||
|
if _contains "$response" "\"success\":true"; then |
||||
|
return 0 |
||||
|
else |
||||
|
_err "Removing TXT record failed due to errors." |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
_err "Removing TXT record failed due to errors." |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
#################### OpenProvider API common functions #################### |
||||
|
_openprovider_prepare_credentials() { |
||||
|
OPENPROVIDER_REST_USERNAME="${OPENPROVIDER_REST_USERNAME:-$(_readaccountconf_mutable OPENPROVIDER_REST_USERNAME)}" |
||||
|
OPENPROVIDER_REST_PASSWORD="${OPENPROVIDER_REST_PASSWORD:-$(_readaccountconf_mutable OPENPROVIDER_REST_PASSWORD)}" |
||||
|
|
||||
|
if [ -z "$OPENPROVIDER_REST_USERNAME" ] || [ -z "$OPENPROVIDER_REST_PASSWORD" ]; then |
||||
|
OPENPROVIDER_REST_USERNAME="" |
||||
|
OPENPROVIDER_REST_PASSWORD="" |
||||
|
_err "You didn't specify the Openprovider username or password yet." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
#save the credentials to the account conf file. |
||||
|
_saveaccountconf_mutable OPENPROVIDER_REST_USERNAME "$OPENPROVIDER_REST_USERNAME" |
||||
|
_saveaccountconf_mutable OPENPROVIDER_REST_PASSWORD "$OPENPROVIDER_REST_PASSWORD" |
||||
|
} |
||||
|
|
||||
|
_openprovider_rest() { |
||||
|
httpmethod=$1 |
||||
|
queryparameters=$2 |
||||
|
requestbody=$3 |
||||
|
|
||||
|
_openprovider_rest_login |
||||
|
if [ -z "$openproviderauthtoken" ]; then |
||||
|
_err "Unable to fetch authentication token from Openprovider API." |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
export _H1="Content-Type: application/json" |
||||
|
export _H2="Accept: application/json" |
||||
|
export _H3="Authorization: Bearer $openproviderauthtoken" |
||||
|
|
||||
|
if [ "$httpmethod" != "GET" ]; then |
||||
|
response="$(_post "$requestbody" "$OPENPROVIDER_API_URL/$queryparameters" "" "$httpmethod")" |
||||
|
else |
||||
|
response="$(_get "$OPENPROVIDER_API_URL/$queryparameters")" |
||||
|
fi |
||||
|
|
||||
|
if [ "$?" != "0" ]; then |
||||
|
_err "No valid parameters supplied for Openprovider API: Error $queryparameters" |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
_debug2 response "$response" |
||||
|
|
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
_openprovider_rest_login() { |
||||
|
export _H1="Content-Type: application/json" |
||||
|
export _H2="Accept: application/json" |
||||
|
|
||||
|
loginrequesturl="$OPENPROVIDER_API_URL/auth/login" |
||||
|
loginrequestbody="{\"ip\":\"0.0.0.0\",\"password\":\"$OPENPROVIDER_REST_PASSWORD\",\"username\":\"$OPENPROVIDER_REST_USERNAME\"}" |
||||
|
loginresponse="$(_post "$loginrequestbody" "$loginrequesturl" "" "POST")" |
||||
|
|
||||
|
openproviderauthtoken="$(printf "%s\n" "$loginresponse" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" |
||||
|
|
||||
|
export openproviderauthtoken |
||||
|
} |
||||
|
|
||||
|
#################### Private functions ################################## |
||||
|
|
||||
|
# Usage: _get_dns_zone _acme-challenge.www.domain.com |
||||
|
# Returns: |
||||
|
# _domain_id=123456789 |
||||
|
# _domain_name=domain.com |
||||
|
# _sub_domain=_acme-challenge.www |
||||
|
_get_dns_zone() { |
||||
|
domain=$1 |
||||
|
i=1 |
||||
|
p=1 |
||||
|
|
||||
|
while true; do |
||||
|
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) |
||||
|
if [ -z "$h" ]; then |
||||
|
# Empty value not allowed |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if ! _openprovider_rest GET "dns/zones/$h" ""; then |
||||
|
return 1 |
||||
|
fi |
||||
|
|
||||
|
if _contains "$response" "\"name\":\"$h\""; then |
||||
|
_domain_id="$(printf "%s\n" "$response" | _egrep_o '"id" *: *[^,]*' | _head_n 1 | sed 's#^"id" *: *##')" |
||||
|
_debug _domain_id "$_domain_id" |
||||
|
|
||||
|
_domain_name="$h" |
||||
|
_debug _domain_name "$_domain_name" |
||||
|
|
||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") |
||||
|
_debug _sub_domain "$_sub_domain" |
||||
|
return 0 |
||||
|
fi |
||||
|
|
||||
|
p=$i |
||||
|
i=$(_math "$i" + 1) |
||||
|
done |
||||
|
|
||||
|
return 1 |
||||
|
} |
||||
@ -0,0 +1,130 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
|
||||
|
#Support OpsGenie API integration |
||||
|
|
||||
|
#OPSGENIE_API_KEY="" Required, opsgenie api key |
||||
|
#OPSGENIE_REGION="" Optional, opsgenie region, can be EU or US (default: US) |
||||
|
#OPSGENIE_PRIORITY_SUCCESS="" Optional, opsgenie priority for success (default: P5) |
||||
|
#OPSGENIE_PRIORITY_ERROR="" Optional, opsgenie priority for error (default: P2) |
||||
|
#OPSGENIE_PRIORITY_SKIP="" Optional, opsgenie priority for renew skipped (default: P5) |
||||
|
|
||||
|
_OPSGENIE_AVAIL_REGION="US,EU" |
||||
|
_OPSGENIE_AVAIL_PRIORITIES="P1,P2,P3,P4,P5" |
||||
|
|
||||
|
opsgenie_send() { |
||||
|
_subject="$1" |
||||
|
_content="$2" |
||||
|
_status_code="$3" #0: success, 1: error, 2($RENEW_SKIP): skipped |
||||
|
|
||||
|
OPSGENIE_API_KEY="${OPSGENIE_API_KEY:-$(_readaccountconf_mutable OPSGENIE_API_KEY)}" |
||||
|
if [ -z "$OPSGENIE_API_KEY" ]; then |
||||
|
OPSGENIE_API_KEY="" |
||||
|
_err "You didn't specify an OpsGenie API key OPSGENIE_API_KEY yet." |
||||
|
return 1 |
||||
|
fi |
||||
|
_saveaccountconf_mutable OPSGENIE_API_KEY "$OPSGENIE_API_KEY" |
||||
|
export _H1="Authorization: GenieKey $OPSGENIE_API_KEY" |
||||
|
|
||||
|
OPSGENIE_REGION="${OPSGENIE_REGION:-$(_readaccountconf_mutable OPSGENIE_REGION)}" |
||||
|
if [ -z "$OPSGENIE_REGION" ]; then |
||||
|
OPSGENIE_REGION="US" |
||||
|
_info "The OPSGENIE_REGION is not set, so use the default US as regeion." |
||||
|
elif ! _hasfield "$_OPSGENIE_AVAIL_REGION" "$OPSGENIE_REGION"; then |
||||
|
_err "The OPSGENIE_REGION \"$OPSGENIE_REGION\" is not available, should be one of $_OPSGENIE_AVAIL_REGION" |
||||
|
OPSGENIE_REGION="" |
||||
|
return 1 |
||||
|
else |
||||
|
_saveaccountconf_mutable OPSGENIE_REGION "$OPSGENIE_REGION" |
||||
|
fi |
||||
|
|
||||
|
OPSGENIE_PRIORITY_SUCCESS="${OPSGENIE_PRIORITY_SUCCESS:-$(_readaccountconf_mutable OPSGENIE_PRIORITY_SUCCESS)}" |
||||
|
if [ -z "$OPSGENIE_PRIORITY_SUCCESS" ]; then |
||||
|
OPSGENIE_PRIORITY_SUCCESS="P5" |
||||
|
_info "The OPSGENIE_PRIORITY_SUCCESS is not set, so use the default P5 as priority." |
||||
|
elif ! _hasfield "$_OPSGENIE_AVAIL_PRIORITIES" "$OPSGENIE_PRIORITY_SUCCESS"; then |
||||
|
_err "The OPSGENIE_PRIORITY_SUCCESS \"$OPSGENIE_PRIORITY_SUCCESS\" is not available, should be one of $_OPSGENIE_AVAIL_PRIORITIES" |
||||
|
OPSGENIE_PRIORITY_SUCCESS="" |
||||
|
return 1 |
||||
|
else |
||||
|
_saveaccountconf_mutable OPSGENIE_PRIORITY_SUCCESS "$OPSGENIE_PRIORITY_SUCCESS" |
||||
|
fi |
||||
|
|
||||
|
OPSGENIE_PRIORITY_ERROR="${OPSGENIE_PRIORITY_ERROR:-$(_readaccountconf_mutable OPSGENIE_PRIORITY_ERROR)}" |
||||
|
if [ -z "$OPSGENIE_PRIORITY_ERROR" ]; then |
||||
|
OPSGENIE_PRIORITY_ERROR="P2" |
||||
|
_info "The OPSGENIE_PRIORITY_ERROR is not set, so use the default P2 as priority." |
||||
|
elif ! _hasfield "$_OPSGENIE_AVAIL_PRIORITIES" "$OPSGENIE_PRIORITY_ERROR"; then |
||||
|
_err "The OPSGENIE_PRIORITY_ERROR \"$OPSGENIE_PRIORITY_ERROR\" is not available, should be one of $_OPSGENIE_AVAIL_PRIORITIES" |
||||
|
OPSGENIE_PRIORITY_ERROR="" |
||||
|
return 1 |
||||
|
else |
||||
|
_saveaccountconf_mutable OPSGENIE_PRIORITY_ERROR "$OPSGENIE_PRIORITY_ERROR" |
||||
|
fi |
||||
|
|
||||
|
OPSGENIE_PRIORITY_SKIP="${OPSGENIE_PRIORITY_SKIP:-$(_readaccountconf_mutable OPSGENIE_PRIORITY_SKIP)}" |
||||
|
if [ -z "$OPSGENIE_PRIORITY_SKIP" ]; then |
||||
|
OPSGENIE_PRIORITY_SKIP="P5" |
||||
|
_info "The OPSGENIE_PRIORITY_SKIP is not set, so use the default P5 as priority." |
||||
|
elif ! _hasfield "$_OPSGENIE_AVAIL_PRIORITIES" "$OPSGENIE_PRIORITY_SKIP"; then |
||||
|
_err "The OPSGENIE_PRIORITY_SKIP \"$OPSGENIE_PRIORITY_SKIP\" is not available, should be one of $_OPSGENIE_AVAIL_PRIORITIES" |
||||
|
OPSGENIE_PRIORITY_SKIP="" |
||||
|
return 1 |
||||
|
else |
||||
|
_saveaccountconf_mutable OPSGENIE_PRIORITY_SKIP "$OPSGENIE_PRIORITY_SKIP" |
||||
|
fi |
||||
|
|
||||
|
case "$OPSGENIE_REGION" in |
||||
|
"US") |
||||
|
_opsgenie_url="https://api.opsgenie.com/v2/alerts" |
||||
|
;; |
||||
|
"EU") |
||||
|
_opsgenie_url="https://api.eu.opsgenie.com/v2/alerts" |
||||
|
;; |
||||
|
*) |
||||
|
_err "opsgenie region error." |
||||
|
return 1 |
||||
|
;; |
||||
|
esac |
||||
|
|
||||
|
case $_status_code in |
||||
|
0) |
||||
|
_priority=$OPSGENIE_PRIORITY_SUCCESS |
||||
|
;; |
||||
|
1) |
||||
|
_priority=$OPSGENIE_PRIORITY_ERROR |
||||
|
;; |
||||
|
2) |
||||
|
_priority=$OPSGENIE_PRIORITY_SKIP |
||||
|
;; |
||||
|
*) |
||||
|
_priority=$OPSGENIE_PRIORITY_ERROR |
||||
|
;; |
||||
|
esac |
||||
|
|
||||
|
_subject_json=$(echo "$_subject" | _json_encode) |
||||
|
_content_json=$(echo "$_content" | _json_encode) |
||||
|
_subject_underscore=$(echo "$_subject" | sed 's/ /_/g') |
||||
|
_alias_json=$(echo "acme.sh-$(hostname)-$_subject_underscore-$(date +%Y%m%d)" | base64 --wrap=0 | _json_encode) |
||||
|
|
||||
|
_data="{ |
||||
|
\"message\": \"$_subject_json\", |
||||
|
\"alias\": \"$_alias_json\", |
||||
|
\"description\": \"$_content_json\", |
||||
|
\"tags\": [ |
||||
|
\"acme.sh\", |
||||
|
\"host:$(hostname)\" |
||||
|
], |
||||
|
\"entity\": \"$(hostname -f)\", |
||||
|
\"priority\": \"$_priority\" |
||||
|
}" |
||||
|
|
||||
|
if response=$(_post "$_data" "$_opsgenie_url" "" "" "application/json"); then |
||||
|
if ! _contains "$response" error; then |
||||
|
_info "opsgenie send success." |
||||
|
return 0 |
||||
|
fi |
||||
|
fi |
||||
|
_err "opsgenie send error." |
||||
|
_err "$response" |
||||
|
return 1 |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue