File: //remove_htaccess_hacked/remove_specific_block.sh
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# Modalità: dry (mostra quali file verrebbero modificati) o apply (applica, crea .bak)
MODE="${1:-dry}" # uso: ./remove_specific_block.sh [dry|apply]
# Regex Perl (case-insensitive, dot matches newline)
# - individua <FilesMatch ...>...</FilesMatch>
# - verifica che l'apertura contenga la sequenza .(py|exe|php|...|suspected)$ (qualsiasi case)
# - verifica che il corpo contenga la riga "Deny from all" (qualsiasi case, spazi tollerati)
PERL_EXPR='
use strict;
use warnings;
local $/ = undef;
$_ = <>; # slurp file
s/\r\n?/\n/g; # normalizza EOL
my $before = $_;
my $removed = 0;
# cerca tutti i blocchi <FilesMatch ...>...</FilesMatch>
while (/<FilesMatch\b([^>]*)>(.*?)<\/FilesMatch>/igs) {
my $attrs = $1;
my $inner = $2;
my $hay = lc($attrs . " " . $inner);
if ( $hay =~ qr/\\.\(py\\|exe\\|php\\|php7\\|php5\\|suspected\)\$?/i || $hay =~ qr/\\.\(py\\|exe\\|php/ ) {
if ( $hay =~ /deny\s+from\s+all/ ) {
# rimuovi l'esatta occorrenza (case-insensitive)
my $full = $&; # l'ultima corrispondenza del while non sempre qui, quindi ricostruiamo
# ricostruiamo il blocco esatto e rimuoviamolo con quotemeta
my $open = "<FilesMatch$attrs>";
my $block = $open . $inner . "</FilesMatch>";
# rimuovi la prima occorrenza di questo blocco (case-insensitive)
$_ =~ s/\Q$block\E//is;
$removed++;
}
}
}
# collassa righe vuote multiple e assicura newline finale
s/\n{3,}/\n\n/g;
$_ .= "\n" unless $_ =~ /\n\z/;
if ($removed) {
print $_;
exit 0;
} else {
exit 1;
}
'
# Trova .htaccess (gestisce nomi con spazi)
mapfile -d '' FILES < <(find . -type f -name ".htaccess" -print0)
if [ "${#FILES[@]}" -eq 0 ]; then
echo "Nessun file .htaccess trovato."
exit 0
fi
echo "Trovati ${#FILES[@]} file .htaccess. Modalità: $MODE"
for f in "${FILES[@]}"; do
tmp="$(mktemp)"
# esegui il perl sul file; perl restituisce 0 se ha scritto output (rimozione)
if perl -0777 -e "$PERL_EXPR" "$f" > "$tmp" 2>/dev/null; then
if cmp -s "$f" "$tmp"; then
rm -f "$tmp"
echo "Nessuna modifica per: $f"
continue
fi
if [ "$MODE" = "dry" ]; then
echo "=== DRY diff per $f ==="
diff -u --label "orig: $f" --label "new: $f.new" "$f" "$tmp" | sed -n '1,200p' || true
echo "=== fine diff ==="
rm -f "$tmp"
else
cp --preserve=mode,timestamps "$f" "$f.bak"
mv "$tmp" "$f"
echo "Aggiornato: $f (backup: $f.bak)"
fi
else
rm -f "$tmp"
echo "No match nel file: $f"
fi
done
echo "Operazione completata."
exit 0