#!/usr/bin/env bash
# =============================================================================
# Corrige permisos en las carpetas que NO vienen de git
# =============================================================================
# Arregla DOS cosas, y solo esas dos. No normaliza el resto a propósito: cuanto
# menos toque, menos puede romper y más fácil es leer lo que cambió.
#
#   1. DIRECTORIOS ESCRIBIBLES POR CUALQUIERA (o+w, o sea 777) → se les quita el
#      permiso de escritura a "otros". Es el problema de verdad: cualquier usuario
#      del servidor puede dejar un archivo dentro. Medido en local: 2900 (225 en
#      storage, 1 en bootstrap/cache, 2674 en vendor).
#
#   2. ARCHIVOS CON BIT DE EJECUCIÓN que no se ejecutan → se les quita el +x.
#      Son JSON del debugbar, cachés compiladas, .gitignore… Medido: 662.
#      No rompe nada hoy, pero es superficie de ataque gratis y ensucia auditorías.
#
# ⚠️ LA CAUSA DE AMBOS ES `chmod -R 777` / `chmod -R 775`, que aplican el modo tal cual
#    a archivos y directorios por igual. La forma correcta de PREVENIRLO usa la `X`
#    mayúscula, que solo se lo da a los directorios:
#
#        chmod -R u=rwX,g=rwX,o=rX storage bootstrap/cache
#
# ⚠️ PERO ESE COMANDO NO ARREGLA LO YA ROTO, aunque se repita como si sí. La `X`
#    significa «si es directorio O YA TIENE +x para alguien», así que en un archivo
#    que ya está mal lo respeta. Comprobado:
#
#        $ chmod 775 datos.json && chmod -R u=rwX,g=rwX,o=rX .
#        -rwxrwxr-x  datos.json      ← intacto
#
#    Sirve para NO crear el problema; para CORREGIRLO hay que ir por `find -type f`,
#    que es lo que hace este script.
#
# ⚠️ NUNCA le quita el +x a algo que de verdad se ejecuta. Se salta:
#      · cualquier cosa bajo `bin/` o `.bin/` (vendor/bin, node_modules/.bin…)
#      · archivos que empiezan por `#!` (shebang)
#      · binarios ELF
#    Medido: de los 290 con +x en `vendor`, 36 son ejecutables reales y 254 son datos.
#    En `storage` y `bootstrap/cache` no hay NI UNO real.
#
# ⚠️ NO toca los directorios restrictivos (700) de `storage/app/backups` y compañía:
#    los crea spatie/laravel-backup así y ser MÁS cerrado nunca es el problema.
#    Aflojarlos es una decisión, no una corrección.
#
# Uso:
#   bash deploy/fix-permissions.sh --dry-run                       # solo informa
#   bash deploy/fix-permissions.sh                                 # storage + bootstrap/cache
#   bash deploy/fix-permissions.sh storage bootstrap/cache vendor node_modules
#
# Idempotente: la segunda corrida no cambia nada. En el servidor puede hacer falta
# correrlo como el dueño de los archivos (`sudo -u www-data bash deploy/…`).
# =============================================================================
set -uo pipefail

DRY=0
DIRS=()
for a in "$@"; do
    case "$a" in
        --dry-run|-n) DRY=1 ;;
        -*) echo "Opción desconocida: $a" >&2; exit 2 ;;
        *)  DIRS+=("$a") ;;
    esac
done
[ ${#DIRS[@]} -eq 0 ] && DIRS=(storage bootstrap/cache)

# ¿Este archivo se ejecuta de verdad?
es_ejecutable_real() {
    case "$1" in */bin/*|*/.bin/*) return 0 ;; esac
    local cab
    cab=$(head -c 4 -- "$1" 2>/dev/null | od -An -tx1 | tr -d ' \n')
    [ "${cab:0:4}" = "2321" ]     && return 0   # '#!'
    [ "${cab:0:8}" = "7f454c46" ] && return 0   # ELF
    return 1
}

tot_w=0; tot_x=0; saltados=0; fallos=0

for d in "${DIRS[@]}"; do
    [ -d "$d" ] || { printf "  ⏭  %-18s no existe, se salta\n" "$d"; continue; }

    n_w=0
    while IFS= read -r -d '' dir; do
        [ "$DRY" -eq 1 ] || chmod o-w -- "$dir" 2>/dev/null || { fallos=$((fallos+1)); continue; }
        n_w=$((n_w+1))
    done < <(find "$d" -type d -perm -o+w -print0 2>/dev/null)

    n_x=0
    while IFS= read -r -d '' f; do
        if es_ejecutable_real "$f"; then saltados=$((saltados+1)); continue; fi
        [ "$DRY" -eq 1 ] || chmod a-x -- "$f" 2>/dev/null || { fallos=$((fallos+1)); continue; }
        n_x=$((n_x+1))
    done < <(find "$d" -type f -perm /u+x,g+x,o+x -print0 2>/dev/null)

    printf "  %-18s dirs 777→775: %-6s archivos sin +x: %s\n" "$d" "$n_w" "$n_x"
    tot_w=$((tot_w+n_w)); tot_x=$((tot_x+n_x))
done

echo
if [ "$DRY" -eq 1 ]; then
    echo "  [DRY-RUN] Se corregirían $tot_w directorios escribibles por otros y $tot_x archivos con +x."
else
    echo "  Corregidos $tot_w directorios escribibles por otros y $tot_x archivos con +x."
fi
[ "$saltados" -gt 0 ] && echo "  Respetados $saltados ejecutables reales (shebang, ELF o bajo bin/)."
[ "$fallos" -gt 0 ]   && echo "  ⚠️  $fallos sin permiso para cambiar (¿hace falta sudo o el usuario correcto?)."
exit 0
