#!/bin/bash
# =============================================================================
# regen_apache_cert.sh
# Regenerates the self-signed TLS cert used by Apache/LAM (CN read from
# /opt/app/cert.txt), replacing the cert already in use. Also updates
# Apache's ServerName to match, and restarts httpd so the new cert takes
# effect in the browser.
#
# Includes explicit BasicConstraints/KeyUsage/ExtendedKeyUsage/SAN extensions
# so the cert is issued as a proper leaf/server cert rather than defaulting
# to CA:TRUE. SAN type (IP vs DNS) is auto-detected based on whether the CN
# is a literal IP address, since strict clients (e.g. Chrome's Service
# Worker registration path) reject an IP address listed under a DNS: SAN.
#
# NOTE: This is separate from regen_ldap_cert.sh. Apache (LAM web UI, port
# 8443) and slapd (LDAPS, port 636) use two independent certs. Regenerating
# one has no effect on the other - run both scripts if you want them to
# match.
# =============================================================================

SSL_DIR="/etc/apache2/ssl"
CERT="$SSL_DIR/lam.crt"
KEY="$SSL_DIR/lam.key"
CN_FILE="/opt/app/cert.txt"
SERVERNAME_CONF="/etc/apache2/conf-available/servername.conf"

# 1. Read CN from file, fallback to "localhost"
if [[ -f "$CN_FILE" && -s "$CN_FILE" ]]; then
  CERT_CN=$(head -n 1 "$CN_FILE" | xargs)
  echo "Read CN from $CN_FILE: $CERT_CN"
else
  CERT_CN="localhost"
  echo "CN file ($CN_FILE) not found or empty. Falling back to: $CERT_CN"
fi

# 2. Determine correct SAN type: IP address literal vs DNS hostname
if [[ "$CERT_CN" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
  SAN="IP:$CERT_CN"
  echo "CN looks like an IP address - using SAN type IP:$CERT_CN"
else
  SAN="DNS:$CERT_CN"
  echo "CN looks like a hostname - using SAN type DNS:$CERT_CN"
fi

# 3. Generate cert (overwrites the cert already in use)
#    Explicit extensions ensure this is issued as a normal server/leaf cert:
#      - basicConstraints CA:FALSE   -> not a CA cert
#      - keyUsage                    -> proper TLS server key usage
#      - extendedKeyUsage serverAuth -> explicitly a TLS server cert
#      - subjectAltName              -> IP: or DNS: as determined above
echo "Creating SSL directory: $SSL_DIR"
mkdir -p "$SSL_DIR"

echo "Re-generating self-signed certificate (10 years) for CN=$CERT_CN..."
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout "$KEY" \
  -out    "$CERT" \
  -subj "/C=US/ST=State/L=City/O=Cohesive/CN=$CERT_CN" \
  -addext "basicConstraints=critical,CA:FALSE" \
  -addext "keyUsage=critical,digitalSignature,keyEncipherment" \
  -addext "extendedKeyUsage=serverAuth" \
  -addext "subjectAltName=$SAN"

# 4. Fix ownership/permissions so Apache (running as www-data) can read the key
chown root:www-data "$KEY" "$CERT"
chmod 640 "$KEY" "$CERT"
echo "Certificate generated and permissions set for www-data user."

# 5. Keep Apache's ServerName in sync with the cert's CN so the "does NOT
#    include an ID which matches the server name" warning doesn't reappear.
echo "ServerName $CERT_CN" > "$SERVERNAME_CONF"
echo "ServerName set to $CERT_CN in $SERVERNAME_CONF"

# 6. Restart httpd so it picks up the new cert and ServerName
if command -v supervisorctl &>/dev/null && supervisorctl status httpd &>/dev/null; then
  echo "Restarting httpd to load the new certificate..."
  supervisorctl restart httpd
else
  echo "WARNING: supervisorctl not available - restart httpd manually for the new cert to take effect."
fi

echo "Done. New Apache/LAM cert CN=$CERT_CN is now active, ServerName matches."
echo "Note: this does NOT affect the LDAP (slapd) cert - run regen_ldap_cert.sh separately if you want both to match."