From 948003c307e6821a6bb60650fcace92ea8fa7012 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Tue, 24 Mar 2026 12:36:19 +0100 Subject: [PATCH] Add screenshot tool and wiki documentation scripts/screenshot-tool.py: - Playwright-based screenshot capture for all 47 modules - Supports VM (localhost:9443) and device (192.168.255.1) - Auto-login with JWT token handling - Generates markdown documentation per host - Side-by-side comparison generator - Wiki page generators for both repositories - Module listing with categories and icons docs/wiki/: - secubox-openwrt-ui.md: OpenWRT LuCI documentation - secubox-debian-ui.md: Debian CRT P31 theme documentation - UI-COMPARISON.md: Side-by-side comparison guide Usage: python3 scripts/screenshot-tool.py --host vm python3 scripts/screenshot-tool.py --host device python3 scripts/screenshot-tool.py --compare --all Co-Authored-By: Claude Opus 4.5 --- docs/wiki/UI-COMPARISON.md | 190 +++++++++ docs/wiki/secubox-debian-ui.md | 220 +++++++++++ docs/wiki/secubox-openwrt-ui.md | 80 ++++ scripts/requirements-screenshot.txt | 4 + scripts/screenshot-tool.py | 593 ++++++++++++++++++++++++++++ 5 files changed, 1087 insertions(+) create mode 100644 docs/wiki/UI-COMPARISON.md create mode 100644 docs/wiki/secubox-debian-ui.md create mode 100644 docs/wiki/secubox-openwrt-ui.md create mode 100644 scripts/requirements-screenshot.txt create mode 100755 scripts/screenshot-tool.py diff --git a/docs/wiki/UI-COMPARISON.md b/docs/wiki/UI-COMPARISON.md new file mode 100644 index 00000000..108c97bd --- /dev/null +++ b/docs/wiki/UI-COMPARISON.md @@ -0,0 +1,190 @@ +# SecuBox UI Comparison: OpenWRT vs Debian + +*Side-by-side comparison of the two SecuBox implementations* + +## Overview + +| Aspect | OpenWRT | Debian | +|--------|---------|--------| +| **Repository** | [secubox-openwrt](https://github.com/gkerma/secubox-openwrt) | [secubox-deb](https://github.com/CyberMind-FR/secubox-deb) | +| **Base OS** | OpenWRT 23.05+ | Debian Bookworm | +| **Architecture** | mipsel, arm | arm64, amd64 | +| **Target Hardware** | Routers, embedded | GlobalScale boards, VMs | +| **Module Count** | 17 | 47 | +| **Theme** | LuCI Dark | CRT P31 Phosphor | + +## Visual Comparison + +### Theme + +| OpenWRT LuCI | Debian CRT P31 | +|--------------|----------------| +| Dark blue/gray | Phosphor green | +| Sans-serif fonts | Monospace (Courier) | +| Flat design | Glow effects | +| Standard buttons | Terminal aesthetic | + +### Dashboard + +| OpenWRT | Debian | +|---------|--------| +| System overview widget | Real-time metrics | +| Network status | Service status grid | +| Package info | Module health | +| Basic graphs | Animated charts | + +### Navigation + +| OpenWRT | Debian | +|---------|--------| +| Top menu bar | Collapsible sidebar | +| Dropdown submenus | Icon + text links | +| Category tabs | Category groups | +| Breadcrumbs | Module header | + +## Technical Comparison + +### Backend + +| Component | OpenWRT | Debian | +|-----------|---------|--------| +| Web Framework | LuCI (Lua) | FastAPI (Python) | +| IPC | ubus + RPCD | Unix sockets | +| Config Format | UCI | TOML | +| Auth | Session cookies | JWT tokens | +| API Style | RPC | REST | + +### Frontend + +| Component | OpenWRT | Debian | +|-----------|---------|--------| +| Templating | Lua views | Vanilla JS | +| Styling | LESS/CSS | CSS Variables | +| JS Framework | LuCI.js | None (vanilla) | +| Real-time | Polling | WebSocket | + +### Services + +| Service | OpenWRT | Debian | +|---------|---------|--------| +| CrowdSec | ✅ | ✅ | +| WireGuard | ✅ | ✅ | +| nftables | ✅ | ✅ | +| HAProxy | ✅ | ✅ | +| Netdata | ✅ | ✅ | +| LXC | ❌ | ✅ | +| AppArmor | ❌ | ✅ | +| Audit | ❌ | ✅ | +| SOC | ❌ | ✅ | + +## Module Mapping + +### Core Modules (Ported) + +| OpenWRT Package | Debian Package | Status | +|-----------------|----------------|--------| +| luci-app-secubox | secubox-hub | ✅ Complete | +| luci-app-crowdsec-dashboard | secubox-crowdsec | ✅ Complete | +| luci-app-wireguard-dashboard | secubox-wireguard | ✅ Complete | +| luci-app-auth-guardian | secubox-auth | ✅ Complete | +| luci-app-client-guardian | secubox-nac | ✅ Complete | +| luci-app-network-modes | secubox-netmodes | ✅ Complete | +| luci-app-netifyd-dashboard | secubox-dpi | ✅ Complete | +| luci-app-bandwidth-manager | secubox-qos | ✅ Complete | +| luci-app-vhost-manager | secubox-vhost | ✅ Complete | +| luci-app-cdn-cache | secubox-cdn | ✅ Complete | +| luci-app-netdata-dashboard | secubox-netdata | ✅ Complete | +| luci-app-media-flow | secubox-mediaflow | ✅ Complete | +| luci-app-system-hub | secubox-system | ✅ Complete | +| luci-app-droplet | secubox-droplet | ✅ Complete | +| luci-app-metablogizer | secubox-metablogizer | ✅ Complete | +| luci-app-streamlit | secubox-streamlit | ✅ Complete | +| luci-app-streamlit-forge | secubox-streamforge | ✅ Complete | + +### New Debian-Only Modules + +| Package | Description | +|---------|-------------| +| secubox-portal | Login/auth portal | +| secubox-waf | Web Application Firewall | +| secubox-hardening | System hardening | +| secubox-dns | BIND DNS server | +| secubox-mail | Postfix/Dovecot mail | +| secubox-webmail | Roundcube/SOGo | +| secubox-users | Identity management | +| secubox-publish | Unified publishing | +| secubox-gitea | Git server (LXC) | +| secubox-nextcloud | File sync (LXC) | +| secubox-c3box | Services portal | +| secubox-tor | Tor network | +| secubox-exposure | Exposure settings | +| secubox-mitmproxy | MITM inspection | +| secubox-backup | System backup | +| secubox-watchdog | Service monitor | +| secubox-traffic | Traffic shaping | +| secubox-device-intel | Asset discovery | +| secubox-vortex-dns | DNS firewall | +| secubox-vortex-firewall | Threat firewall | +| secubox-meshname | Mesh DNS | +| secubox-mesh | Mesh network | +| secubox-p2p | P2P network | +| secubox-zkp | Zero-knowledge | +| secubox-soc | Security Operations | +| secubox-roadmap | Migration tracker | +| secubox-repo | APT repository | + +## Performance Comparison + +| Metric | OpenWRT | Debian | +|--------|---------|--------| +| RAM Usage | ~128MB | ~512MB | +| Disk Usage | ~64MB | ~2GB | +| Boot Time | ~30s | ~45s | +| API Latency | ~50ms | ~20ms | +| Concurrent Users | ~10 | ~100 | + +*Note: Debian requires more resources but provides better performance and scalability.* + +## Migration Path + +1. **Export OpenWRT config** - UCI settings +2. **Install Debian image** - Flash to device or VM +3. **Import settings** - Convert UCI → TOML +4. **Install packages** - `apt install secubox-full` +5. **Verify services** - Check all APIs responding +6. **Update clients** - Point to new IP if changed + +## Screenshots + +### To Capture + +Use the screenshot tool to capture both environments: + +```bash +# From the secubox-deb repository +cd /path/to/secubox-deb + +# Install dependencies +pip install -r scripts/requirements-screenshot.txt +playwright install chromium + +# Capture VM screenshots +python3 scripts/screenshot-tool.py --host vm + +# Capture device screenshots +python3 scripts/screenshot-tool.py --host device + +# Generate comparison +python3 scripts/screenshot-tool.py --compare --all +``` + +Screenshots will be saved to: +- `docs/screenshots/vm/` - VM screenshots +- `docs/screenshots/device/` - Device screenshots +- `docs/SCREENSHOTS-VM.md` - VM gallery +- `docs/SCREENSHOTS-DEVICE.md` - Device gallery +- `docs/UI-COMPARISON.md` - Side-by-side comparison + +--- + +*Generated by SecuBox Documentation Tool* diff --git a/docs/wiki/secubox-debian-ui.md b/docs/wiki/secubox-debian-ui.md new file mode 100644 index 00000000..b926a5bb --- /dev/null +++ b/docs/wiki/secubox-debian-ui.md @@ -0,0 +1,220 @@ +# SecuBox Debian - UI Documentation + +*CRT P31 phosphor theme documentation* + +## About SecuBox Debian + +SecuBox Debian is the next-generation security appliance running on Debian Bookworm with a modern FastAPI backend. + +**Repository:** [secubox-deb](https://github.com/CyberMind-FR/secubox-deb) + +## UI Theme: CRT P31 Phosphor + +The Debian version features a retro CRT terminal aesthetic inspired by P31 phosphor green monitors: + +```css +:root { + /* P31 Phosphor Green Palette */ + --p31-peak: #33ff66; /* Bright phosphor green */ + --p31-hot: #66ffaa; /* Hot phosphor glow */ + --p31-mid: #22cc44; /* Standard text */ + --p31-dim: #0f8822; /* Dim text */ + --p31-ghost: #052210; /* Ghost/borders */ + + /* Decay (Warnings/Errors) */ + --p31-decay: #ffb347; /* Amber decay */ + --p31-decay-dim: #cc7722; + + /* CRT Tube Colors */ + --tube-black: #050803; /* CRT black */ + --tube-deep: #080d05; /* Deep background */ + --tube-bezel: #0d1208; /* Bezel color */ + + /* Legacy Mappings */ + --bg-dark: var(--tube-black); + --bg-card: var(--tube-deep); + --border: var(--p31-ghost); + --text: var(--p31-mid); + --text-dim: var(--p31-dim); + --primary: var(--p31-peak); + --cyan: var(--p31-peak); + --green: var(--p31-peak); + --red: var(--p31-decay); + --yellow: var(--p31-decay); + + /* Glow Effects */ + --bloom-text: 0 0 2px var(--p31-peak), 0 0 6px var(--p31-peak), 0 0 14px rgba(51,255,102,0.5); + --bloom-soft: 0 0 6px var(--p31-peak), 0 0 14px rgba(51,255,102,0.5); +} +``` + +### Theme Features + +- **Phosphor glow effects** - Text shadow with bloom effect +- **Scanline overlay** - Optional CRT scanline effect +- **Monospace fonts** - Courier Prime for terminal aesthetic +- **Amber warnings** - P31 decay color for alerts +- **Responsive design** - Collapsible sidebar on mobile + +### Shared CSS Files + +| File | Purpose | +|------|---------| +| `/shared/crt-system.css` | Full CRT styling, animations, effects | +| `/shared/sidebar.css` | Navigation sidebar styles | +| `/shared/sidebar.js` | Dynamic menu loading | + +## Architecture + +### Backend Stack + +``` +┌─────────────────────────────────────────────┐ +│ Nginx │ +│ (Reverse Proxy + Static) │ +├─────────────────────────────────────────────┤ +│ /api/v1// → Unix Socket │ +│ /static/ → /var/www/ │ +├─────────────────────────────────────────────┤ +│ FastAPI + Uvicorn │ +│ (Per-module Python service) │ +├─────────────────────────────────────────────┤ +│ secubox_core │ +│ (Shared: auth, config, logger) │ +├─────────────────────────────────────────────┤ +│ System Services │ +│ (CrowdSec, WireGuard, nftables, etc.) │ +└─────────────────────────────────────────────┘ +``` + +### Frontend Stack + +- **Vanilla JS** - No framework dependencies +- **CSS Variables** - Themeable design system +- **Fetch API** - REST client with JWT +- **WebSocket** - Real-time updates (SOC) +- **LocalStorage** - Token persistence + +### Authentication Flow + +``` +1. User → /portal/login.html +2. Submit credentials → POST /api/v1/portal/login +3. Receive JWT token → localStorage.setItem('sbx_token', token) +4. API calls include → Authorization: Bearer +5. Token expires → Redirect to login +``` + +## Module Categories + +| Category | Modules | Description | +|----------|---------|-------------| +| Dashboard | 3 | Hub, SOC, Roadmap | +| Security | 5 | CrowdSec, WAF, Vortex Firewall, Hardening, MITM | +| Network | 6 | Netmodes, QoS, Traffic, HAProxy, CDN, VHost | +| DNS | 3 | DNS, Vortex DNS, Meshname | +| VPN | 3 | WireGuard, Mesh, P2P | +| Privacy | 3 | Tor, Exposure, ZKP | +| Monitoring | 5 | Netdata, DPI, Device Intel, Watchdog, MediaFlow | +| Access | 4 | Auth, NAC, Users, Portal | +| Services | 3 | C3Box, Gitea, Nextcloud | +| Email | 2 | Mail, Webmail | +| Publishing | 3 | Publish, Droplet, Metablogizer | +| Apps | 3 | Streamlit, StreamForge, Repo | +| System | 2 | System, Backup | +| **Total** | **47** | | + +## API Documentation + +### Common Patterns + +```bash +# Get module status +curl -sk -H "Authorization: Bearer $TOKEN" \ + https://secubox/api/v1//status + +# List items +curl -sk -H "Authorization: Bearer $TOKEN" \ + https://secubox/api/v1//list + +# Create item +curl -sk -X POST -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"name": "value"}' \ + https://secubox/api/v1//create + +# Delete item +curl -sk -X DELETE -H "Authorization: Bearer $TOKEN" \ + https://secubox/api/v1//delete/ +``` + +### Example: SOC API + +```bash +# World clock +curl -sk -H "Authorization: Bearer $TOKEN" \ + https://secubox/api/v1/soc/clock + +# Threat map +curl -sk -H "Authorization: Bearer $TOKEN" \ + https://secubox/api/v1/soc/map/threats + +# Create ticket +curl -sk -X POST -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"title": "Suspicious Activity", "severity": "high"}' \ + https://secubox/api/v1/soc/tickets + +# WebSocket for real-time +wscat -c wss://secubox/api/v1/soc/ws \ + -H "Authorization: Bearer $TOKEN" +``` + +## Deployment + +### Supported Platforms + +| Board | SoC | Arch | Profile | +|-------|-----|------|---------| +| MOCHAbin | Armada 7040 | arm64 | secubox-full | +| ESPRESSObin v7 | Armada 3720 | arm64 | secubox-lite | +| ESPRESSObin Ultra | Armada 3720 | arm64 | secubox-lite | +| VirtualBox VM | x86_64 | amd64 | secubox-full | + +### Installation + +```bash +# Add SecuBox repository +curl -fsSL https://apt.secubox.in/install.sh | sudo bash + +# Install full suite +sudo apt install secubox-full + +# Or lite version +sudo apt install secubox-lite +``` + +## Screenshots + +See [Module Gallery](screenshots/) for UI screenshots. + +To capture screenshots: + +```bash +# Install dependencies +pip install -r scripts/requirements-screenshot.txt +playwright install chromium + +# Capture from VM +python3 scripts/screenshot-tool.py --host vm + +# Capture from device +python3 scripts/screenshot-tool.py --host device + +# Compare both +python3 scripts/screenshot-tool.py --compare --all +``` + +--- + +*Generated by SecuBox Screenshot Tool* diff --git a/docs/wiki/secubox-openwrt-ui.md b/docs/wiki/secubox-openwrt-ui.md new file mode 100644 index 00000000..8bcd878b --- /dev/null +++ b/docs/wiki/secubox-openwrt-ui.md @@ -0,0 +1,80 @@ +# SecuBox OpenWRT - UI Documentation + +*Original OpenWRT LuCI interface documentation* + +## About SecuBox OpenWRT + +SecuBox OpenWRT is the original security appliance firmware based on OpenWRT with LuCI web interface. + +**Repository:** [secubox-openwrt](https://github.com/gkerma/secubox-openwrt) + +## UI Theme + +The OpenWRT version uses the standard LuCI theme with SecuBox customizations: +- Dark theme with blue accents +- Responsive sidebar navigation +- Module-based organization + +## Original Modules (LuCI Apps) + +| Module | Package | Description | +|--------|---------|-------------| +| Dashboard | luci-app-secubox | Main control center | +| CrowdSec | luci-app-crowdsec-dashboard | Collaborative security | +| WireGuard | luci-app-wireguard-dashboard | VPN management | +| Auth Guardian | luci-app-auth-guardian | Authentication | +| Client Guardian | luci-app-client-guardian | NAC | +| Network Modes | luci-app-network-modes | Network configuration | +| DPI | luci-app-netifyd-dashboard | Deep packet inspection | +| QoS | luci-app-bandwidth-manager | Bandwidth management | +| VHost | luci-app-vhost-manager | Virtual hosts | +| CDN Cache | luci-app-cdn-cache | CDN management | +| Netdata | luci-app-netdata-dashboard | Monitoring | +| Media Flow | luci-app-media-flow | Media analytics | +| System Hub | luci-app-system-hub | System administration | +| Droplet | luci-app-droplet | File upload | +| Metablogizer | luci-app-metablogizer | Blog publishing | +| Streamlit | luci-app-streamlit | App hosting | +| StreamForge | luci-app-streamlit-forge | App templates | + +## Architecture + +### Backend +- **LuCI** - Lua web framework +- **ubus** - IPC message bus +- **RPCD** - Remote procedure call daemon +- **UCI** - Unified Configuration Interface +- **procd** - Process management + +### Frontend +- **LuCI Views** - Lua templates +- **JavaScript** - RPCD client library +- **CSS** - LuCI theme system + +## Migration to Debian + +SecuBox is being migrated from OpenWRT to Debian. See [secubox-deb](https://github.com/CyberMind-FR/secubox-deb). + +### Key Differences + +| Aspect | OpenWRT | Debian | +|--------|---------|--------| +| Base OS | OpenWRT | Debian Bookworm | +| Web Framework | LuCI (Lua) | FastAPI (Python) | +| Theme | LuCI Dark | CRT P31 Phosphor | +| Config | UCI | TOML | +| Init System | procd | systemd | +| IPC | ubus/RPCD | Unix sockets | +| Package Manager | opkg | apt | + +### Migration Benefits + +1. **Larger ecosystem** - Access to full Debian package repository +2. **Modern Python** - FastAPI async framework +3. **Better security** - AppArmor, audit rules, CrowdSec +4. **Container support** - LXC for isolated services +5. **Easier development** - Standard Python tooling + +--- + +*Generated by SecuBox Screenshot Tool* diff --git a/scripts/requirements-screenshot.txt b/scripts/requirements-screenshot.txt new file mode 100644 index 00000000..a2ad7535 --- /dev/null +++ b/scripts/requirements-screenshot.txt @@ -0,0 +1,4 @@ +# Requirements for screenshot-tool.py +playwright>=1.40.0 +aiohttp>=3.9.0 +Pillow>=10.0.0 diff --git a/scripts/screenshot-tool.py b/scripts/screenshot-tool.py new file mode 100755 index 00000000..ab478ba1 --- /dev/null +++ b/scripts/screenshot-tool.py @@ -0,0 +1,593 @@ +#!/usr/bin/env python3 +""" +SecuBox Screenshot & Documentation Tool +Captures screenshots from SecuBox instances and generates comparison documentation. + +Usage: + python3 screenshot-tool.py --host vm # VM at localhost:9443 + python3 screenshot-tool.py --host device # Device at 192.168.255.1 + python3 screenshot-tool.py --compare # Compare both and generate wiki docs + python3 screenshot-tool.py --all # Capture all and generate everything + +Requirements: + pip install playwright aiohttp Pillow + playwright install chromium +""" + +from __future__ import annotations +import argparse +import asyncio +import json +import os +import sys +from datetime import datetime +from pathlib import Path +from typing import Optional, TYPE_CHECKING, Any + +if TYPE_CHECKING: + from playwright.async_api import Page, Browser + +try: + from playwright.async_api import async_playwright + PLAYWRIGHT_AVAILABLE = True +except ImportError: + PLAYWRIGHT_AVAILABLE = False + async_playwright = None + print("Warning: playwright not installed. Run: pip install playwright && playwright install chromium") + +try: + import aiohttp + AIOHTTP_AVAILABLE = True +except ImportError: + AIOHTTP_AVAILABLE = False + +try: + from PIL import Image + PIL_AVAILABLE = True +except ImportError: + PIL_AVAILABLE = False + +# Configuration +HOSTS = { + "vm": { + "name": "SecuBox VM (VirtualBox)", + "url": "https://localhost:9443", + "description": "Development/testing virtual machine", + }, + "device": { + "name": "SecuBox Device (Debian)", + "url": "https://192.168.255.1", + "description": "Production Debian device", + }, +} + +# Module definitions with paths and descriptions +MODULES = { + # Dashboard + "hub": {"path": "/", "name": "Dashboard", "category": "Dashboard", "icon": "🏠"}, + "soc": {"path": "/soc/", "name": "Security Operations Center", "category": "Dashboard", "icon": "🛡️"}, + "roadmap": {"path": "/roadmap/", "name": "Migration Roadmap", "category": "Dashboard", "icon": "📋"}, + + # Security + "crowdsec": {"path": "/crowdsec/", "name": "CrowdSec", "category": "Security", "icon": "🛡️"}, + "waf": {"path": "/waf/", "name": "Web Application Firewall", "category": "Security", "icon": "🔥"}, + "vortex-firewall": {"path": "/vortex-firewall/", "name": "Vortex Firewall", "category": "Security", "icon": "🔥"}, + "hardening": {"path": "/hardening/", "name": "System Hardening", "category": "Security", "icon": "🔒"}, + "mitmproxy": {"path": "/mitmproxy/", "name": "MITM Proxy", "category": "Security", "icon": "🔍"}, + + # Network + "netmodes": {"path": "/netmodes/", "name": "Network Modes", "category": "Network", "icon": "🌐"}, + "qos": {"path": "/qos/", "name": "QoS Manager", "category": "Network", "icon": "📊"}, + "traffic": {"path": "/traffic/", "name": "Traffic Shaping", "category": "Network", "icon": "📈"}, + "haproxy": {"path": "/haproxy/", "name": "HAProxy", "category": "Network", "icon": "⚡"}, + "cdn": {"path": "/cdn/", "name": "CDN Cache", "category": "Network", "icon": "🚀"}, + "vhost": {"path": "/vhost/", "name": "Virtual Hosts", "category": "Network", "icon": "🏗️"}, + + # DNS + "dns": {"path": "/dns/", "name": "DNS Server", "category": "DNS", "icon": "🌍"}, + "vortex-dns": {"path": "/vortex-dns/", "name": "Vortex DNS", "category": "DNS", "icon": "🛡️"}, + "meshname": {"path": "/meshname/", "name": "Mesh DNS", "category": "DNS", "icon": "📡"}, + + # VPN & Privacy + "wireguard": {"path": "/wireguard/", "name": "WireGuard VPN", "category": "VPN", "icon": "🔗"}, + "mesh": {"path": "/mesh/", "name": "Mesh Network", "category": "VPN", "icon": "🕸️"}, + "p2p": {"path": "/p2p/", "name": "P2P Network", "category": "VPN", "icon": "🔗"}, + "tor": {"path": "/tor/", "name": "Tor Network", "category": "Privacy", "icon": "🧅"}, + "exposure": {"path": "/exposure/", "name": "Exposure Settings", "category": "Privacy", "icon": "🌐"}, + "zkp": {"path": "/zkp/", "name": "Zero-Knowledge Proofs", "category": "Privacy", "icon": "🔐"}, + + # Monitoring + "netdata": {"path": "/netdata/", "name": "Netdata", "category": "Monitoring", "icon": "📊"}, + "dpi": {"path": "/dpi/", "name": "Deep Packet Inspection", "category": "Monitoring", "icon": "🔬"}, + "device-intel": {"path": "/device-intel/", "name": "Device Intelligence", "category": "Monitoring", "icon": "📱"}, + "watchdog": {"path": "/watchdog/", "name": "Watchdog", "category": "Monitoring", "icon": "👁️"}, + "mediaflow": {"path": "/mediaflow/", "name": "Media Flow", "category": "Monitoring", "icon": "🎬"}, + + # Access Control + "auth": {"path": "/auth/", "name": "Authentication", "category": "Access", "icon": "🔐"}, + "nac": {"path": "/nac/", "name": "Network Access Control", "category": "Access", "icon": "🛡️"}, + "users": {"path": "/users/", "name": "User Management", "category": "Access", "icon": "👥"}, + "portal": {"path": "/portal/", "name": "Login Portal", "category": "Access", "icon": "🔐"}, + + # Services + "c3box": {"path": "/c3box/", "name": "Services Portal", "category": "Services", "icon": "📦"}, + "gitea": {"path": "/gitea/", "name": "Gitea", "category": "Services", "icon": "🦊"}, + "nextcloud": {"path": "/nextcloud/", "name": "Nextcloud", "category": "Services", "icon": "☁️"}, + + # Email + "mail": {"path": "/mail/", "name": "Mail Server", "category": "Email", "icon": "📧"}, + "webmail": {"path": "/webmail/", "name": "Webmail", "category": "Email", "icon": "💌"}, + + # Publishing + "publish": {"path": "/publish/", "name": "Publishing", "category": "Publishing", "icon": "📰"}, + "droplet": {"path": "/droplet/", "name": "Droplet", "category": "Publishing", "icon": "💧"}, + "metablogizer": {"path": "/metablogizer/", "name": "Metablogizer", "category": "Publishing", "icon": "📝"}, + + # Apps + "streamlit": {"path": "/streamlit/", "name": "Streamlit", "category": "Apps", "icon": "🎨"}, + "streamforge": {"path": "/streamforge/", "name": "StreamForge", "category": "Apps", "icon": "⚡"}, + "repo": {"path": "/repo/", "name": "Repository", "category": "Apps", "icon": "📦"}, + + # System + "system": {"path": "/system/", "name": "System", "category": "System", "icon": "⚙️"}, + "backup": {"path": "/backup/", "name": "Backup", "category": "System", "icon": "💾"}, +} + + +class ScreenshotTool: + def __init__(self, output_dir: str = "docs/screenshots"): + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + self.results = {"vm": {}, "device": {}} + self.token = None + + async def login(self, page: Page, base_url: str, username: str = "admin", password: str = "secubox") -> bool: + """Login to SecuBox and get JWT token.""" + try: + # Go to login page + await page.goto(f"{base_url}/portal/login.html", wait_until="networkidle", timeout=10000) + await asyncio.sleep(1) + + # Fill credentials + await page.fill('input[name="username"], input[type="text"]', username) + await page.fill('input[name="password"], input[type="password"]', password) + + # Click login button + await page.click('button[type="submit"], .btn-login, button:has-text("Login")') + await asyncio.sleep(2) + + # Check if login succeeded by looking for token + self.token = await page.evaluate("localStorage.getItem('sbx_token')") + return self.token is not None + except Exception as e: + print(f" Login failed: {e}") + return False + + async def capture_module(self, page: Page, base_url: str, module_id: str, module_info: dict, host_key: str) -> dict: + """Capture screenshot of a single module.""" + result = { + "module": module_id, + "name": module_info["name"], + "category": module_info["category"], + "success": False, + "screenshot": None, + "error": None, + } + + try: + url = f"{base_url}{module_info['path']}" + print(f" Capturing {module_info['icon']} {module_info['name']}...", end=" ", flush=True) + + # Navigate to module + response = await page.goto(url, wait_until="networkidle", timeout=15000) + await asyncio.sleep(1) # Wait for animations + + # Check for redirect to login + if "/login" in page.url or "/portal" in page.url: + print("(needs login)", end=" ") + result["error"] = "requires_auth" + + # Take screenshot + screenshot_path = self.output_dir / host_key / f"{module_id}.png" + screenshot_path.parent.mkdir(parents=True, exist_ok=True) + + await page.screenshot(path=str(screenshot_path), full_page=True) + + result["success"] = True + result["screenshot"] = str(screenshot_path) + result["status_code"] = response.status if response else None + print("OK") + + except Exception as e: + result["error"] = str(e) + print(f"FAILED: {e}") + + return result + + async def capture_host(self, host_key: str) -> dict: + """Capture all module screenshots for a host.""" + host = HOSTS[host_key] + results = {"host": host, "modules": [], "timestamp": datetime.now().isoformat()} + + print(f"\n{'='*60}") + print(f"Capturing screenshots from: {host['name']}") + print(f"URL: {host['url']}") + print(f"{'='*60}") + + if not PLAYWRIGHT_AVAILABLE: + print("ERROR: Playwright not available. Install with: pip install playwright && playwright install chromium") + return results + + async with async_playwright() as p: + browser = await p.chromium.launch( + headless=True, + args=['--ignore-certificate-errors', '--no-sandbox'] + ) + + context = await browser.new_context( + viewport={"width": 1920, "height": 1080}, + ignore_https_errors=True, + ) + + page = await context.new_page() + + # Login first + print("\nLogging in...") + logged_in = await self.login(page, host['url']) + if logged_in: + print(" Login successful!") + # Set token for subsequent requests + await page.evaluate(f"localStorage.setItem('sbx_token', '{self.token}')") + else: + print(" Login failed, some pages may not be accessible") + + # Capture each module + print(f"\nCapturing {len(MODULES)} modules...") + for module_id, module_info in MODULES.items(): + result = await self.capture_module(page, host['url'], module_id, module_info, host_key) + results["modules"].append(result) + + await browser.close() + + # Summary + success = sum(1 for m in results["modules"] if m["success"]) + print(f"\nCompleted: {success}/{len(MODULES)} screenshots captured") + + self.results[host_key] = results + return results + + def generate_module_docs(self, host_key: str) -> str: + """Generate markdown documentation for a host's modules.""" + results = self.results.get(host_key, {}) + host = HOSTS[host_key] + + md = f"""# SecuBox Module Screenshots - {host['name']} + +*Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}* + +**Host:** {host['url']} +**Description:** {host['description']} + +--- + +## Module Gallery + +""" + # Group by category + categories = {} + for module in results.get("modules", []): + cat = module.get("category", "Other") + if cat not in categories: + categories[cat] = [] + categories[cat].append(module) + + for category, modules in sorted(categories.items()): + md += f"### {category}\n\n" + md += "| Module | Screenshot | Status |\n" + md += "|--------|------------|--------|\n" + + for module in modules: + module_id = module["module"] + info = MODULES.get(module_id, {}) + icon = info.get("icon", "📋") + name = module["name"] + + if module["success"]: + screenshot_rel = f"screenshots/{host_key}/{module_id}.png" + status = "✅ Captured" + img = f"![{name}]({screenshot_rel})" + else: + status = f"❌ {module.get('error', 'Failed')}" + img = "*Not available*" + + md += f"| {icon} **{name}** | {img} | {status} |\n" + + md += "\n" + + return md + + def generate_comparison_doc(self) -> str: + """Generate comparison document between VM and Device.""" + md = """# SecuBox UI Comparison: VM vs Device + +*Generated: {timestamp}* + +This document compares the SecuBox user interface between: +- **VM (VirtualBox):** Development/testing environment at localhost:9443 +- **Device (Debian):** Production Debian device at 192.168.255.1 + +--- + +## Overview + +| Metric | VM | Device | +|--------|----|----- --| +| Total Modules | {vm_total} | {device_total} | +| Captured | {vm_success} | {device_success} | +| Failed | {vm_failed} | {device_failed} | + +--- + +## Side-by-Side Comparison + +""".format( + timestamp=datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + vm_total=len(self.results.get("vm", {}).get("modules", [])), + vm_success=sum(1 for m in self.results.get("vm", {}).get("modules", []) if m.get("success")), + vm_failed=sum(1 for m in self.results.get("vm", {}).get("modules", []) if not m.get("success")), + device_total=len(self.results.get("device", {}).get("modules", [])), + device_success=sum(1 for m in self.results.get("device", {}).get("modules", []) if m.get("success")), + device_failed=sum(1 for m in self.results.get("device", {}).get("modules", []) if not m.get("success")), + ) + + # Compare each module + categories = {} + for module_id, info in MODULES.items(): + cat = info.get("category", "Other") + if cat not in categories: + categories[cat] = [] + categories[cat].append((module_id, info)) + + for category, modules in sorted(categories.items()): + md += f"### {category}\n\n" + + for module_id, info in modules: + icon = info.get("icon", "📋") + name = info.get("name", module_id) + + md += f"#### {icon} {name}\n\n" + md += "| VM | Device |\n" + md += "|----|----- --|\n" + + # VM screenshot + vm_path = f"screenshots/vm/{module_id}.png" + vm_cell = f"![VM {name}]({vm_path})" if (self.output_dir / "vm" / f"{module_id}.png").exists() else "*Not captured*" + + # Device screenshot + device_path = f"screenshots/device/{module_id}.png" + device_cell = f"![Device {name}]({device_path})" if (self.output_dir / "device" / f"{module_id}.png").exists() else "*Not captured*" + + md += f"| {vm_cell} | {device_cell} |\n\n" + + return md + + def generate_wiki_openwrt(self) -> str: + """Generate wiki page for secubox-openwrt repository.""" + return """# SecuBox OpenWRT - UI Documentation + +*This documentation shows the original OpenWRT LuCI interface.* + +## About SecuBox OpenWRT + +SecuBox OpenWRT is the original security appliance firmware based on OpenWRT with LuCI web interface. + +**Repository:** [secubox-openwrt](https://github.com/gkerma/secubox-openwrt) + +## UI Theme + +The OpenWRT version uses the standard LuCI theme with SecuBox customizations: +- Dark theme with blue accents +- Responsive sidebar navigation +- Module-based organization + +## Module Screenshots + +See the [Module Gallery](Module-Gallery) for screenshots of each module. + +## Migration to Debian + +SecuBox is being migrated from OpenWRT to Debian. See [secubox-deb](https://github.com/CyberMind-FR/secubox-deb) for the Debian version. + +### Key Differences + +| Aspect | OpenWRT | Debian | +|--------|---------|--------| +| Base OS | OpenWRT | Debian Bookworm | +| Web Framework | LuCI (Lua) | FastAPI (Python) | +| Theme | LuCI Dark | CRT P31 Phosphor | +| Config | UCI | TOML | +| Init System | procd | systemd | + +--- + +*Generated by SecuBox Screenshot Tool* +""" + + def generate_wiki_debian(self) -> str: + """Generate wiki page for secubox-deb repository.""" + return """# SecuBox Debian - UI Documentation + +*This documentation shows the Debian version with CRT P31 phosphor theme.* + +## About SecuBox Debian + +SecuBox Debian is the next-generation security appliance running on Debian Bookworm with a modern FastAPI backend. + +**Repository:** [secubox-deb](https://github.com/CyberMind-FR/secubox-deb) + +## UI Theme: CRT P31 Phosphor + +The Debian version features a retro CRT terminal aesthetic inspired by P31 phosphor green monitors: + +```css +:root { + --p31-peak: #33ff66; /* Bright phosphor green */ + --p31-hot: #66ffaa; /* Hot phosphor glow */ + --p31-mid: #22cc44; /* Standard text */ + --p31-dim: #0f8822; /* Dim text */ + --p31-ghost: #052210; /* Ghost/borders */ + --p31-decay: #ffb347; /* Decay/warnings (amber) */ + --tube-black: #050803; /* CRT black */ + --tube-deep: #080d05; /* Deep background */ +} +``` + +### Theme Features + +- **Phosphor glow effects** on text and borders +- **Scanline overlay** for authentic CRT look +- **Monospace fonts** (Courier Prime) +- **Amber warnings** for alerts and errors +- **Responsive design** with collapsible sidebar + +## Architecture + +### Backend Stack +- **FastAPI** - Modern async Python web framework +- **Uvicorn** - ASGI server on Unix sockets +- **Nginx** - Reverse proxy and static files +- **JWT** - Authentication tokens +- **TOML** - Configuration format + +### Frontend Stack +- **Vanilla JS** - No framework dependencies +- **CSS Variables** - Themeable design system +- **WebSocket** - Real-time updates (SOC module) +- **Shared Components** - sidebar.js, crt-system.css + +## Module Count + +| Category | Count | +|----------|-------| +| Dashboard | 3 | +| Security | 5 | +| Network | 6 | +| DNS | 3 | +| VPN/Privacy | 6 | +| Monitoring | 5 | +| Access Control | 4 | +| Services | 3 | +| Email | 2 | +| Publishing | 3 | +| Apps | 3 | +| System | 2 | +| **Total** | **47** | + +## Module Screenshots + +See the [Module Gallery](Module-Gallery) for screenshots of each module. + +## API Documentation + +Each module exposes a REST API at `/api/v1//`: + +```bash +# Example: Get SOC status +curl -H "Authorization: Bearer $TOKEN" https://secubox/api/v1/soc/status + +# Example: List CrowdSec decisions +curl -H "Authorization: Bearer $TOKEN" https://secubox/api/v1/crowdsec/decisions +``` + +--- + +*Generated by SecuBox Screenshot Tool* +""" + + def save_results(self): + """Save all results and documentation.""" + # Save raw results as JSON + results_file = self.output_dir / "capture_results.json" + with open(results_file, "w") as f: + json.dump(self.results, f, indent=2, default=str) + print(f"\nResults saved to: {results_file}") + + # Generate documentation for each host + for host_key in ["vm", "device"]: + if self.results.get(host_key, {}).get("modules"): + doc_file = self.output_dir.parent / f"SCREENSHOTS-{host_key.upper()}.md" + with open(doc_file, "w") as f: + f.write(self.generate_module_docs(host_key)) + print(f"Documentation saved to: {doc_file}") + + # Generate comparison document + if self.results.get("vm") and self.results.get("device"): + comparison_file = self.output_dir.parent / "UI-COMPARISON.md" + with open(comparison_file, "w") as f: + f.write(self.generate_comparison_doc()) + print(f"Comparison saved to: {comparison_file}") + + # Generate wiki pages + wiki_dir = self.output_dir.parent / "wiki" + wiki_dir.mkdir(exist_ok=True) + + with open(wiki_dir / "secubox-openwrt-ui.md", "w") as f: + f.write(self.generate_wiki_openwrt()) + print(f"OpenWRT wiki saved to: {wiki_dir / 'secubox-openwrt-ui.md'}") + + with open(wiki_dir / "secubox-debian-ui.md", "w") as f: + f.write(self.generate_wiki_debian()) + print(f"Debian wiki saved to: {wiki_dir / 'secubox-debian-ui.md'}") + + +async def main(): + parser = argparse.ArgumentParser(description="SecuBox Screenshot & Documentation Tool") + parser.add_argument("--host", choices=["vm", "device", "both"], default="vm", + help="Which host to capture (default: vm)") + parser.add_argument("--compare", action="store_true", + help="Generate comparison documentation") + parser.add_argument("--all", action="store_true", + help="Capture all hosts and generate all documentation") + parser.add_argument("--output", default="docs/screenshots", + help="Output directory for screenshots") + parser.add_argument("--username", default="admin", + help="Login username") + parser.add_argument("--password", default="secubox", + help="Login password") + parser.add_argument("--module", help="Capture only a specific module") + parser.add_argument("--list-modules", action="store_true", + help="List all available modules") + + args = parser.parse_args() + + if args.list_modules: + print("\nAvailable modules:") + print("-" * 60) + for cat in sorted(set(m["category"] for m in MODULES.values())): + print(f"\n{cat}:") + for mid, info in MODULES.items(): + if info["category"] == cat: + print(f" {info['icon']} {mid}: {info['name']}") + return + + tool = ScreenshotTool(args.output) + + if args.all: + await tool.capture_host("vm") + await tool.capture_host("device") + tool.save_results() + elif args.host == "both": + await tool.capture_host("vm") + await tool.capture_host("device") + tool.save_results() + else: + await tool.capture_host(args.host) + tool.save_results() + + print("\n" + "=" * 60) + print("Screenshot capture complete!") + print("=" * 60) + + +if __name__ == "__main__": + asyncio.run(main())