secubox-openwrt/package/secubox/secubox-p2p/root/www/api/factory/dashboard
CyberMind-FR a9130715e9 feat(p2p): Add SecuBox Factory unified dashboard with signed Merkle snapshots
Implement mesh-distributed, cryptographically-validated control center:

- Add factory.sh library with Ed25519 signing via signify-openbsd
- Add Merkle tree calculation for /etc/config validation
- Add CGI endpoints: dashboard, tools, run, snapshot, pubkey
- Add KISS Web UI (~280 lines vanilla JS, inline CSS, zero deps)
- Add gossip-based 3-peer fanout for snapshot synchronization
- Add offline operations queue with replay on reconnect
- Add LuCI iframe integration under MirrorBox > Factory tab
- Configure uhttpd alias for /factory/ on port 7331
- Bump secubox-p2p version to 0.4.0

Factory UI accessible at http://<device>:7331/factory/

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 08:03:54 +01:00

133 lines
3.7 KiB
Bash

#!/bin/sh
# Factory Dashboard - Aggregated mesh status
# CGI endpoint for SecuBox Factory
echo "Content-Type: application/json"
echo "Access-Control-Allow-Origin: *"
echo "Access-Control-Allow-Methods: GET, OPTIONS"
echo ""
# Handle CORS preflight
if [ "$REQUEST_METHOD" = "OPTIONS" ]; then
exit 0
fi
# Load factory library
. /usr/lib/secubox/factory.sh 2>/dev/null
# Get local node status
get_local_status() {
if [ -x /usr/sbin/secubox-p2p ]; then
/usr/sbin/secubox-p2p status 2>/dev/null
else
echo '{"error":"p2p_unavailable"}'
fi
}
# Get services status
get_services_status() {
local running=0
local total=0
for init_script in /etc/init.d/*; do
[ -x "$init_script" ] || continue
local svc_name=$(basename "$init_script")
# Skip system services
case "$svc_name" in
boot|done|rcS|rc.local|umount|sysfixtime|sysntpd|gpio_switch) continue ;;
esac
total=$((total + 1))
if pgrep "$svc_name" >/dev/null 2>&1; then
running=$((running + 1))
fi
done
echo "{\"running\":$running,\"total\":$total}"
}
# Get system stats
get_system_stats() {
local uptime_val=$(cat /proc/uptime 2>/dev/null | cut -d' ' -f1)
local load=$(cat /proc/loadavg 2>/dev/null | cut -d' ' -f1)
local mem_info=$(cat /proc/meminfo 2>/dev/null)
local mem_total=$(echo "$mem_info" | grep MemTotal | awk '{print $2}')
local mem_free=$(echo "$mem_info" | grep MemAvailable | awk '{print $2}')
[ -z "$mem_free" ] && mem_free=$(echo "$mem_info" | grep MemFree | awk '{print $2}')
local mem_used=0
local mem_pct=0
if [ -n "$mem_total" ] && [ "$mem_total" -gt 0 ]; then
mem_used=$((mem_total - mem_free))
mem_pct=$((mem_used * 100 / mem_total))
fi
echo "{\"uptime\":${uptime_val:-0},\"load\":\"${load:-0}\",\"mem_used_kb\":$mem_used,\"mem_total_kb\":${mem_total:-0},\"mem_pct\":$mem_pct}"
}
# Get peer statuses
get_peer_statuses() {
local peers_file="/tmp/secubox-p2p-peers.json"
local result="["
local first=1
if [ -f "$peers_file" ]; then
# Parse each peer
local peers=$(jsonfilter -i "$peers_file" -e '@.peers[*]' 2>/dev/null)
local count=$(jsonfilter -i "$peers_file" -e '@.peers[*]' 2>/dev/null | wc -l)
local i=0
while [ $i -lt $count ]; do
local addr=$(jsonfilter -i "$peers_file" -e "@.peers[$i].address" 2>/dev/null)
local name=$(jsonfilter -i "$peers_file" -e "@.peers[$i].name" 2>/dev/null)
local is_local=$(jsonfilter -i "$peers_file" -e "@.peers[$i].is_local" 2>/dev/null)
if [ -n "$addr" ] && [ "$is_local" != "true" ]; then
# Try to get peer status (with timeout)
local peer_status=$(curl -s --connect-timeout 2 "http://$addr:7331/api/status" 2>/dev/null)
local status="offline"
local peer_merkle=""
if [ -n "$peer_status" ] && echo "$peer_status" | grep -q "node_id"; then
status="online"
# Try to get peer's merkle root
peer_merkle=$(curl -s --connect-timeout 1 "http://$addr:7331/api/factory/snapshot" 2>/dev/null | jsonfilter -e '@.merkle_root' 2>/dev/null)
fi
[ $first -eq 0 ] && result="$result,"
first=0
result="$result{\"address\":\"$addr\",\"name\":\"$name\",\"status\":\"$status\",\"merkle_root\":\"${peer_merkle:-}\"}"
fi
i=$((i + 1))
done
fi
result="$result]"
echo "$result"
}
# Main response
local_status=$(get_local_status)
local_merkle=$(merkle_config 2>/dev/null || echo "")
snapshot=$(get_snapshot 2>/dev/null | tr '\n' ' ' | tr '\t' ' ')
services=$(get_services_status)
system=$(get_system_stats)
peers=$(get_peer_statuses)
pending=$(pending_count 2>/dev/null || echo "0")
fingerprint=$(factory_fingerprint 2>/dev/null || echo "")
# Build response
cat << EOF
{
"local": $local_status,
"merkle_root": "$local_merkle",
"snapshot": $snapshot,
"services": $services,
"system": $system,
"peers": $peers,
"pending_ops": $pending,
"fingerprint": "$fingerprint"
}
EOF