#!/usr/bin/env bash
# proxy-setup — install a corporate forward proxy system-wide AND extract
# the proxy's TLS-intercepting root CA into the system trust store.
#
# Combines proxy-env.sh + proxy-ca.sh in that order: env first so any
# tool the CA step might reach for honors the proxy, then CA so TLS
# verification stops failing.
#
# Run on the target host (copy/scp this script there first — fetching
# it from the hrs server with `curl` won't work yet, since that's
# exactly the TLS path this script is here to make trustworthy):
#   sudo PROXY=http://10.0.0.1:8080 bash proxy-setup.sh
#
# Optional:
#   NO_PROXY=...   bypass list for env vars (default: localhost,127.0.0.1,::1)
#   PROBE=<host>   host to TLS-handshake against in order to force the
#                  proxy to present its re-signed chain. Default: google.com
#                  (always reachable through any general-purpose forward proxy).
set -euo pipefail

: "${PROXY:?PROXY env var required, e.g. PROXY=http://10.0.0.1:8080}"
NO_PROXY_DEFAULT="localhost,127.0.0.1,::1"
NO_PROXY="${NO_PROXY:-${NO_PROXY_DEFAULT}}"
PROBE="${PROBE:-google.com}"

if [[ ${EUID} -ne 0 ]]; then
  echo "ERROR: must run as root (use sudo)" >&2
  exit 1
fi

# ---------------------------------------------------------------------------
# Part 1: env vars
# ---------------------------------------------------------------------------

MARK_BEGIN="# >>> hrs proxy-env >>>"
MARK_END="# <<< hrs proxy-env <<<"

# Body shared by both files. Both lower- and upper-case forms — different
# tools honor different conventions (curl/wget read lowercase, many Go
# programs read uppercase first).
read -r -d '' BLOCK <<EOF || true
${MARK_BEGIN}
http_proxy=${PROXY}
https_proxy=${PROXY}
HTTP_PROXY=${PROXY}
HTTPS_PROXY=${PROXY}
no_proxy=${NO_PROXY}
NO_PROXY=${NO_PROXY}
${MARK_END}
EOF

# strip_block <file> — remove a previously-written block, if any.
strip_block() {
  local f="$1"
  [[ -f "$f" ]] || return 0
  sed -i "/^${MARK_BEGIN}\$/,/^${MARK_END}\$/d" "$f"
}

write_block() {
  local f="$1"
  strip_block "$f"
  printf '%s\n' "${BLOCK}" >> "$f"
}

echo "==> writing /etc/environment"
write_block /etc/environment

# /etc/environment is read by PAM at login but NOT sourced by every
# shell (notably non-login service shells). Drop a profile.d snippet
# with `export` so any shell that sources /etc/profile picks them up.
PROFILE_D=/etc/profile.d/hrs-proxy.sh
echo "==> writing ${PROFILE_D}"
{
  echo "${MARK_BEGIN}"
  echo "export http_proxy=${PROXY}"
  echo "export https_proxy=${PROXY}"
  echo "export HTTP_PROXY=${PROXY}"
  echo "export HTTPS_PROXY=${PROXY}"
  echo "export no_proxy=${NO_PROXY}"
  echo "export NO_PROXY=${NO_PROXY}"
  echo "${MARK_END}"
} > "${PROFILE_D}"
chmod 0644 "${PROFILE_D}"

echo "  http_proxy / https_proxy = ${PROXY}"
echo "  no_proxy                 = ${NO_PROXY}"
echo

# ---------------------------------------------------------------------------
# Part 2: CA cert
# ---------------------------------------------------------------------------

# Strip scheme so openssl gets host:port. Accepts http://h:p, https://h:p,
# or bare h:p.
PROXY_HP="${PROXY#http://}"
PROXY_HP="${PROXY_HP#https://}"
PROXY_HP="${PROXY_HP%/}"

if ! command -v openssl >/dev/null 2>&1; then
  echo "ERROR: openssl is required but not installed." >&2
  exit 1
fi

# Detect the trust-store layout. Order matters: Debian/Ubuntu and
# Alpine both ship update-ca-certificates but read different anchor
# dirs; RHEL uses update-ca-trust + a different path.
if command -v update-ca-certificates >/dev/null 2>&1 && [[ -d /usr/local/share/ca-certificates ]]; then
  ANCHOR_DIR=/usr/local/share/ca-certificates
  UPDATE_CMD=(update-ca-certificates)
elif command -v update-ca-trust >/dev/null 2>&1 && [[ -d /etc/pki/ca-trust/source/anchors ]]; then
  ANCHOR_DIR=/etc/pki/ca-trust/source/anchors
  UPDATE_CMD=(update-ca-trust extract)
else
  echo "ERROR: no supported CA trust-store tool found." >&2
  echo "       Need either update-ca-certificates (Debian/Ubuntu/Alpine)" >&2
  echo "       or update-ca-trust (RHEL/Fedora/CentOS)." >&2
  exit 1
fi

CRT="${ANCHOR_DIR}/hrs-proxy-ca.crt"

echo "==> probing ${PROBE}:443 via proxy ${PROXY_HP}"

# Pull the chain. Last cert in the dump is the root.
CHAIN="$(
  openssl s_client \
    -connect "${PROBE}:443" \
    -proxy   "${PROXY_HP}" \
    -servername "${PROBE}" \
    -showcerts </dev/null 2>/dev/null \
  || true
)"

if [[ -z "${CHAIN}" ]]; then
  echo "ERROR: openssl s_client returned nothing — is the proxy reachable?" >&2
  exit 1
fi

# Last BEGIN..END block in the chain.
ROOT_PEM="$(printf '%s\n' "${CHAIN}" \
  | awk '/-----BEGIN CERT/{p=1;c=""} p{c=c$0"\n"} /-----END CERT/{p=0;last=c} END{printf "%s",last}')"

if [[ -z "${ROOT_PEM}" ]]; then
  echo "ERROR: no certificates in chain. Is ${PROBE}:443 actually being intercepted?" >&2
  exit 1
fi

# Sanity check: subject == issuer means self-signed root.
SUBJECT="$(printf '%s' "${ROOT_PEM}" | openssl x509 -noout -subject 2>/dev/null || true)"
ISSUER="$(printf '%s'  "${ROOT_PEM}" | openssl x509 -noout -issuer  2>/dev/null || true)"
echo "==> last-in-chain cert:"
echo "    ${SUBJECT}"
echo "    ${ISSUER}"
if [[ "${SUBJECT#subject=}" != "${ISSUER#issuer=}" ]]; then
  echo "WARN: subject != issuer — this may not be a self-signed root." >&2
  echo "      Installing it anyway. If verification still fails,"     >&2
  echo "      the proxy may not be doing TLS interception."           >&2
fi

echo "==> installing to ${CRT}"
printf '%s' "${ROOT_PEM}" > "${CRT}"
chmod 0644 "${CRT}"

echo "==> running ${UPDATE_CMD[*]}"
"${UPDATE_CMD[@]}"

echo
echo "Done. Open a new shell (or \`source ${PROFILE_D}\`) to pick up the env vars."
echo "Verify with:  curl -sS https://${PROBE} >/dev/null && echo OK"
