Maxim Pogozhiy
1 week ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 1188 additions and 146 deletions
-
4acme.sh
-
120deploy/proxmoxbs.sh
-
2deploy/truenas.sh
-
294deploy/truenas_ws.sh
-
91deploy/unifi.sh
-
2dnsapi/dns_azure.sh
-
19dnsapi/dns_cyon.sh
-
38dnsapi/dns_he_ddns.sh
-
18dnsapi/dns_limacity.sh
-
215dnsapi/dns_mijnhost.sh
-
10dnsapi/dns_myapi.sh
-
6dnsapi/dns_netcup.sh
-
4dnsapi/dns_omglol.sh
-
1dnsapi/dns_openprovider.sh
-
2dnsapi/dns_pdns.sh
-
463dnsapi/dns_selectel.sh
-
7dnsapi/dns_technitium.sh
-
14dnsapi/dns_west_cn.sh
-
2dnsapi/dns_yandex360.sh
-
20dnsapi/dns_zoneedit.sh
-
2notify/aws_ses.sh
@ -0,0 +1,120 @@ |
|||
#!/usr/bin/env sh |
|||
|
|||
# Deploy certificates to a proxmox backup server using the API. |
|||
# |
|||
# Environment variables that can be set are: |
|||
# `DEPLOY_PROXMOXBS_SERVER`: The hostname of the proxmox backup server. Defaults to |
|||
# _cdomain. |
|||
# `DEPLOY_PROXMOXBS_SERVER_PORT`: The port number the management interface is on. |
|||
# Defaults to 8007. |
|||
# `DEPLOY_PROXMOXBS_USER`: The user we'll connect as. Defaults to root. |
|||
# `DEPLOY_PROXMOXBS_USER_REALM`: The authentication realm the user authenticates |
|||
# with. Defaults to pam. |
|||
# `DEPLOY_PROXMOXBS_API_TOKEN_NAME`: The name of the API token created for the |
|||
# user account. Defaults to acme. |
|||
# `DEPLOY_PROXMOXBS_API_TOKEN_KEY`: The API token. Required. |
|||
|
|||
proxmoxbs_deploy() { |
|||
_cdomain="$1" |
|||
_ckey="$2" |
|||
_ccert="$3" |
|||
_cca="$4" |
|||
_cfullchain="$5" |
|||
|
|||
_debug _cdomain "$_cdomain" |
|||
_debug2 _ckey "$_ckey" |
|||
_debug _ccert "$_ccert" |
|||
_debug _cca "$_cca" |
|||
_debug _cfullchain "$_cfullchain" |
|||
|
|||
# "Sane" defaults. |
|||
_getdeployconf DEPLOY_PROXMOXBS_SERVER |
|||
if [ -z "$DEPLOY_PROXMOXBS_SERVER" ]; then |
|||
_target_hostname="$_cdomain" |
|||
else |
|||
_target_hostname="$DEPLOY_PROXMOXBS_SERVER" |
|||
_savedeployconf DEPLOY_PROXMOXBS_SERVER "$DEPLOY_PROXMOXBS_SERVER" |
|||
fi |
|||
_debug2 DEPLOY_PROXMOXBS_SERVER "$_target_hostname" |
|||
|
|||
_getdeployconf DEPLOY_PROXMOXBS_SERVER_PORT |
|||
if [ -z "$DEPLOY_PROXMOXBS_SERVER_PORT" ]; then |
|||
_target_port="8007" |
|||
else |
|||
_target_port="$DEPLOY_PROXMOXBS_SERVER_PORT" |
|||
_savedeployconf DEPLOY_PROXMOXBS_SERVER_PORT "$DEPLOY_PROXMOXBS_SERVER_PORT" |
|||
fi |
|||
_debug2 DEPLOY_PROXMOXBS_SERVER_PORT "$_target_port" |
|||
|
|||
# Complete URL. |
|||
_target_url="https://${_target_hostname}:${_target_port}/api2/json/nodes/localhost/certificates/custom" |
|||
_debug TARGET_URL "$_target_url" |
|||
|
|||
# More "sane" defaults. |
|||
_getdeployconf DEPLOY_PROXMOXBS_USER |
|||
if [ -z "$DEPLOY_PROXMOXBS_USER" ]; then |
|||
_proxmoxbs_user="root" |
|||
else |
|||
_proxmoxbs_user="$DEPLOY_PROXMOXBS_USER" |
|||
_savedeployconf DEPLOY_PROXMOXBS_USER "$DEPLOY_PROXMOXBS_USER" |
|||
fi |
|||
_debug2 DEPLOY_PROXMOXBS_USER "$_proxmoxbs_user" |
|||
|
|||
_getdeployconf DEPLOY_PROXMOXBS_USER_REALM |
|||
if [ -z "$DEPLOY_PROXMOXBS_USER_REALM" ]; then |
|||
_proxmoxbs_user_realm="pam" |
|||
else |
|||
_proxmoxbs_user_realm="$DEPLOY_PROXMOXBS_USER_REALM" |
|||
_savedeployconf DEPLOY_PROXMOXBS_USER_REALM "$DEPLOY_PROXMOXBS_USER_REALM" |
|||
fi |
|||
_debug2 DEPLOY_PROXMOXBS_USER_REALM "$_proxmoxbs_user_realm" |
|||
|
|||
_getdeployconf DEPLOY_PROXMOXBS_API_TOKEN_NAME |
|||
if [ -z "$DEPLOY_PROXMOXBS_API_TOKEN_NAME" ]; then |
|||
_proxmoxbs_api_token_name="acme" |
|||
else |
|||
_proxmoxbs_api_token_name="$DEPLOY_PROXMOXBS_API_TOKEN_NAME" |
|||
_savedeployconf DEPLOY_PROXMOXBS_API_TOKEN_NAME "$DEPLOY_PROXMOXBS_API_TOKEN_NAME" |
|||
fi |
|||
_debug2 DEPLOY_PROXMOXBS_API_TOKEN_NAME "$_proxmoxbs_api_token_name" |
|||
|
|||
# This is required. |
|||
_getdeployconf DEPLOY_PROXMOXBS_API_TOKEN_KEY |
|||
if [ -z "$DEPLOY_PROXMOXBS_API_TOKEN_KEY" ]; then |
|||
_err "API key not provided." |
|||
return 1 |
|||
else |
|||
_proxmoxbs_api_token_key="$DEPLOY_PROXMOXBS_API_TOKEN_KEY" |
|||
_savedeployconf DEPLOY_PROXMOXBS_API_TOKEN_KEY "$DEPLOY_PROXMOXBS_API_TOKEN_KEY" |
|||
fi |
|||
_debug2 DEPLOY_PROXMOXBS_API_TOKEN_KEY "$_proxmoxbs_api_token_key" |
|||
|
|||
# PBS API Token header value. Used in "Authorization: PBSAPIToken". |
|||
_proxmoxbs_header_api_token="${_proxmoxbs_user}@${_proxmoxbs_user_realm}!${_proxmoxbs_api_token_name}:${_proxmoxbs_api_token_key}" |
|||
_debug2 "Auth Header" "$_proxmoxbs_header_api_token" |
|||
|
|||
# Ugly. I hate putting heredocs inside functions because heredocs don't |
|||
# account for whitespace correctly but it _does_ work and is several times |
|||
# cleaner than anything else I had here. |
|||
# |
|||
# This dumps the json payload to a variable that should be passable to the |
|||
# _psot function. |
|||
_json_payload=$( |
|||
cat <<HEREDOC |
|||
{ |
|||
"certificates": "$(tr '\n' ':' <"$_cfullchain" | sed 's/:/\\n/g')", |
|||
"key": "$(tr '\n' ':' <"$_ckey" | sed 's/:/\\n/g')", |
|||
"node":"localhost", |
|||
"restart":true, |
|||
"force":true |
|||
} |
|||
HEREDOC |
|||
) |
|||
_debug2 Payload "$_json_payload" |
|||
|
|||
_info "Push certificates to server" |
|||
export HTTPS_INSECURE=1 |
|||
export _H1="Authorization: PBSAPIToken=${_proxmoxbs_header_api_token}" |
|||
_post "$_json_payload" "$_target_url" "" POST "application/json" |
|||
|
|||
} |
@ -0,0 +1,294 @@ |
|||
#!/usr/bin/env sh |
|||
|
|||
# TrueNAS deploy script for SCALE/CORE using websocket |
|||
# It is recommend to use a wildcard certificate |
|||
# |
|||
# Websocket Documentation: https://www.truenas.com/docs/api/scale_websocket_api.html |
|||
# |
|||
# Tested with TrueNAS Scale - Electric Eel 24.10 |
|||
# Changes certificate in the following services: |
|||
# - Web UI |
|||
# - FTP |
|||
# - iX Apps |
|||
# |
|||
# The following environment variables must be set: |
|||
# ------------------------------------------------ |
|||
# |
|||
# # API KEY |
|||
# # Use the folowing URL to create a new API token: <TRUENAS_HOSTNAME OR IP>/ui/apikeys |
|||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI" |
|||
# |
|||
|
|||
### Private functions |
|||
|
|||
# Call websocket method |
|||
# Usage: |
|||
# _ws_response=$(_ws_call "math.dummycalc" "'{"x": 4, "y": 5}'") |
|||
# _info "$_ws_response" |
|||
# |
|||
# Output: |
|||
# {"z": 9} |
|||
# |
|||
# Arguments: |
|||
# $@ - midclt arguments for call |
|||
# |
|||
# Returns: |
|||
# JSON/JOBID |
|||
_ws_call() { |
|||
_debug "_ws_call arg1" "$1" |
|||
_debug "_ws_call arg2" "$2" |
|||
_debug "_ws_call arg3" "$3" |
|||
if [ $# -eq 3 ]; then |
|||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2" "$3") |
|||
fi |
|||
if [ $# -eq 2 ]; then |
|||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1" "$2") |
|||
fi |
|||
if [ $# -eq 1 ]; then |
|||
_ws_response=$(midclt -K "$DEPLOY_TRUENAS_APIKEY" call "$1") |
|||
fi |
|||
_debug "_ws_response" "$_ws_response" |
|||
printf "%s" "$_ws_response" |
|||
return 0 |
|||
} |
|||
|
|||
# Check argument is a number |
|||
# Usage: |
|||
# |
|||
# Output: |
|||
# n/a |
|||
# |
|||
# Arguments: |
|||
# $1 - Anything |
|||
# |
|||
# Returns: |
|||
# 0: true |
|||
# 1: false |
|||
_ws_check_jobid() { |
|||
case "$1" in |
|||
[0-9]*) |
|||
return 0 |
|||
;; |
|||
esac |
|||
return 1 |
|||
} |
|||
|
|||
# Wait for job to finish and return result as JSON |
|||
# Usage: |
|||
# _ws_result=$(_ws_get_job_result "$_ws_jobid") |
|||
# _new_certid=$(printf "%s" "$_ws_result" | jq -r '."id"') |
|||
# |
|||
# Output: |
|||
# JSON result of the job |
|||
# |
|||
# Arguments: |
|||
# $1 - JobID |
|||
# |
|||
# Returns: |
|||
# n/a |
|||
_ws_get_job_result() { |
|||
while true; do |
|||
sleep 2 |
|||
_ws_response=$(_ws_call "core.get_jobs" "[[\"id\", \"=\", $1]]") |
|||
if [ "$(printf "%s" "$_ws_response" | jq -r '.[]."state"')" != "RUNNING" ]; then |
|||
_ws_result="$(printf "%s" "$_ws_response" | jq '.[]."result"')" |
|||
_debug "_ws_result" "$_ws_result" |
|||
printf "%s" "$_ws_result" |
|||
_ws_error="$(printf "%s" "$_ws_response" | jq '.[]."error"')" |
|||
if [ "$_ws_error" != "null" ]; then |
|||
_err "Job $1 failed:" |
|||
_err "$_ws_error" |
|||
return 7 |
|||
fi |
|||
break |
|||
fi |
|||
done |
|||
return 0 |
|||
} |
|||
|
|||
######################## |
|||
### Public functions ### |
|||
######################## |
|||
|
|||
# truenas_ws_deploy |
|||
# |
|||
# Deploy new certificate to TrueNAS services |
|||
# |
|||
# Arguments |
|||
# 1: Domain |
|||
# 2: Key-File |
|||
# 3: Certificate-File |
|||
# 4: CA-File |
|||
# 5: FullChain-File |
|||
# Returns: |
|||
# 0: Success |
|||
# 1: Missing API Key |
|||
# 2: TrueNAS not ready |
|||
# 3: Not a JobID |
|||
# 4: FTP cert error |
|||
# 5: WebUI cert error |
|||
# 6: Job error |
|||
# 7: WS call error |
|||
# 10: No CORE or SCALE detected |
|||
# |
|||
truenas_ws_deploy() { |
|||
_domain="$1" |
|||
_file_key="$2" |
|||
_file_cert="$3" |
|||
_file_ca="$4" |
|||
_file_fullchain="$5" |
|||
_debug _domain "$_domain" |
|||
_debug _file_key "$_file_key" |
|||
_debug _file_cert "$_file_cert" |
|||
_debug _file_ca "$_file_ca" |
|||
_debug _file_fullchain "$_file_fullchain" |
|||
|
|||
########## Environment check |
|||
|
|||
_info "Checking environment variables..." |
|||
_getdeployconf DEPLOY_TRUENAS_APIKEY |
|||
# Check API Key |
|||
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then |
|||
_err "TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable." |
|||
return 1 |
|||
fi |
|||
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY" |
|||
_info "Environment variables: OK" |
|||
|
|||
########## Health check |
|||
|
|||
_info "Checking TrueNAS health..." |
|||
_ws_response=$(_ws_call "system.ready" | tr '[:lower:]' '[:upper:]') |
|||
_ws_ret=$? |
|||
if [ $_ws_ret -gt 0 ]; then |
|||
_err "Error calling system.ready:" |
|||
_err "$_ws_response" |
|||
return $_ws_ret |
|||
fi |
|||
|
|||
if [ "$_ws_response" != "TRUE" ]; then |
|||
_err "TrueNAS is not ready." |
|||
_err "Please check environment variables DEPLOY_TRUENAS_APIKEY, DEPLOY_TRUENAS_HOSTNAME and DEPLOY_TRUENAS_PROTOCOL." |
|||
_err "Verify API key." |
|||
return 2 |
|||
fi |
|||
_savedeployconf DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY" |
|||
_info "TrueNAS health: OK" |
|||
|
|||
########## System info |
|||
|
|||
_info "Gather system info..." |
|||
_ws_response=$(_ws_call "system.info") |
|||
_truenas_system=$(printf "%s" "$_ws_response" | jq -r '."version"' | cut -d '-' -f 2 | tr '[:lower:]' '[:upper:]') |
|||
_truenas_version=$(printf "%s" "$_ws_response" | jq -r '."version"' | cut -d '-' -f 3) |
|||
_info "TrueNAS system: $_truenas_system" |
|||
_info "TrueNAS version: $_truenas_version" |
|||
if [ "$_truenas_system" != "SCALE" ] && [ "$_truenas_system" != "CORE" ]; then |
|||
_err "Cannot gather TrueNAS system. Nor CORE oder SCALE detected." |
|||
return 10 |
|||
fi |
|||
|
|||
########## Gather current certificate |
|||
|
|||
_info "Gather current WebUI certificate..." |
|||
_ws_response="$(_ws_call "system.general.config")" |
|||
_ui_certificate_id=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."id"') |
|||
_ui_certificate_name=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."name"') |
|||
_info "Current WebUI certificate ID: $_ui_certificate_id" |
|||
_info "Current WebUI certificate name: $_ui_certificate_name" |
|||
|
|||
########## Upload new certificate |
|||
|
|||
_info "Upload new certificate..." |
|||
_certname="acme_$(_utc_date | tr -d '\-\:' | tr ' ' '_')" |
|||
_info "New WebUI certificate name: $_certname" |
|||
_debug _certname "$_certname" |
|||
_ws_jobid=$(_ws_call "certificate.create" "{\"name\": \"${_certname}\", \"create_type\": \"CERTIFICATE_CREATE_IMPORTED\", \"certificate\": \"$(_json_encode <"$_file_fullchain")\", \"privatekey\": \"$(_json_encode <"$_file_key")\", \"passphrase\": \"\"}") |
|||
_debug "_ws_jobid" "$_ws_jobid" |
|||
if ! _ws_check_jobid "$_ws_jobid"; then |
|||
_err "No JobID returned from websocket method." |
|||
return 3 |
|||
fi |
|||
_ws_result=$(_ws_get_job_result "$_ws_jobid") |
|||
_ws_ret=$? |
|||
if [ $_ws_ret -gt 0 ]; then |
|||
return $_ws_ret |
|||
fi |
|||
_debug "_ws_result" "$_ws_result" |
|||
_new_certid=$(printf "%s" "$_ws_result" | jq -r '."id"') |
|||
_info "New certificate ID: $_new_certid" |
|||
|
|||
########## FTP |
|||
|
|||
_info "Replace FTP certificate..." |
|||
_ws_response=$(_ws_call "ftp.update" "{\"ssltls_certificate\": $_new_certid}") |
|||
_ftp_certid=$(printf "%s" "$_ws_response" | jq -r '."ssltls_certificate"') |
|||
if [ "$_ftp_certid" != "$_new_certid" ]; then |
|||
_err "Cannot set FTP certificate." |
|||
_debug "_ws_response" "$_ws_response" |
|||
return 4 |
|||
fi |
|||
|
|||
########## ix Apps (SCALE only) |
|||
|
|||
if [ "$_truenas_system" = "SCALE" ]; then |
|||
_info "Replace app certificates..." |
|||
_ws_response=$(_ws_call "app.query") |
|||
for _app_name in $(printf "%s" "$_ws_response" | jq -r '.[]."name"'); do |
|||
_info "Checking app $_app_name..." |
|||
_ws_response=$(_ws_call "app.config" "$_app_name") |
|||
if [ "$(printf "%s" "$_ws_response" | jq -r '."network" | has("certificate_id")')" = "true" ]; then |
|||
_info "App has certificate option, setup new certificate..." |
|||
_info "App will be redeployed after updating the certificate." |
|||
_ws_jobid=$(_ws_call "app.update" "$_app_name" "{\"values\": {\"network\": {\"certificate_id\": $_new_certid}}}") |
|||
_debug "_ws_jobid" "$_ws_jobid" |
|||
if ! _ws_check_jobid "$_ws_jobid"; then |
|||
_err "No JobID returned from websocket method." |
|||
return 3 |
|||
fi |
|||
_ws_result=$(_ws_get_job_result "$_ws_jobid") |
|||
_ws_ret=$? |
|||
if [ $_ws_ret -gt 0 ]; then |
|||
return $_ws_ret |
|||
fi |
|||
_debug "_ws_result" "$_ws_result" |
|||
_info "App certificate replaced." |
|||
else |
|||
_info "App has no certificate option, skipping..." |
|||
fi |
|||
done |
|||
fi |
|||
|
|||
########## WebUI |
|||
|
|||
_info "Replace WebUI certificate..." |
|||
_ws_response=$(_ws_call "system.general.update" "{\"ui_certificate\": $_new_certid}") |
|||
_changed_certid=$(printf "%s" "$_ws_response" | jq -r '."ui_certificate"."id"') |
|||
if [ "$_changed_certid" != "$_new_certid" ]; then |
|||
_err "WebUI certificate change error.." |
|||
return 5 |
|||
else |
|||
_info "WebUI certificate replaced." |
|||
fi |
|||
_info "Restarting WebUI..." |
|||
_ws_response=$(_ws_call "system.general.ui_restart") |
|||
_info "Waiting for UI restart..." |
|||
sleep 6 |
|||
|
|||
########## Certificates |
|||
|
|||
_info "Deleting old certificate..." |
|||
_ws_jobid=$(_ws_call "certificate.delete" "$_ui_certificate_id") |
|||
if ! _ws_check_jobid "$_ws_jobid"; then |
|||
_err "No JobID returned from websocket method." |
|||
return 3 |
|||
fi |
|||
_ws_result=$(_ws_get_job_result "$_ws_jobid") |
|||
_ws_ret=$? |
|||
if [ $_ws_ret -gt 0 ]; then |
|||
return $_ws_ret |
|||
fi |
|||
|
|||
_info "Have a nice day...bye!" |
|||
|
|||
} |
@ -0,0 +1,38 @@ |
|||
#!/usr/bin/env sh |
|||
# shellcheck disable=SC2034 |
|||
dns_he_ddns_info='Hurricane Electric HE.net DDNS |
|||
Site: dns.he.net |
|||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_he_ddns |
|||
Options: |
|||
HE_DDNS_KEY The DDNS key |
|||
Author: Markku Leiniö |
|||
' |
|||
|
|||
HE_DDNS_URL="https://dyn.dns.he.net/nic/update" |
|||
|
|||
######## Public functions ##################### |
|||
|
|||
#Usage: dns_he_ddns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
|||
dns_he_ddns_add() { |
|||
fulldomain=$1 |
|||
txtvalue=$2 |
|||
HE_DDNS_KEY="${HE_DDNS_KEY:-$(_readaccountconf_mutable HE_DDNS_KEY)}" |
|||
if [ -z "$HE_DDNS_KEY" ]; then |
|||
HE_DDNS_KEY="" |
|||
_err "You didn't specify a DDNS key for accessing the TXT record in HE API." |
|||
return 1 |
|||
fi |
|||
#Save the DDNS key to the account conf file. |
|||
_saveaccountconf_mutable HE_DDNS_KEY "$HE_DDNS_KEY" |
|||
|
|||
_info "Using Hurricane Electric DDNS API" |
|||
_debug fulldomain "$fulldomain" |
|||
_debug txtvalue "$txtvalue" |
|||
|
|||
response="$(_post "hostname=$fulldomain&password=$HE_DDNS_KEY&txt=$txtvalue" "$HE_DDNS_URL")" |
|||
_info "Response: $response" |
|||
_contains "$response" "good" && return 0 || return 1 |
|||
} |
|||
|
|||
# dns_he_ddns_rm() is not implemented because the API call always updates the |
|||
# contents of the existing record (that the API key gives access to). |
@ -0,0 +1,215 @@ |
|||
#!/usr/bin/env sh |
|||
# shellcheck disable=SC2034 |
|||
dns_mijnhost_info='mijn.host |
|||
Domains: mijn.host |
|||
Site: mijn.host |
|||
Docs: https://mijn.host/api/doc/ |
|||
Issues: https://github.com/acmesh-official/acme.sh/issues/6177 |
|||
Author: peterv99 |
|||
Options: |
|||
MIJNHOST_API_KEY API Key |
|||
' |
|||
|
|||
######## Public functions ###################### Constants for your mijn-host API |
|||
MIJNHOST_API="https://mijn.host/api/v2" |
|||
|
|||
# Add TXT record for domain verification |
|||
dns_mijnhost_add() { |
|||
fulldomain=$1 |
|||
txtvalue=$2 |
|||
|
|||
MIJNHOST_API_KEY="${MIJNHOST_API_KEY:-$(_readaccountconf_mutable MIJNHOST_API_KEY)}" |
|||
if [ -z "$MIJNHOST_API_KEY" ]; then |
|||
MIJNHOST_API_KEY="" |
|||
_err "You haven't specified your mijn-host API key yet." |
|||
_err "Please add MIJNHOST_API_KEY to the env." |
|||
return 1 |
|||
fi |
|||
|
|||
# Save the API key for future use |
|||
_saveaccountconf_mutable MIJNHOST_API_KEY "$MIJNHOST_API_KEY" |
|||
|
|||
_debug "First detect the root zone" |
|||
if ! _get_root "$fulldomain"; then |
|||
_err "Invalid domain" |
|||
return 1 |
|||
fi |
|||
|
|||
_debug2 _sub_domain "$_sub_domain" |
|||
_debug2 _domain "$_domain" |
|||
_debug "Adding DNS record" "${fulldomain}." |
|||
|
|||
# Construct the API URL |
|||
api_url="$MIJNHOST_API/domains/$_domain/dns" |
|||
|
|||
# Getting previous records |
|||
_mijnhost_rest GET "$api_url" "" |
|||
|
|||
if [ "$_code" != "200" ]; then |
|||
_err "Error getting current DNS enties ($_code)" |
|||
return 1 |
|||
fi |
|||
|
|||
records=$(echo "$response" | _egrep_o '"records":\[.*\]' | sed 's/"records"://') |
|||
|
|||
_debug2 "Current records" "$records" |
|||
|
|||
# Build the payload for the API |
|||
data="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"value\":\"$txtvalue\",\"ttl\":300}" |
|||
|
|||
_debug2 "Record to add" "$data" |
|||
|
|||
# Updating the records |
|||
updated_records=$(echo "$records" | sed -E "s/\]( *$)/,$data\]/") |
|||
|
|||
_debug2 "Updated records" "$updated_records" |
|||
|
|||
# data |
|||
data="{\"records\": $updated_records}" |
|||
|
|||
_mijnhost_rest PUT "$api_url" "$data" |
|||
|
|||
if [ "$_code" = "200" ]; then |
|||
_info "DNS record succesfully added." |
|||
return 0 |
|||
else |
|||
_err "Error adding DNS record ($_code)." |
|||
return 1 |
|||
fi |
|||
} |
|||
|
|||
# Remove TXT record after verification |
|||
dns_mijnhost_rm() { |
|||
fulldomain=$1 |
|||
txtvalue=$2 |
|||
|
|||
MIJNHOST_API_KEY="${MIJNHOST_API_KEY:-$(_readaccountconf_mutable MIJNHOST_API_KEY)}" |
|||
if [ -z "$MIJNHOST_API_KEY" ]; then |
|||
MIJNHOST_API_KEY="" |
|||
_err "You haven't specified your mijn-host API key yet." |
|||
_err "Please add MIJNHOST_API_KEY to the env." |
|||
return 1 |
|||
fi |
|||
|
|||
_debug "Detecting root zone for" "${fulldomain}." |
|||
if ! _get_root "$fulldomain"; then |
|||
_err "Invalid domain" |
|||
return 1 |
|||
fi |
|||
|
|||
_debug "Removing DNS record for TXT value" "${txtvalue}." |
|||
|
|||
# Construct the API URL |
|||
api_url="$MIJNHOST_API/domains/$_domain/dns" |
|||
|
|||
# Get current records |
|||
_mijnhost_rest GET "$api_url" "" |
|||
|
|||
if [ "$_code" != "200" ]; then |
|||
_err "Error getting current DNS enties ($_code)" |
|||
return 1 |
|||
fi |
|||
|
|||
_debug2 "Get current records response:" "$response" |
|||
|
|||
records=$(echo "$response" | _egrep_o '"records":\[.*\]' | sed 's/"records"://') |
|||
|
|||
_debug2 "Current records:" "$records" |
|||
|
|||
updated_records=$(echo "$records" | sed -E "s/\{[^}]*\"value\":\"$txtvalue\"[^}]*\},?//g" | sed 's/,]/]/g') |
|||
|
|||
_debug2 "Updated records:" "$updated_records" |
|||
|
|||
# Build the new payload |
|||
data="{\"records\": $updated_records}" |
|||
|
|||
# Use the _put method to update the records |
|||
_mijnhost_rest PUT "$api_url" "$data" |
|||
|
|||
if [ "$_code" = "200" ]; then |
|||
_info "DNS record removed successfully." |
|||
return 0 |
|||
else |
|||
_err "Error removing DNS record ($_code)." |
|||
return 1 |
|||
fi |
|||
} |
|||
|
|||
# Helper function to detect the root zone |
|||
_get_root() { |
|||
domain=$1 |
|||
|
|||
# Get current records |
|||
_debug "Getting current domains" |
|||
_mijnhost_rest GET "$MIJNHOST_API/domains" "" |
|||
|
|||
if [ "$_code" != "200" ]; then |
|||
_err "error getting current domains ($_code)" |
|||
return 1 |
|||
fi |
|||
|
|||
# Extract root domains from response |
|||
rootDomains=$(echo "$response" | _egrep_o '"domain":"[^"]*"' | sed -E 's/"domain":"([^"]*)"/\1/') |
|||
_debug "Root domains:" "$rootDomains" |
|||
|
|||
for rootDomain in $rootDomains; do |
|||
if _contains "$domain" "$rootDomain"; then |
|||
_domain="$rootDomain" |
|||
_sub_domain=$(echo "$domain" | sed "s/.$rootDomain//g") |
|||
_debug "Found root domain" "$_domain" "and subdomain" "$_sub_domain" "for" "$domain" |
|||
return 0 |
|||
fi |
|||
done |
|||
return 1 |
|||
} |
|||
|
|||
# Helper function for rest calls |
|||
_mijnhost_rest() { |
|||
m=$1 |
|||
ep="$2" |
|||
data="$3" |
|||
|
|||
MAX_REQUEST_RETRY_TIMES=15 |
|||
_request_retry_times=0 |
|||
_retry_sleep=5 #Initial sleep time in seconds. |
|||
|
|||
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do |
|||
_debug2 _request_retry_times "$_request_retry_times" |
|||
export _H1="API-Key: $MIJNHOST_API_KEY" |
|||
export _H2="Content-Type: application/json" |
|||
# clear headers from previous request to avoid getting wrong http code on timeouts |
|||
: >"$HTTP_HEADER" |
|||
_debug "$ep" |
|||
if [ "$m" != "GET" ]; then |
|||
_debug2 "data $data" |
|||
response="$(_post "$data" "$ep" "" "$m")" |
|||
else |
|||
response="$(_get "$ep")" |
|||
fi |
|||
_ret="$?" |
|||
_debug2 "response $response" |
|||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" |
|||
_debug "http response code $_code" |
|||
if [ "$_code" = "401" ]; then |
|||
# we have an invalid API token, maybe it is expired? |
|||
_err "Access denied. Invalid API token." |
|||
return 1 |
|||
fi |
|||
|
|||
if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "400" ] || _contains "$response" "DNS records not managed by mijn.host"; then #Sometimes API errors out |
|||
_request_retry_times="$(_math "$_request_retry_times" + 1)" |
|||
_info "REST call error $_code retrying $ep in ${_retry_sleep}s" |
|||
_sleep "$_retry_sleep" |
|||
_retry_sleep="$(_math "$_retry_sleep" \* 2)" |
|||
continue |
|||
fi |
|||
break |
|||
done |
|||
if [ "$_request_retry_times" = "$MAX_REQUEST_RETRY_TIMES" ]; then |
|||
_err "Error mijn.host API call was retried $MAX_REQUEST_RETRY_TIMES times." |
|||
_err "Calling $ep failed." |
|||
return 1 |
|||
fi |
|||
response="$(echo "$response" | _normalizeJson)" |
|||
return 0 |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue