fix(luci): Performance and UX improvements for exposure and portal
- Optimize exposure RPCD: O(n) single-pass awk parsing for vhost_list and ssl_list (fixes XHR timeout on 200+ vhosts) - Fix portal tree URLs: Use get_menu_path() to read actual LuCI menu paths from JSON instead of hardcoded paths - Add Downloads category to portal tree (torrent, droplet patterns) - Add new apps to System category (config-vault, reporter, smtp-relay, rtty, dpi-dual, metacatalog) - Enhance KISS theme menu: Add Downloads, Monitoring categories - Fix Lyrion URL: Use HTTPS vhost instead of dynamic port URL Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b08e71fa7f
commit
d0cd42e2a1
@ -270,44 +270,52 @@ case "$1" in
|
||||
;;
|
||||
|
||||
ssl_list)
|
||||
TMP_SSLLIST="/tmp/exposure_ssllist_$$"
|
||||
> "$TMP_SSLLIST"
|
||||
|
||||
# Read from HAProxy UCI config (vhosts with their backends)
|
||||
for vhost in $(uci show haproxy 2>/dev/null | grep "=vhost$" | cut -d'.' -f2 | cut -d'=' -f1); do
|
||||
domain=$(uci -q get "haproxy.${vhost}.domain")
|
||||
backend=$(uci -q get "haproxy.${vhost}.backend")
|
||||
enabled=$(uci -q get "haproxy.${vhost}.enabled")
|
||||
|
||||
[ "$enabled" != "1" ] && continue
|
||||
[ -z "$domain" ] && continue
|
||||
|
||||
# Get server address from backend config
|
||||
server=""
|
||||
if [ -n "$backend" ]; then
|
||||
server=$(uci -q get "haproxy.${backend}.server" 2>/dev/null | head -1 | awk '{print $2}')
|
||||
fi
|
||||
|
||||
echo "${backend:-$vhost}|${domain}|${server:-N/A}" >> "$TMP_SSLLIST"
|
||||
done
|
||||
|
||||
json_init
|
||||
json_add_array "backends"
|
||||
|
||||
if [ -s "$TMP_SSLLIST" ]; then
|
||||
while IFS='|' read service domain server; do
|
||||
[ -z "$service" ] && continue
|
||||
json_add_object ""
|
||||
json_add_string "service" "$service"
|
||||
json_add_string "domain" "$domain"
|
||||
json_add_string "backend" "$server"
|
||||
json_close_object
|
||||
done < "$TMP_SSLLIST"
|
||||
fi
|
||||
rm -f "$TMP_SSLLIST"
|
||||
|
||||
json_close_array
|
||||
json_dump
|
||||
# OPTIMIZED: Single-pass awk parsing
|
||||
uci show haproxy 2>/dev/null | awk '
|
||||
BEGIN {
|
||||
printf "{\"backends\":["
|
||||
first = 1
|
||||
}
|
||||
/=vhost$/ {
|
||||
if (vh_domain != "" && vh_enabled == "1") {
|
||||
if (first == 0) printf ","
|
||||
first = 0
|
||||
printf "{\"service\":\"%s\",\"domain\":\"%s\",\"backend\":\"%s\"}",
|
||||
(vh_backend != "" ? vh_backend : vh_id), vh_domain, "N/A"
|
||||
}
|
||||
gsub(/^haproxy\./, "", $0)
|
||||
gsub(/=vhost$/, "", $0)
|
||||
vh_id = $0
|
||||
vh_domain = ""
|
||||
vh_backend = ""
|
||||
vh_enabled = "0"
|
||||
in_vhost = 1
|
||||
}
|
||||
/=backend$/ || /=server$/ { in_vhost = 0 }
|
||||
/\.domain=/ && in_vhost {
|
||||
gsub(/.*\.domain=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_domain = $0
|
||||
}
|
||||
/\.backend=/ && in_vhost {
|
||||
gsub(/.*\.backend=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_backend = $0
|
||||
}
|
||||
/\.enabled=/ && in_vhost {
|
||||
gsub(/.*\.enabled=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_enabled = $0
|
||||
}
|
||||
END {
|
||||
if (vh_domain != "" && vh_enabled == "1") {
|
||||
if (first == 0) printf ","
|
||||
printf "{\"service\":\"%s\",\"domain\":\"%s\",\"backend\":\"%s\"}",
|
||||
(vh_backend != "" ? vh_backend : vh_id), vh_domain, "N/A"
|
||||
}
|
||||
printf "]}"
|
||||
}
|
||||
'
|
||||
;;
|
||||
|
||||
get_config)
|
||||
@ -479,80 +487,171 @@ case "$1" in
|
||||
;;
|
||||
|
||||
vhost_list)
|
||||
json_init
|
||||
# OPTIMIZED: Single-pass awk parsing instead of O(n²) uci calls
|
||||
uci show haproxy 2>/dev/null | awk '
|
||||
BEGIN {
|
||||
printf "{\"haproxy\":["
|
||||
first_vh = 1
|
||||
}
|
||||
|
||||
# HAProxy vhosts (domain -> backend with resolved port)
|
||||
json_add_array "haproxy"
|
||||
for vhost in $(uci show haproxy 2>/dev/null | grep "=vhost$" | cut -d'.' -f2 | cut -d'=' -f1); do
|
||||
domain=$(uci -q get "haproxy.${vhost}.domain")
|
||||
backend=$(uci -q get "haproxy.${vhost}.backend")
|
||||
enabled=$(uci -q get "haproxy.${vhost}.enabled")
|
||||
ssl=$(uci -q get "haproxy.${vhost}.ssl")
|
||||
acme=$(uci -q get "haproxy.${vhost}.acme")
|
||||
# Collect server backend->port mappings
|
||||
/\.backend=/ && /=server$/ == 0 {
|
||||
# This is a vhost or backend .backend= line, skip for server collection
|
||||
}
|
||||
/=server$/ {
|
||||
gsub(/^haproxy\./, "", $0)
|
||||
gsub(/=server$/, "", $0)
|
||||
current_srv = $0
|
||||
}
|
||||
/^haproxy\.[^.]+\.backend=/ && prev_type == "server" {
|
||||
gsub(/^haproxy\.[^.]+\.backend=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
srv_backends[current_srv] = $0
|
||||
}
|
||||
/^haproxy\.[^.]+\.port=/ && prev_type == "server" {
|
||||
gsub(/^haproxy\.[^.]+\.port=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
srv_ports[current_srv] = $0
|
||||
}
|
||||
|
||||
[ -z "$domain" ] && continue
|
||||
# Track section type
|
||||
/=vhost$/ { prev_type = "vhost" }
|
||||
/=server$/ { prev_type = "server" }
|
||||
/=backend$/ { prev_type = "backend" }
|
||||
|
||||
# Check for original_backend (when mitmproxy is intercepting)
|
||||
original_backend=$(uci -q get "haproxy.${vhost}.original_backend")
|
||||
resolve_backend="${original_backend:-$backend}"
|
||||
# Process vhosts
|
||||
/=vhost$/ {
|
||||
# Output previous vhost
|
||||
if (vh_id != "" && vh_domain != "") {
|
||||
if (first_vh == 0) printf ","
|
||||
first_vh = 0
|
||||
# Resolve backend port
|
||||
resolve_be = (vh_orig_be != "") ? vh_orig_be : vh_backend
|
||||
port = 0
|
||||
for (s in srv_backends) {
|
||||
if (srv_backends[s] == resolve_be && srv_ports[s] != "") {
|
||||
port = srv_ports[s]
|
||||
break
|
||||
}
|
||||
}
|
||||
printf "{\"id\":\"%s\",\"domain\":\"%s\",\"backend\":\"%s\",\"backend_port\":%d,\"ssl\":%s,\"acme\":%s,\"enabled\":%s}",
|
||||
vh_id, vh_domain, resolve_be, port,
|
||||
(vh_ssl == "1" ? "true" : "false"),
|
||||
(vh_acme == "1" ? "true" : "false"),
|
||||
(vh_enabled == "1" ? "true" : "false")
|
||||
}
|
||||
# Start new vhost
|
||||
gsub(/^haproxy\./, "", $0)
|
||||
gsub(/=vhost$/, "", $0)
|
||||
vh_id = $0
|
||||
vh_domain = ""
|
||||
vh_backend = ""
|
||||
vh_orig_be = ""
|
||||
vh_ssl = "0"
|
||||
vh_acme = "0"
|
||||
vh_enabled = "0"
|
||||
}
|
||||
/\.domain=/ && prev_type == "vhost" {
|
||||
gsub(/.*\.domain=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_domain = $0
|
||||
}
|
||||
/\.backend=/ && prev_type == "vhost" {
|
||||
gsub(/.*\.backend=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_backend = $0
|
||||
}
|
||||
/\.original_backend=/ && prev_type == "vhost" {
|
||||
gsub(/.*\.original_backend=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_orig_be = $0
|
||||
}
|
||||
/\.ssl=/ && prev_type == "vhost" {
|
||||
gsub(/.*\.ssl=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_ssl = $0
|
||||
}
|
||||
/\.acme=/ && prev_type == "vhost" {
|
||||
gsub(/.*\.acme=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_acme = $0
|
||||
}
|
||||
/\.enabled=/ && prev_type == "vhost" {
|
||||
gsub(/.*\.enabled=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
vh_enabled = $0
|
||||
}
|
||||
|
||||
# Resolve backend port from the target backend
|
||||
backend_port=""
|
||||
if [ -n "$resolve_backend" ]; then
|
||||
# Try inline server option: 'name IP:PORT check'
|
||||
server_line=$(uci -q get "haproxy.${resolve_backend}.server" 2>/dev/null)
|
||||
if [ -n "$server_line" ]; then
|
||||
backend_port=$(echo "$server_line" | awk '{print $2}' | grep -o ':[0-9]*' | tr -d ':')
|
||||
fi
|
||||
# Try server sections referencing this backend
|
||||
if [ -z "$backend_port" ]; then
|
||||
for srv in $(uci show haproxy 2>/dev/null | grep "=server$" | cut -d'.' -f2 | cut -d'=' -f1); do
|
||||
srv_backend=$(uci -q get "haproxy.${srv}.backend")
|
||||
if [ "$srv_backend" = "$resolve_backend" ]; then
|
||||
backend_port=$(uci -q get "haproxy.${srv}.port")
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
END {
|
||||
# Output last vhost
|
||||
if (vh_id != "" && vh_domain != "") {
|
||||
if (first_vh == 0) printf ","
|
||||
resolve_be = (vh_orig_be != "") ? vh_orig_be : vh_backend
|
||||
port = 0
|
||||
for (s in srv_backends) {
|
||||
if (srv_backends[s] == resolve_be && srv_ports[s] != "") {
|
||||
port = srv_ports[s]
|
||||
break
|
||||
}
|
||||
}
|
||||
printf "{\"id\":\"%s\",\"domain\":\"%s\",\"backend\":\"%s\",\"backend_port\":%d,\"ssl\":%s,\"acme\":%s,\"enabled\":%s}",
|
||||
vh_id, vh_domain, resolve_be, port,
|
||||
(vh_ssl == "1" ? "true" : "false"),
|
||||
(vh_acme == "1" ? "true" : "false"),
|
||||
(vh_enabled == "1" ? "true" : "false")
|
||||
}
|
||||
printf "],"
|
||||
}
|
||||
'
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "id" "$vhost"
|
||||
json_add_string "domain" "$domain"
|
||||
json_add_string "backend" "${resolve_backend:-${backend:-}}"
|
||||
json_add_int "backend_port" "${backend_port:-0}"
|
||||
json_add_boolean "ssl" "${ssl:-0}"
|
||||
json_add_boolean "acme" "${acme:-0}"
|
||||
json_add_boolean "enabled" "${enabled:-0}"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
# uhttpd vhosts (non-main instances)
|
||||
json_add_array "uhttpd"
|
||||
for section in $(uci show uhttpd 2>/dev/null | grep "=uhttpd$" | cut -d'.' -f2 | cut -d'=' -f1); do
|
||||
[ "$section" = "main" ] && continue
|
||||
[ "$section" = "acme" ] && continue
|
||||
|
||||
listen=$(uci -q get "uhttpd.${section}.listen_http")
|
||||
home=$(uci -q get "uhttpd.${section}.home")
|
||||
[ -z "$listen" ] && continue
|
||||
|
||||
port=$(echo "$listen" | grep -o '[0-9]*$')
|
||||
|
||||
# Derive friendly name from section id
|
||||
fname=$(echo "$section" | sed 's/^metablog_site_//' | sed 's/_/ /g')
|
||||
|
||||
json_add_object ""
|
||||
json_add_string "id" "$section"
|
||||
json_add_int "port" "${port:-0}"
|
||||
json_add_string "name" "$fname"
|
||||
json_add_string "home" "${home:-}"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_dump
|
||||
# uhttpd vhosts - also optimized with awk
|
||||
uci show uhttpd 2>/dev/null | awk '
|
||||
BEGIN {
|
||||
printf "\"uhttpd\":["
|
||||
first = 1
|
||||
}
|
||||
/=uhttpd$/ {
|
||||
if (section != "" && section != "main" && section != "acme" && listen != "") {
|
||||
if (first == 0) printf ","
|
||||
first = 0
|
||||
# Extract port from listen
|
||||
match(listen, /[0-9]+$/)
|
||||
port = substr(listen, RSTART, RLENGTH)
|
||||
gsub(/^metablog_site_/, "", section)
|
||||
gsub(/_/, " ", section)
|
||||
printf "{\"id\":\"%s\",\"port\":%s,\"name\":\"%s\",\"home\":\"%s\"}",
|
||||
orig_section, (port != "" ? port : "0"), section, home
|
||||
}
|
||||
gsub(/^uhttpd\./, "", $0)
|
||||
gsub(/=uhttpd$/, "", $0)
|
||||
orig_section = $0
|
||||
section = $0
|
||||
listen = ""
|
||||
home = ""
|
||||
}
|
||||
/\.listen_http=/ {
|
||||
gsub(/.*\.listen_http=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
listen = $0
|
||||
}
|
||||
/\.home=/ {
|
||||
gsub(/.*\.home=/, "", $0)
|
||||
gsub(/'\''/, "", $0)
|
||||
home = $0
|
||||
}
|
||||
END {
|
||||
if (section != "" && section != "main" && section != "acme" && listen != "") {
|
||||
if (first == 0) printf ","
|
||||
match(listen, /[0-9]+$/)
|
||||
port = substr(listen, RSTART, RLENGTH)
|
||||
gsub(/^metablog_site_/, "", section)
|
||||
gsub(/_/, " ", section)
|
||||
printf "{\"id\":\"%s\",\"port\":%s,\"name\":\"%s\",\"home\":\"%s\"}",
|
||||
orig_section, (port != "" ? port : "0"), section, home
|
||||
}
|
||||
printf "]}"
|
||||
}
|
||||
'
|
||||
;;
|
||||
|
||||
emancipate)
|
||||
|
||||
@ -145,13 +145,13 @@ return view.extend({
|
||||
E('h3', {}, _('Web Interface')),
|
||||
E('div', { 'style': 'margin-bottom:12px' }, [
|
||||
E('a', {
|
||||
'href': 'http://' + window.location.hostname + ':' + (s.port || 9000),
|
||||
'href': 'https://lyrion.gk2.secubox.in/',
|
||||
'target': '_blank',
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'style': 'margin-right:8px'
|
||||
}, _('Open Lyrion Web UI')),
|
||||
E('span', { 'style': 'color:#888' },
|
||||
'http://' + window.location.hostname + ':' + (s.port || 9000))
|
||||
'https://lyrion.gk2.secubox.in/')
|
||||
])
|
||||
]),
|
||||
|
||||
|
||||
@ -4,6 +4,20 @@
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
# Get actual menu path for a luci-app package
|
||||
get_menu_path() {
|
||||
local pkg="$1"
|
||||
local menu_file="/usr/share/luci/menu.d/${pkg}.json"
|
||||
if [ -f "$menu_file" ]; then
|
||||
local path=$(grep -o '"admin/[^"]*"' "$menu_file" | head -1 | tr -d '"')
|
||||
if [ -n "$path" ]; then
|
||||
echo "$path"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
echo "admin/services/$(echo "$pkg" | sed 's/luci-app-//')"
|
||||
}
|
||||
|
||||
# Discover LuCI menu entries from menu.d JSON files
|
||||
discover_luci_menus() {
|
||||
local menus=""
|
||||
@ -90,11 +104,11 @@ build_tree() {
|
||||
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*)
|
||||
luci-app-crowdsec*|luci-app-mitmproxy*|luci-app-guardian*|luci-app-dnsguard*|luci-app-threat*|luci-app-wazuh*|luci-app-vortex*|luci-app-firewall*|luci-app-device-intel*|luci-app-security*)
|
||||
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 "path" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
@ -109,11 +123,11 @@ build_tree() {
|
||||
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*)
|
||||
luci-app-jellyfin*|luci-app-lyrion*|luci-app-streamlit*|luci-app-peertube*|luci-app-magicmirror*|luci-app-media-flow*|luci-app-icecast*|luci-app-webradio*|luci-app-mmpm*)
|
||||
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 "path" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
@ -128,11 +142,11 @@ build_tree() {
|
||||
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*)
|
||||
luci-app-haproxy*|luci-app-wireguard*|luci-app-tor*|luci-app-cdn*|luci-app-exposure*|luci-app-dns-provider*|luci-app-vhost*|luci-app-bandwidth*|luci-app-traffic*|luci-app-network-modes*|luci-app-ksmbd*)
|
||||
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 "path" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
@ -151,7 +165,7 @@ build_tree() {
|
||||
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 "path" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
@ -166,11 +180,11 @@ build_tree() {
|
||||
json_add_array "items"
|
||||
for app in $apps; do
|
||||
case "$app" in
|
||||
luci-app-domoticz*|luci-app-zigbee*|luci-app-iot*|luci-app-mqtt*)
|
||||
luci-app-domoticz*|luci-app-zigbee*|luci-app-iot*|luci-app-mqtt*|luci-app-picobrew*)
|
||||
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 "path" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
@ -185,11 +199,11 @@ build_tree() {
|
||||
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-*|luci-app-voip*|luci-app-jabber*|luci-app-jitsi*|luci-app-mail*|luci-app-nextcloud*|luci-app-webradio*)
|
||||
luci-app-localai*|luci-app-ollama*|luci-app-simplex*|luci-app-gotosocial*|luci-app-ai-*|luci-app-voip*|luci-app-jabber*|luci-app-jitsi*|luci-app-mailserver*|luci-app-nextcloud*|luci-app-matrix*|luci-app-cyberfeed*)
|
||||
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 "path" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
@ -204,11 +218,11 @@ build_tree() {
|
||||
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*)
|
||||
luci-app-cloner*|luci-app-backup*|luci-app-system*|luci-app-config-advisor*|luci-app-service-registry*|luci-app-watchdog*|luci-app-glances*|luci-app-netdata*|luci-app-package-manager*|luci-app-master-link*|luci-app-uhttpd*|luci-app-config-vault*|luci-app-reporter*|luci-app-smtp-relay*|luci-app-rtty*|luci-app-dpi-dual*|luci-app-metacatalog*)
|
||||
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 "path" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
@ -217,24 +231,36 @@ build_tree() {
|
||||
json_close_array
|
||||
json_close_object
|
||||
|
||||
# Other SecuBox Apps (catch-all)
|
||||
# Downloads Apps
|
||||
json_add_object ""
|
||||
json_add_string "cat" "Other SecuBox Apps"
|
||||
json_add_string "cat" "Downloads"
|
||||
json_add_array "items"
|
||||
for app in $apps; do
|
||||
case "$app" in
|
||||
luci-app-torrent*|luci-app-droplet*|luci-app-aria*|luci-app-transmission*|luci-app-nzb*|luci-app-sabnzbd*)
|
||||
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" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
esac
|
||||
done
|
||||
json_close_array
|
||||
json_close_object
|
||||
|
||||
# SecuBox Core Apps
|
||||
json_add_object ""
|
||||
json_add_string "cat" "SecuBox Core"
|
||||
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-*|luci-app-voip*|luci-app-jabber*|luci-app-jitsi*|luci-app-mail*|luci-app-nextcloud*|luci-app-webradio*) 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 "path" "$(get_menu_path "$app")"
|
||||
json_add_string "package" "$app"
|
||||
json_close_object
|
||||
;;
|
||||
|
||||
@ -96,7 +96,7 @@ var KissThemeClass = baseclass.extend({
|
||||
]},
|
||||
{ icon: '📶', name: 'Traffic Shaper', path: 'admin/secubox/network/traffic-shaper' },
|
||||
{ icon: '📡', name: 'Bandwidth', path: 'admin/secubox/network/bandwidth-manager' },
|
||||
{ icon: '🌐', name: 'Network Modes', path: 'admin/secubox/network/network-modes' },
|
||||
{ icon: '🌐', name: 'Network Modes', path: 'admin/secubox/network/modes' },
|
||||
{ icon: '🔌', name: 'Interfaces', path: 'admin/network/network' },
|
||||
{ icon: '🔧', name: 'Net Diagnostics', path: 'admin/services/network-diagnostics' }
|
||||
]},
|
||||
@ -119,6 +119,7 @@ var KissThemeClass = baseclass.extend({
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
{ cat: 'Communication', icon: '💬', collapsed: true, items: [
|
||||
{ icon: '✉️', name: 'Mail Server', path: 'admin/services/mailserver' },
|
||||
{ icon: '📧', name: 'SMTP Relay', path: 'admin/secubox/system/smtp-relay' },
|
||||
{ icon: '💬', name: 'Jabber/XMPP', path: 'admin/services/jabber' },
|
||||
{ icon: '🔐', name: 'Matrix', path: 'admin/services/matrix' },
|
||||
{ icon: '🔒', name: 'SimpleX', path: 'admin/services/simplex' },
|
||||
@ -145,7 +146,10 @@ var KissThemeClass = baseclass.extend({
|
||||
{ name: 'Settings', path: 'admin/services/metablogizer/settings' }
|
||||
]},
|
||||
{ icon: '🎯', name: 'Streamlit', path: 'admin/services/streamlit' },
|
||||
{ icon: '🔧', name: 'Streamlit Forge', path: 'admin/services/streamlit-forge' },
|
||||
{ icon: '📰', name: 'CyberFeed', path: 'admin/services/cyberfeed' },
|
||||
{ icon: '📚', name: 'Meta Catalog', path: 'admin/secubox/metacatalog' },
|
||||
{ icon: '🎭', name: 'Avatar Tap', path: 'admin/services/avatar-tap' },
|
||||
{ icon: '🏠', name: 'Domoticz', path: 'admin/services/domoticz' },
|
||||
{ icon: '🍺', name: 'PicoBrew', path: 'admin/services/picobrew' }
|
||||
]},
|
||||
@ -168,13 +172,12 @@ var KissThemeClass = baseclass.extend({
|
||||
// P2P & MESH - Distributed networking
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
{ cat: 'P2P & Mesh', icon: '🔗', collapsed: true, items: [
|
||||
{ icon: '🔗', name: 'Master Link', path: 'admin/secubox/master-link' },
|
||||
{ icon: '🔗', name: 'Master Link', path: 'admin/services/secubox-mesh' },
|
||||
{ icon: '🌐', name: 'P2P Network', path: 'admin/services/secubox-p2p' },
|
||||
{ icon: '🔗', name: 'Mesh Network', path: 'admin/services/secubox-mesh' },
|
||||
{ icon: '📡', name: 'Exposure', path: 'admin/services/exposure' },
|
||||
{ icon: '📡', name: 'Exposure', path: 'admin/secubox/network/exposure' },
|
||||
{ icon: '📋', name: 'Service Registry', path: 'admin/services/service-registry' },
|
||||
{ icon: '☁️', name: 'SaaS Relay', path: 'admin/services/saas-relay' },
|
||||
{ icon: '🌳', name: 'Netifyd', path: 'admin/services/secubox-netifyd' }
|
||||
{ icon: '🌳', name: 'Netifyd', path: 'admin/secubox/netifyd' }
|
||||
]},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
@ -187,7 +190,31 @@ var KissThemeClass = baseclass.extend({
|
||||
{ icon: '📁', name: 'File Sharing', path: 'admin/services/ksmbd' },
|
||||
{ icon: '🌳', name: 'LuCI Menu', path: 'admin/secubox/luci-tree' },
|
||||
{ icon: '🔧', name: 'Software', path: 'admin/system/opkg' },
|
||||
{ icon: '🖥️', name: 'uhttpd', path: 'admin/services/uhttpd' }
|
||||
{ icon: '🖥️', name: 'uhttpd', path: 'admin/services/uhttpd' },
|
||||
{ icon: '🔐', name: 'Config Vault', path: 'admin/secubox/system/config-vault' },
|
||||
{ icon: '📋', name: 'Reporter', path: 'admin/secubox/system/reporter' },
|
||||
{ icon: '🐕', name: 'Watchdog', path: 'admin/secubox/system/watchdog' },
|
||||
{ icon: '🖥️', name: 'Remote RTTY', path: 'admin/secubox/system/system-hub/rtty-remote' }
|
||||
]},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// DOWNLOADS - Torrent and Usenet clients
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
{ cat: 'Downloads', icon: '📥', collapsed: true, items: [
|
||||
{ icon: '🧲', name: 'Torrent', path: 'admin/services/torrent' },
|
||||
{ icon: '💧', name: 'Droplet', path: 'admin/services/droplet' },
|
||||
{ icon: '🌊', name: 'WebTorrent', path: 'admin/services/webtorrent' }
|
||||
]},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// MONITORING - System and network monitoring
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
{ cat: 'Monitoring', icon: '📈', collapsed: true, items: [
|
||||
{ icon: '👁️', name: 'Glances', path: 'admin/secubox/monitoring/glances' },
|
||||
{ icon: '📊', name: 'Netdata', path: 'admin/secubox/monitoring/netdata' },
|
||||
{ icon: '🔍', name: 'Device Intel', path: 'admin/secubox/device-intel' },
|
||||
{ icon: '📡', name: 'Threat Analyst', path: 'admin/services/threat-analyst' },
|
||||
{ icon: '🔬', name: 'DPI Dual', path: 'admin/secubox/dpi-dual' }
|
||||
]}
|
||||
],
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user