From a677f8cf490a6c1155d5851897c1ccfe8600c872 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Mon, 12 Jan 2026 07:57:39 +0100 Subject: [PATCH] feat: Media-flow UI + security updates Co-Authored-By: Claude Opus 4.5 --- .claude/settings.local.json | 469 +----------------- .../view/crowdsec-dashboard/settings.js | 34 ++ package/secubox/luci-app-media-flow/Makefile | 2 +- .../luci-static/resources/media-flow/nav.js | 49 ++ .../resources/view/media-flow/alerts.js | 53 +- .../resources/view/media-flow/clients.js | 41 +- .../resources/view/media-flow/dashboard.js | 22 +- .../resources/view/media-flow/history.js | 49 +- .../resources/view/media-flow/services.js | 44 +- .../root/www/secubox-feed/Packages.gz | Bin 6466 -> 6466 bytes .../root/www/secubox-feed/apps-local.json | 2 +- .../secubox/secubox-app-mitmproxy/Makefile | 58 +-- scripts/auto_block_luci_bruteforce.sh | 52 ++ 13 files changed, 245 insertions(+), 630 deletions(-) create mode 100644 package/secubox/luci-app-media-flow/htdocs/luci-static/resources/media-flow/nav.js create mode 100644 scripts/auto_block_luci_bruteforce.sh diff --git a/.claude/settings.local.json b/.claude/settings.local.json index f1320ca8..5707c58a 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -1,474 +1,7 @@ { "permissions": { "allow": [ - "Bash(done)", - "Bash(ls:*)", - "Bash(find:*)", - "Bash(xargs:*)", - "Bash(mkdir:*)", - "Bash(shellcheck:*)", - "Bash(git add:*)", - "Bash(git commit:*)", - "Bash(git push)", - "Bash(git remote set-url:*)", - "Bash(git tag:*)", - "Bash(git push:*)", - "Bash(for module in crowdsec netdata netifyd)", - "Bash(do echo \"=== $module-dashboard ===\" grep '\"\"\"\"path\"\"\"\":' luci-app-$module-dashboard/root/usr/share/luci/menu.d/*.json)", - "Bash(grep:*)", - "Bash(for module in cdn-cache client-guardian crowdsec netdata netifyd-dashboard network-modes system-hub wireguard-dashboard)", - "Bash(do echo '=== $module ===' find luci-app-$module/htdocs -name *.js -exec grep -h object: {})", - "Bash(chmod:*)", - "Bash(./secubox-tools/validate-modules.sh:*)", - "Bash(./secubox-tools/validate-module-generation.sh:*)", - "Bash(bash:*)", - "Bash(timeout 10 ./secubox-tools/validate-module-generation.sh:*)", - "Bash(cat:*)", - "Bash(python3:*)", - "Bash(for file in luci-app-vhost-manager/htdocs/luci-static/resources/view/vhost-manager/*.js)", - "Bash(do)", - "Bash(node -c:*)", - "Bash(for file in luci-app-bandwidth-manager/htdocs/luci-static/resources/view/bandwidth-manager/*.js)", - "Bash(for file in luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/*.js)", - "Bash(./local-build.sh:*)", - "Bash(./scripts/feeds list:*)", - "Bash(./scripts/feeds update:*)", - "Bash(./scripts/feeds install:*)", - "Bash(make:*)", - "Bash(rsync:*)", - "Bash(./secubox-tools/local-build.sh:*)", - "Bash(gh --version:*)", - "Bash(git reset:*)", - "Bash(test:*)", - "Bash(for file in luci-app-traffic-shaper/htdocs/luci-static/resources/view/traffic-shaper/*.js)", - "Bash(wc:*)", - "Bash(./secubox-tools/show-module-status.sh:*)", - "Bash(for file in luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/*.js luci-app-client-guardian/htdocs/luci-static/resources/client-guardian/api.js)", - "Bash(for file in luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/*.js luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js)", - "Bash(for file in luci-app-netdata-dashboard/htdocs/luci-static/resources/view/netdata-dashboard/*.js luci-app-netdata-dashboard/htdocs/luci-static/resources/netdata-dashboard/api.js)", - "Bash(do echo \"Checking $file...\")", - "Bash(echo:*)", - "Bash(for file in luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/*.js luci-app-media-flow/htdocs/luci-static/resources/media-flow/*.js)", - "WebFetch(domain:github.com)", - "Bash(for file in luci-app-traffic-shaper/htdocs/luci-static/resources/view/traffic-shaper/*.js luci-app-traffic-shaper/htdocs/luci-static/resources/traffic-shaper/api.js)", - "Bash(timeout 5 ./secubox-tools/validate-modules.sh:*)", - "Bash(tree:*)", - "Bash(for file in luci-app-ksm-manager/htdocs/luci-static/resources/view/ksm-manager/*.js luci-app-ksm-manager/htdocs/luci-static/resources/ksm-manager/api.js)", - "Bash(git show:*)", - "Bash(for module in luci-app-*/root/usr/share/luci/menu.d/*.json)", - "Bash(do if [ -f $module ])", - "Bash(then echo '=== $\\(basename $module\\) ===' jq -r \".[\"\"admin/secubox\"\"] // empty | keys[]\" $module)", - "Bash(for category in security monitoring network system services)", - "Bash(do echo \"=== admin/secubox/$category ===\" grep -h \"\"\"admin/secubox/$category/\" luci-app-*/root/usr/share/luci/menu.d/*.json)", - "Bash(pgrep:*)", - "Bash(git rev-parse:*)", - "Bash(ping:*)", - "Bash(timeout 5 curl:*)", - "Bash(gh run list:*)", - "Bash(for dir in luci-app-*/)", - "Bash(do if [ -f \"$dir/Makefile\" ])", - "Bash(then if ! grep -q \"include.*luci.mk\" \"$dir/Makefile\")", - "Bash(fi)", - "Bash(gh workflow run:*)", - "Bash(curl:*)", - "Bash(sudo apt-get install:*)", - "Bash(/tmp/deploy-system-hub.sh)", - "Bash(ssh:*)", - "Bash(timeout 10 ./secubox-tools/validate-modules.sh:*)", - "Bash(scp:*)", - "Bash(./deploy-theme-system.sh)", - "Bash(for file in health.js services.js logs.js backup.js components.js remote.js settings.js diagnostics.js)", - "Bash(if [ -f \"$file\" ])", - "Bash(then)", - "Bash(if ! grep -q \"system-hub/theme\" \"$file\")", - "Bash(for file in services.js logs.js backup.js components.js remote.js settings.js diagnostics.js)", - "Bash(do if [ -f \"$file\" ])", - "Bash(then head -10 \"$file\")", - "Bash(./deploy-beta-release.sh:*)", - "Bash(./deploy-v0.1.1.sh:*)", - "Bash(luci-app-secubox/Makefile )", - "Bash(luci-app-secubox/htdocs/luci-static/resources/secubox/*.css)", - "Bash(luci-app-secubox/htdocs/luci-static/resources/secubox/theme.js )", - "Bash(luci-app-secubox/htdocs/luci-static/resources/view/secubox/*.js)", - "Bash(luci-app-secubox/root/usr/libexec/rpcd/luci.secubox )", - "Bash(luci-app-secubox/root/usr/share/rpcd/acl.d/luci-app-secubox.json )", - "Bash(luci-app-system-hub/Makefile )", - "Bash(luci-app-system-hub/README.md )", - "Bash(luci-app-system-hub/htdocs/luci-static/resources/system-hub/api.js )", - "Bash(luci-app-system-hub/htdocs/luci-static/resources/system-hub/dashboard.css )", - "Bash(luci-app-system-hub/htdocs/luci-static/resources/system-hub/theme.js )", - "Bash(luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/*.js)", - "Bash(luci-app-system-hub/root/usr/libexec/rpcd/luci.system-hub )", - "Bash(luci-app-system-hub/root/usr/share/rpcd/acl.d/luci-app-system-hub.json )", - "Bash(LUCI_DEVELOPMENT_REFERENCE.md)", - "Bash(while read file)", - "Bash(do echo \"=== $file ===\" grep \"object:\" \"$file\")", - "Bash(for file in luci-app-secubox/htdocs/luci-static/resources/view/secubox/*.js luci-app-secubox/htdocs/luci-static/resources/secubox/*.js)", - "Bash(./deploy-secubox-fix.sh)", - "Bash(./deploy-modules-v2.sh:*)", - "Bash(./deploy-dynamic-modules.sh:*)", - "Bash(/tmp/force-reload-luci.sh:*)", - "Bash(/tmp/deploy-common-css.sh)", - "Bash(/tmp/deploy-services.sh)", - "Bash(/tmp/deploy-health.sh)", - "Bash(/tmp/deploy-system-hub-all.sh)", - "Bash(/tmp/deploy-secubox-final.sh)", - "WebFetch(domain:cybermind.fr)", - "Bash(/tmp/deploy-system-hub-demo-style.sh)", - "Bash(./secubox-tools/build-modules.sh:*)", - "Bash(./secubox-tools/fix-permissions.sh:*)", - "Bash(/tmp/deploy-acl-updates.sh:*)", - "Bash(/tmp/deploy-acl-updates-v2.sh)", - "WebSearch", - "WebFetch(domain:secubox.cybermood.eu)", - "Bash(timeout 5 ssh:*)", - "Bash(ssh-keygen:*)", - "Bash(/tmp/deploy-v0.3.1.sh)", - "Bash(/tmp/deploy-v0.3.1-scp.sh)", - "Bash(tar czf:*)", - "Bash(__NEW_LINE__ echo \"\")", - "Bash(./secubox-tools/add-pkg-file-modes.sh:*)", - "Bash(luci-app-secubox/htdocs/luci-static/resources/view/secubox/dashboard.js )", - "Bash(luci-app-secubox/htdocs/luci-static/resources/view/secubox/modules.js )", - "Bash(git checkout:*)", - "Bash(./scripts/setup-github-pages.sh:*)", - "Bash(mkdocs:*)", - "Bash(apt search:*)", - "Bash(source .venv/bin/activate)", - "Bash(pip install:*)", - "Bash(./scripts/setup-wiki.sh:*)", - "Bash(gh repo edit --help:*)", - "Bash(gh repo edit:*)", - "Bash(gh auth status:*)", - "Bash(git ls-remote:*)", - "Bash(for module in luci-app-ksm-manager luci-app-media-flow luci-app-netdata-dashboard luci-app-netifyd-dashboard luci-app-network-modes luci-app-secubox luci-app-system-hub luci-app-traffic-shaper luci-app-vhost-manager luci-app-wireguard-dashboard)", - "Bash(do echo \"=== $module ===\" find \"$module/htdocs/luci-static/resources/view\" -name \"*.js\")", - "Bash(gh run view:*)", - "Bash(/tmp/deploy-system-hub-overview-fix.sh)", - "Bash(./secubox-tools/deploy-network-modes.sh:*)", - "Bash(/tmp/generalize-makefile-filemodes.sh)", - "Bash(for file in luci-theme-secubox/htdocs/luci-static/resources/secubox-theme/i18n/*.json)", - "Bash(./deploy-theme.sh:*)", - "Bash(./deploy-modules-with-theme.sh:*)", - "Bash(luci-app-network-modes/htdocs/luci-static/resources/view/network-modes/overview.js )", - "Bash(luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/overview.js )", - "Bash(luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/services.js )", - "Bash(deploy-modules-with-theme.sh)", - "Bash(timeout 120 ./local-build.sh:*)", - "Bash(do echo \"=== admin/secubox/$category ===\")", - "Bash(./secubox-tools/sync_module_versions.sh:*)", - "Bash(for f in /home/reepost/CyberMindStudio/_files/secubox-openwrt/luci-app-*/htdocs/luci-static/resources/view/*/*.js)", - "Bash(do grep -q \"secubox-theme/theme\" \"$f\")", - "Bash(! grep -q \"cyberpunk.css\" \"$f\")", - "Bash(./secubox-tools/quick-deploy.sh:*)", - "WebFetch(domain:raw.githubusercontent.com)", - "WebFetch(domain:docs.crowdsec.net)", - "Bash(timeout 600 make:*)", - "Bash(timeout 300 make:*)", - "Bash(timeout 120 make:*)", - "Bash(ln:*)", - "Bash(tee:*)", - "Bash(feeds/packages/net/crowdsec/patches/)", - "Bash(feeds/packages/net/crowdsec/files/)", - "Bash(feeds/packages/net/crowdsec/Makefile)", - "Bash(feeds/packages/net/crowdsec/patches/002-fix_go_version.patch)", - "Bash(tail:*)", - "Bash(pkill -f \"local-build.sh build secubox-app-crowdsec\")", - "Bash(go version:*)", - "Bash(timeout 600 ./secubox-tools/local-build.sh:*)", - "Bash(timeout 300 ./secubox-tools/local-build.sh:*)", - "Bash(paste:*)", - "Bash(git -C /home/reepost/CyberMindStudio/_files/secubox-openwrt status --short .github/workflows/)", - "Bash(/tmp/deploy-secubox-bonus.sh)", - "Bash(git rm:*)", - "Bash(timeout 180 ./local-build.sh:*)", - "Bash(tar:*)", - "Bash(for makefile in luci-app-*/Makefile)", - "Bash(do echo \"=== $makefile ===\" grep -A15 \"define Package.*install\" \"$makefile\")", - "Bash(ssh root@192.168.8.191:*)", - "Bash(flatpak-spawn --host which:*)", - "Bash(export PATH=\"$HOME/.local/bin:$PATH\")", - "Bash(jsonfilter:*)", - "Bash(for app in luci-app-auth-guardian luci-app-bandwidth-manager luci-app-cdn-cache luci-app-client-guardian luci-app-crowdsec-dashboard)", - "Bash(do echo \"Moving $app...\")", - "Bash(git mv:*)", - "Bash(rm:*)", - "Bash(find . -type d -name \"appstore\" ! -path \"*/\\\\.git/*\" ! -path \"*/sdk/*\" -exec sh -c 'echo \"\"{}:\"\" && ls -la \"\"{}\"\" | tail -n +4 | head -5' ;)", - "Bash(find . -type d -name \"modules\" ! -path \"*/\\\\.git/*\" ! -path \"*/sdk/*\" ! -path \"*/node_modules/*\" -exec sh -c 'dir=\"\"{}\"\"; if echo \"\"$dir\"\" | grep -q \"\"secubox\"\"; then echo \"\"$dir:\"\" && ls -la \"\"$dir\"\" 2>/dev/null | tail -n +4 | head -5 || echo \"\" \\(empty\\)\"\"; fi' ;)", - "Bash(find . -type d -name \"components\" ! -path \"*/\\\\.git/*\" ! -path \"*/sdk/*\" ! -path \"*/node_modules/*\" -exec sh -c 'dir=\"\"{}\"\"; if echo \"\"$dir\"\" | grep -q \"\"secubox\"\"; then echo \"\"$dir:\"\" && ls -la \"\"$dir\"\" 2>/dev/null | tail -n +4 | head -5 || echo \"\" \\(empty\\)\"\"; fi' ;)", - "Bash(for file in package/secubox/secubox-core/root/usr/share/secubox/plugins/catalog/*.json)", - "Bash(do jq:*)", - "Bash(then jq -e . \"$file\")", - "Bash(sh:*)", - "Bash(/tmp/deploy-components-modules-fix.sh)", - "Bash(while read d)", - "Bash(do mf=\"$d/Makefile\")", - "Bash(if [ -f \"$mf\" ])", - "Bash(then echo \"$mf\")", - "Bash(for d in package/secubox/luci-app-*/)", - "Bash(do if [ -d \"$d/files\" ])", - "Bash(for d in secubox-tools/local-feed/luci-app-*/)", - "Bash(sudo apt-get update:*)", - "Bash(apt-get update:*)", - "Bash(apt-get install:*)", - "Bash(uvicorn:*)", - "Bash(lsof:*)", - "Bash(netstat:*)", - "Bash(python -c:*)", - "Bash(python -m pytest:*)", - "Bash(source secubox-tools/webui/.venv/bin/activate:*)", - "Bash(python -m app.ingest:*)", - "Bash(python -m json.tool:*)", - "Bash(python -m uvicorn:*)", - "Bash(./local-build.sh)", - "Bash(./scripts/feeds search:*)", - "Bash(./sdk/scripts/feeds install:*)", - "Bash(readlink:*)", - "Bash(git -C feeds/luci branch:*)", - "WebFetch(domain:mailinabox.email)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat: Release v0.8.2 - Admin Control Center, Documentation Mirror & Docker Automation\n\nThis release adds major new features for SecuBox management and deployment:\n\n## New Features\n\n### 1. LuCI Admin Control Center \\(luci-app-secubox-admin\\)\n- Unified admin dashboard for managing all SecuBox appstore plugins\n- **Control Panel**: Real-time stats, system health, alerts, quick actions\n- **Apps Manager**: Browse catalog, install/remove apps with search & filtering\n- **App Settings**: Per-app configuration, start/stop controls\n- **System Health**: Live monitoring \\(CPU, RAM, disk\\) with auto-refresh\n- **System Logs**: Centralized log viewer with download capability\n- Fully integrated with existing RPCD backend \\(luci.secubox\\)\n- Mobile-responsive design with polished UI components\n\n### 2. Documentation Mirror in SecuBox Bonus\n- Integrated complete development documentation into luci-app-secubox-bonus\n- 64+ documentation files now available offline at /luci-static/secubox/docs/\n- Beautiful landing page \\(index-main.html\\) with 4 sections:\n - Development guides & references\n - Live module demos\n - Tutorials & blog posts\n - Marketing campaign pages\n- Accessible locally on router without internet connection\n\n### 3. Automated Docker Plugin Installation\n- Enhanced secubox-appstore CLI with full Docker automation\n- One-click installation from web UI now fully automated:\n - Auto-detects Docker runtime from catalog\n - Discovers and executes control scripts \\(*ctl install\\)\n - Pulls Docker images automatically\n - Creates directories and configures UCI\n - Enables init services\n- No manual CLI steps required for Docker apps\n- Works for all Docker apps: AdGuard Home, Mail-in-a-Box, Nextcloud, etc.\n\n### 4. Mail-in-a-Box Plugin\n- New Docker-based email server plugin \\(secubox-app-mailinabox\\)\n- Complete package with:\n - UCI configuration \\(8 port mappings, feature flags\\)\n - Control script \\(mailinaboxctl\\) with install/check/update/status/logs\n - Procd init script with auto-restart\n - Catalog manifest \\(category: hosting, maturity: beta\\)\n- Network mode: host \\(required for mail server\\)\n- Persistent storage: mail, SSL, data, DNS volumes\n\n## Improvements\n\n### Build System\n- Updated local-build.sh to include luci-app-* packages from package/secubox/\n- Now automatically discovers and builds luci-app-secubox-admin and similar packages\n- Fixed Makefile include paths for feed structure\n\n### Catalog Updates\n- Mail-in-a-Box entry moved from \"productivity\" to \"hosting\" category\n- Status changed to \"beta\" reflecting community Docker image maturity\n- Storage requirement increased: 1024MB → 2048MB\n- Added port 25 accessibility note\n\n## Files Changed\n\n### New Packages \\(2\\)\n- package/secubox/luci-app-secubox-admin/ \\(12 files\\)\n- package/secubox/secubox-app-mailinabox/ \\(4 files\\)\n\n### Enhanced Packages \\(1\\)\n- package/secubox/luci-app-secubox-bonus/ \\(65 new docs files\\)\n\n### Modified Core \\(3\\)\n- package/secubox/secubox-core/root/usr/sbin/secubox-appstore\n- package/secubox/secubox-core/root/usr/share/secubox/catalog.json\n- secubox-tools/local-build.sh\n\n## Technical Details\n\n**Admin Control Center Architecture:**\n- Frontend: 5 views \\(dashboard, apps, settings, health, logs\\)\n- API: Wrapper around luci.secubox RPCD methods\n- Components: Reusable UI library \\(cards, badges, alerts, loaders\\)\n- Styling: Common + admin-specific CSS with responsive design\n- Auto-refresh: Polling for live updates \\(5-30s intervals\\)\n\n**Docker Automation Flow:**\n```\nWeb UI → RPCD → secubox-appstore CLI → opkg install → *ctl install →\ndocker pull → directories → UCI config → init enable → ✓ Ready\n```\n\n**Access Points:**\n- Admin Control: http://router/cgi-bin/luci/admin/secubox/admin/\n- Documentation: http://router/luci-static/secubox/index-main.html\n- Demos: http://router/luci-static/secubox/demo-*.html\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(git commit --amend -m \"$\\(cat <<''EOF''\nfeat: Release v0.8.2 - Admin Control Center, Documentation Mirror & Docker Automation\n\nThis release adds major new features for SecuBox management and deployment:\n\n## New Features\n\n### 1. LuCI Admin Control Center \\(luci-app-secubox-admin\\)\n- Unified admin dashboard for managing all SecuBox appstore plugins\n- **Control Panel**: Real-time stats, system health, alerts, quick actions\n- **Apps Manager**: Browse catalog, install/remove apps with search & filtering\n- **App Settings**: Per-app configuration, start/stop controls\n- **System Health**: Live monitoring \\(CPU, RAM, disk\\) with auto-refresh\n- **System Logs**: Centralized log viewer with download capability\n- Fully integrated with existing RPCD backend \\(luci.secubox\\)\n- Mobile-responsive design with polished UI components\n\n### 2. Documentation Mirror in SecuBox Bonus\n- Integrated complete development documentation into luci-app-secubox-bonus\n- 64+ documentation files now available offline at /luci-static/secubox/docs/\n- Beautiful landing page \\(index-main.html\\) with 4 sections:\n - Development guides & references\n - Live module demos\n - Tutorials & blog posts\n - Marketing campaign pages\n- Accessible locally on router without internet connection\n\n### 3. Automated Docker Plugin Installation\n- Enhanced secubox-appstore CLI with full Docker automation\n- One-click installation from web UI now fully automated:\n - Auto-detects Docker runtime from catalog\n - Discovers and executes control scripts \\(*ctl install\\)\n - Pulls Docker images automatically\n - Creates directories and configures UCI\n - Enables init services\n- No manual CLI steps required for Docker apps\n- Works for all Docker apps: AdGuard Home, Mail-in-a-Box, Nextcloud, etc.\n\n### 4. Mail-in-a-Box Plugin\n- New Docker-based email server plugin \\(secubox-app-mailinabox\\)\n- Complete package with:\n - UCI configuration \\(8 port mappings, feature flags\\)\n - Control script \\(mailinaboxctl\\) with install/check/update/status/logs\n - Procd init script with auto-restart\n - Catalog manifest \\(category: hosting, maturity: beta\\)\n- Network mode: host \\(required for mail server\\)\n- Persistent storage: mail, SSL, data, DNS volumes\n\n## Improvements\n\n### Build System\n- Updated local-build.sh to include luci-app-* packages from package/secubox/\n- Now automatically discovers and builds luci-app-secubox-admin and similar packages\n- Fixed Makefile include paths for feed structure\n\n### Package Releases\n- Incremented PKG_RELEASE for all 31 SecuBox packages\n- Ensures clean upgrade path from previous versions\n\n### Catalog Updates\n- Mail-in-a-Box entry moved from \"productivity\" to \"hosting\" category\n- Status changed to \"beta\" reflecting community Docker image maturity\n- Storage requirement increased: 1024MB → 2048MB\n- Added port 25 accessibility note\n\n## Files Changed\n\n### New Packages \\(2\\)\n- package/secubox/luci-app-secubox-admin/ \\(12 files\\)\n- package/secubox/secubox-app-mailinabox/ \\(4 files\\)\n\n### Enhanced Packages \\(1\\)\n- package/secubox/luci-app-secubox-bonus/ \\(65 new docs files\\)\n\n### Modified Core \\(3\\)\n- package/secubox/secubox-core/root/usr/sbin/secubox-appstore\n- package/secubox/secubox-core/root/usr/share/secubox/catalog.json\n- secubox-tools/local-build.sh\n\n### All Makefiles \\(31 packages\\)\n- Incremented PKG_RELEASE for clean upgrade path\n\n## Technical Details\n\n**Admin Control Center Architecture:**\n- Frontend: 5 views \\(dashboard, apps, settings, health, logs\\)\n- API: Wrapper around luci.secubox RPCD methods\n- Components: Reusable UI library \\(cards, badges, alerts, loaders\\)\n- Styling: Common + admin-specific CSS with responsive design\n- Auto-refresh: Polling for live updates \\(5-30s intervals\\)\n\n**Docker Automation Flow:**\n```\nWeb UI → RPCD → secubox-appstore CLI → opkg install → *ctl install →\ndocker pull → directories → UCI config → init enable → ✓ Ready\n```\n\n**Access Points:**\n- Admin Control: http://router/cgi-bin/luci/admin/secubox/admin/\n- Documentation: http://router/luci-static/secubox/index-main.html\n- Demos: http://router/luci-static/secubox/demo-*.html\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(xargs git add)", - "Bash(./scripts/feeds:*)", - "Bash(network)", - "Bash(monitoring)", - "Bash(hosting)", - "Bash(compact)", - "Bash(But that file is already provided by package secubox-core\"\n\nChanges:\n- Makefile: Removed +luci-app-secubox from LUCI_DEPENDS\n- Package now only depends on: +luci-base +rpcd +secubox-core\n- Incremented PKG_RELEASE: 7 → 8\n- Updated DEPLOY_UPDATES.md with v1.0.0-8 details\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(./deploy-to-router.sh:*)", - "Bash(pkill:*)", - "Bash(/usr/libexec/rpcd/luci.secubox call:*)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat: v0.8.3 - Complete theming, responsive & dynamic features\n\nMajor Features:\n- 🎨 8 Themes: dark, light, cyberpunk, ocean, sunset, forest, minimal, contrast\n- 📱 Fully Responsive: mobile-first with 500+ utility classes\n- 📊 Chart.js Integration: 5 chart types \\(line, bar, doughnut, gauge, sparkline\\)\n- 🔄 Real-time Updates: WebSocket + polling fallback\n- ✨ 60+ Animations: entrance, attention, loading, continuous, interactive\n- 📚 Complete Documentation: 35,000+ words across 5 guides\n\nTheming System:\n- Unified cyberpunk theme \\(643 lines\\)\n- 5 new themes \\(ocean, sunset, forest, minimal, contrast\\)\n- 30+ CSS custom properties\n- Theme switching API\n\nResponsive Design:\n- Mobile-first approach \\(375px - 1920px+\\)\n- 500+ utility classes \\(spacing, display, flex, grid, typography\\)\n- Responsive components \\(tables, forms, navigation, modals, cards\\)\n- Touch-friendly targets \\(44px minimum on mobile\\)\n\nDynamic Features:\n- 9 widget templates \\(default, security, network, monitoring, hosting, compact, charts, sparkline\\)\n- Chart.js wrapper utilities \\(chart-utils.js\\)\n- Real-time client \\(WebSocket + polling, auto-reconnect\\)\n- Widget renderer with real-time integration\n\nAnimations:\n- 889 lines of animations \\(was 389\\)\n- 14 entrance animations\n- 10 attention seekers\n- 5 loading animations\n- Page transitions, modals, tooltips, forms, badges\n- JavaScript animation API\n\nDocumentation:\n- README.md \\(2,500 words\\)\n- THEME_GUIDE.md \\(10,000 words\\)\n- RESPONSIVE_GUIDE.md \\(8,000 words\\)\n- WIDGET_GUIDE.md \\(9,000 words\\)\n- ANIMATION_GUIDE.md \\(8,000 words\\)\n\nBug Fixes:\n- Fixed data-utils.js baseclass implementation\n- Fixed realtime-client integration in widget-renderer\n- Removed duplicate cyberpunk.css\n\nFiles Created: 15\n- 5 new themes\n- 2 new components \\(charts.css, featured-apps.css\\)\n- 3 JS modules \\(chart-utils.js, realtime-client.js\\)\n- 1 library \\(chart.min.js 201KB\\)\n- 5 documentation guides\n\nFiles Modified: 7\n- animations.css \\(+500 lines\\)\n- utilities.css \\(+460 lines\\)\n- theme.js \\(+90 lines\\)\n- widget-renderer.js \\(+50 lines\\)\n- data-utils.js \\(baseclass fix\\)\n- cyberpunk.css \\(unified\\)\n\nPerformance:\n- CSS bundle: ~150KB minified\n- JS core: ~50KB\n- Chart.js: 201KB \\(lazy loaded\\)\n- First Contentful Paint: <1.5s\n- Time to Interactive: <2.5s\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(/home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/secubox-core/root/usr/sbin/secubox-state:*)", - "Bash(command -v shellcheck:*)", - "Bash(/home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/secubox-core/root/usr/sbin/secubox-component:*)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat: Admin Control Center with State Management \\(v0.9.0\\)\n\nMajor feature release implementing comprehensive state management, component registry,\nand admin control center with full UI integration.\n\n## Backend Features \\(secubox-core v0.9.0-1\\)\n\nState Management System:\n- ✅ State database \\(state-db.json\\) with 15 states across 4 categories\n- ✅ State machine with transition matrix validation\n- ✅ secubox-state CLI \\(8 commands: get, set, history, list, validate, sync, freeze, clear-error\\)\n- ✅ state-machine.sh with atomic transitions using flock\n- ✅ State history tracking with timestamps and reasons\n- ✅ Error state handling with detailed error info\n- ✅ Frozen state support for system-critical components\n\nComponent Registry System:\n- ✅ Component registry database \\(component-registry.json\\)\n- ✅ secubox-component CLI \\(7 commands: list, get, register, unregister, tree, affected, set-setting\\)\n- ✅ Component types: app, module, widget, service, composite\n- ✅ Dependency tracking \\(required/optional\\)\n- ✅ Recursive dependency tree resolution\n- ✅ Reverse dependency tracking\n- ✅ Component settings management\n- ✅ Profile tagging and filtering\n\nAuto-Sync System:\n- ✅ secubox-sync-registry CLI for catalog synchronization\n- ✅ Auto-populate from catalog.json\n- ✅ Plugin catalog directory scanning\n- ✅ Installed package detection\n- ✅ Automatic state initialization\n\nRPC Backend \\(luci.secubox\\):\n- ✅ 6 state management RPC methods\n- ✅ 5 component registry RPC methods\n- ✅ Bulk operations support\n- ✅ State validation endpoints\n\n## Frontend Features \\(luci-app-secubox-admin v1.0.0-16\\)\n\nUI Components:\n- ✅ state-utils.js: 20+ utility functions, state config, transition validation\n- ✅ StateIndicator.js: 5 rendering modes \\(badge, compact, pill, dot, statistics\\)\n- ✅ StateTimeline.js: 4 visualization modes \\(vertical, horizontal, compact, transition diagram\\)\n- ✅ state-management.css: 600+ lines with animations, responsive design, accessibility\n\nAdmin Control Center Dashboard:\n- ✅ System overview panel with health metrics\n- ✅ Component state summary with statistics\n- ✅ Recent state transitions timeline\n- ✅ Alerts panel for warnings and errors\n- ✅ Quick actions panel\n- ✅ Real-time updates \\(5-second polling\\)\n- ✅ Metric cards with hover effects\n- ✅ State distribution by category\n\nAPI Integration \\(api.js\\):\n- ✅ 11 RPC method declarations\n- ✅ Enhanced methods: getComponentWithState\\(\\), getAllComponentsWithStates\\(\\)\n- ✅ Bulk operations: bulkSetComponentState\\(\\)\n- ✅ State statistics: getStateStatistics\\(\\)\n- ✅ Retry logic with exponential backoff\n- ✅ Promise-based async operations\n\n## Documentation\n\nComprehensive Documentation:\n- ✅ API-REFERENCE.md \\(1,200+ lines\\): Complete API docs for RPC, CLI, JS\n- ✅ EXAMPLES.md \\(800+ lines\\): 30+ usage examples, shell scripts, integration patterns\n- ✅ State definitions table \\(15 states\\)\n- ✅ State transition matrix\n- ✅ Component metadata schemas\n- ✅ Error codes reference\n- ✅ Testing examples\n\n## State Definitions\n\n15 States Across 4 Categories:\n- Persistent: available, installed, active, disabled, frozen\n- Transient: installing, configuring, activating, starting, stopping, uninstalling\n- Runtime: running, stopped\n- Error: error \\(with subtypes\\)\n\nState Transition Flow:\navailable → installing → installed → configuring → configured →\nactivating → active → starting → running → stopping → stopped\n\n## Technical Details\n\nFiles Created \\(10 backend + 8 frontend\\):\nBackend:\n- /usr/sbin/secubox-state \\(12KB, 8 commands\\)\n- /usr/sbin/secubox-component \\(12KB, 7 commands\\)\n- /usr/sbin/secubox-sync-registry \\(8.4KB\\)\n- /usr/share/secubox/state-machine.sh \\(5.2KB\\)\n- /var/lib/secubox/state-db.json \\(schema\\)\n- /var/lib/secubox/component-registry.json \\(schema\\)\n\nFrontend:\n- resources/secubox-admin/state-utils.js \\(~400 lines\\)\n- resources/secubox-admin/components/StateIndicator.js \\(~350 lines\\)\n- resources/secubox-admin/components/StateTimeline.js \\(~450 lines\\)\n- resources/secubox-admin/state-management.css \\(~600 lines\\)\n- resources/view/secubox-admin/control-center.js \\(~550 lines\\)\n- resources/secubox-admin/api.js \\(+145 lines\\)\n\nDocumentation:\n- docs/admin-control-center/API-REFERENCE.md \\(1,200+ lines\\)\n- docs/admin-control-center/EXAMPLES.md \\(800+ lines\\)\n\nFiles Modified \\(3\\):\n- package/secubox/secubox-core/Makefile \\(v0.8.0 → v0.9.0-1\\)\n- package/secubox/luci-app-secubox-admin/Makefile \\(release 15 → 16\\)\n- package/secubox/secubox-core/root/usr/libexec/rpcd/luci.secubox \\(+157 lines\\)\n\n## Installation & Migration\n\nMakefile Updates:\n- Added 3 new CLI tools to install section\n- Added state-machine.sh to scripts\n- Updated package description\n- Enhanced postinst to initialize databases\n- Auto-sync registry on first install\n\nPostinst Features:\n- Automatic state-db.json initialization\n- Automatic component-registry.json initialization\n- Catalog sync on install\n- Version announcement with new features\n\n## Performance & Security\n\nPerformance:\n- File locking \\(flock\\) for atomic state transitions\n- State history limited to 100 entries per component\n- RPC retry logic with exponential backoff\n- Bulk operations use Promise.all for parallel execution\n- Component list caching \\(30 seconds\\)\n\nSecurity:\n- Frozen state prevents unauthorized modifications\n- All state changes logged with timestamp and reason\n- System-critical components have additional safeguards\n- Proper authentication required for state transitions\n\n## Testing & Validation\n\nFeatures:\n- State transition validation\n- Component dependency resolution\n- Circular dependency detection\n- State consistency checker\n- Integration test scripts included in docs\n\n## Breaking Changes\n\nNone - Backward Compatible:\n- Existing RPC methods remain functional\n- State-aware methods are additive\n- Components without state default to ''available''\n- Migration is automatic on install\n\n## Statistics\n\nTotal Implementation:\n- Lines of Code: ~4,000\n - Backend: ~1,800 \\(Bash + JSON\\)\n - Frontend: ~2,200 \\(JavaScript + CSS\\)\n - Documentation: ~2,000 \\(Markdown\\)\n- Functions/Commands: 40+\n- RPC Methods: 11\n- CLI Commands: 22\n- UI Components: 5\n- Documentation Pages: 2\n\n## Next Phase\n\nRemaining from Plan:\n- Phase 4: System Hub integration\n- Phase 5: Migration script \\(secubox-migrate-state\\)\n- Phase 6: Additional documentation \\(ARCHITECTURE.md, STATE-MANAGEMENT.md, etc.\\)\n- Phase 7: Additional UI views \\(components.js, state-manager.js, debug-panel.js\\)\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(for file in package/secubox/secubox-core/root/usr/sbin/*)", - "Bash(do if head -n1 \"$file\")", - "Bash(then echo \"$file\")", - "Bash(for file in secubox secubox-profile secubox-recovery secubox-verify secubox-core secubox-diagnostics secubox-catalog-sync secubox-appstore secubox-sync-registry)", - "Bash(do head -n1 \"$file\")", - "Bash(head:*)", - "WebFetch(domain:www.netify.ai)", - "WebFetch(domain:forum.openwrt.org)", - "Bash(for f in *.js)", - "Bash(do echo \"Checking $f...\")", - "Bash(for f in view/secubox-netifyd/*.js secubox-netifyd/*.js)", - "Bash(do node -c \"$f\")", - "Bash(bash -n:*)", - "Bash(./scripts/feeds uninstall:*)", - "Bash(aarch64-openwrt-linux-musl-g++:*)", - "Bash(opkg-cl info:*)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat: Netifyd Integration & Build System Improvements \\(v0.9.1\\)\n\nMajor updates:\n- Replace luci-app-netifyd-dashboard with enhanced luci-app-secubox-netifyd\n- Add netifyd 5.2.1 package with GCC 13.3/C++17 build fixes\n- Fix nd-risks.cpp compilation errors via inline static maps patch\n- Enhance local-build.sh with improved package building workflow\n- Update secubox-core scripts version to v0.9.1\n\nNew Features:\n- Complete netifyd dashboard with flows, devices, applications, and settings\n- Local data collection with netifyd-collector\n- Automated cron-based data aggregation\n- RPCd integration for real-time statistics\n\nBuild Fixes:\n- Patch 001: Fix C++17 inline static maps in nd-risks.hpp and nd-protos.hpp\n- Patch 003: Skip ndpi tests to resolve roaring_v2 dependency issues\n- Add libatomic dependency\n- Include libnetifyd shared libraries in package\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(netifyd:*)", - "Bash(ubus call:*)", - "Bash(ss:*)", - "Bash(git cherry-pick:*)", - "Bash(for file in overview.js decisions.js alerts.js waf.js metrics.js)", - "Bash(do scp /home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/$file root@192.168.8.191:/www/luci-static/resources/view/crowdsec-dashboard/ done)", - "Bash(Last: Xs ago\" in header\n- Updates every second\n- Visual feedback that polling is working\n- Easy to spot stalled/broken polling\n\nError Handling:\n- Try/catch around all poll callbacks\n- Errors logged to debug panel and console\n- Error counting for diagnostics\n- Polling continues even after errors\n\nCode Improvements:\n- Proper container creation order\n- Better error handling in load\\(\\) and polling\n- Debug logging throughout lifecycle\n- Performance metrics tracking\n\nDocumentation:\n- Complete analysis in REFRESH-DEBUG.md\n- Troubleshooting guide\n- Debug mode usage instructions\n- Performance considerations\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(ar r:*)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfix: Add missing API utility functions and fix data structure handling \\(v0.6.0-r9\\)\n\n- Add parseScenario\\(\\) to format scenario names\n- Add getCountryFlag\\(\\) to display country flag emojis\n- Add formatRelativeTime\\(\\) for relative timestamps\n- Fix decisions data flattening in handleUnban, handleBulkUnban, submitBan, and polling\n- Fix getDashboardData to properly flatten alerts->decisions structure\n- Fix context error in overview renderDecisionsTable \\(this vs self\\)\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfix: Sanitize malformed JSON from cscli metrics \\(v0.6.0-r10\\)\n\n- cscli metrics sometimes outputs empty string keys \\(\"\": {...}\\)\n- This causes RPC parsing errors in LuCI\n- Added sed filter to replace empty keys with \"unknown\"\n- Fixes \"No related RPC reply\" error in metrics view\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 \nEOF\n\\)\")", - "Bash(for f in luci-app-secubox/htdocs/luci-static/resources/view/secubox/*.js)", - "Bash(do scp \"$f\" root@192.168.8.191:/www/luci-static/resources/view/secubox/)", - "Bash(node:*)", - "Bash(awk:*)", - "Bash(for f in luci-app-secubox/htdocs/luci-static/resources/view/secubox/wizard.js luci-app-secubox/htdocs/luci-static/resources/secubox/api.js)", - "Bash(for f in /home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/*.js)", - "Bash(do scp \"$f\" root@192.168.8.191:/www/luci-static/resources/view/client-guardian/)", - "Bash(for f in dashboard.js health.js logs.js settings.js)", - "Bash(root@192.168.8.191:/www/luci-static/resources/view/secubox-admin/)", - "Bash(root@192.168.8.191:/usr/libexec/rpcd/luci.secubox)", - "Bash(root@192.168.8.191:/www/luci-static/resources/secubox-admin/)", - "Bash(root@192.168.8.191:/www/luci-static/resources/system-hub/)", - "Bash(root@192.168.8.191:/usr/libexec/rpcd/luci.system-hub)", - "Bash(root@192.168.8.191:/usr/sbin/secubox-appstore)", - "Bash(for f in zones.js overview.js clients.js)", - "Bash(do scp /home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/view/client-guardian/$f root@192.168.8.191:/www/luci-static/resources/view/client-guardian/)", - "Bash(for f in clients.js overview.js)", - "Bash(for f in htdocs/luci-static/resources/view/client-guardian/settings.js htdocs/luci-static/resources/client-guardian/api.js root/usr/libexec/rpcd/luci.client-guardian root/etc/config/client-guardian)", - "Bash(do scp \"$f\" root@192.168.8.191:/$f#root/)", - "Bash(ssh root@192.168.255.1:*)", - "Bash(SSH=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\")", - "Bash($SSH root@192.168.255.1 \"ubus list | grep secubox; ls -la /usr/libexec/rpcd/luci.secubox* 2>/dev/null; ls -la /www/luci-static/resources/view/secubox/ 2>/dev/null\")", - "Bash($SSH root@192.168.255.1 \"cat /usr/share/luci/menu.d/luci-app-secubox.json 2>/dev/null || echo ''NOT FOUND''\")", - "Bash($SSH root@192.168.255.1 \"ubus call luci.secubox getModules ''{}'' 2>&1 | head -50\")", - "Bash($SSH root@192.168.255.1 \"ubus -v list luci.secubox\")", - "Bash($SSH root@192.168.255.1 \"echo ''{\"\"method\"\":\"\"getModules\"\"}'' | /usr/libexec/rpcd/luci.secubox call getModules 2>&1 | head -30\")", - "Bash($SSH root@192.168.255.1 \"sed -n ''90,100p'' /usr/sbin/secubox-appstore\")", - "Bash(SCP=\"scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\":*)", - "Bash(__NEW_LINE__ $SCP /home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/secubox-core/root/usr/sbin/secubox-appstore root@192.168.255.1:/usr/sbin/secubox-appstore)", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/sbin/secubox-appstore && /etc/init.d/rpcd restart\")", - "Bash(SCP=\"scp -O -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\")", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/sbin/secubox-appstore && /etc/init.d/rpcd restart && echo ''✅ Fixed''\")", - "Bash($SSH root@192.168.255.1 \"ubus call luci.secubox getModules ''{}'' 2>&1 | head -30\")", - "Bash($SSH root@192.168.255.1 \"grep -A50 ''getModules'' /usr/libexec/rpcd/luci.secubox | head -60\")", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/sbin/secubox-appstore && /etc/init.d/rpcd restart && ubus call luci.secubox getModules ''{}'' 2>&1 | head -50\")", - "Bash($SSH root@192.168.255.1 \"sleep 2 && ubus call luci.secubox getModules ''{}'' 2>&1 | head -80\")", - "Bash($SSH root@192.168.255.1 \"cat /usr/share/secubox/plugins/catalog/crowdsec-dashboard.json 2>/dev/null | head -30\")", - "Bash($SSH root@192.168.255.1 \"grep -E ''^\\(luci-app-|secubox-\\)'' /tmp/secubox-installed-cache 2>/dev/null | head -20\")", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/sbin/secubox-appstore && rm -f /tmp/secubox-installed-cache && /etc/init.d/rpcd restart\")", - "Bash($SSH root@192.168.255.1 \"sleep 2 && ubus call luci.secubox getModules ''{}'' 2>&1\")", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/sbin/secubox-appstore && rm -f /tmp/secubox-installed-cache && /etc/init.d/rpcd restart && sleep 2 && ubus call luci.secubox getModules ''{}'' 2>&1 | grep -A12 ''crowdsec-dashboard''\")", - "Bash($SSH root@192.168.255.1 \"ubus call luci.secubox getModules ''{}'' 2>&1 | grep -A12 ''netifyd''\")", - "Bash($SSH root@192.168.255.1 \"/etc/init.d/netifyd status; ls /etc/rc.d/S*netifyd 2>/dev/null\")", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/sbin/secubox-appstore && rm -f /tmp/secubox-installed-cache && /etc/init.d/rpcd restart && sleep 2 && ubus call luci.secubox getModules ''{}'' 2>&1 | grep -A12 -E ''\\(netifyd|crowdsec-dashboard\\)''\")", - "Bash($SSH root@192.168.255.1 \"cat /etc/config/secubox 2>/dev/null | head -50\")", - "Bash($SSH root@192.168.255.1 \"cat /etc/config/firewall | grep -A5 ''luci\\\\|secubox'' | head -30\")", - "Bash($SSH root@192.168.255.1 \"/etc/init.d/rpcd restart && sleep 2 && ubus -v list luci.secubox | grep wan\")", - "Bash(__NEW_LINE__ $SCP /home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/secubox-core/root/usr/libexec/rpcd/luci.secubox root@192.168.255.1:/usr/libexec/rpcd/luci.secubox)", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/libexec/rpcd/luci.secubox && /etc/init.d/rpcd restart && sleep 2 && ubus call luci.secubox get_wan_access ''{}''\")", - "Bash($SSH root@192.168.255.1 \"/usr/sbin/secubox-wan-access status\")", - "Bash($SSH root@192.168.255.1 \"uci show firewall | grep secubox_wan\")", - "Bash($SSH root@192.168.255.1 \"nft list ruleset 2>/dev/null | grep -A2 ''secubox\\\\|dport 443'' | head -20\")", - "Bash($SSH root@192.168.255.1 \"/etc/init.d/firewall restart && sleep 2 && fw4 print 2>/dev/null | grep -i ''secubox\\\\|443'' | head -10\")", - "Bash(SSH=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10\")", - "Bash($SSH root@192.168.255.1 \"echo ''connected''\")", - "Bash($SSH root@192.168.255.1 \"uci show firewall | grep -E ''=zone$|\\\\.name=''\")", - "Bash($SSH root@192.168.255.1 \"uci show firewall | grep -E ''network=|\\\\.input=|\\\\.output=|\\\\.forward=''\")", - "Bash(__NEW_LINE__ $SCP /home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/secubox-core/root/usr/sbin/secubox-wan-access root@192.168.255.1:/usr/sbin/secubox-wan-access)", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/sbin/secubox-wan-access && /usr/sbin/secubox-wan-access apply && /etc/init.d/firewall restart && sleep 2 && /usr/sbin/secubox-wan-access status\")", - "Bash($SSH root@192.168.255.1 \"\n# Remove old invalid rule\nuci delete firewall.@rule[0] 2>/dev/null\n\n# Run apply which will create new rules with correct src\n/usr/sbin/secubox-wan-access apply\n\n# Show the new rule\nuci show firewall | grep secubox\n\n# Restart firewall\n/etc/init.d/firewall restart\n\")", - "Bash(SSH=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=15\")", - "Bash(SSH=\"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=30\")", - "Bash($SSH root@192.168.255.1 \"echo connected && uci show firewall | grep secubox\")", - "Bash($SSH root@192.168.255.1 \"/etc/init.d/firewall restart && sleep 3 && /usr/sbin/secubox-wan-access status\")", - "Bash($SSH root@192.168.255.1 \"fw4 print 2>&1 | grep -i ''secubox\\\\|443'' | head -10\")", - "Bash($SSH root@192.168.255.1 \"fw4 print 2>&1 | grep -E ''secubox|tcp dport 443'' | head -10\")", - "Bash($SSH root@192.168.255.1 \"cat /usr/share/rpcd/acl.d/luci-app-secubox-admin.json 2>/dev/null || cat /usr/share/rpcd/acl.d/luci-mod-secubox.json 2>/dev/null | head -30\")", - "Bash($SSH root@192.168.255.1 \"ls /usr/share/rpcd/acl.d/ | grep -E ''secubox|admin''\")", - "Bash($SSH root@192.168.255.1 \"cat /usr/share/rpcd/acl.d/luci-app-secubox-admin.json\")", - "Bash($SSH root@192.168.255.1 'cat > /usr/share/rpcd/acl.d/luci-app-secubox-admin.json << ''''EOF''''\n{\n\t\"\"luci-app-secubox-admin\"\": {\n\t\t\"\"description\"\": \"\"SecuBox Admin Control Center\"\",\n\t\t\"\"read\"\": {\n\t\t\t\"\"ubus\"\": {\n\t\t\t\t\"\"luci.secubox\"\": [\n\t\t\t\t\t\"\"get_appstore_apps\"\",\n\t\t\t\t\t\"\"get_appstore_app\"\",\n\t\t\t\t\t\"\"getModules\"\",\n\t\t\t\t\t\"\"getModuleInfo\"\",\n\t\t\t\t\t\"\"get_dashboard_data\"\",\n\t\t\t\t\t\"\"get_system_health\"\",\n\t\t\t\t\t\"\"get_alerts\"\",\n\t\t\t\t\t\"\"getLogs\"\",\n\t\t\t\t\t\"\"listProfiles\"\",\n\t\t\t\t\t\"\"get_catalog_sources\"\",\n\t\t\t\t\t\"\"check_updates\"\",\n\t\t\t\t\t\"\"get_app_versions\"\",\n\t\t\t\t\t\"\"get_changelog\"\",\n\t\t\t\t\t\"\"get_widget_data\"\",\n\t\t\t\t\t\"\"get_wan_access\"\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"\"uci\"\": [\n\t\t\t\t\"\"secubox\"\",\n\t\t\t\t\"\"secubox-appstore\"\",\n\t\t\t\t\"\"firewall\"\",\n\t\t\t\t\"\"*\"\"\n\t\t\t]\n\t\t},\n\t\t\"\"write\"\": {\n\t\t\t\"\"ubus\"\": {\n\t\t\t\t\"\"luci.secubox\"\": [\n\t\t\t\t\t\"\"install_appstore_app\"\",\n\t\t\t\t\t\"\"remove_appstore_app\"\",\n\t\t\t\t\t\"\"enable_module\"\",\n\t\t\t\t\t\"\"disable_module\"\",\n\t\t\t\t\t\"\"updateModule\"\",\n\t\t\t\t\t\"\"applyProfile\"\",\n\t\t\t\t\t\"\"set_catalog_source\"\",\n\t\t\t\t\t\"\"sync_catalog\"\",\n\t\t\t\t\t\"\"set_wan_access\"\",\n\t\t\t\t\t\"\"apply_wan_access\"\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"\"uci\"\": [\n\t\t\t\t\"\"secubox\"\",\n\t\t\t\t\"\"secubox-appstore\"\",\n\t\t\t\t\"\"firewall\"\",\n\t\t\t\t\"\"*\"\"\n\t\t\t]\n\t\t}\n\t}\n}\nEOF\n/etc/init.d/rpcd restart && echo \"\"ACL updated\"\"')", - "Bash($SSH root@192.168.255.1 \"ubus call luci.secubox apply_wan_access ''{}'' 2>&1\")", - "Bash($SSH root@192.168.255.1 \"/usr/sbin/secubox-wan-access apply 2>&1\")", - "Bash($SSH root@192.168.255.1 \"ubus call luci.secubox apply_wan_access ''{}''\")", - "Bash($SSH root@192.168.255.1 \"chmod 755 /usr/libexec/rpcd/luci.secubox && /etc/init.d/rpcd restart && sleep 2 && ubus call luci.secubox apply_wan_access ''{}''\")", - "Bash($SSH root@192.168.255.1 \"uci show network | grep -E ''=interface|\\\\.proto=''\")", - "Bash($SSH root@192.168.255.1 \"uci show firewall | grep -E ''zone.*name|=forwarding''\")", - "Bash(for:*)", - "Bash(do sed -i \"s/''require secubox-theme\\\\/theme as Theme'';//g\" \"$f\")", - "Bash(do sleep 5)", - "Bash(break)", - "Bash(sshpass:*)", - "Bash(brew install:*)", - "Bash(pip3 install:*)", - "Bash(/usr/bin/python3 -m pip install:*)", - "Bash(# Try with simple password pipe using printf\n\\(echo \"\"2Klslm_jv\"\"\\) | timeout 10 ssh -o StrictHostKeyChecking=no -o PreferredAuthentications=password -o NumberOfPasswordPrompts=1 root@192.168.255.1 \"\"echo OK\"\" 2>&1 || echo \"\"SSH failed\"\")", - "Bash(expect:*)", - "Bash(export SSH_ASKPASS=/tmp/ssh_pass.sh export SSH_ASKPASS_REQUIRE=force export DISPLAY=:0)", - "WebFetch(domain:download.netify.ai)", - "Bash(export SSH_ASKPASS_REQUIRE=force)", - "Bash(export SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass)", - "WebFetch(domain:192.168.255.1)", - "WebFetch(domain:api.github.com)", - "Bash(zstd:*)", - "Bash(git tag -a v0.11.0 -m \"$\\(cat <<''EOF''\nSecuBox v0.11.0 - nDPId Integration & Dashboard Enhancements\n\nNew Features:\n- nDPId package: Lightweight DPI alternative to netifyd with bundled libndpi 5.x\n- luci-app-ndpid: LuCI interface for nDPId management\n- WireGuard Dashboard v0.5.0: Real-time updates, traffic charts, peer wizard\n\nBug Fixes:\n- WireGuard: QR code generation, peer status detection, traffic stats accuracy\n- Netdata Dashboard: Service status display, settings UI improvements\n- Build system: Package name mapping, mochabin as default architecture\nEOF\n\\)\")", - "Bash(constructor\" error.\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "Bash(secubox-tools/sync-openwrt-packages.sh:*)", - "Bash(./quick-deploy.sh luci-app-ndpid)", - "Bash(./quick-deploy.sh:*)", - "Bash(sshpass -p 'alpds_vv' scp:*)", - "Bash(export DISPLAY=:0)", - "Bash(setsid -w scp:*)", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\ncp /tmp/luci.ndpid /usr/libexec/rpcd/luci.ndpid\nchmod +x /usr/libexec/rpcd/luci.ndpid\n\ncp /tmp/ndpid-compat /usr/bin/ndpid-compat\nchmod +x /usr/bin/ndpid-compat\n\ncp /tmp/api.js /www/luci-static/resources/ndpid/api.js\ncp /tmp/dashboard.css /www/luci-static/resources/ndpid/dashboard.css\ncp /tmp/dashboard.js /www/luci-static/resources/view/ndpid/dashboard.js\ncp /tmp/flows.js /www/luci-static/resources/view/ndpid/flows.js\n\n# Restart services\n/etc/init.d/rpcd restart\n/etc/init.d/ndpid-compat restart 2>/dev/null || true\n\necho \"\"Deployment complete\"\"\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Checking jq ===\"\"\nwhich jq 2>/dev/null || echo \"\"jq not installed\"\"\n\necho \"\"\"\"\necho \"\"=== Checking ndpid-compat status ===\"\"\n/etc/init.d/ndpid-compat status 2>/dev/null || ps | grep ndpid-compat | grep -v grep\n\necho \"\"\"\"\necho \"\"=== Checking cache files ===\"\"\nls -la /tmp/ndpid-*.json 2>/dev/null || echo \"\"No cache files yet\"\"\n\necho \"\"\"\"\necho \"\"=== Status.json content ===\"\"\ncat /var/run/netifyd/status.json 2>/dev/null | head -20\n\necho \"\"\"\"\necho \"\"=== RPCD methods ===\"\"\nubus list luci.ndpid\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Testing get_detailed_flows ===\"\"\nubus call luci.ndpid get_detailed_flows 2>&1 | head -30\n\necho \"\"\"\"\necho \"\"=== Testing get_categories ===\"\"\nubus call luci.ndpid get_categories 2>&1\n\necho \"\"\"\"\necho \"\"=== Testing get_top_applications ===\"\"\nubus call luci.ndpid get_top_applications 2>&1\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== ndpid-flows.json content ===\"\"\ncat /tmp/ndpid-flows.json\n\necho \"\"\"\"\necho \"\"=== ndpid-apps.json content ===\"\"\ncat /tmp/ndpid-apps.json\n\necho \"\"\"\"\necho \"\"=== FLOWS_CACHE path in RPCD ===\"\"\ngrep -E \"\"^FLOWS_CACHE|^APPS_CACHE\"\" /usr/libexec/rpcd/luci.ndpid\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\nsed -n \"\"/^get_detailed_flows/,/^}/p\"\" /usr/libexec/rpcd/luci.ndpid | head -40\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\ncp /tmp/luci.ndpid /usr/libexec/rpcd/luci.ndpid\nchmod +x /usr/libexec/rpcd/luci.ndpid\n/etc/init.d/rpcd restart\necho \"\"RPCD restarted\"\"\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Testing get_top_applications ===\"\"\nubus call luci.ndpid get_top_applications 2>&1\n\necho \"\"\"\"\necho \"\"=== Testing get_categories ===\"\"\nubus call luci.ndpid get_categories 2>&1\n\necho \"\"\"\"\necho \"\"=== Testing get_detailed_flows \\(first 3\\) ===\"\"\nubus call luci.ndpid get_detailed_flows 2>&1 | head -60\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Checking deployed files ===\"\"\nls -la /www/luci-static/resources/view/ndpid/\nls -la /www/luci-static/resources/ndpid/\n\necho \"\"\"\"\necho \"\"=== Check dashboard.js has getCategories ===\"\"\ngrep -c \"\"getCategories\\\\|getDetailedFlows\"\" /www/luci-static/resources/view/ndpid/dashboard.js /www/luci-static/resources/view/ndpid/flows.js /www/luci-static/resources/ndpid/api.js 2>/dev/null\n\necho \"\"\"\"\necho \"\"=== Check api.js has new methods ===\"\"\ngrep \"\"callDetailedFlows\\\\|callCategories\"\" /www/luci-static/resources/ndpid/api.js | head -5\n\necho \"\"\"\"\necho \"\"=== LuCI error log ===\"\"\nlogread | grep -i \"\"luci\\\\|error\\\\|ndpid\"\" | tail -20\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\n# Redeploy ndpid-compat from /tmp if still there\nif [ -f /tmp/ndpid-compat ]; then\n cp /tmp/ndpid-compat /usr/bin/ndpid-compat\n chmod +x /usr/bin/ndpid-compat\nfi\n\n# Restart ndpid-compat\nkillall ndpid-compat 2>/dev/null\nsleep 1\n/etc/init.d/ndpid-compat restart 2>/dev/null || /usr/bin/ndpid-compat -d\n\n# Clear LuCI cache\nrm -rf /tmp/luci-* 2>/dev/null\n/etc/init.d/rpcd restart\n\necho \"\"\"\"\necho \"\"=== Check ndpid-compat running ===\"\"\nps | grep ndpid-compat | grep -v grep\n\necho \"\"\"\"\necho \"\"=== Wait and check cache files ===\"\"\nsleep 3\nls -la /tmp/ndpid-*.json 2>/dev/null\n\necho \"\"\"\"\necho \"\"=== Test RPCD methods ===\"\"\nubus call luci.ndpid get_top_applications | head -20\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== api.js - checking getDetailedFlows method ===\"\"\ngrep -A2 \"\"getDetailedFlows:\"\" /www/luci-static/resources/ndpid/api.js\n\necho \"\"\"\"\necho \"\"=== dashboard.js - checking categories variable ===\"\"\ngrep \"\"var categories\"\" /www/luci-static/resources/view/ndpid/dashboard.js\n\necho \"\"\"\"\necho \"\"=== dashboard.js - checking load function ===\"\"\ngrep -A10 \"\"load: function\"\" /www/luci-static/resources/view/ndpid/dashboard.js | head -15\n\necho \"\"\"\"\necho \"\"=== flows.js - checking load function calls ===\"\"\ngrep -A10 \"\"load: function\"\" /www/luci-static/resources/view/ndpid/flows.js | head -15\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== get_dashboard ===\"\"\nubus call luci.ndpid get_dashboard 2>&1 | head -30\n\necho \"\"\"\"\necho \"\"=== get_interface_stats ===\"\"\nubus call luci.ndpid get_interface_stats 2>&1\n\necho \"\"\"\"\necho \"\"=== get_top_protocols ===\"\"\nubus call luci.ndpid get_top_protocols 2>&1\n\necho \"\"\"\"\necho \"\"=== get_realtime_flows ===\"\"\nubus call luci.ndpid get_realtime_flows 2>&1\n\necho \"\"\"\"\necho \"\"=== get_top_applications count ===\"\"\nubus call luci.ndpid get_top_applications 2>&1 | grep -c \"\"name\"\"\n\necho \"\"\"\"\necho \"\"=== get_detailed_flows count ===\"\"\nubus call luci.ndpid get_detailed_flows 2>&1 | grep -c \"\"src_ip\"\"\n\necho \"\"\"\"\necho \"\"=== get_categories ===\"\"\nubus call luci.ndpid get_categories 2>&1\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Check ACL file ===\"\"\ncat /usr/share/rpcd/acl.d/luci-app-ndpid.json 2>/dev/null || echo \"\"ACL file not found\"\"\n\necho \"\"\"\"\necho \"\"=== List ACL files ===\"\"\nls -la /usr/share/rpcd/acl.d/ | grep ndpid\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\n/etc/init.d/rpcd restart\nrm -rf /tmp/luci-*\necho \"\"ACL updated and RPCD restarted\"\"\ncat /usr/share/rpcd/acl.d/luci-app-ndpid.json\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\n# Test as if we are the web interface\necho \"\"=== Testing RPC via HTTP \\(simulating browser\\) ===\"\"\n\n# Get a session token first\nSESSION=$\\(curl -s -c - \"\"http://127.0.0.1/cgi-bin/luci/admin/status\"\" 2>/dev/null | grep -o \"\"sysauth_[^=]*=[^;]*\"\" | head -1\\)\necho \"\"Session: $SESSION\"\"\n\necho \"\"\"\"\necho \"\"=== Direct ubus call as root ===\"\"\nubus call luci.ndpid get_detailed_flows 2>&1 | head -30\n\necho \"\"\"\"\necho \"\"=== Check if the method is accessible ===\"\"\nubus -v list luci.ndpid 2>&1 | grep -E \"\"detailed|categories\"\"\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\n# Full restart of web services\necho \"\"Restarting services...\"\"\n/etc/init.d/rpcd restart\n/etc/init.d/uhttpd restart\n\n# Clear all LuCI caches\nrm -rf /tmp/luci-*\nrm -rf /tmp/luci-indexcache*\n\n# Verify ACL is loaded\necho \"\"\"\"\necho \"\"=== Checking ACL loaded ===\"\"\nubus call session list 2>/dev/null | head -20\n\necho \"\"\"\"\necho \"\"Services restarted. Please log out of LuCI and log back in.\"\"\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Check flows.js data access pattern ===\"\"\ngrep -A5 \"\"var flows\"\" /www/luci-static/resources/view/ndpid/flows.js | head -10\n\necho \"\"\"\"\necho \"\"=== Check what render receives ===\"\"\ngrep -B2 -A3 \"\"render: function\"\" /www/luci-static/resources/view/ndpid/flows.js | head -10\n\necho \"\"\"\"\necho \"\"=== Check flows length check ===\"\"\ngrep \"\"flows.length\"\" /www/luci-static/resources/view/ndpid/flows.js\n\necho \"\"\"\"\necho \"\"=== Check actual data structure from API ===\"\"\nubus call luci.ndpid get_detailed_flows 2>&1 | jq \"\"keys\"\"\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Check flows.js render function ===\"\"\ngrep -n \"\"var flows = \"\" /www/luci-static/resources/view/ndpid/flows.js\n\necho \"\"\"\"\necho \"\"=== Check flows.length usage ===\"\"\ngrep -n \"\"flows.length\"\" /www/luci-static/resources/view/ndpid/flows.js\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Service status ===\"\"\nps | grep -E \"\"ndpid|nDPId\"\" | grep -v grep\n\necho \"\"\"\"\necho \"\"=== Distributor socket ===\"\"\nls -la /var/run/ndpid/ 2>/dev/null || echo \"\"No socket directory\"\"\n\necho \"\"\"\"\necho \"\"=== Restart ndpid-compat ===\"\"\nkillall ndpid-compat 2>/dev/null\nsleep 2\n/usr/bin/ndpid-compat -d\nsleep 3\n\necho \"\"\"\"\necho \"\"=== Check running ===\"\"\nps | grep ndpid-compat | grep -v grep\n\necho \"\"\"\"\necho \"\"=== Cache files ===\"\"\nls -la /tmp/ndpid-*.json 2>/dev/null\n\necho \"\"\"\"\necho \"\"=== Test API ===\"\"\nubus call luci.ndpid get_realtime_flows\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Kill all old processes ===\"\"\nkillall ndpid-compat 2>/dev/null\nkillall nDPId 2>/dev/null \nkillall ndpisrvd 2>/dev/null\nsleep 2\n\necho \"\"\"\"\necho \"\"=== Check nDPId init script ===\"\"\nls -la /etc/init.d/ndpid* 2>/dev/null\n\necho \"\"\"\"\necho \"\"=== Check nDPId config ===\"\"\nuci show ndpid 2>/dev/null | head -20\n\necho \"\"\"\"\necho \"\"=== Start nDPId service ===\"\"\n/etc/init.d/ndpid start 2>&1 || /etc/init.d/nDPId start 2>&1\n\nsleep 3\n\necho \"\"\"\"\necho \"\"=== Check processes ===\"\"\nps | grep -E \"\"ndpi|nDPI\"\" | grep -v grep\n\necho \"\"\"\"\necho \"\"=== Start ndpid-compat ===\"\"\n/usr/bin/ndpid-compat -d\nsleep 3\n\necho \"\"\"\"\necho \"\"=== Final check ===\"\"\nps | grep -E \"\"ndpi|nDPI\"\" | grep -v grep\nls -la /tmp/ndpid-*.json 2>/dev/null\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Find nDPId binary ===\"\"\nwhich nDPId 2>/dev/null || find /usr -name \"\"nDPId\"\" -o -name \"\"ndpid\"\" 2>/dev/null | head -5\n\necho \"\"\"\"\necho \"\"=== Init script content ===\"\"\ncat /etc/init.d/ndpid | head -60\n\necho \"\"\"\"\necho \"\"=== Try starting with verbose ===\"\"\n/etc/init.d/ndpid restart 2>&1\nsleep 2\n\necho \"\"\"\"\necho \"\"=== Check all processes ===\"\"\nps | grep -iE \"\"ndpi\"\" | grep -v grep\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Full init script start_service ===\"\"\nsed -n \"\"/^start_service/,/^}/p\"\" /etc/init.d/ndpid\n\necho \"\"\"\"\necho \"\"=== Try starting ndpid manually ===\"\"\n/usr/sbin/ndpid --help 2>&1 | head -20\n\necho \"\"\"\"\necho \"\"=== Check config file ===\"\"\ncat /etc/ndpid.conf 2>/dev/null\n\necho \"\"\"\"\necho \"\"=== Start ndpid on br-lan ===\"\"\n/usr/sbin/ndpid -i br-lan -c /var/run/ndpid/collector.sock -u nobody -g nogroup &\nsleep 3\n\necho \"\"\"\"\necho \"\"=== Check if ndpid running ===\"\"\nps | grep -E \"\"ndpid|nDPId\"\" | grep -v grep | grep -v compat\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Wait for flows ===\"\"\nsleep 5\n\necho \"\"=== Check cache files ===\"\"\nls -la /tmp/ndpid-*.json\n\necho \"\"\"\"\necho \"\"=== Apps content ===\"\"\ncat /tmp/ndpid-apps.json\n\necho \"\"\"\"\necho \"\"=== Flows count ===\"\"\ncat /tmp/ndpid-flows.json | jq length 2>/dev/null || wc -c /tmp/ndpid-flows.json\n\necho \"\"\"\"\necho \"\"=== Test API ===\"\"\nubus call luci.ndpid get_realtime_flows\n\necho \"\"\"\"\necho \"\"=== Top apps ===\"\"\nubus call luci.ndpid get_top_applications | head -30\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Check why nDPId stopped ===\"\"\nlogread | grep -i ndpid | tail -20\n\necho \"\"\"\"\necho \"\"=== Check procd status ===\"\"\nubus call service list '{\"name\":\"ndpid\"}' 2>/dev/null | head -30\n\necho \"\"\"\"\necho \"\"=== Is nDPId running? ===\"\"\nps | grep -E \"\"/usr/sbin/ndpid\"\" | grep -v grep\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Available interfaces ===\"\"\nip link show | grep \"\"^[0-9]\"\" | cut -d: -f2\n\necho \"\"\"\"\necho \"\"=== Current config ===\"\"\nuci get ndpid.main.interface\n\necho \"\"\"\"\necho \"\"=== Fix config - only br-lan ===\"\"\nuci delete ndpid.main.interface\nuci add_list ndpid.main.interface=\"\"br-lan\"\"\nuci commit ndpid\n\necho \"\"\"\"\necho \"\"=== New config ===\"\"\nuci get ndpid.main.interface\n\necho \"\"\"\"\necho \"\"=== Restart nDPId properly ===\"\"\nkillall ndpid 2>/dev/null\nsleep 1\n/etc/init.d/ndpid restart\nsleep 3\n\necho \"\"\"\"\necho \"\"=== Check running ===\"\"\nps | grep \"\"/usr/sbin/ndpid\"\" | grep -v grep\n\necho \"\"\"\"\necho \"\"=== Check procd ===\"\"\nubus call service list ''''{\"\"name\"\":\"\"ndpid\"\"}'''' 2>/dev/null | head -20\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Restart ndpid-compat ===\"\"\nkillall ndpid-compat 2>/dev/null\nsleep 1\n/etc/init.d/ndpid-compat restart 2>/dev/null || /usr/bin/ndpid-compat -d\nsleep 5\n\necho \"\"\"\"\necho \"\"=== Check all services ===\"\"\nps | grep -E \"\"ndpid|ndpisrvd\"\" | grep -v grep\n\necho \"\"\"\"\necho \"\"=== Check data ===\"\"\nls -la /tmp/ndpid-*.json\ncat /tmp/ndpid-apps.json\n\necho \"\"\"\"\necho \"\"=== API test ===\"\"\nubus call luci.ndpid get_detailed_flows 2>&1 | head -30\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Network interfaces from UCI ===\"\"\nuci show network | grep \"\"interface\\\\|device\"\" | head -30\n\necho \"\"\"\"\necho \"\"=== Physical interfaces ===\"\"\nls -la /sys/class/net/ | grep -v \"\"^total\"\" | awk \"\"{print \\\\$NF}\"\" | xargs -I{} basename {}\n\necho \"\"\"\"\necho \"\"=== Bridge members ===\"\"\nbrctl show 2>/dev/null || ip link show type bridge_slave 2>/dev/null\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Check flows.js render function ===\"\"\ngrep -n \"\"render: function\"\" /www/luci-static/resources/view/ndpid/flows.js\ngrep -n \"\"var flows = \"\" /www/luci-static/resources/view/ndpid/flows.js\ngrep -n \"\"Array.isArray\"\" /www/luci-static/resources/view/ndpid/flows.js\n\necho \"\"\"\"\necho \"\"=== Show actual render section \\(lines 185-200\\) ===\"\"\nsed -n \"\"185,200p\"\" /www/luci-static/resources/view/ndpid/flows.js\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Current init script start_service ===\"\"\nsed -n \"\"/^start_service/,/^[a-z_]*\\(\\).*{$/p\"\" /etc/init.d/ndpid | head -50\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\n# Backup original\ncp /etc/init.d/ndpid /etc/init.d/ndpid.bak\n\n# Update start_service to validate interfaces\ncat > /tmp/ndpid_start_service.patch << ''''PATCH''''\nstart_service\\(\\) {\n\tlocal enabled interfaces\n\n\tconfig_load ndpid\n\tconfig_get_bool enabled main enabled 0\n\n\t[ \"\"$enabled\"\" -eq 0 ] && {\n\t\tlogger -t ndpid \"\"Service disabled in config\"\"\n\t\treturn 0\n\t}\n\n\t# Create runtime directories\n\tmkdir -p \"\"$RUNTIME_DIR\"\"\n\tmkdir -p \"\"$\\(dirname \"\"$COMPAT_STATUS\"\"\\)\"\"\n\tchown nobody:nogroup \"\"$RUNTIME_DIR\"\"\n\n\t# Generate native config from UCI\n\tgenerate_config\n\n\t# Get interfaces and validate they exist\n\tconfig_get interfaces main interface \"\"br-lan\"\"\n\n\t# Build interface arguments - only include existing interfaces\n\tlocal iface_args=\"\"\"\"\n\tlocal valid_ifaces=\"\"\"\"\n\tfor iface in $interfaces; do\n\t\tif [ -d \"\"/sys/class/net/$iface\"\" ]; then\n\t\t\tiface_args=\"\"$iface_args -i $iface\"\"\n\t\t\tvalid_ifaces=\"\"$valid_ifaces $iface\"\"\n\t\telse\n\t\t\tlogger -t ndpid \"\"WARNING: Interface $iface does not exist, skipping\"\"\n\t\tfi\n\tdone\n\n\t# Check if we have at least one valid interface\n\tif [ -z \"\"$iface_args\"\" ]; then\n\t\tlogger -t ndpid \"\"ERROR: No valid interfaces found, falling back to br-lan\"\"\n\t\tif [ -d \"\"/sys/class/net/br-lan\"\" ]; then\n\t\t\tiface_args=\"\"-i br-lan\"\"\n\t\t\tvalid_ifaces=\"\"br-lan\"\"\n\t\telse\n\t\t\tlogger -t ndpid \"\"ERROR: br-lan not found either, cannot start\"\"\n\t\t\treturn 1\n\t\tfi\n\tfi\n\n\t# Get collector socket\n\tlocal collector_socket\n\tconfig_get collector_socket main collector_socket /var/run/ndpid/collector.sock\n\n\tlogger -t ndpid \"\"Starting nDPId on interfaces:$valid_ifaces\"\"\n\n\tprocd_open_instance ndpid\n\tprocd_set_param command \"\"$PROG\"\" -c \"\"$collector_socket\"\" $iface_args\n\tprocd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}\n\tprocd_set_param stdout 1\n\tprocd_set_param stderr 1\n\tprocd_set_param pidfile /var/run/ndpid.pid\n\tprocd_close_instance\n}\nPATCH\n\n# Apply the patch by replacing start_service function\nsed -i \"\"/^start_service\\(\\)/,/^stop_service\\(\\)/{ /^start_service\\(\\)/r /tmp/ndpid_start_service.patch\n/^start_service\\(\\)/,/^stop_service\\(\\)/{/^stop_service\\(\\)/!d}\n}\"\" /etc/init.d/ndpid\n\n# Actually lets do it cleaner - just replace the whole function\nhead -n $\\(grep -n \"\"^start_service\\(\\)\"\" /etc/init.d/ndpid.bak | cut -d: -f1 | head -1\\) /etc/init.d/ndpid.bak | head -n -1 > /tmp/ndpid_new\ncat /tmp/ndpid_start_service.patch >> /tmp/ndpid_new\ntail -n +$\\(grep -n \"\"^stop_service\\(\\)\"\" /etc/init.d/ndpid.bak | cut -d: -f1 | head -1\\) /etc/init.d/ndpid.bak >> /tmp/ndpid_new\ncp /tmp/ndpid_new /etc/init.d/ndpid\nchmod +x /etc/init.d/ndpid\n\necho \"\"=== Verify new start_service ===\"\"\nsed -n \"\"/^start_service/,/^stop_service/p\"\" /etc/init.d/ndpid | head -40\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\nchmod +x /usr/libexec/rpcd/luci.ndpid\n/etc/init.d/rpcd restart\n\necho \"\"=== Test interface scanning ===\"\"\nubus call luci.ndpid get_interfaces\n\necho \"\"\"\"\necho \"\"=== Restart nDPId ===\"\"\n/etc/init.d/ndpid restart\nsleep 2\nps | grep \"\"/usr/sbin/ndpid\"\" | grep -v grep\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Restart RPCD ===\"\"\n/etc/init.d/rpcd restart\nsleep 2\n\necho \"\"\"\"\necho \"\"=== Test interface scanning ===\"\"\nubus call luci.ndpid get_interfaces 2>&1\n\necho \"\"\"\"\necho \"\"=== Check nDPId status ===\"\"\nps | grep ndpid | grep -v grep | head -5\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== Check for syntax errors ===\"\"\nsh -n /usr/libexec/rpcd/luci.ndpid 2>&1\n\necho \"\"\"\"\necho \"\"=== Test get_interfaces directly ===\"\"\n/usr/libexec/rpcd/luci.ndpid call get_interfaces 2>&1 | head -30\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\nkillall rpcd\nsleep 1\n/etc/init.d/rpcd start\nsleep 2\n\necho \"\"=== Test ubus call ===\"\"\nubus call luci.ndpid get_interfaces 2>&1\n')", - "Bash(setsid -w ssh -o StrictHostKeyChecking=no root@192.168.255.1 '\necho \"\"=== nDPId status ===\"\"\nps | grep \"\"/usr/sbin/ndpid \"\" | grep -v grep\n\necho \"\"\"\"\necho \"\"=== Flow count ===\"\"\nubus call luci.ndpid get_realtime_flows\n\necho \"\"\"\"\necho \"\"=== Top apps ===\"\"\nubus call luci.ndpid get_top_applications 2>&1 | head -25\n\necho \"\"\"\"\necho \"\"=== Detailed flows count ===\"\"\nubus call luci.ndpid get_detailed_flows 2>&1 | jq \"\".flows | length\"\"\n')", - "Bash(export SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\")", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid scp -o StrictHostKeyChecking=no package/secubox/luci-app-system-hub/root/usr/libexec/rpcd/luci.system-hub root@192.168.255.1:/usr/libexec/rpcd/luci.system-hub)", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid scp -o StrictHostKeyChecking=no package/secubox/luci-app-system-hub/htdocs/luci-static/resources/system-hub/api.js root@192.168.255.1:/www/luci-static/resources/system-hub/api.js)", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid scp -o StrictHostKeyChecking=no package/secubox/luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/remote.js root@192.168.255.1:/www/luci-static/resources/view/system-hub/remote.js)", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid ssh:*)", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid scp -o StrictHostKeyChecking=no package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/nav.js root@192.168.255.1:/www/luci-static/resources/crowdsec-dashboard/nav.js)", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid scp -o StrictHostKeyChecking=no package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/*.js root@192.168.255.1:/www/luci-static/resources/view/crowdsec-dashboard/)", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid scp -o StrictHostKeyChecking=no package/secubox/luci-app-crowdsec-dashboard/root/usr/share/luci/menu.d/luci-app-crowdsec-dashboard.json root@192.168.255.1:/usr/share/luci/menu.d/luci-app-crowdsec-dashboard.json)", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid scp -o StrictHostKeyChecking=no package/secubox/luci-app-client-guardian/htdocs/luci-static/resources/client-guardian/nav.js root@192.168.255.1:/www/luci-static/resources/client-guardian/nav.js)", - "Bash(SSH_ASKPASS=/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass DISPLAY=:0 setsid scp -o StrictHostKeyChecking=no package/secubox/luci-app-client-guardian/root/usr/share/luci/menu.d/luci-app-client-guardian.json root@192.168.255.1:/usr/share/luci/menu.d/luci-app-client-guardian.json)", - "Bash(SSHPASS=secubox sshpass:*)", - "WebFetch(domain:openwrt.org)", - "Bash(git -C /home/reepost/CyberMindStudio/_files/secubox-openwrt tag -l)", - "Bash(git -C /home/reepost/CyberMindStudio/_files/secubox-openwrt log --oneline --all --decorate)", - "Bash(git -C /home/reepost/CyberMindStudio/_files/secubox-openwrt show:*)", - "Bash(git -C /home/reepost/CyberMindStudio/_files/secubox-openwrt log --all --grep=\"bandwidth\" --oneline)", - "Bash(SSHPASS=\"alpds_vv\" sshpass:*)", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force scp:*)", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh:*)", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== flows.json ===\"\" ; cat /tmp/ndpid-flows.json ; echo \"\"\"\" ; echo \"\"=== apps.json ===\"\" ; cat /tmp/ndpid-apps.json ; echo \"\"\"\" ; echo \"\"=== state files ===\"\" ; cat /tmp/ndpid-state/flows ; echo \"\"\"\" ; cat /tmp/ndpid-state/apps')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== ndpid config ===\"\" ; uci show ndpid 2>&1 ; echo \"\"\"\" ; echo \"\"=== ndpid running args ===\"\" ; ps w | grep ndpid | grep -v grep ; echo \"\"\"\" ; echo \"\"=== try nDPIsrvd query ===\"\" ; echo \"\"{\\\\\"\"packet_id\\\\\"\":0,\\\\\"\"flow_event_name\\\\\"\":\\\\\"\"status\\\\\"\"}\"\" | timeout 2 nc -U /var/run/ndpid/distributor.sock 2>&1 | head -20')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Check nDPIsrvd socket ===\"\" ; ls -la /var/run/ndpid/ ; echo \"\"\"\" ; echo \"\"=== Query distributor ===\"\" ; \\(echo \"\"{}\"\" | nc -w2 127.0.0.1 7000 2>&1\\) | head -50 ; echo \"\"\"\" ; echo \"\"=== Check compat script ===\"\" ; head -100 /usr/bin/ndpid-compat')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Check nDPIsrvd ===\"\" ; ps | grep ndpisrvd ; echo \"\"\"\" ; echo \"\"=== Check br-lan traffic ===\"\" ; ifconfig br-lan | grep -E \"\"RX|TX\"\" ; echo \"\"\"\" ; echo \"\"=== Restart ndpid ===\"\" ; /etc/init.d/ndpid restart ; sleep 3 ; echo \"\"\"\" ; echo \"\"=== Status after restart ===\"\" ; /etc/init.d/ndpid status ; ps | grep -E \"\"ndpid|ndpisrvd\"\" | grep -v grep')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Kill zombie compat processes ===\"\" ; killall ndpid-compat 2>/dev/null ; pkill -f \"\"ndpid-compat\"\" 2>/dev/null ; sleep 1 ; echo \"\"\"\" ; echo \"\"=== Check ndpisrvd binary ===\"\" ; which ndpisrvd ; ls -la /usr/sbin/ndpisrvd 2>/dev/null ; echo \"\"\"\" ; echo \"\"=== Init script ===\"\" ; head -80 /etc/init.d/ndpid')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'sed -n \"\"80,180p\"\" /etc/init.d/ndpid')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Start ndpisrvd manually ===\"\" ; /usr/sbin/ndpisrvd -c /var/run/ndpid/collector.sock -d /var/run/ndpid/distributor.sock & sleep 2 ; echo \"\"\"\" ; echo \"\"=== Check processes ===\"\" ; ps | grep -E \"\"ndpi\"\" | grep -v grep ; echo \"\"\"\" ; echo \"\"=== Start compat layer ===\"\" ; /usr/bin/ndpid-compat & sleep 3 ; echo \"\"\"\" ; echo \"\"=== Check flows now ===\"\" ; cat /tmp/ndpid-flows.json | head -50')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 '/usr/sbin/ndpisrvd --help 2>&1 | head -40')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Start ndpisrvd properly ===\"\" ; /usr/sbin/ndpisrvd -c /var/run/ndpid/collector.sock -s /var/run/ndpid/distributor.sock -S 127.0.0.1:7000 -d -u nobody ; sleep 2 ; echo \"\"\"\" ; echo \"\"=== Check processes ===\"\" ; ps | grep -E \"\"ndpi\"\" | grep -v grep ; echo \"\"\"\" ; echo \"\"=== Start compat ===\"\" ; nohup /usr/bin/ndpid-compat >/dev/null 2>&1 & sleep 5 ; echo \"\"\"\" ; echo \"\"=== Check flows ===\"\" ; cat /tmp/ndpid-flows.json')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Start compat layer ===\"\" ; nohup /usr/bin/ndpid-compat >/tmp/compat.log 2>&1 & sleep 8 ; echo \"\"\"\" ; echo \"\"=== Check compat log ===\"\" ; cat /tmp/compat.log 2>/dev/null | head -30 ; echo \"\"\"\" ; echo \"\"=== Check flows ===\"\" ; cat /tmp/ndpid-flows.json | head -100 ; echo \"\"\"\" ; echo \"\"=== Check apps ===\"\" ; cat /tmp/ndpid-apps.json | head -50')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Run compat in background ===\"\" ; /usr/bin/ndpid-compat >/tmp/compat.log 2>&1 & COMPAT_PID=$! ; sleep 10 ; echo \"\"=== Compat PID: $COMPAT_PID ===\"\" ; echo \"\"\"\" ; echo \"\"=== Log ===\"\" ; cat /tmp/compat.log 2>/dev/null | tail -50 ; echo \"\"\"\" ; echo \"\"=== Flows ===\"\" ; cat /tmp/ndpid-flows.json 2>/dev/null | head -100')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Check init.d ===\"\" ; ls -la /etc/init.d/ndpi* ; echo \"\"\"\" ; echo \"\"=== ndpisrvd status ===\"\" ; /etc/init.d/ndpisrvd enabled && echo \"\"enabled\"\" || echo \"\"disabled\"\" ; /etc/init.d/ndpisrvd status ; echo \"\"\"\" ; echo \"\"=== rcS links ===\"\" ; ls -la /etc/rc.d/*ndpi* 2>/dev/null ; echo \"\"\"\" ; echo \"\"=== Enable and start ===\"\" ; /etc/init.d/ndpisrvd enable ; /etc/init.d/ndpisrvd start ; sleep 2 ; /etc/init.d/ndpid restart ; sleep 2 ; echo \"\"\"\" ; echo \"\"=== Final check ===\"\" ; ps | grep -E \"\"ndpi\"\" | grep -v grep')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Clean restart ===\"\" ; /etc/init.d/ndpid-compat stop 2>/dev/null ; /etc/init.d/ndpid stop 2>/dev/null ; /etc/init.d/ndpisrvd stop 2>/dev/null ; killall ndpid ndpisrvd ndpid-compat socat 2>/dev/null ; sleep 2 ; rm -f /var/run/ndpid/*.sock ; echo \"\"\"\" ; echo \"\"=== Start in order ===\"\" ; /etc/init.d/ndpisrvd start ; sleep 2 ; /etc/init.d/ndpid start ; sleep 2 ; /etc/init.d/ndpid-compat start ; sleep 5 ; echo \"\"\"\" ; echo \"\"=== Processes ===\"\" ; ps | grep -E \"\"ndpi|socat\"\" | grep -v grep ; echo \"\"\"\" ; echo \"\"=== Flows ===\"\" ; cat /tmp/ndpid-flows.json | head -60')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Test RPC get_streams ===\"\" ; ubus call luci.media-flow get_streams 2>&1 | head -100')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Available methods ===\"\" ; ubus -v list luci.media-flow ; echo \"\"\"\" ; echo \"\"=== Test get_status ===\"\" ; ubus call luci.media-flow get_status 2>&1 | head -50')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Status ===\"\" ; ubus call luci.media-flow status 2>&1 ; echo \"\"\"\" ; echo \"\"=== Flows file ===\"\" ; wc -l /tmp/ndpid-flows.json ; head -20 /tmp/ndpid-flows.json')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== get_active_streams ===\"\" ; ubus call luci.media-flow get_active_streams 2>&1 ; echo \"\"\"\" ; echo \"\"=== get_network_stats ===\"\" ; ubus call luci.media-flow get_network_stats 2>&1')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'grep -n \"\"requestAnimationFrame\"\" /www/luci-static/resources/view/media-flow/dashboard.js')", - "Bash(DISPLAY=:0 SSH_ASKPASS=\"/home/reepost/CyberMindStudio/_files/secubox-openwrt/.ssh-askpass\" SSH_ASKPASS_REQUIRE=force ssh -o StrictHostKeyChecking=no root@192.168.255.1 'echo \"\"=== Check deployed file ===\"\" ; ls -la /www/luci-static/resources/view/media-flow/dashboard.js ; echo \"\"\"\" ; echo \"\"=== Check for initialFlowCount ===\"\" ; grep -n \"\"initialFlowCount\"\" /www/luci-static/resources/view/media-flow/dashboard.js ; echo \"\"\"\" ; echo \"\"=== First 50 lines ===\"\" ; head -50 /www/luci-static/resources/view/media-flow/dashboard.js')", - "Bash(SSH_ASKPASS_REQUIRE=never scp:*)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat: Add SecuBox portal header to all System Hub views\n\nAdd unified SecuBox header navigation to all 10 System Hub views\nfor consistent portal integration when accessed from SecuBox Portal:\n- overview.js, health.js, services.js, diagnostics.js\n- logs.js, backup.js, components.js, settings.js\n- dev-status.js, remote.js\n\nPattern: Wrap view content with secubox-page-wrapper and prepend\nSbHeader.render\\(\\) to hide LuCI sidebar when in portal context.\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "Bash(git tag -a v0.14.0-beta.1 -m \"$\\(cat <<''EOF''\nSecuBox v0.14.0-beta.1\n\nFeatures:\n- Unified SecuBox portal header across all apps\n- Portal navigation with Hub, Admin, Security, Network, Monitoring, System\n- Media Flow views with portal header and dark theme\n- Admin Control Panel integration\n- OpenWrt header hiding with MutationObserver\n\nFixes:\n- App Store now correctly detects installed packages\n- Aggressive CSS/JS for hiding LuCI native elements\nEOF\n\\)\")", - "WebFetch(domain:doc.crowdsec.net)", - "WebFetch(domain:app.crowdsec.net)", - "WebFetch(domain:kroon.email)", - "Bash(make defconfig:*)", - "Bash(python3 -m json.tool:*)", - "Bash(xargs cat:*)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat: Portal service detection, nDPId compat layer, CrowdSec/Netifyd packages\n\nPortal \\(luci-app-secubox-portal\\):\n- Fix service status showing 0/9 by checking if init scripts exist\n- Only count installed services in status display\n- Use pgrep fallback when init script status fails\n\nnDPId Dashboard \\(luci-app-ndpid\\):\n- Add default /etc/config/ndpid configuration\n- Add /etc/init.d/ndpid-compat init script\n- Enable compat service in postinst for app detection\n- Fix Makefile to install init script and config\n\nCrowdSec Dashboard:\n- Add CLAUDE.md with OpenWrt-specific guidelines \\(pgrep without -x\\)\n- CSS fixes for hiding LuCI left menu in all views\n- LAPI repair improvements with retry logic\n\nNew Packages:\n- secubox-app-crowdsec: OpenWrt-native CrowdSec package\n- secubox-app-netifyd: Netifyd DPI integration\n- luci-app-secubox: Core SecuBox hub\n- luci-theme-secubox: Custom theme\n\nRemoved:\n- luci-app-secubox-crowdsec \\(replaced by crowdsec-dashboard\\)\n- secubox-crowdsec-setup \\(functionality moved to dashboard\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat: Add mitmproxy HTTPS interception proxy packages\n\nNew packages for full URL/cookie/header capture via MITM proxy:\n\nsecubox-app-mitmproxy:\n- Downloads mitmproxy v11.1.2 binary for aarch64\n- Transparent proxy mode with iptables integration\n- mitmweb UI on port 8081\n- Auto CA certificate generation\n- mitmproxyctl CLI management tool\n\nluci-app-mitmproxy:\n- SecuBox themed dashboard with red color scheme\n- Real-time request capture view\n- Top hosts statistics\n- CA certificate management\n- Full UCI settings interface\n- RPCD backend for ubus API\n\nThis enables full HTTP/HTTPS inspection including:\n- Complete URLs \\(not just hostnames like nDPId\\)\n- Cookies and headers\n- Request/response bodies\n- Flow recording for replay\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "WebFetch(domain:downloads.mitmproxy.org)", - "WebFetch(domain:mitmproxy.org)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfix: Build mitmproxy from Python source for aarch64\n\n- Update mitmproxy to v11.1.3\n- Build from Python source \\(no prebuilt arm64 binaries\\)\n- Add Python dependencies\n- Add mitmproxy to local-build.sh and sync-openwrt-packages.sh\n- Set PKGARCH:=all for Python package\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "Bash(export PATH=\"/usr/bin:$PATH\")", - "Bash(pip index:*)", - "Bash(pip3 show:*)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat: Integrate mitmproxy and vhost-manager into SecuBox portal\n\nPortal Integration:\n- Add mitmproxy to Security section with service status tracking\n- Add vhost-manager to new Services section\n- Add Services section to portal navigation header\n- Update path detection for security/mitmproxy and services/vhosts\n\nmitmproxy Changes:\n- Move menu from admin/secubox/mitmproxy to admin/secubox/security/mitmproxy\n- Update view navigation links to use new path structure\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfix: Use baseclass.extend\\(\\) for mitmproxy API module\n\nLuCI requires modules to use baseclass.extend\\(\\) pattern.\nFixed \"factory yields invalid constructor\" error.\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", - "Bash(pip3 index:*)", - "WebFetch(domain:pypi.org)", - "Bash(/usr/bin/rsync:*)", - "Bash(for d in /home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/python3-*)", - "Bash(if [ ! -f \"$d/Makefile\" ])", - "Bash(for pkg in crowdsec-firewall-bouncer mitmproxy python3-aioquic python3-h11 python3-h2 python3-hpack python3-hyperframe python3-kaitaistruct python3-ldap3 python3-mitmproxy-rs python3-publicsuffix2 python3-pylsqpack python3-wsproto python3-zstandard secubox-app-crowdsec secubox-app-mitmproxy secubox-app-ndpid secubox-app-netifyd secubox-app-nodogsplash)", - "Bash(while read dir)" + "Bash(git add:*)" ] } } diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js index abaad70d..8def8c8b 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/view/crowdsec-dashboard/settings.js @@ -617,6 +617,40 @@ return view.extend({ }, _('Apply Interface Settings')) ]) ]) + + // Firewall Bouncer quick control + E('div', { 'style': 'margin-top: 1em; padding: 1em; background: #fff; border-radius: 6px; border: 1px solid #e6e6e6;' }, [ + E('h4', { 'style': 'margin-bottom: 0.5em; color: var(--cyber-text-secondary, #888);' }, _('Firewall Bouncer')), + E('p', { 'style': 'color: #666; margin-bottom: 0.5em;' }, _('Enable or disable the CrowdSec firewall bouncer (requires nftables and the firewall-bouncer collection).')), + E('div', { 'id': 'bouncer-control', 'style': 'display: flex; gap: 0.5em; align-items: center;' }, [ + E('button', { + 'class': 'cbi-button cbi-button-action', + 'click': function(ev) { + ev.target.disabled = true; + ev.target.classList.add('spinning'); + API.getFirewallBouncerStatus().then(function(res) { + var enabled = res && res.enabled; + var action = enabled ? 'disable' : 'enable'; + API.controlFirewallBouncer(action).then(function(result) { + ev.target.disabled = false; + ev.target.classList.remove('spinning'); + if (result && result.success) { + ui.addNotification(null, E('p', {}, enabled ? _('Firewall bouncer disabled') : _('Firewall bouncer enabled')), 'info'); + window.setTimeout(function() { location.reload(); }, 1200); + } else { + ui.addNotification(null, E('p', {}, result.error || _('Failed to change bouncer state')), 'error'); + } + }); + }).catch(function(err) { + ev.target.disabled = false; + ev.target.classList.remove('spinning'); + ui.addNotification(null, E('p', {}, err.message || err), 'error'); + }); + } + }, _('Toggle Firewall Bouncer')), + E('div', { 'id': 'bouncer-status', 'style': 'color: #666; font-size: 0.95em;' }, _('Checking status...')) + ]) + ]), ]), // Configuration Files diff --git a/package/secubox/luci-app-media-flow/Makefile b/package/secubox/luci-app-media-flow/Makefile index 65bd4eaf..471a11a6 100644 --- a/package/secubox/luci-app-media-flow/Makefile +++ b/package/secubox/luci-app-media-flow/Makefile @@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-media-flow -PKG_VERSION:=0.6.2 +PKG_VERSION:=0.6.3 PKG_RELEASE:=1 PKG_ARCH:=all PKG_LICENSE:=Apache-2.0 diff --git a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/media-flow/nav.js b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/media-flow/nav.js new file mode 100644 index 00000000..15fa2a8c --- /dev/null +++ b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/media-flow/nav.js @@ -0,0 +1,49 @@ +'use strict'; +'require baseclass'; + +var tabs = [ + { id: 'dashboard', icon: '📊', label: _('Dashboard'), path: ['admin', 'secubox', 'monitoring', 'mediaflow', 'dashboard'] }, + { id: 'alerts', icon: '🔔', label: _('Alerts'), path: ['admin', 'secubox', 'monitoring', 'mediaflow', 'alerts'] }, + { id: 'clients', icon: '👥', label: _('Clients'), path: ['admin', 'secubox', 'monitoring', 'mediaflow', 'clients'] }, + { id: 'services', icon: '🎬', label: _('Services'), path: ['admin', 'secubox', 'monitoring', 'mediaflow', 'services'] }, + { id: 'history', icon: '📜', label: _('History'), path: ['admin', 'secubox', 'monitoring', 'mediaflow', 'history'] } +]; + +return baseclass.extend({ + getTabs: function() { + return tabs.slice(); + }, + + ensureLuCITabsHidden: function() { + if (typeof document === 'undefined') + return; + if (document.getElementById('media-flow-tabstyle')) + return; + var style = document.createElement('style'); + style.id = 'media-flow-tabstyle'; + style.textContent = ` + body[data-page^="admin-secubox-monitoring-mediaflow"] .tabs, + body[data-page^="admin-secubox-monitoring-mediaflow"] #tabmenu, + body[data-page^="admin-secubox-monitoring-mediaflow"] .cbi-tabmenu, + body[data-page^="admin-secubox-monitoring-mediaflow"] .nav-tabs { + display: none !important; +} + `; + document.head && document.head.appendChild(style); + }, + + renderTabs: function(active) { + this.ensureLuCITabsHidden(); + return E('div', { 'class': 'sh-nav-tabs media-flow-nav-tabs' }, + this.getTabs().map(function(tab) { + return E('a', { + 'class': 'sh-nav-tab' + (tab.id === active ? ' active' : ''), + 'href': L.url.apply(L, tab.path) + }, [ + E('span', { 'class': 'sh-tab-icon' }, tab.icon), + E('span', { 'class': 'sh-tab-label' }, tab.label) + ]); + }) + ); + } +}); diff --git a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/alerts.js b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/alerts.js index 94dfdd9b..e5983e1c 100644 --- a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/alerts.js +++ b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/alerts.js @@ -3,33 +3,9 @@ 'require form'; 'require ui'; 'require media-flow/api as API'; +'require media-flow/nav as NavHelper'; 'require secubox-portal/header as SbHeader'; -var MEDIAFLOW_NAV = [ - { id: 'dashboard', icon: '📊', label: 'Dashboard' }, - { id: 'clients', icon: '👥', label: 'Clients' }, - { id: 'services', icon: '🎬', label: 'Services' }, - { id: 'history', icon: '📜', label: 'History' }, - { id: 'alerts', icon: '🔔', label: 'Alerts' } -]; - -function renderMediaFlowNav(activeId) { - return E('div', { - 'class': 'sb-app-nav', - 'style': 'display:flex;gap:8px;margin-bottom:20px;padding:12px 16px;background:#141419;border:1px solid rgba(255,255,255,0.08);border-radius:12px;flex-wrap:wrap;' - }, MEDIAFLOW_NAV.map(function(item) { - var isActive = activeId === item.id; - return E('a', { - 'href': L.url('admin', 'secubox', 'mediaflow', item.id), - 'style': 'display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500;transition:all 0.2s;' + - (isActive ? 'background:linear-gradient(135deg,#ec4899,#8b5cf6);color:white;' : 'color:#a0a0b0;background:transparent;') - }, [ - E('span', {}, item.icon), - E('span', {}, _(item.label)) - ]); - })); -} - return L.view.extend({ load: function() { return Promise.all([ @@ -53,18 +29,19 @@ return L.view.extend({ o.placeholder = 'Netflix'; o.rmempty = false; - o = s.option(form.Value, 'threshold_hours', _('Threshold (hours)')); + o = s.option(form.Value, 'threshold_hours', _("Daily Usage Limit (hours)")); o.datatype = 'uinteger'; - o.placeholder = '2'; + o.placeholder = '4'; o.rmempty = false; - o.description = _('Trigger alert if usage exceeds this many hours per day'); + o.description = _('Alert when daily usage exceeds this threshold (e.g., 2-4 hours)'); - o = s.option(form.ListValue, 'action', _('Action')); - o.value('notify', _('Notification only')); - o.value('limit', _('Limit bandwidth')); - o.value('block', _('Block service')); + o = s.option(form.ListValue, 'action', _("Alert Action")); + o.value('notify', _('📬 Notify Only')); + o.value('limit', _('🐌 Limit Bandwidth')); + o.value('block', _('🚫 Block Service')); o.default = 'notify'; o.rmempty = false; + o.description = _('Choose what happens when threshold is exceeded'); o = s.option(form.Flag, 'enabled', _('Enabled')); o.default = o.enabled; @@ -75,10 +52,20 @@ return L.view.extend({ .mf-header { margin-bottom: 24px; } .mf-title { font-size: 1.5rem; font-weight: 700; margin-bottom: 8px; display: flex; align-items: center; gap: 12px; } .mf-subtitle { color: #a1a1aa; font-size: 0.875rem; } +.cbi-section { margin: 0 !important; background: rgba(255,255,255,0.02) !important; border: 1px solid rgba(255,255,255,0.08) !important; border-radius: 12px !important; padding: 20px !important; } +.cbi-section-create { margin-top: 12px !important; } +.cbi-option-compact { padding: 12px 0 !important; border-bottom: 1px solid rgba(255,255,255,0.04) !important; } +.cbi-option-compact:last-child { border-bottom: none !important; } +.form-control { background: rgba(255,255,255,0.05) !important; border-color: rgba(255,255,255,0.1) !important; color: #e4e4e7 !important; border-radius: 6px !important; padding: 8px 12px !important; } +.form-control:focus { border-color: #ec4899 !important; background: rgba(236,72,153,0.08) !important; box-shadow: 0 0 0 3px rgba(236,72,153,0.1) !important; } +.cbi-button { border-radius: 8px !important; font-weight: 500 !important; transition: all 0.2s !important; } +.cbi-button-add { background: linear-gradient(135deg, #ec4899, #8b5cf6) !important; color: white !important; border: none !important; } +.cbi-button-add:hover { opacity: 0.9 !important; transform: translateY(-2px) !important; } `; var container = E('div', { 'class': 'mf-page' }, [ E('style', {}, css), - renderMediaFlowNav('alerts'), + E('link', { 'rel': 'stylesheet', 'href': L.resource('media-flow/common.css') }), + NavHelper.renderTabs('alerts'), E('div', { 'class': 'mf-header' }, [ E('div', { 'class': 'mf-title' }, ['🔔 ', _('Streaming Alerts')]), E('div', { 'class': 'mf-subtitle' }, _('Configure alerts based on streaming service usage')) diff --git a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/clients.js b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/clients.js index d48deff0..487618fb 100644 --- a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/clients.js +++ b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/clients.js @@ -2,33 +2,9 @@ 'require view'; 'require ui'; 'require media-flow/api as API'; +'require media-flow/nav as NavHelper'; 'require secubox-portal/header as SbHeader'; -var MEDIAFLOW_NAV = [ - { id: 'dashboard', icon: '📊', label: 'Dashboard' }, - { id: 'clients', icon: '👥', label: 'Clients' }, - { id: 'services', icon: '🎬', label: 'Services' }, - { id: 'history', icon: '📜', label: 'History' }, - { id: 'alerts', icon: '🔔', label: 'Alerts' } -]; - -function renderMediaFlowNav(activeId) { - return E('div', { - 'class': 'sb-app-nav', - 'style': 'display:flex;gap:8px;margin-bottom:20px;padding:12px 16px;background:#141419;border:1px solid rgba(255,255,255,0.08);border-radius:12px;flex-wrap:wrap;' - }, MEDIAFLOW_NAV.map(function(item) { - var isActive = activeId === item.id; - return E('a', { - 'href': L.url('admin', 'secubox', 'mediaflow', item.id), - 'style': 'display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500;transition:all 0.2s;' + - (isActive ? 'background:linear-gradient(135deg,#ec4899,#8b5cf6);color:white;' : 'color:#a0a0b0;background:transparent;') - }, [ - E('span', {}, item.icon), - E('span', {}, _(item.label)) - ]); - })); -} - return L.view.extend({ load: function() { return Promise.all([ @@ -47,16 +23,27 @@ return L.view.extend({ .mf-subtitle { color: #a1a1aa; font-size: 0.875rem; } .mf-card { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 12px; overflow: hidden; } .mf-table { width: 100%; border-collapse: collapse; } -.mf-table th { text-align: left; padding: 12px 16px; font-size: 0.75rem; text-transform: uppercase; color: #71717a; border-bottom: 1px solid rgba(255, 255, 255, 0.08); background: rgba(255,255,255,0.02); } +.mf-table th { text-align: left; padding: 12px 16px; font-size: 0.75rem; text-transform: uppercase; color: #71717a; border-bottom: 1px solid rgba(255, 255, 255, 0.08); background: rgba(255,255,255,0.02); font-weight: 600; } .mf-table td { padding: 12px 16px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .mf-table tr:hover td { background: rgba(255, 255, 255, 0.03); } .mf-empty { text-align: center; padding: 48px 20px; color: #71717a; } .mf-empty-icon { font-size: 3rem; margin-bottom: 12px; opacity: 0.5; } +@media (max-width: 768px) { + .mf-card { overflow-x: auto; } + .mf-table { font-size: 0.9rem; } + .mf-table th, .mf-table td { padding: 10px 8px; } +} +@media (max-width: 480px) { + .mf-title { font-size: 1.25rem; } + .mf-table { font-size: 0.8rem; } + .mf-table th, .mf-table td { padding: 8px 4px; } +} `; var container = E('div', { 'class': 'mf-page' }, [ E('style', {}, css), - renderMediaFlowNav('clients'), + E('link', { 'rel': 'stylesheet', 'href': L.resource('media-flow/common.css') }), + NavHelper.renderTabs('clients'), E('div', { 'class': 'mf-header' }, [ E('div', { 'class': 'mf-title' }, ['👥 ', _('Clients Statistics')]), E('div', { 'class': 'mf-subtitle' }, _('Streaming activity per client')) diff --git a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/dashboard.js b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/dashboard.js index de16e4e9..ebbf67c6 100644 --- a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/dashboard.js +++ b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/dashboard.js @@ -3,6 +3,7 @@ 'require poll'; 'require ui'; 'require media-flow/api as API'; +'require media-flow/nav as NavHelper'; 'require secubox-portal/header as SbHeader'; return view.extend({ @@ -37,10 +38,6 @@ return view.extend({ var streams = streamsData.streams || []; var flowCount = streamsData.flow_count || status.active_flows || 0; - // Main wrapper with SecuBox header - var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); - wrapper.appendChild(SbHeader.render()); - // Inject CSS var css = ` .mf-dashboard { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #e4e4e7; } @@ -54,7 +51,9 @@ return view.extend({ .mf-status-badge.stopped { background: rgba(239, 68, 68, 0.2); color: #ef4444; border: 1px solid rgba(239, 68, 68, 0.3); } .mf-status-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; } -.mf-stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px; } +.mf-stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 24px; } +@media (max-width: 768px) { .mf-stats-grid { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 480px) { .mf-stats-grid { grid-template-columns: 1fr; } } .mf-stat-card { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 12px; padding: 20px; text-align: center; transition: all 0.2s; } .mf-stat-card:hover { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.12); } .mf-stat-icon { font-size: 1.5rem; margin-bottom: 8px; } @@ -84,13 +83,20 @@ return view.extend({ .mf-empty-icon { font-size: 3rem; margin-bottom: 12px; opacity: 0.5; } .mf-empty-text { font-size: 1rem; } -.mf-streams-table { width: 100%; border-collapse: collapse; } +.mf-streams-table { width: 100%; border-collapse: collapse; overflow-x: auto; } +@media (max-width: 768px) { .mf-streams-table { font-size: 0.85rem; } .mf-streams-table th, .mf-streams-table td { padding: 10px 8px; } } +@media (max-width: 480px) { .mf-card-body { padding: 12px; overflow-x: auto; } .mf-streams-table { font-size: 0.75rem; } .mf-streams-table th, .mf-streams-table td { padding: 8px 4px; } } .mf-streams-table th { text-align: left; padding: 12px 16px; font-size: 0.75rem; text-transform: uppercase; color: #71717a; border-bottom: 1px solid rgba(255, 255, 255, 0.08); } .mf-streams-table td { padding: 12px 16px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .mf-streams-table tr:hover td { background: rgba(255, 255, 255, 0.03); } .mf-quality-badge { padding: 4px 10px; border-radius: 6px; font-size: 0.75rem; font-weight: 600; color: white; } .mf-btn { padding: 10px 20px; border-radius: 8px; font-size: 0.875rem; font-weight: 500; cursor: pointer; border: none; transition: all 0.2s; } +.mf-btn:disabled { opacity: 0.6; cursor: not-allowed; } +.mf-btn.spinning::after { content: ''; animation: spin 1s linear infinite; display: inline-block; margin-left: 8px; width: 14px; height: 14px; border: 2px solid rgba(255,255,255,0.3); border-top-color: white; border-radius: 50%; } +@keyframes spin { to { transform: rotate(360deg); } } +@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } +.mf-loading { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } .mf-btn-primary { background: linear-gradient(135deg, #ec4899, #8b5cf6); color: white; } .mf-btn-primary:hover { opacity: 0.9; transform: translateY(-1px); } .mf-btn-secondary { background: rgba(255, 255, 255, 0.1); color: #e4e4e7; border: 1px solid rgba(255, 255, 255, 0.2); } @@ -101,6 +107,8 @@ return view.extend({ var view = E('div', { 'class': 'mf-dashboard' }, [ E('style', {}, css), + E('link', { 'rel': 'stylesheet', 'href': L.resource('media-flow/common.css') }), + NavHelper.renderTabs('dashboard'), // Header E('div', { 'class': 'mf-header' }, [ @@ -246,6 +254,8 @@ return view.extend({ }, this)); }, this), this.pollInterval); + var wrapper = E('div', { 'class': 'secubox-page-wrapper' }); + wrapper.appendChild(SbHeader.render()); wrapper.appendChild(view); return wrapper; }, diff --git a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/history.js b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/history.js index 3ce1c4ed..27ee6c2e 100644 --- a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/history.js +++ b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/history.js @@ -2,33 +2,9 @@ 'require view'; 'require ui'; 'require media-flow/api as API'; +'require media-flow/nav as NavHelper'; 'require secubox-portal/header as SbHeader'; -var MEDIAFLOW_NAV = [ - { id: 'dashboard', icon: '📊', label: 'Dashboard' }, - { id: 'clients', icon: '👥', label: 'Clients' }, - { id: 'services', icon: '🎬', label: 'Services' }, - { id: 'history', icon: '📜', label: 'History' }, - { id: 'alerts', icon: '🔔', label: 'Alerts' } -]; - -function renderMediaFlowNav(activeId) { - return E('div', { - 'class': 'sb-app-nav', - 'style': 'display:flex;gap:8px;margin-bottom:20px;padding:12px 16px;background:#141419;border:1px solid rgba(255,255,255,0.08);border-radius:12px;flex-wrap:wrap;' - }, MEDIAFLOW_NAV.map(function(item) { - var isActive = activeId === item.id; - return E('a', { - 'href': L.url('admin', 'secubox', 'mediaflow', item.id), - 'style': 'display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500;transition:all 0.2s;' + - (isActive ? 'background:linear-gradient(135deg,#ec4899,#8b5cf6);color:white;' : 'color:#a0a0b0;background:transparent;') - }, [ - E('span', {}, item.icon), - E('span', {}, _(item.label)) - ]); - })); -} - return L.view.extend({ load: function() { return Promise.all([ @@ -47,22 +23,37 @@ return L.view.extend({ .mf-subtitle { color: #a1a1aa; font-size: 0.875rem; } .mf-card { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 12px; overflow: hidden; } .mf-controls { display: flex; gap: 10px; align-items: center; margin-bottom: 20px; flex-wrap: wrap; } -.mf-select { padding: 8px 12px; border-radius: 6px; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); color: #e4e4e7; } +.mf-select { padding: 8px 12px; border-radius: 6px; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); color: #e4e4e7; cursor: pointer; transition: all 0.2s; } +.mf-select:focus { border-color: #ec4899; background: rgba(236,72,153,0.08); } .mf-btn { padding: 8px 16px; border-radius: 6px; font-size: 0.8rem; cursor: pointer; border: none; background: rgba(255,255,255,0.1); color: #e4e4e7; transition: all 0.2s; } -.mf-btn:hover { background: rgba(255,255,255,0.15); } +.mf-btn:hover { background: rgba(255,255,255,0.15); transform: translateY(-1px); } .mf-btn-danger { background: rgba(239, 68, 68, 0.2); color: #ef4444; } .mf-btn-danger:hover { background: rgba(239, 68, 68, 0.3); } .mf-table { width: 100%; border-collapse: collapse; } -.mf-table th { text-align: left; padding: 12px 16px; font-size: 0.75rem; text-transform: uppercase; color: #71717a; border-bottom: 1px solid rgba(255, 255, 255, 0.08); background: rgba(255,255,255,0.02); } +.mf-table th { text-align: left; padding: 12px 16px; font-size: 0.75rem; text-transform: uppercase; color: #71717a; border-bottom: 1px solid rgba(255, 255, 255, 0.08); background: rgba(255,255,255,0.02); font-weight: 600; } .mf-table td { padding: 12px 16px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .mf-table tr:hover td { background: rgba(255, 255, 255, 0.03); } .mf-empty { text-align: center; padding: 48px 20px; color: #71717a; } .mf-quality { padding: 4px 10px; border-radius: 6px; font-size: 0.75rem; font-weight: 600; color: white; } +@media (max-width: 768px) { + .mf-controls { flex-direction: column; align-items: stretch; } + .mf-select, .mf-btn { width: 100%; } + .mf-card { overflow-x: auto; } + .mf-table { font-size: 0.9rem; } + .mf-table th, .mf-table td { padding: 10px 8px; } +} +@media (max-width: 480px) { + .mf-title { font-size: 1.25rem; } + .mf-table { font-size: 0.8rem; } + .mf-table th, .mf-table td { padding: 8px 4px; } + .mf-btn { padding: 6px 12px; font-size: 0.75rem; } +} `; var container = E('div', { 'class': 'mf-page' }, [ E('style', {}, css), - renderMediaFlowNav('history'), + E('link', { 'rel': 'stylesheet', 'href': L.resource('media-flow/common.css') }), + NavHelper.renderTabs('history'), E('div', { 'class': 'mf-header' }, [ E('div', { 'class': 'mf-title' }, ['📜 ', _('Stream History')]), E('div', { 'class': 'mf-subtitle' }, _('Historical record of detected streaming sessions')) diff --git a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/services.js b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/services.js index 3dc93853..4e6bec7d 100644 --- a/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/services.js +++ b/package/secubox/luci-app-media-flow/htdocs/luci-static/resources/view/media-flow/services.js @@ -2,33 +2,9 @@ 'require view'; 'require ui'; 'require media-flow/api as API'; +'require media-flow/nav as NavHelper'; 'require secubox-portal/header as SbHeader'; -var MEDIAFLOW_NAV = [ - { id: 'dashboard', icon: '📊', label: 'Dashboard' }, - { id: 'clients', icon: '👥', label: 'Clients' }, - { id: 'services', icon: '🎬', label: 'Services' }, - { id: 'history', icon: '📜', label: 'History' }, - { id: 'alerts', icon: '🔔', label: 'Alerts' } -]; - -function renderMediaFlowNav(activeId) { - return E('div', { - 'class': 'sb-app-nav', - 'style': 'display:flex;gap:8px;margin-bottom:20px;padding:12px 16px;background:#141419;border:1px solid rgba(255,255,255,0.08);border-radius:12px;flex-wrap:wrap;' - }, MEDIAFLOW_NAV.map(function(item) { - var isActive = activeId === item.id; - return E('a', { - 'href': L.url('admin', 'secubox', 'mediaflow', item.id), - 'style': 'display:flex;align-items:center;gap:8px;padding:10px 16px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500;transition:all 0.2s;' + - (isActive ? 'background:linear-gradient(135deg,#ec4899,#8b5cf6);color:white;' : 'color:#a0a0b0;background:transparent;') - }, [ - E('span', {}, item.icon), - E('span', {}, _(item.label)) - ]); - })); -} - return L.view.extend({ load: function() { return Promise.all([ @@ -47,18 +23,30 @@ return L.view.extend({ .mf-subtitle { color: #a1a1aa; font-size: 0.875rem; } .mf-card { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 12px; overflow: hidden; } .mf-table { width: 100%; border-collapse: collapse; } -.mf-table th { text-align: left; padding: 12px 16px; font-size: 0.75rem; text-transform: uppercase; color: #71717a; border-bottom: 1px solid rgba(255, 255, 255, 0.08); background: rgba(255,255,255,0.02); } +.mf-table th { text-align: left; padding: 12px 16px; font-size: 0.75rem; text-transform: uppercase; color: #71717a; border-bottom: 1px solid rgba(255, 255, 255, 0.08); background: rgba(255,255,255,0.02); font-weight: 600; } .mf-table td { padding: 12px 16px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .mf-table tr:hover td { background: rgba(255, 255, 255, 0.03); } .mf-empty { text-align: center; padding: 48px 20px; color: #71717a; } .mf-empty-icon { font-size: 3rem; margin-bottom: 12px; opacity: 0.5; } .mf-btn { padding: 8px 16px; border-radius: 6px; font-size: 0.8rem; cursor: pointer; border: none; background: rgba(255,255,255,0.1); color: #e4e4e7; transition: all 0.2s; } -.mf-btn:hover { background: rgba(255,255,255,0.15); } +.mf-btn:hover { background: rgba(255,255,255,0.15); transform: translateY(-1px); } +@media (max-width: 768px) { + .mf-card { overflow-x: auto; } + .mf-table { font-size: 0.9rem; } + .mf-table th, .mf-table td { padding: 10px 8px; } +} +@media (max-width: 480px) { + .mf-title { font-size: 1.25rem; } + .mf-table { font-size: 0.8rem; } + .mf-table th, .mf-table td { padding: 8px 4px; } + .mf-btn { padding: 6px 12px; font-size: 0.75rem; } +} `; var container = E('div', { 'class': 'mf-page' }, [ E('style', {}, css), - renderMediaFlowNav('services'), + E('link', { 'rel': 'stylesheet', 'href': L.resource('media-flow/common.css') }), + NavHelper.renderTabs('services'), E('div', { 'class': 'mf-header' }, [ E('div', { 'class': 'mf-title' }, ['🎬 ', _('Services Statistics')]), E('div', { 'class': 'mf-subtitle' }, _('Detailed statistics per streaming service')) diff --git a/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/Packages.gz b/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/Packages.gz index c3dc4c5b543a6ef2b278a0d96ccfbcd58bb618bc..d016167e64114739e0ea7bfce621a552f75048d7 100644 GIT binary patch delta 15 WcmX?PbjXNJzMF$%=827LHj)4=69pCk delta 15 WcmX?PbjXNJzMF%?I%gxBjU)gl69ilU diff --git a/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/apps-local.json b/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/apps-local.json index c076e139..5a25b15c 100644 --- a/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/apps-local.json +++ b/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/apps-local.json @@ -1,6 +1,6 @@ { "feed_url": "/secubox-feed", - "generated": "2026-01-11T10:24:11+01:00", + "generated": "2026-01-11T16:58:17+01:00", "packages": [ { "name": "luci-app-auth-guardian", diff --git a/package/secubox/secubox-app-mitmproxy/Makefile b/package/secubox/secubox-app-mitmproxy/Makefile index 1e4880dd..60552ab0 100644 --- a/package/secubox/secubox-app-mitmproxy/Makefile +++ b/package/secubox/secubox-app-mitmproxy/Makefile @@ -5,23 +5,18 @@ # # secubox-app-mitmproxy - mitmproxy integration for SecuBox # Provides init scripts, UCI configuration, and control utilities -# mitmproxy is installed via pip at runtime (with pre-built wheels) +# mitmproxy binary must be installed separately via pip # include $(TOPDIR)/rules.mk PKG_NAME:=secubox-app-mitmproxy -PKG_VERSION:=2.1.0 +PKG_VERSION:=2.2.0 PKG_RELEASE:=1 PKG_MAINTAINER:=CyberMind PKG_LICENSE:=MIT -# mitmproxy version to install -MITMPROXY_VERSION:=8.1.1 -# zstandard version with musllinux aarch64 wheels -ZSTANDARD_VERSION:=0.23.0 - include $(INCLUDE_DIR)/package.mk define Package/secubox-app-mitmproxy @@ -30,16 +25,16 @@ define Package/secubox-app-mitmproxy SUBMENU:=SecuBox Apps TITLE:=mitmproxy - Interactive HTTPS Proxy (SecuBox Integration) URL:=https://mitmproxy.org/ - DEPENDS:=+python3 +python3-pip +jq +openssl-util + DEPENDS:=+python3 +jq +openssl-util PKGARCH:=all endef define Package/secubox-app-mitmproxy/description - SecuBox integration package for mitmproxy $(MITMPROXY_VERSION). + SecuBox integration package for mitmproxy. Provides init scripts, UCI configuration, and control utilities. - mitmproxy is installed via pip during post-install with pre-built - musllinux wheels for optimal compatibility. + NOTE: mitmproxy binary must be installed separately via pip: + pip3 install mitmproxy Features: - Intercept and modify HTTP/HTTPS traffic @@ -85,36 +80,25 @@ define Package/secubox-app-mitmproxy/postinst # Create runtime directories mkdir -p /var/lib/mitmproxy /tmp/mitmproxy /etc/mitmproxy - # Install mitmproxy via pip if not present - if ! python3 -c "import mitmproxy" 2>/dev/null; then - echo "Installing mitmproxy dependencies..." + # Check if mitmproxy is installed + if python3 -c "import mitmproxy" 2>/dev/null; then + echo "mitmproxy detected" - # IMPORTANT: Install zstandard first with musllinux wheel - # Older versions don't have musllinux wheels and fail to compile - pip3 install --no-cache-dir zstandard==0.23.0 || { - echo "Warning: zstandard installation failed" - } + # Generate CA certificate if needed + if [ ! -f /etc/mitmproxy/mitmproxy-ca.pem ]; then + echo "Generating mitmproxy CA certificate..." + /usr/bin/mitmdump --set confdir=/etc/mitmproxy -q & + sleep 5 + killall mitmdump 2>/dev/null || killall python3 2>/dev/null || true + fi - echo "Installing mitmproxy 8.1.1..." - pip3 install --no-cache-dir mitmproxy==8.1.1 || { - echo "Error: mitmproxy installation failed" - echo "Try manually: pip3 install zstandard==0.23.0 mitmproxy==8.1.1" - exit 1 - } + /etc/init.d/mitmproxy enable + echo "mitmproxy service enabled. Start with: /etc/init.d/mitmproxy start" else - echo "mitmproxy already installed" + echo "NOTE: mitmproxy binary not found." + echo "Install via pip: pip3 install mitmproxy" + echo "Then enable service: /etc/init.d/mitmproxy enable" fi - - # Generate CA certificate if needed - if [ ! -f /etc/mitmproxy/mitmproxy-ca.pem ]; then - echo "Generating mitmproxy CA certificate..." - /usr/bin/mitmdump --set confdir=/etc/mitmproxy -q & - sleep 5 - killall mitmdump 2>/dev/null || killall python3 2>/dev/null || true - fi - - /etc/init.d/mitmproxy enable - echo "mitmproxy installed. Start with: /etc/init.d/mitmproxy start" } exit 0 endef diff --git a/scripts/auto_block_luci_bruteforce.sh b/scripts/auto_block_luci_bruteforce.sh new file mode 100644 index 00000000..d68dfa7f --- /dev/null +++ b/scripts/auto_block_luci_bruteforce.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# Simple OpenWrt script: detect repeated LuCI failed logins and block offending IPs +# Place this file in /usr/bin or /etc/init.d and run periodically (cron) as root. + +THRESHOLD=${THRESHOLD:-5} # attempts +TAIL_LINES=${TAIL_LINES:-1000} + +log() { logger -t auto_block_luci "$@"; } + +detect_offenders() { + log "Scanning logs for failed LuCI logins..." + # Gather recent failed login lines and extract IPs + logread | tail -n "$TAIL_LINES" | grep -i "luci: failed login" | awk '{for(i=1;i<=NF;i++) if ($i=="from") print $(i+1)}' | sort | uniq -c | while read -r count ip; do + if [ -z "$ip" ]; then continue; fi + if [ "$count" -ge "$THRESHOLD" ]; then + block_ip "$ip" "$count" + fi + done +} + +block_ip() { + ip=$1 + cnt=$2 + log "Detected $cnt failed attempts from $ip; blocking" + + # Check if already blocked by searching existing firewall rules + exists=$(uci show firewall 2>/dev/null | grep "src_ip='$ip'" || true) + if [ -n "$exists" ]; then + log "$ip already blocked (uci rule exists)" + return + fi + + # Create persistent UCI firewall rule named auto_block_ + # UCI section names cannot contain dots, replace with '_' + name="auto_block_$(echo "$ip" | tr '.' '_')" + uci set firewall.$name=rule + uci set firewall.$name.name="auto_block_$ip" + uci set firewall.$name.src='lan' + uci set firewall.$name.src_ip="$ip" + uci set firewall.$name.family='ipv4' + uci set firewall.$name.target='DROP' + uci commit firewall + /etc/init.d/firewall reload + + log "Blocked $ip via UCI firewall rule $name" +} + +main() { + detect_offenders +} + +main