Merge branch 'dev' into dns_nexcess_thermo_fh

This commit is contained in:
Frank Laszlo 2019-01-21 15:15:32 -05:00 committed by GitHub
commit f7c933a088
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1094 additions and 227 deletions

View File

@ -70,11 +70,16 @@ For all build statuses, check our [weekly build project](https://github.com/Neil
https://github.com/Neilpang/acmetest
# Supported CA
- Letsencrypt.org CA(default)
- [BuyPass.com CA](https://github.com/Neilpang/acme.sh/wiki/BuyPass.com-CA)
# Supported modes
- Webroot mode
- Standalone mode
- Standalone tls-alpn mode
- Apache mode
- Nginx mode
- DNS mode
@ -221,8 +226,20 @@ acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 5. Use Standalone ssl server to issue cert
# 5. Use Apache mode
**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))**
Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again.
```bash
acme.sh --issue --alpn -d example.com -d www.example.com -d cp.example.com
```
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 6. Use Apache mode
**(requires you to be root/sudoer, since it is required to interact with Apache server)**
@ -242,7 +259,7 @@ We don't want to mess your apache server, don't worry.**
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 6. Use Nginx mode
# 7. Use Nginx mode
**(requires you to be root/sudoer, since it is required to interact with Nginx server)**
@ -266,7 +283,7 @@ We don't want to mess your nginx server, don't worry.**
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 7. Automatic DNS API integration
# 8. Automatic DNS API integration
If your DNS provider supports API access, we can use that API to automatically issue the certs.
@ -330,6 +347,8 @@ You don't have to do anything manually!
1. MyDNS.JP API (https://www.mydns.jp/)
1. hosting.de (https://www.hosting.de)
1. Neodigit.net API (https://www.neodigit.net)
1. Exoscale.com API (https://www.exoscale.com/)
1. PointDNS API (https://pointhq.com/)
1. Nexcess API (https://www.nexcess.net)
1. Thermo.io API (https://www.thermo.io)
1. Futurehosting API (https://www.futurehosting.com)
@ -346,7 +365,7 @@ If your DNS provider is not on the supported list above, you can write your own
For more details: [How to use DNS API](dnsapi)
# 8. Use DNS manual mode:
# 9. Use DNS manual mode:
See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first.
@ -382,7 +401,7 @@ Ok, it's done.
**Please use dns api mode instead.**
# 9. Issue ECC certificates
# 10. Issue ECC certificates
`Let's Encrypt` can now issue **ECDSA** certificates.
@ -414,7 +433,7 @@ Valid values are:
# 10. Issue Wildcard certificates
# 11. Issue Wildcard certificates
It's simple, just give a wildcard domain as the `-d` parameter.
@ -424,7 +443,7 @@ acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf
# 11. How to renew the certs
# 12. How to renew the certs
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
@ -441,7 +460,7 @@ acme.sh --renew -d example.com --force --ecc
```
# 12. How to stop cert renewal
# 13. How to stop cert renewal
To stop renewal of a cert, you can execute the following to remove the cert from the renewal list:
@ -454,7 +473,7 @@ The cert/key file is not removed from the disk.
You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself.
# 13. How to upgrade `acme.sh`
# 14. How to upgrade `acme.sh`
acme.sh is in constant development, so it's strongly recommended to use the latest code.
@ -479,25 +498,25 @@ acme.sh --upgrade --auto-upgrade 0
```
# 14. Issue a cert from an existing CSR
# 15. Issue a cert from an existing CSR
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
# 15. Under the Hood
# 16. Under the Hood
Speak ACME language using shell, directly to "Let's Encrypt".
TODO:
# 16. Acknowledgments
# 17. Acknowledgments
1. Acme-tiny: https://github.com/diafygi/acme-tiny
2. ACME protocol: https://github.com/ietf-wg-acme/acme
# 17. License & Others
# 18. License & Others
License is GPLv3
@ -506,7 +525,7 @@ Please Star and Fork me.
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
# 18. Donate
# 19. Donate
Your donation makes **acme.sh** better:
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)

129
acme.sh
View File

@ -36,11 +36,11 @@ _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org"
VTYPE_HTTP="http-01"
VTYPE_DNS="dns-01"
VTYPE_TLS="tls-sni-01"
VTYPE_TLS2="tls-sni-02"
VTYPE_ALPN="tls-alpn-01"
LOCAL_ANY_ADDRESS="0.0.0.0"
MAX_RENEW=60
DEFAULT_RENEW=60
DEFAULT_DNS_SLEEP=120
@ -48,6 +48,7 @@ NO_VALUE="no"
W_TLS="tls"
W_DNS="dns"
W_ALPN="alpn"
DNS_ALIAS_PREFIX="="
MODE_STATELESS="stateless"
@ -1046,7 +1047,7 @@ _idn() {
fi
}
#_createcsr cn san_list keyfile csrfile conf
#_createcsr cn san_list keyfile csrfile conf acmeValidationv1
_createcsr() {
_debug _createcsr
domain="$1"
@ -1054,6 +1055,7 @@ _createcsr() {
csrkey="$3"
csr="$4"
csrconf="$5"
acmeValidationv1="$6"
_debug2 domain "$domain"
_debug2 domainlist "$domainlist"
_debug2 csrkey "$csrkey"
@ -1062,7 +1064,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"
if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
if [ "$acmeValidationv1" ]; then
printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf"
elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
#single domain
_info "Single domain" "$domain"
printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
@ -1084,6 +1088,10 @@ _createcsr() {
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
fi
if [ "$acmeValidationv1" ]; then
printf "\n1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}"
fi
_csr_cn="$(_idn "$domain")"
_debug2 _csr_cn "$_csr_cn"
if _contains "$(uname -a)" "MINGW"; then
@ -1134,12 +1142,17 @@ _readSubjectAltNamesFromCSR() {
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
_debug "AltNames contains subject"
_dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")"
_excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')"
_debug _excapedAlgnames "$_excapedAlgnames"
_escapedSubject="$(echo "$_csrsubj" | tr '*' '#')"
_debug _escapedSubject "$_escapedSubject"
_dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")"
_debug _dnsAltnames "$_dnsAltnames"
else
_debug "AltNames doesn't contain subject"
fi
printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
echo "$_dnsAltnames" | sed "s/DNS://g"
}
#_csrfile
@ -1516,7 +1529,8 @@ _calcjwk() {
JWK_HEADERPLACE_PART1='{"nonce": "'
JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
else
_err "Only RSA or EC key is supported."
_err "Only RSA or EC key is supported. keyfile=$keyfile"
_debug2 "$(cat "$keyfile")"
return 1
fi
@ -1860,11 +1874,7 @@ _send_signed_request() {
sig="$(printf "%s" "$_sig_t" | _url_replace)"
_debug3 sig "$sig"
if [ "$ACME_VERSION" = "2" ]; then
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
else
body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
fi
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
_debug3 body "$body"
response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
@ -2101,7 +2111,7 @@ _sleep() {
fi
}
# _starttlsserver san_a san_b port content _ncaddr
# _starttlsserver san_a san_b port content _ncaddr acmeValidationv1
_starttlsserver() {
_info "Starting tls server."
san_a="$1"
@ -2109,10 +2119,12 @@ _starttlsserver() {
port="$3"
content="$4"
opaddr="$5"
acmeValidationv1="$6"
_debug san_a "$san_a"
_debug san_b "$san_b"
_debug port "$port"
_debug acmeValidationv1 "$acmeValidationv1"
#create key TLS_KEY
if ! _createkey "2048" "$TLS_KEY"; then
@ -2125,7 +2137,7 @@ _starttlsserver() {
if [ "$san_b" ]; then
alt="$alt,$san_b"
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."
return 1
fi
@ -2151,6 +2163,10 @@ _starttlsserver() {
__S_OPENSSL="$__S_OPENSSL -6"
fi
if [ "$acmeValidationv1" ]; then
__S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1"
fi
_debug "$__S_OPENSSL"
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
$__S_OPENSSL -tlsextdebug &
@ -2905,7 +2921,10 @@ _clearup() {
_clearupdns() {
_debug "_clearupdns"
if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then
_debug "dnsadded" "$dnsadded"
_debug "vlist" "$vlist"
#dnsadded is "0" or "1" means dns-01 method was used for at least one domain
if [ -z "$dnsadded" ] || [ -z "$vlist" ]; then
_debug "skip dns."
return
fi
@ -3061,8 +3080,8 @@ _on_before_issue() {
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
fi
_checkport="$Le_HTTPPort"
elif [ "$_currentRoot" = "$W_TLS" ]; then
_info "Standalone tls mode."
elif [ "$_currentRoot" = "$W_TLS" ] || [ "$_currentRoot" = "$W_ALPN" ]; then
_info "Standalone tls/alpn mode."
if [ -z "$Le_TLSPort" ]; then
Le_TLSPort=443
else
@ -3422,15 +3441,17 @@ __get_domain_new_authz() {
#uri keyAuthorization
__trigger_validation() {
_debug2 "tigger domain validation."
_debug2 "Trigger domain validation."
_t_url="$1"
_debug2 _t_url "$_t_url"
_t_key_authz="$2"
_debug2 _t_key_authz "$_t_key_authz"
_t_vtype="$3"
_debug2 _t_vtype "$_t_vtype"
if [ "$ACME_VERSION" = "2" ]; then
_send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}"
else
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}"
fi
}
@ -3633,7 +3654,7 @@ issue() {
_authorizations_map=""
for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do
_debug2 "_authz_url" "$_authz_url"
if ! response="$(_get "$_authz_url")"; then
if ! _send_signed_request "$_authz_url"; then
_err "get to authz error."
_err "_authorizations_seg" "$_authorizations_seg"
_err "_authz_url" "$_authz_url"
@ -3681,11 +3702,11 @@ $_authorizations_map"
fi
if [ "$_currentRoot" = "$W_TLS" ]; then
if [ "$ACME_VERSION" = "2" ]; then
vtype="$VTYPE_TLS2"
else
vtype="$VTYPE_TLS"
fi
vtype="$VTYPE_TLS"
fi
if [ "$_currentRoot" = "$W_ALPN" ]; then
vtype="$VTYPE_ALPN"
fi
if [ "$ACME_VERSION" = "2" ]; then
@ -3836,8 +3857,8 @@ $_authorizations_map"
)
if [ "$?" != "0" ]; then
_clearup
_on_issue_err "$_post_hook" "$vlist"
_clearup
return 1
fi
dnsadded='1'
@ -3848,8 +3869,8 @@ $_authorizations_map"
_savedomainconf "Le_Vlist" "$vlist"
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
_err "Please add the TXT records to the domains, and re-run with --renew."
_clearup
_on_issue_err "$_post_hook"
_clearup
return 1
fi
@ -3883,7 +3904,7 @@ $_authorizations_map"
continue
fi
_info "Verifying:$d"
_info "Verifying: $d"
_debug "d" "$d"
_debug "keyauthorization" "$keyauthorization"
_debug "uri" "$uri"
@ -4001,9 +4022,19 @@ $_authorizations_map"
_on_issue_err "$_post_hook" "$vlist"
return 1
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
if ! __trigger_validation "$uri" "$keyauthorization"; then
if ! __trigger_validation "$uri" "$keyauthorization" "$vtype"; then
_err "$d:Can not get challenge: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
@ -4012,7 +4043,7 @@ $_authorizations_map"
fi
if [ "$code" ] && [ "$code" != '202' ]; then
if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then
if [ "$code" = '200' ]; then
_debug "trigger validation code: $code"
else
_err "$d:Challenge error: $response"
@ -4041,7 +4072,11 @@ $_authorizations_map"
_debug "sleep 2 secs to verify"
sleep 2
_debug "checking"
response="$(_get "$uri")"
if [ "$ACME_VERSION" = "2" ]; then
_send_signed_request "$uri"
else
response="$(_get "$uri")"
fi
if [ "$?" != "0" ]; then
_err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
@ -4117,13 +4152,16 @@ $_authorizations_map"
fi
Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
if ! _get "$Le_LinkCert" >"$CERT_PATH"; then
_tempSignedResponse="$response"
if ! _send_signed_request "$Le_LinkCert" "" "needbase64"; then
_err "Sign failed, can not download cert:$Le_LinkCert."
_err "$response"
_on_issue_err "$_post_hook"
return 1
fi
echo "$response" | _dbase64 "multiline" >"$CERT_PATH"
if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then
_debug "Found cert chain"
cat "$CERT_PATH" >"$CERT_FULLCHAIN_PATH"
@ -4133,6 +4171,7 @@ $_authorizations_map"
_end_n="$(_math $_end_n + 1)"
sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" >"$CA_CERT_PATH"
fi
response="$_tempSignedResponse"
else
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
_err "Sign failed. $response"
@ -4203,7 +4242,8 @@ $_authorizations_map"
while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do
_debug _link_issuer_retry "$_link_issuer_retry"
if [ "$ACME_VERSION" = "2" ]; then
if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then
if _send_signed_request "$Le_LinkIssuer"; then
echo "$response" >"$CA_CERT_PATH"
break
fi
else
@ -4239,8 +4279,8 @@ $_authorizations_map"
Le_CertCreateTimeStr=$(date -u)
_savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then
Le_RenewalDays="$MAX_RENEW"
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then
Le_RenewalDays="$DEFAULT_RENEW"
else
_savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
fi
@ -4929,7 +4969,7 @@ _deactivate() {
authzUri="$_authorizations_seg"
_debug2 "authzUri" "$authzUri"
if ! response="$(_get "$authzUri")"; then
if ! _send_signed_request "$authzUri"; then
_err "get to authz error."
_err "_authorizations_seg" "$_authorizations_seg"
_err "authzUri" "$authzUri"
@ -5463,6 +5503,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.
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode.
--alpn Use standalone alpn mode.
--stateless Use stateless mode, see: $_STATELESS_WIKI
--apache Use apache mode.
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
@ -5491,8 +5532,9 @@ Parameters:
--useragent Specifies the user agent string. it will be saved for future use too.
--accountemail Specifies the account email, only valid for the '--install' and '--update-account' 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 default value is $DEFAULT_RENEW days.
--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.
--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.
@ -5817,6 +5859,14 @@ _process() {
_webroot="$_webroot,$wvalue"
fi
;;
--alpn)
wvalue="$W_ALPN"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--stateless)
wvalue="$MODE_STATELESS"
if [ -z "$_webroot" ]; then
@ -5941,6 +5991,11 @@ _process() {
Le_HTTPPort="$_httpport"
shift
;;
--tlsport)
_tlsport="$2"
Le_TLSPort="$_tlsport"
shift
;;
--listraw)
_listraw="raw"
;;

View File

@ -146,13 +146,17 @@ Finally, make the DNS server and update Key available to `acme.sh`
export NSUPDATE_SERVER="dns.example.com"
export NSUPDATE_KEY="/path/to/your/nsupdate.key"
```
and optionally (depending on DNS server)
```
export NSUPDATE_ZONE="example.com"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com
```
The `NSUPDATE_SERVER` and `NSUPDATE_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
The `NSUPDATE_SERVER`, `NSUPDATE_KEY`, and `NSUPDATE_ZONE` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 8. Use LuaDNS domain API
@ -263,25 +267,26 @@ when needed.
## 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.
* [Classic Manager](https://manager.linode.com/profile/api)
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.
Then add an API key with label *ACME* and copy the new key into the following
command.
```sh
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:
@ -289,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
```
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
@ -1077,7 +1110,37 @@ 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.
## 57. Use Nexcess API
## 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_exoscale -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.
## 58. Using PointHQ API to issue certs
Log into [PointHQ account management](https://app.pointhq.com/profile) and copy the API key from the page there.
```export PointHQ_Key="apikeystringgoeshere"
exportPointHQ_Email="accountemail@yourdomain.com"
```
You can then issue certs by using:
```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com
```
## 59. Use Nexcess API
First, you'll need to login to the [Nexcess.net Client Portal](https://portal.nexcess.net) and [generate a new API token](https://portal.nexcess.net/api-token).
@ -1095,7 +1158,7 @@ acme.sh --issue --dns dns_nexcess -d example.com --dnssleep 900
The `NEXCESS_API_TOKEN will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 58. Use Thermo.io API
## 60. Use Thermo.io API
First, you'll need to login to the [Thermo.io Client Portal](https://core.thermo.io) and [generate a new API token](https://core.thermo.io/api-token).
@ -1113,7 +1176,7 @@ acme.sh --issue --dns dns_thermo -d example.com --dnssleep 900
The `THERMO_API_TOKEN will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 59. Use Futurehosting API
## 61. Use Futurehosting API
First, you'll need to login to the [Futurehosting Client Portal](https://my.futurehosting.com) and [generate a new API token](https://my.futurehosting.com/api-token).

View File

@ -19,8 +19,8 @@ dns_cf_add() {
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key=""
CF_Email=""
_err "You didn't specify a cloudflare api key and email yet."
_err "Please create the key and try again."
_err "You didn't specify a Cloudflare api key and email yet."
_err "You can get yours from here https://dash.cloudflare.com/profile."
return 1
fi
@ -34,9 +34,6 @@ dns_cf_add() {
_saveaccountconf_mutable CF_Key "$CF_Key"
_saveaccountconf_mutable CF_Email "$CF_Email"
_DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')"
_cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
@ -100,21 +97,16 @@ dns_cf_rm() {
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key=""
CF_Email=""
_err "You didn't specify a cloudflare api key and email yet."
_err "Please create the key and try again."
_err "You didn't specify a Cloudflare api key and email yet."
_err "You can get yours from here https://dash.cloudflare.com/profile."
return 1
fi
_DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_"
_err "invalid domain"
return 1
fi
_cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_"
_debug _domain_id "$_domain_id"
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
@ -154,21 +146,6 @@ dns_cf_rm() {
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
_cf_zones="$(_readdomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_")"
_debug2 "_cf_zones" "$_cf_zones"
if [ -z "$_cf_zones" ]; then
_debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ is none, so get it."
if ! _cf_rest GET "zones"; then
return 1
fi
_cf_zones="$response"
_savedomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" "$(echo "$_cf_zones" | _base64)"
else
_debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ found"
_cf_zones="$(echo "$_cf_zones" | _dbase64)"
fi
domain=$1
i=2
p=1
@ -180,8 +157,12 @@ _get_root() {
return 1
fi
if _contains "$_cf_zones" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(echo "$_cf_zones" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "^\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
if ! _cf_rest GET "zones?name=$h"; then
return 1
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _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

View File

@ -104,48 +104,60 @@ dns_dgon_rm() {
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
GURL="https://api.digitalocean.com/v2/domains/$_domain/records"
## while we dont have a record ID we keep going
while [ -z "$record" ]; do
## Get all the matching records
while true; do
## 1) get the URL
## the create request - get
## args: URL, [onlyheader, timeout]
domain_list="$(_get "$GURL")"
## 2) find record
## check for what we are looing for: "type":"A","name":"$_sub_domain"
record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
## 3) check record and get next page
if [ -z "$record" ]; then
## find the next page if we dont have a match
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
if [ -z "$nextpage" ]; then
_err "no record and no nextpage in digital ocean DNS removal"
return 1
fi
_debug2 nextpage "$nextpage"
GURL="$nextpage"
## check response
if [ "$?" != "0" ]; then
_err "error in domain_list response: $domain_list"
return 1
fi
## we break out of the loop when we have a record
_debug2 domain_list "$domain_list"
## 2) find records
## check for what we are looking for: "type":"A","name":"$_sub_domain"
record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
if [ ! -z "$record" ]; then
## we found records
rec_ids="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
_debug rec_ids "$rec_ids"
if [ ! -z "$rec_ids" ]; then
echo "$rec_ids" | while IFS= read -r rec_id; do
## delete the record
## delete URL for removing the one we dont want
DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
## the create request - delete
## args: BODY, URL, [need64, httpmethod]
response="$(_post "" "$DURL" "" "DELETE")"
## check response (sort of)
if [ "$?" != "0" ]; then
_err "error in remove response: $response"
return 1
fi
_debug2 response "$response"
done
fi
fi
## 3) find the next page
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
if [ -z "$nextpage" ]; then
break
fi
_debug2 nextpage "$nextpage"
GURL="$nextpage"
done
## we found the record
rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
_debug rec_id "$rec_id"
## delete the record
## delete URL for removing the one we dont want
DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id"
## the create request - delete
## args: BODY, URL, [need64, httpmethod]
response="$(_post "" "$DURL" "" "DELETE")"
## check response (sort of)
if [ "$?" != "0" ]; then
_err "error in remove response: $response"
return 1
fi
_debug2 response "$response"
## finished correctly
return 0
}
@ -178,44 +190,57 @@ _get_base_domain() {
export _H2="Authorization: Bearer $DO_API_KEY"
_debug DO_API_KEY "$DO_API_KEY"
## get URL for the list of domains
## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO)
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
DOMURL="https://api.digitalocean.com/v2/domains"
## get the domain list (DO gives basically a full XFER!)
domain_list="$(_get "$DOMURL")"
## while we dont have a matching domain we keep going
while [ -z "$found" ]; do
## get the domain list (current page)
domain_list="$(_get "$DOMURL")"
## check response
if [ "$?" != "0" ]; then
_err "error in domain_list response: $domain_list"
return 1
fi
_debug2 domain_list "$domain_list"
## for each shortening of our $fulldomain, check if it exists in the $domain_list
## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
i=2
while [ $i -gt 0 ]; do
## get next longest domain
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
## check we got something back from our cut (or are we at the end)
if [ -z "$_domain" ]; then
## we got to the end of the domain - invalid domain
_err "domain not found in DigitalOcean account"
## check response
if [ "$?" != "0" ]; then
_err "error in domain_list response: $domain_list"
return 1
fi
## we got part of a domain back - grep it out
found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")"
## check if it exists
if [ ! -z "$found" ]; then
## exists - exit loop returning the parts
sub_point=$(_math $i - 1)
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
_debug _domain "$_domain"
_debug _sub_domain "$_sub_domain"
return 0
_debug2 domain_list "$domain_list"
## for each shortening of our $fulldomain, check if it exists in the $domain_list
## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
i=2
while [ $i -gt 0 ]; do
## get next longest domain
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
## check we got something back from our cut (or are we at the end)
if [ -z "$_domain" ]; then
break
fi
## we got part of a domain back - grep it out
found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")"
## check if it exists
if [ ! -z "$found" ]; then
## exists - exit loop returning the parts
sub_point=$(_math $i - 1)
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
_debug _domain "$_domain"
_debug _sub_domain "$_sub_domain"
return 0
fi
## increment cut point $i
i=$(_math $i + 1)
done
if [ -z "$found" ]; then
## find the next page if we dont have a match
nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
if [ -z "$nextpage" ]; then
_err "no record and no nextpage in digital ocean DNS removal"
return 1
fi
_debug2 nextpage "$nextpage"
DOMURL="$nextpage"
fi
## increment cut point $i
i=$(_math $i + 1)
done
## we went through the entire domain zone list and dint find one that matched

View File

@ -10,7 +10,7 @@
Dynu_Token=""
#
#Endpoint
Dynu_EndPoint="https://api.dynu.com/v1"
Dynu_EndPoint="https://api.dynu.com/v2"
#
#Author: Dynu Systems, Inc.
#Report Bugs here: https://github.com/shar0119/acme.sh
@ -51,11 +51,11 @@ dns_dynu_add() {
_debug _domain_name "$_domain_name"
_info "Creating TXT record."
if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then
if ! _dynu_rest POST "dns/$dnsId/record" "{\"domainId\":\"$dnsId\",\"nodeName\":\"$_node\",\"recordType\":\"TXT\",\"textData\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then
return 1
fi
if ! _contains "$response" "text_data"; then
if ! _contains "$response" "200"; then
_err "Could not add TXT record."
return 1
fi
@ -132,11 +132,12 @@ _get_root() {
return 1
fi
if ! _dynu_rest GET "dns/get/$h"; then
if ! _dynu_rest GET "dns/getroot/$h"; then
return 1
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
if _contains "$response" "\"domainName\":\"$h\"" >/dev/null; then
dnsId=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 2 | cut -d : -f 2)
_domain_name=$h
_node=$(printf "%s" "$domain" | cut -d . -f 1-$p)
return 0
@ -152,7 +153,7 @@ _get_recordid() {
fulldomain=$1
txtvalue=$2
if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then
if ! _dynu_rest GET "dns/$dnsId/record"; then
return 1
fi
@ -161,19 +162,18 @@ _get_recordid() {
return 0
fi
_dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2)
_dns_record_id=$(printf "%s" "$response" | sed -e 's/[^{]*\({[^}]*}\)[^{]*/\1\n/g' | grep "\"textData\":\"$txtvalue\"" | sed -e 's/.*"id":\([^,]*\).*/\1/')
return 0
}
_delete_txt_record() {
_dns_record_id=$1
if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then
if ! _dynu_rest DELETE "dns/$dnsId/record/$_dns_record_id"; then
return 1
fi
if ! _contains "$response" "true"; then
if ! _contains "$response" "200"; then
return 1
fi
@ -189,7 +189,7 @@ _dynu_rest() {
export _H1="Authorization: Bearer $Dynu_Token"
export _H2="Content-Type: application/json"
if [ "$data" ]; then
if [ "$data" ] || [ "$m" = "DELETE" ]; then
_debug data "$data"
response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")"
else
@ -216,8 +216,8 @@ _dynu_authentication() {
_err "Authentication failed."
return 1
fi
if _contains "$response" "accessToken"; then
Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2)
if _contains "$response" "access_token"; then
Dynu_Token=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2)
fi
if _contains "$Dynu_Token" "null"; then
Dynu_Token=""

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
}

60
dnsapi/dns_gandi_livedns.sh Executable file → Normal file
View File

@ -7,6 +7,7 @@
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
#
#Author: Frédéric Crozat <fcrozat@suse.com>
# Dominik Röttsches <drott@google.com>
#Report Bugs here: https://github.com/fcrozat/acme.sh
#
######## Public functions #####################
@ -36,9 +37,7 @@ dns_gandi_livedns_add() {
_debug domain "$_domain"
_debug sub_domain "$_sub_domain"
_gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \
&& _contains "$response" '{"message": "DNS Record Created"}' \
&& _info "Add $(__green "success")"
_dns_gandi_append_record "$_domain" "$_sub_domain" "$txtvalue"
}
#Usage: fulldomain txtvalue
@ -56,9 +55,23 @@ dns_gandi_livedns_rm() {
_debug fulldomain "$fulldomain"
_debug domain "$_domain"
_debug sub_domain "$_sub_domain"
_debug txtvalue "$txtvalue"
_gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" ""
if ! _dns_gandi_existing_rrset_values "$_domain" "$_sub_domain"; then
return 1
fi
_new_rrset_values=$(echo "$_rrset_values" | sed "s/...$txtvalue...//g")
# Cleanup dangling commata.
_new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, ,/ ,/g")
_new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, *\]/\]/g")
_new_rrset_values=$(echo "$_new_rrset_values" | sed "s/\[ *,/\[/g")
_debug "New rrset_values" "$_new_rrset_values"
_gandi_livedns_rest PUT \
"domains/$_domain/records/$_sub_domain/TXT" \
"{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" \
&& _contains "$response" '{"message": "DNS Record Created"}' \
&& _info "Removing record $(__green "success")"
}
#################### Private functions below ##################################
@ -98,6 +111,45 @@ _get_root() {
return 1
}
_dns_gandi_append_record() {
domain=$1
sub_domain=$2
txtvalue=$3
if _dns_gandi_existing_rrset_values "$domain" "$sub_domain"; then
_debug "Appending new value"
_rrset_values=$(echo "$_rrset_values" | sed "s/\"]/\",\"$txtvalue\"]/")
else
_debug "Creating new record" "$_rrset_values"
_rrset_values="[\"$txtvalue\"]"
fi
_debug new_rrset_values "$_rrset_values"
_gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \
"{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" \
&& _contains "$response" '{"message": "DNS Record Created"}' \
&& _info "Adding record $(__green "success")"
}
_dns_gandi_existing_rrset_values() {
domain=$1
sub_domain=$2
if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then
return 1
fi
if ! _contains "$response" '"rrset_type": "TXT"'; then
_debug "Does not have a _acme-challenge TXT record yet."
return 1
fi
if _contains "$response" '"rrset_values": \[\]'; then
_debug "Empty rrset_values for TXT record, no previous TXT record."
return 1
fi
_debug "Already has TXT record."
_rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' \
| _egrep_o '\[".*\"]')
return 0
}
_gandi_livedns_rest() {
m=$1
ep="$2"

View File

@ -74,8 +74,26 @@ _hostingde_getZoneConfig() {
return $returnCode
}
_hostingde_getZoneStatus() {
_debug "Checking Zone status"
curData="{\"filter\":{\"field\":\"zoneConfigId\",\"value\":\"${zoneConfigId}\"},\"limit\":1,\"authToken\":\"${HOSTINGDE_APIKEY}\"}"
curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zonesFind")"
_debug "Calling zonesFind '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zonesFind'"
_debug "Result of zonesFind '$curResult'"
zoneStatus=$(echo "${curResult}" | grep -v success | _egrep_o '"status":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
_debug "zoneStatus '${zoneStatus}'"
return 0
}
_hostingde_addRecord() {
_info "Adding record to zone"
_hostingde_getZoneStatus
_debug "Result of zoneStatus: '${zoneStatus}'"
while [ "${zoneStatus}" != "active" ]; do
_sleep 5
_hostingde_getZoneStatus
_debug "Result of zoneStatus: '${zoneStatus}'"
done
curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}"
curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")"
_debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'"
@ -93,6 +111,13 @@ _hostingde_addRecord() {
_hostingde_removeRecord() {
_info "Removing record from zone"
_hostingde_getZoneStatus
_debug "Result of zoneStatus: '$zoneStatus'"
while [ "$zoneStatus" != "active" ]; do
_sleep 5
_hostingde_getZoneStatus
_debug "Result of zoneStatus: '$zoneStatus'"
done
curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}"
curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")"
_debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'"

View File

@ -158,7 +158,8 @@ _inwx_login() {
export _H1
#https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71
if _contains "$response" "tfa"; then
if _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>" \
&& _contains "$response" "<member><name>tfa</name><value><string>GOOGLE-AUTH</string></value></member>"; then
if [ -z "$INWX_Shared_Secret" ]; then
_err "Mobile TAN detected."
_err "Please define a shared secret."

View File

@ -2,7 +2,7 @@
#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 #####################
@ -27,14 +27,10 @@ dns_linode_add() {
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_payload="{
\"type\": \"TXT\",
\"name\": \"$_sub_domain\",
\"target\": \"$txtvalue\"
}"
_parameters="&DomainID=$_domain_id&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)
if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then
_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
@ -69,21 +65,25 @@ dns_linode_rm() {
_debug _sub_domain "$_sub_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")"
resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")"
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 \ )
_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
_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)
_parameters="&DomainID=$_domain_id&ResourceID=$_resource_id"
if [ -n "$_error_response" ]; then
_err "Error deleting the domain resource: $_error_response"
if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then
_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
fi
@ -127,7 +127,7 @@ _get_root() {
i=2
p=1
if _rest GET; then
if _rest GET "domain.list"; 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)
@ -137,9 +137,9 @@ _get_root() {
return 1
fi
hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")"
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 \ )
_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
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
@ -165,7 +165,6 @@ _rest() {
export _H1="Accept: application/json"
export _H2="Content-Type: application/json"
export _H3="Authorization: Bearer $LINODE_API_KEY"
if [ "$mtd" != "GET" ]; then
# 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
}

View File

@ -38,8 +38,8 @@ dns_loopia_add() {
_info "Adding record"
_loopia_add_record "$_domain" "$_sub_domain"
_loopia_update_record "$_domain" "$_sub_domain" "$txtvalue"
_loopia_add_sub_domain "$_domain" "$_sub_domain"
_loopia_add_record "$_domain" "$_sub_domain" "$txtvalue"
}
@ -96,6 +96,37 @@ dns_loopia_rm() {
#################### Private functions below ##################################
_loopia_get_records() {
domain=$1
sub_domain=$2
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>getZoneRecords</methodName>
<params>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if ! _contains "$response" "<array>"; then
_err "Error"
return 1
fi
return 0
}
_get_root() {
domain=$1
_debug "get root"
@ -137,14 +168,14 @@ _get_root() {
}
_loopia_update_record() {
_loopia_add_record() {
domain=$1
sub_domain=$2
txtval=$3
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>updateZoneRecord</methodName>
<methodName>addZoneRecord</methodName>
<params>
<param>
<value><string>%s</string></value>
@ -176,10 +207,6 @@ _loopia_update_record() {
<name>rdata</name>
<value><string>%s</string></value>
</member>
<member>
<name>record_id</name>
<value><int>0</int></value>
</member>
</struct>
</param>
</params>
@ -194,10 +221,42 @@ _loopia_update_record() {
return 0
}
_loopia_add_record() {
_sub_domain_exists() {
domain=$1
sub_domain=$2
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>getSubdomains</methodName>
<params>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
<param>
<value><string>%s</string></value>
</param>
</params>
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain")
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
if _contains "$response" "$sub_domain"; then
return 0
fi
return 1
}
_loopia_add_sub_domain() {
domain=$1
sub_domain=$2
if _sub_domain_exists "$domain" "$sub_domain"; then
return 0
fi
xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>addSubdomain</methodName>

View File

@ -161,12 +161,12 @@ _namecheap_parse_host() {
_host=$1
_debug _host "$_host"
_hostid=$(echo "$_host" | _egrep_o '\sHostId="[^"]*' | cut -d '"' -f 2)
_hostname=$(echo "$_host" | _egrep_o '\sName="[^"]*' | cut -d '"' -f 2)
_hosttype=$(echo "$_host" | _egrep_o '\sType="[^"]*' | cut -d '"' -f 2)
_hostaddress=$(echo "$_host" | _egrep_o '\sAddress="[^"]*' | cut -d '"' -f 2)
_hostmxpref=$(echo "$_host" | _egrep_o '\sMXPref="[^"]*' | cut -d '"' -f 2)
_hostttl=$(echo "$_host" | _egrep_o '\sTTL="[^"]*' | cut -d '"' -f 2)
_hostid=$(echo "$_host" | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2)
_hostname=$(echo "$_host" | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2)
_hosttype=$(echo "$_host" | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2)
_hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2)
_hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2)
_hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2)
_debug hostid "$_hostid"
_debug hostname "$_hostname"
@ -199,9 +199,12 @@ _namecheap_check_config() {
_set_namecheap_TXT() {
subdomain=$2
txt=$3
tld=$(echo "$1" | cut -d '.' -f 2)
sld=$(echo "$1" | cut -d '.' -f 1)
request="namecheap.domains.dns.getHosts&SLD=$sld&TLD=$tld"
if ! _namecheap_set_tld_sld "$1"; then
return 1
fi
request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
if ! _namecheap_post "$request"; then
_err "$error"
@ -231,7 +234,7 @@ EOT
_debug hostrequestfinal "$_hostrequest"
request="namecheap.domains.dns.setHosts&SLD=${sld}&TLD=${tld}${_hostrequest}"
request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
if ! _namecheap_post "$request"; then
_err "$error"
@ -244,9 +247,12 @@ EOT
_del_namecheap_TXT() {
subdomain=$2
txt=$3
tld=$(echo "$1" | cut -d '.' -f 2)
sld=$(echo "$1" | cut -d '.' -f 1)
request="namecheap.domains.dns.getHosts&SLD=$sld&TLD=$tld"
if ! _namecheap_set_tld_sld "$1"; then
return 1
fi
request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
if ! _namecheap_post "$request"; then
_err "$error"
@ -286,7 +292,7 @@ EOT
_debug hostrequestfinal "$_hostrequest"
request="namecheap.domains.dns.setHosts&SLD=${sld}&TLD=${tld}${_hostrequest}"
request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
if ! _namecheap_post "$request"; then
_err "$error"
@ -306,3 +312,45 @@ _namecheap_add_host() {
_hostindex=$(_math "$_hostindex" + 1)
_hostrequest=$(printf '%s&HostName%d=%s&RecordType%d=%s&Address%d=%s&MXPref%d=%d&TTL%d=%d' "$_hostrequest" "$_hostindex" "$1" "$_hostindex" "$2" "$_hostindex" "$3" "$_hostindex" "$4" "$_hostindex" "$5")
}
_namecheap_set_tld_sld() {
domain=$1
_tld=""
_sld=""
i=2
while true; do
_tld=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug tld "$_tld"
if [ -z "$_tld" ]; then
_debug "invalid tld"
return 1
fi
j=$(_math "$i" - 1)
_sld=$(printf "%s" "$domain" | cut -d . -f 1-"$j")
_debug sld "$_sld"
if [ -z "$_sld" ]; then
_debug "invalid sld"
return 1
fi
request="namecheap.domains.dns.getHosts&SLD=$_sld&TLD=$_tld"
if ! _namecheap_post "$request"; then
_debug "sld($_sld)/tld($_tld) not found"
else
_debug "sld($_sld)/tld($_tld) found"
return 0
fi
i=$(_math "$i" + 1)
done
}

View File

@ -13,12 +13,24 @@ dns_nsupdate_add() {
_saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}"
_saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}"
_saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}"
_saveaccountconf NSUPDATE_ZONE "${NSUPDATE_ZONE}"
_info "adding ${fulldomain}. 60 in txt \"${txtvalue}\""
nsupdate -k "${NSUPDATE_KEY}" <<EOF
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d"
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D"
if [ -z "${NSUPDATE_ZONE}" ]; then
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
update add ${fulldomain}. 60 in txt "${txtvalue}"
send
EOF
else
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
zone ${NSUPDATE_ZONE}.
update add ${fulldomain}. 60 in txt "${txtvalue}"
send
EOF
fi
if [ $? -ne 0 ]; then
_err "error updating domain"
return 1
@ -34,11 +46,22 @@ dns_nsupdate_rm() {
[ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost"
[ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53
_info "removing ${fulldomain}. txt"
nsupdate -k "${NSUPDATE_KEY}" <<EOF
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d"
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D"
if [ -z "${NSUPDATE_ZONE}" ]; then
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
update delete ${fulldomain}. txt
send
EOF
else
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
zone ${NSUPDATE_ZONE}.
update delete ${fulldomain}. txt
send
EOF
fi
if [ $? -ne 0 ]; then
_err "error updating domain"
return 1

164
dnsapi/dns_pointhq.sh Normal file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env sh
#
#PointHQ_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
#
#PointHQ_Email="xxxx@sss.com"
PointHQ_Api="https://api.pointhq.com"
######## Public functions #####################
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_pointhq_add() {
fulldomain=$1
txtvalue=$2
PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}"
PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}"
if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then
PointHQ_Key=""
PointHQ_Email=""
_err "You didn't specify a PointHQ API key and email yet."
_err "Please create the key and try again."
return 1
fi
if ! _contains "$PointHQ_Email" "@"; then
_err "It seems that the PointHQ_Email=$PointHQ_Email is not a valid email address."
_err "Please check and retry."
return 1
fi
#save the api key and email to the account conf file.
_saveaccountconf_mutable PointHQ_Key "$PointHQ_Key"
_saveaccountconf_mutable PointHQ_Email "$PointHQ_Email"
_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 _pointhq_rest POST "zones/$_domain/records" "{\"zone_record\": {\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":3600}}"; then
if printf -- "%s" "$response" | grep "$fulldomain" >/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
}
#fulldomain txtvalue
dns_pointhq_rm() {
fulldomain=$1
txtvalue=$2
PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}"
PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}"
if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then
PointHQ_Key=""
PointHQ_Email=""
_err "You didn't specify a PointHQ API key and email yet."
_err "Please create the key 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"
_debug "Getting txt records"
_pointhq_rest GET "zones/${_domain}/records?record_type=TXT&name=$_sub_domain"
if ! printf "%s" "$response" | grep "^\[" >/dev/null; then
_err "Error"
return 1
fi
if [ "$response" = "[]" ]; then
_info "No records to remove."
else
record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | tr -d \" | head -n 1)
_debug "record_id" "$record_id"
if [ -z "$record_id" ]; then
_err "Can not get record id to remove."
return 1
fi
if ! _pointhq_rest DELETE "zones/$_domain/records/$record_id"; then
_err "Delete record error."
return 1
fi
_contains "$response" '"status":"OK"'
fi
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
_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 ! _pointhq_rest GET "zones"; then
return 1
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; 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
}
_pointhq_rest() {
m=$1
ep="$2"
data="$3"
_debug "$ep"
_pointhq_auth=$(printf "%s:%s" "$PointHQ_Email" "$PointHQ_Key" | _base64)
export _H1="Authorization: Basic $_pointhq_auth"
export _H2="Content-Type: application/json"
export _H3="Accept: application/json"
if [ "$m" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "$PointHQ_Api/$ep" "" "$m")"
else
response="$(_get "$PointHQ_Api/$ep")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}