-
-
Notifications
You must be signed in to change notification settings - Fork 5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fornex.com API v.2.2.0 support #5162
base: dev
Are you sure you want to change the base?
Changes from all commits
ebaa39b
0499e2d
bc90376
0d8a314
ece0ab8
67c5794
0b1f5af
84870b6
a73c767
e491d37
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,55 @@ | ||
#!/usr/bin/env sh | ||
# shellcheck disable=SC2034 | ||
dns_fornex_info='Fornex.com | ||
Site: Fornex.com | ||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_fornex | ||
Options: | ||
FORNEX_API_KEY API Key | ||
Issues: github.com/acmesh-official/acme.sh/issues/3998 | ||
Author: Timur Umarov <[email protected]> | ||
' | ||
|
||
FORNEX_API_URL="https://fornex.com/api/dns/v0.1" | ||
# Author: @SBohomolov <[email protected]> | ||
# Site: Fornex.com | ||
# Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_fornex | ||
# Bugs: https://github.com/acmesh-official/acme.sh/issues/5161 | ||
|
||
######## Public functions ##################### | ||
|
||
#Usage: dns_fornex_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||
## install jq ## | ||
|
||
# Check the operating system | ||
if [ "$(uname)" = "Darwin" ]; then | ||
# macOS - install jq using Homebrew | ||
if ! command -v brew >/dev/null 2>&1; then | ||
echo "Error: Homebrew is not installed. Please install Homebrew first." >&2 | ||
exit 1 | ||
fi | ||
brew install jq | ||
elif [ -f "/etc/redhat-release" ] || [ -f "/etc/centos-release" ] || [ -f "/etc/fedora-release" ]; then | ||
# RedHat/CentOS/Fedora - install jq using yum or dnf | ||
if command -v dnf >/dev/null 2>&1; then | ||
dnf install -y jq | ||
elif command -v yum >/dev/null 2>&1; then | ||
yum install -y jq | ||
else | ||
echo "Error: Neither yum nor dnf package manager found." >&2 | ||
exit 1 | ||
fi | ||
elif [ -f "/etc/lsb-release" ] || [ -f "/etc/debian_version" ]; then | ||
# Debian/Ubuntu - install jq using apt | ||
if command -v apt >/dev/null 2>&1; then | ||
apt update | ||
apt install -y jq | ||
else | ||
echo "Error: apt package manager not found." >&2 | ||
exit 1 | ||
fi | ||
else | ||
echo "Error: Unsupported operating system." >&2 | ||
exit 1 | ||
fi | ||
|
||
# jq installed successfully | ||
echo "jq installed successfully." | ||
|
||
####################################################### | ||
|
||
FORNEX_API_URL="https://fornex.com/api/dns/domain" | ||
|
||
######## Public functions ########################### | ||
|
||
# Usage: dns_fornex_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | ||
dns_fornex_add() { | ||
fulldomain=$1 | ||
txtvalue=$2 | ||
|
@@ -22,95 +58,90 @@ dns_fornex_add() { | |
return 1 | ||
fi | ||
|
||
if ! _get_root "$fulldomain"; then | ||
_err "Unable to determine root domain" | ||
domain=$(echo "$fulldomain" | sed 's/^\*\.//') | ||
|
||
if ! _get_domain_id "$domain"; then | ||
_err "Unable to determine domain ID" | ||
return 1 | ||
else | ||
_debug _domain "$_domain" | ||
_debug _domain_id "$_domain_id" | ||
fi | ||
|
||
_info "Adding record" | ||
if _rest POST "$_domain/entry_set/add/" "host=$fulldomain&type=TXT&value=$txtvalue&apikey=$FORNEX_API_KEY"; then | ||
_debug _response "$response" | ||
if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then | ||
_info "Added, OK" | ||
return 0 | ||
fi | ||
_info "Adding TXT record for $fulldomain" | ||
# Add the TXT record | ||
if ! _rest POST "$domain/entry_set/" "type=TXT&host=_acme-challenge&value=$txtvalue"; then | ||
_err "Failed to add TXT record" | ||
return 1 | ||
fi | ||
_err "Add txt record error." | ||
return 1 | ||
|
||
_info "TXT record added successfully" | ||
return 0 | ||
} | ||
|
||
#Usage: dns_fornex_rm _acme-challenge.www.domain.com | ||
dns_fornex_rm() { | ||
fulldomain=$1 | ||
txtvalue=$2 | ||
|
||
if ! _Fornex_API; then | ||
return 1 | ||
fi | ||
|
||
if ! _get_root "$fulldomain"; then | ||
_err "Unable to determine root domain" | ||
domain=$(echo "$fulldomain" | sed 's/^\*\.//') | ||
|
||
if ! _get_domain_id "$domain"; then | ||
_err "Unable to determine domain ID" | ||
return 1 | ||
else | ||
_debug _domain "$_domain" | ||
_debug _domain_id "$_domain_id" | ||
fi | ||
|
||
_debug "Getting txt records" | ||
_rest GET "$_domain/entry_set.json?apikey=$FORNEX_API_KEY" | ||
_info "Removing TXT records for domain: _acme-challenge.$domain" | ||
|
||
if ! _contains "$response" "$txtvalue"; then | ||
_err "Txt record not found" | ||
return 1 | ||
fi | ||
response=$(curl -X GET -H "Authorization: Api-Key $FORNEX_API_KEY" "https://fornex.com/api/dns/domain/$domain/entry_set/") | ||
|
||
# Extract TXT record IDs using jq | ||
txt_ids=$(echo "$response" | jq -r '.[] | select(.type == "TXT") | .id') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a total disaster! dns_fornex_rm() selects and removes ALL TXT records from a domain, regardless of what they contain and who created them. Bye-bye all marketing Previous version of the script checked TXT record value and only deleted TXT records with the value that script previously added. I would suggest at least check here that TXT record .host value starts with "_acme-challenge". I.e. use something like this: txt_ids=$(echo "$response" | jq -r '.[] | select(.type == "TXT") | select(.host | startswith("_acme-challenge")) | .id') |
||
|
||
_record_id="$(echo "$response" | _egrep_o "{[^{]*\"value\"*:*\"$txtvalue\"[^}]*}" | sed -n -e 's#.*"id": \([0-9]*\).*#\1#p')" | ||
_debug "_record_id" "$_record_id" | ||
if [ -z "$_record_id" ]; then | ||
_err "can not find _record_id" | ||
return 1 | ||
if [ -z "$txt_ids" ]; then | ||
_info "No TXT records found for domain: _acme-challenge.$domain" | ||
return 0 | ||
fi | ||
|
||
if ! _rest POST "$_domain/entry_set/$_record_id/delete/" "apikey=$FORNEX_API_KEY"; then | ||
_err "Delete record error." | ||
return 1 | ||
fi | ||
for txt_id in $txt_ids; do | ||
_info "Removing TXT record with ID: $txt_id" | ||
if ! curl -X DELETE -H "Authorization: Api-Key $FORNEX_API_KEY" "https://fornex.com/api/dns/domain/$domain/entry_set/$txt_id/"; then | ||
_err "Failed to remove TXT record with ID: $txt_id" | ||
else | ||
_info "TXT record with ID $txt_id removed successfully" | ||
fi | ||
done | ||
|
||
return 0 | ||
} | ||
|
||
#################### Private functions below ################################## | ||
|
||
#_acme-challenge.www.domain.com | ||
#returns | ||
# _acme-challenge.www.domain.com | ||
# returns | ||
# _sub_domain=_acme-challenge.www | ||
# _domain=domain.com | ||
_get_root() { | ||
_get_domain_id() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This updated script doesn't work correctly with subdomains. For example, if I have {
"name": "thedomain.com",
"created": "...",
"updated": "...",
"tags": [],
"entry_set": [
...
{
"id": <xxx>,
"host": "api",
"type": "A",
"prio": null,
"value": "xx.xx.xx.xx",
"ttl": null
},
... and I want to renew certificate for
Notice how previous version of the script uses while true; do loop to find a correct "root" domain to use. |
||
domain=$1 | ||
|
||
i=1 | ||
while true; do | ||
h=$(printf "%s" "$domain" | cut -d . -f $i-100) | ||
_debug h "$h" | ||
if [ -z "$h" ]; then | ||
#not valid | ||
return 1 | ||
fi | ||
_debug "Getting domain ID for $domain" | ||
|
||
if ! _rest GET "domain_list.json?q=$h&apikey=$FORNEX_API_KEY"; then | ||
return 1 | ||
fi | ||
if echo "$domain" | grep -q "_acme-challenge"; then | ||
# If yes, remove "_acme-challenge" from the domain name | ||
domain=$(echo "$domain" | sed 's/_acme-challenge\.//') | ||
fi | ||
|
||
if _contains "$response" "\"$h\"" >/dev/null; then | ||
_domain=$h | ||
return 0 | ||
else | ||
_debug "$h not found" | ||
fi | ||
i=$(_math "$i" + 1) | ||
done | ||
if ! _rest GET "$domain/entry_set/"; then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Error handling is somehow incorrect here. In the case outlined above when a domain {
"name": "thedomain.com",
"created": "...",
"updated": "...",
"tags": [],
"entry_set": [
...
{
"id": <xxx>,
"host": "api",
"type": "A",
"prio": null,
"value": "xx.xx.xx.xx",
"ttl": null
},
... this piece of code calls /api.thedomain.com/entry_set/, fornex DNS API 2.2.0 return error string:
But script ignores this error, and goes on as if nothing happened:
The script should handle this and other similar errors correctly, and terminate processing. |
||
_err "Failed to get domain ID for $domain" | ||
return 1 | ||
fi | ||
|
||
return 1 | ||
_domain_id="$response" | ||
_debug "Domain ID for $domain is $_domain_id" | ||
return 0 | ||
} | ||
|
||
_Fornex_API() { | ||
|
@@ -127,20 +158,23 @@ _Fornex_API() { | |
_saveaccountconf_mutable FORNEX_API_KEY "$FORNEX_API_KEY" | ||
} | ||
|
||
#method method action data | ||
# method method action data | ||
_rest() { | ||
m=$1 | ||
ep="$2" | ||
data="$3" | ||
_debug "$ep" | ||
|
||
export _H1="Accept: application/json" | ||
export _H2="Authorization: Api-Key $FORNEX_API_KEY" | ||
|
||
if [ "$m" != "GET" ]; then | ||
_debug data "$data" | ||
response="$(_post "$data" "$FORNEX_API_URL/$ep" "" "$m")" | ||
url="$FORNEX_API_URL/$ep" | ||
response=$(curl -X "$m" -H "Authorization: Api-Key $FORNEX_API_KEY" -d "$data" "$url") | ||
else | ||
response="$(_get "$FORNEX_API_URL/$ep" | _normalizeJson)" | ||
url="$FORNEX_API_URL/$ep" | ||
response=$(curl -X GET -H "Authorization: Api-Key $FORNEX_API_KEY" "$url") | ||
fi | ||
|
||
_ret="$?" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To work correctly with subdomains TXT record "host" value must be:
_acme-challenge[.subdomain]
.I.e. in the case when domain
api.thedomain.com
doesn't exist, but there isthedomain.com
domain with "host": "api" record:Script must create a TXT record with ".host" == "_acme-challenge.api" value, for example.
Script needs to be modified to account for this.