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 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-03-24 12:36:19 +01:00
parent d2049bb920
commit 948003c307
5 changed files with 1087 additions and 0 deletions

190
docs/wiki/UI-COMPARISON.md Normal file
View File

@ -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*

View File

@ -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/<module>/ → 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 <token>
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/<module>/status
# List items
curl -sk -H "Authorization: Bearer $TOKEN" \
https://secubox/api/v1/<module>/list
# Create item
curl -sk -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "value"}' \
https://secubox/api/v1/<module>/create
# Delete item
curl -sk -X DELETE -H "Authorization: Bearer $TOKEN" \
https://secubox/api/v1/<module>/delete/<id>
```
### 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*

View File

@ -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*

View File

@ -0,0 +1,4 @@
# Requirements for screenshot-tool.py
playwright>=1.40.0
aiohttp>=3.9.0
Pillow>=10.0.0

593
scripts/screenshot-tool.py Executable file
View File

@ -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/<module>/`:
```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())