#!/usr/bin/env bash # Página de entrada del sitio (27-oct-2026): instala el nginx nuevo de drogheda.helgen.online con respaldo, prueba y # regreso automático. Se corre EN EL SERVIDOR con sudo (lo llama scripts/despliegue-1027.sh desde la Mac): # sudo bash /srv/projects/drogheda/hbox-docs/backend/nginx/cambiar-entrada.sh servicio # 1. servicio nuevo (hilos, admins) # sudo bash …/cambiar-entrada.sh aplicar # 2. nginx con página de entrada (si una prueba falla, regresa solo) # sudo bash …/cambiar-entrada.sh deshacer # regresar al nginx anterior (ventana gris) si algo no te gusta # sudo bash …/cambiar-entrada.sh probar # solo las pruebas, sin cambiar nada set -uo pipefail AQUI="$(cd "$(dirname "$0")" && pwd)" BACK="$(dirname "$AQUI")" # El archivo real de nginx de este sitio (el que está habilitado), no una ruta supuesta CONF="$(readlink -f "$(grep -l 'server_name drogheda.helgen.online' /etc/nginx/sites-enabled/* 2>/dev/null | head -1)" 2>/dev/null)" NUEVO="$AQUI/drogheda.helgen.online.conf" HTP=/etc/nginx/hbox-docs.htpasswd DATOS=/srv/projects/drogheda UNIDAD=/etc/systemd/system/actas-hbox.service HOST=drogheda.helgen.online [ "$(id -u)" = 0 ] || { echo "Córrelo con sudo."; exit 1; } ok=0; mal=0 prueba() { # nombre, esperado (subcadena), comando local r; r="$(eval "$3" 2>&1)" if [[ "$r" == *"$2"* ]]; then ok=$((ok+1)); echo " ✓ $1"; else mal=$((mal+1)); echo " ✕ $1 — esperaba «$2», obtuve: ${r:0:160}"; fi } C="curl -s --max-time 10 --resolve $HOST:443:127.0.0.1" probar_backend() { echo "## backend (127.0.0.1:8081)" prueba "salud" '"ok":true' "curl -s --max-time 5 http://127.0.0.1:8081/api/salud" prueba "/api/_auth sin sesión → 401" "401" "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8081/api/_auth" prueba "/api/sesion responde" '"sesion":false' "curl -s http://127.0.0.1:8081/api/sesion" prueba "incidencias cargadas" '"ok":true' "curl -s -H 'X-Remote-User: vigia' http://127.0.0.1:8081/api/incidencias/resumen" prueba "standup cargado" '"ok":true' "curl -s -H 'X-Remote-User: vigia' http://127.0.0.1:8081/api/standup/estado" } cookie_de_prueba() { # sesión de 5 minutos para leo, firmada con el secreto del servicio (sin contraseña) # El servicio crea su secreto la primera vez que firma o revisa una cookie; en el primer despliegue aún no existe # (27-oct: por eso fallaron las 3 pruebas «con sesión»). Una cookie falsa «vigente» lo obliga a crearlo (responde 401). [ -s "$DATOS/.sesion-secreto" ] || curl -s -o /dev/null --max-time 5 -b 'hbox_sesion=x~9999999999~x~x' http://127.0.0.1:8081/api/_auth python3 - "$DATOS/.sesion-secreto" "$HTP" <<'PY' import sys, time, hmac, hashlib sec = open(sys.argv[1]).read().strip().encode() h = [l.split(":", 1)[1].strip() for l in open(sys.argv[2]) if l.split(":", 1)[0].strip() == "leo"][0] ver = hashlib.sha256(h.encode()).hexdigest()[:12]; v = int(time.time()) + 300 print("leo~%d~%s~%s" % (v, ver, hmac.new(sec, ("leo|%d|%s" % (v, ver)).encode(), hashlib.sha256).hexdigest()[:40])) PY } probar_nginx() { echo "## nginx ($HOST)" prueba "/ sin sesión → 302 a /entrar.html" "entrar.html" "$C -o /dev/null -w '%{http_code} %{redirect_url}' https://$HOST/tableros/pendientes/" prueba "/entrar.html → 200" "200" "$C -o /dev/null -w '%{http_code}' https://$HOST/entrar.html" prueba "estilos públicos → 200" "200" "$C -o /dev/null -w '%{http_code}' https://$HOST/stylesheets/helgen.css" prueba "/publico/entrar.js → 200" "200" "$C -o /dev/null -w '%{http_code}' https://$HOST/publico/entrar.js" prueba "/api/sesion sin sesión → 200" '"sesion":false' "$C https://$HOST/api/sesion" prueba "/api/tareas sin sesión → 401 JSON" '"sesion":false' "$C https://$HOST/api/tareas" prueba "/api/_auth desde fuera → 404" "404" "$C -o /dev/null -w '%{http_code}' https://$HOST/api/_auth" prueba "X-Remote-User falso no entra" '"sesion":false' "$C -H 'X-Remote-User: leo' https://$HOST/api/tareas" prueba "entrar con contraseña mala → 401" '"codigo":"' "$C -H 'Content-Type: application/json' -d '{\"usuario\":\"vigia-prueba\",\"password\":\"x\"}' https://$HOST/api/entrar" prueba "curl -u (Basic) ya no entra" '"sesion":false' "$C -A curl -u leo:x https://$HOST/api/whoami" local CK; CK="$(cookie_de_prueba 2>/dev/null)" if [[ ! "$CK" =~ ^leo~[0-9]+~[0-9a-f]{12}~[0-9a-f]{40}$ ]]; then mal=$((mal+1)); echo " ✕ no pude armar la sesión de prueba de leo: ¿existe $DATOS/.sesion-secreto? ¿está leo en $HTP?" fi prueba "con sesión: /api/whoami = leo" '"user":"leo"' "$C -b hbox_sesion=$CK https://$HOST/api/whoami" prueba "con sesión: la página abre (200)" "200" "$C -b hbox_sesion=$CK -o /dev/null -w '%{http_code}' https://$HOST/tableros/pendientes/" prueba "POST desde otro sitio → 403" "otro sitio" "$C -b hbox_sesion=$CK -H 'Origin: https://malo.example' -H 'Content-Type: application/json' -d '{}' https://$HOST/api/incidencias" } revisar_htpasswd() { # la entrada nueva lee $apr1$ y {SHA}; si alguien quedó con otro formato, no podría entrar local otros; otros="$(cut -d: -f2 "$HTP" | grep -vcE '^(\$apr1\$|\{SHA\})' || true)" if [ "${otros:-0}" != "0" ]; then echo " ✕ $otros cuenta(s) del htpasswd con un formato que la entrada nueva no lee:"; cut -d: -f1,2 "$HTP" | grep -vE ':(\$apr1\$|\{SHA\})' | cut -d: -f1 | sed 's/^/ /' echo " Restablécelas en Mi cuenta antes de cambiar nginx."; return 1 fi echo " ✓ todas las contraseñas en \$apr1\$" } case "${1:-}" in servicio) UANT="$UNIDAD.antes-$(date +%Y%m%d-%H%M%S)" cp -p "$UNIDAD" "$UANT" || { echo "No pude respaldar $UNIDAD: no cambio nada."; exit 1; } install -m 644 "$BACK/actas-hbox.service" "$UNIDAD" systemctl daemon-reload && systemctl restart actas-hbox for i in 1 2 3 4 5 6 7 8 9 10; do curl -s --max-time 2 http://127.0.0.1:8081/api/salud >/dev/null && break; sleep 1; done probar_backend if [ "$mal" != 0 ]; then echo "El servicio nuevo no pasó ($mal mal): regreso al anterior ($UANT). Revisa 'journalctl -u actas-hbox -n 50'." cp -p "$UANT" "$UNIDAD" && systemctl daemon-reload && systemctl restart actas-hbox; exit 1 fi echo "Servicio listo ($ok pruebas). Respaldo del anterior: $UANT" ;; aplicar) [ -n "$CONF" ] && [ -f "$CONF" ] || { echo "No encuentro el nginx de $HOST en sites-enabled. No cambio nada."; exit 1; } echo "Archivo de nginx: $CONF" probar_backend [ "$mal" = 0 ] || { echo "El backend todavía no tiene la entrada nueva: corre primero «servicio». No cambié nginx."; exit 1; } revisar_htpasswd || exit 1 # respaldo FUERA de sites-enabled/ (lo que esté ahí lo carga nginx: un respaldo ahí duplicaría el sitio) mkdir -p /etc/nginx/respaldos-drogheda RESP="/etc/nginx/respaldos-drogheda/$(basename "$CONF").antes-entrada-$(date +%Y%m%d-%H%M%S)" cp -p "$CONF" "$RESP" || { echo "No pude respaldar $CONF: no cambio nada."; exit 1; } echo "Respaldo: $RESP" install -m 644 "$NUEVO" "$CONF" if ! nginx -t 2>&1; then echo "nginx -t falló: regreso al anterior."; cp -p "$RESP" "$CONF"; nginx -t && systemctl reload nginx; exit 1; fi systemctl reload nginx; sleep 1 ok=0; mal=0; probar_nginx if [ "$mal" != 0 ]; then echo "Algo falló ($mal): regreso al nginx anterior."; cp -p "$RESP" "$CONF"; nginx -t && systemctl reload nginx; exit 1 fi echo; echo "Listo ($ok pruebas). Abre https://$HOST : debe salir la página de entrada. Para regresar: sudo bash $0 deshacer" ;; deshacer) [ -n "$CONF" ] || CONF=/etc/nginx/sites-available/drogheda.helgen.online.conf RESP="$(ls -1t /etc/nginx/respaldos-drogheda/"$(basename "$CONF")".antes-entrada-* 2>/dev/null | head -1)" [ -n "$RESP" ] || { echo "No hay respaldo de antes de la entrada."; exit 1; } cp -p "$RESP" "$CONF" && nginx -t && systemctl reload nginx && echo "Regresé a $RESP (ventana gris de antes)." ;; probar) probar_backend; probar_nginx; echo "$ok bien · $mal mal" ;; *) sed -n '2,9p' "$0"; exit 1 ;; esac