#!/usr/bin/env bash
# create-ops-user.sh — cria o usuário de operação no servidor.
#
# Executado no PRIMEIRO acesso, com o usuário administrativo que o provedor entregou.
# Depois deste passo, root nunca mais e usado para nada.
#
# Idempotente: rodar duas vezes não altera nada na segunda.
#
# Uso: create-ops-user.sh --host <ip> --admin <root> --ops <deploy> --pubkey <arquivo.pub> [--port 22] [--key <chave>]

set -uo pipefail

HOST=""; ADMIN="root"; OPS="deploy"; PUBKEY_FILE=""; PORT=22; KEY_PATH=""

while [ $# -gt 0 ]; do
  case "$1" in
    --host)   HOST="$2"; shift 2 ;;
    --admin)  ADMIN="$2"; shift 2 ;;
    --ops)    OPS="$2"; shift 2 ;;
    --pubkey) PUBKEY_FILE="$2"; shift 2 ;;
    --port)   PORT="$2"; shift 2 ;;
    --key)    KEY_PATH="$2"; shift 2 ;;
    *) echo "argumento desconhecido: $1" >&2; exit 2 ;;
  esac
done

[ -n "$HOST" ] || { echo "ERRO: --host é obrigatório" >&2; exit 2; }
[ -f "${PUBKEY_FILE/#\~/$HOME}" ] || { echo "ERRO: chave pública não encontrada em ${PUBKEY_FILE}" >&2; exit 2; }

PUBKEY=$(cat "${PUBKEY_FILE/#\~/$HOME}")

case "$OPS" in
  root|""|*[!a-z0-9_-]*)
    echo "ERRO: nome de usuário de operação inválido: '${OPS}'" >&2
    echo "Use letras minusculas, números, hifen ou sublinhado. Nunca 'root'." >&2
    exit 2 ;;
esac

SSH_OPTS=(-o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ForwardAgent=no -o ConnectTimeout=10 -p "$PORT")
[ -n "$KEY_PATH" ] && SSH_OPTS+=(-i "${KEY_PATH/#\~/$HOME}" -o IdentitiesOnly=yes)

# O cofre de segredos é instalado AQUI, na única sessão de root que o framework
# usa. Depois do endurecimento root não entra mais, e o usuário de operação não
# recebe sudo para bash: este é o momento.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "${SCRIPT_DIR}/vault-install.sh"
VAULT_BLOCK=$(vault_install_block "$OPS")

# A elevação de privilegio fica restrita ao que o framework realmente precisa,
# em vez de sudo irrestrito sem senha.
REMOTE=$(cat <<REMOTE_SCRIPT
set -e
OPS="${OPS}"
PUBKEY='${PUBKEY}'

if ! id -u "\$OPS" >/dev/null 2>&1; then
  useradd --create-home --shell /bin/bash "\$OPS"
  echo "criou_usuario=sim"
else
  echo "criou_usuario=não (já existia)"
fi

# Grupo de elevação varia entre distribuicoes.
if getent group sudo >/dev/null; then usermod -aG sudo "\$OPS"; GRUPO=sudo
elif getent group wheel >/dev/null; then usermod -aG wheel "\$OPS"; GRUPO=wheel
else GRUPO=nenhum; fi
echo "grupo_elevacao=\$GRUPO"

install -d -m 700 -o "\$OPS" -g "\$OPS" "/home/\$OPS/.ssh"
AUTH="/home/\$OPS/.ssh/authorized_keys"
touch "\$AUTH"
if ! grep -qxF "\$PUBKEY" "\$AUTH"; then
  printf '%s\n' "\$PUBKEY" >> "\$AUTH"
  echo "instalou_chave=sim"
else
  echo "instalou_chave=não (já estava la)"
fi
chown "\$OPS:\$OPS" "\$AUTH"
chmod 600 "\$AUTH"

# Elevação sem senha, restrita aos comandos de operação do framework.
#
# Este arquivo e o ÚLTIMO limite: ele continua valendo mesmo que alguem escape da
# camada de controle do SSHepherd. Por isso nada de curinga solto aqui.
#
#   systemctl  → so as unidades que o framework opera. \`systemctl restart *\`
#                aceitava \`systemctl stop sshd.service\` e trancava o dono fora.
#   apt-get    → so os pacotes que o framework instala. \`install *\` aceitava um
#                .deb local, é .deb roda script de pos-instalacao como root.
#   journalctl → so as unidades do framework, é com o paginador desligado: o
#                paginador do journalctl abre shell de root (\`!sh\` dentro do less).
SUDOERS="/etc/sudoers.d/sshp-\$OPS"
UNIDADES="sshepherd-app caddy nginx fail2ban"
PACOTES="caddy nginx fail2ban unattended-upgrades rsync curl git ufw"

{
  echo "# Gerado pelo SSHepherd. Elevação restrita as operações do framework."
  echo "# Nao edite a mao: \`create-ops-user.sh\` reescreve este arquivo."
  echo "Defaults:\$OPS env_keep += \"SYSTEMD_PAGER SYSTEMD_LESS\""
  # Sem \`!requiretty\`: o sudo-rs (Ubuntu 25.10 em diante) recusa a opção, e
  # Debian e Ubuntu nunca exigiram terminal para o sudo.
  for U in \$UNIDADES; do
    for ACAO in start stop restart reload status is-active; do
      echo "\$OPS ALL=(root) NOPASSWD: /bin/systemctl \$ACAO \$U, /usr/bin/systemctl \$ACAO \$U"
    done
    echo "\$OPS ALL=(root) NOPASSWD: /bin/journalctl --no-pager -u \$U *, /usr/bin/journalctl --no-pager -u \$U *"
  done
  echo "\$OPS ALL=(root) NOPASSWD: /usr/bin/apt-get update, /usr/bin/apt-get -y upgrade"
  for P in \$PACOTES; do
    echo "\$OPS ALL=(root) NOPASSWD: /usr/bin/apt-get -y install \$P"
  done
  echo "\$OPS ALL=(root) NOPASSWD: /usr/sbin/ufw status, /usr/sbin/ufw status verbose"
} > "\$SUDOERS"
chmod 440 "\$SUDOERS"
if visudo -cf "\$SUDOERS" >/dev/null 2>&1; then
  echo "sudoers=válido"
else
  rm -f "\$SUDOERS"
  echo "sudoers=inválido, removido"
  exit 4
fi

echo "== cofre de segredos =="
${VAULT_BLOCK}

echo "usuario_pronto=\$OPS"
REMOTE_SCRIPT
)

echo "--------------------------------------------"
echo " Vou criar o usuário de operação '${OPS}' em ${HOST}"
echo " Conectando como: ${ADMIN}"
echo " Depois deste passo, ${ADMIN} não será mais usado para operar."
echo "--------------------------------------------"

ssh "${SSH_OPTS[@]}" "${ADMIN}@${HOST}" "bash -s" <<< "$REMOTE"
CODE=$?

if [ $CODE -ne 0 ]; then
  echo "FALHOU ao criar o usuário de operação (código ${CODE})." >&2
  exit $CODE
fi

echo ""
echo "PRÓXIMO PASSO OBRIGATORIO: rodar validate-access.sh com --user ${OPS}"
echo "Enquanto essa validação não passar, o endurecimento fica bloqueado."
exit 0
