#!/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" # 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 [options] COMMANDS: generate Generate report (dev|services|all) send Generate and email report schedule Set cron schedule (daily|weekly|off) status Show generator status preview 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) all Both reports OPTIONS: --email Also send via email --theme Theme: dark, light, cyberpunk (default: dark) --output 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="

Repository not found at $REPO_PATH

" wip_entries="

Repository not found

" roadmap_data="

Repository not found

" 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" } # 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" ;; all) generate_dev_report "$output_path/dev-status-$timestamp.html" "$theme" generate_services_report "$output_path/services-status-$timestamp.html" "$theme" ;; *) log_err "Unknown report type: $report_type" echo "Valid types: dev, services, 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