| @ -0,0 +1,28 @@ | |||
| --- | |||
| name: Bug report | |||
| about: Create a report to help us improve | |||
| title: '' | |||
| labels: '' | |||
| assignees: '' | |||
| --- | |||
| **Describe the bug** | |||
| A clear and concise description of what the bug is. | |||
| **To Reproduce** | |||
| Steps to reproduce the behavior: | |||
| 1. Go to '...' | |||
| 2. Click on '....' | |||
| 3. Scroll down to '....' | |||
| 4. See error | |||
| **Expected behavior** | |||
| A clear and concise description of what you expected to happen. | |||
| **Operating system (please complete the following information):** | |||
| - OS: [e.g. Debian 9, Ubuntu 18.04, freeBSD ] | |||
| - Bash Version [e.g. GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)] | |||
| **Additional context** | |||
| Add any other context about the problem here. | |||
| @ -0,0 +1,20 @@ | |||
| --- | |||
| name: Feature request | |||
| about: Suggest an idea for this project | |||
| title: '' | |||
| labels: '' | |||
| assignees: '' | |||
| --- | |||
| **Is your feature request related to a problem? Please describe.** | |||
| A clear and concise description of what the problem is. [...] | |||
| **Describe the solution you'd like** | |||
| A clear and concise description of what you want to happen. | |||
| **Describe alternatives you've considered** | |||
| A clear and concise description of any alternative solutions or features you've considered. | |||
| **Additional context** | |||
| Add any other context or screenshots about the feature request here. | |||
| @ -0,0 +1,60 @@ | |||
| Using GoDaddy DNS for LetsEncrypt domain validation. | |||
| Quick guide to setting up getssl for domain validation of | |||
| GoDaddy DNS domains. | |||
| There are two prerequisites to using getssl with GoDaddy DNS: | |||
| 1) Obtain an API access key from developer.godaddy.com | |||
| At first sign-up, you will be required to take a "test" key. | |||
| This is NOT what you need. Accept it, then get a "Production" | |||
| key. At this writing, there is no charge - but you must have | |||
| a GoDaddy customer account. | |||
| You must get the API key for the account which owns the domain | |||
| that you want to get certificates for. If the domains that you | |||
| manage are owned by more than one account, get a key for each. | |||
| The access key consists of a "Key" and a "Secret". You need | |||
| both. | |||
| 2) Obtain JSON.sh - https://github.com/dominictarr/JSON.sh | |||
| With those in hand, the installation procedure is: | |||
| 1) Put JSON.sh in the getssl DNS scripts directory | |||
| Default: /usr/share/getssl/dns_scripts | |||
| 2) Open your config file (the global file in ~/.getssl/getssl.cfg | |||
| or the per-account file in ~/.getssl/example.net/getssl.cfg | |||
| 3) Set the following options: | |||
| VALIDATE_VIA_DNS="true" | |||
| DNS_ADD_COMMAND="/usr/share/getssl/dns_scripts/dns_add_godaddy" | |||
| DNS_DEL_COMMAND="/usr/share/getssl/dns_scripts/dns_del_godaddy" | |||
| # The API key for your account/this domain | |||
| export GODADDY_KEY="..." GODADDY_SECRET="..." | |||
| 4) Set any other options that you wish (per the standard | |||
| directions.) Use the test CA to make sure that | |||
| everything is setup correctly. | |||
| That's it. getssl example.net will now validate with DNS. | |||
| To trace record additions and removals, run getssl as | |||
| GODADDY_TRACE=Y getssl example.net | |||
| There are additional options, which are documented in the | |||
| *godaddy" files and dns_godaddy -h. | |||
| Copyright (2017) Timothe Litt litt at acm _dot org | |||
| This sofware may be freely used providing this notice is included with | |||
| all copies. The name of the author may not be used to endorse | |||
| any other product or derivative work. No warranty is provided | |||
| and the user assumes all responsibility for use of this software. | |||
| Report any issues to https://github.com/tlhackque/getssl/issues. | |||
| Enjoy. | |||
| @ -0,0 +1,40 @@ | |||
| #!/bin/bash | |||
| # Copyright (2017) Timothe Litt litt at acm _dot org | |||
| # Add token to GoDaddy dns using dns_godaddy | |||
| # You do not have to customize this script. | |||
| # | |||
| # Obtain the Key and Secret from https://developer.godaddy.com/getstarted | |||
| # You must obtain a "Production" key - NOT the "Test" key you're required | |||
| # to get first. | |||
| # | |||
| # Obtain JSON.sh from https://github.com/dominictarr/JSON.sh | |||
| # Place it in (or softlink it to) the same directory as $GODADDY_SCRIPT, | |||
| # or specify its location with GODADDY_JSON The default is | |||
| # /usr/share/getssl/dns_scripts/ | |||
| # | |||
| # Define GODADDY_KEY and GO_DADDY_SECRET in your account or domain getssl.cfg | |||
| # | |||
| # See GoDaddy-README.txt for complete instructions. | |||
| fulldomain="$1" | |||
| token="$2" | |||
| [ -z "$GODADDY_SCRIPT" ] && GODADDY_SCRIPT="/usr/share/getssl/dns_scripts/dns_godaddy" | |||
| [[ "$GODADDY_SCRIPT" =~ ^~ ]] && \ | |||
| eval 'GODADDY_SCRIPT=`readlink -nf ' $GODADDY_SCRIPT '`' | |||
| if [ ! -x "$GODADDY_SCRIPT" ]; then | |||
| echo "$GODADDY_SCRIPT: not found. Please install, softlink or set GODADDY_SCRIPT to its full path" | |||
| echo "See GoDaddy-README.txt for complete instructions." | |||
| exit 3 | |||
| fi | |||
| # JSON.sh is not (currently) used by add | |||
| export GODADDY_KEY | |||
| export GODADDY_SECRET | |||
| $GODADDY_SCRIPT -q add "${fulldomain}" "_acme-challenge.${fulldomain}." "${token}" | |||
| @ -0,0 +1,44 @@ | |||
| #!/bin/bash | |||
| FULLDOMAIN=$1 | |||
| TOKEN=$2 | |||
| TMPFILE=$(mktemp /tmp/dns_add_joker.XXXXXXX) | |||
| USERNAME="youruser" | |||
| PASSWORD="yourpassword" | |||
| # Verify that required parameters are set | |||
| if [[ -z "${FULLDOMAIN}" ]]; then | |||
| echo "DNS script requires full domain name as first parameter" | |||
| exit 1 | |||
| fi | |||
| if [[ -z "${TOKEN}" ]]; then | |||
| echo "DNS script requires challenge token as second parameter" | |||
| exit 1 | |||
| fi | |||
| DOMAIN_ROOT=$(echo "${FULLDOMAIN}" | awk -F\. '{print $(NF-1) FS $NF}') | |||
| SID=$(curl --silent -X POST https://dmapi.joker.com/request/login \ | |||
| -H "Accept: application/json" -H "User-Agent: getssl/0.1" \ | |||
| -H "application/x-www-form-urlencoded" -d "username=${USERNAME}&password=${PASSWORD}" \ | |||
| -i -k 2>/dev/null | grep Auth-Sid | awk '{ print $2 }') | |||
| ## put zone data in tempfile | |||
| curl --silent -X POST https://dmapi.joker.com/request/dns-zone-get \ | |||
| -H "Accept: application/json" -H "User-Agent: getssl/0.1" \ | |||
| -H "application/x-www-form-urlencoded" -d "domain=${DOMAIN_ROOT}&auth-sid=${SID}" | \ | |||
| tail -n +7 >"${TMPFILE}" | |||
| ## add txt record | |||
| printf "_acme-challenge.%s. TXT 0 \"%s \" 300\n\n" "${FULLDOMAIN}" "${TOKEN}" >>"${TMPFILE}" | |||
| ## generate encoded url data | |||
| URLDATA=$(cat "${TMPFILE}" | sed 's/ /%20/g' | sed 's/"/%22/g' | sed ':a;N;$!ba;s/\n/%0A/g') | |||
| ## write new zonefile to joker | |||
| curl --silent --output /dev/null "https://dmapi.joker.com/request/dns-zone-put?domain=${DOMAIN_ROOT}&zone=${URLDATA}&auth-sid=${SID}" 2>&1 | |||
| ## remove tempfile | |||
| rm -f "${TMPFILE}" | |||
| @ -1,33 +1,33 @@ | |||
| #!/bin/bash | |||
| domains=($(echo "$1"|sed -e 's/^\(\([a-zA-Z0-9.-]*\?\)\.\)*\([a-zA-Z0-9-]\+\.[a-zA-Z-]\+\)$/"\1" _acme-challenge.\2 \3/g')) | |||
| challenge="$2" | |||
| # Please, do not forget to ask for your credentials at https://eu.api.ovh.com/createToken/ | |||
| # permissions needed are /domain/zone/* in GET,POST,DELETE | |||
| applicationKey="YourAK" | |||
| applicationSecret="YourAS" | |||
| consumerKey="YourCK" | |||
| topDomain=${domains[2]} | |||
| subDomain=${domains[1]%%.} | |||
| function send | |||
| { | |||
| method=$1 | |||
| url=$2 | |||
| body=$3 | |||
| ts=$(date +%s) | |||
| sign=\$1\$$(echo -n "${applicationSecret}+${consumerKey}+${method}+https://eu.api.ovh.com/1.0${url}+${body}+${ts}"|sha1sum|cut -d" " -f1) | |||
| curl -X ${method} -H "Content-Type: application/json" -H "X-Ovh-Application: ${applicationKey}" -H "X-Ovh-Timestamp: ${ts}" -H "X-Ovh-Signature: ${sign}" -H "X-Ovh-Consumer: ${consumerKey}" -d "${body}" https://eu.api.ovh.com/1.0${url} | |||
| } | |||
| # Creation request | |||
| send POST /domain/zone/${topDomain}/record "{\"fieldType\":\"TXT\",\"subDomain\":\"$subDomain\",\"ttl\":60,\"target\":\"$challenge\"}" | |||
| # Refresh request | |||
| send POST /domain/zone/${topDomain}/refresh "" | |||
| # Pause for 10 seconds, for DNS propagation | |||
| sleep 10 | |||
| #!/bin/bash | |||
| domains=($(echo "$1"|sed -e 's/^\(\([a-zA-Z0-9.-]*\?\)\.\)*\([a-zA-Z0-9-]\+\.[a-zA-Z-]\+\)$/"\1" _acme-challenge.\2 \3/g')) | |||
| challenge="$2" | |||
| # Please, do not forget to ask for your credentials at https://eu.api.ovh.com/createToken/ | |||
| # permissions needed are /domain/zone/* in GET,POST,DELETE | |||
| applicationKey="YourAK" | |||
| applicationSecret="YourAS" | |||
| consumerKey="YourCK" | |||
| topDomain=${domains[2]} | |||
| subDomain=${domains[1]%%.} | |||
| function send | |||
| { | |||
| method=$1 | |||
| url=$2 | |||
| body=$3 | |||
| ts=$(date +%s) | |||
| sign=\$1\$$(echo -n "${applicationSecret}+${consumerKey}+${method}+https://eu.api.ovh.com/1.0${url}+${body}+${ts}"|sha1sum|cut -d" " -f1) | |||
| curl -X "${method}" -H "Content-Type: application/json" -H "X-Ovh-Application: ${applicationKey}" -H "X-Ovh-Timestamp: ${ts}" -H "X-Ovh-Signature: ${sign}" -H "X-Ovh-Consumer: ${consumerKey}" -d "${body}" "https://eu.api.ovh.com/1.0${url}" | |||
| } | |||
| # Creation request | |||
| send POST "/domain/zone/${topDomain}/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$subDomain\",\"ttl\":60,\"target\":\"$challenge\"}" | |||
| # Refresh request | |||
| send POST "/domain/zone/${topDomain}/refresh" "" | |||
| # Pause for 10 seconds, for DNS propagation | |||
| sleep 10 | |||
| @ -0,0 +1,38 @@ | |||
| #!/bin/bash | |||
| # Copyright (2017) Timothe Litt litt at acm _dot org | |||
| # Remove token from GoDaddy dns using dns_godaddy | |||
| # You do not have to customize this script. | |||
| # | |||
| # Obtain the Key and Secret from https://developer.godaddy.com/getstarted | |||
| # You must obtain a "Production" key - NOT the "Test" key you're required | |||
| # to get first. | |||
| # | |||
| # Obtain JSON.sh from https://github.com/dominictarr/JSON.sh | |||
| # Place it in (or softlink it to) the same directory as $GODADDY_SCRIPT, | |||
| # or specify its location with GODADDY_JSON The default is | |||
| # /usr/share/getssl/dns_scripts/ | |||
| # | |||
| # Define GODADDY_KEY and GO_DADDY_SECRET in your account or domain getssl.cfg | |||
| # | |||
| # See GoDaddy-README.txt for complete instructions. | |||
| fulldomain="$1" | |||
| token="$2" | |||
| [ -z "$GODADDY_SCRIPT" ] && GODADDY_SCRIPT="/usr/share/getssl/dns_scripts/dns_godaddy" | |||
| [[ "$GODADDY_SCRIPT" =~ ^~ ]] && \ | |||
| eval 'GODADDY_SCRIPT=`readlink -nf ' "$GODADDY_SCRIPT" '`' | |||
| if ! [ -x "$GODADDY_SCRIPT" ]; then | |||
| echo "$GODADDY_SCRIPT: not found. Please install, softlink or set GODADDY_SCRIPT to its full path" | |||
| echo "See GoDaddy-README.txt for complete instructions." | |||
| exit 3 | |||
| fi | |||
| export GODADDY_KEY | |||
| export GODADDY_SECRET | |||
| $GODADDY_SCRIPT -q del "${fulldomain}" "_acme-challenge.${fulldomain}." "${token}" | |||
| @ -0,0 +1,44 @@ | |||
| #!/bin/bash | |||
| FULLDOMAIN=$1 | |||
| TOKEN=$2 | |||
| TMPFILE=$(mktemp /tmp/dns_add_joker.XXXXXXX) | |||
| USERNAME="youruser" | |||
| PASSWORD="yourpassword" | |||
| # Verify that required parameters are set | |||
| if [[ -z "${FULLDOMAIN}" ]]; then | |||
| echo "DNS script requires full domain name as first parameter" | |||
| exit 1 | |||
| fi | |||
| if [[ -z "${TOKEN}" ]]; then | |||
| echo "DNS script requires challenge token as second parameter" | |||
| exit 1 | |||
| fi | |||
| DOMAIN_ROOT=$(echo "${FULLDOMAIN}" | awk -F\. '{print $(NF-1) FS $NF}') | |||
| SID=$(curl --silent -X POST https://dmapi.joker.com/request/login \ | |||
| -H "Accept: application/json" -H "User-Agent: getssl/0.1" \ | |||
| -H "application/x-www-form-urlencoded" -d "username=${USERNAME}&password=${PASSWORD}" \ | |||
| -i -k 2>/dev/null | grep Auth-Sid | awk '{ print $2 }') | |||
| ## put zone data in tempfile | |||
| curl --silent -X POST https://dmapi.joker.com/request/dns-zone-get \ | |||
| -H "Accept: application/json" -H "User-Agent: getssl/0.1" \ | |||
| -H "application/x-www-form-urlencoded" -d "domain=${DOMAIN_ROOT}&auth-sid=${SID}" | \ | |||
| tail -n +7 >"${TMPFILE}" | |||
| ## remove txt record | |||
| sed -i "/_acme-challenge.${FULLDOMAIN}.*${TOKEN}.*/d" "${TMPFILE}" | |||
| ## generate encoded url data | |||
| URLDATA=$(cat "${TMPFILE}" | sed 's/ /%20/g' | sed 's/"/%22/g' | sed ':a;N;$!ba;s/\n/%0A/g') | |||
| ## write new zonefile to joker | |||
| curl --silent --output /dev/null "https://dmapi.joker.com/request/dns-zone-put?domain=${DOMAIN_ROOT}&zone=${URLDATA}&auth-sid=${SID}" 2>&1 | |||
| ## remove tempfile | |||
| rm -f "${TMPFILE}" | |||
| @ -1,15 +1,39 @@ | |||
| #!/bin/bash | |||
| # example of script to add token to local dns using nsupdate | |||
| # example of script to remove token from local dns using nsupdate | |||
| dnskeyfile="path/to/bla.key" | |||
| fulldomain="$1" | |||
| token="$2" | |||
| updatefile=$(mktemp) | |||
| # VARIABLES: | |||
| # | |||
| # DNS_NSUPDATE_KEYFILE - path to a TSIG key file, if required | |||
| # DNS_NSUPDATE_GETKEY - command to execute if access to the key file requires | |||
| # some special action: dismounting a disk, encrypting a | |||
| # file... Called with the operation 'del' and action | |||
| # 'open" / 'close' | |||
| printf "update delete _acme-challenge.%s. 300 in TXT \"%s\"\n\n" "${fulldomain}" "${token}" > "${updatefile}" | |||
| if [ -n "${DNS_NSUPDATE_KEYFILE}" ]; then | |||
| if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! "${DNS_NSUPDATE_KEY_HOOK}" 'del' 'open' "${fulldomain}" ; then | |||
| exit $(( $? + 128 )) | |||
| fi | |||
| nsupdate -k "${dnskeyfile}" -v "${updatefile}" | |||
| options="-k ${DNS_NSUPDATE_KEYFILE}" | |||
| fi | |||
| rm -f "${updatefile}" | |||
| # Note that blank line is a "send" command to nsupdate | |||
| nsupdate "${options}" -v <<EOF | |||
| update delete "_acme-challenge.${fulldomain}." 300 in TXT "${token}" | |||
| EOF | |||
| sts=$? | |||
| if [ -n "${DNS_NSUPDATE_KEYFILE}" ]; then | |||
| if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! "${DNS_NSUPDATE_KEY_HOOK}" 'del' 'close' "${fulldomain}" ; then | |||
| exit $(( sts + ( $? * 10 ) )) | |||
| fi | |||
| fi | |||
| exit ${sts} | |||
| @ -1,35 +1,35 @@ | |||
| #!/bin/bash | |||
| domains=($(echo "$1"|sed -e 's/^\(\([a-zA-Z0-9.-]*\?\)\.\)*\([a-zA-Z0-9-]\+\.[a-zA-Z-]\+\)$/"\1" _acme-challenge.\2 \3/g')) | |||
| challenge="$2" | |||
| # Please, do not forget to ask for your credentials at https://eu.api.ovh.com/createToken/ | |||
| # permissions needed are /domain/zone/* in GET,POST,DELETE | |||
| applicationKey="YourAK" | |||
| applicationSecret="YourAS" | |||
| consumerKey="YourCK" | |||
| topDomain=${domains[2]} | |||
| subDomain=${domains[1]%%.} | |||
| function send | |||
| { | |||
| method=$1 | |||
| url=$2 | |||
| body=$3 | |||
| ts=$(date +%s) | |||
| sign=\$1\$$(echo -n "${applicationSecret}+${consumerKey}+${method}+https://eu.api.ovh.com/1.0${url}+${body}+${ts}"|sha1sum|cut -d" " -f1) | |||
| curl -X ${method} -H "Content-Type: application/json" -H "X-Ovh-Application: ${applicationKey}" -H "X-Ovh-Timestamp: ${ts}" -H "X-Ovh-Signature: ${sign}" -H "X-Ovh-Consumer: ${consumerKey}" -d "${body}" https://eu.api.ovh.com/1.0${url} | |||
| } | |||
| # Creation request | |||
| oldResult=$(send GET "/domain/zone/${topDomain}/record?fieldType=TXT&subDomain=${subDomain}" ""|sed -e 's/\[//' -e 's/\]//') | |||
| for num in ${oldResult//,/ } | |||
| do | |||
| send DELETE "/domain/zone/${topDomain}/record/${num}" "" | |||
| done | |||
| # Refresh request | |||
| send POST /domain/zone/${topDomain}/refresh "" | |||
| #!/bin/bash | |||
| domains=($(echo "$1"|sed -e 's/^\(\([a-zA-Z0-9.-]*\?\)\.\)*\([a-zA-Z0-9-]\+\.[a-zA-Z-]\+\)$/"\1" _acme-challenge.\2 \3/g')) | |||
| #challenge="$2" | |||
| # Please, do not forget to ask for your credentials at https://eu.api.ovh.com/createToken/ | |||
| # permissions needed are /domain/zone/* in GET,POST,DELETE | |||
| applicationKey="YourAK" | |||
| applicationSecret="YourAS" | |||
| consumerKey="YourCK" | |||
| topDomain=${domains[2]} | |||
| subDomain=${domains[1]%%.} | |||
| function send | |||
| { | |||
| method=$1 | |||
| url=$2 | |||
| body=$3 | |||
| ts=$(date +%s) | |||
| sign=\$1\$$(echo -n "${applicationSecret}+${consumerKey}+${method}+https://eu.api.ovh.com/1.0${url}+${body}+${ts}"|sha1sum|cut -d" " -f1) | |||
| curl -X "${method}" -H "Content-Type: application/json" -H "X-Ovh-Application: ${applicationKey}" -H "X-Ovh-Timestamp: ${ts}" -H "X-Ovh-Signature: ${sign}" -H "X-Ovh-Consumer: ${consumerKey}" -d "${body}" "https://eu.api.ovh.com/1.0${url}" | |||
| } | |||
| # Creation request | |||
| oldResult=$(send GET "/domain/zone/${topDomain}/record?fieldType=TXT&subDomain=${subDomain}" ""|sed -e 's/\[//' -e 's/\]//') | |||
| for num in ${oldResult//,/ } | |||
| do | |||
| send DELETE "/domain/zone/${topDomain}/record/${num}" "" | |||
| done | |||
| # Refresh request | |||
| send POST "/domain/zone/${topDomain}/refresh" "" | |||
| @ -0,0 +1,418 @@ | |||
| #!/bin/bash | |||
| # Copyright (2017) Timothe Litt litt at acm _dot org | |||
| VERSION="1.0.1" | |||
| PROG="`basename $0`" | |||
| # This script is used to update TXT records in GoDaddy DNS server | |||
| # It depends on JSON.sh from https://github.com/dominictarr/JSON.sh | |||
| # Place it in (or softlink it to) the same directory as this script, | |||
| # or specify its location with GODADDY_JSON | |||
| # | |||
| # See the usage text below, 00GoDaddy-README.txt, dns_add_godaddy | |||
| # and dns_del_godaddy for additional information. | |||
| # | |||
| # It may be freely used providing this notice is included with | |||
| # all copies. The name of the author may not be used to endorse | |||
| # any other product or derivative work. No warranty is provided | |||
| # and the user assumes all responsibility for use of this software. | |||
| # | |||
| # Bug reports are welcome at https://github.com/tlhackque/getssl/issues. | |||
| API='https://api.godaddy.com/v1/domains' | |||
| APISIGNUP='https://developer.godaddy.com/getstarted' | |||
| GETJSON='https://github.com/dominictarr/JSON.sh' | |||
| VERB="y" | |||
| DEBUG="$GODADDY_DEBUG" | |||
| [ -z "$JSON" ] && JSON="$GODADDY_JSON" | |||
| [ -z "$JSON" ] && JSON="`dirname $0`/JSON.sh" | |||
| while getopts 'dhj:k:s:t:qv' opt; do | |||
| case $opt in | |||
| d) DEBUG="Y" ;; | |||
| j) JSON="$OPTARG" ;; | |||
| k) GODADDY_KEY="$OPTARG" ;; | |||
| s) GODADDY_SECRET="$OPTARG" ;; | |||
| t) TRACE="$OPTARG" ;; | |||
| q) VERB= ;; | |||
| v) echo "dns_godaddy version $VERSION"; exit 0 ;; | |||
| *) | |||
| cat <<EOF | |||
| Usage | |||
| $PROG [-dt -h -j JSON -k:KEY -s:SECRET -q] add domain name data [ttl] | |||
| $PROG [-dt -h -j JSON -k:KEY -s:SECRET -q] del domain name data | |||
| Add or delete TXT records from GoDaddy DNS | |||
| Obtain the Key and Secret from $APISIGNUP | |||
| You must obtain a "Production" key - NOT the "Test" key you're required | |||
| to get first. | |||
| With getssl, this script is called from the dns_add_godaddy and | |||
| dns_del_godaddy wrapper scripts. | |||
| Arguments: | |||
| add - add the specified record to the domain | |||
| del - remove the specified record from the domain | |||
| domain is the domain name, e.g. example.org | |||
| name is the DNS record name to add, e.g. _acme-challenge.example.org. | |||
| Note that trailing '.' is significant in DNS. | |||
| data is the record data, e.g. "myverificationtoken" | |||
| ttl is optional, and defaults to the GoDaddy minimum of 600. | |||
| If it is necessary to turn on debugging externally, define | |||
| GODADDY_DEBUG="y" (any non-null string will do). | |||
| For minimal trace output (to override -q), define GODADDY_TRACE="y". | |||
| Options | |||
| -d Provide debugging output - all requests and responses | |||
| -h This help. | |||
| -j: Location of JSON.sh Default `dirname $0`/JSON.sh, or | |||
| the GODADDY_JSON variable. | |||
| -k: The GoDaddy API key Default from GODADDY_KEY | |||
| -s: The GoDaddy API secret Default from GODADDY_SECRET | |||
| -t: Detailed protocol trace data is appended to specified file | |||
| -q Quiet - omit normal success messages, | |||
| All output, except for this help text, is to stderr. | |||
| Environment variables | |||
| GODADDY_JSON location of the JSOH.sh script | |||
| GODADDY_KEY default API key | |||
| GODADDY_SCRIPT location of this script, default location of JSON.sh | |||
| GODADDY_SECRET default API secret | |||
| GODADDY_TRACE forces -q off if true | |||
| GODADDY_TFILE appends protocol trace to file. Overrides -t | |||
| BUGS | |||
| Due to a limitation of the gOdADDY API, deleting the last TXT record | |||
| would be too risky for my taste. So in that case, I replace it with | |||
| _dummy.record_.domain. TXT "Ihis record is not used". This record is | |||
| not automatically deleted by this script, though it's perfectly OK to | |||
| do so manually. (Via another mechanism, or if it's no longer the last.) | |||
| This really shouldn't happen often, since most domains have at least | |||
| one TXT record - for SPF, tracking APIs, etc. | |||
| Report any issues to https://github.com/tlhackque/getssl/issues | |||
| EOF | |||
| exit 0 | |||
| ;; | |||
| esac | |||
| done | |||
| shift $((OPTIND-1)) | |||
| # Check for JSON -- required for delete, but if records are added, | |||
| # we assume they'll be deleted later & don't want to strand them. | |||
| [[ "$JSON" =~ ^~ ]] && \ | |||
| eval 'JSON=`readlink -nf ' $JSON '`' | |||
| if [ ! -x "$JSON" ]; then | |||
| cat <<EOF >&2 | |||
| $0: requires JSON.sh as "$JSON" | |||
| The full path to JSON.sh can be specified with -j, or the | |||
| GODADDY_JSON environment variable. | |||
| You can obtain a copy from $GETJSON | |||
| Then place or softlink it to $JSON or set GODADDY_JSON. | |||
| EOF | |||
| exit 2 | |||
| fi | |||
| if [ -z "$GODADDY_KEY" ] || [ -z "$GODADDY_SECRET" ]; then | |||
| echo "GODADDY_KEY and GODADDY secret must be defined" >&2 | |||
| exit 3 | |||
| fi | |||
| [ -n "$DEBUG" ] && VERB="y" | |||
| [ -n "$GODADDY_TRACE" ] && VERB="Y" | |||
| [ -n "$GODADDY_TFILE" ] && TRACE="$GODADDY_TFILE" | |||
| # Get parameters & validate | |||
| op="$1" | |||
| if ! [[ "$op" =~ ^(add|del)$ ]]; then | |||
| echo "Operation must be \"add\" or \"del\"" >&2 | |||
| exit 3 | |||
| fi | |||
| domain="$2" | |||
| domain="${domain%'.'}" | |||
| if [ -z "$domain" ]; then | |||
| echo "'domain' parameter is required, see -h" >&2 | |||
| exit 3 | |||
| fi | |||
| name="$3" | |||
| if [ -z "$name" ]; then | |||
| echo "'name' parameter is required, see -h" >&2 | |||
| exit 3 | |||
| fi | |||
| ! [[ "$name" =~ [.]$ ]] && name="${name}.${domain}." | |||
| data="$4" | |||
| if [ -z "$data" ]; then | |||
| echo "'data' parameter is required, see -h" >&2 | |||
| exit 3 | |||
| fi | |||
| if [ "$op" = 'del' ]; then | |||
| ttl= | |||
| elif [ -z "$5" ]; then | |||
| ttl="600" # GoDaddy minimum TTL is 600 | |||
| elif ! [[ "$5" =~ ^[0-9]+$ ]]; then | |||
| echo "TTL $5 is not numeric" >&2 | |||
| exit 3 | |||
| elif [ $5 -lt 600 ]; then | |||
| [ -n "$VERB" ] && \ | |||
| echo "$5 is less than GoDaddy minimum of 600; increased to 600" >&2 | |||
| ttl="600" | |||
| else | |||
| ttl="$5" | |||
| fi | |||
| # --- Done with parameters | |||
| [ -n "$DEBUG" ] && \ | |||
| echo "$PROG: $op $domain $name \"$data\" $ttl" >&2 | |||
| # Authorization header has secret and key | |||
| authhdr="Authorization: sso-key $GODADDY_KEY:$GODADDY_SECRET" | |||
| if [ -n "$TRACE" ]; then | |||
| function timestamp { local tm="`LC_TIME=C date '+%T.%N'`" | |||
| local class="$1"; shift | |||
| echo "${tm:0:15} ** ${class}: $*" >>"$TRACE" | |||
| } | |||
| timestamp 'Info' "$PROG" "V$VERSION" 'Starting new protocol trace' | |||
| timestamp 'Args' "$@" | |||
| curl --help | grep -q -- --trace-time && CURL_TFLAGS="--trace-time" # 7.14.0 | |||
| function curl { | |||
| command curl ${CURL_TFLAGS} --trace-ascii % "$@" 2>>"$TRACE" | |||
| } | |||
| [ -n "$VERB" ] && echo "Appending protocol trace to $TRACE" | |||
| fi | |||
| [ -n "$DEBUG" ] && echo "$authhdr" >&2 | |||
| if [ "$op" = "add" ]; then | |||
| # May need to retry due to zone cuts | |||
| while [[ "$domain" =~ [^.]+\.[^.]+ ]]; do | |||
| url="$API/$domain/records/TXT/$name" | |||
| request='{"data":"'$data'","ttl":'$ttl'}' | |||
| [ -n "$DEBUG" ] && cat >&2 <<EOF | |||
| Add request to: $url | |||
| -------- | |||
| $request" | |||
| -------- | |||
| EOF | |||
| result="$(curl -i -s -X PUT -d "$request" --config - "$url" <<EOF | |||
| header = "Content-Type: application/json" | |||
| header = "$authhdr" | |||
| EOF | |||
| )" | |||
| sts=$? | |||
| [ -n "$DEBUG" ] && cat >&2 <<EOF | |||
| Result: | |||
| curl status = $sts | |||
| -------- | |||
| $result | |||
| -------- | |||
| EOF | |||
| if [ $sts -ne 0 ]; then | |||
| echo "curl error $sts adding record" >&2 | |||
| exit $sts | |||
| fi | |||
| if ! echo "$result" | grep -q '^HTTP/.* 200 '; then | |||
| code="`echo "$result" | grep '"code":' | sed -e's/^.*"code":"//; s/\".*$//'`" | |||
| msg="`echo "$result" | grep '"message":' | sed -e's/^.*"message":"//; s/\".*$//'`" | |||
| if [ "$code" = "DUPLICATE_RECORD" ]; then | |||
| if [ -n "$VERB" ]; then | |||
| echo "$msg in $domain" >&2 | |||
| fi | |||
| exit 0 # Duplicate record is still success | |||
| fi | |||
| if [ "$code" = 'UNKNOWN_DOMAIN' ]; then | |||
| if [[ "$domain" =~ ^([^.]+)\.([^.]+\.[^.]+.*) ]]; then | |||
| [ -n "$DEBUG" ] && \ | |||
| echo "$domain unknown, trying ${BASH_REMATCH[2]}" >&2 | |||
| domain="${BASH_REMATCH[2]}" | |||
| continue; | |||
| fi | |||
| fi | |||
| echo "Request failed $msg" >&2 | |||
| exit 1 | |||
| fi | |||
| [ -n "$VERB" ] && echo "$domain: added $name $ttl TXT \"$data\"" >&2 | |||
| exit 0 | |||
| done | |||
| fi | |||
| # ----- Delete | |||
| # There is no delete API | |||
| # But, it is possible to replace all TXT records. | |||
| # | |||
| # So, first query for all TXT records | |||
| # May need to retry due to zone cuts | |||
| while [[ "$domain" =~ [^.]+\.[^.]+ ]]; do | |||
| url="$API/$domain/records/TXT" | |||
| [ -n "$DEBUG" ] && echo "Query for TXT records to: $url" >&2 | |||
| current="$(curl -i -s -X GET --config - "$url" <<EOF | |||
| header = "$authhdr" | |||
| EOF | |||
| )" | |||
| sts=$? | |||
| if [ $sts -ne 0 ]; then | |||
| echo "curl error $sts for query" >&2 | |||
| exit $sts | |||
| fi | |||
| [ -n "$DEBUG" ] && cat >&2 <<EOF | |||
| Response | |||
| -------- | |||
| $current | |||
| -------- | |||
| EOF | |||
| if ! echo "$current" | grep -q '^HTTP/.* 200 '; then | |||
| code="`echo "$current" | grep '"code":' | sed -e's/^.*"code":"//; s/\".*$//'`" | |||
| msg="`echo "$current" | grep '"message":' | sed -e's/^.*"message":"//; s/\".*$//'`" | |||
| if [ "$code" = "UNKNOWN_DOMAIN" ]; then | |||
| if [[ "$domain" =~ ^([^.]+)\.([^.]+\.[^.]+.*) ]]; then | |||
| [ -n "$DEBUG" ] && echo \ | |||
| "$domain unknown, trying ${BASH_REMATCH[2]}" >&2 | |||
| domain="${BASH_REMATCH[2]}" | |||
| continue; | |||
| fi | |||
| fi | |||
| echo "Request failed $msg" >&2 | |||
| exit 1 | |||
| fi | |||
| # Remove headers | |||
| current="$(echo "$current" | sed -e'0,/^\r*$/d')" | |||
| break | |||
| done | |||
| # The zone cut is known, so the replace can't fail due to UNKNOWN domain | |||
| if [ "$current" = '[]' ]; then # No TXT records in zone | |||
| [ -n "$VERB" ] && echo "$domain: $name TXT \"$data\" does not exist" >&2 | |||
| [ -n "$DEBUG" ] && echo "No TXT records in $domain" >&2 | |||
| exit 1 # Intent was to change, so error status | |||
| fi | |||
| [ -n "$DEBUG" ] && echo "Response is valid" | |||
| # Prepare request to replace TXT RRSET | |||
| # Parse JSON and select only the record structures, which are [index] { ...} | |||
| current="$(echo "$current" | $JSON | sed -n -e'/^\[[0-9][0-9]*\]/{ s/^\[[0-9][0-9]*\]//; p}')" | |||
| base="$current" | |||
| [ -n "$DEBUG" ] && cat >&2 <<EOF | |||
| Old TXT RRSET: | |||
| $current | |||
| EOF | |||
| # Remove the desired record. The name must be relative. | |||
| eval 'name="$''{name%'"'.$domain.'}"'"' | |||
| match="$(printf '"name":"%s","data":"%s","ttl":' "$name" "$data")" | |||
| cmd="$(printf 'echo %s%s%s | grep -v %s%s%s' "'" "$current" "'" "'" "$match" "'")" | |||
| eval 'new="$('"$cmd"')"' | |||
| if [ "$new" = "$base" ]; then | |||
| [ -n "$VERB" ] && echo "$domain: $name TXT \"$data\" does not exist" >&2 | |||
| exit 1 # Intent was to change DNS, so this is an error | |||
| fi | |||
| # Remove whitespace and insert needed commmas | |||
| # | |||
| fmtnew="$new" | |||
| new=$(echo "$new" | sed -e"s/}/},/g; \$s/},/}/;" | tr -d '\t\n') | |||
| if [ -z "$new" ]; then | |||
| [ -n "$VERB" ] && echo "Replacing last TXT record with a dummy (see -h)" >&2 | |||
| new='{"type":"TXT","name":"_dummy.record_","data":"_This record is not used_","ttl":601}' | |||
| dummy="t" | |||
| TAB=$'\t' | |||
| fmtnew="${TAB}$new" | |||
| if [ "$fmtnew" = "$base" ]; then | |||
| [ -n "$VERB" ] && echo "This tool can't delete a placeholder when it is the only TXT record" >&2 | |||
| exit 0 # Not really success, but retrying won't help. | |||
| fi | |||
| fi | |||
| request="[$new]" | |||
| [ -n "$DEBUG" ] && cat >&2 <<EOF | |||
| New TXT RRSET will be | |||
| $fmtnew | |||
| EOF | |||
| url="$API/$domain/records/TXT" | |||
| [ -n "$DEBUG" ] && cat >&2 <<EOF | |||
| Replace (delete) request to: $url | |||
| -------- | |||
| $request | |||
| -------- | |||
| EOF | |||
| result="$(curl -i -s -X PUT -d "$request" --config - "$url" <<EOF | |||
| header = "Content-Type: application/json" | |||
| header = "$authhdr" | |||
| EOF | |||
| )" | |||
| sts=$? | |||
| [ -n "$DEBUG" ] && cat >&2 <<EOF | |||
| Result: | |||
| curl status = $sts | |||
| -------- | |||
| $result | |||
| -------- | |||
| EOF | |||
| if [ $sts -ne 0 ]; then | |||
| echo "curl error $sts deleting record" >&2 | |||
| exit $sts | |||
| fi | |||
| if ! echo "$result" | grep -q '^HTTP/.* 200 '; then | |||
| result="$(echo "$result" | sed -e'0,/^\r*$/d')" | |||
| code="`echo "$result" | grep '"code":' | sed -e's/^.*"code":"//; s/\".*$//'`" | |||
| msg="`echo "$result" | grep '"message":' | sed -e's/^.*"message":"//; s/\".*$//'`" | |||
| echo "Request failed $msg" >&2 | |||
| exit 1 | |||
| fi | |||
| if [ -n "$VERB" ]; then | |||
| if [ -n "$dummy" ]; then | |||
| echo "$domain: replaced $name TXT \"$data\" with a placeholder" >&2 | |||
| else | |||
| echo "$domain: deleted $name TXT \"$data\"" >&2 | |||
| fi | |||
| fi | |||
| exit 0 | |||