#!/usr/bin/env sh


# define variables

# enable proxychains?
proxychains=false

# wait for this many seconds before trying certificate issuance/renewal
wait_before_renew=30

# bridge46 provider ipv4 address
bridge46_ipv4="207.127.103.198"

# mesh domain provider
provider="mesh.cat"

# whoami service
whoami_domain="ygg.mesh.cat"
whoami_url="https://$whoami_domain/whoami"

# mesh domain provider alternative dns port for acme challenge and bridge46 A records
alternative_dns_port="53536"

# acme challenge dnsmasq instance port
acme_challenge_port="53537"

# either letsencrypt or zerossl
tls_provider="zerossl"
# either letsencrypt.org or sectigo.com
tls_provider_domain="sectigo.com"

# temporary working directory
twd="/tmp"


# internal function to check if a command exists
_exists() {
  cmd="$1"
  if [ -z "$cmd" ] ; then
    echo "Usage: _exists cmd"
    return 1
  fi
  if type command >/dev/null 2>&1 ; then
    command -v $cmd >/dev/null 2>&1
  else
    type $cmd >/dev/null 2>&1
  fi
  ret="$?"
  return $ret
}

# check if we got wget/curl
_get=""
_get_is=""
if _exists curl && [ "${ACME_USE_WGET:-0}" = "0" ]; then
  _get="curl --noproxy $whoami_domain -s -L"
  _get_is="curl"
elif _exists wget ; then
  _get="wget --no-proxy -O -"
  _get_is="wget"
else
  echo "Sorry, you must have curl or wget installed first."
  echo "Please install either of them and try again."
  exit 1
fi

# start
echo Starting...

# check if we got dnsmasq
if _exists dnsmasq --help ; then
  echo "dnsmasq is available."
else
  echo "Sorry, you must have dnsmasq installed first."
  echo "Please install dnsmasq and try again."
  exit 1
fi

# get my domain
domain=`$_get "$whoami_url"`
if [ $? -ne 0 ]; then
  echo "Error: could not fetch my domain."
  exit 1
fi
my_ygg_ip=`$_get "$whoami_url?ip=true"`
if [ $? -ne 0 ]; then
  echo "Error: could not fetch my yggdrasil ip address."
  exit 1
fi
provider_regex=`echo "$provider" | sed 's/\./\\\./g'`
domain_regex="^[a-zA-Z0-9]+\\.$provider_regex$"
echo $domain_regexp
if echo "$domain" | grep -qE "$domain_regex"; then
  echo "Got domain: $domain"
else
  echo "Error: Received string does not match the expected format."
  exit 1
fi

# define acme.sh's url
if [ -z "$BRANCH" ]; then
  BRANCH="master"
fi
_url="https://raw.githubusercontent.com/acmesh-official/acme.sh/$BRANCH/acme.sh"

# if acme.sh does not exist install it
if [ ! -e "$HOME/.acme.sh/acme.sh" ]; then
  cd $twd
  $_get "$_url" | sh -s -- --install-online --nocron
fi

# define acme.sh command
acme_cmd="$HOME/.acme.sh/acme.sh --log"
if [ "$proxychains" = true ] ; then
  if _exists proxychains ; then
    acme_cmd="proxychains -q $acme_cmd"
  else
    echo "Error: proxychains enabled but not found."
    exit 1
  fi
fi

# register zerossl account
if [ $tls_provider == "zerossl" ] ; then
  $acme_cmd \
    --register-account \
    -m admin@$domain \
    --server zerossl
fi

# get challenge
timestamp=`date +"%Y%m%d%H%M%S"`
long_flag="--yes-I-know-dns-manual-mode-enough-go-ahead-please"
challenge_file=$twd/acme_challenge.$timestamp.txt
$acme_cmd --issue --server $tls_provider \
  -d "$domain" \
  --dns $long_flag \
  > $challenge_file
cat $challenge_file
echo ""

# extract TXT value
txt_value=`cat $challenge_file | grep 'TXT' | sed -n "s/.*\x27\(.*\)\x27$/\1/p"`
rm $challenge_file
if [ $txt_value != "" ] ; then
  echo TXT value is $txt_value
  echo ""
else
  echo "Error: could not get an acme challenge TXT string."
  exit 1
fi

# prepare to launche dnsmasq
tmp_conf_file=$twd/dnsmasq.$USER.tmp.cnf

# clean dnsmasq processes
for p in `ps | grep dnsmasq.*.tmp.cnf | grep -v grep | awk '{print $1}'` ; do
  kill $p ;
done

# launch acme challenge dnsmasq process
touch $tmp_conf_file \
  && dnsmasq \
    --conf-file=$tmp_conf_file \
    -k -d -D -b -R -n -N -h -q \
    -p $acme_challenge_port \
    --txt-record="_acme-challenge.$domain,$txt_value" \
    1>&- 2>&- &
acme_dnsmasq_pid=$!
sleep 3
if [ "`ps aux | grep dnsmasq | grep $acme_dnsmasq_pid`" != "" ]; then
  echo acme dnsmasq PID: $acme_dnsmasq_pid
  echo ""
else
  echo "Error: could not start a dnsmasq process for the acme challenge."
  exit 1
fi

# launch main dnsmasq process
touch $tmp_conf_file \
  && dnsmasq \
    --conf-file=$tmp_conf_file \
    -k -d -D -b -R -n -N -h -q \
    -p $alternative_dns_port \
    --address="/$domain/$my_ygg_ip" \
    --address="/$domain/$bridge46_ipv4" \
    --caa-record=$domain,0,issue,$tls_provider_domain \
    --server="/_acme-challenge.$domain/127.0.0.1#$acme_challenge_port" \
    1>&- 2>&- &
main_dnsmasq_pid=$!
sleep 3
if [ "`ps aux | grep dnsmasq | grep $main_dnsmasq_pid`" != "" ]; then
  echo main dnsmasq PID: $main_dnsmasq_pid
  echo ""
fi

echo "Waiting for $wait_before_renew seconds."
sleep $wait_before_renew

# issue certificate
export MAX_RETRY_TIMES=40
$acme_cmd --renew --server $tls_provider \
  -d "$domain" \
  --dns $long_flag
acme_renew_state=$?

rm $tmp_conf_file

echo ""
if [ $acme_renew_state == "0" ]; then
  echo "Job finished."
  echo "Remember to create a cron job to run this script once a week."
  exit 0
else
  echo "Something when wrong when trying to get/renew the certificate."
  exit $acme_renew_state
fi