feat(peertube,portal): Add PeerTube config and generative luci-tree

- secubox-app-peertube: Update default port to 9001, hostname to tube.gk2.secubox.in
- luci-app-secubox-portal: Add RPCD backend for dynamic tree generation
  - get_tree: Auto-discovers luci-app-* packages grouped by category
  - get_containers: Lists LXC containers with running state
  - get_vhosts: Lists HAProxy virtual hosts
- luci-tree.js: Rewritten to use RPC for live data with refresh button

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-15 06:48:10 +01:00
parent ffb9fe3785
commit 1a8beb45e0
4 changed files with 514 additions and 150 deletions

View File

@ -1,7 +1,26 @@
'use strict';
'require view';
'require dom';
'require secubox/kiss-theme';
'require rpc';
'require poll';
var callGetTree = rpc.declare({
object: 'luci.secubox-portal',
method: 'get_tree',
expect: { }
});
var callGetContainers = rpc.declare({
object: 'luci.secubox-portal',
method: 'get_containers',
expect: { }
});
var callGetVhosts = rpc.declare({
object: 'luci.secubox-portal',
method: 'get_vhosts',
expect: { }
});
return view.extend({
handleSaveApply: null,
@ -9,180 +28,128 @@ return view.extend({
handleReset: null,
load: function() {
return Promise.resolve();
return Promise.all([
callGetTree(),
callGetContainers(),
callGetVhosts()
]);
},
render: function() {
var TREE = [
{ cat: 'SecuBox Core', items: [
{ name: 'Dashboard', path: 'admin/secubox/dashboard' },
{ name: 'App Store', path: 'admin/secubox/apps' },
{ name: 'Modules', path: 'admin/secubox/modules' },
{ name: 'Alerts', path: 'admin/secubox/alerts' },
{ name: 'Settings', path: 'admin/secubox/settings' }
]},
{ cat: 'Admin Control', items: [
{ name: 'Control Panel', path: 'admin/secubox/admin/dashboard' },
{ name: 'Cyber Console', path: 'admin/secubox/admin/cyber-dashboard' },
{ name: 'Apps Manager', path: 'admin/secubox/admin/apps' },
{ name: 'Profiles', path: 'admin/secubox/admin/profiles' },
{ name: 'Skills', path: 'admin/secubox/admin/skills' },
{ name: 'System Health', path: 'admin/secubox/admin/health' },
{ name: 'System Logs', path: 'admin/secubox/admin/logs' }
]},
{ cat: 'Security', items: [
{ name: 'CrowdSec Overview', path: 'admin/secubox/security/crowdsec/overview' },
{ name: 'CrowdSec Decisions', path: 'admin/secubox/security/crowdsec/decisions' },
{ name: 'CrowdSec Alerts', path: 'admin/secubox/security/crowdsec/alerts' },
{ name: 'CrowdSec Bouncers', path: 'admin/secubox/security/crowdsec/bouncers' },
{ name: 'mitmproxy Status', path: 'admin/secubox/security/mitmproxy/status' },
{ name: 'mitmproxy Settings', path: 'admin/secubox/security/mitmproxy/settings' },
{ name: 'Client Guardian', path: 'admin/secubox/security/guardian' },
{ name: 'DNS Guard', path: 'admin/secubox/security/dnsguard' },
{ name: 'Threat Analyst', path: 'admin/secubox/security/threat-analyst' },
{ name: 'Network Anomaly', path: 'admin/secubox/security/network-anomaly' },
{ name: 'Auth Guardian', path: 'admin/secubox/security/auth-guardian' },
{ name: 'Key Storage Manager', path: 'admin/secubox/security/ksm-manager' }
]},
{ cat: 'AI Gateway', items: [
{ name: 'AI Insights', path: 'admin/secubox/ai/insights' },
{ name: 'LocalRecall', path: 'admin/secubox/ai/localrecall' }
]},
{ cat: 'MirrorBox P2P', items: [
{ name: 'Overview', path: 'admin/secubox/mirrorbox/overview' },
{ name: 'P2P Hub', path: 'admin/secubox/mirrorbox/hub' },
{ name: 'Peers', path: 'admin/secubox/mirrorbox/peers' },
{ name: 'Services', path: 'admin/secubox/mirrorbox/services' },
{ name: 'Factory', path: 'admin/secubox/mirrorbox/factory' },
{ name: 'App Store', path: 'admin/secubox/mirrorbox/packages' },
{ name: 'Dev Status', path: 'admin/secubox/mirrorbox/devstatus' }
]},
{ cat: 'Network', items: [
{ name: 'Network Modes', path: 'admin/secubox/network/modes' },
{ name: 'DNS Providers', path: 'admin/secubox/network/dns-provider' },
{ name: 'Service Exposure', path: 'admin/secubox/network/exposure' },
{ name: 'Bandwidth Manager', path: 'admin/secubox/network/bandwidth-manager' },
{ name: 'Traffic Shaper', path: 'admin/secubox/network/traffic-shaper' },
{ name: 'MQTT Bridge', path: 'admin/secubox/network/mqtt-bridge' },
{ name: 'Network Tweaks', path: 'admin/network/network-tweaks' }
]},
{ cat: 'Monitoring', items: [
{ name: 'Netdata Dashboard', path: 'admin/secubox/monitoring/netdata' },
{ name: 'Glances', path: 'admin/secubox/monitoring/glances' },
{ name: 'Media Flow', path: 'admin/secubox/monitoring/mediaflow' }
]},
{ cat: 'System', items: [
{ name: 'System Hub', path: 'admin/secubox/system/system-hub' },
{ name: 'Cloning Station', path: 'admin/secubox/system/cloner' }
]},
{ cat: 'Device Intelligence', items: [
{ name: 'Dashboard', path: 'admin/secubox/device-intel/dashboard' },
{ name: 'Devices', path: 'admin/secubox/device-intel/devices' },
{ name: 'Mesh', path: 'admin/secubox/device-intel/mesh' }
]},
{ cat: 'InterceptoR', items: [
{ name: 'Overview', path: 'admin/secubox/interceptor/overview' }
]},
{ cat: 'IoT & Automation', items: [
{ name: 'IoT Guard', path: 'admin/secubox/services/iot-guard' },
{ name: 'Zigbee2MQTT', path: 'admin/secubox/zigbee2mqtt' },
{ name: 'nDPId', path: 'admin/secubox/ndpid' },
{ name: 'Netifyd', path: 'admin/secubox/netifyd' }
]},
{ cat: 'Services - Proxy & VPN', items: [
{ name: 'HAProxy', path: 'admin/services/haproxy' },
{ name: 'VHost Manager', path: 'admin/services/vhosts' },
{ name: 'WireGuard', path: 'admin/services/wireguard' },
{ name: 'Tor Shield', path: 'admin/services/tor-shield' },
{ name: 'CDN Cache', path: 'admin/services/cdn-cache' }
]},
{ cat: 'Services - AI & Chat', items: [
{ name: 'LocalAI', path: 'admin/services/localai' },
{ name: 'Ollama', path: 'admin/services/ollama' },
{ name: 'SimpleX Chat', path: 'admin/services/simplex' },
{ name: 'Jitsi Meet', path: 'admin/services/jitsi' }
]},
{ cat: 'Services - Media & Cloud', items: [
{ name: 'Nextcloud', path: 'admin/services/nextcloud' },
{ name: 'Jellyfin', path: 'admin/services/jellyfin' },
{ name: 'Lyrion', path: 'admin/services/lyrion' },
{ name: 'MagicMirror', path: 'admin/services/magicmirror2' },
{ name: 'MMPM', path: 'admin/services/mmpm' },
{ name: 'Streamlit', path: 'admin/services/streamlit' }
]},
{ cat: 'Services - Home & IoT', items: [
{ name: 'Domoticz', path: 'admin/services/domoticz' },
{ name: 'MAC Guardian', path: 'admin/services/mac-guardian' },
{ name: 'Mesh Link', path: 'admin/services/secubox-mesh' }
]},
{ cat: 'Services - Dev & CMS', items: [
{ name: 'Gitea', path: 'admin/services/gitea' },
{ name: 'Hexo CMS', path: 'admin/services/hexojs' },
{ name: 'MetaBlogizer', path: 'admin/services/metablogizer' },
{ name: 'Metabolizer', path: 'admin/services/metabolizer' },
{ name: 'PicoBrew', path: 'admin/services/picobrew' }
]},
{ cat: 'Services - DNS & Security', items: [
{ name: 'Service Registry', path: 'admin/services/service-registry' },
{ name: 'Vortex DNS', path: 'admin/services/vortex-dns' },
{ name: 'Vortex Firewall', path: 'admin/services/vortex-firewall' },
{ name: 'Threat Monitor', path: 'admin/services/threat-monitor' },
{ name: 'CyberFeed', path: 'admin/services/cyberfeed' },
{ name: 'Config Advisor', path: 'admin/services/config-advisor' },
{ name: 'Network Diagnostics', path: 'admin/services/network-diagnostics' }
]},
{ cat: 'Public Portal', items: [
{ name: 'C3BOX Portal', path: 'secubox-public/portal' },
{ name: 'Crowdfunding', path: 'secubox-public/crowdfunding' },
{ name: 'Bug Bounty', path: 'secubox-public/bugbounty' },
{ name: 'Dev Status', path: 'secubox-public/devstatus' }
]}
];
render: function(data) {
var treeData = data[0] || {};
var containersData = data[1] || {};
var vhostsData = data[2] || {};
var categories = treeData.categories || [];
var stats = treeData.stats || {};
var containers = containersData.containers || [];
var vhosts = vhostsData.vhosts || [];
var totalLinks = 0;
TREE.forEach(function(cat) { totalLinks += cat.items.length; });
categories.forEach(function(cat) {
if (cat.items) totalLinks += cat.items.length;
});
var runningContainers = containers.filter(function(c) { return c.state === 'running'; }).length;
var enabledVhosts = vhosts.filter(function(v) { return v.enabled === '1'; }).length;
var style = E('style', {}, [
'.luci-tree-page { background: #111; min-height: 100vh; padding: 20px; font-family: monospace; }',
'.luci-tree-header { text-align: center; margin-bottom: 30px; }',
'.luci-tree-header h1 { color: #0f0; font-size: 24px; margin: 0 0 10px 0; }',
'.luci-tree-header p { color: #888; margin: 0; }',
'.luci-tree-stats { display: flex; justify-content: center; gap: 30px; margin: 20px 0; flex-wrap: wrap; }',
'.luci-tree-stat { text-align: center; padding: 10px 20px; background: #222; border-radius: 8px; }',
'.luci-tree-stat-value { font-size: 24px; color: #0ff; }',
'.luci-tree-stat-label { font-size: 12px; color: #888; }',
'.luci-tree-stats { display: flex; justify-content: center; gap: 20px; margin: 20px 0; flex-wrap: wrap; }',
'.luci-tree-stat { text-align: center; padding: 10px 15px; background: #222; border-radius: 8px; min-width: 80px; }',
'.luci-tree-stat-value { font-size: 20px; color: #0ff; }',
'.luci-tree-stat-label { font-size: 11px; color: #888; }',
'.luci-tree-search { margin: 20px auto; max-width: 400px; }',
'.luci-tree-search input { width: 100%; padding: 10px; background: #222; border: 1px solid #333; color: #fff; border-radius: 4px; box-sizing: border-box; }',
'.luci-tree-search input:focus { outline: none; border-color: #0f0; }',
'.luci-tree-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 15px; }',
'.luci-tree-tabs { display: flex; justify-content: center; gap: 10px; margin: 20px 0; flex-wrap: wrap; }',
'.luci-tree-tab { padding: 8px 16px; background: #222; border: 1px solid #333; border-radius: 4px; color: #888; cursor: pointer; }',
'.luci-tree-tab:hover { border-color: #0f0; color: #0f0; }',
'.luci-tree-tab.active { background: #0f0; color: #000; border-color: #0f0; }',
'.luci-tree-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 15px; }',
'.luci-tree-section { background: #1a1a1a; border-left: 3px solid #0f0; border-radius: 4px; padding: 15px; }',
'.luci-tree-section-title { color: #0f0; font-size: 16px; margin: 0 0 10px 0; border-bottom: 1px solid #333; padding-bottom: 8px; }',
'.luci-tree-item { padding: 4px 0; }',
'.luci-tree-section-title { color: #0f0; font-size: 14px; margin: 0 0 10px 0; border-bottom: 1px solid #333; padding-bottom: 8px; display: flex; justify-content: space-between; }',
'.luci-tree-section-count { color: #888; font-size: 12px; }',
'.luci-tree-item { padding: 3px 0; font-size: 13px; }',
'.luci-tree-item a { color: #0ff; text-decoration: none; }',
'.luci-tree-item a:hover { color: #fff; text-decoration: underline; }',
'.luci-tree-item::before { content: "- "; color: #555; }'
'.luci-tree-item::before { content: "- "; color: #555; }',
'.luci-tree-item .pkg { color: #666; font-size: 10px; margin-left: 5px; }',
'.luci-tree-panel { display: none; }',
'.luci-tree-panel.active { display: block; }',
'.luci-tree-container { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 15px; }',
'.luci-tree-container-item { padding: 8px 12px; background: #222; border-radius: 4px; display: flex; align-items: center; gap: 8px; }',
'.luci-tree-container-status { width: 8px; height: 8px; border-radius: 50%; }',
'.luci-tree-container-status.running { background: #0f0; }',
'.luci-tree-container-status.stopped { background: #f00; }',
'.luci-tree-vhost { padding: 8px 12px; background: #222; border-radius: 4px; margin-bottom: 8px; }',
'.luci-tree-vhost-domain { color: #0ff; }',
'.luci-tree-vhost-backend { color: #888; font-size: 11px; }',
'.luci-tree-refresh { margin-left: 10px; padding: 5px 10px; background: #333; border: none; color: #0f0; border-radius: 4px; cursor: pointer; }',
'.luci-tree-refresh:hover { background: #444; }'
].join('\n'));
var self = this;
var refreshBtn = E('button', {
'class': 'luci-tree-refresh',
'click': function() {
self.load().then(function(newData) {
var content = document.querySelector('.luci-tree-page');
if (content) {
dom.content(content.parentNode, self.render(newData));
}
});
}
}, 'Refresh');
var header = E('div', { 'class': 'luci-tree-header' }, [
E('h1', {}, 'SecuBox LuCI Navigation Tree'),
E('p', {}, 'Clickable map of all LuCI dashboards and modules')
E('h1', {}, ['SecuBox Navigation Tree ', refreshBtn]),
E('p', {}, 'Auto-generated map of all SecuBox components and services')
]);
var stats = E('div', { 'class': 'luci-tree-stats' }, [
var statsEl = E('div', { 'class': 'luci-tree-stats' }, [
E('div', { 'class': 'luci-tree-stat' }, [
E('div', { 'class': 'luci-tree-stat-value' }, String(TREE.length)),
E('div', { 'class': 'luci-tree-stat-value' }, String(categories.length)),
E('div', { 'class': 'luci-tree-stat-label' }, 'Categories')
]),
E('div', { 'class': 'luci-tree-stat' }, [
E('div', { 'class': 'luci-tree-stat-value' }, String(totalLinks)),
E('div', { 'class': 'luci-tree-stat-label' }, 'Total Links')
E('div', { 'class': 'luci-tree-stat-label' }, 'LuCI Apps')
]),
E('div', { 'class': 'luci-tree-stat' }, [
E('div', { 'class': 'luci-tree-stat-value' }, '60+'),
E('div', { 'class': 'luci-tree-stat-label' }, 'LuCI Apps')
E('div', { 'class': 'luci-tree-stat-value' }, String(stats.packages || 0)),
E('div', { 'class': 'luci-tree-stat-label' }, 'Packages')
]),
E('div', { 'class': 'luci-tree-stat' }, [
E('div', { 'class': 'luci-tree-stat-value' }, runningContainers + '/' + containers.length),
E('div', { 'class': 'luci-tree-stat-label' }, 'Containers')
]),
E('div', { 'class': 'luci-tree-stat' }, [
E('div', { 'class': 'luci-tree-stat-value' }, String(enabledVhosts)),
E('div', { 'class': 'luci-tree-stat-label' }, 'Vhosts')
])
]);
var tabs = E('div', { 'class': 'luci-tree-tabs' });
var tabNames = ['LuCI Apps', 'Containers', 'Vhosts'];
tabNames.forEach(function(name, idx) {
var tab = E('div', {
'class': 'luci-tree-tab' + (idx === 0 ? ' active' : ''),
'data-tab': idx,
'click': function(ev) {
document.querySelectorAll('.luci-tree-tab').forEach(function(t) { t.classList.remove('active'); });
document.querySelectorAll('.luci-tree-panel').forEach(function(p) { p.classList.remove('active'); });
ev.target.classList.add('active');
document.querySelector('.luci-tree-panel[data-panel="' + idx + '"]').classList.add('active');
}
}, name);
tabs.appendChild(tab);
});
var searchInput = E('input', {
'type': 'text',
'placeholder': 'Search modules...',
@ -206,22 +173,62 @@ return view.extend({
var search = E('div', { 'class': 'luci-tree-search' }, [searchInput]);
// Panel 0: LuCI Apps Grid
var grid = E('div', { 'class': 'luci-tree-grid' });
categories.forEach(function(category) {
if (!category.items || category.items.length === 0) return;
TREE.forEach(function(category) {
var section = E('div', { 'class': 'luci-tree-section' }, [
E('div', { 'class': 'luci-tree-section-title' }, category.cat)
E('div', { 'class': 'luci-tree-section-title' }, [
E('span', {}, category.cat),
E('span', { 'class': 'luci-tree-section-count' }, '(' + category.items.length + ')')
])
]);
category.items.forEach(function(item) {
section.appendChild(E('div', { 'class': 'luci-tree-item' }, [
var itemEl = E('div', { 'class': 'luci-tree-item' }, [
E('a', { 'href': '/cgi-bin/luci/' + item.path, 'target': '_blank' }, item.name)
]));
]);
if (item.package) {
itemEl.appendChild(E('span', { 'class': 'pkg' }, item.package));
}
section.appendChild(itemEl);
});
grid.appendChild(section);
});
return KissTheme.wrap([E('div', { 'class': 'luci-tree-page' }, [style, header, stats, search, grid])], 'admin/secubox/portal/luci-tree');
var panel0 = E('div', { 'class': 'luci-tree-panel active', 'data-panel': '0' }, [search, grid]);
// Panel 1: Containers
var containerGrid = E('div', { 'class': 'luci-tree-container' });
containers.forEach(function(c) {
containerGrid.appendChild(E('div', { 'class': 'luci-tree-container-item' }, [
E('div', { 'class': 'luci-tree-container-status ' + c.state }),
E('span', {}, c.name)
]));
});
var panel1 = E('div', { 'class': 'luci-tree-panel', 'data-panel': '1' }, [
E('h3', { 'style': 'color: #0f0; margin: 20px 0 10px 0;' }, 'LXC Containers (' + containers.length + ')'),
containerGrid
]);
// Panel 2: Vhosts
var vhostList = E('div', { 'style': 'max-height: 500px; overflow-y: auto; margin-top: 15px;' });
vhosts.forEach(function(v) {
if (!v.domain) return;
vhostList.appendChild(E('div', { 'class': 'luci-tree-vhost' }, [
E('div', { 'class': 'luci-tree-vhost-domain' }, [
E('a', { 'href': 'https://' + v.domain, 'target': '_blank', 'style': 'color: #0ff; text-decoration: none;' }, v.domain)
]),
E('div', { 'class': 'luci-tree-vhost-backend' }, 'Backend: ' + (v.backend || 'N/A') + (v.ssl === '1' ? ' | SSL' : ''))
]));
});
var panel2 = E('div', { 'class': 'luci-tree-panel', 'data-panel': '2' }, [
E('h3', { 'style': 'color: #0f0; margin: 20px 0 10px 0;' }, 'HAProxy Virtual Hosts (' + vhosts.length + ')'),
vhostList
]);
return E('div', { 'class': 'luci-tree-page' }, [style, header, statsEl, tabs, panel0, panel1, panel2]);
}
});

View File

@ -0,0 +1,347 @@
#!/bin/sh
# RPCD backend for SecuBox Portal - Generative LuCI Tree
. /usr/share/libubox/jshn.sh
# Discover LuCI menu entries from menu.d JSON files
discover_luci_menus() {
local menus=""
for f in /usr/share/luci/menu.d/*.json; do
[ -f "$f" ] || continue
# Extract paths from JSON - format: "admin/path": {...}
local paths=$(grep -oE '"admin/[^"]+":' "$f" 2>/dev/null | tr -d '":' | sort -u)
for p in $paths; do
menus="$menus $p"
done
done
echo "$menus" | tr ' ' '\n' | sort -u | grep -v '^$'
}
# Discover installed SecuBox packages
discover_packages() {
opkg list-installed 2>/dev/null | grep -E '^(secubox|luci-app-)' | awk '{print $1}'
}
# Discover LXC containers
discover_containers() {
ls /srv/lxc/ 2>/dev/null | while read c; do
local state="stopped"
if lxc-info -n "$c" 2>/dev/null | grep -q "State:.*RUNNING"; then
state="running"
fi
echo "$c:$state"
done
}
# Discover HAProxy vhosts
discover_vhosts() {
uci show haproxy 2>/dev/null | grep "=vhost" | sed 's/haproxy\.//;s/=vhost//' | while read vh; do
local domain=$(uci -q get haproxy.$vh.domain)
local backend=$(uci -q get haproxy.$vh.backend)
local enabled=$(uci -q get haproxy.$vh.enabled)
[ "$enabled" = "1" ] && echo "$domain:$backend"
done
}
# Discover running services from init.d
discover_services() {
for f in /etc/init.d/*; do
[ -x "$f" ] || continue
local name=$(basename "$f")
# Skip system services
case "$name" in
boot|done|rcS|umount|sysctl|urandom|gpio*|led*|log*) continue ;;
esac
local enabled="0"
local running="0"
[ -L "/etc/rc.d/S"*"$name" ] 2>/dev/null && enabled="1"
"$f" status >/dev/null 2>&1 && running="1"
echo "$name:$enabled:$running"
done 2>/dev/null
}
# Build tree categories from LuCI menus
build_tree() {
json_init
json_add_array "categories"
# SecuBox Core
json_add_object ""
json_add_string "cat" "SecuBox Core"
json_add_array "items"
for path in admin/secubox/dashboard admin/secubox/apps admin/secubox/modules admin/secubox/alerts admin/secubox/settings; do
if [ -f "/usr/share/luci/menu.d/"*".json" ]; then
json_add_object ""
json_add_string "name" "$(echo "$path" | sed 's|.*/||' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')"
json_add_string "path" "$path"
json_close_object
fi
done
json_close_array
json_close_object
# Discover all luci-app-* packages and group them
local apps=$(opkg list-installed 2>/dev/null | grep "^luci-app-" | awk '{print $1}' | sort)
# Security Apps
json_add_object ""
json_add_string "cat" "Security"
json_add_array "items"
for app in $apps; do
case "$app" in
luci-app-crowdsec*|luci-app-mitmproxy*|luci-app-guardian*|luci-app-dnsguard*|luci-app-threat*|luci-app-wazuh*|luci-app-vortex*)
local name=$(echo "$app" | sed 's/luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')
json_add_object ""
json_add_string "name" "$name"
json_add_string "path" "admin/services/$(echo "$app" | sed 's/luci-app-//')"
json_add_string "package" "$app"
json_close_object
;;
esac
done
json_close_array
json_close_object
# Media & Streaming Apps
json_add_object ""
json_add_string "cat" "Media & Streaming"
json_add_array "items"
for app in $apps; do
case "$app" in
luci-app-jellyfin*|luci-app-lyrion*|luci-app-streamlit*|luci-app-peertube*|luci-app-magicmirror*)
local name=$(echo "$app" | sed 's/luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')
json_add_object ""
json_add_string "name" "$name"
json_add_string "path" "admin/services/$(echo "$app" | sed 's/luci-app-//')"
json_add_string "package" "$app"
json_close_object
;;
esac
done
json_close_array
json_close_object
# Network & Proxy Apps
json_add_object ""
json_add_string "cat" "Network & Proxy"
json_add_array "items"
for app in $apps; do
case "$app" in
luci-app-haproxy*|luci-app-wireguard*|luci-app-tor*|luci-app-cdn*|luci-app-exposure*|luci-app-dns-provider*)
local name=$(echo "$app" | sed 's/luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')
json_add_object ""
json_add_string "name" "$name"
json_add_string "path" "admin/services/$(echo "$app" | sed 's/luci-app-//')"
json_add_string "package" "$app"
json_close_object
;;
esac
done
json_close_array
json_close_object
# Development & CMS Apps
json_add_object ""
json_add_string "cat" "Development & CMS"
json_add_array "items"
for app in $apps; do
case "$app" in
luci-app-gitea*|luci-app-hexo*|luci-app-metablog*|luci-app-metabol*)
local name=$(echo "$app" | sed 's/luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')
json_add_object ""
json_add_string "name" "$name"
json_add_string "path" "admin/services/$(echo "$app" | sed 's/luci-app-//')"
json_add_string "package" "$app"
json_close_object
;;
esac
done
json_close_array
json_close_object
# IoT & Home Automation Apps
json_add_object ""
json_add_string "cat" "IoT & Home"
json_add_array "items"
for app in $apps; do
case "$app" in
luci-app-domoticz*|luci-app-zigbee*|luci-app-iot*|luci-app-mqtt*)
local name=$(echo "$app" | sed 's/luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')
json_add_object ""
json_add_string "name" "$name"
json_add_string "path" "admin/services/$(echo "$app" | sed 's/luci-app-//')"
json_add_string "package" "$app"
json_close_object
;;
esac
done
json_close_array
json_close_object
# AI & Chat Apps
json_add_object ""
json_add_string "cat" "AI & Communication"
json_add_array "items"
for app in $apps; do
case "$app" in
luci-app-localai*|luci-app-ollama*|luci-app-simplex*|luci-app-gotosocial*|luci-app-ai-*)
local name=$(echo "$app" | sed 's/luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')
json_add_object ""
json_add_string "name" "$name"
json_add_string "path" "admin/services/$(echo "$app" | sed 's/luci-app-//')"
json_add_string "package" "$app"
json_close_object
;;
esac
done
json_close_array
json_close_object
# System & Management Apps
json_add_object ""
json_add_string "cat" "System & Management"
json_add_array "items"
for app in $apps; do
case "$app" in
luci-app-cloner*|luci-app-backup*|luci-app-system*|luci-app-config-advisor*|luci-app-service-registry*)
local name=$(echo "$app" | sed 's/luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')
json_add_object ""
json_add_string "name" "$name"
json_add_string "path" "admin/services/$(echo "$app" | sed 's/luci-app-//')"
json_add_string "package" "$app"
json_close_object
;;
esac
done
json_close_array
json_close_object
# Other SecuBox Apps (catch-all)
json_add_object ""
json_add_string "cat" "Other SecuBox Apps"
json_add_array "items"
for app in $apps; do
case "$app" in
luci-app-crowdsec*|luci-app-mitmproxy*|luci-app-guardian*|luci-app-dnsguard*|luci-app-threat*|luci-app-wazuh*|luci-app-vortex*) continue ;;
luci-app-jellyfin*|luci-app-lyrion*|luci-app-streamlit*|luci-app-peertube*|luci-app-magicmirror*) continue ;;
luci-app-haproxy*|luci-app-wireguard*|luci-app-tor*|luci-app-cdn*|luci-app-exposure*|luci-app-dns-provider*) continue ;;
luci-app-gitea*|luci-app-hexo*|luci-app-metablog*|luci-app-metabol*) continue ;;
luci-app-domoticz*|luci-app-zigbee*|luci-app-iot*|luci-app-mqtt*) continue ;;
luci-app-localai*|luci-app-ollama*|luci-app-simplex*|luci-app-gotosocial*|luci-app-ai-*) continue ;;
luci-app-cloner*|luci-app-backup*|luci-app-system*|luci-app-config-advisor*|luci-app-service-registry*) continue ;;
luci-app-secubox*|luci-app-*secubox*)
local name=$(echo "$app" | sed 's/luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)$i=toupper(substr($i,1,1))tolower(substr($i,2))}1')
json_add_object ""
json_add_string "name" "$name"
json_add_string "path" "admin/secubox/$(echo "$app" | sed 's/luci-app-secubox-//' | sed 's/luci-app-//')"
json_add_string "package" "$app"
json_close_object
;;
esac
done
json_close_array
json_close_object
json_close_array
# Add stats
local pkg_count=$(echo "$apps" | wc -w)
local container_count=$(ls /srv/lxc/ 2>/dev/null | wc -l)
local vhost_count=$(uci show haproxy 2>/dev/null | grep "=vhost" | wc -l)
json_add_object "stats"
json_add_int "packages" "$pkg_count"
json_add_int "containers" "$container_count"
json_add_int "vhosts" "$vhost_count"
json_close_object
json_dump
}
# Method: get_tree
method_get_tree() {
build_tree
}
# Method: get_containers
method_get_containers() {
json_init
json_add_array "containers"
for c in $(ls /srv/lxc/ 2>/dev/null); do
json_add_object ""
json_add_string "name" "$c"
if lxc-info -n "$c" 2>/dev/null | grep -q "State:.*RUNNING"; then
json_add_string "state" "running"
else
json_add_string "state" "stopped"
fi
json_close_object
done
json_close_array
json_dump
}
# Method: get_vhosts
method_get_vhosts() {
json_init
json_add_array "vhosts"
for vh in $(uci show haproxy 2>/dev/null | grep "=vhost" | sed 's/haproxy\.//;s/=vhost//'); do
local domain=$(uci -q get haproxy.$vh.domain)
local backend=$(uci -q get haproxy.$vh.backend)
local enabled=$(uci -q get haproxy.$vh.enabled)
local ssl=$(uci -q get haproxy.$vh.ssl)
json_add_object ""
json_add_string "id" "$vh"
json_add_string "domain" "$domain"
json_add_string "backend" "$backend"
json_add_string "enabled" "${enabled:-0}"
json_add_string "ssl" "${ssl:-0}"
json_close_object
done
json_close_array
json_dump
}
# List available methods
list_methods() {
json_init
json_add_object "get_tree"
json_close_object
json_add_object "get_containers"
json_close_object
json_add_object "get_vhosts"
json_close_object
json_dump
}
# Main dispatcher
case "$1" in
list)
list_methods
;;
call)
case "$2" in
get_tree)
method_get_tree
;;
get_containers)
method_get_containers
;;
get_vhosts)
method_get_vhosts
;;
*)
echo '{"error":"Method not found"}'
;;
esac
;;
*)
echo '{"error":"Invalid action"}'
;;
esac

View File

@ -7,6 +7,11 @@
"/bin/sh": ["exec"]
},
"ubus": {
"luci.secubox-portal": [
"get_tree",
"get_containers",
"get_vhosts"
],
"luci.secubox": [
"modules",
"getModules",
@ -33,6 +38,11 @@
"description": "Public access for SecuBox Portal",
"read": {
"ubus": {
"luci.secubox-portal": [
"get_tree",
"get_containers",
"get_vhosts"
],
"luci.secubox": [
"modules",
"getModules",

View File

@ -6,7 +6,7 @@ config peertube 'main'
option timezone 'Europe/Paris'
config peertube 'server'
option hostname 'peertube.local'
option hostname 'tube.gk2.secubox.in'
option port '9001'
option https '1'
option webserver_hostname ''