Implement Service Registry LuCI app for unified service management: - RPCD backend aggregating services from HAProxy, Tor, netstat, LXC - One-click publish to clearnet (HAProxy+ACME) and/or Tor hidden service - Static landing page generator with QR codes for all URLs - LuCI dashboard with service grid, quick publish form - CLI tool (secubox-registry) for command-line management - Share buttons for X, Telegram, WhatsApp RPCD methods: list_services, publish_service, unpublish_service, generate_landing_page, get_qr_data, list_categories Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
278 lines
6.6 KiB
Bash
278 lines
6.6 KiB
Bash
#!/bin/sh
|
|
# SPDX-License-Identifier: MIT
|
|
# SecuBox Service Registry CLI
|
|
# Copyright (C) 2025 CyberMind.fr
|
|
|
|
. /lib/functions.sh
|
|
|
|
UCI_CONFIG="service-registry"
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
SecuBox Service Registry - Unified service management
|
|
|
|
Usage: secubox-registry <command> [options]
|
|
|
|
Commands:
|
|
list List all services
|
|
show <service_id> Show service details
|
|
publish <name> <port> [opts] Publish a new service
|
|
unpublish <service_id> Unpublish a service
|
|
landing regen Regenerate landing page
|
|
categories List categories
|
|
|
|
Publish options:
|
|
--domain <domain> Create HAProxy vhost with ACME cert
|
|
--tor Enable Tor hidden service
|
|
--category <cat> Service category (default: services)
|
|
--icon <icon> Service icon
|
|
|
|
Examples:
|
|
secubox-registry list
|
|
secubox-registry publish "Gitea" 3000 --domain git.example.com --tor
|
|
secubox-registry unpublish gitea
|
|
secubox-registry landing regen
|
|
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
# List services
|
|
cmd_list() {
|
|
local json_output
|
|
json_output=$(ubus call luci.service-registry list_services 2>/dev/null)
|
|
|
|
if [ -z "$json_output" ]; then
|
|
echo "Error: Could not fetch services"
|
|
exit 1
|
|
fi
|
|
|
|
echo "SecuBox Services"
|
|
echo "================"
|
|
echo
|
|
|
|
# Parse and display services
|
|
local count
|
|
count=$(echo "$json_output" | jsonfilter -e '@.services[*]' 2>/dev/null | wc -l)
|
|
|
|
if [ "$count" -eq 0 ]; then
|
|
echo "No services found"
|
|
return
|
|
fi
|
|
|
|
printf "%-20s %-10s %-8s %-30s %-15s\n" "NAME" "PORT" "STATUS" "CLEARNET" "ONION"
|
|
printf "%-20s %-10s %-8s %-30s %-15s\n" "----" "----" "------" "--------" "-----"
|
|
|
|
local i=0
|
|
while [ $i -lt "$count" ]; do
|
|
local name port status clearnet onion
|
|
name=$(echo "$json_output" | jsonfilter -e "@.services[$i].name" 2>/dev/null)
|
|
port=$(echo "$json_output" | jsonfilter -e "@.services[$i].local_port" 2>/dev/null)
|
|
status=$(echo "$json_output" | jsonfilter -e "@.services[$i].status" 2>/dev/null)
|
|
clearnet=$(echo "$json_output" | jsonfilter -e "@.services[$i].urls.clearnet" 2>/dev/null)
|
|
onion=$(echo "$json_output" | jsonfilter -e "@.services[$i].urls.onion" 2>/dev/null)
|
|
|
|
[ -z "$clearnet" ] && clearnet="-"
|
|
[ -z "$onion" ] && onion="-"
|
|
[ -z "$port" ] && port="-"
|
|
|
|
# Truncate long strings
|
|
[ ${#clearnet} -gt 30 ] && clearnet="${clearnet:0:27}..."
|
|
[ ${#onion} -gt 15 ] && onion="${onion:0:12}..."
|
|
|
|
printf "%-20s %-10s %-8s %-30s %-15s\n" "$name" "$port" "$status" "$clearnet" "$onion"
|
|
|
|
i=$((i + 1))
|
|
done
|
|
|
|
echo
|
|
echo "Providers:"
|
|
local haproxy_status haproxy_count tor_status tor_count
|
|
haproxy_status=$(echo "$json_output" | jsonfilter -e "@.providers.haproxy.status" 2>/dev/null)
|
|
haproxy_count=$(echo "$json_output" | jsonfilter -e "@.providers.haproxy.count" 2>/dev/null)
|
|
tor_status=$(echo "$json_output" | jsonfilter -e "@.providers.tor.status" 2>/dev/null)
|
|
tor_count=$(echo "$json_output" | jsonfilter -e "@.providers.tor.count" 2>/dev/null)
|
|
|
|
echo " HAProxy: $haproxy_status ($haproxy_count vhosts)"
|
|
echo " Tor: $tor_status ($tor_count hidden services)"
|
|
}
|
|
|
|
# Show service details
|
|
cmd_show() {
|
|
local service_id="$1"
|
|
|
|
if [ -z "$service_id" ]; then
|
|
echo "Error: service_id required"
|
|
usage
|
|
fi
|
|
|
|
local json_output
|
|
json_output=$(ubus call luci.service-registry get_service "{\"service_id\":\"$service_id\"}" 2>/dev/null)
|
|
|
|
if echo "$json_output" | grep -q '"success":false'; then
|
|
echo "Error: Service not found"
|
|
exit 1
|
|
fi
|
|
|
|
echo "$json_output" | jsonfilter -e '@' 2>/dev/null
|
|
}
|
|
|
|
# Publish service
|
|
cmd_publish() {
|
|
local name="$1"
|
|
local port="$2"
|
|
shift 2
|
|
|
|
if [ -z "$name" ] || [ -z "$port" ]; then
|
|
echo "Error: name and port required"
|
|
usage
|
|
fi
|
|
|
|
local domain=""
|
|
local tor_enabled="0"
|
|
local category="services"
|
|
local icon=""
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--domain)
|
|
domain="$2"
|
|
shift 2
|
|
;;
|
|
--tor)
|
|
tor_enabled="1"
|
|
shift
|
|
;;
|
|
--category)
|
|
category="$2"
|
|
shift 2
|
|
;;
|
|
--icon)
|
|
icon="$2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
usage
|
|
;;
|
|
esac
|
|
done
|
|
|
|
local params="{\"name\":\"$name\",\"local_port\":$port,\"tor_enabled\":$tor_enabled,\"category\":\"$category\""
|
|
[ -n "$domain" ] && params="$params,\"domain\":\"$domain\""
|
|
[ -n "$icon" ] && params="$params,\"icon\":\"$icon\""
|
|
params="$params}"
|
|
|
|
echo "Publishing service: $name on port $port"
|
|
[ -n "$domain" ] && echo " Domain: $domain (HAProxy + ACME)"
|
|
[ "$tor_enabled" = "1" ] && echo " Tor hidden service: enabled"
|
|
|
|
local result
|
|
result=$(ubus call luci.service-registry publish_service "$params" 2>/dev/null)
|
|
|
|
if echo "$result" | grep -q '"success":true'; then
|
|
echo
|
|
echo "Service published successfully!"
|
|
echo
|
|
echo "URLs:"
|
|
local url_local url_clearnet url_onion
|
|
url_local=$(echo "$result" | jsonfilter -e '@.urls.local' 2>/dev/null)
|
|
url_clearnet=$(echo "$result" | jsonfilter -e '@.urls.clearnet' 2>/dev/null)
|
|
url_onion=$(echo "$result" | jsonfilter -e '@.urls.onion' 2>/dev/null)
|
|
|
|
[ -n "$url_local" ] && echo " Local: $url_local"
|
|
[ -n "$url_clearnet" ] && echo " Clearnet: $url_clearnet"
|
|
[ -n "$url_onion" ] && echo " Onion: $url_onion"
|
|
else
|
|
echo "Error: Failed to publish service"
|
|
echo "$result"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Unpublish service
|
|
cmd_unpublish() {
|
|
local service_id="$1"
|
|
|
|
if [ -z "$service_id" ]; then
|
|
echo "Error: service_id required"
|
|
usage
|
|
fi
|
|
|
|
echo "Unpublishing service: $service_id"
|
|
|
|
local result
|
|
result=$(ubus call luci.service-registry unpublish_service "{\"service_id\":\"$service_id\"}" 2>/dev/null)
|
|
|
|
if echo "$result" | grep -q '"success":true'; then
|
|
echo "Service unpublished successfully"
|
|
else
|
|
echo "Error: Failed to unpublish service"
|
|
echo "$result"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Landing page commands
|
|
cmd_landing() {
|
|
local subcmd="$1"
|
|
|
|
case "$subcmd" in
|
|
regen|regenerate)
|
|
echo "Regenerating landing page..."
|
|
/usr/sbin/secubox-landing-gen
|
|
echo "Done"
|
|
;;
|
|
*)
|
|
echo "Usage: secubox-registry landing regen"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# List categories
|
|
cmd_categories() {
|
|
local json_output
|
|
json_output=$(ubus call luci.service-registry list_categories 2>/dev/null)
|
|
|
|
echo "Categories:"
|
|
echo "$json_output" | jsonfilter -e '@.categories[*].id' 2>/dev/null | while read id; do
|
|
local name icon
|
|
name=$(echo "$json_output" | jsonfilter -e "@.categories[@.id='$id'].name" 2>/dev/null)
|
|
icon=$(echo "$json_output" | jsonfilter -e "@.categories[@.id='$id'].icon" 2>/dev/null)
|
|
echo " $id: $name ($icon)"
|
|
done
|
|
}
|
|
|
|
# Main
|
|
case "$1" in
|
|
list)
|
|
cmd_list
|
|
;;
|
|
show)
|
|
shift
|
|
cmd_show "$@"
|
|
;;
|
|
publish)
|
|
shift
|
|
cmd_publish "$@"
|
|
;;
|
|
unpublish)
|
|
shift
|
|
cmd_unpublish "$@"
|
|
;;
|
|
landing)
|
|
shift
|
|
cmd_landing "$@"
|
|
;;
|
|
categories)
|
|
cmd_categories
|
|
;;
|
|
-h|--help|help)
|
|
usage
|
|
;;
|
|
*)
|
|
usage
|
|
;;
|
|
esac
|