Changelog
Tutte le versioni di SoccorsoWP Connect, dalla più recente. Novità, miglioramenti e aggiornamenti di sicurezza.
Sistema di aggiornamento self-hosted completo e sicuro. Il plugin si aggiorna da SoccorsoWP come un normale plugin WordPress (header Update URI, nessun conflitto con WordPress.org), verifica il checksum SHA-256 di ogni pacchetto prima di installarlo, firma le richieste di aggiornamento col secret del sito (HMAC), installa automaticamente le sole release di sicurezza e ripristina la versione precedente se un aggiornamento non va a buon fine.
Backup Iter 2 (Fase 2A): incrementale reale. Il full genera una baseline (rel/mtime/size) promossa a .baseline solo a full riuscito. Nuova action backup.incremental.build: archivia solo i file cambiati rispetto alla baseline + DB intero + lista file cancellati (.soccorsowp-deleted.json, per il restore a catena), poi aggiorna la baseline (catena "vs ultimo"). fallback_full se baseline assente; dry_run per contare senza costruire nulla. Restore a catena = Fase 2B.
Backup: esclusioni intelligenti dei file (helper backup_exclude_dirs/ backup_should_exclude). Fuori dal backup vanno cache (wp-content/cache, uploads/cache, litespeed, et-cache), temporanei WP (upgrade, upgrade-temp-backup), node_modules/.git ovunque, log rumorosi (debug.log/error_log) e archivi di ALTRI plugin di backup (updraft, ai1wm, wpvivid, duplicator, backupwordpress). Vale per full monolitico, full chunked (manifest) e incrementale. Su siti con centinaia di migliaia di file riduce numero file e peso dello zip → build più corto. Estendibile via params exclude_extra o filtro soccorsowp_backup_exclude.
Upload FTP a blocchi via cURL (fix 504): backup.full.upload_step carica lo zip in blocchi da 16MB con APPE (append); l'offset autoritativo è la SIZE remota (probe NOBODY), così una coda parziale di un blocco fallito si auto-corregge. Il timeout di ogni blocco è legato al budget residuo → nessuna chiamata supera il timeout del gateway. Il precedente ftp_nb_put/ftp_nb_continue NON rispettava il deadline (un singolo continue poteva bloccare oltre il gateway su FTP lento → HTTP 504) e poteva andare in livelock sulla coda del file. (0.20.2 usava STOR+REST ma CURLOPT_*_LARGE/SEEKFUNCTION non sono definite su questo build cURL → APPE non le richiede.)
Dump DB in streaming (memoria piatta): la esportazione del database usa una query UNBUFFERED (MYSQLI_USE_RESULT) e scrive riga per riga invece di caricare l'intera tabella in RAM. backup.full.begin non abbassa più memory_limit a 512M. Senza, i siti con tabelle grandi (es. postmeta con centinaia di migliaia di righe) andavano in fatal (HTTP 500) sul begin. Fallback bufferizzato solo per driver DB non-mysqli.
Backup asincrono resumable (scalabilità, PLAN-BACKUP-FASE2): l'upload non avviene più in un'unica chiamata HTTP (causa dei 504 Gateway Timeout sui siti grandi). Nuova azione backup.full.upload_step: carica lo zip a blocchi time-boxed e resumable — FTP via ftp_nb_put con startpos (resume nativo, offset riletto da ftp_size), Google Drive via PUT Content-Range sulla sessione resumable. Nuova azione backup.full.status (snapshot read-only per polling). backup.full.finish diventa un finalize sottile (unlink locale + cleanup) con fallback single-shot per compat/S3. Nessuna singola chiamata al worker è più lunga → nessun timeout gateway.
Hardening sicurezza (audit 27/06, Fase 2): #1 archivi di backup non più indovinabili dal web: nome con suffisso random a 24 char (full_backup_<ts>_<rand>.zip), index.php nella cartella backup (anti directory-listing) e reaper degli archivi/job orfani >24h (filtro soccorsowp_backup_local_ttl); #2 clone.export azzera soccorsowp_communication_secret nel dump (non esporre il secret in un archivio servito via token pubblico); #3 allowlist IP basata su REMOTE_ADDR; gli header X-Forwarded-For / X-Real-IP / CF-Connecting-IP sono onorati solo dietro un proxy fidato (opzione soccorsowp_trusted_proxies) — niente più bypass via header; #5 anti-replay idempotente: un nonce già elaborato riceve la STESSA risposta cachata invece di un 401 (che il client leggeva come auth fallita → auto-rollback indebito su visual.update); backup.restore: guardia zip-slip, rifiuta archivi con entry "../" o path assoluti prima di estrarre dentro ABSPATH.
updates.execute bonifica la rollback dir di WP 6.3+: se wp-content/upgrade-temp-backup/{plugins,themes} esiste, è vuota e non scrivibile dall'utente PHP (subdir root-owned residua), la rimuove così WP la ricrea con l'owner giusto. Senza, l'update abortiva con "Could not move the old version to the upgrade-temp-backup directory".
Hardening sicurezza (audit medium): clone.import deserializza con allowed_classes=false (no object injection da dump di siti terzi, M6); anti-SSRF is_safe_remote_url valida tutti i record A+AAAA, non solo IPv4 (M9); download_authenticated (restore Drive) disabilita i redirect e pinna l'IP validato con CURLOPT_RESOLVE contro il DNS-rebinding (M7); dump DB emette i valori binari come letterale esadecimale 0x... per un round-trip fedele al restore (M8).
debug.toggle non scrive più un backup wp-config.php.soccorsowp-bak nella web root (avrebbe potuto esporre credenziali/salt se servito come testo); la validazione token_get_all(TOKEN_PARSE) prima della scrittura resta la garanzia contro un wp-config.php rotto.
debug.toggle / debug.status: attiva/disattiva il debug di WordPress da remoto modificando wp-config.php. All'attivazione usa il profilo sicuro (WP_DEBUG + WP_DEBUG_LOG, ma WP_DEBUG_DISPLAY=false: errori non mostrati ai visitatori). La modifica è validata con token_get_all(TOKEN_PARSE) prima di scrivere; errore esplicito se wp-config.php non è scrivibile.
Backup su Google Drive: backup.full/incremental/full.finish accettano il param gdrive.session_url (sessione di upload resumable aperta dal CRM) e caricano l'archivio via PUT in streaming, restituendo gdrive_id. backup.restore accetta download_auth per il download autenticato (Authorization: Bearer) dall'endpoint media di Drive.
security.scan, integrità core senza falso positivo su version.php: wp-includes/version.php è l'unico file core che cambia tra i pacchetti localizzati ($wp_local_package), quindi il suo checksum non torna quando il locale del sito non coincide col package installato (sito integro segnalato come "compromesso"). Ora non se ne confronta il md5 ma se ne verifica il contenuto (deve dichiarare $wp_version ed essere privo di pattern di codice sospetto).
security.scan, rilevamento PHP in uploads più preciso: la cache legittima dei plugin (WPML/Twig, Divi et-cache, fw_files) e gli index.php di silenzio non fanno più scattare l'allarme integrità (meno falsi positivi). I file davvero sospetti vengono ispezionati per pattern di webshell/offuscamento (eval/gzinflate/shell_exec/ preg_replace /e…): se presenti la severità sale a "critical".
security.scan: finding strutturati. Ogni problema ora ha code (id stabile), category (configurazione/accesso/integrità/esposizione/ trasporto), severity a 5 livelli (critical/high/medium/low/info), remediation dal worker e details (elementi coinvolti). Il risk_level è calcolato con scoring pesato per severità invece del conteggio. Nuovi controlli di hardening (introspettivi, niente HTTP loopback): DISALLOW_FILE_EDIT, salt/chiavi deboli o di default, prefisso DB wp_, PHP a fine supporto, XML-RPC attivo, core non aggiornato, plugin/temi con update in sospeso, plugin installati ma disattivati.
Hardening audit (batch Low): /execute risponde 401 generico anche quando il secret non è configurato (anti-enumerazione); cleanup DB rimuove anche le righe-valore dei transient scaduti (non più solo i timeout, niente orfani); l'auto-updater valida la versione remota prima di version_compare; i webhook di eventi critici (update/ attivazioni) sono inviati in modo bloccante con retry e last_webhook_at è aggiornato solo su consegna 2xx confermata.
clone.export non lascia più archivi orfani: il file viene rinominato con prefisso clone_export_, cancellato subito dopo il download (monouso) e uno sweep rimuove gli export abbandonati più vecchi di 2h.
updates.execute non maschera più i fallimenti: oltre a WP_Error rileva anche il false/null di Plugin_Upgrader::upgrade() (es. copia file non riuscita per permessi) e gli errori dello skin. Guard anti-SSRF (is_safe_remote_url) su download_url in backup.restore e clone.import, + guard anti zip-slip sulle entry di clone.import.
Sicurezza anti-replay: /execute valida ora il timestamp FIRMATO (non più l'header non firmato) e rifiuta i nonce già visti (transient). I webhook includono un nonce firmato per la dedup lato CRM. L'auto-updater fa host-pinning di download_url sull'host del CRM. (Allinea anche la costante versione, rimasta indietro a 0.11.1: i siti ricevono così anche le feature 0.12.x — Code Snippets/Strumenti.)
snippets.run ritorna sempre HTTP 200 (success a livello trasporto); l'esito dello snippet è in data.ok + data.error. Prima un errore dello snippet → success:false → HTTP 400 e il CRM perdeva il messaggio d'errore reale.
snippets.run accetta il codice in base64 (param code_b64) per evitare che i WAF server-side (ModSecurity/Imunify) blocchino i body con pattern SQL/PHP (davano HTTP 400). Fallback al campo 'code' in chiaro.
snippets.run: esecuzione di codice PHP o SQL arbitrario sul sito (cattura output/return/errori; SQL read → righe, write → affected). Protetto da HMAC; lato CRM riservato a super_admin + audit. Feature "Strumenti" (Code Snippets bulk stile ManageWP).
backup.restore robusto: prima il valore di ritorno di extractTo() era ignorato → un solo file non scrivibile fermava l'estrazione lasciando il sito non ripristinato, ma il restore riportava comunque "successo". Ora: se l'extractTo in blocco fallisce si estrae file-per-file CONTINUANDO sugli errori (con diagnostica: quali file e perché), e se non si estrae nulla si ritorna errore. Aggiunto flush cache plugin/temi + transient update dopo il restore (le versioni riportate erano stale).
Backup full CHUNKED asincrono: backup.full.begin/step/finish/abort. Il CRM orchestra la costruzione dello zip in più richieste HTTP, ognuna sotto il timeout di PHP-FPM (~120s), per i siti dove il full sincrono veniva ucciso. Stato in option soccorsowp_bkjob_<id> + manifest su file.
Export DB streaming per-tabella su file (un SELECT per tabella, RAM liberata dopo ciascuna): niente più dump intero in memoria, senza la paginazione OFFSET di 0.10.3 che era quadratica e mandava in timeout il backup su DB con tabelle grandi. Vale per full e incremental.
(sostituita da 0.10.4) Export DB a blocchi LIMIT/OFFSET — troppo lenta.
backup.full/incremental: dopo upload riuscito su storage remoto (FTP o S3) la copia locale viene cancellata (niente accumulo sul sito). backup.restore: ripristino da FTP (scarica l'archivio dal server FTP con credenziali + ftp_path passati dal CRM).
backup.list / backup.delete: elenco e cancellazione dei backup .zip locali nella cartella uploads/soccorsowp-backups (con guardia anti path-traversal: solo .zip dentro la cartella). Permette di liberare spazio dai backup pre-update accumulati.
Backup su cloud S3-compatibile: backup.full/incremental accettano un URL presigned (param s3.put_url) e caricano l'archivio via PUT in streaming. backup.restore accetta download_url per ripristinare da cloud.
clone.export / clone.import: clonazione di un sito gestito su un altro. L'origine espone l'archivio via URL con token monouso; la destinazione lo importa, riscrive prefisso tabelle e URL (serialize-safe) e preserva il proprio secret di comunicazione. Download via ?soccorsowp_clone_download.
maintenance.toggle: modalità manutenzione persistente gestita dal worker (opzione + guard template_redirect 503) al posto del file .maintenance core. Risolve: scadenza 10 min, blocco dell'endpoint REST, bypass della cache (purge automatico FlyingPress/altri all'attivazione).
woocommerce.stats: categorie principali per fatturato. analytics.stats: breakdown referrer/browser/pagine/paesi + delta % vs periodo precedente. security.scan: scansione malware (integrità core via checksum WordPress.org + PHP in uploads).
woocommerce.stats, analytics.stats (Site Kit), server_ip nel metadata.
