#!/bin/bash
# CUPS backend: verae — virtual printer "Verae Timestamping" (Linux)
# Discovery (no args): advertise device URI verae:/
# Job: spool PDF and run verae-print as the job user (digests only).
#
# MUST be installed mode 0700 root:root. CUPS runs 0755 backends as user "lp",
# which can't write into /home/<user> or switch to the job user, so every job
# fails with status 1 and sits in the queue being retried.
#
# Debug: touch /etc/verae-print/debug  → full bash trace in the backend log.
# Log:   /var/log/cups/verae-backend.log  (plus ERROR:/INFO: lines in CUPS error_log
#        and the job's status in `lpstat -l -o`).
set -uo pipefail

BACKEND_LOG="/var/log/cups/verae-backend.log"

log() {
  echo "$(date '+%Y-%m-%dT%H:%M:%S%z') [job ${JOB_ID:-?}] $*" >>"$BACKEND_LOG" 2>/dev/null || true
}
# Messages prefixed ERROR:/INFO: on stderr show up in CUPS error_log and job status.
fail() {
  local code="$1"; shift
  log "FAIL: $*"
  echo "ERROR: Verae: $*" >&2
  exit "$code"
}

if [[ $# -eq 0 ]]; then
  echo 'direct verae:/ "Verae Timestamping" "Verae Timestamping — digests-only stamp"'
  exit 0
fi

JOB_ID="${1:-}"
JOB_USER="${2:-}"
JOB_TITLE="${3:-document}"
JOB_FILE="${6:-}"

if [[ -f /etc/verae-print/debug ]]; then
  exec 2> >(tee -a "$BACKEND_LOG" >&2)
  set -x
fi

log "start uid=$(id -u) user=$JOB_USER title=$JOB_TITLE file=${JOB_FILE:-stdin} argv=$*"

if [[ "$(id -u)" != "0" ]]; then
  fail 4 "backend is running as $(id -un), not root. Fix: sudo chown root:root $0 && sudo chmod 700 $0 && sudo systemctl restart cups"
fi

# Find the CLI: env override, then the .deb path, then the tarball path.
VERAE_PRINT="${VERAE_PRINT_BIN:-}"
if [[ -z "$VERAE_PRINT" ]]; then
  for c in /usr/bin/verae-print /usr/local/bin/verae-print; do
    [[ -x "$c" ]] && { VERAE_PRINT="$c"; break; }
  done
fi
[[ -x "${VERAE_PRINT:-}" ]] || fail 4 "verae-print CLI not found (looked in /usr/bin and /usr/local/bin)"
CHANNEL="${VERAE_PRINT_CHANNEL:-zapier}"

USER_HOME=""
if [[ -n "$JOB_USER" && "$JOB_USER" != "root" ]] && id "$JOB_USER" >/dev/null 2>&1; then
  USER_HOME="$(getent passwd "$JOB_USER" | cut -d: -f6)"
fi
if [[ -n "$USER_HOME" && -d "$USER_HOME" ]]; then
  SPOOL_BASE="$USER_HOME/.local/share/verae/print-spool"
  OUT_DIR="$USER_HOME/Documents/Verae Timestamps"
  USER_GROUP="$(id -gn "$JOB_USER")"
else
  SPOOL_BASE="/var/spool/verae/${JOB_USER:-unknown}"
  OUT_DIR="/tmp/VeraeTimestamps"
  USER_GROUP=""
fi

# Pop the "get a signing key" window in the job user's desktop session.
# Detached (setsid) so the backend returns at once; throttled to one launch per
# 10 minutes per user so CUPS retries don't keep reopening it after "Skip".
launch_key_dialog() {
  local reason="$1"
  [[ -n "$USER_HOME" ]] || return 0
  local uid; uid="$(id -u "$JOB_USER")"
  local stamp="$USER_HOME/.local/share/verae/.key-dialog-launched"
  if [[ -f "$stamp" ]] && (( $(date +%s) - $(stat -c %Y "$stamp") < 600 )); then
    log "key dialog launched recently; not reopening"
    return 0
  fi
  # Borrow DISPLAY/XAUTHORITY/DBUS from one of the user's graphical processes.
  local pid envf disp="" xauth="" wl="" dbus=""
  for pid in $(pgrep -u "$uid" 2>/dev/null); do
    envf="/proc/$pid/environ"
    [[ -r "$envf" ]] || continue
    disp="$(tr '\0' '\n' <"$envf" | sed -n 's/^DISPLAY=//p' | head -n1)"
    wl="$(tr '\0' '\n' <"$envf" | sed -n 's/^WAYLAND_DISPLAY=//p' | head -n1)"
    [[ -n "$disp" || -n "$wl" ]] || continue
    xauth="$(tr '\0' '\n' <"$envf" | sed -n 's/^XAUTHORITY=//p' | head -n1)"
    dbus="$(tr '\0' '\n' <"$envf" | sed -n 's/^DBUS_SESSION_BUS_ADDRESS=//p' | head -n1)"
    break
  done
  if [[ -z "$disp" && -z "$wl" ]]; then
    log "no desktop session found for $JOB_USER; key dialog not shown"
    return 0
  fi
  [[ -n "$xauth" ]] || xauth="$USER_HOME/.Xauthority"
  [[ -n "$dbus" ]] || dbus="unix:path=/run/user/$uid/bus"
  mkdir -p "$USER_HOME/.local/share/verae" && touch "$stamp"
  chown -R "$JOB_USER:$(id -gn "$JOB_USER")" "$USER_HOME/.local/share/verae" 2>/dev/null || true
  log "launching key dialog for $JOB_USER on DISPLAY=$disp WAYLAND_DISPLAY=$wl"
  runuser -u "$JOB_USER" -- env -i HOME="$USER_HOME" USER="$JOB_USER" LOGNAME="$JOB_USER" \
    PATH=/usr/local/bin:/usr/bin:/bin DISPLAY="$disp" WAYLAND_DISPLAY="$wl" XAUTHORITY="$xauth" \
    DBUS_SESSION_BUS_ADDRESS="$dbus" XDG_RUNTIME_DIR="/run/user/$uid" \
    VERAE_KEY_REASON="$reason" \
    setsid "$VERAE_PRINT" key-dialog </dev/null >/dev/null 2>&1 &
  disown || true
}

# Signing key must exist for the job user before we bother spooling.
if [[ -n "$USER_HOME" && -z "${XVERAE_TOKEN:-}" && ! -s "$USER_HOME/.verae/xverae-token" ]]; then
  # Exit 1 = CUPS retries the job later (ErrorPolicy retry-job), so it prints
  # by itself once the user runs setup.
  launch_key_dialog "\"$JOB_TITLE\" is waiting to be timestamped. It will print by itself as soon as a Verae signing key is saved."
  fail 1 "no signing key for $JOB_USER — finish the Verae sign-in window (or run 'verae-print key-dialog'); the job retries automatically"
fi

SAFE_TITLE=$(echo "$JOB_TITLE" | tr -cd 'A-Za-z0-9._ -' | head -c 80)
SAFE_TITLE=${SAFE_TITLE:-document}
WORK="$SPOOL_BASE/job-${JOB_ID}-$$"
mkdir -p "$WORK" "$OUT_DIR" || fail 1 "cannot create $WORK or $OUT_DIR"

INPUT="$WORK/input.dat"
if [[ -n "$JOB_FILE" && -f "$JOB_FILE" ]]; then
  cp "$JOB_FILE" "$INPUT" || fail 1 "cannot copy $JOB_FILE"
else
  cat >"$INPUT" || fail 1 "cannot read job from stdin"
fi
PDF="$WORK/${SAFE_TITLE}.pdf"
mv "$INPUT" "$PDF"
log "spooled $(stat -c %s "$PDF") bytes, magic=$(head -c 4 "$PDF" | tr -cd '[:print:]') → $PDF"

# Files were created by root inside the user's home: hand them to the user,
# otherwise verae-print (run as the user) can't read the PDF or write outputs.
if [[ -n "$USER_GROUP" ]]; then
  chown -R "$JOB_USER:$USER_GROUP" "$USER_HOME/.local/share/verae" "$OUT_DIR"
  chmod 700 "$SPOOL_BASE"
fi

run_as_user() {
  if [[ -n "$USER_GROUP" ]]; then
    runuser -u "$JOB_USER" -- env HOME="$USER_HOME" "$@"
  else
    "$@"
  fi
}

echo "INFO: Verae: registering digest" >&2
OUT=$(run_as_user "$VERAE_PRINT" stamp -channel "$CHANNEL" -out-dir "$OUT_DIR" -skip-setup "$PDF" 2>&1)
RC=$?
log "verae-print rc=$RC output: $OUT"
if [[ $RC -eq 0 ]]; then
  rm -rf "$WORK"
  log "ok → $OUT_DIR"
  echo "INFO: Verae: timestamped → $OUT_DIR" >&2
  exit 0
fi
if echo "$OUT" | grep -qiE '\b(401|403)\b|unauthori|rejected|invalid key'; then
  launch_key_dialog "Verae did not accept the saved signing key. \"$JOB_TITLE\" will print by itself once a working key is saved."
fi
fail 1 "verae-print stamp failed (rc=$RC): $(echo "$OUT" | tail -n 2 | tr '\n' ' ')"
