diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/Packages b/package/secubox/secubox-app-bonus/root/www/secubox-feed/Packages index 286c9185..8b92e065 100644 --- a/package/secubox/secubox-app-bonus/root/www/secubox-feed/Packages +++ b/package/secubox/secubox-app-bonus/root/www/secubox-feed/Packages @@ -20,7 +20,7 @@ Architecture: all Installed-Size: 378880 Description: Advanced bandwidth management with QoS rules, client quotas, and SQM integration Filename: luci-app-bandwidth-manager_0.5.0-r2_all.ipk -Size: 66966 +Size: 66972 Package: luci-app-cdn-cache Version: 0.5.0-r3 @@ -32,7 +32,7 @@ Architecture: all Installed-Size: 122880 Description: Dashboard for managing local CDN caching proxy on OpenWrt Filename: luci-app-cdn-cache_0.5.0-r3_all.ipk -Size: 23189 +Size: 23190 Package: luci-app-client-guardian Version: 0.4.0-r7 @@ -44,7 +44,7 @@ Architecture: all Installed-Size: 307200 Description: Network Access Control with client monitoring, zone management, captive portal, parental controls, and SMS/email alerts Filename: luci-app-client-guardian_0.4.0-r7_all.ipk -Size: 57042 +Size: 57045 Package: luci-app-crowdsec-dashboard Version: 0.7.0-r29 @@ -56,7 +56,7 @@ Architecture: all Installed-Size: 296960 Description: Real-time security monitoring dashboard for CrowdSec on OpenWrt Filename: luci-app-crowdsec-dashboard_0.7.0-r29_all.ipk -Size: 55585 +Size: 55583 Package: luci-app-cyberfeed Version: 0.1.1-r1 @@ -68,7 +68,7 @@ Architecture: all Installed-Size: 71680 Description: Cyberpunk-themed RSS feed aggregator dashboard with social media support Filename: luci-app-cyberfeed_0.1.1-r1_all.ipk -Size: 12838 +Size: 12841 Package: luci-app-exposure Version: 1.0.0-r3 @@ -92,7 +92,7 @@ Architecture: all Installed-Size: 92160 Description: Modern dashboard for Gitea Platform management on OpenWrt Filename: luci-app-gitea_1.0.0-r2_all.ipk -Size: 15585 +Size: 15589 Package: luci-app-glances Version: 1.0.0-r2 @@ -104,7 +104,7 @@ Architecture: all Installed-Size: 40960 Description: Modern dashboard for Glances system monitoring with SecuBox theme Filename: luci-app-glances_1.0.0-r2_all.ipk -Size: 6963 +Size: 6968 Package: luci-app-haproxy Version: 1.0.0-r8 @@ -116,7 +116,7 @@ Architecture: all Installed-Size: 204800 Description: Web interface for managing HAProxy load balancer with vhosts, SSL certificates, and backend routing Filename: luci-app-haproxy_1.0.0-r8_all.ipk -Size: 34168 +Size: 34166 Package: luci-app-hexojs Version: 1.0.0-r3 @@ -128,7 +128,7 @@ Architecture: all Installed-Size: 215040 Description: Modern dashboard for Hexo static site generator on OpenWrt Filename: luci-app-hexojs_1.0.0-r3_all.ipk -Size: 32974 +Size: 32975 Package: luci-app-ksm-manager Version: 0.4.0-r2 @@ -140,7 +140,7 @@ Architecture: all Installed-Size: 112640 Description: Centralized cryptographic key management with hardware security module (HSM) support for Nitrokey and YubiKey devices. Provides secure key storage, certificate management, SSH key handling, and secret storage with audit logging. Filename: luci-app-ksm-manager_0.4.0-r2_all.ipk -Size: 18720 +Size: 18721 Package: luci-app-localai Version: 0.1.0-r15 @@ -164,7 +164,7 @@ Architecture: all Installed-Size: 40960 Description: LuCI support for Lyrion Music Server Filename: luci-app-lyrion_1.0.0-r1_all.ipk -Size: 6725 +Size: 6730 Package: luci-app-magicmirror2 Version: 0.4.0-r6 @@ -176,7 +176,7 @@ Architecture: all Installed-Size: 71680 Description: Modern dashboard for MagicMirror2 smart display platform with module manager and SecuBox theme Filename: luci-app-magicmirror2_0.4.0-r6_all.ipk -Size: 12274 +Size: 12277 Package: luci-app-mailinabox Version: 1.0.0-r1 @@ -188,7 +188,7 @@ Architecture: all Installed-Size: 30720 Description: LuCI support for Mail-in-a-Box Filename: luci-app-mailinabox_1.0.0-r1_all.ipk -Size: 5481 +Size: 5482 Package: luci-app-media-flow Version: 0.6.4-r1 @@ -200,7 +200,7 @@ Architecture: all Installed-Size: 102400 Description: Real-time detection and monitoring of streaming services (Netflix, YouTube, Spotify, etc.) with quality estimation, history tracking, and alerts. Supports nDPId local DPI and netifyd. Filename: luci-app-media-flow_0.6.4-r1_all.ipk -Size: 19120 +Size: 19117 Package: luci-app-metablogizer Version: 1.0.0-r3 @@ -212,7 +212,7 @@ Architecture: all Installed-Size: 112640 Description: LuCI support for MetaBlogizer Static Site Publisher Filename: luci-app-metablogizer_1.0.0-r3_all.ipk -Size: 23503 +Size: 23501 Package: luci-app-metabolizer Version: 1.0.0-r2 @@ -236,7 +236,7 @@ Architecture: all Installed-Size: 102400 Description: Modern dashboard for mitmproxy HTTPS traffic inspection with SecuBox theme Filename: luci-app-mitmproxy_0.4.0-r6_all.ipk -Size: 18933 +Size: 18932 Package: luci-app-mmpm Version: 0.2.0-r3 @@ -248,7 +248,7 @@ Architecture: all Installed-Size: 51200 Description: Web interface for MMPM - MagicMirror Package Manager Filename: luci-app-mmpm_0.2.0-r3_all.ipk -Size: 7899 +Size: 7901 Package: luci-app-mqtt-bridge Version: 0.4.0-r4 @@ -260,7 +260,7 @@ Architecture: all Installed-Size: 122880 Description: USB-to-MQTT IoT hub with SecuBox theme Filename: luci-app-mqtt-bridge_0.4.0-r4_all.ipk -Size: 22777 +Size: 22779 Package: luci-app-ndpid Version: 1.1.2-r2 @@ -272,7 +272,7 @@ Architecture: all Installed-Size: 122880 Description: Modern dashboard for nDPId deep packet inspection on OpenWrt Filename: luci-app-ndpid_1.1.2-r2_all.ipk -Size: 22455 +Size: 22457 Package: luci-app-netdata-dashboard Version: 0.5.0-r2 @@ -284,7 +284,7 @@ Architecture: all Installed-Size: 133120 Description: Real-time system monitoring dashboard with Netdata integration for OpenWrt Filename: luci-app-netdata-dashboard_0.5.0-r2_all.ipk -Size: 22396 +Size: 22400 Package: luci-app-network-modes Version: 0.5.0-r3 @@ -296,7 +296,7 @@ Architecture: all Installed-Size: 307200 Description: Configure OpenWrt for different network modes: Sniffer, Access Point, Relay, Router Filename: luci-app-network-modes_0.5.0-r3_all.ipk -Size: 55608 +Size: 55613 Package: luci-app-network-tweaks Version: 1.0.0-r7 @@ -308,7 +308,7 @@ Architecture: all Installed-Size: 81920 Description: Unified network services dashboard with DNS/hosts sync, CDN cache control, and WPAD auto-proxy configuration Filename: luci-app-network-tweaks_1.0.0-r7_all.ipk -Size: 15455 +Size: 15466 Package: luci-app-nextcloud Version: 1.0.0-r1 @@ -320,7 +320,7 @@ Architecture: all Installed-Size: 30720 Description: LuCI support for Nextcloud Filename: luci-app-nextcloud_1.0.0-r1_all.ipk -Size: 6485 +Size: 6487 Package: luci-app-ollama Version: 0.1.0-r1 @@ -332,7 +332,7 @@ Architecture: all Installed-Size: 71680 Description: Modern dashboard for Ollama LLM management on OpenWrt Filename: luci-app-ollama_0.1.0-r1_all.ipk -Size: 11991 +Size: 11998 Package: luci-app-picobrew Version: 1.0.0-r1 @@ -344,7 +344,7 @@ Architecture: all Installed-Size: 51200 Description: Modern dashboard for PicoBrew Server management on OpenWrt Filename: luci-app-picobrew_1.0.0-r1_all.ipk -Size: 9972 +Size: 9979 Package: luci-app-secubox Version: 0.7.1-r4 @@ -356,7 +356,7 @@ Architecture: all Installed-Size: 266240 Description: Central control hub for all SecuBox modules. Provides unified dashboard, module status, system health monitoring, and quick actions. Filename: luci-app-secubox_0.7.1-r4_all.ipk -Size: 49900 +Size: 49901 Package: luci-app-secubox-admin Version: 1.0.0-r19 @@ -367,7 +367,7 @@ Architecture: all Installed-Size: 337920 Description: Unified admin control center for SecuBox appstore plugins with system monitoring Filename: luci-app-secubox-admin_1.0.0-r19_all.ipk -Size: 57094 +Size: 57098 Package: luci-app-secubox-crowdsec Version: 1.0.0-r3 @@ -379,7 +379,7 @@ Architecture: all Installed-Size: 81920 Description: LuCI SecuBox CrowdSec Dashboard Filename: luci-app-secubox-crowdsec_1.0.0-r3_all.ipk -Size: 13914 +Size: 13925 Package: luci-app-secubox-netdiag Version: 1.0.0-r1 @@ -391,7 +391,7 @@ Architecture: all Installed-Size: 61440 Description: Real-time DSA switch port statistics, error monitoring, and network health diagnostics Filename: luci-app-secubox-netdiag_1.0.0-r1_all.ipk -Size: 12000 +Size: 12002 Package: luci-app-secubox-netifyd Version: 1.2.1-r1 @@ -415,7 +415,7 @@ Architecture: all Installed-Size: 215040 Description: LuCI SecuBox P2P Hub Filename: luci-app-secubox-p2p_0.1.0-r1_all.ipk -Size: 39254 +Size: 39257 Package: luci-app-secubox-portal Version: 0.7.0-r2 @@ -427,7 +427,7 @@ Architecture: all Installed-Size: 122880 Description: Unified entry point for all SecuBox applications with tabbed navigation Filename: luci-app-secubox-portal_0.7.0-r2_all.ipk -Size: 24553 +Size: 24557 Package: luci-app-secubox-security-threats Version: 1.0.0-r4 @@ -439,7 +439,7 @@ Architecture: all Installed-Size: 71680 Description: Unified dashboard integrating netifyd DPI threats with CrowdSec intelligence for real-time threat monitoring and automated blocking Filename: luci-app-secubox-security-threats_1.0.0-r4_all.ipk -Size: 13899 +Size: 13906 Package: luci-app-service-registry Version: 1.0.0-r1 @@ -451,7 +451,7 @@ Architecture: all Installed-Size: 194560 Description: Unified service aggregation with HAProxy vhosts, Tor hidden services, and QR-coded landing page Filename: luci-app-service-registry_1.0.0-r1_all.ipk -Size: 39826 +Size: 39827 Package: luci-app-streamlit Version: 1.0.0-r9 @@ -463,7 +463,7 @@ Architecture: all Installed-Size: 122880 Description: Modern dashboard for Streamlit Platform management on OpenWrt Filename: luci-app-streamlit_1.0.0-r9_all.ipk -Size: 20470 +Size: 20471 Package: luci-app-system-hub Version: 0.5.1-r4 @@ -475,7 +475,7 @@ Architecture: all Installed-Size: 358400 Description: Central system control with monitoring, services, logs, and backup Filename: luci-app-system-hub_0.5.1-r4_all.ipk -Size: 66345 +Size: 66351 Package: luci-app-tor-shield Version: 1.0.0-r10 @@ -487,7 +487,7 @@ Architecture: all Installed-Size: 133120 Description: Modern dashboard for Tor anonymization on OpenWrt Filename: luci-app-tor-shield_1.0.0-r10_all.ipk -Size: 24532 +Size: 24537 Package: luci-app-traffic-shaper Version: 0.4.0-r2 @@ -499,7 +499,7 @@ Architecture: all Installed-Size: 92160 Description: Advanced traffic shaping with TC/CAKE for precise bandwidth control Filename: luci-app-traffic-shaper_0.4.0-r2_all.ipk -Size: 15635 +Size: 15637 Package: luci-app-vhost-manager Version: 0.5.0-r5 @@ -511,7 +511,7 @@ Architecture: all Installed-Size: 153600 Description: Nginx reverse proxy manager with Let's Encrypt SSL certificates, authentication, and WebSocket support Filename: luci-app-vhost-manager_0.5.0-r5_all.ipk -Size: 26199 +Size: 26204 Package: luci-app-wireguard-dashboard Version: 0.7.0-r5 @@ -523,7 +523,7 @@ Architecture: all Installed-Size: 235520 Description: Modern dashboard for WireGuard VPN monitoring on OpenWrt Filename: luci-app-wireguard-dashboard_0.7.0-r5_all.ipk -Size: 45368 +Size: 45372 Package: luci-app-zigbee2mqtt Version: 1.0.0-r2 @@ -535,7 +535,7 @@ Architecture: all Installed-Size: 40960 Description: Graphical interface for managing the Zigbee2MQTT docker application. Filename: luci-app-zigbee2mqtt_1.0.0-r2_all.ipk -Size: 7085 +Size: 7095 Package: luci-theme-secubox Version: 0.4.7-r1 @@ -547,7 +547,7 @@ Architecture: all Installed-Size: 460800 Description: Global CyberMood design system (CSS/JS/i18n) shared by all SecuBox dashboards. Filename: luci-theme-secubox_0.4.7-r1_all.ipk -Size: 111793 +Size: 111798 Package: secubox-app Version: 1.0.0-r2 @@ -558,7 +558,7 @@ Installed-Size: 92160 Description: Command line helper for SecuBox App Store manifests. Installs /usr/sbin/secubox-app and ships the default manifests under /usr/share/secubox/plugins/. Filename: secubox-app_1.0.0-r2_all.ipk -Size: 11185 +Size: 11181 Package: secubox-app-adguardhome Version: 1.0.0-r2 @@ -572,7 +572,7 @@ Description: Installer, configuration, and service manager for running AdGuard inside Docker on SecuBox-powered OpenWrt systems. Network-wide ad blocker with DNS-over-HTTPS/TLS support and detailed analytics. Filename: secubox-app-adguardhome_1.0.0-r2_all.ipk -Size: 2876 +Size: 2883 Package: secubox-app-auth-logger Version: 1.2.2-r1 @@ -590,7 +590,7 @@ Description: Logs authentication failures from LuCI/rpcd and Dropbear SSH - JavaScript hook to intercept login failures - CrowdSec parser and bruteforce scenario Filename: secubox-app-auth-logger_1.2.2-r1_all.ipk -Size: 9378 +Size: 9379 Package: secubox-app-crowdsec-custom Version: 1.1.0-r1 @@ -613,7 +613,7 @@ Description: Custom CrowdSec configurations for SecuBox web interface protectio - Webapp generic auth bruteforce protection - Whitelist for trusted networks Filename: secubox-app-crowdsec-custom_1.1.0-r1_all.ipk -Size: 5759 +Size: 5767 Package: secubox-app-cs-firewall-bouncer Version: 0.0.31-r4 @@ -640,7 +640,7 @@ Description: SecuBox CrowdSec Firewall Bouncer for OpenWrt. - Automatic restart on firewall reload - procd service management Filename: secubox-app-cs-firewall-bouncer_0.0.31-r4_aarch64_cortex-a72.ipk -Size: 5049321 +Size: 5049326 Package: secubox-app-cyberfeed Version: 0.2.1-r1 @@ -654,7 +654,7 @@ Description: Cyberpunk-themed RSS feed aggregator for OpenWrt/SecuBox. Features emoji injection, neon styling, and RSS-Bridge support for social media feeds (Facebook, Twitter, Mastodon). Filename: secubox-app-cyberfeed_0.2.1-r1_all.ipk -Size: 12451 +Size: 12453 Package: secubox-app-domoticz Version: 1.0.0-r2 @@ -667,7 +667,7 @@ Installed-Size: 10240 Description: Installer, configuration, and service manager for running Domoticz inside Docker on SecuBox-powered OpenWrt systems. Filename: secubox-app-domoticz_1.0.0-r2_all.ipk -Size: 2544 +Size: 2553 Package: secubox-app-exposure Version: 1.0.0-r1 @@ -682,7 +682,7 @@ Description: Unified service exposure manager for SecuBox. - Dynamic Tor hidden service management - HAProxy SSL reverse proxy configuration Filename: secubox-app-exposure_1.0.0-r1_all.ipk -Size: 6825 +Size: 6838 Package: secubox-app-gitea Version: 1.0.0-r5 @@ -772,7 +772,7 @@ Description: Hexo CMS - Self-hosted static blog generator for OpenWrt Runs in LXC container with Alpine Linux. Configure in /etc/config/hexojs. Filename: secubox-app-hexojs_1.0.0-r8_all.ipk -Size: 94934 +Size: 94935 Package: secubox-app-localai Version: 2.25.0-r1 @@ -794,7 +794,7 @@ Description: LocalAI native binary package for OpenWrt. API: http://:8081/v1 Filename: secubox-app-localai_2.25.0-r1_all.ipk -Size: 5712 +Size: 5721 Package: secubox-app-localai-wb Version: 2.25.0-r1 @@ -818,7 +818,7 @@ Description: LocalAI native binary package for OpenWrt. API: http://:8080/v1 Filename: secubox-app-localai-wb_2.25.0-r1_all.ipk -Size: 7950 +Size: 7956 Package: secubox-app-lyrion Version: 2.0.2-r1 @@ -838,7 +838,7 @@ Description: Lyrion Media Server (formerly Logitech Media Server / Squeezebox S Auto-detects available runtime, preferring LXC for lower resource usage. Configure runtime in /etc/config/lyrion. Filename: secubox-app-lyrion_2.0.2-r1_all.ipk -Size: 7285 +Size: 7289 Package: secubox-app-magicmirror2 Version: 0.4.0-r8 @@ -860,7 +860,7 @@ Description: MagicMirrorΒ² - Open source modular smart mirror platform for Secu Runs in LXC container for isolation and security. Configure in /etc/config/magicmirror2. Filename: secubox-app-magicmirror2_0.4.0-r8_all.ipk -Size: 9251 +Size: 9249 Package: secubox-app-mailinabox Version: 2.0.0-r1 @@ -885,7 +885,7 @@ Description: Complete email server solution using docker-mailserver for SecuBox Commands: mailinaboxctl --help Filename: secubox-app-mailinabox_2.0.0-r1_all.ipk -Size: 7566 +Size: 7575 Package: secubox-app-metabolizer Version: 1.0.0-r3 @@ -906,7 +906,7 @@ Description: Metabolizer Blog Pipeline - Integrated CMS with Git-based workflow Pipeline: Edit in Streamlit -> Push to Gitea -> Build with Hexo -> Publish Filename: secubox-app-metabolizer_1.0.0-r3_all.ipk -Size: 13979 +Size: 13984 Package: secubox-app-mitmproxy Version: 0.4.0-r16 @@ -927,7 +927,7 @@ Description: mitmproxy - Interactive HTTPS proxy for SecuBox-powered OpenWrt sy Runs in LXC container for isolation and security. Configure in /etc/config/mitmproxy. Filename: secubox-app-mitmproxy_0.4.0-r16_all.ipk -Size: 10215 +Size: 10213 Package: secubox-app-mmpm Version: 0.2.0-r5 @@ -948,7 +948,7 @@ Description: MMPM (MagicMirror Package Manager) for SecuBox. Runs inside the MagicMirror2 LXC container. Filename: secubox-app-mmpm_0.2.0-r5_all.ipk -Size: 3974 +Size: 3977 Package: secubox-app-nextcloud Version: 1.0.0-r2 @@ -962,7 +962,7 @@ Description: Installer, configuration, and service manager for running Nextclou inside Docker on SecuBox-powered OpenWrt systems. Self-hosted file sync and share with calendar, contacts, and collaboration. Filename: secubox-app-nextcloud_1.0.0-r2_all.ipk -Size: 2955 +Size: 2959 Package: secubox-app-ollama Version: 0.1.0-r1 @@ -984,7 +984,7 @@ Description: Ollama - Simple local LLM runtime for SecuBox-powered OpenWrt syst Runs in Docker/Podman container. Configure in /etc/config/ollama. Filename: secubox-app-ollama_0.1.0-r1_all.ipk -Size: 5733 +Size: 5739 Package: secubox-app-picobrew Version: 1.0.0-r7 @@ -1033,7 +1033,7 @@ Description: Streamlit App Platform - Self-hosted Python data app platform Configure in /etc/config/streamlit. Filename: secubox-app-streamlit_1.0.0-r5_all.ipk -Size: 11717 +Size: 11721 Package: secubox-app-tor Version: 1.0.0-r1 @@ -1056,7 +1056,7 @@ Description: SecuBox Tor Shield - One-click Tor anonymization for OpenWrt Configure in /etc/config/tor-shield. Filename: secubox-app-tor_1.0.0-r1_all.ipk -Size: 7379 +Size: 7377 Package: secubox-app-webapp Version: 1.5.0-r7 @@ -1074,7 +1074,7 @@ Description: SecuBox Control Center Dashboard - A web-based dashboard for monit - Service management - Network interface control Filename: secubox-app-webapp_1.5.0-r7_all.ipk -Size: 39169 +Size: 39171 Package: secubox-app-zigbee2mqtt Version: 1.0.0-r3 @@ -1087,7 +1087,7 @@ Installed-Size: 20480 Description: Installer, configuration, and service manager for running Zigbee2MQTT inside Docker on SecuBox-powered OpenWrt systems. Filename: secubox-app-zigbee2mqtt_1.0.0-r3_all.ipk -Size: 3542 +Size: 3545 Package: secubox-core Version: 0.10.0-r9 @@ -1107,21 +1107,22 @@ Description: SecuBox Core Framework provides the foundational infrastructure fo - Unified CLI interface - ubus RPC backend Filename: secubox-core_0.10.0-r9_all.ipk -Size: 80068 +Size: 80071 Package: secubox-p2p -Version: 0.4.0-r1 +Version: 0.5.0-r1 Depends: jsonfilter, curl, avahi-daemon, avahi-utils, uhttpd License: MIT Section: secubox Maintainer: SecuBox Team Architecture: all -Installed-Size: 133120 +Installed-Size: 143360 Description: SecuBox P2P Hub backend providing peer discovery, mesh networking DNS federation, and distributed service management. Includes mDNS service announcement, REST API on port 7331 for mesh visibility - and SecuBox Factory unified dashboard with Ed25519 signed Merkle - snapshots for cryptographic configuration validation. -Filename: secubox-p2p_0.4.0-r1_all.ipk -Size: 27891 + SecuBox Factory unified dashboard with Ed25519 signed Merkle + snapshots for cryptographic configuration validation, and distributed + mesh services panel for aggregated service discovery across all nodes. +Filename: secubox-p2p_0.5.0-r1_all.ipk +Size: 30574 diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/Packages.gz b/package/secubox/secubox-app-bonus/root/www/secubox-feed/Packages.gz index cd87c993..21c75f54 100644 Binary files a/package/secubox/secubox-app-bonus/root/www/secubox-feed/Packages.gz and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/Packages.gz differ diff --git a/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-p2p_0.5.0-r1_all.ipk b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-p2p_0.5.0-r1_all.ipk new file mode 100644 index 00000000..0d8cc19a Binary files /dev/null and b/package/secubox/secubox-app-bonus/root/www/secubox-feed/secubox-p2p_0.5.0-r1_all.ipk differ diff --git a/package/secubox/secubox-p2p/Makefile b/package/secubox/secubox-p2p/Makefile index 7a82073d..fb30202f 100644 --- a/package/secubox/secubox-p2p/Makefile +++ b/package/secubox/secubox-p2p/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=secubox-p2p -PKG_VERSION:=0.5.0 +PKG_VERSION:=0.6.0 PKG_RELEASE:=1 PKG_MAINTAINER:=SecuBox Team @@ -22,8 +22,10 @@ define Package/secubox-p2p/description DNS federation, and distributed service management. Includes mDNS service announcement, REST API on port 7331 for mesh visibility, SecuBox Factory unified dashboard with Ed25519 signed Merkle - snapshots for cryptographic configuration validation, and distributed - mesh services panel for aggregated service discovery across all nodes. + snapshots for cryptographic configuration validation, distributed + mesh services panel for aggregated service discovery across all nodes, + and MirrorBox NetMesh Catalog for cross-chain distributed service + registry with HAProxy vhost discovery and multi-endpoint access URLs. endef define Package/secubox-p2p/conffiles @@ -66,6 +68,7 @@ define Package/secubox-p2p/install $(INSTALL_BIN) ./root/www/api/factory/snapshot $(1)/www/api/factory/ $(INSTALL_BIN) ./root/www/api/factory/pubkey $(1)/www/api/factory/ $(INSTALL_BIN) ./root/www/api/factory/mesh-services $(1)/www/api/factory/ + $(INSTALL_BIN) ./root/www/api/factory/catalog $(1)/www/api/factory/ # Factory Web UI $(INSTALL_DIR) $(1)/www/factory diff --git a/package/secubox/secubox-p2p/root/usr/lib/secubox/factory.sh b/package/secubox/secubox-p2p/root/usr/lib/secubox/factory.sh index 31a3c65c..e9007be5 100644 --- a/package/secubox/secubox-p2p/root/usr/lib/secubox/factory.sh +++ b/package/secubox/secubox-p2p/root/usr/lib/secubox/factory.sh @@ -295,6 +295,177 @@ factory_audit_log() { fi } +# =========================================== +# Distributed Catalog Functions +# =========================================== + +CATALOG_DIR="$FACTORY_DIR/catalog" +LOCAL_CATALOG="$CATALOG_DIR/local.json" +MERGED_CATALOG="$CATALOG_DIR/merged.json" + +# Initialize catalog directory +catalog_init() { + factory_init + mkdir -p "$CATALOG_DIR" + mkdir -p "$CATALOG_DIR/peers" +} + +# Generate local catalog (calls the CGI endpoint logic) +catalog_generate_local() { + catalog_init + local node_id=$(cat "$P2P_STATE_DIR/node.id" 2>/dev/null || hostname) + local node_name=$(uci -q get system.@system[0].hostname || hostname) + local updated=$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S') + + # Fetch from local catalog API + local catalog=$(curl -s "http://127.0.0.1:7331/api/factory/catalog" 2>/dev/null) + + if [ -n "$catalog" ] && echo "$catalog" | grep -q "node_id"; then + echo "$catalog" > "$LOCAL_CATALOG" + echo "$LOCAL_CATALOG" + else + echo '{"error":"catalog_generation_failed"}' > "$LOCAL_CATALOG" + echo "$LOCAL_CATALOG" + fi +} + +# Pull catalog from a peer +catalog_pull_peer() { + local peer_addr="$1" + local peer_name="${2:-$peer_addr}" + + [ -z "$peer_addr" ] && return 1 + + catalog_init + + local peer_catalog=$(curl -s --connect-timeout 3 --max-time 10 "http://$peer_addr:7331/api/factory/catalog" 2>/dev/null) + + if [ -n "$peer_catalog" ] && echo "$peer_catalog" | grep -q "node_id"; then + local peer_node_name=$(echo "$peer_catalog" | jsonfilter -e '@.node_name' 2>/dev/null || echo "$peer_name") + echo "$peer_catalog" > "$CATALOG_DIR/peers/${peer_node_name}.json" + echo "pulled:$peer_node_name" + else + echo "failed:$peer_addr" + fi +} + +# Sync catalogs with all known peers +catalog_sync() { + catalog_init + + local peers_file="/tmp/secubox-p2p-peers.json" + [ -f "$peers_file" ] || { echo '{"synced":0,"error":"no_peers"}'; return 1; } + + # Generate local catalog first + catalog_generate_local >/dev/null 2>&1 + + # Pull from all online peers + local synced=0 + local failed=0 + local peer_count=$(jsonfilter -i "$peers_file" -e '@.peers[*]' 2>/dev/null | wc -l) + local p=0 + + while [ $p -lt $peer_count ]; do + local peer_addr=$(jsonfilter -i "$peers_file" -e "@.peers[$p].address" 2>/dev/null) + local peer_name=$(jsonfilter -i "$peers_file" -e "@.peers[$p].name" 2>/dev/null) + local is_local=$(jsonfilter -i "$peers_file" -e "@.peers[$p].is_local" 2>/dev/null) + + if [ "$is_local" != "true" ] && [ -n "$peer_addr" ]; then + local result=$(catalog_pull_peer "$peer_addr" "$peer_name") + if echo "$result" | grep -q "^pulled:"; then + synced=$((synced + 1)) + else + failed=$((failed + 1)) + fi + fi + p=$((p + 1)) + done + + # Merge all catalogs + catalog_merge + + # Push to Gitea if enabled + if [ "$(uci -q get secubox-p2p.gitea.enabled)" = "1" ]; then + catalog_push_gitea + fi + + echo "{\"synced\":$synced,\"failed\":$failed}" +} + +# Merge all catalogs into unified view (CRDT union) +catalog_merge() { + catalog_init + + local merged_services='{"nodes":[' + local first_node=1 + + # Add local catalog + if [ -f "$LOCAL_CATALOG" ]; then + [ $first_node -eq 0 ] && merged_services="$merged_services," + first_node=0 + cat "$LOCAL_CATALOG" | tr '\n' ' ' | tr '\t' ' ' >> /tmp/catalog_merge_local.tmp + local local_entry=$(cat /tmp/catalog_merge_local.tmp) + merged_services="$merged_services$local_entry" + rm -f /tmp/catalog_merge_local.tmp + fi + + # Add peer catalogs + for peer_catalog in "$CATALOG_DIR/peers"/*.json; do + [ -f "$peer_catalog" ] || continue + [ $first_node -eq 0 ] && merged_services="$merged_services," + first_node=0 + cat "$peer_catalog" | tr '\n' ' ' | tr '\t' ' ' >> /tmp/catalog_merge_peer.tmp + local peer_entry=$(cat /tmp/catalog_merge_peer.tmp) + merged_services="$merged_services$peer_entry" + rm -f /tmp/catalog_merge_peer.tmp + done + + merged_services="$merged_services],\"updated\":\"$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S')\"}" + + echo "$merged_services" > "$MERGED_CATALOG" +} + +# Push catalog to Gitea repository +catalog_push_gitea() { + local gitea_enabled=$(uci -q get secubox-p2p.gitea.enabled) + [ "$gitea_enabled" = "1" ] || return 0 + + local node_name=$(uci -q get system.@system[0].hostname || hostname) + + # This would push to secubox-catalog repo in Gitea + # For now, just log the action + logger -t factory "Catalog sync: would push to Gitea nodes/${node_name}.json" + + # Future: use ubus call to trigger actual git push + # ubus call luci.secubox-p2p push_catalog_gitea "{\"file\":\"nodes/${node_name}.json\"}" 2>/dev/null +} + +# Get merged catalog JSON +catalog_get_merged() { + if [ -f "$MERGED_CATALOG" ]; then + cat "$MERGED_CATALOG" + elif [ -f "$LOCAL_CATALOG" ]; then + # Return local only if no merge yet + echo "{\"nodes\":[$(cat "$LOCAL_CATALOG" | tr '\n' ' ')],\"updated\":\"$(date -Iseconds)\"}" + else + echo '{"nodes":[],"updated":"","error":"no_catalog"}' + fi +} + +# List available catalogs +catalog_list() { + catalog_init + echo "Local catalog: $LOCAL_CATALOG" + [ -f "$LOCAL_CATALOG" ] && echo " - $(jsonfilter -i "$LOCAL_CATALOG" -e '@.node_name' 2>/dev/null || echo 'unknown')" + + echo "Peer catalogs:" + for peer_catalog in "$CATALOG_DIR/peers"/*.json; do + [ -f "$peer_catalog" ] || continue + local name=$(basename "$peer_catalog" .json) + echo " - $name" + done +} + # Main entry point for CLI usage case "${1:-}" in init) @@ -331,6 +502,33 @@ case "${1:-}" in merkle) merkle_config ;; + # Catalog commands + catalog) + case "${2:-}" in + sync) + catalog_sync + ;; + list) + catalog_list + ;; + generate) + catalog_generate_local + ;; + merge) + catalog_merge + echo "Merged catalog: $MERGED_CATALOG" + ;; + get) + catalog_get_merged + ;; + pull) + catalog_pull_peer "$3" "$4" + ;; + *) + echo "Usage: factory.sh catalog {sync|list|generate|merge|get|pull }" + ;; + esac + ;; *) # Sourced as library - do nothing : diff --git a/package/secubox/secubox-p2p/root/usr/sbin/secubox-p2p b/package/secubox/secubox-p2p/root/usr/sbin/secubox-p2p index 26b4329e..c48ddad9 100644 --- a/package/secubox/secubox-p2p/root/usr/sbin/secubox-p2p +++ b/package/secubox/secubox-p2p/root/usr/sbin/secubox-p2p @@ -3,7 +3,7 @@ # Handles peer discovery, mesh networking, and service federation # Supports WAN IP, LAN IP, and WireGuard tunnel redundancy -VERSION="0.4.0" +VERSION="0.6.0" CONFIG_FILE="/etc/config/secubox-p2p" PEERS_FILE="/tmp/secubox-p2p-peers.json" SERVICES_FILE="/tmp/secubox-p2p-services.json" @@ -439,6 +439,210 @@ stop_mdns() { fi } +# =========================================== +# DNS Federation - Dynamic mesh DNS entries +# =========================================== + +DNS_HOSTS_FILE="/tmp/hosts/secubox-mesh" +DNS_DOMAIN_BASE="mesh.local" + +# Initialize DNS federation +dns_init() { + local dns_enabled=$(get_config dns enabled 0) + [ "$dns_enabled" = "1" ] || return 0 + + DNS_DOMAIN_BASE=$(get_config dns base_domain "mesh.local") + + # Ensure hosts directory exists + mkdir -p /tmp/hosts + + # Create or update mesh hosts file + touch "$DNS_HOSTS_FILE" + + # Ensure dnsmasq reads from /tmp/hosts + # Check if addn-hosts is configured + if ! uci -q get dhcp.@dnsmasq[0].addnhosts | grep -q "/tmp/hosts"; then + uci add_list dhcp.@dnsmasq[0].addnhosts="/tmp/hosts" + uci commit dhcp + logger -t secubox-p2p "Added /tmp/hosts to dnsmasq additional hosts" + fi +} + +# Update DNS entries for all mesh peers +dns_update_peers() { + local dns_enabled=$(get_config dns enabled 0) + [ "$dns_enabled" = "1" ] || return 0 + + dns_init + + local base_domain=$(get_config dns base_domain "mesh.local") + local hosts_content="" + local count=0 + + # Get all peers (including local) + local peers_json=$(cat "$PEERS_FILE" 2>/dev/null || echo '{"peers":[]}') + + # Parse peers and build hosts entries + # Format: IP hostname hostname.mesh.local + if command -v jq >/dev/null 2>&1; then + hosts_content=$(echo "$peers_json" | jq -r '.peers[] | select(.status == "online" or .is_local == true) | + # Build hostname entries + ( + (.address // empty) as $lan | + (.wan_address // empty) as $wan | + (.wg_addresses // empty) as $wg | + (.name // "peer") | gsub(" \\(local\\)"; "") | gsub("[^a-zA-Z0-9-]"; "-") | ascii_downcase as $hostname | + + # LAN entry (primary for local network) + (if $lan != "" and $lan != null then + "\($lan)\t\($hostname)\t\($hostname).'$base_domain'" + else empty end), + + # WireGuard entry (for mesh access) + (if $wg != "" and $wg != null then + ($wg | split(",")[0]) as $wg_ip | + if $wg_ip != "" then + "\($wg_ip)\t\($hostname)-wg\t\($hostname)-wg.'$base_domain'" + else empty end + else empty end) + ) + ' 2>/dev/null) + else + # Fallback without jq - use jsonfilter + local peer_count=$(echo "$peers_json" | jsonfilter -e '@.peers[*]' 2>/dev/null | wc -l) + local i=0 + + while [ $i -lt $peer_count ]; do + local addr=$(echo "$peers_json" | jsonfilter -e "@.peers[$i].address" 2>/dev/null) + local name=$(echo "$peers_json" | jsonfilter -e "@.peers[$i].name" 2>/dev/null) + local status=$(echo "$peers_json" | jsonfilter -e "@.peers[$i].status" 2>/dev/null) + local is_local=$(echo "$peers_json" | jsonfilter -e "@.peers[$i].is_local" 2>/dev/null) + local wg_addr=$(echo "$peers_json" | jsonfilter -e "@.peers[$i].wg_addresses" 2>/dev/null | cut -d',' -f1) + + # Only add online peers or local node + if [ "$status" = "online" ] || [ "$is_local" = "true" ]; then + # Clean hostname (remove special chars) + local hostname=$(echo "$name" | sed -e 's/ (local)//' -e 's/[^a-zA-Z0-9-]/-/g' | tr 'A-Z' 'a-z') + + # Add LAN entry + if [ -n "$addr" ]; then + hosts_content="$hosts_content$addr $hostname $hostname.$base_domain +" + count=$((count + 1)) + fi + + # Add WireGuard entry + if [ -n "$wg_addr" ]; then + hosts_content="$hosts_content$wg_addr ${hostname}-wg ${hostname}-wg.$base_domain +" + count=$((count + 1)) + fi + fi + i=$((i + 1)) + done + fi + + # Write hosts file + echo "# SecuBox Mesh DNS Federation - Auto-generated" > "$DNS_HOSTS_FILE" + echo "# Domain: $base_domain" >> "$DNS_HOSTS_FILE" + echo "# Updated: $(date -Iseconds 2>/dev/null || date)" >> "$DNS_HOSTS_FILE" + echo "" >> "$DNS_HOSTS_FILE" + echo "$hosts_content" >> "$DNS_HOSTS_FILE" + + # Count actual entries (non-comment, non-empty lines) + count=$(grep -c "^[0-9]" "$DNS_HOSTS_FILE" 2>/dev/null || echo "0") + + # Signal dnsmasq to reload hosts + killall -HUP dnsmasq 2>/dev/null || /etc/init.d/dnsmasq reload 2>/dev/null + + logger -t secubox-p2p "DNS federation updated: $count mesh host entries in $base_domain" + echo "{\"success\":true,\"entries\":$count,\"domain\":\"$base_domain\"}" +} + +# Add a single peer to DNS +dns_add_peer() { + local hostname="$1" + local ip="$2" + + local dns_enabled=$(get_config dns enabled 0) + [ "$dns_enabled" = "1" ] || return 0 + + local base_domain=$(get_config dns base_domain "mesh.local") + + # Clean hostname + hostname=$(echo "$hostname" | sed -e 's/[^a-zA-Z0-9-]/-/g' | tr 'A-Z' 'a-z') + + # Append to hosts file (avoid duplicates) + if ! grep -q " $hostname " "$DNS_HOSTS_FILE" 2>/dev/null; then + echo "$ip $hostname $hostname.$base_domain" >> "$DNS_HOSTS_FILE" + killall -HUP dnsmasq 2>/dev/null + logger -t secubox-p2p "DNS: Added $hostname.$base_domain -> $ip" + fi +} + +# Remove a peer from DNS +dns_remove_peer() { + local hostname="$1" + + local dns_enabled=$(get_config dns enabled 0) + [ "$dns_enabled" = "1" ] || return 0 + + # Clean hostname + hostname=$(echo "$hostname" | sed -e 's/[^a-zA-Z0-9-]/-/g' | tr 'A-Z' 'a-z') + + # Remove from hosts file + sed -i "/ $hostname /d" "$DNS_HOSTS_FILE" 2>/dev/null + killall -HUP dnsmasq 2>/dev/null + logger -t secubox-p2p "DNS: Removed $hostname" +} + +# Get DNS federation status +dns_status() { + local dns_enabled=$(get_config dns enabled 0) + local base_domain=$(get_config dns base_domain "mesh.local") + local entry_count=0 + + if [ -f "$DNS_HOSTS_FILE" ]; then + entry_count=$(grep -c "^[0-9]" "$DNS_HOSTS_FILE" 2>/dev/null || echo "0") + fi + + cat << EOF +{ + "enabled": $dns_enabled, + "domain": "$base_domain", + "hosts_file": "$DNS_HOSTS_FILE", + "entries": $entry_count, + "dnsmasq_running": $(pgrep dnsmasq >/dev/null && echo "true" || echo "false") +} +EOF +} + +# Enable DNS federation +dns_enable() { + set_config dns enabled 1 + + local base_domain="${1:-mesh.local}" + set_config dns base_domain "$base_domain" + + dns_init + dns_update_peers + + logger -t secubox-p2p "DNS federation enabled with domain: $base_domain" + echo "{\"success\":true,\"domain\":\"$base_domain\"}" +} + +# Disable DNS federation +dns_disable() { + set_config dns enabled 0 + + # Clear hosts file + echo "# SecuBox Mesh DNS Federation - Disabled" > "$DNS_HOSTS_FILE" + killall -HUP dnsmasq 2>/dev/null + + logger -t secubox-p2p "DNS federation disabled" + echo "{\"success\":true}" +} + # Get node status JSON (for REST API) # Now includes WAN IP and WireGuard tunnel addresses get_node_status() { @@ -526,6 +730,9 @@ daemon_loop() { # Register self in peer list register_self + # Initialize DNS federation + dns_init + # Setup signal handlers trap 'stop_mdns; exit 0' INT TERM @@ -603,6 +810,9 @@ daemon_loop() { echo "$peers" > "$PEERS_FILE" fi + # Update DNS federation with current peer list + dns_update_peers >/dev/null 2>&1 + # Sleep interval local interval=$(get_config main sync_interval 60) sleep "$interval" @@ -660,8 +870,28 @@ case "$1" in init register_self ;; + # DNS Federation commands + dns-status) + dns_status + ;; + dns-enable) + dns_enable "$2" + ;; + dns-disable) + dns_disable + ;; + dns-update) + init + dns_update_peers + ;; + dns-add) + dns_add_peer "$2" "$3" + ;; + dns-remove) + dns_remove_peer "$2" + ;; *) - echo "Usage: $0 {daemon|discover|peers|add-peer|remove-peer|settings|set-settings|services|shared-services|sync|broadcast|version|status|publish-mdns|stop-mdns|register-self}" + echo "Usage: $0 {daemon|discover|peers|add-peer|remove-peer|settings|set-settings|services|shared-services|sync|broadcast|version|status|publish-mdns|stop-mdns|register-self|dns-status|dns-enable|dns-disable|dns-update|dns-add|dns-remove}" exit 1 ;; esac diff --git a/package/secubox/secubox-p2p/root/www/api/factory/catalog b/package/secubox/secubox-p2p/root/www/api/factory/catalog new file mode 100644 index 00000000..7bbc9925 --- /dev/null +++ b/package/secubox/secubox-p2p/root/www/api/factory/catalog @@ -0,0 +1,351 @@ +#!/bin/sh +# Factory Catalog - Distributed Service Registry +# CGI endpoint for MirrorBox NetMesh Catalog +# Returns services with multiple access endpoints (HAProxy vhosts, mesh, local) + +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 + +# Source OpenWrt functions for UCI iteration +. /lib/functions.sh + +# Load factory library +. /usr/lib/secubox/factory.sh 2>/dev/null + +# Get local node info +P2P_STATE_DIR="/var/run/secubox-p2p" +LOCAL_NODE_ID=$(cat "$P2P_STATE_DIR/node.id" 2>/dev/null || hostname) +LOCAL_NODE_NAME=$(uci -q get system.@system[0].hostname || hostname) +LOCAL_IP=$(uci -q get network.lan.ipaddr || echo "192.168.255.1") +UPDATED=$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S') + +# DNS Federation settings +DNS_ENABLED=$(uci -q get secubox-p2p.dns.enabled || echo "0") +DNS_DOMAIN=$(uci -q get secubox-p2p.dns.base_domain || echo "mesh.local") + +# Generate DNS hostname from node name +get_dns_hostname() { + local name="$1" + # Remove "(local)" suffix, lowercase, replace special chars with dashes + echo "$name" | sed -e 's/ (local)//' -e 's/[^a-zA-Z0-9-]/-/g' | tr 'A-Z' 'a-z' +} + +# Get WAN IP (for external access) +get_wan_ip() { + # Try to get WAN IP from interface + local wan_ip=$(ip -4 addr show wan 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) + [ -z "$wan_ip" ] && wan_ip=$(ip -4 addr show pppoe-wan 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) + [ -z "$wan_ip" ] && wan_ip=$(ip -4 addr show eth1 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) + # Fallback: try to detect via external service (cached) + if [ -z "$wan_ip" ] && [ -f "/tmp/secubox-wan-ip" ]; then + wan_ip=$(cat /tmp/secubox-wan-ip) + fi + echo "$wan_ip" +} + +# Get WireGuard mesh IP +get_mesh_ip() { + local mesh_ip=$(ip -4 addr show wg0 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1) + echo "$mesh_ip" +} + +# Build HAProxy vhost map: domain -> backend +# Returns: domain|backend|ssl|enabled for each vhost +get_haproxy_vhosts() { + config_load haproxy 2>/dev/null || return + + # Callback function for each vhost + _emit_vhost() { + local section="$1" + local enabled domain backend ssl ssl_redirect + + config_get enabled "$section" enabled "0" + [ "$enabled" = "1" ] || return + + config_get domain "$section" domain + config_get backend "$section" backend + config_get ssl "$section" ssl "0" + config_get ssl_redirect "$section" ssl_redirect "0" + + [ -n "$domain" ] || return + [ -n "$backend" ] || return + + # Determine scheme + local scheme="http" + [ "$ssl" = "1" ] && scheme="https" + + echo "${domain}|${backend}|${scheme}|${ssl_redirect}" + } + + config_foreach _emit_vhost vhost +} + +# Map backend name to service name (normalize) +# E.g., backend_gitea -> gitea, srv_domoticz -> domoticz +normalize_backend_name() { + local backend="$1" + # Strip common prefixes + echo "$backend" | sed -e 's/^backend_//' -e 's/^srv_//' -e 's/^be_//' -e 's/_/-/g' +} + +# Get service status and port from init scripts +get_service_info() { + local svc_name="$1" + local status="unknown" + local port="" + local enabled=false + + # Check init script + local init_script="/etc/init.d/$svc_name" + if [ -x "$init_script" ]; then + enabled=$("$init_script" enabled 2>/dev/null && echo true || echo false) + # Check if running + if pgrep "$svc_name" >/dev/null 2>&1; then + status="running" + else + status="stopped" + fi + fi + + # Try to find port from UCI or known mappings + case "$svc_name" in + gitea) port="3000" ;; + domoticz) port="8080" ;; + crowdsec) port="8080" ;; + haproxy) port="8404" ;; + adguardhome) port="3000" ;; + netdata) port="19999" ;; + glances) port="61208" ;; + streamlit) port="8501" ;; + zigbee2mqtt) port="8080" ;; + nextcloud) port="8080" ;; + ollama) port="11434" ;; + localai) port="8080" ;; + wireguard-dashboard|wg-dashboard) port="10086" ;; + mitmproxy) port="8081" ;; + *) + # Try to get from UCI config + port=$(uci -q get "$svc_name.main.port" 2>/dev/null) + [ -z "$port" ] && port=$(uci -q get "$svc_name.@server[0].port" 2>/dev/null) + ;; + esac + + echo "$status|$port|$enabled" +} + +# Build catalog entries from HAProxy vhosts and local services +build_catalog() { + local wan_ip=$(get_wan_ip) + local mesh_ip=$(get_mesh_ip) + local first_service=1 + + # Start services array + echo '"services": [' + + # Track processed backends to avoid duplicates + local processed_backends="" + + # First, enumerate HAProxy vhosts (primary access method) + local vhosts=$(get_haproxy_vhosts) + for vhost_line in $vhosts; do + local domain=$(echo "$vhost_line" | cut -d'|' -f1) + local backend=$(echo "$vhost_line" | cut -d'|' -f2) + local scheme=$(echo "$vhost_line" | cut -d'|' -f3) + local ssl_redirect=$(echo "$vhost_line" | cut -d'|' -f4) + + local svc_name=$(normalize_backend_name "$backend") + + # Skip if already processed + echo "$processed_backends" | grep -qw "$svc_name" && continue + processed_backends="$processed_backends $svc_name" + + # Get service status + local svc_info=$(get_service_info "$svc_name") + local status=$(echo "$svc_info" | cut -d'|' -f1) + local port=$(echo "$svc_info" | cut -d'|' -f2) + local enabled=$(echo "$svc_info" | cut -d'|' -f3) + + [ $first_service -eq 0 ] && echo "," + first_service=0 + + # Build endpoints array + local endpoints='[' + local first_ep=1 + + # Primary: HAProxy vhost (published domain) + [ $first_ep -eq 0 ] && endpoints="$endpoints," + first_ep=0 + endpoints="$endpoints{\"type\":\"haproxy\",\"url\":\"${scheme}://${domain}\",\"ssl\":$([ \"$scheme\" = \"https\" ] && echo true || echo false),\"primary\":true}" + + # Collect all vhosts for this backend + for other_vhost in $vhosts; do + local other_domain=$(echo "$other_vhost" | cut -d'|' -f1) + local other_backend=$(echo "$other_vhost" | cut -d'|' -f2) + local other_scheme=$(echo "$other_vhost" | cut -d'|' -f3) + + [ "$other_backend" = "$backend" ] || continue + [ "$other_domain" = "$domain" ] && continue # Skip primary + + endpoints="$endpoints,{\"type\":\"haproxy\",\"url\":\"${other_scheme}://${other_domain}\",\"ssl\":$([ \"$other_scheme\" = \"https\" ] && echo true || echo false),\"primary\":false}" + done + + # Mesh endpoint (WireGuard) + if [ -n "$mesh_ip" ] && [ -n "$port" ]; then + endpoints="$endpoints,{\"type\":\"mesh\",\"url\":\"http://${mesh_ip}:${port}\",\"ssl\":false,\"primary\":false}" + fi + + # Local endpoint (LAN) + if [ -n "$port" ]; then + endpoints="$endpoints,{\"type\":\"local\",\"url\":\"http://${LOCAL_IP}:${port}\",\"ssl\":false,\"primary\":false}" + fi + + endpoints="$endpoints]" + + # Output service entry + cat << SVCEOF +{ + "name": "$svc_name", + "backend": "$backend", + "status": "$status", + "enabled": $enabled, + "port": "${port:-}", + "endpoints": $endpoints, + "health": { + "last_check": "$UPDATED", + "status": "$([ \"$status\" = \"running\" ] && echo healthy || echo unhealthy)", + "latency_ms": 0 + } +} +SVCEOF + done + + # Now add services without HAProxy vhosts (mesh/local only) + local services_json=$(/usr/sbin/secubox-p2p services 2>/dev/null) + if [ -n "$services_json" ]; then + local svc_count=$(echo "$services_json" | jsonfilter -e '@.services[*]' 2>/dev/null | wc -l) + local i=0 + + while [ $i -lt $svc_count ]; do + local svc_name=$(echo "$services_json" | jsonfilter -e "@.services[$i].name" 2>/dev/null) + local svc_status=$(echo "$services_json" | jsonfilter -e "@.services[$i].status" 2>/dev/null) + local svc_enabled=$(echo "$services_json" | jsonfilter -e "@.services[$i].enabled" 2>/dev/null) + local svc_port=$(echo "$services_json" | jsonfilter -e "@.services[$i].port" 2>/dev/null) + + # Skip if already processed via HAProxy + if ! echo "$processed_backends" | grep -qw "$svc_name"; then + [ $first_service -eq 0 ] && echo "," + first_service=0 + + # Build endpoints (mesh + local only, no HAProxy) + local endpoints='[' + local first_ep=1 + + # Mesh endpoint + if [ -n "$mesh_ip" ] && [ -n "$svc_port" ] && [ "$svc_port" != "0" ]; then + [ $first_ep -eq 0 ] && endpoints="$endpoints," + first_ep=0 + endpoints="$endpoints{\"type\":\"mesh\",\"url\":\"http://${mesh_ip}:${svc_port}\",\"ssl\":false,\"primary\":true}" + fi + + # Local endpoint + if [ -n "$svc_port" ] && [ "$svc_port" != "0" ]; then + [ $first_ep -eq 0 ] && endpoints="$endpoints," + first_ep=0 + endpoints="$endpoints{\"type\":\"local\",\"url\":\"http://${LOCAL_IP}:${svc_port}\",\"ssl\":false,\"primary\":$([ $first_ep -eq 1 ] && echo true || echo false)}" + fi + + endpoints="$endpoints]" + + cat << SVCEOF +{ + "name": "$svc_name", + "backend": "", + "status": "$svc_status", + "enabled": ${svc_enabled:-false}, + "port": "${svc_port:-}", + "endpoints": $endpoints, + "health": { + "last_check": "$UPDATED", + "status": "$([ \"$svc_status\" = \"running\" ] && echo healthy || echo unhealthy)", + "latency_ms": 0 + } +} +SVCEOF + fi + + i=$((i + 1)) + done + fi + + echo ']' +} + +# Get DNS hostname for this node +LOCAL_DNS_HOST=$(get_dns_hostname "$LOCAL_NODE_NAME") + +# Get linked peers for navigation +get_peer_links() { + local peers_file="/tmp/secubox-p2p-peers.json" + [ -f "$peers_file" ] || { echo '[]'; return; } + + local result='[' + local first=1 + local peer_count=$(jsonfilter -i "$peers_file" -e '@.peers[*]' 2>/dev/null | wc -l) + local i=0 + + while [ $i -lt $peer_count ]; do + local is_local=$(jsonfilter -i "$peers_file" -e "@.peers[$i].is_local" 2>/dev/null) + [ "$is_local" = "true" ] && { i=$((i + 1)); continue; } + + local peer_addr=$(jsonfilter -i "$peers_file" -e "@.peers[$i].address" 2>/dev/null) + local peer_name=$(jsonfilter -i "$peers_file" -e "@.peers[$i].name" 2>/dev/null) + local peer_status=$(jsonfilter -i "$peers_file" -e "@.peers[$i].status" 2>/dev/null) + local peer_wg=$(jsonfilter -i "$peers_file" -e "@.peers[$i].wg_addresses" 2>/dev/null | cut -d',' -f1) + + [ -n "$peer_addr" ] || { i=$((i + 1)); continue; } + + local peer_dns=$(get_dns_hostname "$peer_name") + + [ $first -eq 0 ] && result="$result," + first=0 + + result="$result{\"name\":\"$peer_name\",\"address\":\"$peer_addr\",\"status\":\"$peer_status\"" + result="$result,\"dns_hostname\":\"$peer_dns\"" + result="$result,\"dns_fqdn\":\"$peer_dns.$DNS_DOMAIN\"" + result="$result,\"wg_address\":\"$peer_wg\"" + result="$result,\"factory_url\":\"http://$peer_addr:7331/factory/\"" + result="$result,\"catalog_url\":\"http://$peer_addr:7331/api/factory/catalog\"}" + + i=$((i + 1)) + done + + result="$result]" + echo "$result" +} + +# Main output +cat << EOF +{ + "node_id": "$LOCAL_NODE_ID", + "node_name": "$LOCAL_NODE_NAME", + "updated": "$UPDATED", + "local_ip": "$LOCAL_IP", + "wan_ip": "$(get_wan_ip)", + "mesh_ip": "$(get_mesh_ip)", + "dns": { + "enabled": $DNS_ENABLED, + "domain": "$DNS_DOMAIN", + "hostname": "$LOCAL_DNS_HOST", + "fqdn": "$LOCAL_DNS_HOST.$DNS_DOMAIN" + }, + "linked_peers": $(get_peer_links), + $(build_catalog) +} +EOF diff --git a/package/secubox/secubox-p2p/root/www/api/factory/run b/package/secubox/secubox-p2p/root/www/api/factory/run index 3a9dcf7f..2033683d 100644 --- a/package/secubox/secubox-p2p/root/www/api/factory/run +++ b/package/secubox/secubox-p2p/root/www/api/factory/run @@ -137,6 +137,61 @@ case "$tool_id" in output="Merkle root: $merkle" ;; + catalog-sync) + result=$(catalog_sync 2>&1) + output="Catalog sync result: $result" + ;; + + catalog-list) + result=$(catalog_list 2>&1) + output="$result" + ;; + + catalog-generate) + result=$(catalog_generate_local 2>&1) + output="Catalog generated: $result" + ;; + + dns-status) + if [ -x /usr/sbin/secubox-p2p ]; then + result=$(/usr/sbin/secubox-p2p dns-status 2>&1) + output="$result" + else + output='{"error":"p2p_unavailable"}' + success=0 + fi + ;; + + dns-enable) + if [ -x /usr/sbin/secubox-p2p ]; then + result=$(/usr/sbin/secubox-p2p dns-enable "mesh.local" 2>&1) + output="DNS Federation enabled: $result" + else + output="P2P daemon not available" + success=0 + fi + ;; + + dns-disable) + if [ -x /usr/sbin/secubox-p2p ]; then + result=$(/usr/sbin/secubox-p2p dns-disable 2>&1) + output="DNS Federation disabled: $result" + else + output="P2P daemon not available" + success=0 + fi + ;; + + dns-update) + if [ -x /usr/sbin/secubox-p2p ]; then + result=$(/usr/sbin/secubox-p2p dns-update 2>&1) + output="DNS entries updated: $result" + else + output="P2P daemon not available" + success=0 + fi + ;; + *) output="Unknown tool: $tool_id" success=0 diff --git a/package/secubox/secubox-p2p/root/www/api/factory/tools b/package/secubox/secubox-p2p/root/www/api/factory/tools index 7a25aa88..43f4b6d2 100644 --- a/package/secubox/secubox-p2p/root/www/api/factory/tools +++ b/package/secubox/secubox-p2p/root/www/api/factory/tools @@ -112,15 +112,73 @@ cat << 'EOF' "category": "security", "icon": "hash", "dangerous": false + }, + { + "id": "catalog-sync", + "name": "Sync Catalog", + "description": "Sync service catalog with mesh peers and merge registries", + "category": "catalog", + "icon": "book", + "dangerous": false + }, + { + "id": "catalog-list", + "name": "List Catalogs", + "description": "Show local and peer catalog files", + "category": "catalog", + "icon": "list", + "dangerous": false + }, + { + "id": "catalog-generate", + "name": "Generate Catalog", + "description": "Regenerate local service catalog from HAProxy vhosts", + "category": "catalog", + "icon": "refresh", + "dangerous": false + }, + { + "id": "dns-status", + "name": "DNS Federation Status", + "description": "Show mesh DNS federation status and entries", + "category": "dns", + "icon": "globe", + "dangerous": false + }, + { + "id": "dns-enable", + "name": "Enable DNS Federation", + "description": "Enable automatic DNS entries for mesh peers (.mesh.local)", + "category": "dns", + "icon": "toggle-on", + "dangerous": false + }, + { + "id": "dns-disable", + "name": "Disable DNS Federation", + "description": "Disable mesh DNS federation", + "category": "dns", + "icon": "toggle-off", + "dangerous": false + }, + { + "id": "dns-update", + "name": "Update DNS Entries", + "description": "Refresh DNS entries from current peer list", + "category": "dns", + "icon": "refresh", + "dangerous": false } ], "categories": [ {"id": "security", "name": "Security", "order": 1}, {"id": "mesh", "name": "Mesh Network", "order": 2}, - {"id": "monitoring", "name": "Monitoring", "order": 3}, - {"id": "maintenance", "name": "Maintenance", "order": 4}, - {"id": "backup", "name": "Backup", "order": 5}, - {"id": "queue", "name": "Queue", "order": 6} + {"id": "dns", "name": "DNS Federation", "order": 3}, + {"id": "catalog", "name": "Catalog", "order": 4}, + {"id": "monitoring", "name": "Monitoring", "order": 5}, + {"id": "maintenance", "name": "Maintenance", "order": 6}, + {"id": "backup", "name": "Backup", "order": 7}, + {"id": "queue", "name": "Queue", "order": 8} ] } EOF diff --git a/package/secubox/secubox-p2p/root/www/factory/index.html b/package/secubox/secubox-p2p/root/www/factory/index.html index 37bfd0ae..a5993345 100644 --- a/package/secubox/secubox-p2p/root/www/factory/index.html +++ b/package/secubox/secubox-p2p/root/www/factory/index.html @@ -98,12 +98,12 @@ /* Fingerprint display */ .fingerprint { font-family: ui-monospace, monospace; font-size: 0.8rem; background: var(--bg); padding: 0.35rem 0.5rem; border-radius: 0.25rem; letter-spacing: 0.05em; } - /* Tab navigation */ - .tabs { display: flex; gap: 0.5rem; margin-bottom: 1rem; border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; } - .tab { padding: 0.5rem 1rem; background: transparent; border: none; color: var(--muted); cursor: pointer; font-weight: 500; position: relative; } - .tab.active { color: var(--accent); } - .tab.active::after { content: ''; position: absolute; bottom: -0.5rem; left: 0; right: 0; height: 2px; background: var(--accent); } - .tab:hover { color: var(--text); } + /* Emoji nav */ + .emoji-nav { display: flex; gap: 0.5rem; margin-bottom: 1rem; } + .emoji-btn { font-size: 1.5rem; padding: 0.5rem; background: var(--card); border: 2px solid transparent; border-radius: 0.5rem; cursor: pointer; transition: all 0.2s; filter: grayscale(0.5); opacity: 0.7; } + .emoji-btn:hover { filter: grayscale(0); opacity: 1; transform: scale(1.1); } + .emoji-btn.active { filter: grayscale(0); opacity: 1; border-color: var(--accent); background: rgba(99, 102, 241, 0.2); } + .emoji-btn[title]:hover::after { content: attr(title); position: absolute; bottom: -1.5rem; left: 50%; transform: translateX(-50%); font-size: 0.65rem; background: var(--card); padding: 0.2rem 0.4rem; border-radius: 0.2rem; white-space: nowrap; } .tab-content { display: none; } .tab-content.active { display: block; } @@ -137,6 +137,78 @@ .filter-input { flex: 1; min-width: 200px; padding: 0.5rem 0.75rem; background: var(--card); border: 1px solid var(--border); border-radius: 0.25rem; color: var(--text); font-size: 0.85rem; } .filter-input:focus { outline: none; border-color: var(--accent); } .filter-select { padding: 0.5rem 0.75rem; background: var(--card); border: 1px solid var(--border); border-radius: 0.25rem; color: var(--text); font-size: 0.85rem; } + + /* Health emoji status */ + .health-emoji { cursor: pointer; font-size: 1rem; transition: transform 0.2s; } + .health-emoji:hover { transform: scale(1.3); } + .health-emoji.clickable { cursor: pointer; } + + /* Service URL display */ + .service-url { font-size: 0.65rem; color: var(--accent); font-family: ui-monospace, monospace; word-break: break-all; } + .service-url a { color: var(--accent); text-decoration: none; } + .service-url a:hover { text-decoration: underline; } + + /* QR code modal */ + .qr-modal { text-align: center; } + .qr-modal canvas { margin: 1rem auto; display: block; background: white; padding: 1rem; border-radius: 0.5rem; } + .qr-url { font-family: ui-monospace, monospace; font-size: 0.8rem; color: var(--accent); margin-top: 0.5rem; word-break: break-all; } + + /* Stat emoji clickable */ + .stat-emoji { font-size: 1.5rem; cursor: pointer; transition: transform 0.2s; } + .stat-emoji:hover { transform: scale(1.2); } + + /* Catalog styles */ + .catalog-service { background: var(--card); border-radius: 0.5rem; overflow: hidden; margin-bottom: 0.75rem; } + .catalog-service-header { padding: 0.75rem 1rem; background: rgba(0,0,0,0.2); display: flex; justify-content: space-between; align-items: center; cursor: pointer; border-bottom: 1px solid var(--border); } + .catalog-service-header:hover { background: rgba(0,0,0,0.3); } + .catalog-service-name { font-size: 1rem; font-weight: 600; display: flex; align-items: center; gap: 0.5rem; } + .catalog-service-meta { display: flex; gap: 0.5rem; align-items: center; } + .catalog-endpoints { padding: 0; max-height: 0; overflow: hidden; transition: max-height 0.3s ease, padding 0.3s ease; } + .catalog-endpoints.open { padding: 0.75rem 1rem; max-height: 500px; } + .endpoint-item { display: flex; justify-content: space-between; align-items: center; padding: 0.5rem 0.75rem; margin-bottom: 0.5rem; background: rgba(0,0,0,0.15); border-radius: 0.25rem; border-left: 3px solid var(--border); } + .endpoint-item.primary { border-left-color: var(--accent); } + .endpoint-item.haproxy { border-left-color: var(--success); } + .endpoint-item.mesh { border-left-color: #818cf8; } + .endpoint-item.local { border-left-color: var(--muted); } + .endpoint-type { font-size: 0.65rem; text-transform: uppercase; padding: 0.15rem 0.4rem; border-radius: 0.15rem; background: var(--border); margin-right: 0.5rem; } + .endpoint-type.haproxy { background: var(--success); color: #000; } + .endpoint-type.mesh { background: #818cf8; } + .endpoint-type.local { background: var(--muted); } + .endpoint-url { flex: 1; font-family: ui-monospace, monospace; font-size: 0.8rem; color: var(--accent); word-break: break-all; } + .endpoint-url a { color: inherit; text-decoration: none; } + .endpoint-url a:hover { text-decoration: underline; } + .endpoint-actions { display: flex; gap: 0.35rem; } + .endpoint-badge { font-size: 0.6rem; padding: 0.1rem 0.3rem; border-radius: 0.15rem; background: var(--accent); } + .endpoint-badge.ssl { background: var(--success); color: #000; } + + /* Catalog node grouping */ + .catalog-node-group { margin-bottom: 1.5rem; } + .catalog-node-header { display: flex; justify-content: space-between; align-items: center; padding: 0.5rem 0; border-bottom: 2px solid var(--accent); margin-bottom: 0.75rem; } + .catalog-node-name { font-size: 1.1rem; font-weight: 700; display: flex; align-items: center; gap: 0.5rem; } + .catalog-node-stats { font-size: 0.75rem; color: var(--muted); } + + /* URL tabs in QR modal */ + .url-tabs { display: flex; gap: 0.25rem; margin-bottom: 0.75rem; flex-wrap: wrap; justify-content: center; } + .url-tab { padding: 0.35rem 0.6rem; border-radius: 0.25rem; font-size: 0.7rem; cursor: pointer; background: var(--border); border: none; color: var(--text); } + .url-tab.active { background: var(--accent); } + .url-tab.haproxy { border-bottom: 2px solid var(--success); } + .url-tab.mesh { border-bottom: 2px solid #818cf8; } + .url-tab.local { border-bottom: 2px solid var(--muted); } + + /* Linked peers / mesh navigation */ + .peer-links { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1rem; padding: 0.75rem; background: var(--card); border-radius: 0.5rem; border-left: 3px solid #818cf8; } + .peer-links-title { font-size: 0.75rem; color: var(--muted); width: 100%; margin-bottom: 0.25rem; } + .peer-link { display: flex; align-items: center; gap: 0.35rem; padding: 0.35rem 0.6rem; background: rgba(0,0,0,0.2); border-radius: 0.25rem; font-size: 0.75rem; cursor: pointer; transition: all 0.2s; text-decoration: none; color: var(--text); } + .peer-link:hover { background: var(--accent); transform: translateY(-1px); } + .peer-link.online { border-left: 2px solid var(--success); } + .peer-link.offline { border-left: 2px solid var(--danger); opacity: 0.6; } + .peer-link-name { font-weight: 500; } + .peer-link-dns { font-family: ui-monospace, monospace; font-size: 0.65rem; color: var(--accent); } + + /* DNS info badge */ + .dns-info { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.25rem 0.5rem; background: rgba(129, 140, 248, 0.2); border-radius: 0.25rem; font-size: 0.7rem; font-family: ui-monospace, monospace; color: #818cf8; } + .dns-enabled { color: var(--success); } + .dns-disabled { color: var(--muted); } @@ -145,19 +217,20 @@ SecuBox Factory +
+ + + +
- nodes ... ... - +
-
- - -
@@ -170,6 +243,12 @@
Loading services...
+ +
+
+
Loading catalog...
+
+
@@ -187,14 +266,27 @@ + +

Service Access

+ +
+
+ + +
+
+