#!/usr/bin/env bash # STEP046 - Porting Presenze 215.6 # # Audit mirato delle stampe Silvelox: # - utilizzo reale di stimulsoft_legacy; # - eventuali riferimenti misti a versioni non legacy; # - report MRT e impostazioni pagina/margini/orientamento; # - font richiesti e font disponibili sul server; # - asset JS/CSS/font mancanti; # - errori Apache/PHP recenti; # - permessi di cache e directory temporanee. # # Server atteso: 215.6 / ax-accessi # Modalita': AUDIT ONLY - nessuna modifica. set -Eeuo pipefail umask 077 STEP_NAME="STEP046_2156_SILVELOX_PRINT_LAYOUT_STIMULSOFT_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}" BASE_ROOT="${BASE_ROOT:-/var/www/html/presenze.distribuite}" TARGET_HOST="${TARGET_HOST:-presenze.silvelox.axuno.it}" ALLOW_TEST="${ALLOW_TEST:-0}" SKIP_HTTP="${SKIP_HTTP:-0}" SKIP_SYSTEM="${SKIP_SYSTEM:-0}" STAMP="$(date +%Y%m%d_%H%M%S)" OUTPUT_ZIP="$PWD/${STEP_NAME}_${STAMP}.zip" WORKDIR="$(mktemp -d "$PWD/.${STEP_NAME}.XXXXXX")" REPORT="$WORKDIR/${STEP_NAME}_REPORT.txt" REFERENCES="$WORKDIR/stimulsoft_references.txt" MRT_FILES="$WORKDIR/mrt_files.txt" MRT_SETTINGS="$WORKDIR/mrt_page_font_settings.txt" FONT_NAMES="$WORKDIR/mrt_font_names.txt" FONT_MATCH="$WORKDIR/font_matches.txt" LIB_FILES="$WORKDIR/legacy_library_files.txt" LIB_HASHES="$WORKDIR/legacy_library_hashes.txt" LIB_COMPARE="$WORKDIR/legacy_library_compare_with_base.txt" HTTP_CHECKS="$WORKDIR/http_checks.txt" ACCESS_LOGS="$WORKDIR/recent_print_access_requests.txt" ERROR_LOGS="$WORKDIR/recent_print_errors.txt" RECENT_FILES="$WORKDIR/recent_print_related_files.txt" PERMISSIONS="$WORKDIR/print_cache_permissions.txt" DB_REPORT_TABLES="$WORKDIR/report_related_database_tables.txt" SUMMARY="$WORKDIR/automatic_findings.txt" cleanup() { rm -rf -- "$WORKDIR" } trap cleanup EXIT INT TERM on_error() { local rc=$? local line="${1:-?}" printf 'ERRORE linea %s, codice %s\n' "$line" "$rc" >&2 exit "$rc" } trap 'on_error "$LINENO"' ERR section() { printf '\n\n================================================================\n%s\n================================================================\n' "$1" >> "$REPORT" } progress() { 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 } safe_grep_tree() { local root="$1" local pattern="$2" [[ -d "$root" ]] || return 0 limited 25 grep -RniIE \ --exclude-dir=.git \ --exclude-dir=node_modules \ --exclude-dir=bower_components \ --exclude-dir=vendor \ --exclude-dir=templates_c \ --exclude-dir=cache \ --exclude-dir=tmp \ --exclude='*.min.js' \ --exclude='*.map' \ --exclude='*.log' \ "$pattern" \ "$root" 2>/dev/null | head -n 8000 || true } 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 Silvelox non trovato: $TARGET_ROOT" >&2 exit 11 } fi for file in \ "$REFERENCES" "$MRT_FILES" "$MRT_SETTINGS" "$FONT_NAMES" \ "$FONT_MATCH" "$LIB_FILES" "$LIB_HASHES" "$LIB_COMPARE" \ "$HTTP_CHECKS" "$ACCESS_LOGS" "$ERROR_LOGS" "$RECENT_FILES" \ "$PERMISSIONS" "$DB_REPORT_TABLES" "$SUMMARY"; do : > "$file" done { echo "$STEP_NAME" echo "DATA: $(date --iso-8601=seconds 2>/dev/null || date)" echo "SERVER: $HOST_NOW" echo "IP: $IPS_NOW" echo "PORTALE: $TARGET_ROOT" echo "BASE CONFRONTO: $BASE_ROOT" echo "HOST: $TARGET_HOST" echo "MODALITA': AUDIT ONLY" echo "NESSUNA MODIFICA A FILE, DATABASE O SERVIZI" } > "$REPORT" progress "[1/9] Runtime, librerie Stimulsoft e riferimenti attivi" section "Runtime" if [[ "$SKIP_SYSTEM" == "1" ]]; then echo "Controlli runtime saltati in ambiente simulato." >> "$REPORT" else { php5.6 -v 2>/dev/null || php -v 2>/dev/null || true apache2ctl -v 2>/dev/null || true convert -version 2>/dev/null | head -n 5 || true gs --version 2>/dev/null || true wkhtmltopdf --version 2>/dev/null || true fc-list --version 2>/dev/null || true } >> "$REPORT" 2>&1 fi LEGACY_DIR="$TARGET_ROOT/libs/stimulsoft_legacy" section "Stato directory Stimulsoft" { for path in \ "$LEGACY_DIR" \ "$TARGET_ROOT/libs/stimulsoft" \ "$TARGET_ROOT/libs/stimulsoft_reports" \ "$TARGET_ROOT/libs/stimulsoft-viewer" \ "$BASE_ROOT/libs/stimulsoft_legacy"; do if [[ -e "$path" || -L "$path" ]]; then ls -ld "$path" readlink -f "$path" 2>/dev/null || true else echo "ASSENTE: $path" fi done } >> "$REPORT" 2>&1 if [[ -d "$LEGACY_DIR" ]]; then limited 20 find "$LEGACY_DIR" -xdev -type f -size -15M \ \( -name '*.php' -o -name '*.js' -o -name '*.css' \ -o -name '*.json' -o -name '*.woff' -o -name '*.woff2' \ -o -name '*.ttf' -o -name '*.svg' \) \ -printf '%s\t%TY-%Tm-%Td %TH:%TM:%TS\t%p\n' 2>/dev/null \ | sort -k3,3 > "$LIB_FILES" || true while IFS=$'\t' read -r size modified file; do [[ -f "${file:-}" ]] || continue case "$file" in */viewer.php|*/designer.php|*/stimulsoft*.js|*/stimulsoft*.css|*/license*.php|*/config*.php) sha256sum "$file" 2>/dev/null || true ;; esac done < "$LIB_FILES" > "$LIB_HASHES" fi safe_grep_tree "$TARGET_ROOT" \ 'stimulsoft_legacy|libs/stimulsoft|viewer[.]php|designer[.]php|[.]mrt([?"'\''[:space:]]|$)|StiViewer|StiReport|Stimulsoft' \ > "$REFERENCES" cat "$REFERENCES" >> "$REPORT" progress "[2/9] Ricerca mirata dei report MRT e delle impostazioni di pagina" SEARCH_DIRS=( "$TARGET_ROOT/components/templates/custom_templates/ax_attendance/ax_schede_presenze_modA" "$TARGET_ROOT/components/templates/custom_templates/ax_attendance/ax_schede_presenze_modB" "$TARGET_ROOT/components/templates/custom_templates" "$TARGET_ROOT/reports" "$TARGET_ROOT/report" "$TARGET_ROOT/mrt" ) for dir in "${SEARCH_DIRS[@]}"; do [[ -d "$dir" ]] || continue limited 20 find "$dir" -xdev -type f -size -8M \ \( -iname '*.mrt' -o -iname '*.mrz' -o -iname '*.xml' \) \ -print 2>/dev/null || true done | sort -u > "$MRT_FILES" MRT_COUNT="$(grep -c . "$MRT_FILES" 2>/dev/null || true)" { echo "REPORT MRT/XML TROVATI: $MRT_COUNT" while IFS= read -r file; do [[ -f "$file" ]] || continue stat -c '%s %y %n' "$file" sha256sum "$file" done < "$MRT_FILES" } >> "$REPORT" 2>&1 while IFS= read -r file; do [[ -f "$file" ]] || continue { echo echo "===== $file =====" limited 8 grep -nEi \ 'ReportUnit|PageWidth|PageHeight|PaperSize|Orientation|Margins|LeftMargin|RightMargin|TopMargin|BottomMargin|SegmentPerWidth|SegmentPerHeight|UnlimitedHeight|UnlimitedWidth|Zoom|Font|FontName|FontFamily|TextQuality|ImageQuality|UseParentStyles|Printable|PrintOn|Columns|ColumnWidth|ColumnGaps' \ "$file" 2>/dev/null | head -n 1000 || true } >> "$MRT_SETTINGS" limited 8 grep -Eio \ '(Font(Name|Family)?[="'\'': >]+|]*>|font-family[[:space:]]*:[[:space:]]*)[A-Za-z0-9 _.,-]+' \ "$file" 2>/dev/null \ | sed -E \ -e 's/^[^=:>]*[=:>][[:space:]"'\'']*//' \ -e 's/[,"'\''].*$//' \ -e 's/[<].*$//' \ -e 's/^[[:space:]]+//' \ -e 's/[[:space:]]+$//' \ | grep -E '.{2,80}' || true done < "$MRT_FILES" | sort -fu > "$FONT_NAMES" cat "$MRT_SETTINGS" >> "$REPORT" progress "[3/9] Verifica dei font richiesti dai report" if [[ "$SKIP_SYSTEM" == "1" ]]; then while IFS= read -r font; do [[ -n "$font" ]] || continue printf '%s\tSIMULATED_FONT_MATCH\n' "$font" done < "$FONT_NAMES" > "$FONT_MATCH" elif command -v fc-match >/dev/null 2>&1; then while IFS= read -r font; do [[ -n "$font" ]] || continue match="$(limited 5 fc-match -f '%{family}|%{file}\n' "$font" 2>/dev/null | head -n 1 || true)" printf '%s\t%s\n' "$font" "${match:-NESSUNA CORRISPONDENZA}" done < "$FONT_NAMES" > "$FONT_MATCH" { echo echo "===== FONT DI RIFERIMENTO =====" for font in \ Arial "Arial Narrow" Calibri "Times New Roman" \ "Courier New" Tahoma Verdana "DejaVu Sans" \ "Liberation Sans"; do printf '%s\t' "$font" limited 5 fc-match -f '%{family}|%{file}\n' "$font" 2>/dev/null \ | head -n 1 || true done } >> "$FONT_MATCH" else echo "fc-match non disponibile." > "$FONT_MATCH" fi cat "$FONT_MATCH" >> "$REPORT" progress "[4/9] Controllo versioni miste e confronto libreria con la base" { echo "===== VERSIONI E STRINGHE IDENTIFICATIVE =====" while IFS=$'\t' read -r size modified file; do [[ -f "${file:-}" ]] || continue case "$file" in *.php|*.js|*.json) limited 5 grep -nEim 8 \ 'Stimulsoft Reports|Stimulsoft.*Version|version[[:space:]]*[:=]|ProductVersion|fileVersion|build' \ "$file" 2>/dev/null \ | sed "s#^#$file:#" || true ;; esac done < "$LIB_FILES" } >> "$REPORT" if [[ -d "$LEGACY_DIR" && -d "$BASE_ROOT/libs/stimulsoft_legacy" ]]; then limited 30 diff -qr \ "$LEGACY_DIR" \ "$BASE_ROOT/libs/stimulsoft_legacy" \ 2>/dev/null | head -n 5000 > "$LIB_COMPARE" || true else echo "Confronto non disponibile: una delle due directory legacy e' assente." > "$LIB_COMPARE" fi cat "$LIB_COMPARE" >> "$REPORT" progress "[5/9] File di stampa modificati recentemente" for dir in \ "$TARGET_ROOT/components/templates/custom_templates/ax_attendance/ax_schede_presenze_modA" \ "$TARGET_ROOT/components/templates/custom_templates/ax_attendance/ax_schede_presenze_modB" \ "$TARGET_ROOT/libs/stimulsoft_legacy"; do [[ -d "$dir" ]] || continue limited 15 find "$dir" -xdev -type f -mtime -120 -size -15M \ -printf '%TY-%Tm-%Td %TH:%TM:%TS\t%s\t%p\n' 2>/dev/null || true done | sort -r | head -n 5000 > "$RECENT_FILES" cat "$RECENT_FILES" >> "$REPORT" progress "[6/9] Permessi cache, temporanei e directory di esportazione" { for path in \ "$TARGET_ROOT/templates_c" \ "$TARGET_ROOT/cache" \ "$TARGET_ROOT/tmp" \ "$TARGET_ROOT/temp" \ "$TARGET_ROOT/libs/stimulsoft_legacy" \ "$TARGET_ROOT/libs/stimulsoft_legacy/cache" \ "$TARGET_ROOT/libs/stimulsoft_legacy/temp" \ "$TARGET_ROOT/libs/stimulsoft_legacy/tmp" \ /tmp; do if [[ -e "$path" || -L "$path" ]]; then stat -c '%A %a %U:%G %s %y %n' "$path" 2>/dev/null || true if [[ -d "$path" ]]; then limited 8 find "$path" -maxdepth 1 -type f \ -printf '%A %m %u:%g %s %TY-%Tm-%Td %TH:%TM:%TS %p\n' \ 2>/dev/null | tail -n 100 || true fi else echo "ASSENTE: $path" fi done } > "$PERMISSIONS" cat "$PERMISSIONS" >> "$REPORT" progress "[7/9] Richieste HTTP ed errori recenti delle stampe" if [[ "$SKIP_SYSTEM" == "1" ]]; then echo "Log di sistema saltati in ambiente simulato." > "$ACCESS_LOGS" echo "Log di sistema saltati in ambiente simulato." > "$ERROR_LOGS" else for log in \ /var/log/apache2/presenze.silvelox.axuno.it_access.log \ /var/log/apache2/*silvelox*access*.log \ /var/log/apache2/access.log; do [[ -r "$log" ]] || continue { echo echo "===== $log =====" limited 10 tail -n 50000 "$log" 2>/dev/null \ | grep -Ei \ 'stimulsoft|viewer[.]php|designer[.]php|[.]mrt([?[:space:]]|$)|ax_schede_presenze|export|print|font|[.]woff2?|[.]ttf|[.]css|[.]js' \ | tail -n 5000 || true } >> "$ACCESS_LOGS" done for log in \ /var/log/apache2/presenze.silvelox.axuno.it_error.log \ /var/log/apache2/*silvelox*error*.log \ /var/log/apache2/error.log \ /var/log/php5.6-fpm.log; do [[ -r "$log" ]] || continue { echo echo "===== $log =====" limited 10 tail -n 30000 "$log" 2>/dev/null \ | grep -Ei \ 'stimulsoft|viewer[.]php|designer[.]php|[.]mrt|ax_schede_presenze|font|export|print|PHP (Fatal|Warning|Notice)|Uncaught|Exception|404|500|permission denied|not found|failed' \ | tail -n 5000 || true } >> "$ERROR_LOGS" done fi cat "$ACCESS_LOGS" >> "$REPORT" cat "$ERROR_LOGS" >> "$REPORT" progress "[8/9] Test HTTP locale e tabelle DB correlate ai report" if [[ "$ALLOW_TEST" == "1" || "$SKIP_HTTP" == "1" ]]; then echo "Test HTTP saltato in ambiente simulato." > "$HTTP_CHECKS" elif command -v curl >/dev/null 2>&1; then URLS=( "/" "/libs/stimulsoft_legacy/viewer.php" "/libs/stimulsoft_legacy/designer.php" ) while IFS= read -r core_asset; do [[ -n "$core_asset" ]] || continue rel="${core_asset#"$TARGET_ROOT"}" URLS+=("$rel") break done < <( limited 10 find "$LEGACY_DIR" -xdev -type f \ \( -iname 'stimulsoft*.js' -o -iname 'stimulsoft*.css' \) \ -size -10M -print 2>/dev/null | sort ) for url in "${URLS[@]}"; do body="$WORKDIR/http_$(echo "$url" | tr '/?&=' '____').body" meta="$( curl -sS --max-time 20 \ -H "Host: $TARGET_HOST" \ -o "$body" \ -w '%{http_code}|%{content_type}|%{size_download}|%{url_effective}' \ "http://127.0.0.1$url" 2>&1 || true )" printf '%s\t%s\n' "$url" "$meta" done > "$HTTP_CHECKS" else echo "curl non disponibile." > "$HTTP_CHECKS" fi MYSQL_BIN="$(command -v mariadb || command -v mysql || true)" if [[ -n "$MYSQL_BIN" && "$SKIP_SYSTEM" != "1" ]]; then limited 15 "$MYSQL_BIN" --batch --raw --skip-column-names -e \ "SELECT TABLE_SCHEMA,TABLE_NAME,ENGINE,TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA='presenze_silvelox' AND ( TABLE_NAME LIKE '%report%' OR TABLE_NAME LIKE '%stimul%' OR TABLE_NAME LIKE '%print%' OR TABLE_NAME LIKE '%stamp%' ) ORDER BY TABLE_NAME;" \ > "$DB_REPORT_TABLES" 2>&1 || true else echo "Controllo tabelle DB non disponibile o saltato." > "$DB_REPORT_TABLES" fi cat "$HTTP_CHECKS" >> "$REPORT" cat "$DB_REPORT_TABLES" >> "$REPORT" progress "[9/9] Riepilogo automatico e creazione ZIP" LEGACY_REF_COUNT="$(grep -Eic 'stimulsoft_legacy' "$REFERENCES" 2>/dev/null || true)" NONLEGACY_REF_COUNT="$( grep -Ei 'libs/stimulsoft(/|["'\''])|libs/stimulsoft_reports|libs/stimulsoft-viewer' \ "$REFERENCES" 2>/dev/null \ | grep -Eiv 'stimulsoft_legacy' \ | wc -l || true )" HTTP_BAD_COUNT="$(grep -Ec $'\t(4|5)[0-9][0-9][|]' "$HTTP_CHECKS" 2>/dev/null || true)" LOG_404_COUNT="$(grep -Eic ' 404 |404|not found' "$ACCESS_LOGS" "$ERROR_LOGS" 2>/dev/null || true)" FONT_COUNT="$(grep -c . "$FONT_NAMES" 2>/dev/null || true)" DIFF_COUNT="$(grep -c . "$LIB_COMPARE" 2>/dev/null || true)" { echo "MRT/XML trovati: $MRT_COUNT" echo "Font distinti estratti: $FONT_COUNT" echo "Riferimenti stimulsoft_legacy: $LEGACY_REF_COUNT" echo "Riferimenti potenzialmente non legacy: $NONLEGACY_REF_COUNT" echo "Risposte HTTP 4xx/5xx nei test locali: $HTTP_BAD_COUNT" echo "Occorrenze 404/not found nei log raccolti: $LOG_404_COUNT" echo "Differenze inventario legacy rispetto alla base: $DIFF_COUNT" echo echo "ATTENZIONE: questi conteggi sono indicatori da confermare leggendo il report." echo "ESITO: AUDIT COMPLETATO" echo "NESSUNA MODIFICA ESEGUITA" } > "$SUMMARY" cat "$SUMMARY" >> "$REPORT" ( cd "$WORKDIR" zip -q -9 "$OUTPUT_ZIP" \ "$(basename "$REPORT")" \ "$(basename "$REFERENCES")" \ "$(basename "$MRT_FILES")" \ "$(basename "$MRT_SETTINGS")" \ "$(basename "$FONT_NAMES")" \ "$(basename "$FONT_MATCH")" \ "$(basename "$LIB_FILES")" \ "$(basename "$LIB_HASHES")" \ "$(basename "$LIB_COMPARE")" \ "$(basename "$HTTP_CHECKS")" \ "$(basename "$ACCESS_LOGS")" \ "$(basename "$ERROR_LOGS")" \ "$(basename "$RECENT_FILES")" \ "$(basename "$PERMISSIONS")" \ "$(basename "$DB_REPORT_TABLES")" \ "$(basename "$SUMMARY")" ) zip -T "$OUTPUT_ZIP" >/dev/null echo "STEP046 COMPLETATO" echo "ZIP: $OUTPUT_ZIP"