diff --git a/README.md b/README.md index 1e3b563..730be22 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,7 @@ converts one font type to another with fontforge, (just an alias posing as a bas using lets encrypt, allows checking and renewal of lets encrypt certificates. usefull for cron jobs this uses certbot with webroot, so make sure to have DOMAIN/.well-known/acme-challenge pointed to /var/www/html/.well-known/acme-challenge on your system + +#### cfdns + +allows creation or updating of existing cloudflare dns records diff --git a/cfdns b/cfdns new file mode 100755 index 0000000..2476ad0 --- /dev/null +++ b/cfdns @@ -0,0 +1,233 @@ +#!/usr/bin/env bash + +quiet=0 # should i shut up?!?!? :< + +token="" # the api token +domain="" # the domain to update + +record="A" # the record type +ttl="60" # the new time to live +content="" # the new record content + +usage() { + printf "usage: cfdns [-hq] [-d DOMAIN] [-t TOKEN] [-r RECORD] [-l TTL] [-cC CONTENT]\n\n" + printf "\t-h\t\tshow the help message\n" + printf "\t-q\t\tquiet output\n" + printf "\t-d DOMAIN\tthe domain name to update\n" + printf "\t-t TOKEN\tthe api token\n" + printf "\t-r RECORD\tthe new record type\n" + printf "\t-l TTL\t\tthe new time to live\n" + printf "\t-c CONTENT\tthe new contents of the record\n" + printf "\t-C RAW CONTENT\tthe new conents of the record (as raw json)\n" +} + +chk_command() { + if ! command -v "$1" > /dev/null; then + >&2 echo "error: command '$1' could not be found" + exit 1 + fi +} + +chk_command "getopts" +chk_command "curl" +chk_command "jq" + +while getopts "hqd:t:r:l:c:C:" arg > /dev/null; do + case $arg in + h) + usage + exit 0 + ;; + q) + quiet=1 + ;; + d) + domain="${OPTARG}" + ;; + t) + token="${OPTARG}" + ;; + r) + record="${OPTARG}" + ;; + l) + ttl="${OPTARG}" + ;; + c) + content="\"content\": \"${OPTARG}\"" + ;; + C) + content="${OPTARG}" + ;; + ?) + exit 1 + ;; + esac +done + +if [ ! "$cert" = "cert.pem" ] && [ "$key" = "cert.key" ]; then + name=${cert%.*} + key="$name.key" +fi + +log() { + if [ $quiet = 0 ]; then + printf "$*\n" 1>&2 + fi +} + +step() { + if [ $quiet = 0 ]; then + printf "\033[32m>>> \033[0m$*\n" 1>&2 + fi +} + +error() { + printf "\033[31merror: \033[0m$*\n" > /dev/stderr +} + +die() { + kill $$ +} + +handle_error() { + errs="$1" + count="$(echo $errs | jq -r ". | length")" + for i in $(seq 0 $(($count - 1))); do + err="$(echo $errs | jq -r ".[$i]")" + error "$(echo $err | jq -r '.message')" + chain="$(echo $err | jq -r '.error_chain')" + if ! [ "$chain" = "null" ]; then + count="$(echo $chain | jq -r ". | length")" + for j in $(seq 0 $(($count - 1))); do + error "$(echo $chain | jq -r ".[$j].message")" + done + fi + done +} + +_curl() { + RESPONSE=$(curl --silent --request $1 \ + --url "https://api.cloudflare.com/client/v4$2" \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $token" \ + --data "$3") + SUCCESS=$(echo $RESPONSE | jq -r ".success") + if [ "$SUCCESS" != "true" ]; then + errs="$(echo $RESPONSE | jq -r .errors)" + handle_error "$errs" + die + fi + + echo $RESPONSE | jq ".result" +} + +patch() { + _curl "PATCH" "$1" "$2" +} + +post() { + _curl "POST" "$1" "$2" +} + +get() { + _curl "GET" "$1" "" +} + +# Step 1: get the zone the domain is in +zone=$(echo "$domain" | awk -F'.' '{print $(NF-1)"."$(NF);}' 2>/dev/null) + +if [ "$zone" = "" ]; then + error "invalid domain: '$domain'" + die +fi + +step "fetching zones..." +zones=$(get "/zones") +zone_id="null" + +i=0 +while true; do + json="$(echo "$zones" | jq ".[$i]")" + + if [ "$json" == "null" ]; then + break + fi + + name="$(echo "$json" | jq -r ".name")" + id="$(echo "$json" | jq -r ".id")" + + log "found zone: $name ($id)" + + if [ "$name" == "$zone" ]; then + zone_id="$id" + break + fi + + ((i=i+1)) +done + +if [ "$zone_id" == "null" ]; then + error "could not find zone: $zone" + die +fi + +# Step 2: get the current record id if it exists +step "fetching records..." + +records="$(get "/zones/$zone_id/dns_records")" +current="null" + +i=0 +while true; do + + _record="$(echo "$records" | jq ".[$i]")" + + if [ "$_record" == "null" ]; then + break + fi + + name="$(echo "$_record" | jq -r ".name")" + type="$(echo "$_record" | jq -r ".type")" + _content="$(echo "$_record" | jq -r ".name")" + id="$(echo "$_record" | jq -r ".id")" + + log "found record: $name $type \"$_content\" ($id)" + + if [ "$name" == "$domain" ] && [ "$record" = "$type" ]; then + current="$id" + break + fi + + ((i=i+1)) +done + +# Step 3: update record +step "updating record" + +update() { + patch "/zones/$zone_id/dns_records/$1" "$2" +} + +create() { + post "/zones/$zone_id/dns_records" "$1" +} + +json="{ + \"name\": \"$domain\", + \"proxied\": false, + \"type\": \"$record\", + $content +}" + +log $(echo "$json" | jq -C) + +if [ "$current" == "null" ]; then + log "no record found... creating new one" + create "$json" +else + log "record found... updating" + update "$current" "$json" +fi + +step "successfully updated record" diff --git a/recert b/recert old mode 100644 new mode 100755