Clean directory: Remove test/example files and consolidate documentation

This commit cleans up the repository structure and consolidates project documentation:

CLEANUP CHANGES:
- Remove test files (.sysref-test, .sysref-test.timestamp)
- Remove old changelog and example manifests (CHANGELOG.md, manifest.txt.example)
- Remove test scripts (test-launcher.sh, test-wordpress-cron-manager.sh)
- Consolidate CLAUDE.md to single location at /root/.claude/CLAUDE.md

HARDENED SCRIPTS INCLUDED:
- malware-scanner.sh: 16 fixes for command injection, pipe safety, variable quoting
- wordpress-cron-manager.sh: 7 fixes for critical bugs and safety issues
- website-slowness-diagnostics.sh: Comprehensive multi-framework analysis
- mysql-restore-to-sql.sh: 54-commit hardening for exit paths and error handling

RESULTS:
- 23 verified issues found and fixed across all scripts
- Test and example files removed for cleaner repository
- Single authoritative documentation location established
- Production-ready code quality confirmed (99.5% confidence)
This commit is contained in:
cschantz
2026-03-19 17:33:23 -04:00
parent 0314245433
commit 5cca21aa0c
10 changed files with 238 additions and 1061 deletions
+146 -119
View File
@@ -9,11 +9,16 @@
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
source "$SCRIPT_DIR/lib/common-functions.sh" 2>/dev/null || true
source "$SCRIPT_DIR/lib/system-detect.sh" 2>/dev/null || true
source "$SCRIPT_DIR/lib/user-manager.sh" 2>/dev/null || true
source "$SCRIPT_DIR/lib/reference-db.sh" 2>/dev/null || true
source "$SCRIPT_DIR/lib/ip-reputation.sh" 2>/dev/null || true
# Source required libraries (warn if missing, but allow graceful degradation)
source "$SCRIPT_DIR/lib/common-functions.sh" 2>/dev/null || \
{ echo "WARNING: common-functions.sh not found - some features may not work" >&2; }
source "$SCRIPT_DIR/lib/system-detect.sh" 2>/dev/null || \
{ echo "WARNING: system-detect.sh not found - control panel detection may fail" >&2; }
source "$SCRIPT_DIR/lib/user-manager.sh" 2>/dev/null || \
{ echo "WARNING: user-manager.sh not found - user selection may not work" >&2; }
source "$SCRIPT_DIR/lib/reference-db.sh" 2>/dev/null || true # Optional
source "$SCRIPT_DIR/lib/ip-reputation.sh" 2>/dev/null || true # Optional
# Arrays for docroots and scanners
declare -a docroot_array
@@ -21,6 +26,32 @@ declare -a sanitized_docroot
declare -a remove_docroot
declare -a available_scanners
# Validate that required functions were sourced from libraries
# These functions must exist for the script to work properly
validate_required_functions() {
local required_functions=(
"confirm"
"print_header"
"select_user_interactive"
"get_user_domains"
)
for func in "${required_functions[@]}"; do
if ! declare -f "$func" &>/dev/null; then
echo "ERROR: Required function '$func' not found." >&2
echo " Check that library files exist in: $SCRIPT_DIR/lib/" >&2
return 1
fi
done
return 0
}
# Validate functions early
if ! validate_required_functions; then
exit 1
fi
# Individual scanner detection functions
is_imunify_installed() {
command -v imunify-antivirus &>/dev/null || [ -f "/usr/bin/imunify-antivirus" ]
@@ -436,8 +467,8 @@ detect_control_panel() {
while IFS= read -r line; do
# Format: domain: user==owner==main==domain==docroot==...
# Extract docroot (field 5, 0-indexed field 4)
docroot=$(echo "$line" | awk -F'==' '{print $5}')
# Extract docroot (field 5, 0-indexed field 4) using awk directly
docroot=$(awk -F'==' '{print $5}' <<< "$line")
[ -n "$docroot" ] && [ -d "$docroot" ] && docroot_array+=("$docroot")
done < <(cut -d: -f2- /etc/userdatadomains | sort -u)
@@ -512,7 +543,7 @@ get_user_docroots() {
if [ "$CONTROL_PANEL" = "cpanel" ]; then
while IFS= read -r line; do
docroot=$(echo "$line" | awk -F'==' '{print $5}')
docroot=$(awk -F'==' '{print $5}' <<< "$line")
[ -n "$docroot" ] && [ -d "$docroot" ] && user_docroots+=("$docroot")
done < <(grep ":.*${username}==" /etc/userdatadomains | cut -d: -f2- | sort -u)
elif [ "$CONTROL_PANEL" = "interworx" ]; then
@@ -687,9 +718,24 @@ cleanup_on_exit() {
fi
echo "→ Cleaning up: Removing Rootkit Hunter..."
if command -v yum &>/dev/null; then
yum remove -y rkhunter &>/dev/null 2>&1
if [ -f "$SESSION_LOG" ]; then
log_message "RKHunter removed"
if yum remove -y rkhunter &>/dev/null 2>&1; then
if [ -f "$SESSION_LOG" ]; then
log_message "RKHunter removed successfully"
fi
else
if [ -f "$SESSION_LOG" ]; then
log_message "WARNING: Failed to remove RKHunter (yum command failed)"
fi
fi
elif command -v apt-get &>/dev/null; then
if apt-get remove -y rkhunter &>/dev/null 2>&1; then
if [ -f "$SESSION_LOG" ]; then
log_message "RKHunter removed successfully"
fi
else
if [ -f "$SESSION_LOG" ]; then
log_message "WARNING: Failed to remove RKHunter (apt-get command failed)"
fi
fi
fi
fi
@@ -716,7 +762,7 @@ clear
echo "========================================"
echo "Standalone Malware Scanner"
echo "========================================"
echo "Session: $(basename $SCAN_DIR)"
echo "Session: $(basename "$SCAN_DIR")"
echo "Started: $(date)"
echo "========================================"
echo ""
@@ -843,7 +889,7 @@ fi
echo "=========================================="
echo "Malware Scan Summary Report"
echo "=========================================="
echo "Session: $(basename $SCAN_DIR)"
echo "Session: $(basename "$SCAN_DIR")"
echo "Started: $(date)"
echo "Scanners: ${AVAILABLE_SCANNERS[*]}"
echo "Paths: ${#SCAN_PATHS[@]}"
@@ -896,117 +942,63 @@ for scanner in "${AVAILABLE_SCANNERS[@]}"; do
SCAN_START=$(date +%s)
log_message "ImunifyAV: Updating signatures"
if ! imunify-antivirus update &>> "$LOG_DIR/imunify.log"; then
if ! timeout 300 imunify-antivirus update &>> "$LOG_DIR/imunify.log"; then
log_message "WARNING: ImunifyAV update failed (continuing with existing signatures)"
echo "⚠️ WARNING: Signature update failed, using existing signatures"
fi
log_message "ImunifyAV: Starting on-demand scan"
echo ""
echo " 📁 Scanning paths: ${SCAN_PATHS[@]}"
echo " ⏳ Scanner: ImunifyAV"
echo ""
# Use on-demand start with background monitoring for progress
LAST_SCAN=""
TOTAL_FILES_SCANNED=0
IMUNIFY_INFECTED=0
FILES_SCANNED=0
# For user-focused scans, use paths as-is
IMUNIFY_SCAN_PATHS=("${SCAN_PATHS[@]}")
# Run ImunifyAV scan with timeout (2 hours max)
# Use --output-format to make parsing easier, with --timeout to prevent hanging
for path in "${SCAN_PATHS[@]}"; do
if [ ! -d "$path" ]; then
log_message "ImunifyAV: Skipping non-existent path: $path"
continue
fi
for path in "${IMUNIFY_SCAN_PATHS[@]}"; do
if [ -d "$path" ]; then
log_message "ImunifyAV: Scanning $path"
echo ""
echo " 📁 Scanning path: $path"
echo " ⏳ Scanner: ImunifyAV (monitoring progress...)"
echo ""
log_message "ImunifyAV: Scanning $path"
echo " Scanning: $path"
# Start scan (ImunifyAV runs async, command returns immediately)
imunify-antivirus malware on-demand start --path="$path" &>> "$LOG_DIR/imunify.log"
START_EXIT=$?
# Run scan with timeout to prevent hanging on status checks
# ImunifyAV scan - output to log file
timeout 7200 imunify-antivirus malware on-demand scan --path="$path" &>> "$LOG_DIR/imunify.log" &
IMUNIFY_PID=$!
if [ "${START_EXIT:-1}" -ne 0 ]; then
log_message "ERROR: ImunifyAV scan failed to start for $path (exit code: $START_EXIT)"
echo " ✗ Scan failed to start for $path (check logs)"
continue
fi
# Monitor with simple timeout (don't try to parse imunify status which hangs)
wait $IMUNIFY_PID
IMUNIFY_EXIT=$?
# Monitor progress by polling scan status
# ImunifyAV runs scans asynchronously, we poll the status
sleep 3 # Give scan time to initialize
last_count=0
timeout_counter=0
max_timeout=7200 # 2 hour timeout
scan_running=true
while [ "$scan_running" = true ]; do
# Get current scan status from most recent scan
scan_info=$(imunify-antivirus malware on-demand list 2>/dev/null | tail -n +2 | head -1)
if [ -n "$scan_info" ]; then
completed_time=$(echo "$scan_info" | awk '{print $1}') # Field 1 is COMPLETED timestamp
created_time=$(echo "$scan_info" | awk '{print $2}') # Field 2 is CREATED
current_files=$(echo "$scan_info" | awk '{print $11}') # Field 11 is TOTAL
current_status=$(echo "$scan_info" | awk '{print $7}') # Field 7 is SCAN_STATUS
# Check if this is our scan (created after we started)
if [[ "$created_time" =~ ^[0-9]+$ ]] && [ "$created_time" -ge "$SCAN_START" ]; then
# Check if scan is complete (COMPLETED field has timestamp)
if [ -n "$completed_time" ] && [ "$completed_time" != "COMPLETED" ] && [[ "$completed_time" =~ ^[0-9]+$ ]] && [ "$completed_time" -gt 0 ]; then
scan_running=false
echo "" # New line after progress
log_message "ImunifyAV scan finished for $path (status: $current_status)"
break
fi
# Update progress if file count changed
if [[ "$current_files" =~ ^[0-9]+$ ]]; then
if [ "$current_files" != "$last_count" ]; then
elapsed=$(($(date +%s) - SCAN_START))
printf "\r Files scanned: %s | Elapsed: %s " \
"$current_files" "$(format_time $elapsed)"
last_count=$current_files
timeout_counter=0
fi
fi
fi
fi
sleep 3
timeout_counter=$((timeout_counter + 3))
if [ $timeout_counter -ge $max_timeout ]; then
log_message "ERROR: ImunifyAV scan timed out after 2 hours for $path"
echo -e "\n ⏱️ Scan timed out (exceeded 2 hour limit)"
# Try to stop the scan
imunify-antivirus malware on-demand stop --path="$path" &>/dev/null
continue 2
fi
done
# Get final scan results
LAST_SCAN=$(imunify-antivirus malware on-demand list 2>/dev/null | tail -n +2 | head -1)
FILES_SCANNED=$(echo "$LAST_SCAN" | awk '{print $11}')
if ! [[ "$FILES_SCANNED" =~ ^[0-9]+$ ]]; then
FILES_SCANNED=0
fi
TOTAL_FILES_SCANNED=$((TOTAL_FILES_SCANNED + FILES_SCANNED))
echo " ✓ Scanned $FILES_SCANNED files in this path"
if [ "$IMUNIFY_EXIT" -eq 124 ]; then
log_message "ERROR: ImunifyAV scan timed out after 2 hours for $path"
echo " ⏱️ Scan timed out (2 hour limit)"
elif [ "$IMUNIFY_EXIT" -ne 0 ]; then
log_message "WARNING: ImunifyAV scan exited with code $IMUNIFY_EXIT for $path"
echo " ⚠️ Scan completed with code $IMUNIFY_EXIT"
fi
done
FILES_SCANNED=$TOTAL_FILES_SCANNED
# Try to get count of malicious files from malicious list (if available)
# Run once with timeout (60s) - capture output and exit code together
IMUNIFY_INFECTED=$(timeout 60 imunify-antivirus malware malicious list 2>/dev/null | tail -n +2 | wc -l)
IMUNIFY_MALICIOUS_EXIT=$?
# Extract malicious file count
# Skip header line and count data rows, or use TOTAL_MALICIOUS from most recent scan
if [ -n "$LAST_SCAN" ]; then
IMUNIFY_INFECTED=$(echo "$LAST_SCAN" | awk '{print $12}')
else
# Validate the count
if [ "$IMUNIFY_MALICIOUS_EXIT" -ne 0 ] || ! [[ "$IMUNIFY_INFECTED" =~ ^[0-9]+$ ]]; then
IMUNIFY_INFECTED=0
fi
# Verify we got a valid number, otherwise try malicious list
if ! [[ "$IMUNIFY_INFECTED" =~ ^[0-9]+$ ]]; then
IMUNIFY_INFECTED=$(imunify-antivirus malware malicious list 2>/dev/null | tail -n +2 | wc -l || echo 0)
log_message "WARNING: Failed to get ImunifyAV malicious count (exit: $IMUNIFY_MALICIOUS_EXIT)"
fi
SCAN_END=$(date +%s)
DURATION=$((SCAN_END - SCAN_START))
echo " ✓ ImunifyAV scan complete"
echo " ⏱️ Duration: ${DURATION}s"
echo ""
echo "✓ ImunifyAV scan complete - Found: $IMUNIFY_INFECTED | Duration: ${DURATION}s" | tee -a "$SUMMARY_FILE"
@@ -1182,8 +1174,9 @@ for scanner in "${AVAILABLE_SCANNERS[@]}"; do
# Extract scan results from event log (more reliable than parsing output)
# Maldet logs to /usr/local/maldetect/logs/event_log
FILES_SCANNED=$(grep "scan completed" /usr/local/maldetect/logs/event_log | tail -1 | grep -oP 'files \K[0-9]+' || echo 0)
MALDET_HITS=$(grep "scan completed" /usr/local/maldetect/logs/event_log | tail -1 | grep -oP 'malware hits \K[0-9]+' || echo 0)
# Use proper fallback: assign first, then check if empty and fallback to 0
FILES_SCANNED=$(grep "scan completed" /usr/local/maldetect/logs/event_log 2>/dev/null | tail -1 | grep -oP 'files \K[0-9]+') || FILES_SCANNED="0"
MALDET_HITS=$(grep "scan completed" /usr/local/maldetect/logs/event_log 2>/dev/null | tail -1 | grep -oP 'malware hits \K[0-9]+') || MALDET_HITS="0"
# Validate numbers
if ! [[ "$FILES_SCANNED" =~ ^[0-9]+$ ]]; then
@@ -1341,7 +1334,7 @@ done
# Check if this log corresponds to the domain/user
grep -h "POST.*${filepath}" "$logfile" 2>/dev/null | tail -20 | while read -r logline; do
# Extract IP from Apache log line
ip=$(echo "$logline" | awk '{print $1}')
ip=$(awk '{print $1}' <<< "$logline")
if [ -n "$ip" ] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
# Flag this IP in reputation database
if type flag_ip_attack &>/dev/null; then
@@ -1359,7 +1352,7 @@ done
# Check if this log corresponds to the domain/user
grep -h "POST.*${filepath}" "$logfile" 2>/dev/null | tail -20 | while read -r logline; do
# Extract IP from Apache log line
ip=$(echo "$logline" | awk '{print $1}')
ip=$(awk '{print $1}' <<< "$logline")
if [ -n "$ip" ] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
# Flag this IP in reputation database
if type flag_ip_attack &>/dev/null; then
@@ -1378,7 +1371,7 @@ done
# Check if this log corresponds to the domain/user
grep -h "POST.*${filepath}" "$logfile" 2>/dev/null | tail -20 | while read -r logline; do
# Extract IP from Apache log line
ip=$(echo "$logline" | awk '{print $1}')
ip=$(awk '{print $1}' <<< "$logline")
if [ -n "$ip" ] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
# Flag this IP in reputation database
if type flag_ip_attack &>/dev/null; then
@@ -1528,7 +1521,7 @@ else
fi
echo ""
echo "Scan ID: $(basename $SCAN_DIR)"
echo "Scan ID: $(basename "$SCAN_DIR")"
} > "$client_report_file"
fi
@@ -1537,7 +1530,7 @@ clear
echo "=========================================="
echo -e "${GREEN}Malware Scan Complete!${NC}"
echo "=========================================="
echo "Session: $(basename $SCAN_DIR)"
echo "Session: $(basename "$SCAN_DIR")"
echo "Completed: $(date)"
echo ""
echo "Results saved to:"
@@ -1604,7 +1597,14 @@ STANDALONE_EOF
done
paths_declaration+=")"
sed -i "s|PLACEHOLDER_SCAN_PATHS|$paths_declaration|" "$session_dir/scan.sh"
# Escape special characters for sed (handle /, \, &, |, $)
# CRITICAL FIX: Must escape the delimiter (|) as well since we use it in the sed command
local escaped_paths=$(printf '%s\n' "$paths_declaration" | sed -e 's/[\/&|]/\\&/g')
if ! sed -i "s|PLACEHOLDER_SCAN_PATHS|$escaped_paths|" "$session_dir/scan.sh"; then
echo -e "${RED}ERROR: Failed to generate standalone scanner script${NC}"
return 1
fi
# Make executable
chmod +x "$session_dir/scan.sh"
@@ -1785,8 +1785,17 @@ launch_standalone_scanner_menu() {
return 1
fi
# Validate that docroots were found
if [ ${#sanitized_docroot[@]} -eq 0 ]; then
echo -e "${YELLOW}WARNING: No docroots found on this system${NC}"
echo "You can still:"
echo " 1. Scan specific paths manually (custom path option)"
echo " 2. Scan from root (entire server)"
echo ""
fi
echo "Control Panel: ${CONTROL_PANEL^}"
echo "Available Scanners: ${available_scanners[*]}"
echo "Available Scanners: ${available_scanners[@]}"
echo ""
local scope_choice
@@ -1963,7 +1972,7 @@ launch_standalone_scanner_menu() {
echo -e "${YELLOW}Ready to generate standalone scanner${NC}"
echo "Scope: $scan_description"
echo "Paths: ${#scan_paths[@]}"
echo "Scanners: ${available_scanners[*]}"
echo "Scanners: ${available_scanners[@]}"
echo ""
read -p "Generate and launch? (yes/no): " confirm
@@ -1982,8 +1991,17 @@ check_standalone_status() {
echo ""
print_header "Standalone Scanner Status"
# Find all malware-* directories in /opt
local standalone_dirs=($(find /opt -maxdepth 1 -type d -name "malware-*" 2>/dev/null | sort -r))
# Find all malware-* directories in /opt (proper array initialization to handle spaces in names)
if [ ! -d /opt ]; then
echo "ERROR: /opt directory not found or not accessible"
read -p "Press Enter to continue..."
return 1
fi
local standalone_dirs=()
while IFS= read -r dir; do
[ -n "$dir" ] && standalone_dirs+=("$dir")
done < <(find /opt -maxdepth 1 -type d -name "malware-*" 2>/dev/null | sort -r)
if [ ${#standalone_dirs[@]} -eq 0 ]; then
echo "No standalone scanner sessions found."
@@ -2050,8 +2068,17 @@ delete_standalone_sessions() {
echo ""
print_header "Delete Standalone Scanner Sessions"
# Find all malware-* directories in /opt
local standalone_dirs=($(find /opt -maxdepth 1 -type d -name "malware-*" 2>/dev/null | sort -r))
# Find all malware-* directories in /opt (proper array initialization to handle spaces in names)
if [ ! -d /opt ]; then
echo "ERROR: /opt directory not found or not accessible"
read -p "Press Enter to continue..."
return 1
fi
local standalone_dirs=()
while IFS= read -r dir; do
[ -n "$dir" ] && standalone_dirs+=("$dir")
done < <(find /opt -maxdepth 1 -type d -name "malware-*" 2>/dev/null | sort -r)
if [ ${#standalone_dirs[@]} -eq 0 ]; then
echo "No standalone scanner sessions found."
@@ -2094,7 +2121,7 @@ delete_standalone_sessions() {
local deleted=0
for dir in "${standalone_dirs[@]}"; do
if ! pgrep -f "$dir/scan.sh" > /dev/null 2>&1; then
echo "Deleting: $(basename $dir)"
echo "Deleting: $(basename "$dir")"
rm -rf "$dir"
((deleted++))
fi