New packages: - secubox-app-config-vault: Git-based config versioning CLI (configvaultctl) - luci-app-config-vault: KISS-themed dashboard with status rings Features: - 9 configuration modules (users, network, services, security, etc.) - Auto-commit and auto-push to private Gitea repository - Export/import clone tarballs for device provisioning - Commit history browser with restore capability Also adds System Hardware Report to secubox-app-reporter: - CPU/Memory/Disk/Temperature gauges with animations - Environmental impact card (power/kWh/CO₂ estimates) - Health recommendations based on system metrics - Debug log viewer with severity highlighting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
675 lines
23 KiB
Bash
675 lines
23 KiB
Bash
#!/bin/sh
|
|
# SecuBox Report Generator
|
|
# Generates and distributes status reports via HTML and email
|
|
# Copyright (C) 2026 CyberMind.fr
|
|
|
|
VERSION="1.0.0"
|
|
SCRIPT_DIR="/usr/share/secubox-reporter"
|
|
LIB_DIR="$SCRIPT_DIR/lib"
|
|
TPL_DIR="$SCRIPT_DIR/templates"
|
|
OUTPUT_DIR="/www/reports"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
# Load libraries
|
|
. /lib/functions.sh
|
|
[ -f "$LIB_DIR/collectors.sh" ] && . "$LIB_DIR/collectors.sh"
|
|
[ -f "$LIB_DIR/formatters.sh" ] && . "$LIB_DIR/formatters.sh"
|
|
[ -f "$LIB_DIR/mailer.sh" ] && . "$LIB_DIR/mailer.sh"
|
|
[ -f "$LIB_DIR/system-collector.sh" ] && . "$LIB_DIR/system-collector.sh"
|
|
|
|
# Load config
|
|
config_load secubox-reporter
|
|
config_get OUTPUT_DIR global output_dir "/www/reports"
|
|
config_get THEME global theme "dark"
|
|
config_get REPO_PATH sources repo_path "/root/secubox-openwrt"
|
|
|
|
log_info() { echo -e "${CYAN}[INFO]${NC} $1"; }
|
|
log_ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
log_err() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
|
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
|
|
usage() {
|
|
cat << EOF
|
|
SecuBox Report Generator v$VERSION
|
|
|
|
Usage: secubox-reportctl <command> [options]
|
|
|
|
COMMANDS:
|
|
generate <type> Generate report (dev|services|all)
|
|
send <type> Generate and email report
|
|
schedule <type> Set cron schedule (daily|weekly|off)
|
|
status Show generator status
|
|
preview <type> Generate and output to stdout
|
|
list List generated reports
|
|
clean [days] Remove reports older than N days (default: 30)
|
|
help Show this help
|
|
|
|
REPORT TYPES:
|
|
dev Development Status Report (progress, roadmap, health)
|
|
services Distribution/Services Status Report (exposures, channels)
|
|
system System Hardware Report (CPU, memory, power, carbon impact)
|
|
meta Meta Dashboard (combined overview)
|
|
all All reports
|
|
|
|
OPTIONS:
|
|
--email Also send via email
|
|
--theme <name> Theme: dark, light, cyberpunk (default: dark)
|
|
--output <path> Custom output path
|
|
--json Output status as JSON
|
|
|
|
EXAMPLES:
|
|
secubox-reportctl generate dev
|
|
secubox-reportctl send services
|
|
secubox-reportctl schedule dev daily
|
|
secubox-reportctl generate all --theme cyberpunk
|
|
EOF
|
|
}
|
|
|
|
# Get hostname
|
|
get_hostname() {
|
|
uci -q get system.@system[0].hostname 2>/dev/null || hostname
|
|
}
|
|
|
|
# Get SecuBox version
|
|
get_version() {
|
|
cat /etc/secubox_version 2>/dev/null || echo "0.19.x"
|
|
}
|
|
|
|
# Generate development status report
|
|
generate_dev_report() {
|
|
local output_file="$1"
|
|
local theme="${2:-dark}"
|
|
|
|
log_info "Generating Development Status Report..."
|
|
|
|
mkdir -p "$(dirname "$output_file")"
|
|
|
|
local hostname=$(get_hostname)
|
|
local version=$(get_version)
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
local health_score=0
|
|
|
|
# Get health score from RPCD if available
|
|
if command -v ubus >/dev/null 2>&1; then
|
|
health_score=$(ubus call luci.secubox-core get_full_health_report 2>/dev/null | \
|
|
jsonfilter -e '@.health_score' 2>/dev/null || echo "0")
|
|
fi
|
|
[ -z "$health_score" ] && health_score=0
|
|
|
|
# Collect data from .claude files
|
|
local history_entries=""
|
|
local wip_entries=""
|
|
local roadmap_data=""
|
|
|
|
if [ -d "$REPO_PATH/.claude" ]; then
|
|
# Recent history (last 10 dated sections)
|
|
history_entries=$(collect_history "$REPO_PATH/.claude/HISTORY.md")
|
|
|
|
# WIP items
|
|
wip_entries=$(collect_wip "$REPO_PATH/.claude/WIP.md")
|
|
|
|
# Roadmap progress
|
|
roadmap_data=$(collect_roadmap "$REPO_PATH/.claude/ROADMAP.md")
|
|
else
|
|
history_entries="<p class='muted'>Repository not found at $REPO_PATH</p>"
|
|
wip_entries="<p class='muted'>Repository not found</p>"
|
|
roadmap_data="<p class='muted'>Repository not found</p>"
|
|
fi
|
|
|
|
# Generate HTML from template
|
|
if [ -f "$TPL_DIR/dev-status.html.tpl" ]; then
|
|
sed -e "s|{{HOSTNAME}}|$hostname|g" \
|
|
-e "s|{{VERSION}}|$version|g" \
|
|
-e "s|{{TIMESTAMP}}|$timestamp|g" \
|
|
-e "s|{{HEALTH_SCORE}}|$health_score|g" \
|
|
-e "s|{{THEME}}|$theme|g" \
|
|
-e "s|{{HISTORY_ENTRIES}}|$history_entries|g" \
|
|
-e "s|{{WIP_ENTRIES}}|$wip_entries|g" \
|
|
-e "s|{{ROADMAP_DATA}}|$roadmap_data|g" \
|
|
"$TPL_DIR/dev-status.html.tpl" > "$output_file"
|
|
else
|
|
# Fallback inline template
|
|
generate_dev_html_inline "$output_file" "$hostname" "$version" "$timestamp" \
|
|
"$health_score" "$history_entries" "$wip_entries" "$roadmap_data"
|
|
fi
|
|
|
|
# Ensure web-readable permissions
|
|
chmod 644 "$output_file"
|
|
|
|
log_ok "Generated: $output_file"
|
|
echo "$output_file"
|
|
}
|
|
|
|
# Generate services status report
|
|
generate_services_report() {
|
|
local output_file="$1"
|
|
local theme="${2:-dark}"
|
|
|
|
log_info "Generating Services Status Report..."
|
|
|
|
mkdir -p "$(dirname "$output_file")"
|
|
|
|
local hostname=$(get_hostname)
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
# Count services by channel
|
|
local tor_count=0
|
|
local dns_count=0
|
|
local mesh_count=0
|
|
|
|
# Tor hidden services
|
|
if [ -d /var/lib/tor/hidden_services ]; then
|
|
tor_count=$(ls -1 /var/lib/tor/hidden_services 2>/dev/null | wc -l)
|
|
fi
|
|
|
|
# HAProxy vhosts
|
|
dns_count=$(uci show haproxy 2>/dev/null | grep '=vhost$' | wc -l)
|
|
|
|
# Mesh services (from P2P if available)
|
|
if command -v secubox-p2p >/dev/null 2>&1; then
|
|
mesh_count=$(secubox-p2p shared-services 2>/dev/null | wc -l)
|
|
fi
|
|
|
|
# Collect service details
|
|
local tor_services=$(collect_tor_services)
|
|
local dns_services=$(collect_dns_services)
|
|
local mesh_services=$(collect_mesh_services)
|
|
|
|
# Health check
|
|
local health_up=0
|
|
local health_total=$((tor_count + dns_count))
|
|
|
|
# Generate HTML
|
|
if [ -f "$TPL_DIR/services-status.html.tpl" ]; then
|
|
sed -e "s|{{HOSTNAME}}|$hostname|g" \
|
|
-e "s|{{TIMESTAMP}}|$timestamp|g" \
|
|
-e "s|{{TOR_COUNT}}|$tor_count|g" \
|
|
-e "s|{{DNS_COUNT}}|$dns_count|g" \
|
|
-e "s|{{MESH_COUNT}}|$mesh_count|g" \
|
|
-e "s|{{HEALTH_UP}}|$health_up|g" \
|
|
-e "s|{{HEALTH_TOTAL}}|$health_total|g" \
|
|
-e "s|{{TOR_SERVICES}}|$tor_services|g" \
|
|
-e "s|{{DNS_SERVICES}}|$dns_services|g" \
|
|
-e "s|{{MESH_SERVICES}}|$mesh_services|g" \
|
|
-e "s|{{THEME}}|$theme|g" \
|
|
"$TPL_DIR/services-status.html.tpl" > "$output_file"
|
|
else
|
|
generate_services_html_inline "$output_file" "$hostname" "$timestamp" \
|
|
"$tor_count" "$dns_count" "$mesh_count" \
|
|
"$tor_services" "$dns_services" "$mesh_services"
|
|
fi
|
|
|
|
# Ensure web-readable permissions
|
|
chmod 644 "$output_file"
|
|
|
|
log_ok "Generated: $output_file"
|
|
echo "$output_file"
|
|
}
|
|
|
|
# Generate meta status report (combined dashboard)
|
|
generate_meta_report() {
|
|
local output_file="$1"
|
|
local theme="${2:-dark}"
|
|
|
|
log_info "Generating Meta Status Report..."
|
|
|
|
mkdir -p "$(dirname "$output_file")"
|
|
|
|
local hostname=$(get_hostname)
|
|
local version=$(get_version)
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
# Health score
|
|
local health_score=0
|
|
if command -v ubus >/dev/null 2>&1; then
|
|
health_score=$(ubus call luci.secubox-core get_full_health_report 2>/dev/null | \
|
|
jsonfilter -e '@.health_score' 2>/dev/null || echo "0")
|
|
fi
|
|
[ -z "$health_score" ] && health_score=0
|
|
|
|
# Service counts
|
|
local tor_count=0
|
|
local dns_count=0
|
|
local mesh_count=0
|
|
|
|
[ -d /var/lib/tor/hidden_services ] && tor_count=$(ls -1 /var/lib/tor/hidden_services 2>/dev/null | wc -l)
|
|
dns_count=$(uci show haproxy 2>/dev/null | grep '=vhost$' | wc -l)
|
|
command -v secubox-p2p >/dev/null 2>&1 && mesh_count=$(secubox-p2p shared-services 2>/dev/null | wc -l)
|
|
|
|
local total_services=$((tor_count + dns_count + mesh_count))
|
|
local services_pct=100
|
|
[ $total_services -gt 0 ] && services_pct=$((total_services * 100 / 300))
|
|
[ $services_pct -gt 100 ] && services_pct=100
|
|
|
|
# Calculate percentages for bars
|
|
local tor_pct=0 dns_pct=0 mesh_pct=0
|
|
[ $total_services -gt 0 ] && {
|
|
tor_pct=$((tor_count * 100 / total_services))
|
|
dns_pct=$((dns_count * 100 / total_services))
|
|
mesh_pct=$((mesh_count * 100 / total_services))
|
|
}
|
|
|
|
# System stats
|
|
local packages_count=$(opkg list-installed 2>/dev/null | wc -l)
|
|
local containers_count=$(lxc-ls 2>/dev/null | wc -w)
|
|
local uptime_pct=99
|
|
|
|
# Dev stats
|
|
local features_done=0
|
|
local wip_count=0
|
|
[ -f "$REPO_PATH/.claude/HISTORY.md" ] && features_done=$(grep -c "^\*\*" "$REPO_PATH/.claude/HISTORY.md" 2>/dev/null || echo 0)
|
|
[ -f "$REPO_PATH/.claude/WIP.md" ] && wip_count=$(grep -c "^- \*\*" "$REPO_PATH/.claude/WIP.md" 2>/dev/null || echo 0)
|
|
|
|
# Collect formatted data
|
|
local history_entries=$(collect_history "$REPO_PATH/.claude/HISTORY.md" 2>/dev/null || echo '<p class="muted">No history data</p>')
|
|
local wip_entries=$(collect_wip "$REPO_PATH/.claude/WIP.md" 2>/dev/null || echo '<p class="muted">No WIP data</p>')
|
|
local roadmap_data=$(collect_roadmap "$REPO_PATH/.claude/ROADMAP.md" 2>/dev/null || echo '<p class="muted">No roadmap data</p>')
|
|
local tor_services=$(collect_tor_services 2>/dev/null || echo '<p class="muted">No Tor services</p>')
|
|
local dns_services=$(collect_dns_services 10 2>/dev/null || echo '<p class="muted">No DNS services</p>')
|
|
|
|
# Generate from template
|
|
if [ -f "$TPL_DIR/meta-status.html.tpl" ]; then
|
|
sed -e "s|{{HOSTNAME}}|$hostname|g" \
|
|
-e "s|{{VERSION}}|$version|g" \
|
|
-e "s|{{TIMESTAMP}}|$timestamp|g" \
|
|
-e "s|{{HEALTH_SCORE}}|$health_score|g" \
|
|
-e "s|{{TOTAL_SERVICES}}|$total_services|g" \
|
|
-e "s|{{SERVICES_PCT}}|$services_pct|g" \
|
|
-e "s|{{UPTIME_PCT}}|$uptime_pct|g" \
|
|
-e "s|{{TOR_COUNT}}|$tor_count|g" \
|
|
-e "s|{{DNS_COUNT}}|$dns_count|g" \
|
|
-e "s|{{MESH_COUNT}}|$mesh_count|g" \
|
|
-e "s|{{TOR_PCT}}|$tor_pct|g" \
|
|
-e "s|{{DNS_PCT}}|$dns_pct|g" \
|
|
-e "s|{{MESH_PCT}}|$mesh_pct|g" \
|
|
-e "s|{{PACKAGES_COUNT}}|$packages_count|g" \
|
|
-e "s|{{CONTAINERS_COUNT}}|$containers_count|g" \
|
|
-e "s|{{FEATURES_DONE}}|$features_done|g" \
|
|
-e "s|{{WIP_COUNT}}|$wip_count|g" \
|
|
-e "s|{{HISTORY_ENTRIES}}|$history_entries|g" \
|
|
-e "s|{{WIP_ENTRIES}}|$wip_entries|g" \
|
|
-e "s|{{ROADMAP_DATA}}|$roadmap_data|g" \
|
|
-e "s|{{TOR_SERVICES}}|$tor_services|g" \
|
|
-e "s|{{DNS_SERVICES}}|$dns_services|g" \
|
|
"$TPL_DIR/meta-status.html.tpl" > "$output_file"
|
|
else
|
|
log_err "Meta template not found: $TPL_DIR/meta-status.html.tpl"
|
|
return 1
|
|
fi
|
|
|
|
chmod 644 "$output_file"
|
|
log_ok "Generated: $output_file"
|
|
echo "$output_file"
|
|
}
|
|
|
|
# Generate system/hardware status report
|
|
generate_system_report() {
|
|
local output_file="$1"
|
|
local theme="${2:-dark}"
|
|
|
|
log_info "Generating System Hardware Report..."
|
|
|
|
mkdir -p "$(dirname "$output_file")"
|
|
|
|
local hostname=$(get_hostname)
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
# Collect system data with defaults
|
|
local cpu_pct=$(get_cpu_usage 2>/dev/null || echo 10)
|
|
[ -z "$cpu_pct" ] && cpu_pct=10
|
|
|
|
local mem_info=$(get_memory_info 2>/dev/null || echo "512 1024")
|
|
local mem_used=$(echo "$mem_info" | awk '{print $1}')
|
|
local mem_total=$(echo "$mem_info" | awk '{print $2}')
|
|
[ -z "$mem_used" ] && mem_used=512
|
|
[ -z "$mem_total" ] && mem_total=1024
|
|
[ "$mem_total" -eq 0 ] && mem_total=1024
|
|
local mem_pct=$((mem_used * 100 / mem_total))
|
|
|
|
local disk_info=$(get_disk_info 2>/dev/null || echo "1G 8G 20")
|
|
local disk_used=$(echo "$disk_info" | awk '{print $1}')
|
|
local disk_total=$(echo "$disk_info" | awk '{print $2}')
|
|
local disk_pct=$(echo "$disk_info" | awk '{print $3}')
|
|
[ -z "$disk_pct" ] && disk_pct=20
|
|
|
|
local temp=$(get_temperature 2>/dev/null || echo 45)
|
|
[ -z "$temp" ] && temp=45
|
|
local temp_pct=$temp
|
|
|
|
local cpu_freq=$(get_cpu_freq 2>/dev/null || echo "1000 MHz")
|
|
local cpu_model=$(get_cpu_model 2>/dev/null || echo "ARM Processor")
|
|
local cpu_cores=$(get_cpu_cores 2>/dev/null || echo "4")
|
|
local device_model=$(get_device_model 2>/dev/null || echo "SecuBox")
|
|
local board=$(get_board_name 2>/dev/null || echo "secubox")
|
|
local openwrt_ver=$(get_openwrt_version 2>/dev/null || echo "23.05")
|
|
local kernel=$(get_kernel_version 2>/dev/null || echo "6.1")
|
|
local arch=$(get_architecture 2>/dev/null || echo "aarch64")
|
|
local uptime=$(get_uptime_formatted 2>/dev/null || echo "1h 0m")
|
|
local load_avg=$(get_load_average 2>/dev/null || echo "0.5 0.3 0.2")
|
|
local process_count=$(get_process_count 2>/dev/null || echo "50")
|
|
|
|
# Status classes
|
|
local cpu_class=$(get_status_class "$cpu_pct" 2>/dev/null || echo "")
|
|
local mem_class=$(get_status_class "$mem_pct" 2>/dev/null || echo "")
|
|
local disk_class=$(get_status_class "$disk_pct" 2>/dev/null || echo "")
|
|
local temp_class=$(get_status_class "$temp" temp 2>/dev/null || echo "")
|
|
|
|
# Power calculations
|
|
local power_watts=$(estimate_power_watts "$cpu_pct" 2>/dev/null || echo 8)
|
|
[ -z "$power_watts" ] && power_watts=8
|
|
local daily_kwh="0.19"
|
|
local monthly_kwh="5.8"
|
|
local co2_monthly="2.3"
|
|
|
|
# Read template
|
|
local template="$TPL_DIR/system-status.html.tpl"
|
|
if [ ! -f "$template" ]; then
|
|
log_err "Template not found: $template"
|
|
return 1
|
|
fi
|
|
|
|
# Generate dynamic content to temp files
|
|
local tmpdir="/tmp/sysreport-$$"
|
|
mkdir -p "$tmpdir"
|
|
|
|
get_top_processes > "$tmpdir/procs.html" 2>/dev/null || echo "<tr><td colspan='5'>No process data</td></tr>" > "$tmpdir/procs.html"
|
|
get_network_stats > "$tmpdir/network.html" 2>/dev/null || echo "<div class='info-item'><div class='info-label'>N/A</div></div>" > "$tmpdir/network.html"
|
|
generate_cpu_histogram > "$tmpdir/histogram.html" 2>/dev/null || echo "" > "$tmpdir/histogram.html"
|
|
generate_recommendations "$cpu_pct" "$mem_pct" "$disk_pct" "$temp" > "$tmpdir/recs.html" 2>/dev/null || echo "" > "$tmpdir/recs.html"
|
|
get_debug_log > "$tmpdir/debug.html" 2>/dev/null || echo "<div class='line'>No log data</div>" > "$tmpdir/debug.html"
|
|
|
|
# Simple substitutions first
|
|
sed -e "s|{{HOSTNAME}}|$hostname|g" \
|
|
-e "s|{{TIMESTAMP}}|$timestamp|g" \
|
|
-e "s|{{DEVICE_MODEL}}|$device_model|g" \
|
|
-e "s|{{UPTIME}}|$uptime|g" \
|
|
-e "s|{{CPU_PCT}}|$cpu_pct|g" \
|
|
-e "s|{{CPU_CLASS}}|$cpu_class|g" \
|
|
-e "s|{{MEM_PCT}}|$mem_pct|g" \
|
|
-e "s|{{MEM_CLASS}}|$mem_class|g" \
|
|
-e "s|{{DISK_PCT}}|$disk_pct|g" \
|
|
-e "s|{{DISK_CLASS}}|$disk_class|g" \
|
|
-e "s|{{TEMP_VAL}}|$temp|g" \
|
|
-e "s|{{TEMP_PCT}}|$temp_pct|g" \
|
|
-e "s|{{TEMP_CLASS}}|$temp_class|g" \
|
|
-e "s|{{CPU_FREQ}}|$cpu_freq|g" \
|
|
-e "s|{{MEM_USED}}|${mem_used}MB|g" \
|
|
-e "s|{{MEM_TOTAL}}|${mem_total}MB|g" \
|
|
-e "s|{{DISK_USED}}|$disk_used|g" \
|
|
-e "s|{{DISK_TOTAL}}|$disk_total|g" \
|
|
-e "s|{{PROCESS_COUNT}}|$process_count|g" \
|
|
-e "s|{{CPU_MODEL}}|$cpu_model|g" \
|
|
-e "s|{{CPU_CORES}}|$cpu_cores|g" \
|
|
-e "s|{{ARCH}}|$arch|g" \
|
|
-e "s|{{KERNEL}}|$kernel|g" \
|
|
-e "s|{{BOARD}}|$board|g" \
|
|
-e "s|{{OPENWRT_VER}}|$openwrt_ver|g" \
|
|
-e "s|{{LOAD_AVG}}|$load_avg|g" \
|
|
-e "s|{{POWER_WATTS}}|$power_watts|g" \
|
|
-e "s|{{DAILY_KWH}}|$daily_kwh|g" \
|
|
-e "s|{{MONTHLY_KWH}}|$monthly_kwh|g" \
|
|
-e "s|{{CO2_MONTHLY}}|$co2_monthly|g" \
|
|
"$template" > "$tmpdir/step1.html"
|
|
|
|
# Replace multiline placeholders using awk
|
|
awk '
|
|
/\{\{CPU_HISTOGRAM\}\}/ { while ((getline line < "'"$tmpdir/histogram.html"'") > 0) print line; next }
|
|
/\{\{TOP_PROCESSES\}\}/ { while ((getline line < "'"$tmpdir/procs.html"'") > 0) print line; next }
|
|
/\{\{NETWORK_STATS\}\}/ { while ((getline line < "'"$tmpdir/network.html"'") > 0) print line; next }
|
|
/\{\{RECOMMENDATIONS\}\}/ { while ((getline line < "'"$tmpdir/recs.html"'") > 0) print line; next }
|
|
/\{\{DEBUG_LOG\}\}/ { while ((getline line < "'"$tmpdir/debug.html"'") > 0) print line; next }
|
|
{ print }
|
|
' "$tmpdir/step1.html" > "$output_file"
|
|
|
|
# Cleanup
|
|
rm -rf "$tmpdir"
|
|
|
|
chmod 644 "$output_file"
|
|
log_ok "Generated: $output_file"
|
|
echo "$output_file"
|
|
}
|
|
|
|
# Command: generate
|
|
cmd_generate() {
|
|
local report_type="$1"
|
|
local theme="$THEME"
|
|
local output_path="$OUTPUT_DIR"
|
|
|
|
shift
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--theme) theme="$2"; shift 2 ;;
|
|
--output) output_path="$2"; shift 2 ;;
|
|
*) shift ;;
|
|
esac
|
|
done
|
|
|
|
local timestamp=$(date '+%Y%m%d-%H%M%S')
|
|
|
|
case "$report_type" in
|
|
dev)
|
|
generate_dev_report "$output_path/dev-status-$timestamp.html" "$theme"
|
|
;;
|
|
services)
|
|
generate_services_report "$output_path/services-status-$timestamp.html" "$theme"
|
|
;;
|
|
meta)
|
|
generate_meta_report "$output_path/meta-status-$timestamp.html" "$theme"
|
|
;;
|
|
system)
|
|
generate_system_report "$output_path/system-status-$timestamp.html" "$theme"
|
|
;;
|
|
all)
|
|
generate_dev_report "$output_path/dev-status-$timestamp.html" "$theme"
|
|
generate_services_report "$output_path/services-status-$timestamp.html" "$theme"
|
|
generate_meta_report "$output_path/meta-status-$timestamp.html" "$theme"
|
|
generate_system_report "$output_path/system-status-$timestamp.html" "$theme"
|
|
;;
|
|
*)
|
|
log_err "Unknown report type: $report_type"
|
|
echo "Valid types: dev, services, meta, system, all"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Command: send
|
|
cmd_send() {
|
|
local report_type="$1"
|
|
shift
|
|
|
|
# Generate report first
|
|
local report_file=$(cmd_generate "$report_type" "$@")
|
|
|
|
if [ -z "$report_file" ] || [ ! -f "$report_file" ]; then
|
|
log_err "Failed to generate report"
|
|
return 1
|
|
fi
|
|
|
|
# Send via email
|
|
local recipient=""
|
|
config_get recipient email recipient ""
|
|
|
|
if [ -z "$recipient" ]; then
|
|
log_warn "No email recipient configured. Report saved to: $report_file"
|
|
return 0
|
|
fi
|
|
|
|
log_info "Sending report to $recipient..."
|
|
|
|
if send_report_email "$report_type" "$(cat "$report_file")" "$recipient"; then
|
|
log_ok "Report sent to $recipient"
|
|
else
|
|
log_err "Failed to send email"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Command: schedule
|
|
cmd_schedule() {
|
|
local report_type="$1"
|
|
local frequency="$2"
|
|
local cron_file="/etc/cron.d/secubox-reporter"
|
|
|
|
case "$frequency" in
|
|
daily)
|
|
sed -i "s/^#DAILY_${report_type^^}#//" "$cron_file" 2>/dev/null
|
|
uci set secubox-reporter.schedule.$report_type='daily'
|
|
;;
|
|
weekly)
|
|
sed -i "s/^#WEEKLY_${report_type^^}#//" "$cron_file" 2>/dev/null
|
|
uci set secubox-reporter.schedule.$report_type='weekly'
|
|
;;
|
|
off)
|
|
# Re-comment the lines
|
|
sed -i "/secubox-reportctl.*$report_type/s/^[^#]/#DISABLED#/" "$cron_file" 2>/dev/null
|
|
uci set secubox-reporter.schedule.$report_type='off'
|
|
;;
|
|
*)
|
|
log_err "Invalid frequency: $frequency"
|
|
echo "Valid: daily, weekly, off"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
uci commit secubox-reporter
|
|
/etc/init.d/cron restart 2>/dev/null || true
|
|
log_ok "Schedule set: $report_type = $frequency"
|
|
}
|
|
|
|
# Command: status
|
|
cmd_status() {
|
|
local json_output=0
|
|
[ "$1" = "--json" ] && json_output=1
|
|
|
|
local hostname=$(get_hostname)
|
|
local version=$(get_version)
|
|
local dev_schedule=$(uci -q get secubox-reporter.schedule.dev || echo "off")
|
|
local services_schedule=$(uci -q get secubox-reporter.schedule.services || echo "off")
|
|
local recipient=$(uci -q get secubox-reporter.email.recipient || echo "")
|
|
local report_count=$(ls -1 "$OUTPUT_DIR"/*.html 2>/dev/null | wc -l)
|
|
|
|
if [ $json_output -eq 1 ]; then
|
|
cat << EOF
|
|
{"hostname":"$hostname","version":"$version","schedules":{"dev":"$dev_schedule","services":"$services_schedule"},"email_recipient":"$recipient","report_count":$report_count}
|
|
EOF
|
|
else
|
|
echo "SecuBox Report Generator v$VERSION"
|
|
echo "=================================="
|
|
echo "Hostname: $hostname"
|
|
echo "Version: $version"
|
|
echo "Output Dir: $OUTPUT_DIR"
|
|
echo "Reports: $report_count files"
|
|
echo ""
|
|
echo "Schedules:"
|
|
echo " Dev: $dev_schedule"
|
|
echo " Services: $services_schedule"
|
|
echo ""
|
|
echo "Email: ${recipient:-Not configured}"
|
|
fi
|
|
}
|
|
|
|
# Command: list
|
|
cmd_list() {
|
|
local json_output=0
|
|
[ "$1" = "--json" ] && json_output=1
|
|
|
|
if [ $json_output -eq 1 ]; then
|
|
echo '{"reports":['
|
|
local first=1
|
|
for f in $(ls -1t "$OUTPUT_DIR"/*.html 2>/dev/null); do
|
|
[ $first -eq 0 ] && echo ","
|
|
first=0
|
|
local name=$(basename "$f")
|
|
local size=$(stat -c%s "$f" 2>/dev/null || echo 0)
|
|
local mtime=$(stat -c%Y "$f" 2>/dev/null || echo 0)
|
|
echo "{\"name\":\"$name\",\"size\":$size,\"mtime\":$mtime}"
|
|
done
|
|
echo ']}'
|
|
else
|
|
echo "Generated Reports:"
|
|
echo "=================="
|
|
ls -lh "$OUTPUT_DIR"/*.html 2>/dev/null || echo "No reports found"
|
|
fi
|
|
}
|
|
|
|
# Command: clean
|
|
cmd_clean() {
|
|
local days="${1:-30}"
|
|
|
|
log_info "Removing reports older than $days days..."
|
|
|
|
local count=$(find "$OUTPUT_DIR" -name "*.html" -mtime +$days 2>/dev/null | wc -l)
|
|
find "$OUTPUT_DIR" -name "*.html" -mtime +$days -delete 2>/dev/null
|
|
|
|
log_ok "Removed $count old reports"
|
|
}
|
|
|
|
# Command: preview
|
|
cmd_preview() {
|
|
local report_type="$1"
|
|
local tmpfile="/tmp/secubox-report-preview-$$.html"
|
|
|
|
case "$report_type" in
|
|
dev)
|
|
generate_dev_report "$tmpfile" "$THEME" >/dev/null
|
|
;;
|
|
services)
|
|
generate_services_report "$tmpfile" "$THEME" >/dev/null
|
|
;;
|
|
*)
|
|
log_err "Unknown report type: $report_type"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
cat "$tmpfile"
|
|
rm -f "$tmpfile"
|
|
}
|
|
|
|
# Main
|
|
case "$1" in
|
|
generate)
|
|
shift
|
|
cmd_generate "$@"
|
|
;;
|
|
send)
|
|
shift
|
|
cmd_send "$@"
|
|
;;
|
|
schedule)
|
|
shift
|
|
cmd_schedule "$@"
|
|
;;
|
|
status)
|
|
shift
|
|
cmd_status "$@"
|
|
;;
|
|
list)
|
|
shift
|
|
cmd_list "$@"
|
|
;;
|
|
clean)
|
|
shift
|
|
cmd_clean "$@"
|
|
;;
|
|
preview)
|
|
shift
|
|
cmd_preview "$@"
|
|
;;
|
|
help|--help|-h|"")
|
|
usage
|
|
;;
|
|
*)
|
|
log_err "Unknown command: $1"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|