mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-06-14 21:22:45 +00:00
Merge branch 'acmesh-official:master' into dns_efficientip
This commit is contained in:
commit
718ff3a5f5
18
.github/workflows/pr_dns.yml
vendored
18
.github/workflows/pr_dns.yml
vendored
@ -20,12 +20,26 @@ jobs:
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: `**Welcome**
|
||||
READ ME !!!!!
|
||||
|
||||
|
||||
Read me !!!!!!
|
||||
|
||||
|
||||
First thing: don't send PR to the master branch, please send to the dev branch instead.
|
||||
Please make sure you've read our [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test).
|
||||
|
||||
|
||||
Please read the [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test).
|
||||
|
||||
|
||||
Then reply on this message, otherwise, your code will not be reviewed or merged.
|
||||
|
||||
|
||||
Please also make sure to add/update the usage here: https://github.com/acmesh-official/acme.sh/wiki/dnsapi2
|
||||
We look forward to reviewing your Pull request shortly ✨
|
||||
|
||||
|
||||
注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试.
|
||||
|
||||
`
|
||||
})
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM alpine:3.17
|
||||
FROM alpine:3.21
|
||||
|
||||
RUN apk --no-cache add -f \
|
||||
openssl \
|
||||
|
9
acme.sh
9
acme.sh
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
VER=3.1.1
|
||||
VER=3.1.2
|
||||
|
||||
PROJECT_NAME="acme.sh"
|
||||
|
||||
@ -5504,6 +5504,13 @@ renew() {
|
||||
if [ -z "$Le_Keylength" ]; then
|
||||
Le_Keylength=2048
|
||||
fi
|
||||
if [ "$CA_LETSENCRYPT_V2" = "$Le_API" ]; then
|
||||
#letsencrypt doesn't support ocsp anymore
|
||||
if [ "$Le_OCSP_Staple" ]; then
|
||||
export Le_OCSP_Staple=""
|
||||
_cleardomainconf Le_OCSP_Staple
|
||||
fi
|
||||
fi
|
||||
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain" "$Le_Valid_From" "$Le_Valid_To"
|
||||
res="$?"
|
||||
if [ "$res" != "0" ]; then
|
||||
|
@ -80,10 +80,15 @@ vault_deploy() {
|
||||
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||
URL="$VAULT_ADDR/v1/auth/token/renew-self"
|
||||
_info "Renew the Vault token to default TTL"
|
||||
if ! _post "" "$URL" >/dev/null; then
|
||||
_response=$(_post "" "$URL")
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Failed to renew the Vault token"
|
||||
return 1
|
||||
fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Failed to renew the Vault token: $_response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
@ -91,29 +96,85 @@ vault_deploy() {
|
||||
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||
_info "Writing certificate and key to $URL in Fabio mode"
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL" >/dev/null || return 1
|
||||
_response=$(_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error: $_response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
|
||||
_response=$(_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error: $_response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing cert.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing cert.key: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing CA certificate to $URL/ca.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing ca.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing fullchain.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing cert.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_ckey\"}" "$URL/cert.key")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing cert.key: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing CA certificate to $URL/ca.pem"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/ca.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_cca\"}" "$URL/ca.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing ca.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing fullchain.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions
|
||||
@ -121,11 +182,20 @@ vault_deploy() {
|
||||
_err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
|
||||
_info "Updating CA certificate to $URL/chain.pem for backward compatibility"
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing chain.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem" >/dev/null || return 1
|
||||
_response=$(_post "{\"value\": \"$_cca\"}" "$URL/chain.pem")
|
||||
if [ "$?" != "0" ]; then return 1; fi
|
||||
if echo "$_response" | grep -q '"errors":\['; then
|
||||
_err "Vault error writing chain.pem: $_response"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
@ -340,8 +340,17 @@ _azure_getaccess_token() {
|
||||
|
||||
if [ "$managedIdentity" = true ]; then
|
||||
# https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
|
||||
export _H1="Metadata: true"
|
||||
response="$(_get http://169.254.169.254/metadata/identity/oauth2/token\?api-version=2018-02-01\&resource=https://management.azure.com/)"
|
||||
if [ -n "$IDENTITY_ENDPOINT" ]; then
|
||||
# Some Azure environments may set IDENTITY_ENDPOINT (formerly MSI_ENDPOINT) to have an alternative metadata endpoint
|
||||
url="$IDENTITY_ENDPOINT?api-version=2019-08-01&resource=https://management.azure.com/"
|
||||
headers="X-IDENTITY-HEADER: $IDENTITY_HEADER"
|
||||
else
|
||||
url="http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
|
||||
headers="Metadata: true"
|
||||
fi
|
||||
|
||||
export _H1="$headers"
|
||||
response="$(_get "$url")"
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
|
163
dnsapi/dns_edgecenter.sh
Normal file
163
dnsapi/dns_edgecenter.sh
Normal file
@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
# EdgeCenter DNS API integration for acme.sh
|
||||
# Author: Konstantin Ruchev <konstantin.ruchev@edgecenter.ru>
|
||||
dns_edgecenter_info='edgecenter DNS API
|
||||
Site: https://edgecenter.ru
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_edgecenter
|
||||
Options:
|
||||
EDGECENTER_API_KEY auth APIKey'
|
||||
|
||||
EDGECENTER_API="https://api.edgecenter.ru"
|
||||
DOMAIN_TYPE=
|
||||
DOMAIN_MASTER=
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_edgecenter_add _acme-challenge.www.domain.com "TXT_RECORD_VALUE"
|
||||
dns_edgecenter_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Using EdgeCenter DNS API"
|
||||
|
||||
if ! _dns_edgecenter_init_check; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Detecting root zone for $fulldomain"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
subdomain="${fulldomain%."$_zone"}"
|
||||
subdomain=${subdomain%.}
|
||||
|
||||
_debug "Zone: $_zone"
|
||||
_debug "Subdomain: $subdomain"
|
||||
_debug "TXT value: $txtvalue"
|
||||
|
||||
payload='{"resource_records": [ { "content": ["'"$txtvalue"'"] } ], "ttl": 60 }'
|
||||
_dns_edgecenter_http_api_call "post" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" "$payload"
|
||||
|
||||
if _contains "$response" '"error":"rrset is already exists"'; then
|
||||
_debug "RRSet exists, merging values"
|
||||
_dns_edgecenter_http_api_call "get" "dns/v2/zones/$_zone/$subdomain.$_zone/txt"
|
||||
current="$response"
|
||||
newlist=""
|
||||
for v in $(echo "$current" | sed -n 's/.*"content":\["\([^"]*\)"\].*/\1/p'); do
|
||||
newlist="$newlist {\"content\":[\"$v\"]},"
|
||||
done
|
||||
newlist="$newlist{\"content\":[\"$txtvalue\"]}"
|
||||
putdata="{\"resource_records\":[${newlist}]}
|
||||
"
|
||||
_dns_edgecenter_http_api_call "put" "dns/v2/zones/$_zone/$subdomain.$_zone/txt" "$putdata"
|
||||
_info "Updated existing RRSet with new TXT value."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if _contains "$response" '"exception":'; then
|
||||
_err "Record cannot be added."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "TXT record added successfully."
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: dns_edgecenter_rm _acme-challenge.www.domain.com "TXT_RECORD_VALUE"
|
||||
dns_edgecenter_rm() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Removing TXT record for $fulldomain"
|
||||
|
||||
if ! _dns_edgecenter_init_check; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
subdomain="${fulldomain%."$_zone"}"
|
||||
subdomain=${subdomain%.}
|
||||
|
||||
_dns_edgecenter_http_api_call "delete" "dns/v2/zones/$_zone/$subdomain.$_zone/txt"
|
||||
|
||||
if [ -z "$response" ]; then
|
||||
_info "TXT record deleted successfully."
|
||||
else
|
||||
_info "TXT record may not have been deleted: $response"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_dns_edgecenter_init_check() {
|
||||
EDGECENTER_API_KEY="${EDGECENTER_API_KEY:-$(_readaccountconf_mutable EDGECENTER_API_KEY)}"
|
||||
if [ -z "$EDGECENTER_API_KEY" ]; then
|
||||
_err "EDGECENTER_API_KEY was not exported."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable EDGECENTER_API_KEY "$EDGECENTER_API_KEY"
|
||||
export _H1="Authorization: APIKey $EDGECENTER_API_KEY"
|
||||
|
||||
_dns_edgecenter_http_api_call "get" "dns/v2/clients/me/features"
|
||||
if ! _contains "$response" '"id":'; then
|
||||
_err "Invalid API key."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-)
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
_dns_edgecenter_http_api_call "get" "dns/v2/zones/$h"
|
||||
if ! _contains "$response" 'zone is not found'; then
|
||||
_zone="$h"
|
||||
return 0
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_edgecenter_http_api_call() {
|
||||
mtd="$1"
|
||||
endpoint="$2"
|
||||
data="$3"
|
||||
|
||||
export _H1="Authorization: APIKey $EDGECENTER_API_KEY"
|
||||
|
||||
case "$mtd" in
|
||||
get)
|
||||
response="$(_get "$EDGECENTER_API/$endpoint")"
|
||||
;;
|
||||
post)
|
||||
response="$(_post "$data" "$EDGECENTER_API/$endpoint")"
|
||||
;;
|
||||
delete)
|
||||
response="$(_post "" "$EDGECENTER_API/$endpoint" "" "DELETE")"
|
||||
;;
|
||||
put)
|
||||
response="$(_post "$data" "$EDGECENTER_API/$endpoint" "" "PUT")"
|
||||
;;
|
||||
*)
|
||||
_err "Unknown HTTP method $mtd"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
_debug "HTTP $mtd response: $response"
|
||||
return 0
|
||||
}
|
212
dnsapi/dns_spaceship.sh
Normal file
212
dnsapi/dns_spaceship.sh
Normal file
@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_spaceship_info='Spaceship.com
|
||||
Site: Spaceship.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_spaceship
|
||||
Options:
|
||||
SPACESHIP_API_KEY Spaceship API Key
|
||||
SPACESHIP_API_SECRET Spaceship API Secret
|
||||
SPACESHIP_ROOT_DOMAIN (Optional) Manually specify the root domain if auto-detection fails
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/6304
|
||||
Author: Meow <https://github.com/Meo597>
|
||||
'
|
||||
|
||||
# Spaceship API
|
||||
# https://docs.spaceship.dev/
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
SPACESHIP_API_BASE="https://spaceship.dev/api/v1"
|
||||
|
||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
dns_spaceship_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Adding TXT record for $fulldomain with value $txtvalue"
|
||||
|
||||
# Initialize API credentials and headers
|
||||
if ! _spaceship_init; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detect root zone
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract subdomain part relative to root domain
|
||||
subdomain=$(echo "$fulldomain" | sed "s/\.$_domain$//")
|
||||
if [ "$subdomain" = "$fulldomain" ]; then
|
||||
_err "Failed to extract subdomain from $fulldomain relative to root domain $_domain"
|
||||
return 1
|
||||
fi
|
||||
_debug "Extracted subdomain: $subdomain for root domain: $_domain"
|
||||
|
||||
# Escape txtvalue to prevent JSON injection (e.g., quotes in txtvalue)
|
||||
escaped_txtvalue=$(echo "$txtvalue" | sed 's/"/\\"/g')
|
||||
|
||||
# Prepare payload and URL for adding TXT record
|
||||
# Note: 'name' in payload uses subdomain (e.g., _acme-challenge.sub) as required by Spaceship API
|
||||
payload="{\"force\": true, \"items\": [{\"type\": \"TXT\", \"name\": \"$subdomain\", \"value\": \"$escaped_txtvalue\", \"ttl\": 600}]}"
|
||||
url="$SPACESHIP_API_BASE/dns/records/$_domain"
|
||||
|
||||
# Send API request
|
||||
if _spaceship_api_request "PUT" "$url" "$payload"; then
|
||||
_info "Successfully added TXT record for $fulldomain"
|
||||
return 0
|
||||
else
|
||||
_err "Failed to add TXT record. If the domain $_domain is incorrect, set SPACESHIP_ROOT_DOMAIN to the correct root domain."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage: fulldomain txtvalue
|
||||
# Used to remove the txt record after validation
|
||||
dns_spaceship_rm() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Removing TXT record for $fulldomain with value $txtvalue"
|
||||
|
||||
# Initialize API credentials and headers
|
||||
if ! _spaceship_init; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detect root zone
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract subdomain part relative to root domain
|
||||
subdomain=$(echo "$fulldomain" | sed "s/\.$_domain$//")
|
||||
if [ "$subdomain" = "$fulldomain" ]; then
|
||||
_err "Failed to extract subdomain from $fulldomain relative to root domain $_domain"
|
||||
return 1
|
||||
fi
|
||||
_debug "Extracted subdomain: $subdomain for root domain: $_domain"
|
||||
|
||||
# Escape txtvalue to prevent JSON injection
|
||||
escaped_txtvalue=$(echo "$txtvalue" | sed 's/"/\\"/g')
|
||||
|
||||
# Prepare payload and URL for deleting TXT record
|
||||
# Note: 'name' in payload uses subdomain (e.g., _acme-challenge.sub) as required by Spaceship API
|
||||
payload="[{\"type\": \"TXT\", \"name\": \"$subdomain\", \"value\": \"$escaped_txtvalue\"}]"
|
||||
url="$SPACESHIP_API_BASE/dns/records/$_domain"
|
||||
|
||||
# Send API request
|
||||
if _spaceship_api_request "DELETE" "$url" "$payload"; then
|
||||
_info "Successfully deleted TXT record for $fulldomain"
|
||||
return 0
|
||||
else
|
||||
_err "Failed to delete TXT record. If the domain $_domain is incorrect, set SPACESHIP_ROOT_DOMAIN to the correct root domain."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_spaceship_init() {
|
||||
SPACESHIP_API_KEY="${SPACESHIP_API_KEY:-$(_readaccountconf_mutable SPACESHIP_API_KEY)}"
|
||||
SPACESHIP_API_SECRET="${SPACESHIP_API_SECRET:-$(_readaccountconf_mutable SPACESHIP_API_SECRET)}"
|
||||
|
||||
if [ -z "$SPACESHIP_API_KEY" ] || [ -z "$SPACESHIP_API_SECRET" ]; then
|
||||
_err "Spaceship API credentials are not set. Please set SPACESHIP_API_KEY and SPACESHIP_API_SECRET."
|
||||
_err "Ensure \"$LE_CONFIG_HOME\" directory has restricted permissions (chmod 700 \"$LE_CONFIG_HOME\") to protect credentials."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Save credentials to account config for future renewals
|
||||
_saveaccountconf_mutable SPACESHIP_API_KEY "$SPACESHIP_API_KEY"
|
||||
_saveaccountconf_mutable SPACESHIP_API_SECRET "$SPACESHIP_API_SECRET"
|
||||
|
||||
# Set common headers for API requests
|
||||
export _H1="X-API-Key: $SPACESHIP_API_KEY"
|
||||
export _H2="X-API-Secret: $SPACESHIP_API_SECRET"
|
||||
export _H3="Content-Type: application/json"
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
|
||||
# Check manual override
|
||||
SPACESHIP_ROOT_DOMAIN="${SPACESHIP_ROOT_DOMAIN:-$(_readdomainconf SPACESHIP_ROOT_DOMAIN)}"
|
||||
if [ -n "$SPACESHIP_ROOT_DOMAIN" ]; then
|
||||
_domain="$SPACESHIP_ROOT_DOMAIN"
|
||||
_debug "Using manually specified or saved root domain: $_domain"
|
||||
_savedomainconf SPACESHIP_ROOT_DOMAIN "$SPACESHIP_ROOT_DOMAIN"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_debug "Detecting root zone for '$domain'"
|
||||
|
||||
i=1
|
||||
p=1
|
||||
while true; do
|
||||
_cutdomain=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
|
||||
_debug "Attempt i=$i: Checking if '$_cutdomain' is root zone (cut ret=$?)"
|
||||
|
||||
if [ -z "$_cutdomain" ]; then
|
||||
_debug "Cut resulted in empty string, root zone not found."
|
||||
break
|
||||
fi
|
||||
|
||||
# Call the API to check if this _cutdomain is a manageable zone
|
||||
if _spaceship_api_request "GET" "$SPACESHIP_API_BASE/dns/records/$_cutdomain?take=1&skip=0"; then
|
||||
# API call succeeded (HTTP 200 OK for GET /dns/records)
|
||||
_domain="$_cutdomain"
|
||||
_debug "Root zone found: '$_domain'"
|
||||
|
||||
# Save the detected root domain
|
||||
_savedomainconf SPACESHIP_ROOT_DOMAIN "$_domain"
|
||||
_info "Root domain '$_domain' saved to configuration for future use."
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
_debug "API check failed for '$_cutdomain'. Continuing search."
|
||||
|
||||
p=$i
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
_err "Could not detect root zone for '$domain'. Please set SPACESHIP_ROOT_DOMAIN manually."
|
||||
return 1
|
||||
}
|
||||
|
||||
_spaceship_api_request() {
|
||||
method="$1"
|
||||
url="$2"
|
||||
payload="$3"
|
||||
|
||||
_debug2 "Sending $method request to $url with payload $payload"
|
||||
if [ "$method" = "GET" ]; then
|
||||
response="$(_get "$url")"
|
||||
else
|
||||
response="$(_post "$payload" "$url" "" "$method")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "API request failed. Response: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 "API response body: $response"
|
||||
|
||||
if [ "$method" = "GET" ]; then
|
||||
if _contains "$(_head_n 1 <"$HTTP_HEADER")" '200'; then
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
if _contains "$(_head_n 1 <"$HTTP_HEADER")" '204'; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
_debug2 "API response header: $HTTP_HEADER"
|
||||
return 1
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user