Conflicts: getsslpull/519/head
| @ -0,0 +1,30 @@ | |||
| --- | |||
| 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. | |||
| @ -1,24 +1,31 @@ | |||
| # How to contribute | |||
| If you are happy writing in bash, please create a PR for any changes you'd like to see included (or bug fixes). | |||
| If you are happy writing in bash, please create a PR for any changes | |||
| you'd like to see included (or bug fixes). | |||
| If you aren't happy writing in bash, please open an issue with as much detail as possible about the issue or what you'd like to see added / improved. | |||
| If you aren't happy writing in bash, please open an issue with as much | |||
| detail as possible about the issue or what you'd like to see added / | |||
| improved. | |||
| ## Submitting changes | |||
| Please update the 'revision history' and version number at the top of the code (without this I can't easily do a merge) | |||
| Please update the 'revision history' and version number at the top of | |||
| the code (without this I can't easily do a merge) | |||
| Please update just one issue per PR. If there are multiple issues, please provide separate PR's one per issue. | |||
| Please update just one issue per PR. If there are multiple issues, | |||
| please provide separate PR's one per issue. | |||
| ## Coding conventions | |||
| Please see the guidelines at https://github.com/srvrco/getssl/wiki/Bash-Style-guide | |||
| Please see the guidelines at <https://github.com/srvrco/getssl/wiki/Bash-Style-guide> | |||
| ## Testing | |||
| Please test with [shellcheck](https://github.com/koalaman/shellcheck), although this will also be tested on github ( via travis) on all PRs. | |||
| Please test with [shellcheck](https://github.com/koalaman/shellcheck), | |||
| although this will also be tested on github (via travis) on all PRs. | |||
| Please remember that the system is used across a wide range of platforms, so if you have access to multiple operating systems, please test on all. | |||
| Please remember that the system is used across a wide range of | |||
| platforms, so if you have access to multiple operating systems, please | |||
| test on all. | |||
| Thanks :) | |||
| Thanks :) | |||
| @ -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,7 @@ | |||
| #!/usr/bin/env bash | |||
| # Simple script to update the challtestserv mock DNS server when testing DNS responses | |||
| fulldomain="${1}" | |||
| token="${2}" | |||
| curl -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\", \"value\": \"${token}\"}" http://10.30.50.3:8055/set-txt | |||
| @ -0,0 +1,103 @@ | |||
| #!/usr/bin/env bash | |||
| # Need to add your email address and API key to clouddns below or set as env variables | |||
| email=${CLOUDDNS_EMAIL:-''} | |||
| password=${CLOUDDNS_PASSWORD:-''} | |||
| client=${CLOUDDNS_CLIENT:-''} | |||
| # This script adds a token to clouddns DNS for the ACME challenge | |||
| # usage dns_add_clouddns "domain name" "token" | |||
| # return codes are; | |||
| # 0 - success | |||
| # 1 - error in input | |||
| # 2 - error within internal processing | |||
| # 3 - error in result ( domain not found in clouddns etc) | |||
| fulldomain="${1}" | |||
| token="${2}" | |||
| API='https://admin.vshosting.cloud/clouddns' | |||
| LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login' | |||
| # Check initial parameters | |||
| 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 | |||
| if [[ -z "$email" ]]; then | |||
| echo "CLOUDDNS_EMAIL (email) parameter not set" | |||
| exit 1 | |||
| fi | |||
| if [[ -z "$password" ]]; then | |||
| echo "CLOUDDNS_PASSWORD (password) parameter not set" | |||
| exit 1 | |||
| fi | |||
| if [[ -z "$client" ]]; then | |||
| echo "CLOUDDNS_CLIENT (id) parameter not set" | |||
| exit 1 | |||
| fi | |||
| # Login to clouddns to get accessToken | |||
| resp=$(curl --silent -X POST -H 'Content-Type: application/json' "$LOGIN_API" \ | |||
| --data "{\"email\": \"$email\", \"password\": \"$password\"}") | |||
| re='"accessToken":"([^,]*)",' # Match access token | |||
| if [[ "${resp// }" =~ $re ]]; then | |||
| access_token="${BASH_REMATCH[1]}" | |||
| fi | |||
| if [[ -z "$access_token" ]]; then | |||
| echo 'Could not get access token; check your credentials' | |||
| exit 3 | |||
| fi | |||
| curl_params=( -H "Authorization: Bearer $access_token" -H 'Content-Type: application/json' ) | |||
| # Get main domain | |||
| resp=$(curl --silent "${curl_params[@]}" -X POST "$API/domain/search" \ | |||
| --data "{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$client\"}]}") | |||
| domain_slice="$fulldomain" | |||
| while [[ -z "$domain_root" ]]; do | |||
| if [[ "${resp// }" =~ domainName\":\"$domain_slice ]]; then | |||
| domain_root="$domain_slice" | |||
| _debug domain_root "$domain_root" | |||
| fi | |||
| domain_slice="${domain_slice#[^\.]*.}" | |||
| done | |||
| # Get domain id | |||
| resp=$(curl --silent "${curl_params[@]}" -X POST "$API/domain/search" \ | |||
| --data "{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$client\"}, {\"name\": \"domainName\", \"operator\": \"eq\", \"value\": \"$domain_root.\"}]}") | |||
| re='domainType":"[^"]*","id":"([^,]*)",' # Match domain id | |||
| if [[ "${resp//[$'\t\r\n ']}" =~ $re ]]; then | |||
| domain_id="${BASH_REMATCH[1]}" | |||
| fi | |||
| if [[ -z "$domain_id" ]]; then | |||
| echo 'Domain name not found on your CloudDNS account' | |||
| exit 3 | |||
| fi | |||
| # Add challenge record | |||
| txt_record="_acme-challenge.$fulldomain." | |||
| resp=$(curl --silent "${curl_params[@]}" -X POST "$API/record-txt" \ | |||
| --data "{\"type\":\"TXT\",\"name\":\"$txt_record\",\"value\":\"$token\",\"domainId\":\"$domain_id\"}") | |||
| # If adding record failed (error:) then print error message | |||
| if [[ "${resp// }" == *'"error"'* ]]; then | |||
| if [[ "${resp// }" == *'"code":4136'* ]]; then | |||
| echo "DNS challenge token already exists" | |||
| exit | |||
| fi | |||
| re='"message":"([^"]+)"' | |||
| if [[ "$resp" =~ $re ]]; then | |||
| echo "Error: DNS challenge not added: ${BASH_REMATCH[1]}" | |||
| exit 3 | |||
| else | |||
| echo "Error: DNS challenge not added: unknown error - ${resp}" | |||
| exit 3 | |||
| fi | |||
| fi | |||
| # Publish challenge record | |||
| resp=$(curl --silent "${curl_params[@]}" -X PUT "$API/domain/$domain_id/publish" \ | |||
| --data "{\"soaTtl\":300}") | |||
| @ -0,0 +1,19 @@ | |||
| #!/bin/bash | |||
| # need to add your Token for duckdns below | |||
| token=${DUCKDNS_TOKEN:-} | |||
| if [ -z "$token" ]; then | |||
| echo "DUCKDNS_TOKEN not set" | |||
| exit 1 | |||
| fi | |||
| domain="$1" | |||
| txtvalue="$2" | |||
| response=$(curl --silent "https://www.duckdns.org/update?domains=${domain}&token=${token}&txt=${txtvalue}") | |||
| if [ "$response" != "OK" ]; then | |||
| echo "Failed to update TXT record for ${domain} at duckdns.org (is the TOKEN valid?)" | |||
| echo "Response: $response" | |||
| exit 1 | |||
| fi | |||
| @ -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,6 @@ | |||
| #!/usr/bin/env bash | |||
| # Simple script to update the challtestserv mock DNS server when testing DNS responses | |||
| fulldomain="${1}" | |||
| curl -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\"}" http://10.30.50.3:8055/clear-txt | |||
| @ -0,0 +1,110 @@ | |||
| #!/usr/bin/env bash | |||
| # Need to add your email address and API key to clouddns below or set as env variables | |||
| email=${CLOUDDNS_EMAIL:-''} | |||
| password=${CLOUDDNS_PASSWORD:-''} | |||
| client=${CLOUDDNS_CLIENT:-''} | |||
| # This script adds a token to clouddns DNS for the ACME challenge | |||
| # usage dns_add_clouddns "domain name" "token" | |||
| # return codes are; | |||
| # 0 - success | |||
| # 1 - error in input | |||
| # 2 - error within internal processing | |||
| # 3 - error in result ( domain not found in clouddns etc) | |||
| fulldomain="${1}" | |||
| token="${2}" | |||
| API='https://admin.vshosting.cloud/clouddns' | |||
| LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login' | |||
| # Check initial parameters | |||
| 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 | |||
| if [[ -z "$email" ]]; then | |||
| echo "CLOUDDNS_EMAIL (email) parameter not set" | |||
| exit 1 | |||
| fi | |||
| if [[ -z "$password" ]]; then | |||
| echo "CLOUDDNS_PASSWORD (password) parameter not set" | |||
| exit 1 | |||
| fi | |||
| if [[ -z "$client" ]]; then | |||
| echo "CLOUDDNS_CLIENT (id) parameter not set" | |||
| exit 1 | |||
| fi | |||
| # Login to clouddns to get accessToken | |||
| resp=$(curl --silent -X POST -H 'Content-Type: application/json' "$LOGIN_API" \ | |||
| --data "{\"email\": \"$email\", \"password\": \"$password\"}") | |||
| re='"accessToken":"([^,]*)",' # Match access token | |||
| if [[ "${resp// }" =~ $re ]]; then | |||
| access_token="${BASH_REMATCH[1]}" | |||
| fi | |||
| if [[ -z "$access_token" ]]; then | |||
| echo 'Could not get access token; check your credentials' | |||
| exit 3 | |||
| fi | |||
| curl_params=( -H "Authorization: Bearer $access_token" -H 'Content-Type: application/json' ) | |||
| # Get main domain and challenge record | |||
| resp=$(curl --silent "${curl_params[@]}" -X POST "$API/domain/search" \ | |||
| --data "{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$client\"}]}") | |||
| domain_slice="$fulldomain" | |||
| while [[ -z "$domain_root" ]]; do | |||
| if [[ "${resp// }" =~ domainName\":\"$domain_slice ]]; then | |||
| domain_root="$domain_slice" | |||
| _debug domain_root "$domain_root" | |||
| fi | |||
| domain_slice="${domain_slice#[^\.]*.}" | |||
| done | |||
| txt_record="_acme-challenge.$fulldomain." | |||
| # Get domain id | |||
| curl_domainid_body="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$client\"}, {\"name\": \"domainName\", \"operator\": \"eq\", \"value\": \"$domain_root.\"}]}" | |||
| resp=$(curl --silent "${curl_params[@]}" -X POST -d "$curl_domainid_body" "$API/domain/search") | |||
| re='domainType":"[^"]*","id":"([^,]*)",' # Find result section | |||
| if [[ "${resp//[$'\t\r\n ']}" =~ $re ]]; then | |||
| domain_id="${BASH_REMATCH[1]}" | |||
| fi | |||
| if [[ -z "$domain_id" ]]; then | |||
| echo 'Domain name not found on your CloudDNS account' | |||
| exit 3 | |||
| fi | |||
| # Get challenge record ID | |||
| resp=$(curl --silent "${curl_params[@]}" -X GET "$API/domain/$domain_id" ) | |||
| re="\"lastDomainRecordList\".*\"id\":\"([^,]*)\"[^}]*\"name\":\"$txt_record\"," # Match domain id | |||
| if [[ "${resp//[$'\t\r\n ']}" =~ $re ]]; then | |||
| record_id="${BASH_REMATCH[1]}" | |||
| fi | |||
| if [[ -z "$record_id" ]]; then | |||
| echo 'Challenge record does not exist' | |||
| exit 3 | |||
| fi | |||
| # Remove challenge record | |||
| resp=$(curl --silent "${curl_params[@]}" -X DELETE "$API/record/$record_id") | |||
| # If removing record failed (error:) then print error message | |||
| if [[ "${resp// }" == *'"error"'* ]]; then | |||
| re='"message":"([^"]+)"' | |||
| if [[ "$resp" =~ $re ]]; then | |||
| echo "Error: DNS challenge not removed: ${BASH_REMATCH[1]}" | |||
| exit 3 | |||
| else | |||
| echo "Error: DNS challenge not removed: unknown error - ${resp}" | |||
| exit 3 | |||
| fi | |||
| fi | |||
| # Publish challenge record deletion | |||
| resp=$(curl --silent "${curl_params[@]}" -X PUT "$API/domain/$domain_id/publish" \ | |||
| --data "{\"soaTtl\":300}") | |||
| @ -0,0 +1,12 @@ | |||
| #!/bin/bash | |||
| # need to add your Token for duckdns below | |||
| token=${DUCKDNS_TOKEN:-} | |||
| domain="$1" | |||
| response=$(curl --silent "https://www.duckdns.org/update?domains=${domain}&token=${token}&txt=&clear=true") | |||
| if [ "$response" != "OK" ]; then | |||
| echo "Failed to update TXT record for ${domain} at duckdns.org (is the TOKEN valid?)" | |||
| echo "$response" | |||
| exit 1 | |||
| fi | |||
| @ -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,41 @@ | |||
| #!/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}" | |||
| if [ -n "${DNS_SERVER}" ]; then | |||
| cmd+="server ${DNS_SERVER}\n" | |||
| fi | |||
| cmd+="update delete ${DNS_ZONE:-"_acme-challenge.${fulldomain}."} 300 in TXT \"${token}\"\n" | |||
| cmd+="\n" # blank line is a "send" command to nsupdate | |||
| printf "$cmd" | nsupdate ${options} -v | |||
| 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,702 @@ | |||
| #!/usr/bin/env sh | |||
| #This file name is "dns_freedns.sh" | |||
| #So, here must be a method dns_freedns_add() | |||
| #Which will be called by acme.sh to add the txt record to your api system. | |||
| #returns 0 means success, otherwise error. | |||
| # | |||
| #Author: David Kerr | |||
| #Report Bugs here: https://github.com/dkerr64/acme.sh | |||
| #or here... https://github.com/Neilpang/acme.sh/issues/2305 | |||
| # | |||
| ######## Public functions ##################### | |||
| # Export FreeDNS userid and password in following variables... | |||
| # FREEDNS_User=username | |||
| # FREEDNS_Password=password | |||
| # login cookie is saved in acme account config file so userid / pw | |||
| # need to be set only when changed. | |||
| #Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" | |||
| dns_freedns_add() { | |||
| fulldomain="_acme-challenge.$1" | |||
| txtvalue="$2" | |||
| FREEDNS_COOKIE="$(cat $(dirname "$(readlink -f "$0")")/freednscookie.dat)" | |||
| echo "Info: Add TXT record using FreeDNS" | |||
| #echo "Debug: fulldomain: $fulldomain" | |||
| #echo "Debug: txtvalue: $txtvalue" | |||
| if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then | |||
| FREEDNS_User="" | |||
| FREEDNS_Password="" | |||
| if [ -z "$FREEDNS_COOKIE" ]; then | |||
| echo "ERROR: You did not specify the FreeDNS username and password yet." | |||
| echo "ERROR: Please export as FREEDNS_User / FREEDNS_Password and try again." | |||
| return 1 | |||
| fi | |||
| using_cached_cookies="true" | |||
| else | |||
| FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")" | |||
| if [ -z "$FREEDNS_COOKIE" ]; then | |||
| return 1 | |||
| fi | |||
| using_cached_cookies="false" | |||
| fi | |||
| #echo "Debug: FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)" | |||
| echo "$FREEDNS_COOKIE">$(dirname "$(readlink -f "$0")")/freednscookie.dat | |||
| # We may have to cycle through the domain name to find the | |||
| # TLD that we own... | |||
| i=1 | |||
| wmax="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" | |||
| while [ "$i" -lt "$wmax" ]; do | |||
| # split our full domain name into two parts... | |||
| sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" | |||
| i="$(_math "$i" + 1)" | |||
| top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)" | |||
| #echo "Debug: sub_domain: $sub_domain" | |||
| #echo "Debug: top_domain: $top_domain" | |||
| DNSdomainid="$(_freedns_domain_id "$top_domain")" | |||
| if [ "$?" = "0" ]; then | |||
| echo "Info:Domain $top_domain found at FreeDNS, domain_id $DNSdomainid" | |||
| break | |||
| else | |||
| echo "Info:Domain $top_domain not found at FreeDNS, try with next level of TLD" | |||
| fi | |||
| done | |||
| if [ -z "$DNSdomainid" ]; then | |||
| # If domain ID is empty then something went wrong (top level | |||
| # domain not found at FreeDNS). | |||
| echo "ERROR: Domain $top_domain not found at FreeDNS" | |||
| return 1 | |||
| fi | |||
| # Add in new TXT record with the value provided | |||
| #echo "Debug: Adding TXT record for $fulldomain, $txtvalue" | |||
| _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" | |||
| return $? | |||
| } | |||
| #Usage: fulldomain txtvalue | |||
| #Remove the txt record after validation. | |||
| dns_freedns_rm() { | |||
| fulldomain="_acme-challenge.$1" | |||
| txtvalue="$2" | |||
| echo "Info:Delete TXT record using FreeDNS" | |||
| #echo "Debug: fulldomain: $fulldomain" | |||
| #echo "Debug: txtvalue: $txtvalue" | |||
| # Need to read cookie from conf file again in case new value set | |||
| # during login to FreeDNS when TXT record was created. | |||
| FREEDNS_COOKIE="$(cat $(dirname "$(readlink -f "$0")")/freednscookie.dat)" | |||
| #echo "Debug: FreeDNS login cookies: $FREEDNS_COOKIE" | |||
| TXTdataid="$(_freedns_data_id "$fulldomain" "TXT")" | |||
| if [ "$?" != "0" ]; then | |||
| echo "Info:Cannot delete TXT record for $fulldomain, record does not exist at FreeDNS" | |||
| return 1 | |||
| fi | |||
| #echo "Debug: Data ID's found, $TXTdataid" | |||
| # now we have one (or more) TXT record data ID's. Load the page | |||
| # for that record and search for the record txt value. If match | |||
| # then we can delete it. | |||
| lines="$(echo "$TXTdataid" | wc -l)" | |||
| #echo "Debug: Found $lines TXT data records for $fulldomain" | |||
| i=0 | |||
| while [ "$i" -lt "$lines" ]; do | |||
| i="$(_math "$i" + 1)" | |||
| dataid="$(echo "$TXTdataid" | sed -n "${i}p")" | |||
| #echo "Debug: $dataid" | |||
| htmlpage="$(_freedns_retrieve_data_page "$FREEDNS_COOKIE" "$dataid")" | |||
| if [ "$?" != "0" ]; then | |||
| if [ "$using_cached_cookies" = "true" ]; then | |||
| echo "ERROR: Has your FreeDNS username and password changed? If so..." | |||
| echo "ERROR: Please export as FREEDNS_User / FREEDNS_Password and try again." | |||
| fi | |||
| return 1 | |||
| fi | |||
| echo "$htmlpage" | grep "value=\""$txtvalue"\"" >/dev/null | |||
| if [ "$?" = "0" ]; then | |||
| # Found a match... delete the record and return | |||
| echo "Info:Deleting TXT record for $fulldomain, $txtvalue" | |||
| _freedns_delete_txt_record "$FREEDNS_COOKIE" "$dataid" | |||
| return $? | |||
| fi | |||
| done | |||
| # If we get this far we did not find a match | |||
| # Not necessarily an error, but log anyway. | |||
| echo "Info:Cannot delete TXT record for $fulldomain, $txtvalue. Does not exist at FreeDNS" | |||
| return 0 | |||
| } | |||
| #################### Private functions below ################################## | |||
| # usage: _freedns_login username password | |||
| # print string "cookie=value" etc. | |||
| # returns 0 success | |||
| _freedns_login() { | |||
| export _H1="Accept-Language:en-US" | |||
| username="$1" | |||
| password="$2" | |||
| url="https://freedns.afraid.org/zc.php?step=2" | |||
| #echo "Debug: Login to FreeDNS as user $username" | |||
| data="username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" | |||
| #echo "$data" | |||
| if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then | |||
| HTTP_HEADER="$(_mktemp)" | |||
| fi | |||
| htmlpage="$(curl -L --silent --dump-header $HTTP_HEADER -X POST -H "$_H1" -H "$_H2" --data "$data" "$url")" | |||
| if [ "$?" != "0" ]; then | |||
| echo "ERROR: FreeDNS login failed for user $username bad RC from _post" | |||
| return 1 | |||
| fi | |||
| cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" | |||
| # if cookies is not empty then logon successful | |||
| if [ -z "$cookies" ]; then | |||
| #echo "Debug3: htmlpage: $htmlpage" | |||
| echo "ERROR: FreeDNS login failed for user $username. Check $HTTP_HEADER file" | |||
| return 1 | |||
| fi | |||
| printf "%s" "$cookies" | |||
| return 0 | |||
| } | |||
| # usage _freedns_retrieve_subdomain_page login_cookies | |||
| # echo page retrieved (html) | |||
| # returns 0 success | |||
| _freedns_retrieve_subdomain_page() { | |||
| export _H1="Cookie:$1" | |||
| export _H2="Accept-Language:en-US" | |||
| url="https://freedns.afraid.org/subdomain/" | |||
| #echo "Debug: Retrieve subdomain page from FreeDNS" | |||
| htmlpage="$(curl -L --silent -H "$_H1" -H "$_H2" "$url")" | |||
| if [ "$?" != "0" ]; then | |||
| echo "ERROR: FreeDNS retrieve subdomains failed bad RC from _get" | |||
| return 1 | |||
| elif [ -z "$htmlpage" ]; then | |||
| echo "ERROR: FreeDNS returned empty subdomain page" | |||
| return 1 | |||
| fi | |||
| #echo "Debug3: htmlpage: $htmlpage" | |||
| printf "%s" "$htmlpage" | |||
| return 0 | |||
| } | |||
| # usage _freedns_retrieve_data_page login_cookies data_id | |||
| # echo page retrieved (html) | |||
| # returns 0 success | |||
| _freedns_retrieve_data_page() { | |||
| export _H1="Cookie:$1" | |||
| export _H2="Accept-Language:en-US" | |||
| data_id="$2" | |||
| url="https://freedns.afraid.org/subdomain/edit.php?data_id=$2" | |||
| #echo "Debug: Retrieve data page for ID $data_id from FreeDNS" | |||
| htmlpage="$(curl -L --silent -H "$_H1" -H "$_H2" "$url")" | |||
| if [ "$?" != "0" ]; then | |||
| echo "ERROR: FreeDNS retrieve data page failed bad RC from _get" | |||
| return 1 | |||
| elif [ -z "$htmlpage" ]; then | |||
| echo "ERROR: FreeDNS returned empty data page" | |||
| return 1 | |||
| fi | |||
| #echo "Debug3: htmlpage: $htmlpage" | |||
| printf "%s" "$htmlpage" | |||
| return 0 | |||
| } | |||
| # usage _freedns_add_txt_record login_cookies domain_id subdomain value | |||
| # returns 0 success | |||
| _freedns_add_txt_record() { | |||
| export _H1="Cookie:$1" | |||
| export _H2="Accept-Language:en-US" | |||
| domain_id="$2" | |||
| subdomain="$3" | |||
| value="$(printf '%s' "$4" | _url_encode)" | |||
| url="https://freedns.afraid.org/subdomain/save.php?step=2" | |||
| if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then | |||
| HTTP_HEADER="$(_mktemp)" | |||
| fi | |||
| htmlpage="$(curl -L --silent --dump-header $HTTP_HEADER -X POST -H "$_H1" -H "$_H2" --data "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")" | |||
| if [ "$?" != "0" ]; then | |||
| echo "ERROR: FreeDNS failed to add TXT record for $subdomain bad RC from _post" | |||
| return 1 | |||
| elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then | |||
| #echo "Debug3: htmlpage: $(cat $HTTP_HEADER)" | |||
| echo "ERROR: FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" | |||
| return 1 | |||
| elif _contains "$htmlpage" "security code was incorrect"; then | |||
| #echo "Debug3: htmlpage: $htmlpage" | |||
| echo "ERROR: FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code" | |||
| echo "ERROR: Note that you cannot use automatic DNS validation for FreeDNS public domains" | |||
| return 1 | |||
| fi | |||
| #echo "Debug3: htmlpage: $htmlpage" | |||
| echo "Info:Added acme challenge TXT record for $fulldomain at FreeDNS" | |||
| return 0 | |||
| } | |||
| # usage _freedns_delete_txt_record login_cookies data_id | |||
| # returns 0 success | |||
| _freedns_delete_txt_record() { | |||
| export _H1="Cookie:$1" | |||
| export _H2="Accept-Language:en-US" | |||
| data_id="$2" | |||
| url="https://freedns.afraid.org/subdomain/delete2.php" | |||
| htmlheader="$(curl -L --silent -I -H "$_H1" -H "$_H2" "$url?data_id%5B%5D=$data_id&submit=delete+selected")" | |||
| if [ "$?" != "0" ]; then | |||
| echo "ERROR: FreeDNS failed to delete TXT record for $data_id bad RC from _get" | |||
| return 1 | |||
| elif ! _contains "$htmlheader" "200 OK"; then | |||
| #echo "Debug2: htmlheader: $htmlheader" | |||
| echo "ERROR: FreeDNS failed to delete TXT record $data_id" | |||
| return 1 | |||
| fi | |||
| echo "Info:Deleted acme challenge TXT record for $fulldomain at FreeDNS" | |||
| return 0 | |||
| } | |||
| # usage _freedns_domain_id domain_name | |||
| # echo the domain_id if found | |||
| # return 0 success | |||
| _freedns_domain_id() { | |||
| # Start by escaping the dots in the domain name | |||
| search_domain="$(echo "$1" | sed 's/\./\\./g')" | |||
| # Sometimes FreeDNS does not return the subdomain page but rather | |||
| # returns a page regarding becoming a premium member. This usually | |||
| # happens after a period of inactivity. Immediately trying again | |||
| # returns the correct subdomain page. So, we will try twice to | |||
| # load the page and obtain our domain ID | |||
| attempts=2 | |||
| while [ "$attempts" -gt "0" ]; do | |||
| attempts="$(_math "$attempts" - 1)" | |||
| htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" | |||
| if [ "$?" != "0" ]; then | |||
| if [ "$using_cached_cookies" = "true" ]; then | |||
| echo "ERROR: Has your FreeDNS username and password changed? If so..." | |||
| echo "ERROR: Please export as FREEDNS_User / FREEDNS_Password and try again." | |||
| fi | |||
| return 1 | |||
| fi | |||
| domain_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' \ | |||
| | grep "<td>$search_domain</td>\|<td>$search_domain(.*)</td>" \ | |||
| | sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' \ | |||
| | cut -d = -f 2)" | |||
| # The above beauty extracts domain ID from the html page... | |||
| # strip out all blank space and new lines. Then insert newlines | |||
| # before each table row <tr> | |||
| # search for the domain within each row (which may or may not have | |||
| # a text string in brackets (.*) after it. | |||
| # And finally extract the domain ID. | |||
| if [ -n "$domain_id" ]; then | |||
| printf "%s" "$domain_id" | |||
| return 0 | |||
| fi | |||
| #echo "Debug:Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)" | |||
| done | |||
| #echo "Debug:Domain $search_domain not found after retry" | |||
| return 1 | |||
| } | |||
| # usage _freedns_data_id domain_name record_type | |||
| # echo the data_id(s) if found | |||
| # return 0 success | |||
| _freedns_data_id() { | |||
| # Start by escaping the dots in the domain name | |||
| search_domain="$(echo "$1" | sed 's/\./\\./g')" | |||
| record_type="$2" | |||
| # Sometimes FreeDNS does not return the subdomain page but rather | |||
| # returns a page regarding becoming a premium member. This usually | |||
| # happens after a period of inactivity. Immediately trying again | |||
| # returns the correct subdomain page. So, we will try twice to | |||
| # load the page and obtain our domain ID | |||
| attempts=2 | |||
| while [ "$attempts" -gt "0" ]; do | |||
| attempts="$(_math "$attempts" - 1)" | |||
| htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" | |||
| if [ "$?" != "0" ]; then | |||
| if [ "$using_cached_cookies" = "true" ]; then | |||
| echo "ERROR: Has your FreeDNS username and password changed? If so..." | |||
| echo "ERROR: Please export as FREEDNS_User / FREEDNS_Password and try again." | |||
| fi | |||
| return 1 | |||
| fi | |||
| data_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' \ | |||
| | grep "<td[a-zA-Z=#]*>$record_type</td>" \ | |||
| | grep "<ahref.*>$search_domain</a>" \ | |||
| | sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' \ | |||
| | cut -d = -f 2)" | |||
| # The above beauty extracts data ID from the html page... | |||
| # strip out all blank space and new lines. Then insert newlines | |||
| # before each table row <tr> | |||
| # search for the record type withing each row (e.g. TXT) | |||
| # search for the domain within each row (which is within a <a..> | |||
| # </a> anchor. And finally extract the domain ID. | |||
| if [ -n "$data_id" ]; then | |||
| printf "%s" "$data_id" | |||
| return 0 | |||
| fi | |||
| #echo "Debug:Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)" | |||
| done | |||
| #echo "Debug:Domain $search_domain not found after retry" | |||
| return 1 | |||
| } | |||
| #### BEGIN things shamefully ripped from https://github.com/Neilpang/acme.sh/blob/master/acme.sh | |||
| #_ascii_hex str | |||
| #this can only process ascii chars, should only be used when od command is missing as a backup way. | |||
| _ascii_hex() { | |||
| _debug2 "Using _ascii_hex" | |||
| _str="$1" | |||
| _str_len=${#_str} | |||
| _h_i=1 | |||
| while [ "$_h_i" -le "$_str_len" ]; do | |||
| _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" | |||
| printf " %02x" "'$_str_c" | |||
| _h_i="$(_math "$_h_i" + 1)" | |||
| done | |||
| } | |||
| #stdin output hexstr splited by one space | |||
| #input:"abc" | |||
| #output: " 61 62 63" | |||
| _hex_dump() { | |||
| if _exists od; then | |||
| od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n" | |||
| elif _exists hexdump; then | |||
| hexdump -v -e '/1 ""' -e '/1 " %02x" ""' | |||
| elif _exists xxd; then | |||
| xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " " | |||
| else | |||
| str=$(cat) | |||
| _ascii_hex "$str" | |||
| fi | |||
| } | |||
| #url encode, no-preserved chars | |||
| #A B C D E F G H I J K L M N O P Q R S T U V W X Y Z | |||
| #41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a | |||
| #a b c d e f g h i j k l m n o p q r s t u v w x y z | |||
| #61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a | |||
| #0 1 2 3 4 5 6 7 8 9 - _ . ~ | |||
| #30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e | |||
| #stdin stdout | |||
| _url_encode() { | |||
| _hex_str=$(_hex_dump) | |||
| for _hex_code in $_hex_str; do | |||
| #upper case | |||
| case "${_hex_code}" in | |||
| "41") | |||
| printf "%s" "A" | |||
| ;; | |||
| "42") | |||
| printf "%s" "B" | |||
| ;; | |||
| "43") | |||
| printf "%s" "C" | |||
| ;; | |||
| "44") | |||
| printf "%s" "D" | |||
| ;; | |||
| "45") | |||
| printf "%s" "E" | |||
| ;; | |||
| "46") | |||
| printf "%s" "F" | |||
| ;; | |||
| "47") | |||
| printf "%s" "G" | |||
| ;; | |||
| "48") | |||
| printf "%s" "H" | |||
| ;; | |||
| "49") | |||
| printf "%s" "I" | |||
| ;; | |||
| "4a") | |||
| printf "%s" "J" | |||
| ;; | |||
| "4b") | |||
| printf "%s" "K" | |||
| ;; | |||
| "4c") | |||
| printf "%s" "L" | |||
| ;; | |||
| "4d") | |||
| printf "%s" "M" | |||
| ;; | |||
| "4e") | |||
| printf "%s" "N" | |||
| ;; | |||
| "4f") | |||
| printf "%s" "O" | |||
| ;; | |||
| "50") | |||
| printf "%s" "P" | |||
| ;; | |||
| "51") | |||
| printf "%s" "Q" | |||
| ;; | |||
| "52") | |||
| printf "%s" "R" | |||
| ;; | |||
| "53") | |||
| printf "%s" "S" | |||
| ;; | |||
| "54") | |||
| printf "%s" "T" | |||
| ;; | |||
| "55") | |||
| printf "%s" "U" | |||
| ;; | |||
| "56") | |||
| printf "%s" "V" | |||
| ;; | |||
| "57") | |||
| printf "%s" "W" | |||
| ;; | |||
| "58") | |||
| printf "%s" "X" | |||
| ;; | |||
| "59") | |||
| printf "%s" "Y" | |||
| ;; | |||
| "5a") | |||
| printf "%s" "Z" | |||
| ;; | |||
| #lower case | |||
| "61") | |||
| printf "%s" "a" | |||
| ;; | |||
| "62") | |||
| printf "%s" "b" | |||
| ;; | |||
| "63") | |||
| printf "%s" "c" | |||
| ;; | |||
| "64") | |||
| printf "%s" "d" | |||
| ;; | |||
| "65") | |||
| printf "%s" "e" | |||
| ;; | |||
| "66") | |||
| printf "%s" "f" | |||
| ;; | |||
| "67") | |||
| printf "%s" "g" | |||
| ;; | |||
| "68") | |||
| printf "%s" "h" | |||
| ;; | |||
| "69") | |||
| printf "%s" "i" | |||
| ;; | |||
| "6a") | |||
| printf "%s" "j" | |||
| ;; | |||
| "6b") | |||
| printf "%s" "k" | |||
| ;; | |||
| "6c") | |||
| printf "%s" "l" | |||
| ;; | |||
| "6d") | |||
| printf "%s" "m" | |||
| ;; | |||
| "6e") | |||
| printf "%s" "n" | |||
| ;; | |||
| "6f") | |||
| printf "%s" "o" | |||
| ;; | |||
| "70") | |||
| printf "%s" "p" | |||
| ;; | |||
| "71") | |||
| printf "%s" "q" | |||
| ;; | |||
| "72") | |||
| printf "%s" "r" | |||
| ;; | |||
| "73") | |||
| printf "%s" "s" | |||
| ;; | |||
| "74") | |||
| printf "%s" "t" | |||
| ;; | |||
| "75") | |||
| printf "%s" "u" | |||
| ;; | |||
| "76") | |||
| printf "%s" "v" | |||
| ;; | |||
| "77") | |||
| printf "%s" "w" | |||
| ;; | |||
| "78") | |||
| printf "%s" "x" | |||
| ;; | |||
| "79") | |||
| printf "%s" "y" | |||
| ;; | |||
| "7a") | |||
| printf "%s" "z" | |||
| ;; | |||
| #numbers | |||
| "30") | |||
| printf "%s" "0" | |||
| ;; | |||
| "31") | |||
| printf "%s" "1" | |||
| ;; | |||
| "32") | |||
| printf "%s" "2" | |||
| ;; | |||
| "33") | |||
| printf "%s" "3" | |||
| ;; | |||
| "34") | |||
| printf "%s" "4" | |||
| ;; | |||
| "35") | |||
| printf "%s" "5" | |||
| ;; | |||
| "36") | |||
| printf "%s" "6" | |||
| ;; | |||
| "37") | |||
| printf "%s" "7" | |||
| ;; | |||
| "38") | |||
| printf "%s" "8" | |||
| ;; | |||
| "39") | |||
| printf "%s" "9" | |||
| ;; | |||
| "2d") | |||
| printf "%s" "-" | |||
| ;; | |||
| "5f") | |||
| printf "%s" "_" | |||
| ;; | |||
| "2e") | |||
| printf "%s" "." | |||
| ;; | |||
| "7e") | |||
| printf "%s" "~" | |||
| ;; | |||
| #other hex | |||
| *) | |||
| printf '%%%s' "$_hex_code" | |||
| ;; | |||
| esac | |||
| done | |||
| } | |||
| _exists() { | |||
| cmd="$1" | |||
| if [ -z "$cmd" ]; then | |||
| _usage "Usage: _exists cmd" | |||
| return 1 | |||
| fi | |||
| if eval type type >/dev/null 2>&1; then | |||
| eval type "$cmd" >/dev/null 2>&1 | |||
| elif command >/dev/null 2>&1; then | |||
| command -v "$cmd" >/dev/null 2>&1 | |||
| else | |||
| which "$cmd" >/dev/null 2>&1 | |||
| fi | |||
| ret="$?" | |||
| #echo "Debug3: $cmd exists=$ret" | |||
| return $ret | |||
| } | |||
| _head_n() { | |||
| head -n "$1" | |||
| } | |||
| _mktemp() { | |||
| if _exists mktemp; then | |||
| if mktemp 2>/dev/null; then | |||
| return 0 | |||
| elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then | |||
| #for Mac osx | |||
| return 0 | |||
| fi | |||
| fi | |||
| if [ -d "/tmp" ]; then | |||
| echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" | |||
| return 0 | |||
| elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then | |||
| echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp" | |||
| return 0 | |||
| fi | |||
| _err "Can not create temp file." | |||
| } | |||
| #a + b | |||
| _math() { | |||
| _m_opts="$@" | |||
| printf "%s" "$(($_m_opts))" | |||
| } | |||
| _contains() { | |||
| _str="$1" | |||
| _sub="$2" | |||
| echo "$_str" | grep -- "$_sub" >/dev/null 2>&1 | |||
| } | |||
| ##Now actually do something with that function | |||
| case "$1" in | |||
| add) | |||
| dns_freedns_add $2 $3 | |||
| ;; | |||
| rm) | |||
| dns_freedns_rm $2 $3 | |||
| ;; | |||
| esac | |||
| @ -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 | |||
| @ -0,0 +1,185 @@ | |||
| version: '3' | |||
| services: | |||
| pebble: | |||
| image: letsencrypt/pebble:latest | |||
| # TODO enable -strict | |||
| command: pebble -config /test/config/pebble-config.json -dnsserver 10.30.50.3:8053 | |||
| environment: | |||
| # with Go 1.13.x which defaults TLS 1.3 to on | |||
| GODEBUG: "tls13=1" | |||
| ports: | |||
| - 14000:14000 # HTTPS ACME API | |||
| - 15000:15000 # HTTPS Management API | |||
| networks: | |||
| acmenet: | |||
| ipv4_address: 10.30.50.2 | |||
| challtestsrv: | |||
| image: letsencrypt/pebble-challtestsrv:latest | |||
| command: pebble-challtestsrv -defaultIPv6 "" -defaultIPv4 10.30.50.3 | |||
| ports: | |||
| - 8055:8055 # HTTP Management API | |||
| networks: | |||
| acmenet: | |||
| ipv4_address: 10.30.50.3 | |||
| getssl-alpine: | |||
| build: | |||
| context: . | |||
| dockerfile: test/Dockerfile-alpine | |||
| container_name: getssl-alpine | |||
| volumes: | |||
| - .:/getssl | |||
| environment: | |||
| GETSSL_HOST: alpine.getssl.test | |||
| GETSSL_IP: 10.30.50.10 | |||
| NGINX_CONFIG: /etc/nginx/conf.d/default.conf | |||
| networks: | |||
| acmenet: | |||
| ipv4_address: 10.30.50.10 | |||
| aliases: | |||
| - alpine.getssl.test | |||
| - a.alpine.getssl.test | |||
| - b.alpine.getssl.test | |||
| - c.alpine.getssl.test | |||
| - d.alpine.getssl.test | |||
| - e.alpine.getssl.test | |||
| - f.alpine.getssl.test | |||
| - g.alpine.getssl.test | |||
| - h.alpine.getssl.test | |||
| - i.alpine.getssl.test | |||
| - j.alpine.getssl.test | |||
| - k.alpine.getssl.test | |||
| getssl-centos6: | |||
| build: | |||
| context: . | |||
| dockerfile: test/Dockerfile-centos6 | |||
| container_name: getssl-centos6 | |||
| volumes: | |||
| - .:/getssl | |||
| environment: | |||
| GETSSL_HOST: centos6.getssl.test | |||
| GETSSL_IP: 10.30.50.11 | |||
| NGINX_CONFIG: /etc/nginx/conf.d/default.conf | |||
| networks: | |||
| acmenet: | |||
| ipv4_address: 10.30.50.11 | |||
| aliases: | |||
| - centos6.getssl.test | |||
| - a.centos6.getssl.test | |||
| - b.centos6.getssl.test | |||
| - c.centos6.getssl.test | |||
| - d.centos6.getssl.test | |||
| - e.centos6.getssl.test | |||
| - f.centos6.getssl.test | |||
| - g.centos6.getssl.test | |||
| - h.centos6.getssl.test | |||
| - i.centos6.getssl.test | |||
| - j.centos6.getssl.test | |||
| - k.centos6.getssl.test | |||
| getssl-debian: | |||
| build: | |||
| context: . | |||
| dockerfile: test/Dockerfile-debian | |||
| container_name: getssl-debian | |||
| volumes: | |||
| - .:/getssl | |||
| environment: | |||
| GETSSL_HOST: debian.getssl.test | |||
| GETSSL_IP: 10.30.50.12 | |||
| NGINX_CONFIG: /etc/nginx/sites-enabled/default | |||
| networks: | |||
| acmenet: | |||
| ipv4_address: 10.30.50.12 | |||
| aliases: | |||
| - debian.getssl.test | |||
| - a.debian.getssl.test | |||
| - b.debian.getssl.test | |||
| - c.debian.getssl.test | |||
| - d.debian.getssl.test | |||
| - e.debian.getssl.test | |||
| - f.debian.getssl.test | |||
| - g.debian.getssl.test | |||
| - h.debian.getssl.test | |||
| - i.debian.getssl.test | |||
| - j.debian.getssl.test | |||
| - k.debian.getssl.test | |||
| getssl-ubuntu: | |||
| build: | |||
| context: . | |||
| dockerfile: test/Dockerfile-ubuntu | |||
| container_name: getssl-ubuntu | |||
| volumes: | |||
| - .:/getssl | |||
| environment: | |||
| GETSSL_HOST: ubuntu.getssl.test | |||
| GETSSL_IP: 10.30.50.13 | |||
| NGINX_CONFIG: /etc/nginx/sites-enabled/default | |||
| networks: | |||
| acmenet: | |||
| ipv4_address: 10.30.50.13 | |||
| aliases: | |||
| - ubuntu.getssl.test | |||
| - a.ubuntu.getssl.test | |||
| - b.ubuntu.getssl.test | |||
| - c.ubuntu.getssl.test | |||
| - d.ubuntu.getssl.test | |||
| - e.ubuntu.getssl.test | |||
| - f.ubuntu.getssl.test | |||
| - g.ubuntu.getssl.test | |||
| - h.ubuntu.getssl.test | |||
| - i.ubuntu.getssl.test | |||
| - j.ubuntu.getssl.test | |||
| - k.ubuntu.getssl.test | |||
| getssl-ubuntu18: | |||
| build: | |||
| context: . | |||
| dockerfile: test/Dockerfile-ubuntu18 | |||
| container_name: getssl-ubuntu18 | |||
| volumes: | |||
| - .:/getssl | |||
| environment: | |||
| GETSSL_HOST: ubuntu18.getssl.test | |||
| GETSSL_IP: 10.30.50.14 | |||
| NGINX_CONFIG: /etc/nginx/sites-enabled/default | |||
| networks: | |||
| acmenet: | |||
| ipv4_address: 10.30.50.14 | |||
| aliases: | |||
| - ubuntu18.getssl.test | |||
| - a.ubuntu18.getssl.test | |||
| - b.ubuntu18.getssl.test | |||
| - c.ubuntu18.getssl.test | |||
| - d.ubuntu18.getssl.test | |||
| - e.ubuntu18.getssl.test | |||
| - f.ubuntu18.getssl.test | |||
| - g.ubuntu18.getssl.test | |||
| - h.ubuntu18.getssl.test | |||
| - i.ubuntu18.getssl.test | |||
| - j.ubuntu18.getssl.test | |||
| - k.ubuntu18.getssl.test | |||
| getssl-duckdns: | |||
| build: | |||
| context: . | |||
| dockerfile: test/Dockerfile-ubuntu | |||
| container_name: getssl-duckdns | |||
| volumes: | |||
| - .:/getssl | |||
| environment: | |||
| GETSSL_HOST: getssl.duckdns.org | |||
| GETSSL_IP: 10.30.50.15 | |||
| NGINX_CONFIG: /etc/nginx/sites-enabled/default | |||
| DUCKDNS_TOKEN: $DUCKDNS_TOKEN | |||
| STAGING: "true" | |||
| networks: | |||
| acmenet: | |||
| ipv4_address: 10.30.50.15 | |||
| aliases: | |||
| - getssl.duckdns.org | |||
| networks: | |||
| acmenet: | |||
| driver: bridge | |||
| ipam: | |||
| driver: default | |||
| config: | |||
| - subnet: 10.30.50.0/24 | |||
| @ -0,0 +1,39 @@ | |||
| #! /usr/bin/env bats | |||
| load '/bats-support/load.bash' | |||
| load '/bats-assert/load.bash' | |||
| load '/getssl/test/test_helper.bash' | |||
| # This is run for every test | |||
| setup() { | |||
| export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt | |||
| } | |||
| @test "Create new certificate using HTTP-01 verification" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| CONFIG_FILE="getssl-http01.cfg" | |||
| setup_environment | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| } | |||
| @test "Force renewal of certificate using HTTP-01" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| cleanup_environment | |||
| } | |||
| @ -0,0 +1,40 @@ | |||
| #! /usr/bin/env bats | |||
| load '/bats-support/load.bash' | |||
| load '/bats-assert/load.bash' | |||
| load '/getssl/test/test_helper.bash' | |||
| # This is run for every test | |||
| setup() { | |||
| export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt | |||
| } | |||
| @test "Create new certificate using DNS-01 verification" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| CONFIG_FILE="getssl-dns01.cfg" | |||
| setup_environment | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| } | |||
| @test "Force renewal of certificate using DNS-01" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| cleanup_environment | |||
| } | |||
| @ -0,0 +1,53 @@ | |||
| #! /usr/bin/env bats | |||
| load '/bats-support/load.bash' | |||
| load '/bats-assert/load.bash' | |||
| load '/getssl/test/test_helper.bash' | |||
| # This is run for every test | |||
| setup() { | |||
| export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt | |||
| } | |||
| @test "Create dual certificates using HTTP-01 verification" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| CONFIG_FILE="getssl-http01-dual-rsa-ecdsa.cfg" | |||
| setup_environment | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| } | |||
| @test "Force renewal of dual certificates using HTTP-01" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| } | |||
| @test "Create dual certificates using DNS-01 verification" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| CONFIG_FILE="getssl-dns01-dual-rsa-ecdsa.cfg" | |||
| setup_environment | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| } | |||
| @test "Force renewal of dual certificates using DNS-01" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| cleanup_environment | |||
| } | |||
| @ -0,0 +1,49 @@ | |||
| #! /usr/bin/env bats | |||
| load '/bats-support/load.bash' | |||
| load '/bats-assert/load.bash' | |||
| load '/getssl/test/test_helper.bash' | |||
| # This is run for every test | |||
| setup() { | |||
| export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt | |||
| } | |||
| @test "Create certificates for more than 10 hosts using HTTP-01 verification" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| CONFIG_FILE="getssl-http01-10-hosts.cfg" | |||
| setup_environment | |||
| # Add 11 hosts to DNS (also need to be added as aliases in docker-compose.yml) | |||
| for prefix in a b c d e f g h i j k; do | |||
| curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a | |||
| done | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| } | |||
| @test "Force renewal of more than 10 certificates using HTTP-01" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| # Remove all the dns aliases | |||
| cleanup_environment | |||
| for prefix in a b c d e f g h i j k; do | |||
| curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/del-a | |||
| done | |||
| } | |||
| @ -0,0 +1,53 @@ | |||
| #! /usr/bin/env bats | |||
| load '/bats-support/load.bash' | |||
| load '/bats-assert/load.bash' | |||
| load '/getssl/test/test_helper.bash' | |||
| # This is run for every test | |||
| setup() { | |||
| export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt | |||
| } | |||
| @test "Create new secp384r1 certificate using HTTP-01 verification" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| CONFIG_FILE="getssl-http01-secp384.cfg" | |||
| setup_environment | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| } | |||
| @test "Force renewal of secp384r1 certificate using HTTP-01" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| } | |||
| @test "Create new secp521r1 certificate using HTTP-01 verification" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| CONFIG_FILE="getssl-http01-secp521.cfg" | |||
| setup_environment | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| } | |||
| @test "Force renewal of secp521r1 certificate using HTTP-01" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| } | |||
| @ -0,0 +1,47 @@ | |||
| #! /usr/bin/env bats | |||
| load '/bats-support/load.bash' | |||
| load '/bats-assert/load.bash' | |||
| load '/getssl/test/test_helper.bash' | |||
| # These are run for every test, not once per file | |||
| setup() { | |||
| if [ -z "$STAGING" ]; then | |||
| export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt | |||
| curl --silent -X POST -d '{"host":"'a.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a | |||
| fi | |||
| } | |||
| teardown() { | |||
| if [ -z "$STAGING" ]; then | |||
| curl --silent -X POST -d '{"host":"'a.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/del-a | |||
| fi | |||
| } | |||
| @test "Create dual certificates and copy RSA and ECDSA chain and key to two locations" { | |||
| if [ -n "$STAGING" ]; then | |||
| skip "Using staging server, skipping internal test" | |||
| fi | |||
| CONFIG_FILE="getssl-http01-dual-rsa-ecdsa-2-locations.cfg" | |||
| setup_environment | |||
| mkdir -p /root/a.${GETSSL_HOST} | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| # Check that the RSA chain and key have been copied to both locations | |||
| assert [ -e "/etc/nginx/pki/domain-chain.crt" ] | |||
| assert [ -e "/root/a.${GETSSL_HOST}/domain-chain.crt" ] | |||
| assert [ -e "/etc/nginx/pki/private/server.key" ] | |||
| assert [ -e "/root/a.${GETSSL_HOST}/server.key" ] | |||
| # Check that the ECDSA chain and key have been copied to both locations | |||
| assert [ -e "/etc/nginx/pki/domain-chain.ec.crt" ] | |||
| assert [ -e "/root/a.${GETSSL_HOST}/domain-chain.ec.crt" ] | |||
| assert [ -e "/etc/nginx/pki/private/server.ec.key" ] | |||
| assert [ -e "/root/a.${GETSSL_HOST}/server.ec.key" ] | |||
| } | |||
| @ -0,0 +1,42 @@ | |||
| #! /usr/bin/env bats | |||
| load '/bats-support/load.bash' | |||
| load '/bats-assert/load.bash' | |||
| load '/getssl/test/test_helper.bash' | |||
| # These are run for every test, not once per file | |||
| setup() { | |||
| if [ -n "$STAGING" ]; then | |||
| export GETSSL_HOST=getssl.duckdns.org | |||
| fi | |||
| } | |||
| @test "Create new certificate using staging server and DuckDNS" { | |||
| if [ -z "$STAGING" ]; then | |||
| skip "Running internal tests, skipping external test" | |||
| fi | |||
| CONFIG_FILE="getssl-duckdns01.cfg" | |||
| setup_environment | |||
| init_getssl | |||
| create_certificate | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| } | |||
| @test "Force renewal of certificate using staging server and DuckDNS" { | |||
| if [ -z "$STAGING" ]; then | |||
| skip "Running internal tests, skipping external test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| cleanup_environment | |||
| curl --silent -X POST -d '{"host":"getssl.duckdns.org", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/del-a | |||
| } | |||
| @ -0,0 +1,103 @@ | |||
| #! /usr/bin/env bats | |||
| load '/bats-support/load.bash' | |||
| load '/bats-assert/load.bash' | |||
| load '/getssl/test/test_helper.bash' | |||
| # These are run for every test, not once per file | |||
| setup() { | |||
| if [ -n "$STAGING" ]; then | |||
| export GETSSL_HOST=getssl.duckdns.org | |||
| fi | |||
| } | |||
| @test "Create new certificate using staging server and prime256v1" { | |||
| if [ -z "$STAGING" ]; then | |||
| skip "Running internal tests, skipping external test" | |||
| fi | |||
| CONFIG_FILE="getssl-duckdns01.cfg" | |||
| GETSSL_HOST=getssl.duckdns.org | |||
| setup_environment | |||
| init_getssl | |||
| sed -e 's/rsa/prime256v1/g' < "${CODE_DIR}/test/test-config/${CONFIG_FILE}" > "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg" | |||
| run ${CODE_DIR}/getssl "$GETSSL_HOST" | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| } | |||
| @test "Force renewal of certificate using staging server and prime256v1" { | |||
| if [ -z "$STAGING" ]; then | |||
| skip "Running internal tests, skipping external test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| cleanup_environment | |||
| } | |||
| @test "Create new certificate using staging server and secp384r1" { | |||
| if [ -z "$STAGING" ]; then | |||
| skip "Running internal tests, skipping external test" | |||
| fi | |||
| CONFIG_FILE="getssl-duckdns01.cfg" | |||
| GETSSL_HOST=getssl.duckdns.org | |||
| setup_environment | |||
| init_getssl | |||
| sed -e 's/rsa/secp384r1/g' < "${CODE_DIR}/test/test-config/${CONFIG_FILE}" > "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg" | |||
| run ${CODE_DIR}/getssl "$GETSSL_HOST" | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| } | |||
| @test "Force renewal of certificate using staging server and secp384r1" { | |||
| if [ -z "$STAGING" ]; then | |||
| skip "Running internal tests, skipping external test" | |||
| fi | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| cleanup_environment | |||
| } | |||
| @test "Create new certificate using staging server and secp521r1" { | |||
| skip "The staging server returns 'ECDSA curve P-521 not allowed'" | |||
| CONFIG_FILE="getssl-duckdns01.cfg" | |||
| GETSSL_HOST=getssl.duckdns.org | |||
| setup_environment | |||
| init_getssl | |||
| sed -e 's/rsa/secp521r1/g' < "${CODE_DIR}/test/test-config/${CONFIG_FILE}" > "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg" | |||
| run ${CODE_DIR}/getssl "$GETSSL_HOST" | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| } | |||
| @test "Force renewal of certificate using staging server and secp521r1" { | |||
| skip "The staging server returns 'ECDSA curve P-521 not allowed'" | |||
| run ${CODE_DIR}/getssl -f $GETSSL_HOST | |||
| assert_success | |||
| refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' | |||
| refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' | |||
| refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' | |||
| cleanup_environment | |||
| } | |||
| @ -0,0 +1,22 @@ | |||
| FROM alpine:latest | |||
| # Note this image uses busybox awk instead of gawk | |||
| RUN apk --no-cache add supervisor openssl git curl bind-tools wget nginx bash | |||
| WORKDIR /root | |||
| # Create nginx directories in standard places | |||
| RUN mkdir /run/nginx | |||
| RUN mkdir /etc/nginx/pki | |||
| RUN mkdir /etc/nginx/pki/private | |||
| # BATS (Bash Automated Testings) | |||
| RUN git clone https://github.com/bats-core/bats-core.git /bats-core | |||
| RUN git clone https://github.com/jasonkarns/bats-support /bats-support | |||
| RUN git clone https://github.com/jasonkarns/bats-assert-1 /bats-assert | |||
| RUN /bats-core/install.sh /usr/local | |||
| # Use supervisord to run nginx in the background | |||
| COPY ./test/alpine-supervisord.conf /etc/supervisord.conf | |||
| ENTRYPOINT /usr/bin/supervisord -c /etc/supervisord.conf | |||
| @ -0,0 +1,24 @@ | |||
| FROM centos:centos6 | |||
| # Note this image uses gawk | |||
| # Update and install required software | |||
| RUN yum -y update | |||
| RUN yum -y install epel-release | |||
| RUN yum -y install git curl dnsutils wget nginx | |||
| WORKDIR /root | |||
| RUN mkdir /etc/nginx/pki | |||
| RUN mkdir /etc/nginx/pki/private | |||
| COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf | |||
| # BATS (Bash Automated Testings) | |||
| RUN git clone https://github.com/bats-core/bats-core.git /bats-core | |||
| RUN git clone https://github.com/jasonkarns/bats-support /bats-support | |||
| RUN git clone https://github.com/jasonkarns/bats-assert-1 /bats-assert | |||
| RUN /bats-core/install.sh /usr/local | |||
| EXPOSE 80 443 | |||
| # Run eternal loop - for testing | |||
| CMD tail -f /dev/null | |||
| @ -0,0 +1,20 @@ | |||
| FROM debian:latest | |||
| # Note this image uses mawk 1.3 | |||
| # Update and install required software | |||
| RUN apt-get update --fix-missing | |||
| RUN apt-get install -y git curl dnsutils wget nginx-light | |||
| WORKDIR /root | |||
| RUN mkdir /etc/nginx/pki | |||
| RUN mkdir /etc/nginx/pki/private | |||
| # BATS (Bash Automated Testings) | |||
| RUN git clone https://github.com/bats-core/bats-core.git /bats-core | |||
| RUN git clone https://github.com/jasonkarns/bats-support /bats-support | |||
| RUN git clone https://github.com/jasonkarns/bats-assert-1 /bats-assert | |||
| RUN /bats-core/install.sh /usr/local | |||
| # Run eternal loop - for testing | |||
| CMD tail -f /dev/null | |||
| @ -0,0 +1,23 @@ | |||
| FROM ubuntu:latest | |||
| # Note this image uses mawk1.3 | |||
| # Update and install required software | |||
| RUN apt-get update --fix-missing | |||
| RUN apt-get install -y git curl dnsutils wget nginx-light | |||
| RUN apt-get install -y vim dos2unix # for debugging | |||
| # TODO test with drill, dig, host | |||
| WORKDIR /root | |||
| # Prevent "Can't load /root/.rnd into RNG" error from openssl | |||
| RUN touch /root/.rnd | |||
| # BATS (Bash Automated Testings) | |||
| RUN git clone https://github.com/bats-core/bats-core.git /bats-core | |||
| RUN git clone https://github.com/jasonkarns/bats-support /bats-support | |||
| RUN git clone https://github.com/jasonkarns/bats-assert-1 /bats-assert | |||
| RUN /bats-core/install.sh /usr/local | |||
| # Run eternal loop - for testing | |||
| CMD tail -f /dev/null | |||
| @ -0,0 +1,27 @@ | |||
| FROM ubuntu:bionic | |||
| # bionic = 18 LTS (long term support) | |||
| # Note this image uses gawk | |||
| # Update and install required software | |||
| RUN apt-get update --fix-missing | |||
| RUN apt-get install -y git curl dnsutils wget gawk nginx-light | |||
| WORKDIR /root | |||
| RUN mkdir /etc/nginx/pki | |||
| RUN mkdir /etc/nginx/pki/private | |||
| COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/sites-enabled/default | |||
| # Prevent "Can't load /root/.rnd into RNG" error from openssl | |||
| RUN touch /root/.rnd | |||
| # BATS (Bash Automated Testings) | |||
| RUN git clone https://github.com/bats-core/bats-core.git /bats-core | |||
| RUN git clone https://github.com/jasonkarns/bats-support /bats-support | |||
| RUN git clone https://github.com/jasonkarns/bats-assert-1 /bats-assert | |||
| RUN /bats-core/install.sh /usr/local | |||
| EXPOSE 80 443 | |||
| # Run eternal loop - for testing | |||
| CMD tail -f /dev/null | |||
| @ -0,0 +1,40 @@ | |||
| # Testing | |||
| This directory contains a simple test script which tests creating | |||
| certificates with Pebble (testing version of the LetsEncrypt server) | |||
| Start up pebble, the challdnstest server for DNS challenges | |||
| ```sh | |||
| docker-compose -f "docker-compose.yml" up -d --build | |||
| ``` | |||
| Run the tests | |||
| ```sh | |||
| test/run-all-tests.sh | |||
| ``` | |||
| Run individual test | |||
| ```sh | |||
| docker exec -it getssl bats /getssl/test/<filename.bats> | |||
| ``` | |||
| Debug (uses helper script to set `CURL_CA_BUNDLE` as pebble uses a local certificate, | |||
| otherwise you get a "unknown API version" error) | |||
| ```sh | |||
| docker exec -it getssl-<os> /getssl/test/debug-test.sh <config-file>` | |||
| eg. | |||
| ```sh | |||
| docker exec -it getssl-ubuntu18 /getssl/test/debug-test.sh getssl-http01.cfg | |||
| ``` | |||
| ## TODO | |||
| 1. Test wildcards | |||
| 2. Test SSH, SFTP, SCP | |||
| 3. Test change of key algorithm | |||
| @ -0,0 +1,14 @@ | |||
| [supervisord] | |||
| nodaemon=true | |||
| logfile=/tmp/supervisord.log | |||
| childlogdir=/tmp | |||
| pidfile = /tmp/supervisord.pid | |||
| [program:nginx] | |||
| command=nginx -g 'daemon off;' | |||
| stdout_logfile=/dev/stdout | |||
| stdout_logfile_maxbytes=0 | |||
| stderr_logfile=/dev/stderr | |||
| stderr_logfile_maxbytes=0 | |||
| autorestart=false | |||
| startretries=0 | |||
| @ -0,0 +1,30 @@ | |||
| #!/usr/bin/env bash | |||
| # This runs getssl outside of the BATS framework for debugging, etc, against pebble | |||
| # Usage: /getssl/test/debug-test.sh getssl-http01.cfg | |||
| DEBUG="" | |||
| if [ $# -eq 2 ]; then | |||
| DEBUG=$1 | |||
| shift | |||
| fi | |||
| CONFIG_FILE=$1 | |||
| if [ ! -e "$CONFIG_FILE" ]; then | |||
| CONFIG_FILE=${CODE_DIR}/test/test-config/${CONFIG_FILE} | |||
| fi | |||
| #shellcheck disable=SC1091 | |||
| source /getssl/test/test_helper.bash | |||
| setup_environment 3>&1 | |||
| # Only add the pebble CA to the cert bundle if using pebble | |||
| if [ "$(grep -q pebble "${CONFIG_FILE}")" = 0 ]; then | |||
| export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt | |||
| fi | |||
| "${CODE_DIR}/getssl" -c "$GETSSL_HOST" 3>&1 | |||
| cp "${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg" | |||
| # shellcheck disable=SC2086 | |||
| "${CODE_DIR}/getssl" ${DEBUG} -f "$GETSSL_HOST" 3>&1 | |||
| @ -0,0 +1,8 @@ | |||
| #!/usr/bin/env bash | |||
| if [ "$GETSSL_HOST" = "alpine.getssl.test" ]; then | |||
| killall -HUP nginx >&3- | |||
| sleep 5 | |||
| else | |||
| service nginx restart >&3- | |||
| fi | |||
| @ -0,0 +1,6 @@ | |||
| docker exec -it getssl-alpine bats /getssl/test | |||
| docker exec -it getssl-centos6 bats /getssl/test | |||
| docker exec -it getssl-debian bats /getssl/test | |||
| docker exec -it getssl-ubuntu bats /getssl/test | |||
| docker exec -it getssl-ubuntu18 bats /getssl/test | |||
| docker exec -it getssl-duckdns bats /getssl/test | |||
| @ -0,0 +1,8 @@ | |||
| #!/usr/bin/env bash | |||
| docker exec -it getssl-alpine bats /getssl/test | |||
| docker exec -it getssl-centos6 bats /getssl/test | |||
| docker exec -it getssl-debian bats /getssl/test | |||
| docker exec -it getssl-ubuntu bats /getssl/test | |||
| docker exec -it getssl-ubuntu18 bats /getssl/test | |||
| docker exec -it getssl-duckdns bats /getssl/test | |||
| @ -0,0 +1,37 @@ | |||
| # Uncomment and modify any variables you need | |||
| # see https://github.com/srvrco/getssl/wiki/Config-variables for details | |||
| # see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs | |||
| # | |||
| CA="https://pebble:14000/dir" | |||
| VALIDATE_VIA_DNS=true | |||
| DNS_ADD_COMMAND="/getssl/dns_scripts/dns_add_challtestsrv" | |||
| DNS_DEL_COMMAND="/getssl/dns_scripts/dns_del_challtestsrv" | |||
| DUAL_RSA_ECDSA="true" | |||
| ACCOUNT_KEY_TYPE="prime256v1" | |||
| PRIVATE_KEY_ALG="prime256v1" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="" | |||
| # Acme Challenge Location. The first line for the domain, the following ones for each additional domain. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| #Set USE_SINGLE_ACL="true" to use a single ACL for all checks | |||
| USE_SINGLE_ACL="false" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| # or using ssh /sftp as for the ACL | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,33 @@ | |||
| # Uncomment and modify any variables you need | |||
| # see https://github.com/srvrco/getssl/wiki/Config-variables for details | |||
| # see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs | |||
| # | |||
| CA="https://pebble:14000/dir" | |||
| VALIDATE_VIA_DNS=true | |||
| DNS_ADD_COMMAND="/getssl/dns_scripts/dns_add_challtestsrv" | |||
| DNS_DEL_COMMAND="/getssl/dns_scripts/dns_del_challtestsrv" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="" | |||
| # Acme Challenge Location. The first line for the domain, the following ones for each additional domain. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| #Set USE_SINGLE_ACL="true" to use a single ACL for all checks | |||
| USE_SINGLE_ACL="false" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| # or using ssh /sftp as for the ACL | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,37 @@ | |||
| # Test that the script works with external dns provider and staging server | |||
| # | |||
| CA="https://acme-staging-v02.api.letsencrypt.org/directory" | |||
| VALIDATE_VIA_DNS=true | |||
| DNS_ADD_COMMAND="/getssl/dns_scripts/dns_add_duckdns" | |||
| DNS_DEL_COMMAND="/getssl/dns_scripts/dns_del_duckdns" | |||
| AUTH_DNS_SERVER=1.1.1.1 | |||
| CHECK_ALL_AUTH_DNS=false | |||
| DNS_EXTRA_WAIT=20 | |||
| ACCOUNT_KEY_TYPE="rsa" | |||
| PRIVATE_KEY_ALG="rsa" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="" | |||
| # Acme Challenge Location. The first line for the domain, the following ones for each additional domain. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| #Set USE_SINGLE_ACL="true" to use a single ACL for all checks | |||
| USE_SINGLE_ACL="false" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| # or using ssh /sftp as for the ACL | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed (using a custom port) | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,28 @@ | |||
| # Uncomment and modify any variables you need | |||
| # see https://github.com/srvrco/getssl/wiki/Config-variables for details | |||
| # see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs | |||
| CA="https://pebble:14000/dir" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="a.${GETSSL_HOST},b.${GETSSL_HOST},c.${GETSSL_HOST},d.${GETSSL_HOST},e.${GETSSL_HOST},f.${GETSSL_HOST},g.${GETSSL_HOST},h.${GETSSL_HOST},i.${GETSSL_HOST},j.${GETSSL_HOST},k.${GETSSL_HOST}" | |||
| # Acme Challenge Location. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| # Use a single ACL for all checks | |||
| USE_SINGLE_ACL="true" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,32 @@ | |||
| # Test that more than one location can be specified for CERT and KEY locations and that the | |||
| # files are copied to both locations when both RSA and ECDSA certificates are created | |||
| # | |||
| CA="https://pebble:14000/dir" | |||
| DUAL_RSA_ECDSA="true" | |||
| ACCOUNT_KEY_TYPE="prime256v1" | |||
| PRIVATE_KEY_ALG="prime256v1" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="a.${GETSSL_HOST}" | |||
| # Acme Challenge Location. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| #Set USE_SINGLE_ACL="true" to use a single ACL for all checks | |||
| USE_SINGLE_ACL="true" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| # or using ssh /sftp as for the ACL | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key;/root/a.${GETSSL_HOST}/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="/etc/nginx/pki/domain-chain.crt;/root/a.${GETSSL_HOST}/domain-chain.crt" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,33 @@ | |||
| # Uncomment and modify any variables you need | |||
| # see https://github.com/srvrco/getssl/wiki/Config-variables for details | |||
| # see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs | |||
| # | |||
| CA="https://pebble:14000/dir" | |||
| DUAL_RSA_ECDSA="true" | |||
| ACCOUNT_KEY_TYPE="prime256v1" | |||
| PRIVATE_KEY_ALG="prime256v1" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="" | |||
| # Acme Challenge Location. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| #Set USE_SINGLE_ACL="true" to use a single ACL for all checks | |||
| USE_SINGLE_ACL="false" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| # or using ssh /sftp as for the ACL | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,32 @@ | |||
| # Uncomment and modify any variables you need | |||
| # see https://github.com/srvrco/getssl/wiki/Config-variables for details | |||
| # see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs | |||
| # | |||
| CA="https://pebble:14000/dir" | |||
| ACCOUNT_KEY_TYPE="secp384r1" | |||
| PRIVATE_KEY_ALG="secp384r1" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="" | |||
| # Acme Challenge Location. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| #Set USE_SINGLE_ACL="true" to use a single ACL for all checks | |||
| USE_SINGLE_ACL="false" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| # or using ssh /sftp as for the ACL | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,32 @@ | |||
| # Uncomment and modify any variables you need | |||
| # see https://github.com/srvrco/getssl/wiki/Config-variables for details | |||
| # see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs | |||
| # | |||
| CA="https://pebble:14000/dir" | |||
| ACCOUNT_KEY_TYPE="secp521r1" | |||
| PRIVATE_KEY_ALG="secp521r1" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="" | |||
| # Acme Challenge Location. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| #Set USE_SINGLE_ACL="true" to use a single ACL for all checks | |||
| USE_SINGLE_ACL="false" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| # or using ssh /sftp as for the ACL | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,29 @@ | |||
| # Uncomment and modify any variables you need | |||
| # see https://github.com/srvrco/getssl/wiki/Config-variables for details | |||
| # see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs | |||
| # | |||
| CA="https://pebble:14000/dir" | |||
| # Additional domains - this could be multiple domains / subdomains in a comma separated list | |||
| SANS="" | |||
| # Acme Challenge Location. | |||
| ACL=('/var/www/html/.well-known/acme-challenge') | |||
| #Set USE_SINGLE_ACL="true" to use a single ACL for all checks | |||
| USE_SINGLE_ACL="false" | |||
| # Location for all your certs, these can either be on the server (full path name) | |||
| # or using ssh /sftp as for the ACL | |||
| DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt" | |||
| DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key" | |||
| CA_CERT_LOCATION="/etc/nginx/pki/chain.crt" | |||
| DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert | |||
| DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert | |||
| # The command needed to reload apache / nginx or whatever you use | |||
| RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl ${NGINX_CONFIG} && /getssl/test/restart-nginx" | |||
| # Define the server type and confirm correct certificate is installed | |||
| SERVER_TYPE="https" | |||
| CHECK_REMOTE="true" | |||
| @ -0,0 +1,30 @@ | |||
| # Default server configuration | |||
| # | |||
| server { | |||
| listen 80 default_server; | |||
| listen 5002 default_server; | |||
| listen [::]:5002 default_server; | |||
| # SSL configuration | |||
| # | |||
| listen 443 default_server; | |||
| listen [::]:443 default_server; | |||
| listen 5001 default_server; | |||
| listen [::]:5001 default_server; | |||
| root /var/www/html; | |||
| # Add index.php to the list if you are using PHP | |||
| index index.html index.htm index.nginx-debian.html; | |||
| server_name _; | |||
| # ssl_certificate /etc/nginx/pki/server.crt; | |||
| # ssl_certificate_key /etc/nginx/pki/private/server.key; | |||
| location / { | |||
| # First attempt to serve request as file, then | |||
| # as directory, then fall back to displaying a 404. | |||
| try_files $uri $uri/ =404; | |||
| } | |||
| } | |||
| @ -0,0 +1,92 @@ | |||
| ## | |||
| # You should look at the following URL's in order to grasp a solid understanding | |||
| # of Nginx configuration files in order to fully unleash the power of Nginx. | |||
| # http://wiki.nginx.org/Pitfalls | |||
| # http://wiki.nginx.org/QuickStart | |||
| # http://wiki.nginx.org/Configuration | |||
| # | |||
| # Generally, you will want to move this file somewhere, and start with a clean | |||
| # file but keep this around for reference. Or just disable in sites-enabled. | |||
| # | |||
| # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. | |||
| ## | |||
| # Default server configuration | |||
| # | |||
| server { | |||
| listen 80 default_server; | |||
| listen 5002 default_server; | |||
| listen [::]:5002 default_server; | |||
| # SSL configuration | |||
| # | |||
| listen 443 ssl default_server; | |||
| listen [::]:443 ssl default_server; | |||
| listen 5001 ssl default_server; | |||
| listen [::]:5001 ssl default_server; | |||
| # | |||
| # Note: You should disable gzip for SSL traffic. | |||
| # See: https://bugs.debian.org/773332 | |||
| # | |||
| # Read up on ssl_ciphers to ensure a secure configuration. | |||
| # See: https://bugs.debian.org/765782 | |||
| # | |||
| # Self signed certs generated by the ssl-cert package | |||
| # Don't use them in a production server! | |||
| # | |||
| # include snippets/snakeoil.conf; | |||
| root /var/www/html; | |||
| # Add index.php to the list if you are using PHP | |||
| index index.html index.htm index.nginx-debian.html; | |||
| server_name _; | |||
| ssl_certificate /etc/nginx/pki/server.crt; | |||
| ssl_certificate_key /etc/nginx/pki/private/server.key; | |||
| location / { | |||
| # First attempt to serve request as file, then | |||
| # as directory, then fall back to displaying a 404. | |||
| try_files $uri $uri/ =404; | |||
| } | |||
| # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 | |||
| # | |||
| #location ~ \.php$ { | |||
| # include snippets/fastcgi-php.conf; | |||
| # | |||
| # # With php7.0-cgi alone: | |||
| # fastcgi_pass 127.0.0.1:9000; | |||
| # # With php7.0-fpm: | |||
| # fastcgi_pass unix:/run/php/php7.0-fpm.sock; | |||
| #} | |||
| # deny access to .htaccess files, if Apache's document root | |||
| # concurs with nginx's one | |||
| # | |||
| #location ~ /\.ht { | |||
| # deny all; | |||
| #} | |||
| } | |||
| # Virtual Host configuration for example.com | |||
| # | |||
| # You can move that to a different file under sites-available/ and symlink that | |||
| # to sites-enabled/ to enable it. | |||
| # | |||
| #server { | |||
| # listen 80; | |||
| # listen [::]:80; | |||
| # | |||
| # server_name example.com; | |||
| # | |||
| # root /var/www/example.com; | |||
| # index index.html; | |||
| # | |||
| # location / { | |||
| # try_files $uri $uri/ =404; | |||
| # } | |||
| #} | |||
| @ -0,0 +1,43 @@ | |||
| INSTALL_DIR=/root | |||
| CODE_DIR=/getssl | |||
| setup_environment() { | |||
| # One-off test setup | |||
| if [[ -d ${INSTALL_DIR}/.getssl ]]; then | |||
| rm -r ${INSTALL_DIR}/.getssl | |||
| fi | |||
| if [ ! -f ${INSTALL_DIR}/pebble.minica.pem ]; then | |||
| wget --quiet --no-clobber https://raw.githubusercontent.com/letsencrypt/pebble/master/test/certs/pebble.minica.pem 2>&1 | |||
| CERT_FILE=/etc/ssl/certs/ca-certificates.crt | |||
| if [ ! -f $CERT_FILE ]; then | |||
| CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt | |||
| fi | |||
| cat $CERT_FILE ${INSTALL_DIR}/pebble.minica.pem > ${INSTALL_DIR}/pebble-ca-bundle.crt | |||
| fi | |||
| curl --silent -X POST -d '{"host":"'"$GETSSL_HOST"'", "addresses":["'"$GETSSL_IP"'"]}' http://10.30.50.3:8055/add-a | |||
| cp ${CODE_DIR}/test/test-config/nginx-ubuntu-no-ssl "${NGINX_CONFIG}" | |||
| /getssl/test/restart-nginx | |||
| } | |||
| cleanup_environment() { | |||
| curl --silent -X POST -d '{"host":"'"$GETSSL_HOST"'", "addresses":["'"$GETSSL_IP"'"]}' http://10.30.50.3:8055/del-a | |||
| } | |||
| init_getssl() { | |||
| # Run initialisation (create account key, etc) | |||
| run ${CODE_DIR}/getssl -c "$GETSSL_HOST" | |||
| assert_success | |||
| [ -d "$INSTALL_DIR/.getssl" ] | |||
| } | |||
| create_certificate() { | |||
| # Create certificate | |||
| cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg" | |||
| run ${CODE_DIR}/getssl "$GETSSL_HOST" | |||
| } | |||