#!/usr/bin/env bash
#
# RELAY-PHASE1 · Native mTLS tunnel · V2 — Revoke a device/frp-client leaf, regenerate the CRL.
#
# STAGING TEMPLATE. Marks a previously-issued leaf revoked in the CA database and regenerates
# <CA_DIR>/crl.pem, which nginx :8470 serves via `ssl_crl` (V4) — so the revoked device is rejected at
# the TLS handshake fleet-wide the moment nginx reloads. This script does NOT touch the remote VPS: it
# only prints the reload hint; run the reload yourself on the box after copying the CRL.
#
# Requires the `openssl ca` database created by deploy/scripts/gen-device-ca.sh (index.txt/serial/…).
#
# Usage:  revoke-device.sh <LEAF_CERT.pem>          # revoke by the issued cert file
#     or  revoke-device.sh --serial <HEX_SERIAL>    # revoke by serial (uses <CA_DIR>/newcerts/<serial>.pem)
#
# Config via ENV or flags (no secrets):
#     CA_DIR   which CA to revoke against   (default /etc/relay/device-ca)  — or  --ca-dir <path>
#
# Verify (syntax): bash -n deploy/scripts/revoke-device.sh
set -euo pipefail

CA_DIR="${CA_DIR:-/etc/relay/device-ca}"
LEAF=""
SERIAL=""

while [[ $# -gt 0 ]]; do
  case "$1" in
    --ca-dir) CA_DIR="${2:?--ca-dir needs a value}"; shift 2 ;;
    --serial) SERIAL="${2:?--serial needs a value}"; shift 2 ;;
    -h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
    -*) echo "FATAL: unknown flag '$1' (see --help)" >&2; exit 2 ;;
    *)  if [[ -z "${LEAF}" ]]; then LEAF="$1";
        else echo "FATAL: too many positional args at '$1'" >&2; exit 2; fi; shift ;;
  esac
done

command -v openssl >/dev/null 2>&1 || { echo "FATAL: openssl not found on PATH." >&2; exit 3; }
[[ -f "${CA_DIR}/openssl.cnf" ]] || { echo "FATAL: no CA db in ${CA_DIR} (run gen-device-ca.sh first)." >&2; exit 3; }

# ---- resolve the target leaf (by path or by serial) to an absolute path --------------------------
if [[ -n "${SERIAL}" ]]; then
  # Boundary-validate the serial (used to build a path); openssl stores newcerts/<UPPERCASE-HEX>.pem.
  [[ "${SERIAL}" =~ ^[0-9A-Fa-f]+$ ]] || { echo "FATAL: --serial must be hex." >&2; exit 2; }
  LEAF="${CA_DIR}/newcerts/$(echo "${SERIAL}" | tr '[:lower:]' '[:upper:]').pem"
fi
[[ -n "${LEAF}" ]] || { echo "FATAL: pass a <LEAF_CERT.pem> or --serial <HEX>." >&2; exit 2; }
[[ -f "${LEAF}" ]] || { echo "FATAL: leaf cert not found: ${LEAF}" >&2; exit 3; }
LEAF="$(cd "$(dirname "${LEAF}")" && pwd)/$(basename "${LEAF}")"

REVOKED_SERIAL="$(openssl x509 -in "${LEAF}" -noout -serial | cut -d= -f2)"
echo "== Revoking serial ${REVOKED_SERIAL} against CA ${CA_DIR} =="

# ---- revoke + regenerate the CRL (cd in so openssl.cnf's dir=. resolves to CA_DIR) ----------------
(
  cd "${CA_DIR}"
  openssl ca -config openssl.cnf -revoke "${LEAF}"
  openssl ca -config openssl.cnf -gencrl -out crl.pem
)
chmod 644 "${CA_DIR}/crl.pem"

cat <<SUMMARY

Revoked serial ${REVOKED_SERIAL}. Updated CRL: ${CA_DIR}/crl.pem
Confirm:  openssl crl -in ${CA_DIR}/crl.pem -noout -text | grep -A1 'Serial Number'

RELOAD HINT (run ON THE VPS after copying the new crl.pem into place — NOT executed here):
    nginx -t && nginx -s reload
Until nginx reloads the CRL, the revoked cert is still accepted.
SUMMARY
