#!/bin/bash

# Write the systemd unit for this application, and make sure it has a key to
# hand it.
#
# Usage: bin/build_service [domain]

set -u

DOMAIN=${1:-}
REPLACEME=$(dirname "$0")/..
REPLACEME=$(readlink -f "$REPLACEME")
# Make sure we start it with the *right* perl
PERL5BIN=$(perl -V:scriptdir | sed -e "s/^scriptdir=//g;s/[';]//g")":$PATH"

CREDENTIAL=tpsgi-vault
# systemd reads this one, and /run/credstore.encrypted, and /usr/lib/... .  The
# override is for a distribution that puts it somewhere else, and for testing
# this without writing to /etc.
CREDSTORE=${TPSGI_CREDSTORE:-/etc/credstore.encrypted}

# An application which keeps secrets needs a key which is not kept where the
# secrets are.  systemd's credential store is that place: root owned, decrypted
# into a ramdisk only this service can read, and never anywhere a backup of the
# application would pick it up.
#
# systemd-creds encrypt --with-key=auto seals to the TPM when there is one and
# to the host key when there is not, so there is one command here rather than a
# choice for somebody to get wrong.  What differs is how much a stolen disk
# gets you, which is what gets reported below.
#
# Made once and then left alone.  Replacing it is the same as losing it: whatever
# was sealed under the old one stops opening, and whoever stored it stores it
# again.  That is the deal a key which lives and dies with its machine makes, and
# it is the reason there is nothing here that writes one into $REPLACEME.
setup_credential() {
    if ! command -v systemd-creds > /dev/null; then
        echo "No systemd-creds here, so no vault key.  Applications which wanted one will do without."
        return 0
    fi

    local sealing
    case "$(systemd-creds has-tpm2 2> /dev/null)" in
        yes) sealing="sealed to this machine's TPM" ;;
        *)   sealing="encrypted with the host key -- no usable TPM here, so a stolen disk is a stolen key" ;;
    esac

    sudo mkdir -p "$CREDSTORE" && sudo chmod 700 "$CREDSTORE" || {
        echo "Could not make $CREDSTORE; skipping the vault key." >&2
        return 1
    }

    # Asked as root, because the store is 700 and root owned: a plain -e in here
    # cannot see into it and says the key is absent every single time.  That
    # would quietly replace the key on every build_service, which is the same as
    # losing it -- everything sealed under the old one stops opening.
    if sudo test -e "$CREDSTORE/$CREDENTIAL"; then
        echo "Vault key already in $CREDSTORE/$CREDENTIAL; leaving it alone."
        return 0
    fi

    # Straight down a pipe and into systemd-creds: the key is never a file, an
    # argument, or a line of scrollback on its way there.
    if ! openssl rand -base64 32 \
        | sudo systemd-creds encrypt --name="$CREDENTIAL" - "$CREDSTORE/$CREDENTIAL"; then
        echo "Could not write $CREDSTORE/$CREDENTIAL; skipping the vault key." >&2
        return 1
    fi

    sudo chmod 600 "$CREDSTORE/$CREDENTIAL"
    echo "Wrote $CREDSTORE/$CREDENTIAL, $sealing."
    echo "It is not backed up and cannot be recovered.  Losing this machine loses what was stored under it."
}

setup_credential

sed -e "s|__REPLACEME__|$REPLACEME|g" \
    -e "s|__PERL5BIN__|$PERL5BIN|g" \
    -e "s|__DOMAIN__|$DOMAIN|g" \
    -e "s|__HOME__|${UHOME:-}|g" \
    "$REPLACEME/service/tpsgi.tmpl" > "$REPLACEME/service/tpsgi.service"

echo "Wrote $REPLACEME/service/tpsgi.service"
