#!/usr/bin/env bash # STEP042B - Porting Presenze 215.6 # Audit veloce e mirato del calendario Silvelox: # messaggio "verificare se tutti i dati sono inseriti" # Server: 215.6 / ax-accessi # Modalita': AUDIT ONLY set -Eeuo pipefail umask 077 STEP_NAME="STEP042B_2156_SILVELOX_CALENDAR_VALIDATION_FAST_AUDIT_ONLY_VERIFIED_20260731" EXPECTED_HOST="${EXPECTED_HOST:-ax-accessi}" EXPECTED_IP_FRAGMENT="${EXPECTED_IP_FRAGMENT:-192.168.215.6}" TARGET_ROOT="${TARGET_ROOT:-/var/www/html/presenze.silvelox}" TARGET_DB="${TARGET_DB:-presenze_silvelox}" ALLOW_TEST="${ALLOW_TEST:-0}" START_TS="$(date +%Y%m%d_%H%M%S)" OUTPUT_ZIP="$PWD/${STEP_NAME}_${START_TS}.zip" WORKDIR="$(mktemp -d "$PWD/.${STEP_NAME}.XXXXXX")" REPORT="$WORKDIR/${STEP_NAME}_REPORT.txt" FILES_LIST="$WORKDIR/relevant_files.txt" MATCHES="$WORKDIR/validation_matches.txt" LOGS="$WORKDIR/recent_calendar_requests_errors.txt" SOURCE_DIR="$WORKDIR/source_extract" cleanup() { rm -rf -- "$WORKDIR" } trap cleanup EXIT INT TERM fail() { local rc=$? echo "ERRORE linea ${1:-?}, codice $rc" >&2 exit "$rc" } trap 'fail "$LINENO"' ERR say() { printf '%s\n' "$1" printf '\n[%s] %s\n' "$(date '+%H:%M:%S')" "$1" >> "$REPORT" } limited() { local seconds="$1" shift if command -v timeout >/dev/null 2>&1; then timeout --signal=TERM --kill-after=5s "${seconds}s" "$@" else "$@" fi } HOST_NOW="$(hostname 2>/dev/null || true)" IPS_NOW="$(hostname -I 2>/dev/null || true)" if [[ "$ALLOW_TEST" != "1" ]]; then if [[ "$HOST_NOW" != "$EXPECTED_HOST" && "$IPS_NOW" != *"$EXPECTED_IP_FRAGMENT"* ]]; then echo "ERRORE: server errato. Rilevato host='$HOST_NOW' IP='$IPS_NOW'; atteso 215.6 / ax-accessi." >&2 exit 10 fi [[ -d "$TARGET_ROOT" ]] || { echo "ERRORE: portale non trovato: $TARGET_ROOT" >&2 exit 11 } fi mkdir -p "$SOURCE_DIR" : > "$FILES_LIST" : > "$MATCHES" : > "$LOGS" { echo "$STEP_NAME" echo "DATA: $(date --iso-8601=seconds 2>/dev/null || date)" echo "SERVER: $HOST_NOW" echo "IP: $IPS_NOW" echo "TARGET: $TARGET_ROOT" echo "DATABASE: $TARGET_DB" echo "MODALITA': AUDIT ONLY" echo "NESSUNA MODIFICA A FILE, DATABASE O SERVIZI" } > "$REPORT" say "[1/7] Individuazione dei soli file attivi del calendario" ACTIVE_CAL="$TARGET_ROOT/components/templates/custom_templates/ax_attendance/ax_calendar" COMMON_CTRL="$TARGET_ROOT/components/a000_angular_app/ctrl/controllerCtrl.php" for file in \ "$TARGET_ROOT/ax_calendar.php" \ "$TARGET_ROOT/ax_new_calendar_event.php" \ "$COMMON_CTRL"; do [[ -f "$file" ]] && printf '%s\n' "$file" >> "$FILES_LIST" done if [[ -d "$ACTIVE_CAL" ]]; then limited 15 find "$ACTIVE_CAL" -xdev -type f \ \( -name '*.php' -o -name '*.js' -o -name '*.html' -o -name '*.tpl' -o -name '*.tpl.html' \) \ -size -2M -print 2>/dev/null >> "$FILES_LIST" || true fi # Solo template compilati recenti e piccoli, senza scandire l'intero albero. if [[ -d "$TARGET_ROOT/templates_c" ]]; then limited 10 find "$TARGET_ROOT/templates_c" -maxdepth 1 -type f \ -mtime -7 -size -1M -name '*.php' -print 2>/dev/null \ | head -n 150 >> "$FILES_LIST" || true fi sort -u "$FILES_LIST" -o "$FILES_LIST" FILE_COUNT="$(grep -c . "$FILES_LIST" 2>/dev/null || true)" echo "File mirati: $FILE_COUNT" >> "$REPORT" cat "$FILES_LIST" >> "$REPORT" say "[2/7] Ricerca della frase e delle condizioni di validazione" PATTERN='verificare.{0,100}(tutti|dati|inserit)|tutti.{0,100}dati|dati.{0,100}inserit|campi.{0,80}(obblig|required)|required|ng-required|[$]invalid|[$]error|undefined|null|empty[[:space:]]*[(]|isset[[:space:]]*[(]|trim[[:space:]]*[(]|alert[[:space:]]*[(]|swal|sweetalert|toastr|notify|message' while IFS= read -r file; do [[ -f "$file" ]] || continue limited 5 grep -nEi "$PATTERN" "$file" 2>/dev/null \ | head -n 500 \ | sed "s#^#$file:#" >> "$MATCHES" || true done < "$FILES_LIST" MATCH_COUNT="$(grep -c . "$MATCHES" 2>/dev/null || true)" { echo echo "OCCORRENZE VALIDAZIONE: $MATCH_COUNT" cat "$MATCHES" } >> "$REPORT" say "[3/7] Estrazione del codice attorno ai controlli trovati" CONTEXT="$WORKDIR/validation_context.txt" : > "$CONTEXT" while IFS=: read -r file line rest; do [[ -f "${file:-}" && "${line:-}" =~ ^[0-9]+$ ]] || continue start=$((line - 35)) (( start < 1 )) && start=1 end=$((line + 55)) { echo echo "===== $file | righe $start-$end | match $line =====" sed -n "${start},${end}p" "$file" 2>/dev/null | nl -ba -v "$start" } >> "$CONTEXT" || true done < <(head -n 120 "$MATCHES") cat "$CONTEXT" >> "$REPORT" say "[4/7] Analisi del payload e dell'endpoint di salvataggio" PAYLOAD="$WORKDIR/payload_endpoint_analysis.txt" : > "$PAYLOAD" while IFS= read -r file; do [[ -f "$file" ]] || continue { echo echo "===== $file =====" limited 5 grep -nEi \ '[$]http|ajax|fetch[[:space:]]*[(]|POST|PUT|save|salva|insert|update|controllerCtrl[.]php|data[[:space:]]*:|params[[:space:]]*:|ng-model|name=|cal_[A-Za-z_]+|php://input|json_decode|[$]_POST|REQUEST_METHOD' \ "$file" 2>/dev/null | head -n 800 || true } >> "$PAYLOAD" done < "$FILES_LIST" cat "$PAYLOAD" >> "$REPORT" say "[5/7] Ultime richieste reali del calendario e relativi errori" for log in \ /var/log/apache2/presenze.silvelox.axuno.it_access.log \ /var/log/apache2/presenze.silvelox.axuno.it_error.log \ /var/log/apache2/error.log \ /var/log/php5.6-fpm.log; do [[ -r "$log" ]] || continue { echo echo "===== $log =====" limited 8 tail -n 12000 "$log" 2>/dev/null \ | grep -Ei \ 'ax_calendar[.]php|ax_new_calendar_event[.]php|controllerCtrl[.]php|calendar|cal_|PHP (Fatal|Warning|Notice)|Uncaught|Exception|SQLSTATE|mysqli|PDO|invalid|required|missing|empty| 4[0-9][0-9] | 5[0-9][0-9] ' \ | tail -n 1200 || true } >> "$LOGS" done cat "$LOGS" >> "$REPORT" say "[6/7] Verifica read-only della tabella ax_calendar" MYSQL_BIN="$(command -v mariadb || command -v mysql || true)" { echo echo "===== SCHEMA ax_calendar =====" if [[ -n "$MYSQL_BIN" ]]; then limited 10 "$MYSQL_BIN" --batch --raw -e \ "SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT,EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='${TARGET_DB//\'/\'\'}' AND TABLE_NAME='ax_calendar' ORDER BY ORDINAL_POSITION;" 2>&1 || true echo echo "===== ULTIMI 10 RECORD ax_calendar =====" limited 10 "$MYSQL_BIN" --batch --raw -e \ "SELECT * FROM \`${TARGET_DB//\`/\`\`}\`.ax_calendar ORDER BY 1 DESC LIMIT 10;" 2>&1 || true else echo "Client MariaDB/MySQL non disponibile." fi } >> "$REPORT" say "[7/7] Copia dei soli sorgenti mirati e creazione ZIP" while IFS= read -r file; do [[ -f "$file" ]] || continue rel="${file#"$TARGET_ROOT"/}" if [[ "$rel" == "$file" ]]; then rel="external/$(basename "$file")" fi mkdir -p "$SOURCE_DIR/$(dirname "$rel")" cp -a -- "$file" "$SOURCE_DIR/$rel" done < "$FILES_LIST" { echo echo "RIEPILOGO" echo "File analizzati: $FILE_COUNT" echo "Occorrenze validazione: $MATCH_COUNT" echo "Audit terminato." echo "NESSUNA MODIFICA ESEGUITA" } >> "$REPORT" ( cd "$WORKDIR" zip -q -9 -r "$OUTPUT_ZIP" . \ -x '*.zip' ) zip -T "$OUTPUT_ZIP" >/dev/null echo "AUDIT COMPLETATO" echo "ZIP: $OUTPUT_ZIP"