- Add shared kiss-theme.js module for consistent dark theme across views
- Add eye toggle button (👁️) to switch between KISS and LuCI modes
- Add git repo status methods to luci.gitea RPCD:
- get_repo_status: branch, ahead/behind, staged/modified files
- get_commit_history: recent commits with stats
- get_commit_stats: daily commit counts for graphs
- Update InterceptoR overview with KISS styling and responsive grid
- Fix quick links paths (network-tweaks → admin/network/)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove 'local' keyword from case statement block where it's not
allowed in POSIX shell. Replace && block conditions with proper
if/then/fi statements for health score calculation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add login/logout button in topbar (detects session state)
- Add collapsible LuCI Quick Nav tree in left sidebar
- Add LuCI Tree screen with grid view of all module links
- 7 categories: Core, Security, Network, Services, Monitoring, System, P2P
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add /etc/config/iot-guard with default settings so the Settings
page loads without RPC errors. Includes main config, zone policy,
allowlist, and blocklist sections.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rewrite using standard LuCI view pattern matching other portal views
- Use simple data array structure instead of nested objects
- Add proper event listener for search filter
- Organize 90+ links into 17 categories
- Fix JavaScript errors on public endpoint
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Async progressive cache: instant render from localStorage, async RPC updates
- Public ACL: unauthenticated access for secubox-public/portal route
- Progressive DOM updates via updateText() helpers
- No blocking Promise.all - each fetch updates its section on completion
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Auto-detects DNS server (BIND vs dnsmasq) and generates appropriate
blocklist format:
- BIND: Response Policy Zone (RPZ) with NXDOMAIN responses
- dnsmasq: addn-hosts sinkhole file (existing)
Tested with 46,067 blocked domains on BIND named server.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The handler was looking for dns-guard.detector_${det}.enabled but
UCI config uses dns-guard.${det}.enabled (without detector_ prefix).
This caused all detectors to show as Disabled in the dashboard.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace defunct malwaredomains feed with ThreatFox (abuse.ch)
- Add is_valid_domain() function to validate domain format
- Optimize intel_merge() with batch SQL transactions
- Previous: 765 domains with invalid entries (HTML parsing artifacts)
- Now: 46,056 valid domains from 3 feeds (URLhaus, OpenPhish, ThreatFox)
Performance: Batch import completes in seconds vs minutes for 45K+ domains.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
KISS-style dashboard for Vortex DNS Firewall with:
- Status cards: Active state, Blocked Domains, Total Blocks, x47 Impact
- Quick actions: Update Feeds, Block Domain, Search Domain
- Threat intelligence feeds table with domain counts and update times
- Top blocked domains table with threat badges
- Threat distribution visualization
- Live polling (10s) for real-time stats updates
- Dark mode support
Menu: Services > Vortex DNS Firewall
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 implementation of Vortex DNS Firewall - SecuBox's first line
of defense blocking threats at DNS level BEFORE any connection is
established.
Features:
- Threat intel aggregator (URLhaus, OpenPhish, Malware Domains)
- SQLite-based blocklist database with domain deduplication
- dnsmasq integration via sinkhole hosts file
- x47 vitality multiplier concept (each DNS block prevents ~47 connections)
- RPCD handler for LuCI integration with 8 methods
- CLI tool: vortex-firewall intel/stats/start/stop
Tested with 765 blocked domains across 3 threat feeds.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Support building images for: mochabin, espressobin-v7, espressobin-ultra, x86-64
- New CLI: secubox-cloner build --device espressobin-v7
- New CLI: secubox-cloner devices (list supported devices)
- RPCD: list_devices method, build_image accepts device_type param
- LuCI: Device selection dropdown in build modal
- LuCI: Device column in images table with badges
- Each device type has its own TFTP image file
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Dashboard with status cards: device, TFTP, tokens, clones
- Quick actions: Build Image, Start/Stop TFTP, Token generation
- Clone images table with size and TFTP-ready status
- Token management with auto-approve option
- U-Boot flash commands display when TFTP is running
- RPCD handler with 10 methods for full cloner management
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Pipe | while runs in subshell, json_add calls don't affect parent
- Use temp files to avoid subshell: write data to file, then read
- Fixed https_visitors, top_endpoints, recent_visitors arrays
- All arrays now properly populated with visitor data
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace --no-api + jsonfilter with jq length for counting
- jsonfilter cannot properly count JSON arrays
- --no-api flag returns empty results
- Applied fix to both get_overview() and stats functions
- Active Bans now shows correct count (was showing 0)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add poll.add() for continuous 3-second updates
- Use data-attributes for efficient DOM targeting
- Add CSS pulse animation on value changes
- Add live indicator with timestamp
- Implement updateValue, updateBar, updateList methods
- No page rebuilds - direct element text updates
- KISS and fast real-time metrics
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add get_active_sessions RPCD method to dashboard module
- Display session counts: Tor circuits, HTTPS, Streamlit, Mitmproxy, SSH
- Add ACTIVE SESSIONS panel with yellow/gold theme
- Add RECENT VISITORS panel showing visitor IPs and countries
- Add TOP ENDPOINTS panel showing accessed paths
- Add ACL permissions for get_active_sessions
- Auto-refresh with other metrics every 10 seconds
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove --no-api flag which returned empty results
- Use jq length instead of jsonfilter for counting arrays
- Add grep fallback when jq is not available
- Count all decisions, alerts, and bouncers correctly
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add callGetVisitStats RPC from security-threats API
- Add WEB TRAFFIC section with total requests, bots/humans counts
- Display country flags and visit counts for top 8 countries
- Add TOP HOSTS section showing top 5 visited hosts
- Green color theme for traffic sections
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add get_visit_stats RPCD method parsing mitmproxy threats.log
- Returns total requests, by_country, by_host, by_type, by_severity,
bots_vs_humans breakdown, and top_urls (all top 10)
- Add callGetVisitStats RPC declaration to api.js
- Add renderVisitStats function to dashboard with traffic analytics grid
- Shows traffic breakdown by country, host, and URL patterns
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed default visibility from public to private for new Gitea
repositories created by metablogizerctl and streamlitctl.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
MetaBlogizer uses per-site uhttpd instances, not LXC containers.
The watchdog was incorrectly treating it as an LXC service and
constantly trying to restart a non-existent container.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add automatic Gitea push after upload_finalize in Streamlit RPCD
- Add automatic Gitea push after upload_finalize in MetaBlogizer RPCD
- Fix MetaBlogizer to use site name instead of UCI section ID for push
- Fix metablogizerctl to read Gitea config from dedicated gitea section
Uploaded files via LuCI are now automatically synced to Gitea repos.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Streamlit:
- App create/deploy now auto-pushes to Gitea when enabled
- Add 'gitea init-all' command to initialize repos for all existing apps
- Scans all app directories and creates Gitea repos
MetaBlogizer:
- Site create now auto-pushes to Gitea when token configured
- Add 'gitea init-all' command to initialize repos for all existing sites
- Iterates over UCI site configs and syncs to Gitea
Usage:
# Configure Gitea once
uci set streamlit.gitea.enabled=1
uci set streamlit.gitea.url='http://192.168.255.1:3000'
uci set streamlit.gitea.user='admin'
uci set streamlit.gitea.token='<token>'
uci commit streamlit
# Initialize all existing apps/sites
streamlitctl gitea init-all
metablogizerctl gitea init-all
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Streamlit/MetaBlogizer:
- Add 'gitea push <name>' command to both streamlitctl and metablogizerctl
- Auto-creates Gitea repo via API if it doesn't exist
- Initializes git, commits all files, and pushes to Gitea
- Stores repo reference in UCI for future syncs
Tor Shield:
- Add 'wan_input_allow' option for server preset
- Server mode now properly allows WAN inbound (ports 80, 443, 8443)
- Uses nftables rules to integrate with OpenWrt firewall4
- Outbound traffic still routed through Tor (kill_switch)
- Cleanup nftables rules on stop/disable
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace failing awk-based JSON parsing with jsonfilter per-alert extraction.
Alerts now correctly populate in CrowdSec dashboard.
Changes:
- Use jsonfilter to extract created_at, scenario, source_ip per alert
- Loop through up to 8 alerts with index-based access
- Remove Python dependency (not available on OpenWrt)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend uses timestamp/source_ip but JS was looking for time/ip.
Fixed field mappings:
- timestamp -> time display
- source_ip -> ip display
- request -> details fallback
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Alerts data was loaded but not displayed. Added new section showing:
- Time, IP, country, type, severity, details
- Limited to 25 most recent alerts
- Clear alerts button
- Proper severity colors and icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add HAProxy multi-domain SSL certificate matching issue
- Document crt-list solution for SNI issues
- Minor updates to settings and streamlit readme
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TRUSTED_PATH_PREFIXES for LuCI, ubus, and CGI paths
- Fix moderate mode to always require threshold (3 attempts in 5 min)
instead of immediate ban on critical threats
- Add WireGuard endpoint whitelist support to prevent VPN peer bans
- New script: mitmproxy-sync-wg-endpoints extracts peer IPs from UCI
- Bump version to v2.4
Prevents accidental bans from legitimate external LuCI login attempts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Shows all CrowdSec bans with:
- IP address, reason, source (WAF/CrowdSec), country, expiration
- Summary counts: total, WAF autobans, CrowdSec detections
- Unban button for each entry with confirmation dialog
- Empty state when no bans active
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New methods for threats monitor dashboard:
- bans: Get CrowdSec decisions with counts by source
Returns total, mitmproxy_autoban, crowdsec counts + full bans array
- unban: Remove ban by IP address
Updates ACL to include new methods for LuCI access.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New haproxyctl path commands:
- path list: Show all path ACLs with patterns and backends
- path sync <prefix> <host>: Auto-generate ACLs from all backends
Extracts short name from backend (metablog_X -> X, streamlit_Y -> Y)
Skips existing ACLs, only adds new ones
- path add: Manually add single path ACL
- path remove: Remove specific path ACL
- path clear: Remove all ACLs matching prefix
This enables dynamic route updates when backends change.
Example: haproxyctl path sync /gk2 secubox.in
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Path-based ACLs are now sorted by pattern length (longest first) before
being emitted to haproxy.cfg. This ensures specific paths like /gk2/evolution
match before general paths like /gk2.
Two-phase approach:
- _collect_path_acl() stores ACL data with pattern length prefix
- _emit_sorted_path_acls() sorts by length descending and emits rules
Enables apex domain path routing: secubox.in/gk2/** instead of *.gk2.secubox.in
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>