diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index be9d3aae..ccce2ff6 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -441,7 +441,9 @@ jobs: with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' copyback: false - prepare: pkgutil -y -i socat + prepare: | + pkgutil -U + pkgutil -y -i socat run: | pkg set-mediator -v -I default@1.1 openssl export PATH=/usr/gnu/bin:$PATH diff --git a/.github/workflows/Solaris.yml b/.github/workflows/Solaris.yml index 95bcd8d1..0ba3d2eb 100644 --- a/.github/workflows/Solaris.yml +++ b/.github/workflows/Solaris.yml @@ -66,7 +66,9 @@ jobs: envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET' nat: | "8080": "80" - prepare: pkgutil -y -i socat curl wget + prepare: | + pkgutil -U + pkgutil -y -i socat curl wget copyback: false run: | cd ../acmetest \ diff --git a/acme.sh b/acme.sh index da67fa14..ba0f62bc 100755 --- a/acme.sh +++ b/acme.sh @@ -1031,7 +1031,7 @@ _digest() { outputhex="$2" - if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then + if [ "$alg" = "sha3-256" ] || [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$outputhex" ]; then ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' else diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 53a82f91..90196c69 100755 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -97,12 +97,13 @@ _ali_rest() { } _ali_nonce() { - #_head_n 1 /dev/null && return 0 + fi + printf "%s" "$(date +%s)$$$(date +%N)" | _digest sha256 hex | cut -c 1-32 } -_timestamp() { +_ali_timestamp() { date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ" } @@ -150,7 +151,7 @@ _check_exist_query() { query=$query'&SignatureMethod=HMAC-SHA1' query=$query"&SignatureNonce=$(_ali_nonce)" query=$query'&SignatureVersion=1.0' - query=$query'&Timestamp='$(_timestamp) + query=$query'&Timestamp='$(_ali_timestamp) query=$query'&TypeKeyWord=TXT' query=$query'&Version=2015-01-09' } @@ -166,7 +167,7 @@ _add_record_query() { query=$query'&SignatureMethod=HMAC-SHA1' query=$query"&SignatureNonce=$(_ali_nonce)" query=$query'&SignatureVersion=1.0' - query=$query'&Timestamp='$(_timestamp) + query=$query'&Timestamp='$(_ali_timestamp) query=$query'&Type=TXT' query=$query'&Value='$3 query=$query'&Version=2015-01-09' @@ -182,7 +183,7 @@ _delete_record_query() { query=$query'&SignatureMethod=HMAC-SHA1' query=$query"&SignatureNonce=$(_ali_nonce)" query=$query'&SignatureVersion=1.0' - query=$query'&Timestamp='$(_timestamp) + query=$query'&Timestamp='$(_ali_timestamp) query=$query'&Version=2015-01-09' } @@ -196,7 +197,7 @@ _describe_records_query() { query=$query'&SignatureMethod=HMAC-SHA1' query=$query"&SignatureNonce=$(_ali_nonce)" query=$query'&SignatureVersion=1.0' - query=$query'&Timestamp='$(_timestamp) + query=$query'&Timestamp='$(_ali_timestamp) query=$query'&Version=2015-01-09' } diff --git a/dnsapi/dns_efficientip.sh b/dnsapi/dns_efficientip.sh new file mode 100755 index 00000000..a485849a --- /dev/null +++ b/dnsapi/dns_efficientip.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_efficientip_info='efficientip.com +Site: https://efficientip.com/ +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_efficientip +Options: + EfficientIP_Creds HTTP Basic Authentication credentials. E.g. "username:password" + EfficientIP_Server EfficientIP SOLIDserver Management IP address or FQDN. + EfficientIP_DNS_Name Name of the DNS smart or server hosting the zone. Optional. + EfficientIP_View Name of the DNS view hosting the zone. Optional. +OptionsAlt: + EfficientIP_Token_Key Alternative API token key, prefered over basic authentication. + EfficientIP_Token_Secret Alternative API token secret, required when using a token key. + EfficientIP_Server EfficientIP SOLIDserver Management IP address or FQDN. + EfficientIP_DNS_Name Name of the DNS smart or server hosting the zone. Optional. + EfficientIP_View Name of the DNS view hosting the zone. Optional. +Issues: github.com/acmesh-official/acme.sh/issues/6325 +Author: EfficientIP-Labs +' + +dns_efficientip_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using EfficientIP API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + if { [ -z "${EfficientIP_Creds}" ] && { [ -z "${EfficientIP_Token_Key}" ] || [ -z "${EfficientIP_Token_Secret}" ]; }; } || [ -z "${EfficientIP_Server}" ]; then + EfficientIP_Creds="" + EfficientIP_Token_Key="" + EfficientIP_Token_Secret="" + EfficientIP_Server="" + _err "You didn't specify any EfficientIP credentials or token or server (EfficientIP_Creds; EfficientIP_Token_Key; EfficientIP_Token_Secret; EfficientIP_Server)." + _err "Please set them via EXPORT EfficientIP_Creds=username:password or EXPORT EfficientIP_server=ip/hostname" + _err "or if you want to use Token instead EXPORT EfficientIP_Token_Key=yourkey" + _err "and EXPORT EfficientIP_Token_Secret=yoursecret" + _err "then try again." + return 1 + fi + + if [ -z "${EfficientIP_DNS_Name}" ]; then + EfficientIP_DNS_Name="" + fi + + EfficientIP_DNSNameEncoded=$(printf "%b" "${EfficientIP_DNS_Name}" | _url_encode) + + if [ -z "${EfficientIP_View}" ]; then + EfficientIP_View="" + fi + + EfficientIP_ViewEncoded=$(printf "%b" "${EfficientIP_View}" | _url_encode) + + _saveaccountconf EfficientIP_Creds "${EfficientIP_Creds}" + _saveaccountconf EfficientIP_Token_Key "${EfficientIP_Token_Key}" + _saveaccountconf EfficientIP_Token_Secret "${EfficientIP_Token_Secret}" + _saveaccountconf EfficientIP_Server "${EfficientIP_Server}" + _saveaccountconf EfficientIP_DNS_Name "${EfficientIP_DNS_Name}" + _saveaccountconf EfficientIP_View "${EfficientIP_View}" + + export _H1="Accept-Language:en-US" + baseurlnObject="https://${EfficientIP_Server}/rest/dns_rr_add?rr_type=TXT&rr_ttl=300&rr_name=${fulldomain}&rr_value1=${txtvalue}" + + if [ "${EfficientIP_DNSNameEncoded}" != "" ]; then + baseurlnObject="${baseurlnObject}&dns_name=${EfficientIP_DNSNameEncoded}" + fi + + if [ "${EfficientIP_ViewEncoded}" != "" ]; then + baseurlnObject="${baseurlnObject}&dnsview_name=${EfficientIP_ViewEncoded}" + fi + + if [ -z "${EfficientIP_Token_Secret}" ] || [ -z "${EfficientIP_Token_Key}" ]; then + EfficientIP_CredsEncoded=$(printf "%b" "${EfficientIP_Creds}" | _base64) + export _H2="Authorization: Basic ${EfficientIP_CredsEncoded}" + else + TS=$(date +%s) + Sig=$(printf "%b\n$TS\nPOST\n$baseurlnObject" "${EfficientIP_Token_Secret}" | _digest sha3-256 hex) + EfficientIP_CredsEncoded=$(printf "%b:%b" "${EfficientIP_Token_Key}" "$Sig") + export _H2="Authorization: SDS ${EfficientIP_CredsEncoded}" + export _H3="X-SDS-TS: ${TS}" + fi + + result="$(_post "" "${baseurlnObject}" "" "POST")" + + if [ "$(echo "${result}" | _egrep_o "ret_oid")" ]; then + _info "DNS record successfully created" + return 0 + else + _err "Error creating DNS record" + _err "${result}" + return 1 + fi +} + +dns_efficientip_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Using EfficientIP API" + _debug fulldomain "${fulldomain}" + _debug txtvalue "${txtvalue}" + + EfficientIP_ViewEncoded=$(printf "%b" "${EfficientIP_View}" | _url_encode) + EfficientIP_DNSNameEncoded=$(printf "%b" "${EfficientIP_DNS_Name}" | _url_encode) + EfficientIP_CredsEncoded=$(printf "%b" "${EfficientIP_Creds}" | _base64) + + export _H1="Accept-Language:en-US" + + baseurlnObject="https://${EfficientIP_Server}/rest/dns_rr_delete?rr_type=TXT&rr_name=$fulldomain&rr_value1=$txtvalue" + if [ "${EfficientIP_DNSNameEncoded}" != "" ]; then + baseurlnObject="${baseurlnObject}&dns_name=${EfficientIP_DNSNameEncoded}" + fi + + if [ "${EfficientIP_ViewEncoded}" != "" ]; then + baseurlnObject="${baseurlnObject}&dnsview_name=${EfficientIP_ViewEncoded}" + fi + + if [ -z "$EfficientIP_Token_Secret" ] || [ -z "$EfficientIP_Token_Key" ]; then + EfficientIP_CredsEncoded=$(printf "%b" "${EfficientIP_Creds}" | _base64) + export _H2="Authorization: Basic $EfficientIP_CredsEncoded" + else + TS=$(date +%s) + Sig=$(printf "%b\n$TS\nDELETE\n${baseurlnObject}" "${EfficientIP_Token_Secret}" | _digest sha3-256 hex) + EfficientIP_CredsEncoded=$(printf "%b:%b" "${EfficientIP_Token_Key}" "$Sig") + export _H2="Authorization: SDS ${EfficientIP_CredsEncoded}" + export _H3="X-SDS-TS: $TS" + fi + + result="$(_post "" "${baseurlnObject}" "" "DELETE")" + + if [ "$(echo "${result}" | _egrep_o "ret_oid")" ]; then + _info "DNS Record successfully deleted" + return 0 + else + _err "Error deleting DNS record" + _err "${result}" + return 1 + fi +} diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 0516fee9..aaef07bf 100644 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -23,6 +23,8 @@ dns_gandi_livedns_add() { fulldomain=$1 txtvalue=$2 + GANDI_LIVEDNS_KEY="${GANDI_LIVEDNS_KEY:-$(_readaccountconf_mutable GANDI_LIVEDNS_KEY)}" + GANDI_LIVEDNS_TOKEN="${GANDI_LIVEDNS_TOKEN:-$(_readaccountconf_mutable GANDI_LIVEDNS_TOKEN)}" if [ -z "$GANDI_LIVEDNS_KEY" ] && [ -z "$GANDI_LIVEDNS_TOKEN" ]; then _err "No Token or API key (deprecated) specified for Gandi LiveDNS." _err "Create your token or key and export it as GANDI_LIVEDNS_KEY or GANDI_LIVEDNS_TOKEN respectively" @@ -31,11 +33,11 @@ dns_gandi_livedns_add() { # Keep only one secret in configuration if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then - _saveaccountconf GANDI_LIVEDNS_TOKEN "$GANDI_LIVEDNS_TOKEN" - _clearaccountconf GANDI_LIVEDNS_KEY + _saveaccountconf_mutable GANDI_LIVEDNS_TOKEN "$GANDI_LIVEDNS_TOKEN" + _clearaccountconf_mutable GANDI_LIVEDNS_KEY elif [ -n "$GANDI_LIVEDNS_KEY" ]; then - _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY" - _clearaccountconf GANDI_LIVEDNS_TOKEN + _saveaccountconf_mutable GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY" + _clearaccountconf_mutable GANDI_LIVEDNS_TOKEN fi _debug "First detect the root zone" diff --git a/dnsapi/dns_mgwm.sh b/dnsapi/dns_mgwm.sh new file mode 100644 index 00000000..57679127 --- /dev/null +++ b/dnsapi/dns_mgwm.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env sh +# shellcheck disable=SC2034 +dns_mgwm_info='mgw-media.de +Site: mgw-media.de +Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_mgwm +Options: + MGWM_CUSTOMER Your customer number + MGWM_API_HASH Your API Hash +Issues: github.com/acmesh-official/acme.sh/issues/6669 +' +# Base URL for the mgw-media.de API +MGWM_API_BASE="https://api.mgw-media.de/record" + +######## Public functions ##################### + +# This function is called by acme.sh to add a TXT record. +dns_mgwm_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using mgw-media.de DNS API for domain $fulldomain (add record)" + _debug "fulldomain: $fulldomain" + _debug "txtvalue: $txtvalue" + + # Call the new private function to handle the API request. + # The 'add' action, fulldomain, type 'txt' and txtvalue are passed. + if _mgwm_request "add" "$fulldomain" "txt" "$txtvalue"; then + _info "TXT record for $fulldomain successfully added via mgw-media.de API." + _sleep 10 # Wait briefly for DNS propagation, a common practice in DNS-01 hooks. + return 0 + else + # Error message already logged by _mgwm_request, but a specific one here helps. + _err "mgwm_add: Failed to add TXT record for $fulldomain." + return 1 + fi +} +# This function is called by acme.sh to remove a TXT record after validation. +dns_mgwm_rm() { + fulldomain=$1 + txtvalue=$2 # This txtvalue is now used to identify the specific record to be removed. + _info "Removing TXT record for $fulldomain using mgw-media.de DNS API (remove record)" + _debug "fulldomain: $fulldomain" + _debug "txtvalue: $txtvalue" + + # Call the new private function to handle the API request. + # The 'rm' action, fulldomain, type 'txt' and txtvalue are passed. + if _mgwm_request "rm" "$fulldomain" "txt" "$txtvalue"; then + _info "TXT record for $fulldomain successfully removed via mgw-media.de API." + return 0 + else + # Error message already logged by _mgwm_request, but a specific one here helps. + _err "mgwm_rm: Failed to remove TXT record for $fulldomain." + return 1 + fi +} +#################### Private functions below ################################## + +# _mgwm_request() encapsulates the API call logic, including +# loading credentials, setting the Authorization header, and executing the request. +# Arguments: +# $1: action (e.g., "add", "rm") +# $2: fulldomain +# $3: type (e.g., "txt") +# $4: content (the txtvalue) +_mgwm_request() { + _action="$1" + _fulldomain="$2" + _type="$3" + _content="$4" + + _debug "Calling _mgwm_request for action: $_action, domain: $_fulldomain, type: $_type, content: $_content" + + # Load credentials from environment or acme.sh config + MGWM_CUSTOMER="${MGWM_CUSTOMER:-$(_readaccountconf_mutable MGWM_CUSTOMER)}" + MGWM_API_HASH="${MGWM_API_HASH:-$(_readaccountconf_mutable MGWM_API_HASH)}" + + # Check if credentials are set + if [ -z "$MGWM_CUSTOMER" ] || [ -z "$MGWM_API_HASH" ]; then + _err "You didn't specify one or more of MGWM_CUSTOMER or MGWM_API_HASH." + _err "Please check these environment variables and try again." + return 1 + fi + + # Save credentials for automatic renewal and future calls + _saveaccountconf_mutable MGWM_CUSTOMER "$MGWM_CUSTOMER" + _saveaccountconf_mutable MGWM_API_HASH "$MGWM_API_HASH" + + # Create the Basic Auth Header. acme.sh's _base64 function is used for encoding. + _credentials="$(printf "%s:%s" "$MGWM_CUSTOMER" "$MGWM_API_HASH" | _base64)" + export _H1="Authorization: Basic $_credentials" + _debug "Set Authorization Header: Basic " # Log debug message without sensitive credentials + + # Construct the API URL based on the action and provided parameters. + _request_url="${MGWM_API_BASE}/${_action}/${_fulldomain}/${_type}/${_content}" + _debug "Constructed mgw-media.de API URL for action '$_action': ${_request_url}" + + # Execute the HTTP GET request with the Authorization Header. + # The 5th parameter of _get is where acme.sh expects custom HTTP headers like Authorization. + response="$(_get "$_request_url")" + _debug "mgw-media.de API response for action '$_action': $response" + + # Check the API response for success. The API returns "OK" on success. + if [ "$response" = "OK" ]; then + _info "mgw-media.de API action '$_action' for record '$_fulldomain' successful." + return 0 + else + _err "Failed mgw-media.de API action '$_action' for record '$_fulldomain'. Unexpected API Response: '$response'" + return 1 + fi +}