diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index c0c51a84..4634ed96 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -251,7 +251,11 @@ jobs: fi cd ../acmetest ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" @@ -302,7 +306,11 @@ jobs: fi cd ../acmetest ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" @@ -354,7 +362,11 @@ jobs: fi cd ../acmetest ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" @@ -406,7 +418,11 @@ jobs: fi cd ../acmetest ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" @@ -464,6 +480,11 @@ jobs: fi cd ../acmetest ./letest.sh + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" Omnios: @@ -513,6 +534,12 @@ jobs: fi cd ../acmetest ./letest.sh + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" + OpenIndiana: @@ -562,5 +589,12 @@ jobs: fi cd ../acmetest ./letest.sh + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" + + diff --git a/.github/workflows/DragonFlyBSD.yml b/.github/workflows/DragonFlyBSD.yml index b047a210..dda8c99f 100644 --- a/.github/workflows/DragonFlyBSD.yml +++ b/.github/workflows/DragonFlyBSD.yml @@ -67,5 +67,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml index a4fca67c..21123c4a 100644 --- a/.github/workflows/FreeBSD.yml +++ b/.github/workflows/FreeBSD.yml @@ -72,5 +72,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml index 13b70350..40421552 100644 --- a/.github/workflows/NetBSD.yml +++ b/.github/workflows/NetBSD.yml @@ -67,5 +67,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" + diff --git a/.github/workflows/Omnios.yml b/.github/workflows/Omnios.yml index 5d0af1b1..20eb24d7 100644 --- a/.github/workflows/Omnios.yml +++ b/.github/workflows/Omnios.yml @@ -71,5 +71,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index 98e18545..fab6e4fd 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -72,5 +72,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/OpenIndiana.yml b/.github/workflows/OpenIndiana.yml index d17803de..abad376c 100644 --- a/.github/workflows/OpenIndiana.yml +++ b/.github/workflows/OpenIndiana.yml @@ -71,5 +71,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/.github/workflows/Solaris.yml b/.github/workflows/Solaris.yml index 21a16d1a..2388da71 100644 --- a/.github/workflows/Solaris.yml +++ b/.github/workflows/Solaris.yml @@ -73,5 +73,9 @@ jobs: run: | cd ../acmetest \ && ./letest.sh - + - name: onError + if: ${{ failure() }} + run: | + echo "See how to debug in VM:" + echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM" diff --git a/acme.sh b/acme.sh index 7e65c4eb..ac8ab7cc 100755 --- a/acme.sh +++ b/acme.sh @@ -1466,7 +1466,7 @@ _toPkcs() { ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" fi if [ "$?" = "0" ]; then - _savedomainconf "Le_PFXPassword" "$pfxPassword" + _savedomainconf "Le_PFXPassword" "$pfxPassword" "base64" fi } @@ -4470,7 +4470,7 @@ issue() { Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then - _valid_to_saved=$(_readdomainconf Le_Valid_to) + _valid_to_saved=$(_readdomainconf Le_Valid_To) if [ "$_valid_to_saved" ] && ! _startswith "$_valid_to_saved" "+"; then _info "The domain is set to be valid to: $_valid_to_saved" _info "It cannot be renewed automatically" @@ -5455,10 +5455,10 @@ $_authorizations_map" _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" #convert to pkcs12 + Le_PFXPassword="$(_readdomainconf Le_PFXPassword)" if [ "$Le_PFXPassword" ]; then _toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$Le_PFXPassword" fi - export CERT_PFX_PATH if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then _savedomainconf "Le_RealCertPath" "$_real_cert" @@ -5568,6 +5568,10 @@ renew() { Le_RenewHook="$(_readdomainconf Le_RenewHook)" Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)" Le_Certificate_Profile="$(_readdomainconf Le_Certificate_Profile)" + Le_Valid_From="$(_readdomainconf Le_Valid_From)" + Le_Valid_To="$(_readdomainconf Le_Valid_To)" + Le_ExtKeyUse="$(_readdomainconf Le_ExtKeyUse)" + # When renewing from an old version, the empty Le_Keylength means 2048. # Note, do not use DEFAULT_DOMAIN_KEY_LENGTH as that value may change over # time but an empty value implies 2048 specifically. @@ -5746,6 +5750,10 @@ signcsr() { _local_addr="${11}" _challenge_alias="${12}" _preferred_chain="${13}" + _valid_f="${14}" + _valid_t="${15}" + _cert_prof="${16}" + _en_key_usage="${17}" _csrsubj=$(_readSubjectFromCSR "$_csrfile") if [ "$?" != "0" ]; then @@ -5789,7 +5797,7 @@ signcsr() { _info "Copying CSR to: $CSR_PATH" cp "$_csrfile" "$CSR_PATH" - issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias" "$_preferred_chain" + issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias" "$_preferred_chain" "$_valid_f" "$_valid_t" "$_cert_prof" "$_en_key_usage" } @@ -8145,7 +8153,7 @@ _process() { deploy "$_domain" "$_deploy_hook" "$_ecc" ;; signcsr) - signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" + signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" "$_valid_from" "$_valid_to" "$_certificate_profile" "$_extended_key_usage" ;; showcsr) showcsr "$_csr" "$_domain" diff --git a/dnsapi/dns_qc.sh b/dnsapi/dns_qc.sh new file mode 100755 index 00000000..78756a35 --- /dev/null +++ b/dnsapi/dns_qc.sh @@ -0,0 +1,216 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_qc_info='QUIC.cloud +Site: quic.cloud +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_qc +Options: + QC_API_KEY QC API Key + QC_API_EMAIL Your account email +' + +QC_Api="https://api.quic.cloud/v2" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_qc_add() { + fulldomain=$1 + txtvalue=$2 + + _debug "Enter dns_qc_add fulldomain: $fulldomain, txtvalue: $txtvalue" + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" + QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" + + if [ "$QC_API_KEY" ]; then + _saveaccountconf_mutable QC_API_KEY "$QC_API_KEY" + else + _err "You didn't specify a QUIC.cloud api key as QC_API_KEY." + _err "You can get yours from here https://my.quic.cloud/up/api." + return 1 + fi + + if ! _contains "$QC_API_EMAIL" "@"; then + _err "It seems that the QC_API_EMAIL=$QC_API_EMAIL is not a valid email address." + _err "Please check and retry." + return 1 + fi + #save the api key and email to the account conf file. + _saveaccountconf_mutable QC_API_EMAIL "$QC_API_EMAIL" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain during add" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _qc_rest GET "zones/${_domain_id}/records" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error failed response from QC GET: $response" + return 1 + fi + + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # if [ "$count" = "0" ]; then + _info "Adding txt record" + if _qc_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":1800}"; then + if _contains "$response" "$txtvalue"; then + _info "Added txt record, OK" + return 0 + elif _contains "$response" "Same record already exists"; then + _info "txt record already exists, OK" + return 0 + else + _err "Add txt record error: $response" + return 1 + fi + fi + _err "Add txt record error: POST failed: $response" + return 1 + +} + +#fulldomain txtvalue +dns_qc_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "Enter dns_qc_rm fulldomain: $fulldomain, txtvalue: $txtvalue" + QC_API_KEY="${QC_API_KEY:-$(_readaccountconf_mutable QC_API_KEY)}" + QC_API_EMAIL="${QC_API_EMAIL:-$(_readaccountconf_mutable QC_API_EMAIL)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain during rm" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _qc_rest GET "zones/${_domain_id}/records" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error rm GET response: $response" + return 1 + fi + + _debug "Pre-jq response:" "$response" + # Do not use jq or subsequent code + #response=$(echo "$response" | jq ".result[] | select(.id) | select(.content == \"$txtvalue\") | select(.type == \"TXT\")") + #_debug "get txt response" "$response" + #if [ "${response}" = "" ]; then + # _info "Don't need to remove txt records." + # return 0 + #fi + #record_id=$(echo "$response" | grep \"id\" | awk -F ' ' '{print $2}' | sed 's/,$//') + #_debug "txt record_id" "$record_id" + #Instead of jq + array=$(echo "$response" | grep -o '\[[^]]*\]' | sed 's/^\[\(.*\)\]$/\1/') + if [ -z "$array" ]; then + _err "Expected array in QC response: $response" + return 1 + fi + # Temporary file to hold matched content (one per line) + tmpfile=$(_mktemp) + echo "$array" | grep -o '{[^}]*}' | sed 's/^{//;s/}$//' >"$tmpfile" + record_id="" + + while IFS= read -r obj || [ -n "$obj" ]; do + if echo "$obj" | grep -q '"TXT"' && echo "$obj" | grep -q '"id"' && echo "$obj" | grep -q "$txtvalue"; then + _debug "response includes" "$obj" + record_id=$(echo "$obj" | sed 's/^\"id\":\([0-9]\+\).*/\1/') + break + fi + done <"$tmpfile" + + rm "$tmpfile" + + if [ -z "$record_id" ]; then + _info "TXT record, or $txtvalue not found, nothing to remove" + return 0 + fi + + #End of jq replacement + if ! _qc_rest DELETE "zones/$_domain_id/records/$record_id"; then + _info "Delete txt record error." + return 1 + fi + + _info "TXT Record ID: $record_id successfully deleted" + return 0 + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + p=1 + + h=$(printf "%s" "$domain" | cut -d . -f2-) + _debug h "$h" + if [ -z "$h" ]; then + _err "$h ($domain) is an invalid domain" + return 1 + fi + + if ! _qc_rest GET "zones"; then + _err "qc_rest failed" + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" || _contains "$response" "\"name\":\"$h.\""; then + _domain_id=$h + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p") + _domain=$h + return 0 + fi + _err "Empty domain_id $h" + return 1 + fi + _err "Missing domain_id $h" + return 1 +} + +_qc_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + email_trimmed=$(echo "$QC_API_EMAIL" | tr -d '"') + token_trimmed=$(echo "$QC_API_KEY" | tr -d '"') + + export _H1="Content-Type: application/json" + export _H2="X-Auth-Email: $email_trimmed" + export _H3="X-Auth-Key: $token_trimmed" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$QC_Api/$ep" "" "$m")" + else + response="$(_get "$QC_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/dnsapi/dns_virakcloud.sh b/dnsapi/dns_virakcloud.sh new file mode 100755 index 00000000..7ae665d2 --- /dev/null +++ b/dnsapi/dns_virakcloud.sh @@ -0,0 +1,229 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_virakcloud_info='VirakCloud DNS API +Site: VirakCloud.com +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_virakcloud +Options: + VIRAKCLOUD_API_TOKEN VirakCloud API Bearer Token +' + +VIRAKCLOUD_API_URL="https://public-api.virakcloud.com/dns" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +#Used to add txt record +dns_virakcloud_add() { + fulldomain=$1 + txtvalue=$2 + + VIRAKCLOUD_API_TOKEN="${VIRAKCLOUD_API_TOKEN:-$(_readaccountconf_mutable VIRAKCLOUD_API_TOKEN)}" + + if [ -z "$VIRAKCLOUD_API_TOKEN" ]; then + _err "You haven't configured your VirakCloud API token yet." + _err "Please set VIRAKCLOUD_API_TOKEN environment variable or run:" + _err " export VIRAKCLOUD_API_TOKEN=\"your-api-token\"" + return 1 + fi + + _saveaccountconf_mutable VIRAKCLOUD_API_TOKEN "$VIRAKCLOUD_API_TOKEN" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + http_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + if [ "$http_code" = "401" ]; then + return 1 + fi + _err "Invalid domain" + return 1 + fi + + _debug _domain "$_domain" + _debug fulldomain "$fulldomain" + + _info "Adding TXT record" + + if _virakcloud_rest POST "domains/${_domain}/records" "{\"record\":\"${fulldomain}\",\"type\":\"TXT\",\"ttl\":3600,\"content\":\"${txtvalue}\"}"; then + if echo "$response" | grep -q "success" || echo "$response" | grep -q "\"data\""; then + _info "Added, OK" + return 0 + elif echo "$response" | grep -q "already exists" || echo "$response" | grep -q "duplicate"; then + _info "Record already exists, OK" + return 0 + else + _err "Add TXT record error." + _err "Response: $response" + return 1 + fi + fi + + _err "Add TXT record error." + return 1 +} + +#Usage: fulldomain txtvalue +#Used to remove the txt record after validation +dns_virakcloud_rm() { + fulldomain=$1 + txtvalue=$2 + + VIRAKCLOUD_API_TOKEN="${VIRAKCLOUD_API_TOKEN:-$(_readaccountconf_mutable VIRAKCLOUD_API_TOKEN)}" + + if [ -z "$VIRAKCLOUD_API_TOKEN" ]; then + _err "You haven't configured your VirakCloud API token yet." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + http_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + if [ "$http_code" = "401" ]; then + return 1 + fi + _err "Invalid domain" + return 1 + fi + + _debug _domain "$_domain" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _info "Removing TXT record" + + _debug "Getting list of records to find content ID" + if ! _virakcloud_rest GET "domains/${_domain}/records" ""; then + return 1 + fi + + _debug2 "Records response" "$response" + + contentid="" + # Extract innermost objects (content objects) which look like {"id":"...","content_raw":"..."} + # We filter for the one containing txtvalue + + target_obj=$(echo "$response" | grep -o '{[^}]*}' | grep "$txtvalue" | _head_n 1) + + if [ -n "$target_obj" ]; then + contentid=$(echo "$target_obj" | _egrep_o '"id":"[^"]*"' | cut -d '"' -f 4) + fi + + if [ -z "$contentid" ]; then + _debug "Could not find matching record ID in response" + _info "Record not found, may have been already removed" + return 0 + fi + + _debug contentid "$contentid" + + if _virakcloud_rest DELETE "domains/${_domain}/records/${fulldomain}/TXT/${contentid}" ""; then + if echo "$response" | grep -q "success" || [ -z "$response" ]; then + _info "Removed, OK" + return 0 + elif echo "$response" | grep -q "not found" || echo "$response" | grep -q "404"; then + _info "Record not found, OK" + return 0 + else + _err "Remove TXT record error." + _err "Response: $response" + return 1 + fi + fi + + _err "Remove TXT record error." + return 1 +} + +#################### Private functions below ################################## + +#_acme-challenge.www.domain.com +#returns +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + p=1 + + # Optimization: skip _acme-challenge subdomain to avoid 422 errors + if echo "$domain" | grep -q "^_acme-challenge."; then + i=2 + fi + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) + _debug h "$h" + + if [ -z "$h" ]; then + return 1 + fi + + if ! _virakcloud_rest GET "domains/$h" ""; then + http_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + if [ "$http_code" = "401" ]; then + return 1 + fi + p=$i + i=$(_math "$i" + 1) + continue + fi + + if echo "$response" | grep -q "\"name\""; then + _domain="$h" + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_virakcloud_rest() { + m=$1 + ep="$2" + data="$3" + + _debug "$ep" + + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $VIRAKCLOUD_API_TOKEN" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$VIRAKCLOUD_API_URL/$ep" "" "$m")" + else + response="$(_get "$VIRAKCLOUD_API_URL/$ep")" + fi + + _ret="$?" + + if [ "$_ret" != "0" ]; then + _err "error on $m $ep" + return 1 + fi + + http_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug "http response code" "$http_code" + + if [ "$http_code" = "401" ]; then + _err "VirakCloud API returned 401 Unauthorized." + _err "Your VIRAKCLOUD_API_TOKEN is invalid or expired." + _err "Please check your API token and try again." + return 1 + fi + + if [ "$http_code" = "403" ]; then + _err "VirakCloud API returned 403 Forbidden." + _err "Your API token does not have permission to access this resource." + return 1 + fi + + if [ -n "$http_code" ] && [ "$http_code" -ge 400 ]; then + _err "VirakCloud API error. HTTP code: $http_code" + _err "Response: $response" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/notify/pushover.sh b/notify/pushover.sh index 0f99739a..c59ec026 100644 --- a/notify/pushover.sh +++ b/notify/pushover.sh @@ -46,8 +46,8 @@ pushover_send() { fi export _H1="Content-Type: application/json" - _content="$(printf "*%s*\n" "$_content" | _json_encode)" - _subject="$(printf "*%s*\n" "$_subject" | _json_encode)" + _content="$(printf "%s" "$_content" | _json_encode)" + _subject="$(printf "%s" "$_subject" | _json_encode)" _data="{\"token\": \"$PUSHOVER_TOKEN\",\"user\": \"$PUSHOVER_USER\",\"title\": \"$_subject\",\"message\": \"$_content\",\"sound\": \"$PUSHOVER_SOUND\", \"device\": \"$PUSHOVER_DEVICE\", \"priority\": \"$PUSHOVER_PRIORITY\"}" response="$(_post "$_data" "$PUSHOVER_URI")"