- 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>
769 lines
30 KiB
Bash
Executable File
769 lines
30 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# RPCD backend for SecuBox Service Exposure Manager
|
|
#
|
|
|
|
. /usr/share/libubox/jshn.sh
|
|
. /lib/functions.sh
|
|
|
|
case "$1" in
|
|
list)
|
|
json_init
|
|
json_add_object "scan"
|
|
json_close_object
|
|
json_add_object "conflicts"
|
|
json_close_object
|
|
json_add_object "status"
|
|
json_close_object
|
|
json_add_object "tor_list"
|
|
json_close_object
|
|
json_add_object "ssl_list"
|
|
json_close_object
|
|
json_add_object "get_config"
|
|
json_close_object
|
|
json_add_object "fix_port"
|
|
json_add_string "service" "string"
|
|
json_add_int "port" "integer"
|
|
json_close_object
|
|
json_add_object "tor_add"
|
|
json_add_string "service" "string"
|
|
json_add_int "local_port" "integer"
|
|
json_add_int "onion_port" "integer"
|
|
json_close_object
|
|
json_add_object "tor_remove"
|
|
json_add_string "service" "string"
|
|
json_close_object
|
|
json_add_object "ssl_add"
|
|
json_add_string "service" "string"
|
|
json_add_string "domain" "string"
|
|
json_add_int "local_port" "integer"
|
|
json_close_object
|
|
json_add_object "ssl_remove"
|
|
json_add_string "service" "string"
|
|
json_close_object
|
|
json_add_object "vhost_list"
|
|
json_close_object
|
|
json_add_object "emancipate"
|
|
json_add_string "service" "string"
|
|
json_add_int "port" "integer"
|
|
json_add_string "domain" "string"
|
|
json_add_boolean "tor" "boolean"
|
|
json_add_boolean "dns" "boolean"
|
|
json_add_boolean "mesh" "boolean"
|
|
json_close_object
|
|
json_add_object "revoke"
|
|
json_add_string "service" "string"
|
|
json_add_boolean "tor" "boolean"
|
|
json_add_boolean "dns" "boolean"
|
|
json_add_boolean "mesh" "boolean"
|
|
json_close_object
|
|
json_add_object "get_emancipated"
|
|
json_close_object
|
|
json_dump
|
|
;;
|
|
|
|
call)
|
|
case "$2" in
|
|
scan)
|
|
# Scan listening services - use temp file to avoid subshell issues
|
|
TMP_SVC="/tmp/exposure_scan_$$"
|
|
TMP_NAMES="/tmp/exposure_names_$$"
|
|
> "$TMP_NAMES"
|
|
|
|
netstat -tlnp 2>/dev/null | grep LISTEN | awk '{
|
|
split($4, a, ":")
|
|
port = a[length(a)]
|
|
if (!seen[port]++) {
|
|
split($7, p, "/")
|
|
proc = p[2]
|
|
if (proc == "") proc = "unknown"
|
|
print port, $4, proc
|
|
}
|
|
}' | sort -n > "$TMP_SVC"
|
|
|
|
# Build port->name enrichment from component configs
|
|
|
|
# uhttpd instances
|
|
for _s in $(uci show uhttpd 2>/dev/null | grep "=uhttpd$" | cut -d'.' -f2 | cut -d'=' -f1); do
|
|
_listen=$(uci -q get "uhttpd.${_s}.listen_http")
|
|
[ -z "$_listen" ] && continue
|
|
_p=$(echo "$_listen" | grep -o '[0-9]*$')
|
|
case "$_s" in
|
|
main) echo "$_p|LuCI" >> "$TMP_NAMES" ;;
|
|
acme) echo "$_p|ACME Challenge" >> "$TMP_NAMES" ;;
|
|
metablog_site_*) echo "$_p|Metablog: $(echo "$_s" | sed 's/^metablog_site_//')" >> "$TMP_NAMES" ;;
|
|
p2p_api) echo "$_p|P2P API" >> "$TMP_NAMES" ;;
|
|
*) echo "$_p|uhttpd: $_s" >> "$TMP_NAMES" ;;
|
|
esac
|
|
done
|
|
|
|
# Streamlit instances
|
|
for _s in $(uci show streamlit 2>/dev/null | grep "\.port=" | cut -d'.' -f2); do
|
|
_p=$(uci -q get "streamlit.${_s}.port")
|
|
_n=$(uci -q get "streamlit.${_s}.name")
|
|
[ -n "$_p" ] && echo "$_p|Streamlit: ${_n:-$_s}" >> "$TMP_NAMES"
|
|
done
|
|
|
|
# Docker containers
|
|
docker ps --format '{{.Ports}}|{{.Names}}' 2>/dev/null | while IFS='|' read _ports _cname; do
|
|
[ -z "$_cname" ] && continue
|
|
echo "$_ports" | tr ',' '\n' | while read _bind; do
|
|
_hp=$(echo "$_bind" | sed -n 's/.*:\([0-9]*\)->.*/\1/p')
|
|
[ -n "$_hp" ] && echo "$_hp|Docker: $_cname" >> "$TMP_NAMES"
|
|
done
|
|
done
|
|
|
|
# Glances
|
|
_gp=$(uci -q get glances.main.web_port)
|
|
[ -n "$_gp" ] && echo "$_gp|Glances" >> "$TMP_NAMES"
|
|
|
|
# Known services by port
|
|
echo "9000|Lyrion" >> "$TMP_NAMES"
|
|
echo "3483|Lyrion Discovery" >> "$TMP_NAMES"
|
|
echo "9090|Lyrion CLI" >> "$TMP_NAMES"
|
|
|
|
json_init
|
|
json_add_array "services"
|
|
|
|
while read port addr proc; do
|
|
[ -z "$port" ] && continue
|
|
|
|
external=0
|
|
case "$addr" in
|
|
*0.0.0.0*|*::*) external=1 ;;
|
|
*127.0.0.1*|*::1*) external=0 ;;
|
|
*) external=1 ;;
|
|
esac
|
|
|
|
# Try enriched name first, fallback to process-based mapping
|
|
name=$(grep "^${port}|" "$TMP_NAMES" | head -1 | cut -d'|' -f2)
|
|
if [ -z "$name" ]; then
|
|
case "$proc" in
|
|
sshd|dropbear) name="SSH" ;;
|
|
dnsmasq) name="DNS" ;;
|
|
haproxy) name="HAProxy" ;;
|
|
uhttpd) name="LuCI" ;;
|
|
gitea) name="Gitea" ;;
|
|
netifyd) name="Netifyd" ;;
|
|
tor) name="Tor" ;;
|
|
python*) name="Python App" ;;
|
|
streamlit) name="Streamlit" ;;
|
|
hexo|node) name="HexoJS" ;;
|
|
*) name="$proc" ;;
|
|
esac
|
|
fi
|
|
|
|
json_add_object ""
|
|
json_add_int "port" "$port"
|
|
json_add_string "address" "$addr"
|
|
json_add_string "process" "$proc"
|
|
json_add_string "name" "$name"
|
|
json_add_boolean "external" "$external"
|
|
json_close_object
|
|
done < "$TMP_SVC"
|
|
|
|
rm -f "$TMP_SVC" "$TMP_NAMES"
|
|
json_close_array
|
|
json_dump
|
|
;;
|
|
|
|
status)
|
|
json_init
|
|
|
|
total=$(netstat -tlnp 2>/dev/null | grep LISTEN | awk '{split($4,a,":"); print a[length(a)]}' | sort -u | wc -l)
|
|
external=$(netstat -tlnp 2>/dev/null | grep LISTEN | grep -E "0\.0\.0\.0|::" | awk '{split($4,a,":"); print a[length(a)]}' | sort -u | wc -l)
|
|
|
|
json_add_object "services"
|
|
json_add_int "total" "$total"
|
|
json_add_int "external" "$external"
|
|
json_close_object
|
|
|
|
# Tor hidden services
|
|
TOR_DIR="/var/lib/tor/hidden_services"
|
|
tor_count=0
|
|
[ -d "$TOR_DIR" ] && tor_count=$(ls -1d "$TOR_DIR"/*/ 2>/dev/null | wc -l)
|
|
|
|
json_add_object "tor"
|
|
json_add_int "count" "$tor_count"
|
|
json_add_array "services"
|
|
if [ -d "$TOR_DIR" ]; then
|
|
for dir in "$TOR_DIR"/*/; do
|
|
[ -d "$dir" ] || continue
|
|
svc=$(basename "$dir")
|
|
onion=""
|
|
[ -f "$dir/hostname" ] && onion=$(cat "$dir/hostname")
|
|
if [ -n "$onion" ]; then
|
|
json_add_object ""
|
|
json_add_string "service" "$svc"
|
|
json_add_string "onion" "$onion"
|
|
json_close_object
|
|
fi
|
|
done
|
|
fi
|
|
json_close_array
|
|
json_close_object
|
|
|
|
# HAProxy SSL backends - read from UCI config
|
|
TMP_SSL="/tmp/exposure_ssl_$$"
|
|
ssl_count=0
|
|
|
|
# Get vhosts from UCI (enabled ones with domains)
|
|
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
|
|
echo "${backend:-$vhost}|${domain}" >> "$TMP_SSL"
|
|
ssl_count=$((ssl_count + 1))
|
|
done
|
|
|
|
json_add_object "ssl"
|
|
json_add_int "count" "$ssl_count"
|
|
json_add_array "backends"
|
|
if [ -f "$TMP_SSL" ]; then
|
|
while IFS='|' read backend domain; do
|
|
[ -z "$backend" ] && continue
|
|
json_add_object ""
|
|
json_add_string "service" "$backend"
|
|
json_add_string "domain" "$domain"
|
|
json_close_object
|
|
done < "$TMP_SSL"
|
|
rm -f "$TMP_SSL"
|
|
fi
|
|
json_close_array
|
|
json_close_object
|
|
|
|
json_dump
|
|
;;
|
|
|
|
tor_list)
|
|
TOR_DIR="/var/lib/tor/hidden_services"
|
|
TOR_CONFIG="/etc/tor/torrc"
|
|
|
|
json_init
|
|
json_add_array "services"
|
|
|
|
if [ -d "$TOR_DIR" ]; then
|
|
for dir in "$TOR_DIR"/*/; do
|
|
[ -d "$dir" ] || continue
|
|
svc=$(basename "$dir")
|
|
onion=""
|
|
[ -f "$dir/hostname" ] && onion=$(cat "$dir/hostname")
|
|
|
|
port=$(grep -A1 "HiddenServiceDir $dir" "$TOR_CONFIG" 2>/dev/null | grep HiddenServicePort | awk '{print $2}')
|
|
backend=$(grep -A1 "HiddenServiceDir $dir" "$TOR_CONFIG" 2>/dev/null | grep HiddenServicePort | awk '{print $3}')
|
|
|
|
if [ -n "$onion" ]; then
|
|
json_add_object ""
|
|
json_add_string "service" "$svc"
|
|
json_add_string "onion" "$onion"
|
|
json_add_string "port" "${port:-80}"
|
|
json_add_string "backend" "${backend:-N/A}"
|
|
json_close_object
|
|
fi
|
|
done
|
|
fi
|
|
|
|
json_close_array
|
|
json_dump
|
|
;;
|
|
|
|
ssl_list)
|
|
# 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)
|
|
json_init
|
|
json_add_array "known_services"
|
|
|
|
config_load "secubox-exposure"
|
|
|
|
get_known() {
|
|
local section="$1"
|
|
local default_port config_path category
|
|
|
|
config_get default_port "$section" default_port
|
|
config_get config_path "$section" config_path
|
|
config_get category "$section" category "other"
|
|
|
|
actual_port=""
|
|
if [ -n "$config_path" ]; then
|
|
actual_port=$(uci -q get "$config_path" 2>/dev/null)
|
|
fi
|
|
[ -z "$actual_port" ] && actual_port="$default_port"
|
|
|
|
json_add_object ""
|
|
json_add_string "id" "$section"
|
|
json_add_int "default_port" "${default_port:-0}"
|
|
json_add_int "actual_port" "${actual_port:-0}"
|
|
json_add_string "config_path" "$config_path"
|
|
json_add_string "category" "$category"
|
|
json_close_object
|
|
}
|
|
config_foreach get_known known
|
|
|
|
json_close_array
|
|
json_dump
|
|
;;
|
|
|
|
conflicts)
|
|
json_init
|
|
json_add_array "conflicts"
|
|
json_close_array
|
|
json_dump
|
|
;;
|
|
|
|
fix_port)
|
|
read -r input
|
|
service=$(echo "$input" | jsonfilter -e '@.service')
|
|
port=$(echo "$input" | jsonfilter -e '@.port')
|
|
|
|
if [ -z "$service" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Service name required"
|
|
json_dump
|
|
exit 0
|
|
fi
|
|
|
|
result=$(/usr/sbin/secubox-exposure fix-port "$service" "$port" 2>&1)
|
|
json_init
|
|
if [ $? -eq 0 ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "$result"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
fi
|
|
json_dump
|
|
;;
|
|
|
|
tor_add)
|
|
read -r input
|
|
service=$(echo "$input" | jsonfilter -e '@.service')
|
|
local_port=$(echo "$input" | jsonfilter -e '@.local_port')
|
|
onion_port=$(echo "$input" | jsonfilter -e '@.onion_port')
|
|
|
|
if [ -z "$service" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Service name required"
|
|
json_dump
|
|
exit 0
|
|
fi
|
|
|
|
result=$(/usr/sbin/secubox-exposure tor add "$service" "$local_port" "$onion_port" 2>&1)
|
|
json_init
|
|
if echo "$result" | grep -q "Hidden service created"; then
|
|
onion=$(echo "$result" | grep "Onion:" | awk '{print $2}')
|
|
json_add_boolean "success" 1
|
|
json_add_string "onion" "$onion"
|
|
json_add_string "message" "Hidden service created"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
fi
|
|
json_dump
|
|
;;
|
|
|
|
tor_remove)
|
|
read -r input
|
|
service=$(echo "$input" | jsonfilter -e '@.service')
|
|
|
|
if [ -z "$service" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Service name required"
|
|
json_dump
|
|
exit 0
|
|
fi
|
|
|
|
result=$(/usr/sbin/secubox-exposure tor remove "$service" 2>&1)
|
|
json_init
|
|
if echo "$result" | grep -q "removed"; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Hidden service removed"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
fi
|
|
json_dump
|
|
;;
|
|
|
|
ssl_add)
|
|
read -r input
|
|
service=$(echo "$input" | jsonfilter -e '@.service')
|
|
domain=$(echo "$input" | jsonfilter -e '@.domain')
|
|
local_port=$(echo "$input" | jsonfilter -e '@.local_port')
|
|
|
|
if [ -z "$service" ] || [ -z "$domain" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Service and domain required"
|
|
json_dump
|
|
exit 0
|
|
fi
|
|
|
|
result=$(/usr/sbin/secubox-exposure ssl add "$service" "$domain" "$local_port" 2>&1)
|
|
json_init
|
|
if echo "$result" | grep -q "configured"; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "SSL backend configured"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
fi
|
|
json_dump
|
|
;;
|
|
|
|
ssl_remove)
|
|
read -r input
|
|
service=$(echo "$input" | jsonfilter -e '@.service')
|
|
|
|
if [ -z "$service" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Service name required"
|
|
json_dump
|
|
exit 0
|
|
fi
|
|
|
|
result=$(/usr/sbin/secubox-exposure ssl remove "$service" 2>&1)
|
|
json_init
|
|
if echo "$result" | grep -q "removed"; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "SSL backend removed"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
fi
|
|
json_dump
|
|
;;
|
|
|
|
vhost_list)
|
|
# OPTIMIZED: Single-pass awk parsing instead of O(n²) uci calls
|
|
uci show haproxy 2>/dev/null | awk '
|
|
BEGIN {
|
|
printf "{\"haproxy\":["
|
|
first_vh = 1
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
# Track section type
|
|
/=vhost$/ { prev_type = "vhost" }
|
|
/=server$/ { prev_type = "server" }
|
|
/=backend$/ { prev_type = "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
|
|
}
|
|
|
|
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 "],"
|
|
}
|
|
'
|
|
|
|
# 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)
|
|
read -r input
|
|
service=$(echo "$input" | jsonfilter -e '@.service')
|
|
port=$(echo "$input" | jsonfilter -e '@.port')
|
|
domain=$(echo "$input" | jsonfilter -e '@.domain')
|
|
tor=$(echo "$input" | jsonfilter -e '@.tor')
|
|
dns=$(echo "$input" | jsonfilter -e '@.dns')
|
|
mesh=$(echo "$input" | jsonfilter -e '@.mesh')
|
|
|
|
if [ -z "$service" ] || [ -z "$port" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Service and port required"
|
|
json_dump
|
|
exit 0
|
|
fi
|
|
|
|
flags=""
|
|
[ "$tor" = "true" ] || [ "$tor" = "1" ] && flags="$flags --tor"
|
|
[ "$dns" = "true" ] || [ "$dns" = "1" ] && flags="$flags --dns"
|
|
[ "$mesh" = "true" ] || [ "$mesh" = "1" ] && flags="$flags --mesh"
|
|
[ -z "$flags" ] && flags="--all"
|
|
|
|
result=$(/usr/sbin/secubox-exposure emancipate "$service" "$port" "$domain" $flags 2>&1)
|
|
rc=$?
|
|
|
|
json_init
|
|
if [ $rc -eq 0 ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Service emancipated"
|
|
json_add_string "output" "$result"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
fi
|
|
json_dump
|
|
;;
|
|
|
|
revoke)
|
|
read -r input
|
|
service=$(echo "$input" | jsonfilter -e '@.service')
|
|
tor=$(echo "$input" | jsonfilter -e '@.tor')
|
|
dns=$(echo "$input" | jsonfilter -e '@.dns')
|
|
mesh=$(echo "$input" | jsonfilter -e '@.mesh')
|
|
|
|
if [ -z "$service" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Service name required"
|
|
json_dump
|
|
exit 0
|
|
fi
|
|
|
|
flags=""
|
|
[ "$tor" = "true" ] || [ "$tor" = "1" ] && flags="$flags --tor"
|
|
[ "$dns" = "true" ] || [ "$dns" = "1" ] && flags="$flags --dns"
|
|
[ "$mesh" = "true" ] || [ "$mesh" = "1" ] && flags="$flags --mesh"
|
|
[ -z "$flags" ] && flags="--all"
|
|
|
|
result=$(/usr/sbin/secubox-exposure revoke "$service" $flags 2>&1)
|
|
rc=$?
|
|
|
|
json_init
|
|
if [ $rc -eq 0 ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Service revoked"
|
|
json_add_string "output" "$result"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
fi
|
|
json_dump
|
|
;;
|
|
|
|
get_emancipated)
|
|
json_init
|
|
json_add_array "services"
|
|
|
|
# Read emancipated services from UCI
|
|
for svc in $(uci show secubox-exposure 2>/dev/null | grep "=service$" | cut -d'.' -f2 | cut -d'=' -f1); do
|
|
emancipated=$(uci -q get "secubox-exposure.$svc.emancipated")
|
|
[ "$emancipated" != "1" ] && continue
|
|
|
|
port=$(uci -q get "secubox-exposure.$svc.port")
|
|
domain=$(uci -q get "secubox-exposure.$svc.domain")
|
|
tor=$(uci -q get "secubox-exposure.$svc.tor")
|
|
dns=$(uci -q get "secubox-exposure.$svc.dns")
|
|
mesh=$(uci -q get "secubox-exposure.$svc.mesh")
|
|
|
|
json_add_object ""
|
|
json_add_string "name" "$svc"
|
|
json_add_int "port" "${port:-0}"
|
|
json_add_string "domain" "${domain:-}"
|
|
json_add_boolean "tor" "${tor:-0}"
|
|
json_add_boolean "dns" "${dns:-0}"
|
|
json_add_boolean "mesh" "${mesh:-0}"
|
|
json_close_object
|
|
done
|
|
|
|
json_close_array
|
|
json_dump
|
|
;;
|
|
|
|
*)
|
|
json_init
|
|
json_add_boolean "error" 1
|
|
json_add_string "message" "Unknown method: $2"
|
|
json_dump
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|