The RPC expect clause unwraps responses - when `expect: { peers: [] }`
is used, the response `{peers: [...]}` gets unwrapped to just `[...]`.
Fixed:
- api.js: getAllData and getMonitoringData now handle both array
and object formats for peers, interfaces, and rates
- overview.js: render and polling functions now safely unwrap
data that may be array or nested object
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
RPCD backend:
- Fix critical json_init bug: variables must be extracted BEFORE
json_init() which wipes the loaded JSON. Affected functions:
save_settings, do_enable, set_bridges, add/remove_hidden_service
- Fix process detection: use pgrep instead of pid file
- Fix uptime calculation: get PID from pgrep, not pid file
- Fix RPC expect unwrapping in getDashboardData for presets
Init script:
- Remove PidFile directive (procd manages the process)
- Clean up stale files before starting to avoid permission issues
- Set proper ownership on torrc after generation
- Fix iptables chain creation to handle "already exists" gracefully
- Remove from OUTPUT chain before attempting chain deletion
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The RPC expect clause unwraps the response, so circuits data may be
an array directly rather than an object with circuits property.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix subshell bug in get_circuits (pipe loses JSON state)
- Add has_control flag to status for frontend awareness
- Fix UseBridges without bridge lines causing Tor to fail
- Fix hidden service directory ownership (tor:tor)
- Change log output from file to syslog
- Fix run directory ownership and permissions (700)
- Add CookieAuthentication for control socket auth
- Use socat instead of nc (BusyBox lacks Unix socket support)
- Add socat as package dependency
- Optimize duplicate curl calls in status check
- Use fallback IP services for real_ip detection
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add get_services RPCD method to detect listening TCP services
- Map known ports to service names, icons, and categories
- Display clickable service cards in portal Services tab
- Services link directly to their URLs (e.g., :3000 for Gitea)
- Filter to show only externally accessible services with URLs
- Add ACL permissions for portal and admin apps
Detected services include: Gitea, HexoJS, CyberFeed, Streamlit,
HAProxy Stats, Netifyd, LuCI, Lyrion, and more.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HexoJS now serves dynamically on :4000 via HAProxy vhost routing.
- Disabled auto_publish in metabolizer
- Disabled portal in hexojs
- /www stays free for SecuBox portal and other apps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 'generate' as alias for 'build' command
- Rename cmd_publish for drafts to cmd_publish_draft
- Fix duplicate cmd_publish functions
- Add portal config section with /www/blog path
- publish draft <slug> for drafts, publish for portal
- Metabolizer integration now working
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- RPCD _add_backend now parses inline 'server' option format
- Servers embedded in backend response with inline flag
- update_server converts inline servers to separate UCI sections
- delete_server handles both inline and separate server sections
- API and UI pass inline flag for proper handling
Fixes server port editing in LuCI backends interface.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add showEditVhostModal() for editing virtual host properties
- Add showEditBackendModal() for editing backend configuration
- Add showEditServerModal() for editing server properties
- Modern card-based UI with inline edit/delete actions
- Toggle enable/disable for backends
- Fix haproxyctl to read server option from backend UCI sections
- Add debug logging to container startup script
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change all hardcoded /blog/ paths to use / as root:
Theme configuration:
- _config.yml: Menu paths now /cybersecurity/ instead of /blog/cybersecurity/
- Blog submenu path changed to /categories/
Layout templates:
- post.ejs: Category link uses url_for with root path
- index.ejs: "Voir le blog" links to /categories/
- category.ejs: Breadcrumb and back links use /categories/
Scripts:
- dynamic-blog.js: Category paths now /{slug}/ instead of /blog/{slug}/
- Menu blog path changed to /categories/
Presets:
- tech.yml: Menu paths updated
- portfolio.yml: Blog link updated
hexoctl:
- Default portal_path changed from /www/blog to /www
- Help text updated
This allows the blog to be served from the root URL with categories
at /{category}/ paths.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change pidfile from haproxy-lxc.pid to haproxy.pid for consistency
with the actual container name.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change container references from 'haproxy-lxc' to 'haproxy' to match
the actual container name used by secubox-app-haproxy. This fixes
the LuCI status view showing container_running: false.
Fixes affected methods:
- method_status: container existence and state checks
- method_get_stats: container running check
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Templates now properly use Hexo's url_for() helper:
- apps.ejs: navigation links
- category.ejs: breadcrumb, apps, services, blog links
- showcase.ejs: contact, portfolio, apps, services links
This ensures all links work correctly when root is set to a
subdirectory (e.g., /blog/ instead of /)
Bumped release to r5
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Calculate web root from portal path (e.g., /www/blog → /blog/)
- Update _config.yml root setting before regenerating
- Run hexo clean && generate to apply new root
- Bumped release to r4
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Piped while loop runs in subshell, JSON additions don't persist
- Use temp file + redirect to avoid subshell issue
- Also fix list_backups with same pattern
- Bumped release to r2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Server now binds to 0.0.0.0 instead of localhost for external access
- Added publish command to copy static files to /www/blog/
- Startup script always regenerates to ensure correct binding
- Bumped release to r3
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add gitea_status, gitea_sync, gitea_clone, gitea_save_config RPCD methods
- Add Gitea section to sync.js with config form and sync buttons
- Update ACL for new Gitea methods
- Fix luci-app-metabolizer install section for RPCD executable
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove yaml import, use simple string parsing for front matter
- Remove dependency on host metabolizerctl
- Use environment variables for paths (METABOLIZER_CONTENT)
- Remove switch_page calls that fail in container
- CMS now works standalone inside Streamlit container
- Bump to r2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Export PATH at top of startup script for git binary
- Export HOME=/data for proper environment
- Set SCRIPT_TYPE=sh in app.ini (no bash in Alpine)
- Bump to r5
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Alpine's adduser wasn't creating the group properly, causing
chown git:git to fail with "unknown group".
- Add explicit addgroup -g 1000 git before adduser
- Use -G git flag to assign user to the group
- Bump to r4
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use /bin/sh instead of /bin/bash for git user shell
- Check for su-exec binary instead of marker file for deps
- Always recreate git user on startup (doesn't persist in container)
- Set explicit UID 1000 for git user
- Bump release to r3
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create /data, /opt, /run directories in rootfs during install
- Simplify mount entries (single /data mount)
- Ensure host data directories exist before creating LXC config
- Install dependencies (git, su-exec, etc.) on first container run
- Create required subdirectories in startup script
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add is_installed() and is_running() checks to init.d
- Show reason when service not running (disabled/not installed)
- Enable gitea by default in UCI config
- Require installation before starting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Metabolizer Blog Pipeline - integrated CMS for SecuBox:
- Gitea: Mirror GitHub repos, store blog content
- Streamlit: CMS app with markdown editor and live preview
- HexoJS: Static site generator (clean → generate → publish)
- Webhooks: Auto-rebuild on git push
- Portal: Static blog served at /blog/
Pipeline: Edit in Streamlit CMS → Push to Gitea → Build with Hexo → Publish
Packages:
- secubox-app-streamlit: Streamlit server with LXC container
- luci-app-streamlit: LuCI dashboard for Streamlit apps
- secubox-app-metabolizer: CMS pipeline orchestrator
CMS Features:
- Two-column markdown editor with live preview
- YAML front matter editor
- Post management (drafts, publish, unpublish)
- Media library with image upload
- Git sync and Hexo build controls
- Cyberpunk theme styling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Amber (#ffb000) for titles, borders, hover effects
- Green (#33ff33) for dates, sources, navigation
- Gradient timeline line (amber → green → amber)
- Glow effects on text and borders
- Audio items highlighted in green
- Status bar with item count and sync time
- Emojified content from AWK parser preserved
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Left panel (1/3): CRT monitor style with:
- Phosphor green text with glow effect
- Scanlines overlay
- Screen curvature effect
- Power LED with pulse animation
- VT323 monospace font
- Scrollable latest 15 items
- Right panel (2/3): Standard cyberpunk timeline with:
- Vertical timeline with neon gradient line
- Date grouping
- Audio player support
- Source badges
- Responsive: stacks vertically on mobile (CRT on top)
- Auto-refresh every 3 minutes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Star Wars opening crawl style timeline with:
- Starfield background with twinkling stars
- "A long time ago in a network far, far away...." intro
- CYBERFEED logo zoom animation
- 3D perspective text crawl (rotateX transform)
- Yellow text (#ffd700) with cyan accents (#0ff)
- Auto-refresh every 3 minutes
- Controls: PAUSE, RESET, HOME, REFRESH
- Fix LuCI API array handling in getFeeds/getItems:
- RPC `expect` declarations auto-extract nested properties
- Response IS the array, not res.feeds/res.items
- Add Array.isArray check to handle both cases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move emoji injection inside AWK parser to avoid corrupting JSON keys
- Use grep -o | wc -l for accurate item count on single-line JSON
- Emojis now only applied to title and desc fields, not URLs or keys
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rewrite RSS parser to use BusyBox-compatible AWK (no capture groups)
- Use extract_tag() helper with substr() instead of match() capture
- Use extract_attr() helper for XML attribute extraction
- Fix settings.js select elements to properly set initial value
- Use sel.value = ... instead of selected attribute
- Add new UCI config options for enhanced features:
- download_media, media_dir, history_file, generate_timeline
- Bump versions: secubox-app-cyberfeed 0.2.1, luci-app-cyberfeed 0.1.1
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Radio France presets (France Inter, France Culture, France Info, FIP, Mouv)
- Add international radio (BBC World, NPR)
- Add tech podcasts (Darknet Diaries, Changelog, Syntax.fm)
- Add 'radio' category to feed selector
- One-click quick-add buttons for all radio presets
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- get_feeds now returns {"feeds": [...]} instead of raw array
- get_items now returns {"items": [...]} instead of raw array
- Updated api.js to extract arrays from wrapped responses
- Fixes feed list not displaying in LuCI dashboard
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New packages:
- secubox-app-cyberfeed: Core RSS aggregator service
- Pure shell script, OpenWrt compatible
- Cyberpunk emoji injection based on content keywords
- Caching with configurable TTL
- JSON and HTML output with neon/glitch effects
- RSS-Bridge support for social media (Facebook, Twitter, YouTube)
- luci-app-cyberfeed: LuCI dashboard with cyberpunk theme
- Dashboard with stats, quick actions, recent items
- Feed management with add/delete
- RSS-Bridge templates for easy social media setup
- Preview with category filtering
- Settings page for service configuration
Features:
- Auto-emojification (security, tech, mystical themes)
- Dark neon UI with scanlines and glitch effects
- RSS-Bridge integration for Facebook/Twitter/YouTube
- Category-based filtering
- Auto-refresh via cron (5 min default)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pollRegistered flag to prevent duplicate poll registration
- Fix refreshDashboard to use replaceChild instead of dom.content
- Build content arrays explicitly to avoid null values in arrays
- Fix disabled attribute handling for action buttons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix TypeError "haproxy.api factory yields invalid constructor" by
refactoring api.js to use correct LuCI module pattern:
- Define RPC calls at module level with rpc.declare()
- Reference them in baseclass.extend() object
- Add getDashboardData helper function at module level
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add secubox-app-haproxy: LXC-containerized HAProxy service
- Alpine Linux container with HAProxy
- Multi-certificate SSL/TLS termination with SNI routing
- ACME/Let's Encrypt auto-renewal
- Virtual hosts management
- Backend health checks and load balancing
- Add luci-app-haproxy: Full LuCI web interface
- Overview dashboard with service status
- Virtual hosts management with SSL options
- Backends and servers configuration
- SSL certificate management (ACME + import)
- ACLs and URL-based routing rules
- Statistics dashboard and logs
- Settings for ports, timeouts, ACME
- Update luci-app-secubox-portal:
- Add Services category with HAProxy, HexoJS, PicoBrew,
Tor Shield, Jellyfin, Home Assistant, AdGuard Home, Nextcloud
- Make portal dynamic - only shows installed apps
- Add empty state UI for sections with no apps
- Remove 404 errors for uninstalled apps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add start-hexo.sh script as container init command
- Set PATH properly for hexo CLI in lxc_exec()
- Container now starts Hexo server automatically on boot
- Falls back to tail -f /dev/null if no site exists
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- secubox-app-hexojs: LXC-containerized Hexo service with Node.js
- hexoctl control script for container/site management
- Bundled CyberMind theme with dark/light mode
- Theme presets (minimal, tech, portfolio)
- Post/page scaffolds
- luci-app-hexojs: Full CMS dashboard
- Overview with stats and quick actions
- Post editor with Markdown toolbar and preview
- Media library browser
- Categories and tags management
- Apps portfolio for CyberMind theme
- Build and deploy to GitHub Pages
- GitHub Sync wizard (clone, pull, push)
- Theme configuration and presets
- Site settings
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add secubox-app-tor (backend) and luci-app-tor-shield (frontend) packages
for Tor anonymization on OpenWrt.
Backend features:
- UCI configuration with presets (anonymous, selective, censored)
- procd init script with iptables transparent proxy
- torctl CLI tool for status, enable/disable, circuits, leak-test
- DNS over Tor and kill switch support
- Hidden services and bridge management
Frontend features:
- Modern purple/onion themed dashboard
- One-click master toggle with visual status
- Real-time circuit visualization (Guard -> Middle -> Exit)
- Hidden services (.onion) management with copy/QR
- Bridge configuration (obfs4, snowflake, meek-azure)
- Leak detection tests
- Advanced settings for ports and exit node restrictions
Note: LuCI package renamed to luci-app-tor-shield to avoid conflict
with existing luci-app-tor package in OpenWrt LuCI feeds.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Flask 1.1.2 requires specific old versions of dependencies:
- Jinja2==2.11.3 (escape moved in 3.1)
- markupsafe==1.1.1
- itsdangerous==1.1.0 (json removed in 2.x)
- Werkzeug==1.0.1
- click==7.1.2
- pybeerxml<2.0.0 (Parser import changed in 2.x)
- marshmallow<4.0.0
Also:
- Use pip-installed package instead of git repo mount
- Simplify LXC mounts to just data directories
Tested and working on OpenWrt 24.10.5.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>