#!/usr/bin/bash


setDnfConf() {
  local DNF_CONF="/etc/dnf/dnf.conf"
  local BEGIN_MARK="# BEGIN RetroGrid"
  local END_MARK="#END RetroGrid"
  local tmpfile

  [ -f "$DNF_CONF" ] || { echo "FAIL: $DNF_CONF not found" >&2; return 1; }

  tmpfile=$(mktemp "${DNF_CONF}.XXXXXX") || { echo "FAIL: mktemp failed" >&2; return 1; }

  # Strip any existing RetroGrid block (idempotency: remove old copy before
  # appending a fresh one, so repeated runs don't stack duplicate blocks).
  # sed range-delete between the two exact marker lines, inclusive.
  sed "/^${BEGIN_MARK}\$/,/^${END_MARK}\$/d" "$DNF_CONF" > "$tmpfile"

  # Check to ensure that there isn't already a proxy setting in use.
  local proxy=$(/usr/bin/grep -e '^proxy=' "$tmpfile");
  if [ "$proxy" != "" ] ; then
    echo "This host already uses a proxy setting. Daisy-chaining proxies";
    echo "requires manual configuration and testing. We'd like to support";
    echo "this better. Contact support@retrogrid.io";
    exit 1;
  fi;

  if [ ! -s "$tmpfile" ] && [ -s "$DNF_CONF" ]; then
    echo "FAIL: stripped output is empty but source wasn't; aborting to avoid data loss" >&2
    rm -f "$tmpfile"
    return 1
  fi

  # Ensure exactly one trailing newline before appending, so the block
  # doesn't get glued onto the last existing line.
  if [ -s "$tmpfile" ] && [ "$(tail -c1 "$tmpfile")" != "" ]; then
    echo >> "$tmpfile"
  fi

  # Write the config change to dns.conf
  {
    echo "$BEGIN_MARK"
    echo "proxy=https://proxy.retrogrid.io:5444"
    echo "proxy_sslcacert=/etc/pki/retrogrid/ca.crt"
    echo "proxy_sslclientcert=/etc/pki/retrogrid/client.crt"
    echo "proxy_sslclientkey=/etc/pki/retrogrid/client.key"
    echo "sslcacert=/etc/pki/retrogrid/ca.crt"
    echo "$END_MARK"
  } >> "$tmpfile"

  # Preserve original ownership/permissions rather than letting mktemp's
  # defaults (0600, current user) silently change dnf.conf's mode.
  chmod --reference="$DNF_CONF" "$tmpfile" 2>/dev/null
  chown --reference="$DNF_CONF" "$tmpfile" 2>/dev/null

  mv -f "$tmpfile" "$DNF_CONF"
};



### BEGIN Execution ###


. /usr/lib/retrogrid/functions.common.sh
pass "Start registration";

# parse additional arguments
SEND=false;
REFRESH=false;
for i in "$@"; do
	case "$i" in
		SEND)
			SEND=true;
			;;
		REFRESH)
			REFRESH='true'
			;;
	esac
done;

# During fast development: send home client work if configured to do so.
if [ $SEND = false ] ; then
	:;
else
	if [ ! -f /root/.ssh/lab ] ; then
		echo "missing /root/.ssh/lab";
	elif [ ! -f /root/.ssh/id_rsa.pub ] ; then
		echo "No id_rsa.pub";
	else
		echo "Sending home present state";
		[[ /usr/bin/retrogrid-register -nt /tmp/sent.retrogrid ]] && \
			scp -pP 59595 /usr/bin/retrogrid-register rg@lab.effortlessis.com:/home/rgdev/build/usr/bin/.
		[[ /usr/bin/retrogrid-diagnose.sh -nt /tmp/sent.retrogrid ]] && \
			scp -pP 59595 /usr/bin/retrogrid-diagnose.sh rg@lab.effortlessis.com:/home/rgdev/build/usr/bin/.
		[[ /usr/lib/retrogrid/functions.common.sh -nt /tmp/sent.retrogrid ]] && \
			scp -pP 59595 /usr/lib/retrogrid/functions.common.sh rg@lab.effortlessis.com:/home/rgdev/build/usr/lib/retrogrid/.
		[[ /usr/bin/retrogrid-get-day -nt /tmp/sent.retrogrid ]] && \
			scp -pP 59595 /usr/bin/retrogrid-get-day rg@lab.effortlessis.com:/home/rgdev/build/usr/bin/.
		[[ /usr/bin/retrogrid-set-day -nt /tmp/sent.retrogrid ]] && \
			scp -pP 59595 /usr/bin/retrogrid-set-day rg@lab.effortlessis.com:/home/rgdev/build/usr/bin/.
		[[ /etc/dnf/plugins/retrogrid_dun.conf -nt /tmp/sent.retrogrid ]] && \
			scp -pP 59595 /etc/dnf/plugins/retrogrid_dun.conf rg@lab.effortlessis.com:/home/rgdev/build/etc/dnf/plugins/.
		[[ /usr/lib/python3.9/site-packages/dnf-plugins/retrogrid_dun.py -nt /tmp/sent.retrogrid ]] && \
			scp -pP 59595 /usr/lib/python3.9/site-packages/dnf-plugins/retrogrid_dun.py \
			rg@lab.effortlessis.com:/home/rgdev/build/usr/share/retrogrid/dnf-plugins/.
		touch /tmp/sent.retrogrid;
	fi;
	echo "Sent";
	exit 100;
fi;


if [ "$1" = "" ] ; then
	echo "USAGE:";
	echo "regtrogrid-register <Registration UUID> [refresh]";
	echo "You must specify the registration UUID as the first argument.";
	exit 1;
fi;

pass "Usage correct";

if [[ "$1" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ ]]; then
    echo "UUID V4 format check passed.";
else
    echo "Invalid UUID V4 format."
		exit 1;
fi

pass "Valid UUIDv4 format";

if [ "$2" = "refresh" ] ; then
	rm -rf "/etc/pki/retrogrid";
fi;

echo "Begin Registration";

set -euo pipefail

if [ ! -f /usr/sbin/chroot ] ; then
	echo "Install required packages";
	/usr/bin/dnf install -y openssl ca-certificates coreutils curl;
fi;

pass "Required packages installed";

# Check for host identification files
[[ -f /etc/machine-id ]] || {
	echo "Host is missing machine-id! This is used to identify the host";
	echo "man machine-id";
	exit 1;
	}
[[ -f /sys/class/dmi/id/product_uuid ]] || {
	echo "Host is missing product_uuid! This is used to uniquely identify the host";
	echo "man machine-id";
	exit 1;
	}

pass "Host identification files found";


RG_DIR="/etc/pki/retrogrid"
KEY="$RG_DIR/client.key"
CSR="$RG_DIR/client.csr"
CRT="$RG_DIR/client.crt"
CA="$RG_DIR/rg-ca.pem"
ENROLL_URL="https://t.retrogrid.io/register/$1"
MID=$(cat /etc/machine-id)
DID=$(cat /sys/class/dmi/id/product_uuid);
FQDN=$(hostname -f 2>/dev/null || hostname);

# create PKI directory
/usr/bin/install -d -m 0755 "$RG_DIR";
if [ ! -f "$RG_DIR/client.key" ] || [ $REFRESH = true ] ; then
	echo "make client key";
	# Generate client private key, required for dnf/yum
	# 3072 is 128 bit symmetric equivalence
	openssl genpkey \
	  -algorithm RSA \
	  -pkeyopt rsa_keygen_bits:3072 \
	  -out "$RG_DIR/client.key" 2> /dev/null;
	if [ $? -ne 0 ] ; then
		echo "Error generating client key";
		exit 1;
	fi;
fi;

pass "PKI directory created";

# generate CSR with stable identity.
if [ ! -f "$RG_DIR/openssl-client.cnf" ] || [ $REFRESH = true ] ; then
	echo "Make client.cnf";
	/usr/bin/cat > $RG_DIR/openssl-client.cnf <<EOF
[ req ]
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext

[ dn ]
CN = rg:${MID}
O  = RetroGrid
OU = RetroGrid Host

[ req_ext ]
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectAltName = @alt

[ alt ]
DNS.1 = ${FQDN}
URI.1 = urn:retrogrid.machine:${MID}
URI.2 = urn:retrogrid.device:${DID}
EOF
fi;


# Generate the CSR
if [ ! -f "$RG_DIR/client.csr" ] || [ $REFRESH = true ] ; then
	echo "Generate CSR";
	openssl req -new \
	  -key "$RG_DIR/client.key" \
	  -out "$RG_DIR/client.csr" \
	  -config "$RG_DIR/openssl-client.cnf";
fi;

pass "CSR generated";

# Extract the DNF variables
/usr/bin/python3 -c "import dnf, json; b = dnf.Base(); print(json.dumps(dict(b.conf.substitutions)))" > "$RG_DIR/dnf_vars.json";

# submit the CSR and DNF variables.
echo "Submit the CSR";
tmpCert="/tmp/retrogrid.client.cert";
/usr/bin/curl -f -s \
  -X POST "$ENROLL_URL" \
  -F "csr=@$RG_DIR/client.csr" \
  -F "dnf_vars=@$RG_DIR/dnf_vars.json" \
  -H "Accept: application/json" \
	> $tmpCert || {
	echo "Problem submitting CSR.";
	echo "Contact RetroGrid support with code 150:$?";
	exit 1;
	}

pass "CSR submitted";

# If we can't read the certificate, quit here.
if ! openssl x509 -in "$tmpCert" -noout >/dev/null 2>&1; then
	cat "$tmpCert";
  exit 1
fi

echo "Verifying obtained certificate... $tmpCert";
cert_mod=$(openssl x509 -in "$tmpCert" -noout -modulus 2>/dev/null | openssl sha256)
key_mod=$(openssl rsa  -in "$KEY"  -noout -modulus 2>/dev/null | openssl sha256);

if [[ "$cert_mod" != "$key_mod" ]]; then
  echo "Obtained certificate does not match private key" >&2
  exit 1
fi

pass "Certificate verified";

echo "Installing client cert...";
mv -f "$tmpCert" "$RG_DIR/client.crt"

echo "Updating Certificate Authority...";
/usr/bin/curl -f -s \
  "https://repo.retrogrid.io/ca.crt" \
	-o /etc/pki/retrogrid/ca.crt || {
	echo "Error updating Certificate Authority certificate.";
	echo "Contact RetroGrid support with code 185:$?";
	exit 1;
	};

pass "Certificate Authority updated";

echo "Testing the new token";
/usr/bin/curl -sf   --cert /etc/pki/retrogrid/client.crt   --key /etc/pki/retrogrid/client.key   https://archive.retrogrid.io/observed/almalinux/current/current/10.2/BaseOS/x86_64/os/repodata/ -o /dev/null
exitCode=$?;
[[ $exitCode -eq 0 ]] || {
	echo "Despite a successful registration, authentication with the credentials failed.";
	echo "Contact RetroGrid support with code 194:$exitCode";
	exit 1;
	}

pass "Token test passed";

echo "Setting Permissions";
chmod 0700 /etc/pki/retrogrid;
chmod 0600 /etc/pki/retrogrid/*;

echo "Setting DNF settings";
setDnfConf;

pass "DNF settings set";

/usr/bin/retrogrid-diagnose.sh;
echo;
echo;
pass "Successful registration.";
