#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-or-later
# Install Tor, publish the relay onion service, and run the pvtcoms relay daemon as a
# sandboxed systemd service bound to localhost. Run AFTER harden.sh:  sudo bash setup-relay.sh
set -euo pipefail

RELAY_PORT="${RELAY_PORT:-9911}"          # localhost port the daemon listens on
ONION_PORT="${ONION_PORT:-9911}"          # virtual port the onion exposes (maps to RELAY_PORT)
ONION_DIR=/var/lib/tor/pvtcoms-relay
BIN_SRC="${BIN_SRC:-/root/pvtcoms-deploy/pvtcoms-relay}"  # the relay binary you uploaded
BIN_DST=/usr/local/bin/pvtcoms-relay
SERVICE=/etc/systemd/system/pvtcoms-relay.service

log() { printf '\033[1;34m[relay]\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m[relay] %s\033[0m\n' "$*" >&2; exit 1; }

[ "$(id -u)" -eq 0 ] || die "run with sudo/root"

# --- Tor --------------------------------------------------------------------
log "Installing Tor…"
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y tor openssl

log "Configuring onion service (virtual port ${ONION_PORT} → 127.0.0.1:${RELAY_PORT})…"
install -d -m 755 /etc/tor/torrc.d
grep -q '^%include /etc/tor/torrc.d/' /etc/tor/torrc 2>/dev/null \
  || echo '%include /etc/tor/torrc.d/*.conf' >> /etc/tor/torrc
cat > /etc/tor/torrc.d/pvtcoms.conf <<EOF
HiddenServiceDir ${ONION_DIR}
HiddenServicePort ${ONION_PORT} 127.0.0.1:${RELAY_PORT}
# Single-hop is faster but de-anonymises the SERVER; keep full 3-hop for relay anonymity.
EOF
systemctl enable tor
systemctl restart tor
sleep 3
[ -f "${ONION_DIR}/hostname" ] || { sleep 5; }
[ -f "${ONION_DIR}/hostname" ] || die "onion hostname not generated yet; check 'journalctl -u tor'"
chmod 700 "${ONION_DIR}" || true

# --- Relay binary -----------------------------------------------------------
if [ -f "$BIN_SRC" ]; then
  log "Installing relay binary from $BIN_SRC…"
  install -m 755 "$BIN_SRC" "$BIN_DST"
else
  log "WARNING: relay binary not found at $BIN_SRC."
  log "         Build it on a dev machine and upload it, e.g.:"
  log "           cargo build --release -p pvtcoms-demo"
  log "           scp target/release/pvtcoms-demo $RELAY_USER@<ip>:/root/pvtcoms-deploy/pvtcoms-relay"
  log "         (The current daemon entrypoint is 'pvtcoms-demo relay 127.0.0.1:${RELAY_PORT}'.)"
fi

# --- Dedicated service user + state dir -------------------------------------
id pvtcoms-relay &>/dev/null || useradd --system --no-create-home --shell /usr/sbin/nologin pvtcoms-relay
install -d -m 700 -o pvtcoms-relay -g pvtcoms-relay /var/lib/pvtcoms-relay

# --- Access policy: generate the shared access key once (gated mode) --------
# This 32-byte secret gates the relay to your invited circle. Distribute it to invited members
# (it gets baked into their app build / shared out-of-band). Strangers without it are rejected,
# yet the relay still cannot tell members apart (obliviousness preserved — see ADR-005).
# To run an OPEN/public relay instead, set PVTCOMS_RELAY_KEY= (empty) in the env file below.
ENV_FILE=/etc/pvtcoms-relay.env
RELAY_POW="${RELAY_POW:-20}"
RELAY_TTL="${RELAY_TTL:-1209600}" # 14 days
if [ ! -f "$ENV_FILE" ]; then
  ACCESS_KEY="$(openssl rand -hex 32)"
  cat > "$ENV_FILE" <<EOF
# pvtcoms relay config. Mode 600 — contains the shared access key. Do NOT commit or share publicly.
PVTCOMS_RELAY_KEY=${ACCESS_KEY}
PVTCOMS_RELAY_POW=${RELAY_POW}
PVTCOMS_RELAY_TTL=${RELAY_TTL}
PVTCOMS_RELAY_DATA=/var/lib/pvtcoms-relay/store.bin
EOF
  chmod 600 "$ENV_FILE"
  chown root:root "$ENV_FILE"
  log "Generated relay access key (gated mode). It is stored in $ENV_FILE (root, 0600)."
else
  log "Reusing existing relay config at $ENV_FILE."
fi

# --- Sandboxed systemd unit -------------------------------------------------
log "Installing sandboxed systemd service…"
cat > "$SERVICE" <<EOF
[Unit]
Description=pvtcoms oblivious relay (localhost; reached via Tor onion)
After=network-online.target tor.service
Wants=network-online.target

[Service]
Type=simple
User=pvtcoms-relay
Group=pvtcoms-relay
EnvironmentFile=${ENV_FILE}
ExecStart=${BIN_DST} relay 127.0.0.1:${RELAY_PORT}
Restart=on-failure
RestartSec=3
StateDirectory=pvtcoms-relay
WorkingDirectory=/var/lib/pvtcoms-relay

# --- Sandbox hardening ---
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectClock=true
ProtectHostname=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
# Localhost only — no remote sockets needed (Tor connects to 127.0.0.1).
IPAddressAllow=localhost
IPAddressDeny=any
ReadWritePaths=/var/lib/pvtcoms-relay

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
if [ -f "$BIN_DST" ]; then
  systemctl enable --now pvtcoms-relay
  sleep 1
  systemctl --no-pager --full status pvtcoms-relay | head -n 12 || true
else
  log "Service installed but NOT started (binary missing). Upload it, then: systemctl enable --now pvtcoms-relay"
fi

echo
log "Relay onion address (bake this into the app as the bootstrap relay):"
printf '\033[1;32m    %s\033[0m\n' "$(cat "${ONION_DIR}/hostname")"
log "Shared access key (gated mode — give this to invited members only):"
printf '\033[1;33m    %s\033[0m\n' "$(grep '^PVTCOMS_RELAY_KEY=' "$ENV_FILE" | cut -d= -f2)"
log "Daemon listens on 127.0.0.1:${RELAY_PORT}; firewall stays deny-all-inbound (onion-only)."
log "PoW difficulty ${RELAY_POW} bits, ${RELAY_TTL}s retention. Edit ${ENV_FILE} + 'systemctl restart pvtcoms-relay' to change."
