Merge pull request #1983 from Neilpang/dev

Dev
This commit is contained in:
neil 2018-12-24 19:33:05 +08:00 committed by GitHub
commit 37792e9b38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 483 additions and 39 deletions

View File

@ -330,6 +330,7 @@ You don't have to do anything manually!
1. MyDNS.JP API (https://www.mydns.jp/) 1. MyDNS.JP API (https://www.mydns.jp/)
1. hosting.de (https://www.hosting.de) 1. hosting.de (https://www.hosting.de)
1. Neodigit.net API (https://www.neodigit.net) 1. Neodigit.net API (https://www.neodigit.net)
1. Exoscale.com API (https://www.exoscale.com/)
And: And:

56
acme.sh
View File

@ -37,6 +37,7 @@ VTYPE_HTTP="http-01"
VTYPE_DNS="dns-01" VTYPE_DNS="dns-01"
VTYPE_TLS="tls-sni-01" VTYPE_TLS="tls-sni-01"
VTYPE_TLS2="tls-sni-02" VTYPE_TLS2="tls-sni-02"
VTYPE_ALPN="tls-alpn-01"
LOCAL_ANY_ADDRESS="0.0.0.0" LOCAL_ANY_ADDRESS="0.0.0.0"
@ -48,6 +49,7 @@ NO_VALUE="no"
W_TLS="tls" W_TLS="tls"
W_DNS="dns" W_DNS="dns"
W_ALPN="alpn"
DNS_ALIAS_PREFIX="=" DNS_ALIAS_PREFIX="="
MODE_STATELESS="stateless" MODE_STATELESS="stateless"
@ -1046,7 +1048,7 @@ _idn() {
fi fi
} }
#_createcsr cn san_list keyfile csrfile conf #_createcsr cn san_list keyfile csrfile conf acmeValidationv1
_createcsr() { _createcsr() {
_debug _createcsr _debug _createcsr
domain="$1" domain="$1"
@ -1054,6 +1056,7 @@ _createcsr() {
csrkey="$3" csrkey="$3"
csr="$4" csr="$4"
csrconf="$5" csrconf="$5"
acmeValidationv1="$6"
_debug2 domain "$domain" _debug2 domain "$domain"
_debug2 domainlist "$domainlist" _debug2 domainlist "$domainlist"
_debug2 csrkey "$csrkey" _debug2 csrkey "$csrkey"
@ -1062,7 +1065,9 @@ _createcsr() {
printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf" printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf"
if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then if [ "$acmeValidationv1" ]; then
printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf"
elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
#single domain #single domain
_info "Single domain" "$domain" _info "Single domain" "$domain"
printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf" printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
@ -1084,6 +1089,10 @@ _createcsr() {
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
fi fi
if [ "$acmeValidationv1" ]; then
printf "\n1.3.6.1.5.5.7.1.30.1=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}"
fi
_csr_cn="$(_idn "$domain")" _csr_cn="$(_idn "$domain")"
_debug2 _csr_cn "$_csr_cn" _debug2 _csr_cn "$_csr_cn"
if _contains "$(uname -a)" "MINGW"; then if _contains "$(uname -a)" "MINGW"; then
@ -2107,7 +2116,7 @@ _sleep() {
fi fi
} }
# _starttlsserver san_a san_b port content _ncaddr # _starttlsserver san_a san_b port content _ncaddr acmeValidationv1
_starttlsserver() { _starttlsserver() {
_info "Starting tls server." _info "Starting tls server."
san_a="$1" san_a="$1"
@ -2115,10 +2124,12 @@ _starttlsserver() {
port="$3" port="$3"
content="$4" content="$4"
opaddr="$5" opaddr="$5"
acmeValidationv1="$6"
_debug san_a "$san_a" _debug san_a "$san_a"
_debug san_b "$san_b" _debug san_b "$san_b"
_debug port "$port" _debug port "$port"
_debug acmeValidationv1 "$acmeValidationv1"
#create key TLS_KEY #create key TLS_KEY
if ! _createkey "2048" "$TLS_KEY"; then if ! _createkey "2048" "$TLS_KEY"; then
@ -2131,7 +2142,7 @@ _starttlsserver() {
if [ "$san_b" ]; then if [ "$san_b" ]; then
alt="$alt,$san_b" alt="$alt,$san_b"
fi fi
if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then
_err "Create tls validation csr error." _err "Create tls validation csr error."
return 1 return 1
fi fi
@ -2157,6 +2168,10 @@ _starttlsserver() {
__S_OPENSSL="$__S_OPENSSL -6" __S_OPENSSL="$__S_OPENSSL -6"
fi fi
if [ "$acmeValidationv1" ]; then
__S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1"
fi
_debug "$__S_OPENSSL" _debug "$__S_OPENSSL"
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
$__S_OPENSSL -tlsextdebug & $__S_OPENSSL -tlsextdebug &
@ -3067,8 +3082,8 @@ _on_before_issue() {
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort" _savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
fi fi
_checkport="$Le_HTTPPort" _checkport="$Le_HTTPPort"
elif [ "$_currentRoot" = "$W_TLS" ]; then elif [ "$_currentRoot" = "$W_TLS" ] || [ "$_currentRoot" = "$W_ALPN" ]; then
_info "Standalone tls mode." _info "Standalone tls/alpn mode."
if [ -z "$Le_TLSPort" ]; then if [ -z "$Le_TLSPort" ]; then
Le_TLSPort=443 Le_TLSPort=443
else else
@ -3694,6 +3709,10 @@ $_authorizations_map"
fi fi
fi fi
if [ "$_currentRoot" = "$W_ALPN" ]; then
vtype="$VTYPE_ALPN"
fi
if [ "$ACME_VERSION" = "2" ]; then if [ "$ACME_VERSION" = "2" ]; then
response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")" response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")"
_debug2 "response" "$response" _debug2 "response" "$response"
@ -4007,6 +4026,16 @@ $_authorizations_map"
_on_issue_err "$_post_hook" "$vlist" _on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
elif [ "$vtype" = "$VTYPE_ALPN" ]; then
acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
_debug acmevalidationv1 "$acmevalidationv1"
if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then
_err "Start tls server error."
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
fi fi
if ! __trigger_validation "$uri" "$keyauthorization"; then if ! __trigger_validation "$uri" "$keyauthorization"; then
@ -5469,6 +5498,7 @@ Parameters:
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure. --output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure.
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode. --standalone Use standalone mode.
--alpn Use standalone alpn mode.
--stateless Use stateless mode, see: $_STATELESS_WIKI --stateless Use stateless mode, see: $_STATELESS_WIKI
--apache Use apache mode. --apache Use apache mode.
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
@ -5499,6 +5529,7 @@ Parameters:
--accountkey Specifies the account key path, only valid for the '--install' command. --accountkey Specifies the account key path, only valid for the '--install' command.
--days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days. --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
--httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
--tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
--local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses. --local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
--listraw Only used for '--list' command, list the certs in raw format. --listraw Only used for '--list' command, list the certs in raw format.
--stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal. --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
@ -5823,6 +5854,14 @@ _process() {
_webroot="$_webroot,$wvalue" _webroot="$_webroot,$wvalue"
fi fi
;; ;;
--alpn)
wvalue="$W_ALPN"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--stateless) --stateless)
wvalue="$MODE_STATELESS" wvalue="$MODE_STATELESS"
if [ -z "$_webroot" ]; then if [ -z "$_webroot" ]; then
@ -5947,6 +5986,11 @@ _process() {
Le_HTTPPort="$_httpport" Le_HTTPPort="$_httpport"
shift shift
;; ;;
--tlsport)
_tlsport="$2"
Le_TLSPort="$_tlsport"
shift
;;
--listraw) --listraw)
_listraw="raw" _listraw="raw"
;; ;;

View File

@ -267,25 +267,26 @@ when needed.
## 14. Use Linode domain API ## 14. Use Linode domain API
The tokens created in the classic manager and cloud manager are incompatible
with one another. While the classic manager makes an all or nothing API, the
newer cloud manager interface promises to produce API keys with a finer
permission system. However, either way works just fine.
### Classic Manager ###
Classic Manager: https://manager.linode.com/profile/api
First you need to login to your Linode account to get your API Key. First you need to login to your Linode account to get your API Key.
* [Classic Manager](https://manager.linode.com/profile/api) Then add an API key with label *ACME* and copy the new key into the following
command.
Under "Add an API key", Give the new key a "Label" (we recommend *ACME*),
set the expiry to never, "Create API Key", and copy the new key into the `LINODE_API_KEY` command
below.
* [Cloud Manager](https://cloud.linode.com/profile/tokens)
Click on "Add a Personal Access Token". Give the new key a "Label" (we
recommend *ACME*), give it Read/Write access to "Domains". "Submit", and
copy the new key into the `LINODE_API_KEY` command below.
```sh ```sh
export LINODE_API_KEY="..." export LINODE_API_KEY="..."
``` ```
Due to the reload time of any changes in the DNS records, we have to use the `dnssleep` option to wait at least 15 minutes for the changes to take effect. Due to the reload time of any changes in the DNS records, we have to use the
`dnssleep` option to wait at least 15 minutes for the changes to take effect.
Ok, let's issue a cert now: Ok, let's issue a cert now:
@ -293,7 +294,35 @@ Ok, let's issue a cert now:
acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com
``` ```
The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be
reused when needed.
### Cloud Manager ###
Cloud Manager: https://cloud.linode.com/profile/tokens
First you need to login to your Linode account to get your API Key.
1. Click on "Add a Personal Access Token".
2. Give the new key a "Label" (we recommend *ACME*)
3. Give it Read/Write access to "Domains"
4. "Submit" and copy the new key into the `LINODE_V4_API_KEY` command below.
```sh
export LINODE_V4_API_KEY="..."
```
Due to the reload time of any changes in the DNS records, we have to use the
`dnssleep` option to wait at least 15 minutes for the changes to take effect.
Ok, let's issue a cert now:
```sh
acme.sh --issue --dns dns_linode_v4 --dnssleep 900 -d example.com -d www.example.com
```
The `LINODE_V4_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be
reused when needed.
## 15. Use FreeDNS ## 15. Use FreeDNS
@ -1080,6 +1109,24 @@ acme.sh --issue --dns dns_neodigit -d example.com -d www.example.com
Neodigit API Token will be saved in `~/.acme.sh/account.conf` and will be used when needed. Neodigit API Token will be saved in `~/.acme.sh/account.conf` and will be used when needed.
## 57. Use Exoscale API
Create an API key and secret key in the Exoscale account section
Set your API and secret key:
```
export EXOSCALE_API_KEY='xxx'
export EXOSCALE_SECRET_KEY='xxx'
```
Now, let's issue a cert:
```
acme.sh --issue --dns dns_netcup -d example.com -d www.example.com
```
The `EXOSCALE_API_KEY` and `EXOSCALE_SECRET_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
# Use custom API # Use custom API
If your API is not supported yet, you can write your own DNS API. If your API is not supported yet, you can write your own DNS API.

168
dnsapi/dns_exoscale.sh Executable file
View File

@ -0,0 +1,168 @@
#!/usr/bin/env sh
EXOSCALE_API=https://api.exoscale.com/dns/v1
######## Public functions #####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_exoscale_add() {
fulldomain=$1
txtvalue=$2
if ! _checkAuth; then
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"
_info "Adding record"
if _exoscale_rest POST "domains/$_domain_id/records" "{\"record\":{\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":120}}" "$_domain_token"; then
if _contains "$response" "$txtvalue"; then
_info "Added, OK"
return 0
fi
fi
_err "Add txt record error."
return 1
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
dns_exoscale_rm() {
fulldomain=$1
txtvalue=$2
if ! _checkAuth; then
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"
_debug "Getting txt records"
_exoscale_rest GET "domains/${_domain_id}/records?type=TXT&name=$_sub_domain" "" "$_domain_token"
if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then
_record_id=$(echo "$response" | tr '{' "\n" | grep "\"content\":\"$txtvalue\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \")
fi
if [ -z "$_record_id" ]; then
_err "Can not get record id to remove."
return 1
fi
_debug "Deleting record $_record_id"
if ! _exoscale_rest DELETE "domains/$_domain_id/records/$_record_id" "" "$_domain_token"; then
_err "Delete record error."
return 1
fi
return 0
}
#################### Private functions below ##################################
_checkAuth() {
EXOSCALE_API_KEY="${EXOSCALE_API_KEY:-$(_readaccountconf_mutable EXOSCALE_API_KEY)}"
EXOSCALE_SECRET_KEY="${EXOSCALE_SECRET_KEY:-$(_readaccountconf_mutable EXOSCALE_SECRET_KEY)}"
if [ -z "$EXOSCALE_API_KEY" ] || [ -z "$EXOSCALE_SECRET_KEY" ]; then
EXOSCALE_API_KEY=""
EXOSCALE_SECRET_KEY=""
_err "You don't specify Exoscale application key and application secret yet."
_err "Please create you key and try again."
return 1
fi
_saveaccountconf_mutable EXOSCALE_API_KEY "$EXOSCALE_API_KEY"
_saveaccountconf_mutable EXOSCALE_SECRET_KEY "$EXOSCALE_SECRET_KEY"
return 0
}
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
# _domain_token=sdjkglgdfewsdfg
_get_root() {
if ! _exoscale_rest GET "domains"; then
return 1
fi
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 _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \")
_domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_token" ] && [ "$_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
}
# returns response
_exoscale_rest() {
method=$1
path="$2"
data="$3"
token="$4"
request_url="$EXOSCALE_API/$path"
_debug "$path"
export _H1="Accept: application/json"
if [ "$token" ]; then
export _H2="X-DNS-Domain-Token: $token"
else
export _H2="X-DNS-Token: $EXOSCALE_API_KEY:$EXOSCALE_SECRET_KEY"
fi
if [ "$data" ] || [ "$method" = "DELETE" ]; then
export _H3="Content-Type: application/json"
_debug data "$data"
response="$(_post "$data" "$request_url" "" "$method")"
else
response="$(_get "$request_url" "" "" "$method")"
fi
if [ "$?" != "0" ]; then
_err "error $request_url"
return 1
fi
_debug2 response "$response"
return 0
}

View File

@ -2,7 +2,7 @@
#Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net> #Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
LINODE_API_URL="https://api.linode.com/v4/domains" LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action="
######## Public functions ##################### ######## Public functions #####################
@ -27,14 +27,10 @@ dns_linode_add() {
_debug _sub_domain "$_sub_domain" _debug _sub_domain "$_sub_domain"
_debug _domain "$_domain" _debug _domain "$_domain"
_payload="{ _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue"
\"type\": \"TXT\",
\"name\": \"$_sub_domain\",
\"target\": \"$txtvalue\"
}"
if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
_debug _resource_id "$_resource_id" _debug _resource_id "$_resource_id"
if [ -z "$_resource_id" ]; then if [ -z "$_resource_id" ]; then
@ -69,21 +65,25 @@ dns_linode_rm() {
_debug _sub_domain "$_sub_domain" _debug _sub_domain "$_sub_domain"
_debug _domain "$_domain" _debug _domain "$_domain"
if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then _parameters="&DomainID=$_domain_id"
if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")"
if [ "$resource" ]; then if [ "$resource" ]; then
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
if [ "$_resource_id" ]; then if [ "$_resource_id" ]; then
_debug _resource_id "$_resource_id" _debug _resource_id "$_resource_id"
if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id"
# On 200/OK, empty set is returned. Check for error, if any.
_error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1)
if [ -n "$_error_response" ]; then if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then
_err "Error deleting the domain resource: $_error_response" _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
_debug _resource_id "$_resource_id"
if [ -z "$_resource_id" ]; then
_err "Error deleting the domain resource."
return 1 return 1
fi fi
@ -127,7 +127,7 @@ _get_root() {
i=2 i=2
p=1 p=1
if _rest GET; then if _rest GET "domain.list"; then
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
while true; do while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100) h=$(printf "%s" "$domain" | cut -d . -f $i-100)
@ -137,9 +137,9 @@ _get_root() {
return 1 return 1
fi fi
hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")" hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")"
if [ "$hostedzone" ]; then if [ "$hostedzone" ]; then
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
if [ "$_domain_id" ]; then if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h _domain=$h
@ -165,7 +165,6 @@ _rest() {
export _H1="Accept: application/json" export _H1="Accept: application/json"
export _H2="Content-Type: application/json" export _H2="Content-Type: application/json"
export _H3="Authorization: Bearer $LINODE_API_KEY"
if [ "$mtd" != "GET" ]; then if [ "$mtd" != "GET" ]; then
# both POST and DELETE. # both POST and DELETE.

185
dnsapi/dns_linode_v4.sh Executable file
View File

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#Original Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
#v4 Update Author: Aaron W. Swenson <aaron@grandmasfridge.org>
LINODE_V4_API_URL="https://api.linode.com/v4/domains"
######## Public functions #####################
#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_linode_add() {
fulldomain="${1}"
txtvalue="${2}"
if ! _Linode_API; then
return 1
fi
_info "Using Linode"
_debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "Domain does not exist."
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_payload="{
\"type\": \"TXT\",
\"name\": \"$_sub_domain\",
\"target\": \"$txtvalue\"
}"
if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
_debug _resource_id "$_resource_id"
if [ -z "$_resource_id" ]; then
_err "Error adding the domain resource."
return 1
fi
_info "Domain resource successfully added."
return 0
fi
return 1
}
#Usage: dns_linode_rm _acme-challenge.www.domain.com
dns_linode_rm() {
fulldomain="${1}"
if ! _Linode_API; then
return 1
fi
_info "Using Linode"
_debug "Calling: dns_linode_rm() '${fulldomain}'"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "Domain does not exist."
return 1
fi
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")"
if [ "$resource" ]; then
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
if [ "$_resource_id" ]; then
_debug _resource_id "$_resource_id"
if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then
# On 200/OK, empty set is returned. Check for error, if any.
_error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1)
if [ -n "$_error_response" ]; then
_err "Error deleting the domain resource: $_error_response"
return 1
fi
_info "Domain resource successfully deleted."
return 0
fi
fi
return 1
fi
return 0
fi
return 1
}
#################### Private functions below ##################################
_Linode_API() {
if [ -z "$LINODE_V4_API_KEY" ]; then
LINODE_V4_API_KEY=""
_err "You didn't specify the Linode v4 API key yet."
_err "Please create your key and try again."
return 1
fi
_saveaccountconf LINODE_V4_API_KEY "$LINODE_V4_API_KEY"
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=12345
_get_root() {
domain=$1
i=2
p=1
if _rest GET; then
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")"
if [ "$hostedzone" ]; then
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | 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)
done
fi
return 1
}
#method method action data
_rest() {
mtd="$1"
ep="$2"
data="$3"
_debug mtd "$mtd"
_debug ep "$ep"
export _H1="Accept: application/json"
export _H2="Content-Type: application/json"
export _H3="Authorization: Bearer $LINODE_V4_API_KEY"
if [ "$mtd" != "GET" ]; then
# both POST and DELETE.
_debug data "$data"
response="$(_post "$data" "$LINODE_V4_API_URL$ep" "" "$mtd")"
else
response="$(_get "$LINODE_V4_API_URL$ep$data")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}