#!/bin/sh
# Make a bare IsardVDI Linux desktop reachable: install the SSH server, create
# the account the bastion logs in as, and install the SPICE guest agent.
#
# The Linux counterpart of windows.ps1, and it exists for the same reason: a
# freshly-installed guest often has no SSH server and no account matching
# `guest_properties.credentials`, and both live *inside* the guest — the host
# and this CLI cannot reach them. The symptoms:
#
#   * `isard ssh <name>` → "connection refused": the bastion reached the guest
#     but nothing is listening on port 22.
#   * `isard ssh <name>` → "unable to authenticate, attempted methods
#     [none password]": sshd is up, but the guest has no such account.
#
# Run it once, in the desktop's own viewer, as a single line short enough to
# type into a console with no working clipboard:
#
#     curl -fsSL https://isard.optersoft.com/linux.sh | sudo sh -s isard mypassword
#
# The account can also come from the environment (same names windows.ps1 uses)
# or from a prompt:
#
#     ISARD_USER=isard ISARD_PASS=... ; export ISARD_USER ISARD_PASS
#     curl -fsSL https://isard.optersoft.com/linux.sh | sudo -E sh
#
# Idempotent: safe to run again, skips whatever is already in place.
#
# POSIX sh on purpose — Ubuntu's /bin/sh is dash, and this must run before
# anything has been installed. Supports apt (Debian/Ubuntu) and dnf (Fedora
# and the RHEL family).

set -eu

USER_NAME="${1:-${ISARD_USER:-}}"
USER_PASS="${2:-${ISARD_PASS:-}}"
SSH_KEY="${ISARD_SSH_KEY:-}"

say() { printf '==> %s\n' "$*"; }
warn() { printf 'warning: %s\n' "$*" >&2; }
die() { printf 'error: %s\n' "$*" >&2; exit 1; }

[ "$(id -u)" -eq 0 ] || die "run me as root: pipe into 'sudo sh' rather than 'sh'"

# Prompting reads /dev/tty, not stdin: stdin is this script, arriving down the
# pipe from curl.
if [ -z "$USER_NAME" ]; then
    if [ -r /dev/tty ]; then
        printf 'Username for the IsardVDI bastion to log in as: ' > /dev/tty
        read -r USER_NAME < /dev/tty
    fi
    [ -n "$USER_NAME" ] || die "no username given (pass it as the first argument)"
fi
if [ -z "$USER_PASS" ]; then
    if [ -r /dev/tty ]; then
        printf 'Password for %s: ' "$USER_NAME" > /dev/tty
        stty -echo 2>/dev/null || true
        read -r USER_PASS < /dev/tty
        stty echo 2>/dev/null || true
        printf '\n' > /dev/tty
    fi
    [ -n "$USER_PASS" ] || die "no password given (pass it as the second argument)"
fi

if command -v apt-get > /dev/null 2>&1; then
    FAMILY=debian
elif command -v dnf > /dev/null 2>&1; then
    FAMILY=fedora
else
    die "no apt-get or dnf found — unsupported distribution"
fi
say "detected the $FAMILY family"

# --- packages ---------------------------------------------------------------
#
# spice-vdagent is what makes the viewer's clipboard work; qemu-guest-agent is
# how IsardVDI reads the guest's IP and applies guest properties. Neither is
# required for SSH, so a failure to install them is not fatal.

install_packages() {
    if [ "$FAMILY" = debian ]; then
        DEBIAN_FRONTEND=noninteractive apt-get update -qq
        DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "$@"
    else
        dnf install -y --setopt=install_weak_deps=False "$@"
    fi
}

if [ "$FAMILY" = debian ]; then
    SSHD_PKG=openssh-server; SSHD_SVC=ssh; ADMIN_GROUP=sudo
else
    SSHD_PKG=openssh-server; SSHD_SVC=sshd; ADMIN_GROUP=wheel
fi

if [ -x /usr/sbin/sshd ] || [ -x /usr/bin/sshd ]; then
    say "SSH server already installed"
else
    say "installing $SSHD_PKG"
    install_packages "$SSHD_PKG" || die "could not install $SSHD_PKG — is there internet egress?"
fi

say "enabling $SSHD_SVC"
systemctl enable --now "$SSHD_SVC" 2>/dev/null || service "$SSHD_SVC" start || \
    warn "could not start $SSHD_SVC automatically — start it by hand"

say "installing the guest agents (clipboard + guest agent)"
install_packages spice-vdagent qemu-guest-agent > /dev/null 2>&1 || \
    warn "guest agents not installed — SSH still works, the clipboard may not"
systemctl enable --now qemu-guest-agent 2>/dev/null || true
systemctl enable --now spice-vdagentd 2>/dev/null || true

# --- the bastion account ----------------------------------------------------

if id -u "$USER_NAME" > /dev/null 2>&1; then
    say "user $USER_NAME already exists"
else
    say "creating user $USER_NAME"
    useradd --create-home --shell /bin/bash "$USER_NAME"
fi

# Always (re)set the password: the whole point is that it matches what
# `guest_properties.credentials` will send.
printf '%s:%s\n' "$USER_NAME" "$USER_PASS" | chpasswd
say "password set for $USER_NAME"

if getent group "$ADMIN_GROUP" > /dev/null 2>&1; then
    usermod -aG "$ADMIN_GROUP" "$USER_NAME"
    say "added $USER_NAME to $ADMIN_GROUP"
fi

# Passwordless sudo, so `isard build` can provision without a terminal.
SUDOERS="/etc/sudoers.d/90-${USER_NAME}-isard"
printf '%s ALL=(ALL) NOPASSWD:ALL\n' "$USER_NAME" > "$SUDOERS"
chmod 0440 "$SUDOERS"
say "passwordless sudo enabled for $USER_NAME"

if [ -n "$SSH_KEY" ]; then
    HOME_DIR="$(getent passwd "$USER_NAME" | cut -d: -f6)"
    install -d -m 0700 "$HOME_DIR/.ssh"
    if [ -f "$HOME_DIR/.ssh/authorized_keys" ] && \
       grep -qF "$SSH_KEY" "$HOME_DIR/.ssh/authorized_keys"; then
        say "SSH key already authorised"
    else
        printf '%s\n' "$SSH_KEY" >> "$HOME_DIR/.ssh/authorized_keys"
        say "authorised the SSH key"
    fi
    chmod 0600 "$HOME_DIR/.ssh/authorized_keys"
    chown -R "$USER_NAME": "$HOME_DIR/.ssh"
fi

# The bastion authenticates to the guest with a password, so sshd must accept
# one. Distributions increasingly ship PasswordAuthentication no.
if [ -d /etc/ssh/sshd_config.d ]; then
    printf 'PasswordAuthentication yes\n' > /etc/ssh/sshd_config.d/90-isard.conf
    systemctl reload "$SSHD_SVC" 2>/dev/null || true
    say "password authentication enabled for sshd"
fi

printf '\n'
say "done — this desktop is now reachable with: isard ssh <name>"
say "you can shut it down; the build continues on its own"
