mirror of
https://github.com/hiskaNG/acme.sh.git
synced 2026-08-21 05:12:56 +00:00
Merge remote-tracking branch 'upstream/master' into dnsapi/dns_dnsever
This commit is contained in:
+53
-2
@@ -420,6 +420,7 @@ Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com
|
||||
```
|
||||
The `CLOUDNS_AUTH_ID` and `CLOUDNS_AUTH_PASSWORD` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 22. Use Infoblox API
|
||||
|
||||
@@ -511,7 +512,7 @@ acme.sh --issue --dns dns_nsone -d example.com -d www.example.com
|
||||
export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
```
|
||||
|
||||
Please note that since DuckDNS uses StartSSL as their cert provider, thus
|
||||
Please note that since DuckDNS uses StartSSL as their cert provider, thus
|
||||
--insecure may need to be used when issuing certs:
|
||||
```
|
||||
acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org
|
||||
@@ -601,7 +602,56 @@ The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/accoun
|
||||
|
||||
Please report any issues to https://github.com/angel333/acme.sh or to <me@ondrejsimek.com>.
|
||||
|
||||
##32. Use DNSEver (https://www.dnsever.com/)
|
||||
## 32. Use UnoEuro API to automatically issue cert
|
||||
|
||||
First you need to login to your UnoEuro account to get your API key.
|
||||
|
||||
```
|
||||
export UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
export UNO_User="UExxxxxx"
|
||||
```
|
||||
|
||||
Ok, let's issue a cert now:
|
||||
```
|
||||
acme.sh --issue --dns dns_unoeuro -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `UNO_Key` and `UNO_User` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 33. Use INWX
|
||||
|
||||
[INWX](https://www.inwx.de/) offers an [xmlrpc api](https://www.inwx.de/de/help/apidoc) with your standard login credentials, set them like so:
|
||||
|
||||
```
|
||||
export INWX_User="yourusername"
|
||||
export INWX_Password="password"
|
||||
```
|
||||
|
||||
Then you can issue your certificates with:
|
||||
|
||||
```
|
||||
acme.sh --issue --dns dns_inwx -d example.com -d www.example.com
|
||||
```
|
||||
|
||||
The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
## 34. User Servercow API v1
|
||||
|
||||
Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user.
|
||||
|
||||
```
|
||||
export SERVERCOW_API_Username=username
|
||||
export SERVERCOW_API_Password=password
|
||||
```
|
||||
|
||||
Now you cann issue a cert:
|
||||
|
||||
```
|
||||
acme.sh --issue --dns dns_servercow -d example.com -d www.example.com
|
||||
```
|
||||
Both, `SERVERCOW_API_Username` and `SERVERCOW_API_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
|
||||
|
||||
##35. Use DNSEver (https://www.dnsever.com/)
|
||||
|
||||
You will need your login credentials (ID+PW) to the DNSEver, and export them before you run acme.sh:
|
||||
```
|
||||
@@ -631,6 +681,7 @@ acme.sh --issue --dns dns_myapi -d example.com -d www.example.com
|
||||
|
||||
For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh)
|
||||
|
||||
See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
|
||||
|
||||
# Use lexicon DNS API
|
||||
|
||||
|
||||
+10
-9
@@ -87,6 +87,7 @@ _get_root() {
|
||||
_debug "response" "$response"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug2 "Checking domain: $h"
|
||||
if [ -z "$h" ]; then
|
||||
if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
|
||||
_debug "IsTruncated"
|
||||
@@ -102,23 +103,23 @@ _get_root() {
|
||||
fi
|
||||
fi
|
||||
#not valid
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "<Name>$h.</Name>"; then
|
||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
||||
_debug hostedzone "$hostedzone"
|
||||
if [ -z "$hostedzone" ]; then
|
||||
_err "Error, can not get hostedzone."
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
_err "Can not find domain id: $h"
|
||||
return 1
|
||||
fi
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
|
||||
@@ -96,6 +96,16 @@ _dns_cloudns_init_check() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}"
|
||||
CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}"
|
||||
if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then
|
||||
CLOUDNS_AUTH_ID=""
|
||||
CLOUDNS_AUTH_PASSWORD=""
|
||||
_err "You don't specify cloudns api id and password yet."
|
||||
_err "Please create you id and password and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$CLOUDNS_AUTH_ID" ]; then
|
||||
_err "CLOUDNS_AUTH_ID is not configured"
|
||||
return 1
|
||||
@@ -113,6 +123,10 @@ _dns_cloudns_init_check() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api id and password to the account conf file.
|
||||
_saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID"
|
||||
_saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD"
|
||||
|
||||
CLOUDNS_INIT_CHECK_COMPLETED=1
|
||||
|
||||
return 0
|
||||
|
||||
+32
-45
@@ -53,6 +53,8 @@ dns_freedns_add() {
|
||||
i="$(_math "$i" - 1)"
|
||||
sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
|
||||
|
||||
_debug top_domain "$top_domain"
|
||||
_debug sub_domain "$sub_domain"
|
||||
# Sometimes FreeDNS does not return the subdomain page but rather
|
||||
# returns a page regarding becoming a premium member. This usually
|
||||
# happens after a period of inactivity. Immediately trying again
|
||||
@@ -61,7 +63,6 @@ dns_freedns_add() {
|
||||
attempts=2
|
||||
while [ "$attempts" -gt "0" ]; do
|
||||
attempts="$(_math "$attempts" - 1)"
|
||||
|
||||
htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
|
||||
if [ "$?" != "0" ]; then
|
||||
if [ "$using_cached_cookies" = "true" ]; then
|
||||
@@ -70,19 +71,11 @@ dns_freedns_add() {
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
_debug2 htmlpage "$htmlpage"
|
||||
|
||||
subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$top_domain")"
|
||||
_debug2 subdomain_csv "$subdomain_csv"
|
||||
|
||||
# Now convert the tables in the HTML to CSV. This litte gem from
|
||||
# http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
|
||||
subdomain_csv="$(echo "$htmlpage" \
|
||||
| grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
|
||||
| sed 's/^[\ \t]*//g' \
|
||||
| tr -d '\n' \
|
||||
| sed 's/<\/TR[^>]*>/\n/Ig' \
|
||||
| sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \
|
||||
| sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' \
|
||||
| sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig' \
|
||||
| grep 'edit.php?' \
|
||||
| grep "$top_domain")"
|
||||
# The above beauty ends with striping out rows that do not have an
|
||||
# href to edit.php and do not have the top domain we are looking for.
|
||||
# So all we should be left with is CSV of table of subdomains we are
|
||||
@@ -90,30 +83,32 @@ dns_freedns_add() {
|
||||
|
||||
# Now we have to read through this table and extract the data we need
|
||||
lines="$(echo "$subdomain_csv" | wc -l)"
|
||||
nl='
|
||||
'
|
||||
i=0
|
||||
found=0
|
||||
while [ "$i" -lt "$lines" ]; do
|
||||
i="$(_math "$i" + 1)"
|
||||
line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")"
|
||||
tmp="$(echo "$line" | cut -d ',' -f 1)"
|
||||
if [ $found = 0 ] && _startswith "$tmp" "<td>$top_domain"; then
|
||||
line="$(echo "$subdomain_csv" | sed -n "${i}p")"
|
||||
_debug2 line "$line"
|
||||
if [ $found = 0 ] && _contains "$line" "<td>$top_domain</td>"; then
|
||||
# this line will contain DNSdomainid for the top_domain
|
||||
DNSdomainid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')"
|
||||
DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)"
|
||||
_debug2 DNSdomainid "$DNSdomainid"
|
||||
found=1
|
||||
else
|
||||
# lines contain DNS records for all subdomains
|
||||
DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')"
|
||||
DNStype="$(echo "$line" | cut -d ',' -f 3)"
|
||||
DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug2 DNSname "$DNSname"
|
||||
DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug2 DNStype "$DNStype"
|
||||
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
|
||||
DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')"
|
||||
DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)"
|
||||
# Now get current value for the TXT record. This method may
|
||||
# not produce accurate results as the value field is truncated
|
||||
# on this webpage. To get full value we would need to load
|
||||
# another page. However we don't really need this so long as
|
||||
# there is only one TXT record for the acme challenge subdomain.
|
||||
DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
|
||||
DNSvalue="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '5p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug2 DNSvalue "$DNSvalue"
|
||||
if [ $found != 0 ]; then
|
||||
break
|
||||
# we are breaking out of the loop at the first match of DNS name
|
||||
@@ -169,8 +164,7 @@ dns_freedns_add() {
|
||||
return 0
|
||||
else
|
||||
# Delete the old TXT record (with the wrong value)
|
||||
_freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"
|
||||
if [ "$?" = "0" ]; then
|
||||
if _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"; then
|
||||
# And add in new TXT record with the value provided
|
||||
_freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
|
||||
fi
|
||||
@@ -210,18 +204,9 @@ dns_freedns_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Now convert the tables in the HTML to CSV. This litte gem from
|
||||
# http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv
|
||||
subdomain_csv="$(echo "$htmlpage" \
|
||||
| grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
|
||||
| sed 's/^[\ \t]*//g' \
|
||||
| tr -d '\n' \
|
||||
| sed 's/<\/TR[^>]*>/\n/Ig' \
|
||||
| sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \
|
||||
| sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' \
|
||||
| sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig' \
|
||||
| grep 'edit.php?' \
|
||||
| grep "$fulldomain")"
|
||||
subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '<form .*</form>' | sed 's/<tr>/@<tr>/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")"
|
||||
_debug2 subdomain_csv "$subdomain_csv"
|
||||
|
||||
# The above beauty ends with striping out rows that do not have an
|
||||
# href to edit.php and do not have the domain name we are looking for.
|
||||
# So all we should be left with is CSV of table of subdomains we are
|
||||
@@ -229,19 +214,21 @@ dns_freedns_rm() {
|
||||
|
||||
# Now we have to read through this table and extract the data we need
|
||||
lines="$(echo "$subdomain_csv" | wc -l)"
|
||||
nl='
|
||||
'
|
||||
i=0
|
||||
found=0
|
||||
while [ "$i" -lt "$lines" ]; do
|
||||
i="$(_math "$i" + 1)"
|
||||
line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")"
|
||||
DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')"
|
||||
DNStype="$(echo "$line" | cut -d ',' -f 3)"
|
||||
line="$(echo "$subdomain_csv" | sed -n "${i}p")"
|
||||
_debug2 line "$line"
|
||||
DNSname="$(echo "$line" | _egrep_o 'edit.php.*</a>' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug2 DNSname "$DNSname"
|
||||
DNStype="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '4p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug2 DNStype "$DNStype"
|
||||
if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then
|
||||
DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')"
|
||||
DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')"
|
||||
_debug "DNSvalue: $DNSvalue"
|
||||
DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)"
|
||||
_debug2 DNSdataid "$DNSdataid"
|
||||
DNSvalue="$(echo "$line" | sed 's/<td/@<td/g' | tr '@' '\n' | sed -n '5p' | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug2 DNSvalue "$DNSvalue"
|
||||
# if [ "$DNSvalue" = "$txtvalue" ]; then
|
||||
# Testing value match fails. Website is truncating the value
|
||||
# field. So for now we will assume that there is only one TXT
|
||||
|
||||
@@ -0,0 +1,355 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#INWX_User="username"
|
||||
#
|
||||
#INWX_Password="password"
|
||||
|
||||
INWX_Api="https://api.domrobot.com/xmlrpc/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_inwx_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
|
||||
INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
|
||||
if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
|
||||
INWX_User=""
|
||||
INWX_Password=""
|
||||
_err "You don't specify inwx user and password yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable INWX_User "$INWX_User"
|
||||
_saveaccountconf_mutable INWX_Password "$INWX_Password"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug "Getting txt records"
|
||||
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>nameserver.info</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>domain</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>type</name>
|
||||
<value>
|
||||
<string>TXT</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>name</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>' "$_domain" "$_sub_domain")
|
||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||
|
||||
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
|
||||
_err "Error could net get txt records"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! printf "%s" "$response" | grep "count" >/dev/null; then
|
||||
_info "Adding record"
|
||||
_inwx_add_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
else
|
||||
_record_id=$(printf '%s' "$response" | _egrep_o '.*(<member><name>record){1}(.*)([0-9]+){1}' | _egrep_o '<name>id<\/name><value><int>[0-9]+' | _egrep_o '[0-9]+')
|
||||
_info "Updating record"
|
||||
_inwx_update_record "$_record_id" "$txtvalue"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_inwx_rm() {
|
||||
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
|
||||
INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
|
||||
if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
|
||||
INWX_User=""
|
||||
INWX_Password=""
|
||||
_err "You don't specify inwx user and password yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable INWX_User "$INWX_User"
|
||||
_saveaccountconf_mutable INWX_Password "$INWX_Password"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>nameserver.info</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>domain</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>type</name>
|
||||
<value>
|
||||
<string>TXT</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>name</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>' "$_domain" "$_sub_domain")
|
||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||
|
||||
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
|
||||
_err "Error could not get txt records"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! printf "%s" "$response" | grep "count" >/dev/null; then
|
||||
_info "Do not need to delete record"
|
||||
else
|
||||
_record_id=$(printf '%s' "$response" | _egrep_o '.*(<member><name>record){1}(.*)([0-9]+){1}' | _egrep_o '<name>id<\/name><value><int>[0-9]+' | _egrep_o '[0-9]+')
|
||||
_info "Deleting record"
|
||||
_inwx_delete_record "$_record_id"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_inwx_login() {
|
||||
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>account.login</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>user</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>pass</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>' $INWX_User $INWX_Password)
|
||||
|
||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||
|
||||
printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')"
|
||||
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
_debug "get root"
|
||||
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
_H1=$(_inwx_login)
|
||||
export _H1
|
||||
xml_content='<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>nameserver.list</methodName>
|
||||
</methodCall>'
|
||||
|
||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "$h"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
_inwx_delete_record() {
|
||||
record_id=$1
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>nameserver.deleteRecord</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>id</name>
|
||||
<value>
|
||||
<int>%s</int>
|
||||
</value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>' "$record_id")
|
||||
|
||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||
|
||||
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
_inwx_update_record() {
|
||||
record_id=$1
|
||||
txtval=$2
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>nameserver.updateRecord</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>content</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>id</name>
|
||||
<value>
|
||||
<int>%s</int>
|
||||
</value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>' "$txtval" "$record_id")
|
||||
|
||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||
|
||||
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
_inwx_add_record() {
|
||||
|
||||
domain=$1
|
||||
sub_domain=$2
|
||||
txtval=$3
|
||||
|
||||
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>nameserver.createRecord</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>domain</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>type</name>
|
||||
<value>
|
||||
<string>TXT</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>content</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
<member>
|
||||
<name>name</name>
|
||||
<value>
|
||||
<string>%s</string>
|
||||
</value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>' "$domain" "$txtval" "$sub_domain")
|
||||
|
||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||
|
||||
if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##########
|
||||
# Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/Neilpang/acme.sh)
|
||||
#
|
||||
# Usage:
|
||||
# export SERVERCOW_API_Username=username
|
||||
# export SERVERCOW_API_Password=password
|
||||
# acme.sh --issue -d example.com --dns dns_servercow
|
||||
#
|
||||
# Issues:
|
||||
# Any issues / questions / suggestions can be posted here:
|
||||
# https://github.com/jhartlep/servercow-dns-api/issues
|
||||
#
|
||||
# Author: Jens Hartlep
|
||||
##########
|
||||
|
||||
SERVERCOW_API="https://api.servercow.de/dns/v1/domains"
|
||||
|
||||
# Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz"
|
||||
dns_servercow_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Using servercow"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}"
|
||||
SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}"
|
||||
if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then
|
||||
SERVERCOW_API_Username=""
|
||||
SERVERCOW_API_Password=""
|
||||
_err "You don't specify servercow api username and password yet."
|
||||
_err "Please create your username and password and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# save the credentials to the account conf file
|
||||
_saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username"
|
||||
_saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then
|
||||
if printf -- "%s" "$response" | grep "ok" >/dev/null; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "add txt record error."
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Usage fulldomain txtvalue
|
||||
# Remove the txt record after validation
|
||||
dns_servercow_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Using servercow"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$fulldomain"
|
||||
|
||||
SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}"
|
||||
SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}"
|
||||
if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then
|
||||
SERVERCOW_API_Username=""
|
||||
SERVERCOW_API_Password=""
|
||||
_err "You don't specify servercow api username and password yet."
|
||||
_err "Please create your username and password and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then
|
||||
if printf -- "%s" "$response" | grep "ok" >/dev/null; then
|
||||
_info "Deleted, OK"
|
||||
_contains "$response" '"message":"ok"'
|
||||
else
|
||||
_err "delete txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
# _acme-challenge.www.domain.com
|
||||
# returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
fulldomain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100)
|
||||
|
||||
_debug _domain "$_domain"
|
||||
if [ -z "$_domain" ]; then
|
||||
# not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _servercow_api GET "$_domain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then
|
||||
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p)
|
||||
if [ -z "$_sub_domain" ]; then
|
||||
# not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_servercow_api() {
|
||||
method=$1
|
||||
domain=$2
|
||||
data="$3"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="X-Auth-Username: $SERVERCOW_API_Username"
|
||||
export _H3="X-Auth-Password: $SERVERCOW_API_Password"
|
||||
|
||||
if [ "$method" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")"
|
||||
else
|
||||
response="$(_get "$SERVERCOW_API/$domain")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $domain"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#UNO_User="UExxxxxx"
|
||||
|
||||
Uno_Api="https://api.unoeuro.com/1"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_unoeuro_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}"
|
||||
UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}"
|
||||
if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then
|
||||
UNO_Key=""
|
||||
UNO_User=""
|
||||
_err "You haven't specified a UnoEuro api key and account yet."
|
||||
_err "Please create your key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$UNO_User" "UE"; then
|
||||
_err "It seems that the UNO_User=$UNO_User is not a valid username."
|
||||
_err "Please check and retry."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable UNO_Key "$UNO_Key"
|
||||
_saveaccountconf_mutable UNO_User "$UNO_User"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_uno_rest GET "my/products/$h/dns/records"
|
||||
|
||||
if ! _contains "$response" "\"status\": 200" >/dev/null; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$_sub_domain" >/dev/null; then
|
||||
_info "Adding record"
|
||||
|
||||
if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if _contains "$response" "\"status\": 200" >/dev/null; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
else
|
||||
_info "Updating record"
|
||||
record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1)
|
||||
record_line_number=$(_math "$record_line_number" - 1)
|
||||
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}")
|
||||
_debug "record_id" "$record_id"
|
||||
|
||||
_uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"
|
||||
if _contains "$response" "\"status\": 200" >/dev/null; then
|
||||
_info "Updated, OK"
|
||||
return 0
|
||||
fi
|
||||
_err "Update error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_unoeuro_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}"
|
||||
UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}"
|
||||
if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then
|
||||
UNO_Key=""
|
||||
UNO_User=""
|
||||
_err "You haven't specified a UnoEuro api key and account yet."
|
||||
_err "Please create your key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$UNO_User" "UE"; then
|
||||
_err "It seems that the UNO_User=$UNO_User is not a valid username."
|
||||
_err "Please check and retry."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_uno_rest GET "my/products/$h/dns/records"
|
||||
|
||||
if ! _contains "$response" "\"status\": 200"; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$_sub_domain"; then
|
||||
_info "Don't need to remove."
|
||||
else
|
||||
record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1)
|
||||
record_line_number=$(_math "$record_line_number" - 1)
|
||||
record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}")
|
||||
_debug "record_id" "$record_id"
|
||||
|
||||
if [ -z "$record_id" ]; then
|
||||
_err "Can not get record id to remove."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
_contains "$response" "\"status\": 200"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### 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=2
|
||||
p=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
|
||||
|
||||
if ! _uno_rest GET "my/products/$h/dns/records"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"status\": 200"; then
|
||||
_domain_id=$h
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_uno_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$Uno_Api/$UNO_User/$UNO_Key/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$Uno_Api/$UNO_User/$UNO_Key/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user