refactor(secubox-core): Modularize luci.secubox RPCD handler

Split 2544-line monolithic handler into thin dispatcher + 14 modules:
- _common.sh: Shared utilities (json_success, check_service_running, etc.)
- core.sh: getStatus, getVersion, reload
- modules.sh: Module management (install, remove, update)
- profiles.sh: Profile management
- snapshots.sh: Snapshot/recovery
- health.sh: Health & diagnostics
- dashboard.sh: Dashboard data & quick actions
- appstore.sh: AppStore & catalog operations
- state.sh: Component state management
- network.sh: WAN access, services, proxy mode
- feeds.sh: Feed management
- skills.sh: Skill management
- feedback.sh: Issue/resolution tracking
- p2p.sh: P2P hub operations

Benefits:
- Each module is focused on a single domain
- Easier to maintain, test, and debug
- New features can be added as new modules

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-08 09:45:13 +01:00
parent 872038341a
commit e28f7b952f
16 changed files with 2667 additions and 2515 deletions

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-core
PKG_VERSION:=0.10.0
PKG_RELEASE:=14
PKG_RELEASE:=15
PKG_ARCH:=all
PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=SecuBox Team
@ -103,6 +103,10 @@ define Package/secubox-core/install
$(INSTALL_DIR) $(1)/usr/lib/secubox
$(INSTALL_DATA) ./root/usr/lib/secubox/tftp-mesh.sh $(1)/usr/lib/secubox/
# RPCD method modules
$(INSTALL_DIR) $(1)/usr/lib/secubox/rpcd.d
$(INSTALL_DATA) ./root/usr/lib/secubox/rpcd.d/*.sh $(1)/usr/lib/secubox/rpcd.d/
# WAN Access hotplug for interface events
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_BIN) ./root/etc/hotplug.d/iface/99-secubox-wan $(1)/etc/hotplug.d/iface/

View File

@ -0,0 +1,197 @@
#!/bin/sh
#
# SecuBox RPCD Common Utilities
# Shared functions for all RPCD method modules
#
# Standard JSON success response
json_success() {
local msg="${1:-Success}"
json_init
json_add_boolean "success" 1
json_add_string "message" "$msg"
json_dump
}
# Standard JSON error response
json_error() {
local msg="${1:-Error}"
local details="$2"
json_init
json_add_boolean "success" 0
json_add_string "error" "$msg"
[ -n "$details" ] && json_add_string "details" "$details"
json_dump
}
# Check if a service/process is running
# Usage: check_service_running <process_name>
# Returns: 0 if running, 1 if not
check_service_running() {
local name="$1"
pgrep -f "$name" >/dev/null 2>&1
}
# Check if a port is listening
# Usage: check_port_listening <port>
# Returns: 0 if listening, 1 if not
check_port_listening() {
local port="$1"
# Try netstat first (most common on OpenWrt)
if command -v netstat >/dev/null 2>&1; then
netstat -tln 2>/dev/null | grep -q ":${port} "
return $?
fi
# Fallback to /proc/net/tcp (always available)
# Convert port to hex
local hex_port=$(printf '%04X' "$port")
grep -qi ":${hex_port} " /proc/net/tcp 2>/dev/null
}
# Read and parse JSON input from stdin
# Sets global variable: INPUT_JSON
read_input_json() {
INPUT_JSON=""
read -r INPUT_JSON
}
# Get a value from INPUT_JSON
# Usage: get_input <field>
get_input() {
local field="$1"
echo "$INPUT_JSON" | jsonfilter -e "@.$field" 2>/dev/null
}
# Get boolean from INPUT_JSON (returns 1 or 0)
get_input_bool() {
local field="$1"
local val=$(get_input "$field")
case "$val" in
true|1|yes) echo 1 ;;
*) echo 0 ;;
esac
}
# Get integer from INPUT_JSON with default
get_input_int() {
local field="$1"
local default="${2:-0}"
local val=$(get_input "$field")
[ -n "$val" ] && [ "$val" -eq "$val" ] 2>/dev/null && echo "$val" || echo "$default"
}
# Check if init.d service exists and is enabled
# Usage: check_init_service <service_name>
# Returns: running|stopped|disabled|not_installed
check_init_service() {
local svc="$1"
if [ ! -f "/etc/init.d/$svc" ]; then
echo "not_installed"
return
fi
if ! /etc/init.d/$svc enabled 2>/dev/null; then
echo "disabled"
return
fi
if /etc/init.d/$svc running 2>/dev/null; then
echo "running"
else
echo "stopped"
fi
}
# Check LXC container status
# Usage: check_lxc_status <container_name>
# Returns: running|stopped|not_installed
check_lxc_status() {
local name="$1"
if ! command -v lxc-info >/dev/null 2>&1; then
echo "not_installed"
return
fi
if lxc-info -n "$name" -s 2>/dev/null | grep -q "RUNNING"; then
echo "running"
elif lxc-info -n "$name" 2>/dev/null | grep -q "State"; then
echo "stopped"
else
echo "not_installed"
fi
}
# Get current timestamp in ISO format
get_timestamp() {
date -Iseconds 2>/dev/null || date -u +%Y-%m-%dT%H:%M:%SZ
}
# Get system uptime in seconds
get_uptime_seconds() {
cut -d. -f1 /proc/uptime
}
# Get load average (1 5 15 minute)
get_load_avg() {
cut -d' ' -f1-3 /proc/loadavg
}
# Get memory usage percentage
get_memory_percent() {
local mem_total=$(awk '/MemTotal/ {print $2}' /proc/meminfo)
local mem_avail=$(awk '/MemAvailable/ {print $2}' /proc/meminfo)
mem_avail=${mem_avail:-0}
[ "$mem_total" -gt 0 ] && echo $(( (mem_total - mem_avail) * 100 / mem_total )) || echo 0
}
# Get disk usage percentage for root
get_disk_percent() {
df / 2>/dev/null | tail -1 | awk '{print $5}' | tr -d '%'
}
#
# Method registration helpers
# Each module should call these in its list_methods_<domain>() function
#
# Add a method with no parameters
add_method() {
local name="$1"
json_add_object "$name"
json_close_object
}
# Add a method with string parameter
add_method_str() {
local name="$1"
local param="$2"
json_add_object "$name"
json_add_string "$param" "string"
json_close_object
}
# Add a method with multiple string parameters
add_method_strs() {
local name="$1"
shift
json_add_object "$name"
for param in "$@"; do
json_add_string "$param" "string"
done
json_close_object
}
# Add a method with boolean parameter
add_method_bool() {
local name="$1"
local param="$2"
json_add_object "$name"
json_add_boolean "$param" "boolean"
json_close_object
}
# Add a method with integer parameter
add_method_int() {
local name="$1"
local param="$2"
json_add_object "$name"
json_add_int "$param" "integer"
json_close_object
}

View File

@ -0,0 +1,399 @@
#!/bin/sh
#
# SecuBox RPCD - AppStore Operations
# Catalog, apps, versions, widgets
#
# Register methods
list_methods_appstore() {
add_method "get_appstore_apps"
add_method "list_apps"
add_method_str "get_appstore_app" "app_id"
add_method_str "install_appstore_app" "app_id"
add_method_str "remove_appstore_app" "app_id"
add_method "get_catalog_sources"
add_method_str "set_catalog_source" "source"
add_method_str "sync_catalog" "source"
add_method "check_updates"
add_method_str "get_app_versions" "app_id"
json_add_object "get_changelog"
json_add_string "app_id" "string"
json_add_string "from_version" "string"
json_add_string "to_version" "string"
json_close_object
add_method_str "get_widget_data" "app_id"
add_method_str "get_app_manifest" "app_id"
}
# Handle method calls
handle_appstore() {
local method="$1"
case "$method" in
get_appstore_apps)
_do_get_appstore_apps
;;
list_apps)
_do_list_apps
;;
get_appstore_app)
read_input_json
local app_id=$(get_input "app_id")
_do_get_appstore_app "$app_id"
;;
install_appstore_app)
read_input_json
local app_id=$(get_input "app_id")
if /usr/sbin/secubox-appstore install "$app_id" >/dev/null 2>&1; then
json_success "App installed successfully"
else
json_error "Installation failed" "Check system logs for more information"
fi
;;
remove_appstore_app)
read_input_json
local app_id=$(get_input "app_id")
if /usr/sbin/secubox-appstore remove "$app_id" >/dev/null 2>&1; then
json_success "App removed successfully"
else
json_error "Removal failed" "Check system logs for more information"
fi
;;
get_catalog_sources)
_do_get_catalog_sources
;;
set_catalog_source)
read_input_json
local source=$(get_input "source")
_do_set_catalog_source "$source"
;;
sync_catalog)
read_input_json
local source=$(get_input "source")
if /usr/sbin/secubox-appstore sync ${source:+"$source"} 2>&1; then
json_init
json_add_boolean "success" 1
json_add_string "message" "Catalog synced successfully"
[ -n "$source" ] && json_add_string "source" "$source"
json_dump
else
json_error "Sync failed"
fi
;;
check_updates)
/usr/sbin/secubox-appstore check-updates --json
;;
get_app_versions)
read_input_json
local app_id=$(get_input "app_id")
_do_get_app_versions "$app_id"
;;
get_changelog)
read_input_json
local app_id=$(get_input "app_id")
local from_version=$(get_input "from_version")
local to_version=$(get_input "to_version")
/usr/sbin/secubox-appstore changelog "$app_id" ${from_version:+"$from_version"} ${to_version:+"$to_version"}
;;
get_widget_data)
read_input_json
local app_id=$(get_input "app_id")
_do_get_widget_data "$app_id"
;;
get_app_manifest)
read_input_json
local app_id=$(get_input "app_id")
local manifest="/usr/share/secubox/plugins/$app_id/manifest.json"
if [ -f "$manifest" ]; then
cat "$manifest"
else
json_error "Manifest not found" "$app_id"
fi
;;
*)
return 1
;;
esac
}
# Get apps from catalog with installation status
_do_get_appstore_apps() {
local CATALOG_FILE="/usr/share/secubox/catalog.json"
if [ -f "$CATALOG_FILE" ]; then
local MODULES_JSON=$(/usr/sbin/secubox-appstore list --json 2>/dev/null)
if [ -n "$MODULES_JSON" ]; then
jq --argjson modules "$MODULES_JSON" '
{
apps: [.plugins[] | . as $app |
($modules.modules // [] | map(select(.id == $app.id or .name == $app.id)) | first) as $mod |
$app + {
installed: (if $mod then ($mod.installed // false) else false end),
enabled: (if $mod then ($mod.enabled // false) else false end),
status: (if $mod then ($mod.status // "unknown") else "not_installed" end)
}
],
categories: .categories
}
' "$CATALOG_FILE"
else
jq '{apps: .plugins, categories: .categories}' "$CATALOG_FILE"
fi
else
echo '{"apps":[],"categories":{}}'
fi
}
# List apps with wizard detection
_do_list_apps() {
local CATALOG_FILE="/usr/share/secubox/catalog.json"
local PLUGINS_DIR="/usr/share/secubox/plugins"
local APPS_JSON='[]'
if [ -f "$CATALOG_FILE" ]; then
APPS_JSON=$(jq '.plugins' "$CATALOG_FILE")
fi
for plugin_dir in "$PLUGINS_DIR"/*; do
[ -d "$plugin_dir" ] || continue
local manifest="$plugin_dir/manifest.json"
[ -f "$manifest" ] || continue
local app_id=$(jq -r '.id // empty' "$manifest" 2>/dev/null)
[ -n "$app_id" ] || continue
local has_wizard=$(jq -e '.wizard.fields | length > 0' "$manifest" >/dev/null 2>&1 && echo "true" || echo "false")
if [ "$has_wizard" = "true" ]; then
local app_exists=$(echo "$APPS_JSON" | jq --arg id "$app_id" 'map(select(.id == $id)) | length')
if [ "$app_exists" -gt 0 ]; then
APPS_JSON=$(echo "$APPS_JSON" | jq --arg id "$app_id" \
'map(if .id == $id then . + {has_wizard: true} else . end)')
else
local app_data=$(jq '{
id: .id,
name: .name,
description: .description,
version: .version,
icon: "box",
has_wizard: true,
state: "available"
}' "$manifest")
APPS_JSON=$(echo "$APPS_JSON" | jq --argjson app "$app_data" '. + [$app]')
fi
fi
done
if [ -f "$CATALOG_FILE" ]; then
jq -n --argjson apps "$APPS_JSON" --argjson cats "$(jq '.categories // {}' "$CATALOG_FILE")" \
'{apps: $apps, categories: $cats}'
else
jq -n --argjson apps "$APPS_JSON" '{apps: $apps, categories: {}}'
fi
}
# Get single app details
_do_get_appstore_app() {
local app_id="$1"
local CATALOG_DIR="/usr/share/secubox/plugins/catalog"
local CATALOG_FILE="$CATALOG_DIR/${app_id}.json"
if [ -f "$CATALOG_FILE" ]; then
json_init
cat "$CATALOG_FILE" | jsonfilter -e '@'
local pkg=$(jsonfilter -i "$CATALOG_FILE" -e '@.packages.required[0]')
if [ -n "$pkg" ] && opkg list-installed | grep -q "^$pkg "; then
echo ',"installed":true'
else
echo ',"installed":false'
fi
else
json_error "App not found" "$app_id"
fi
}
# Get catalog sources
_do_get_catalog_sources() {
local CONFIG_NAME="secubox-appstore"
local METADATA_FILE="/var/lib/secubox/catalog-metadata.json"
_add_default_src() {
local name="$1" type="$2" url="$3" path="$4" priority="$5"
json_add_object ""
json_add_string "name" "$name"
json_add_boolean "enabled" 1
json_add_string "type" "$type"
[ -n "$url" ] && json_add_string "url" "$url"
[ -n "$path" ] && json_add_string "path" "$path"
json_add_int "priority" "$priority"
[ "$name" = "embedded" ] && json_add_boolean "active" 1 || json_add_boolean "active" 0
json_add_string "status" "default"
json_add_string "last_success" ""
json_close_object
}
if [ ! -f "/etc/config/$CONFIG_NAME" ]; then
json_init
json_add_array "sources"
_add_default_src "github" "remote" "https://raw.githubusercontent.com/CyberMind-FR/secubox-openwrt/refs/heads/master/package/secubox/secubox-core/root/usr/share/secubox/catalog.json" "" 1
_add_default_src "embedded" "embedded" "" "/usr/share/secubox/catalog.json" 999
json_close_array
json_add_boolean "defaults" true
json_add_string "message" "Catalog config missing, using built-in defaults"
json_dump
return
fi
json_init
json_add_array "sources"
. /lib/functions.sh
config_load "$CONFIG_NAME"
local active_source=""
[ -f "$METADATA_FILE" ] && active_source=$(jsonfilter -i "$METADATA_FILE" -e '@.active_source' 2>/dev/null || echo "")
local metadata_content=""
[ -f "$METADATA_FILE" ] && metadata_content=$(cat "$METADATA_FILE" 2>/dev/null || echo "{}")
local sources_count=0
_add_src_info() {
local section="$1"
local enabled type url path priority
config_get_bool enabled "$section" enabled 0
config_get type "$section" type
config_get url "$section" url
config_get path "$section" path
config_get priority "$section" priority 999
json_add_object ""
json_add_string "name" "$section"
json_add_boolean "enabled" "$enabled"
json_add_string "type" "$type"
[ -n "$url" ] && json_add_string "url" "$url"
[ -n "$path" ] && json_add_string "path" "$path"
json_add_int "priority" "$priority"
json_add_boolean "active" "$([ "$section" = "$active_source" ] && echo 1 || echo 0)"
if [ -n "$metadata_content" ]; then
local status=$(echo "$metadata_content" | jsonfilter -e "@.sources['$section'].status" 2>/dev/null || echo "")
local last_success=$(echo "$metadata_content" | jsonfilter -e "@.sources['$section'].last_success" 2>/dev/null || echo "")
[ -n "$status" ] && json_add_string "status" "$status"
[ -n "$last_success" ] && json_add_string "last_success" "$last_success"
fi
json_close_object
sources_count=$((sources_count + 1))
}
config_foreach _add_src_info source
if [ "$sources_count" -eq 0 ]; then
_add_default_src "github" "remote" "https://raw.githubusercontent.com/CyberMind-FR/secubox-openwrt/refs/heads/master/package/secubox/secubox-core/root/usr/share/secubox/catalog.json" "" 1
_add_default_src "embedded" "embedded" "" "/usr/share/secubox/catalog.json" 999
json_close_array
json_add_boolean "defaults" true
json_add_string "message" "Catalog config empty, using built-in defaults"
else
json_close_array
fi
json_dump
}
# Set catalog source
_do_set_catalog_source() {
local source="$1"
local CONFIG_NAME="secubox-appstore"
local SECTION_NAME=$(uci -q show "$CONFIG_NAME" | grep "=settings" | head -n1 | cut -d'.' -f2 | cut -d'=' -f1)
[ -z "$SECTION_NAME" ] && SECTION_NAME="main"
if [ -n "$source" ]; then
if uci set "${CONFIG_NAME}.${SECTION_NAME}.force_source=$source" >/dev/null 2>&1 && \
uci commit "$CONFIG_NAME" >/dev/null 2>&1; then
json_init
json_add_boolean "success" 1
json_add_string "message" "Catalog source set to: $source"
json_dump
else
json_error "Failed to update UCI config"
fi
else
json_error "No source specified"
fi
}
# Get app versions
_do_get_app_versions() {
local app_id="$1"
local CATALOG_FILE="/usr/share/secubox/catalog.json"
local METADATA_FILE="/var/lib/secubox/catalog-metadata.json"
json_init
if [ -f "$CATALOG_FILE" ]; then
local pkg_version=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].pkg_version" 2>/dev/null)
local app_version=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].app_version" 2>/dev/null)
[ -n "$pkg_version" ] && json_add_string "catalog_pkg_version" "$pkg_version"
[ -n "$app_version" ] && json_add_string "catalog_app_version" "$app_version"
fi
local pkg_name=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].packages.required[0]" 2>/dev/null)
if [ -n "$pkg_name" ]; then
local installed_version=$(opkg list-installed | grep "^$pkg_name " | awk '{print $3}')
[ -n "$installed_version" ] && json_add_string "installed_version" "$installed_version"
fi
if [ -f "$METADATA_FILE" ]; then
local update_available=$(jsonfilter -i "$METADATA_FILE" -e "@.installed_apps['$app_id'].update_available" 2>/dev/null)
[ -n "$update_available" ] && json_add_boolean "update_available" "$update_available"
fi
json_add_string "app_id" "$app_id"
json_dump
}
# Get widget data
_do_get_widget_data() {
local app_id="$1"
local CATALOG_FILE="/usr/share/secubox/catalog.json"
json_init
json_add_string "app_id" "$app_id"
json_add_int "timestamp" "$(date +%s)"
if [ -f "$CATALOG_FILE" ]; then
local widget_enabled=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].widget.enabled" 2>/dev/null)
if [ "$widget_enabled" = "true" ]; then
json_add_boolean "widget_enabled" true
local catalog_version=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].version" 2>/dev/null)
local pkg_version=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].pkg_version" 2>/dev/null)
[ -n "$catalog_version" ] && json_add_string "catalog_version" "$catalog_version"
[ -n "$pkg_version" ] && json_add_string "pkg_version" "$pkg_version"
local installed_version=""
if [ -n "$pkg_version" ]; then
local package_name=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[@.id='$app_id'].packages.required[0]" 2>/dev/null)
if [ -n "$package_name" ]; then
installed_version=$(opkg info "$package_name" 2>/dev/null | awk '/^Version:/ {print $2}')
fi
fi
[ -n "$installed_version" ] && json_add_string "installed_version" "$installed_version"
json_add_boolean "installed" false
json_add_boolean "running" false
json_add_string "status" "unknown"
json_add_array "metrics"
json_close_array
else
json_add_boolean "widget_enabled" false
fi
else
json_add_boolean "widget_enabled" false
fi
json_dump
}

View File

@ -0,0 +1,38 @@
#!/bin/sh
#
# SecuBox RPCD - Core Methods
# Status, version, reload
#
# Register methods
list_methods_core() {
add_method "getStatus"
add_method "getVersion"
add_method "reload"
}
# Handle method calls
handle_core() {
local method="$1"
case "$method" in
getStatus)
/usr/sbin/secubox-core status
;;
getVersion)
json_init
json_add_string "version" "0.8.0"
json_add_string "core" "secubox-core"
json_add_string "build_date" "$(date -u +%Y-%m-%d)"
json_dump
;;
reload)
/usr/sbin/secubox-core reload
json_init
json_add_boolean "success" 1
json_dump
;;
*)
return 1
;;
esac
}

View File

@ -0,0 +1,219 @@
#!/bin/sh
#
# SecuBox RPCD - Dashboard Data
# Dashboard summary, public IPs, quick actions, logs
#
# Register methods
list_methods_dashboard() {
add_method "get_dashboard_data"
add_method "get_public_ips"
add_method "refresh_public_ips"
add_method_str "quick_action" "action"
json_add_object "getLogs"
json_add_string "service" "string"
json_add_int "lines" "integer"
json_close_object
}
# Handle method calls
handle_dashboard() {
local method="$1"
case "$method" in
get_dashboard_data)
_do_dashboard_data
;;
get_public_ips)
_do_public_ips
;;
refresh_public_ips)
_do_refresh_public_ips
;;
quick_action)
read_input_json
local action=$(get_input "action")
_do_quick_action "$action"
;;
getLogs)
read_input_json
local service=$(get_input "service")
local lines=$(get_input_int "lines" 100)
_do_get_logs "$service" "$lines"
;;
*)
return 1
;;
esac
}
# Dashboard summary data (optimized - no slow appstore call)
_do_dashboard_data() {
json_init
# Fast module counting
local total_modules=0
local running_modules=0
local CATALOG_FILE="/usr/share/secubox/catalog.json"
if [ -f "$CATALOG_FILE" ]; then
total_modules=$(jsonfilter -i "$CATALOG_FILE" -e '@.plugins[*].id' 2>/dev/null | wc -l)
fi
[ -z "$total_modules" ] || [ "$total_modules" -eq 0 ] && total_modules=0
# Count running LXC containers
local lxc_running=$(lxc-ls --running 2>/dev/null | wc -w)
lxc_running=${lxc_running:-0}
# Count running init services that are SecuBox-related
local svc_running=0
for svc in crowdsec tor haproxy netifyd syslog-ng; do
if pgrep -f "$svc" >/dev/null 2>&1; then
svc_running=$((svc_running + 1))
fi
done
running_modules=$((lxc_running + svc_running))
# Get system info
local uptime_seconds=$(get_uptime_seconds)
local load_avg=$(get_load_avg)
json_add_object "status"
json_add_string "version" "0.8.0"
json_add_int "uptime" "$uptime_seconds"
json_add_string "load" "$load_avg"
json_close_object
json_add_object "counts"
json_add_int "total" "$total_modules"
json_add_int "running" "$running_modules"
json_add_int "lxc_running" "$lxc_running"
json_add_int "services_running" "$svc_running"
json_close_object
json_dump
}
# Public IPs (cached)
_do_public_ips() {
json_init
local cache_v4="/tmp/secubox_public_ipv4"
local cache_v6="/tmp/secubox_public_ipv6"
local ipv4="" ipv6=""
[ -f "$cache_v4" ] && ipv4=$(cat "$cache_v4" 2>/dev/null)
[ -f "$cache_v6" ] && ipv6=$(cat "$cache_v6" 2>/dev/null)
# Fallback: get from interface
if [ -z "$ipv4" ]; then
ipv4=$(ip -4 addr show scope global 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
if [ -z "$ipv6" ]; then
ipv6=$(ip -6 addr show scope global 2>/dev/null | grep -oE '[0-9a-f:]+::[0-9a-f:]+' | head -1)
fi
json_add_string "ipv4" "${ipv4:-N/A}"
json_add_string "ipv6" "${ipv6:-N/A}"
json_add_boolean "ipv4_available" "$([ -n "$ipv4" ] && [ "$ipv4" != "N/A" ] && echo 1 || echo 0)"
json_add_boolean "ipv6_available" "$([ -n "$ipv6" ] && [ "$ipv6" != "N/A" ] && echo 1 || echo 0)"
json_dump
}
# Refresh public IPs in background
_do_refresh_public_ips() {
json_init
(
for svc in "https://api.ipify.org" "https://ipv4.icanhazip.com"; do
local ipv4=$(curl -4 -s --connect-timeout 2 --max-time 3 "$svc" 2>/dev/null | tr -d '\n')
[ -n "$ipv4" ] && { echo "$ipv4" > /tmp/secubox_public_ipv4; break; }
done
for svc in "https://api64.ipify.org" "https://ipv6.icanhazip.com"; do
local ipv6=$(curl -6 -s --connect-timeout 2 --max-time 3 "$svc" 2>/dev/null | tr -d '\n')
[ -n "$ipv6" ] && { echo "$ipv6" > /tmp/secubox_public_ipv6; break; }
done
) &
json_add_boolean "success" 1
json_dump
}
# Quick actions
_do_quick_action() {
local action="$1"
json_init
case "$action" in
restart_services)
for svc in haproxy crowdsec tor netifyd; do
if [ -x "/etc/init.d/$svc" ]; then
/etc/init.d/$svc restart 2>/dev/null &
elif [ -x "/usr/sbin/${svc}ctl" ]; then
/usr/sbin/${svc}ctl restart 2>/dev/null &
fi
done
json_add_boolean "success" 1
json_add_string "message" "Services restart initiated"
;;
restart_*)
local svc_name="${action#restart_}"
if [ -x "/etc/init.d/$svc_name" ]; then
/etc/init.d/$svc_name restart 2>/dev/null
json_add_boolean "success" 1
json_add_string "message" "Service $svc_name restarted"
elif [ -x "/usr/sbin/${svc_name}ctl" ]; then
/usr/sbin/${svc_name}ctl restart 2>/dev/null
json_add_boolean "success" 1
json_add_string "message" "Service $svc_name restarted"
else
json_add_boolean "success" 0
json_add_string "message" "Service $svc_name not found"
fi
;;
update_packages)
opkg update 2>/dev/null &
json_add_boolean "success" 1
json_add_string "message" "Package update initiated"
;;
view_logs)
json_add_boolean "success" 1
json_add_string "redirect" "/cgi-bin/luci/admin/status/syslog"
;;
export_config)
if [ -x "/usr/sbin/secubox-recovery" ]; then
local snapshot_name="export-$(date +%Y%m%d-%H%M%S)"
/usr/sbin/secubox-recovery snapshot "$snapshot_name" 2>/dev/null
json_add_boolean "success" 1
json_add_string "message" "Configuration exported as $snapshot_name"
else
json_add_boolean "success" 0
json_add_string "message" "Recovery system not available"
fi
;;
*)
json_add_boolean "success" 0
json_add_string "message" "Unknown action: $action"
;;
esac
json_dump
}
# Get logs
_do_get_logs() {
local service="$1"
local lines="$2"
json_init
json_add_array "logs"
if [ -n "$service" ]; then
logread -e "$service" | tail -n "$lines" | while read -r line; do
json_add_string "" "$line"
done
else
logread | tail -n "$lines" | while read -r line; do
json_add_string "" "$line"
done
fi
json_close_array
json_dump
}

View File

@ -0,0 +1,158 @@
#!/bin/sh
#
# SecuBox RPCD - Feedback & Issue Management
# Report, resolve, search issues
#
# Register methods
list_methods_feedback() {
json_add_object "report_issue"
json_add_string "app_id" "string"
json_add_string "type" "string"
json_add_string "summary" "string"
json_add_string "details" "string"
json_close_object
json_add_object "resolve_issue"
json_add_string "issue_id" "string"
json_add_string "description" "string"
json_close_object
add_method_str "search_resolutions" "keyword"
add_method_str "list_issues" "filter"
}
# Handle method calls
handle_feedback() {
local method="$1"
case "$method" in
report_issue)
read_input_json
local app_id=$(get_input "app_id")
local type=$(get_input "type")
local summary=$(get_input "summary")
local details=$(get_input "details")
local result=$(/usr/sbin/secubox-feedback report "$app_id" --type "${type:-bug}" --summary "$summary" --details "$details" 2>&1)
if [ $? -eq 0 ]; then
local issue_num=$(echo "$result" | grep -oE 'Issue #[0-9]+' | grep -oE '[0-9]+')
json_init
json_add_boolean "success" 1
json_add_string "message" "Issue reported"
[ -n "$issue_num" ] && json_add_int "issue_number" "$issue_num"
json_dump
else
json_error "$result"
fi
;;
resolve_issue)
read_input_json
local issue_id=$(get_input "issue_id")
local description=$(get_input "description")
local result=$(/usr/sbin/secubox-feedback resolve "$issue_id" --description "$description" 2>&1)
if [ $? -eq 0 ]; then
json_success "Resolution added"
else
json_error "$result"
fi
;;
search_resolutions)
read_input_json
local keyword=$(get_input "keyword")
_do_search_resolutions "$keyword"
;;
list_issues)
read_input_json
local filter=$(get_input "filter")
_do_list_issues "$filter"
;;
*)
return 1
;;
esac
}
# Search resolutions
_do_search_resolutions() {
local keyword="$1"
local RESOLUTIONS_FILE="/var/lib/secubox/feedback/resolutions.json"
json_init
json_add_string "keyword" "$keyword"
json_add_array "results"
if [ -f "$RESOLUTIONS_FILE" ]; then
local idx=0
while true; do
local res_id=$(jsonfilter -i "$RESOLUTIONS_FILE" -e "@.resolutions[$idx].id" 2>/dev/null)
[ -z "$res_id" ] && break
local description=$(jsonfilter -i "$RESOLUTIONS_FILE" -e "@.resolutions[$idx].description" 2>/dev/null)
local issue_summary=$(jsonfilter -i "$RESOLUTIONS_FILE" -e "@.resolutions[$idx].issue_summary" 2>/dev/null)
local app_id=$(jsonfilter -i "$RESOLUTIONS_FILE" -e "@.resolutions[$idx].app_id" 2>/dev/null)
if echo "$description $issue_summary $app_id" | grep -qi "$keyword"; then
local issue_num=$(jsonfilter -i "$RESOLUTIONS_FILE" -e "@.resolutions[$idx].issue_number" 2>/dev/null)
local upvotes=$(jsonfilter -i "$RESOLUTIONS_FILE" -e "@.resolutions[$idx].upvotes" 2>/dev/null)
local verified=$(jsonfilter -i "$RESOLUTIONS_FILE" -e "@.resolutions[$idx].verified" 2>/dev/null)
json_add_object ""
json_add_string "id" "$res_id"
json_add_int "issue_number" "$issue_num"
json_add_string "app_id" "$app_id"
json_add_string "issue_summary" "$issue_summary"
json_add_string "description" "$description"
json_add_int "upvotes" "${upvotes:-0}"
json_add_boolean "verified" "$([ "$verified" = "true" ] && echo 1 || echo 0)"
json_close_object
fi
idx=$((idx + 1))
done
fi
json_close_array
json_dump
}
# List issues
_do_list_issues() {
local filter="$1"
local ISSUES_FILE="/var/lib/secubox/feedback/issues.json"
json_init
json_add_array "issues"
if [ -f "$ISSUES_FILE" ]; then
local idx=0
while true; do
local issue_id=$(jsonfilter -i "$ISSUES_FILE" -e "@.issues[$idx].id" 2>/dev/null)
[ -z "$issue_id" ] && break
local status=$(jsonfilter -i "$ISSUES_FILE" -e "@.issues[$idx].status" 2>/dev/null)
if [ -n "$filter" ] && [ "$filter" != "all" ] && [ "$filter" != "$status" ]; then
idx=$((idx + 1))
continue
fi
local issue_num=$(jsonfilter -i "$ISSUES_FILE" -e "@.issues[$idx].number" 2>/dev/null)
local app_id=$(jsonfilter -i "$ISSUES_FILE" -e "@.issues[$idx].app_id" 2>/dev/null)
local summary=$(jsonfilter -i "$ISSUES_FILE" -e "@.issues[$idx].summary" 2>/dev/null)
local issue_type=$(jsonfilter -i "$ISSUES_FILE" -e "@.issues[$idx].type" 2>/dev/null)
local created=$(jsonfilter -i "$ISSUES_FILE" -e "@.issues[$idx].created_at" 2>/dev/null)
json_add_object ""
json_add_string "id" "$issue_id"
json_add_int "number" "$issue_num"
json_add_string "app_id" "$app_id"
json_add_string "summary" "$summary"
json_add_string "type" "$issue_type"
json_add_string "status" "$status"
json_add_string "created_at" "$created"
json_close_object
idx=$((idx + 1))
done
fi
json_close_array
json_dump
}

View File

@ -0,0 +1,74 @@
#!/bin/sh
#
# SecuBox RPCD - Feed Management
# List, add, remove, share, import feeds
#
# Register methods
list_methods_feeds() {
add_method "list_feeds"
json_add_object "add_feed"
json_add_string "name" "string"
json_add_string "url" "string"
json_add_string "feed_type" "string"
json_add_string "description" "string"
json_close_object
add_method_str "remove_feed" "name"
add_method_str "share_feed" "name"
add_method_str "import_feed" "url"
}
# Handle method calls
handle_feeds() {
local method="$1"
case "$method" in
list_feeds)
/usr/sbin/secubox-feed-manager list --json
;;
add_feed)
read_input_json
local name=$(get_input "name")
local url=$(get_input "url")
local feed_type=$(get_input "feed_type")
local description=$(get_input "description")
local result=$(/usr/sbin/secubox-feed-manager add "$name" "$url" --type "${feed_type:-unpublished}" --description "$description" 2>&1)
if [ $? -eq 0 ]; then
json_init
json_add_boolean "success" 1
json_add_string "message" "Feed added successfully"
json_add_string "name" "$name"
json_dump
else
json_error "$result"
fi
;;
remove_feed)
read_input_json
local name=$(get_input "name")
local result=$(/usr/sbin/secubox-feed-manager remove "$name" 2>&1)
if [ $? -eq 0 ]; then
json_success "Feed removed"
else
json_error "$result"
fi
;;
share_feed)
read_input_json
local name=$(get_input "name")
/usr/sbin/secubox-feed-manager share "$name"
;;
import_feed)
read_input_json
local url=$(get_input "url")
local result=$(/usr/sbin/secubox-feed-manager import "$url" 2>&1)
if [ $? -eq 0 ]; then
json_success "Feed imported"
else
json_error "$result"
fi
;;
*)
return 1
;;
esac
}

View File

@ -0,0 +1,432 @@
#!/bin/sh
#
# SecuBox RPCD - Health & Diagnostics
# Network health, vital services, full health report, alerts
#
# Register methods
list_methods_health() {
json_add_object "runDiagnostics"
json_add_string "target" "string"
json_close_object
add_method "getHealth"
add_method "get_network_health"
add_method "get_vital_services"
add_method "get_full_health_report"
add_method "get_system_health"
add_method "get_alerts"
}
# Handle method calls
handle_health() {
local method="$1"
case "$method" in
runDiagnostics)
read_input_json
local target=$(get_input "target")
/usr/sbin/secubox-diagnostics run "${target:-all}"
;;
getHealth)
/usr/sbin/secubox-core health
;;
get_network_health)
_do_network_health
;;
get_vital_services)
_do_vital_services
;;
get_full_health_report)
_do_full_health_report
;;
get_system_health)
_do_system_health
;;
get_alerts)
_do_get_alerts
;;
*)
return 1
;;
esac
}
# Network health monitoring - detects CRC errors, link flapping
_do_network_health() {
local DMESG_LINES=500
local FLAP_THRESHOLD=5
local CRC_THRESHOLD=10
json_init
json_add_string "timestamp" "$(get_timestamp)"
json_add_object "interfaces"
local overall="healthy"
local critical_count=0
local warning_count=0
for iface_path in /sys/class/net/eth* /sys/class/net/wan* /sys/class/net/lan*; do
[ -d "$iface_path" ] || continue
[ -d "$iface_path/device" ] || continue
local iface=$(basename "$iface_path")
local current_state=$(cat "$iface_path/operstate" 2>/dev/null || echo "unknown")
local crc_count=$(dmesg | tail -n $DMESG_LINES | grep -c "$iface.*crc error" 2>/dev/null)
crc_count=${crc_count:-0}
local link_up=$(dmesg | tail -n $DMESG_LINES | grep -c "$iface: Link is Up" 2>/dev/null)
link_up=${link_up:-0}
local link_down=$(dmesg | tail -n $DMESG_LINES | grep -c "$iface: Link is Down" 2>/dev/null)
link_down=${link_down:-0}
local link_changes=$((link_up + link_down))
local status="ok"
local issues=""
if [ "$crc_count" -ge "$CRC_THRESHOLD" ]; then
status="critical"
issues="CRC errors ($crc_count)"
critical_count=$((critical_count + 1))
fi
if [ "$link_changes" -ge "$FLAP_THRESHOLD" ]; then
[ "$status" = "ok" ] && status="warning"
[ -n "$issues" ] && issues="$issues; "
issues="${issues}Link flapping ($link_changes changes)"
warning_count=$((warning_count + 1))
fi
local rx_errors=$(cat "$iface_path/statistics/rx_errors" 2>/dev/null || echo 0)
local tx_errors=$(cat "$iface_path/statistics/tx_errors" 2>/dev/null || echo 0)
json_add_object "$iface"
json_add_string "status" "$status"
json_add_string "state" "$current_state"
json_add_int "crc_errors" "$crc_count"
json_add_int "link_changes" "$link_changes"
json_add_int "rx_errors" "$rx_errors"
json_add_int "tx_errors" "$tx_errors"
json_add_string "issues" "$issues"
json_close_object
done
json_close_object
if [ "$critical_count" -gt 0 ]; then
overall="critical"
elif [ "$warning_count" -gt 0 ]; then
overall="warning"
fi
json_add_string "overall" "$overall"
json_add_int "critical_interfaces" "$critical_count"
json_add_int "warning_interfaces" "$warning_count"
if [ "$overall" != "healthy" ]; then
json_add_array "recommendations"
[ "$critical_count" -gt 0 ] && json_add_string "" "Check/replace Ethernet cables"
[ "$critical_count" -gt 0 ] && json_add_string "" "Try different port on switch/modem"
[ "$warning_count" -gt 0 ] && json_add_string "" "Monitor link stability"
json_close_array
fi
json_dump
}
# Vital services monitoring
_do_vital_services() {
json_init
json_add_string "timestamp" "$(get_timestamp)"
_check_svc() {
local name="$1" category="$2" check_type="$3" check_value="$4" description="$5" critical="$6"
local status="unknown" details=""
case "$check_type" in
process)
if pgrep -f "$check_value" >/dev/null 2>&1; then
status="running"
else
status="stopped"
fi
;;
port)
if check_port_listening "$check_value"; then
status="running"
details="Port $check_value listening"
else
status="stopped"
details="Port $check_value not listening"
fi
;;
init)
status=$(check_init_service "$check_value")
;;
lxc)
status=$(check_lxc_status "$check_value")
;;
esac
json_add_object ""
json_add_string "name" "$name"
json_add_string "category" "$category"
json_add_string "status" "$status"
json_add_string "description" "$description"
json_add_boolean "critical" "${critical:-0}"
[ -n "$details" ] && json_add_string "details" "$details"
json_close_object
}
# Core Infrastructure Services
json_add_array "core"
_check_svc "SSH" "remote" "port" "22" "Remote shell access" 1
_check_svc "HTTPS Admin" "remote" "port" "8444" "LuCI admin interface" 1
_check_svc "DNS" "network" "port" "53" "Domain name resolution" 1
_check_svc "DHCP" "network" "process" "dnsmasq" "IP address assignment" 1
_check_svc "Firewall" "security" "process" "fw4" "Network firewall" 1
json_close_array
# Security Services
json_add_array "security"
_check_svc "CrowdSec" "security" "process" "crowdsec" "Intrusion prevention" 1
_check_svc "CrowdSec Bouncer" "security" "process" "crowdsec-firewall-bouncer" "Firewall bouncer" 1
_check_svc "Tor" "privacy" "init" "tor" "Anonymous routing" 0
json_close_array
# Web Publishing Services
json_add_array "publishers"
_check_svc "HAProxy" "proxy" "lxc" "haproxy" "Load balancer & reverse proxy" 1
_check_svc "HexoJS" "cms" "lxc" "hexojs" "Static blog generator" 0
_check_svc "Gitea" "devops" "lxc" "gitea" "Git repository hosting" 0
_check_svc "Streamlit" "app" "lxc" "streamlit" "Python web apps" 0
json_close_array
# Media & App Services
json_add_array "apps"
_check_svc "Lyrion" "media" "lxc" "lyrion" "Music streaming server" 0
_check_svc "MagicMirror" "display" "lxc" "magicmirror2" "Smart mirror display" 0
_check_svc "PicoBrew" "app" "lxc" "picobrew" "Brewing automation" 0
json_close_array
# Monitoring Services
json_add_array "monitoring"
_check_svc "Netifyd" "monitoring" "process" "netifyd" "Network intelligence" 0
_check_svc "Syslog-ng" "logging" "process" "syslog-ng" "System logging" 1
json_close_array
# Calculate summary
json_add_object "summary"
local total=0
for svc in /etc/init.d/*; do
[ -x "$svc" ] || continue
total=$((total + 1))
done
local lxc_running=$(lxc-ls --running 2>/dev/null | wc -w)
local lxc_total=$(lxc-ls 2>/dev/null | wc -w)
json_add_int "init_services" "$total"
json_add_int "lxc_running" "${lxc_running:-0}"
json_add_int "lxc_total" "${lxc_total:-0}"
json_close_object
json_dump
}
# Full health report
_do_full_health_report() {
json_init
json_add_string "timestamp" "$(get_timestamp)"
json_add_string "hostname" "$(uci get system.@system[0].hostname 2>/dev/null || hostname)"
# System info
json_add_object "system"
json_add_int "uptime" "$(get_uptime_seconds)"
json_add_string "load" "$(get_load_avg)"
local mem_pct=$(get_memory_percent)
json_add_int "memory_percent" "$mem_pct"
local disk_pct=$(get_disk_percent)
json_add_int "disk_percent" "${disk_pct:-0}"
json_close_object
# Network Health Summary
json_add_object "network"
local net_overall="healthy"
local net_issues=0
for iface_path in /sys/class/net/eth* /sys/class/net/wan*; do
[ -d "$iface_path" ] || continue
[ -d "$iface_path/device" ] || continue
local iface=$(basename "$iface_path")
local crc=$(dmesg | tail -n 500 | grep -c "$iface.*crc error" 2>/dev/null)
crc=${crc:-0}
local flap=$(dmesg | tail -n 500 | grep -c "$iface: Link is" 2>/dev/null)
flap=${flap:-0}
if [ "$crc" -ge 10 ] || [ "$flap" -ge 10 ]; then
net_overall="critical"
net_issues=$((net_issues + 1))
json_add_object "$iface"
json_add_string "status" "critical"
json_add_int "crc_errors" "$crc"
json_add_int "link_changes" "$flap"
json_close_object
fi
done
json_add_string "overall" "$net_overall"
json_add_int "issues" "$net_issues"
json_close_object
# Critical Services Status
json_add_object "services"
local svc_ok=0 svc_down=0
for svc in sshd dropbear dnsmasq haproxy crowdsec; do
if pgrep -x "$svc" >/dev/null 2>&1 || pgrep -f "$svc" >/dev/null 2>&1; then
svc_ok=$((svc_ok + 1))
else
if [ -f "/etc/init.d/$svc" ] && /etc/init.d/$svc enabled 2>/dev/null; then
svc_down=$((svc_down + 1))
fi
fi
done
local lxc_expected=$(lxc-ls 2>/dev/null | wc -w)
local lxc_running=$(lxc-ls --running 2>/dev/null | wc -w)
json_add_int "services_ok" "$svc_ok"
json_add_int "services_down" "$svc_down"
json_add_int "containers_running" "${lxc_running:-0}"
json_add_int "containers_total" "${lxc_expected:-0}"
if [ "$svc_down" -gt 0 ]; then
json_add_string "overall" "warning"
else
json_add_string "overall" "healthy"
fi
json_close_object
# Overall health score
local health_score=100
[ "$net_overall" = "critical" ] && health_score=$((health_score - 30))
[ "$svc_down" -gt 0 ] && health_score=$((health_score - (svc_down * 10)))
[ "$mem_pct" -gt 90 ] && health_score=$((health_score - 10))
[ "${disk_pct:-0}" -gt 90 ] && health_score=$((health_score - 10))
json_add_int "health_score" "$health_score"
if [ "$health_score" -ge 80 ]; then
json_add_string "overall_status" "healthy"
elif [ "$health_score" -ge 50 ]; then
json_add_string "overall_status" "warning"
else
json_add_string "overall_status" "critical"
fi
# Alerts
json_add_array "alerts"
[ "$net_overall" = "critical" ] && {
json_add_object ""
json_add_string "level" "critical"
json_add_string "message" "Network interface issues detected - check cables"
json_close_object
}
[ "$svc_down" -gt 0 ] && {
json_add_object ""
json_add_string "level" "warning"
json_add_string "message" "$svc_down critical service(s) not running"
json_close_object
}
[ "$mem_pct" -gt 90 ] && {
json_add_object ""
json_add_string "level" "warning"
json_add_string "message" "High memory usage: ${mem_pct}%"
json_close_object
}
json_close_array
json_dump
}
# System health metrics
_do_system_health() {
json_init
local uptime_seconds=$(get_uptime_seconds)
local load1=$(awk '{print $1}' /proc/loadavg)
local cpu_count=$(grep -c ^processor /proc/cpuinfo)
[ "$cpu_count" -le 0 ] && cpu_count=1
local cpu_percent=$(awk -v load="$load1" -v cores="$cpu_count" 'BEGIN {printf "%.0f", (load / cores) * 100}')
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
local mem_free=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
mem_free=${mem_free:-0}
[ "$mem_total" -le 0 ] && mem_total=1
local mem_used=$((mem_total - mem_free))
local mem_percent=$(awk -v used="$mem_used" -v total="$mem_total" 'BEGIN {printf "%.0f", (used / total) * 100}')
local disk_info=$(df / | tail -1)
local disk_total=$(echo "$disk_info" | awk '{print $2}')
local disk_used=$(echo "$disk_info" | awk '{print $3}')
disk_used=${disk_used:-0}
[ -z "$disk_total" ] || [ "$disk_total" -le 0 ] && { disk_total=0; disk_used=0; }
local disk_free=$((disk_total - disk_used))
local disk_percent=$(echo "$disk_info" | awk '{print $5}' | tr -d '%')
[ -n "$disk_percent" ] || disk_percent=0
local overall_score=$(awk -v c="$cpu_percent" -v m="$mem_percent" -v d="$disk_percent" 'BEGIN {printf "%.0f", 100 - ((c + m + d) / 3)}')
json_add_int "uptime" "$uptime_seconds"
local overall_status="healthy"
[ "$overall_score" -le 70 ] && overall_status="warning"
json_add_object "overall"
json_add_int "score" "$overall_score"
json_add_string "status" "$overall_status"
json_close_object
json_add_object "cpu"
json_add_int "usage_percent" "$cpu_percent"
json_add_string "load" "$(get_load_avg)"
json_add_int "count" "$cpu_count"
json_close_object
json_add_object "memory"
json_add_int "total_kb" "$mem_total"
json_add_int "used_kb" "$mem_used"
json_add_int "free_kb" "$mem_free"
json_add_int "usage_percent" "$mem_percent"
json_close_object
json_add_object "disk"
json_add_int "total_kb" "$disk_total"
json_add_int "used_kb" "$disk_used"
json_add_int "free_kb" "$disk_free"
json_add_int "usage_percent" "$disk_percent"
json_close_object
json_dump
}
# Get system alerts
_do_get_alerts() {
json_init
json_add_array "alerts"
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
local mem_free=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
local mem_percent=$(awk "BEGIN {printf \"%.0f\", (($mem_total - $mem_free) / $mem_total) * 100}")
if [ "$mem_percent" -gt 90 ]; then
json_add_object ""
json_add_string "id" "high_memory"
json_add_string "level" "warning"
json_add_string "title" "High Memory Usage"
json_add_string "message" "Memory usage is at ${mem_percent}%"
json_add_int "timestamp" "$(date +%s)"
json_close_object
fi
local disk_percent=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$disk_percent" -gt 85 ]; then
json_add_object ""
json_add_string "id" "high_disk"
json_add_string "level" "warning"
json_add_string "title" "High Disk Usage"
json_add_string "message" "Disk usage is at ${disk_percent}%"
json_add_int "timestamp" "$(date +%s)"
json_close_object
fi
json_close_array
json_dump
}

View File

@ -0,0 +1,108 @@
#!/bin/sh
#
# SecuBox RPCD - Module Management
# Install, remove, update, info
#
# Register methods
list_methods_modules() {
add_method "getModules"
add_method_str "getModuleInfo" "module"
json_add_object "installModule"
json_add_string "module" "string"
json_add_boolean "dryrun" "boolean"
json_close_object
add_method_str "removeModule" "module"
add_method_str "updateModule" "module"
# Module control
add_method_str "start_module" "module"
add_method_str "stop_module" "module"
add_method_str "restart_module" "module"
add_method_str "enable_module" "module"
add_method_str "disable_module" "module"
}
# Handle method calls
handle_modules() {
local method="$1"
case "$method" in
getModules)
/usr/sbin/secubox-appstore list --json
;;
getModuleInfo)
read_input_json
local module=$(get_input "module")
/usr/sbin/secubox-appstore info "$module"
;;
installModule)
read_input_json
local module=$(get_input "module")
local dryrun=$(get_input "dryrun")
/usr/sbin/secubox-appstore install "$module" ${dryrun:+--dryrun}
;;
removeModule)
read_input_json
local module=$(get_input "module")
/usr/sbin/secubox-appstore remove "$module"
;;
updateModule)
read_input_json
local module=$(get_input "module")
/usr/sbin/secubox-appstore update "$module"
;;
start_module)
read_input_json
local module=$(get_input "module")
if [ -x "/etc/init.d/$module" ]; then
/etc/init.d/$module start
json_success "Module $module started"
else
json_error "Module $module not found"
fi
;;
stop_module)
read_input_json
local module=$(get_input "module")
if [ -x "/etc/init.d/$module" ]; then
/etc/init.d/$module stop
json_success "Module $module stopped"
else
json_error "Module $module not found"
fi
;;
restart_module)
read_input_json
local module=$(get_input "module")
if [ -x "/etc/init.d/$module" ]; then
/etc/init.d/$module restart
json_success "Module $module restarted"
else
json_error "Module $module not found"
fi
;;
enable_module)
read_input_json
local module=$(get_input "module")
if [ -x "/etc/init.d/$module" ]; then
/etc/init.d/$module enable
json_success "Module $module enabled"
else
json_error "Module $module not found"
fi
;;
disable_module)
read_input_json
local module=$(get_input "module")
if [ -x "/etc/init.d/$module" ]; then
/etc/init.d/$module disable
json_success "Module $module disabled"
else
json_error "Module $module not found"
fi
;;
*)
return 1
;;
esac
}

View File

@ -0,0 +1,267 @@
#!/bin/sh
#
# SecuBox RPCD - Network & WAN Access
# WAN access, services discovery, proxy mode
#
# Register methods
list_methods_network() {
add_method "get_wan_access"
json_add_object "set_wan_access"
json_add_boolean "enabled" "boolean"
json_add_boolean "https_enabled" "boolean"
json_add_int "https_port" "integer"
json_add_boolean "http_enabled" "boolean"
json_add_int "http_port" "integer"
json_add_boolean "ssh_enabled" "boolean"
json_add_int "ssh_port" "integer"
json_close_object
add_method "apply_wan_access"
add_method "get_services"
add_method "get_proxy_mode"
add_method_str "set_proxy_mode" "mode"
}
# Handle method calls
handle_network() {
local method="$1"
case "$method" in
get_wan_access)
/usr/sbin/secubox-wan-access json
;;
set_wan_access)
read_input_json
local enabled=$(get_input "enabled")
local https_enabled=$(get_input "https_enabled")
local https_port=$(get_input "https_port")
local http_enabled=$(get_input "http_enabled")
local http_port=$(get_input "http_port")
local ssh_enabled=$(get_input "ssh_enabled")
local ssh_port=$(get_input "ssh_port")
[ -n "$enabled" ] && uci set secubox.remote.enabled="$enabled"
[ -n "$https_enabled" ] && uci set secubox.remote.https_enabled="$https_enabled"
[ -n "$https_port" ] && uci set secubox.remote.https_port="$https_port"
[ -n "$http_enabled" ] && uci set secubox.remote.http_enabled="$http_enabled"
[ -n "$http_port" ] && uci set secubox.remote.http_port="$http_port"
[ -n "$ssh_enabled" ] && uci set secubox.remote.ssh_enabled="$ssh_enabled"
[ -n "$ssh_port" ] && uci set secubox.remote.ssh_port="$ssh_port"
uci commit secubox
json_success "WAN access settings updated"
;;
apply_wan_access)
/usr/sbin/secubox-wan-access apply >/dev/null 2>&1
json_success "WAN access rules applied"
;;
get_services)
_do_get_services
;;
get_proxy_mode)
_do_get_proxy_mode
;;
set_proxy_mode)
read_input_json
local mode=$(get_input "mode")
_do_set_proxy_mode "$mode"
;;
*)
return 1
;;
esac
}
# Discover listening services
_do_get_services() {
local TMP_SERVICES="/tmp/services_$$"
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 -u > "$TMP_SERVICES"
json_init
json_add_array "services"
while read port local proc; do
local addr=$(echo "$local" | sed 's/:[^:]*$//')
local name="" icon="" category="other" path=""
case "$port" in
22) name="SSH"; icon="lock"; category="system" ;;
53) name="DNS"; icon="globe"; category="system" ;;
80) name="HTTP"; icon="arrow"; path="/"; category="proxy" ;;
443) name="HTTPS"; icon="shield"; path="/"; category="proxy" ;;
2222) name="Gitea SSH"; icon="git"; category="app" ;;
3000) name="Gitea"; icon="git"; path=":3000"; category="app" ;;
3483) name="Squeezebox"; icon="music"; category="media" ;;
4000) name="HexoJS"; icon="blog"; path=":4000"; category="app" ;;
6060) name="CrowdSec LAPI"; icon="security"; category="security" ;;
8081) name="LuCI"; icon="settings"; path=":8081"; category="system" ;;
8085) name="MagicMirror2"; icon="app"; path=":8085"; category="app" ;;
8086) name="Netifyd"; icon="chart"; path=":8086"; category="monitoring" ;;
8404) name="HAProxy Stats"; icon="stats"; path=":8404/stats"; category="monitoring" ;;
8444) name="LuCI HTTPS"; icon="admin"; path=":8444"; category="system" ;;
8501) name="Streamlit"; icon="app"; path=":8501"; category="app" ;;
9000) name="Lyrion"; icon="music"; path=":9000"; category="media" ;;
9050) name="Tor SOCKS"; icon="onion"; category="privacy" ;;
9090) name="Lyrion CLI"; icon="music"; category="media" ;;
esac
if [ -z "$name" ]; then
case "$proc" in
sshd|dropbear) name="SSH"; icon="lock"; category="system" ;;
dnsmasq|named|unbound) name="DNS"; icon="globe"; category="system" ;;
haproxy) name="HAProxy"; icon="arrow"; category="proxy" ;;
nginx|uhttpd) name="Web Server"; icon="settings"; category="system" ;;
gitea) name="Gitea"; icon="git"; path=":$port"; category="app" ;;
hexo|node) name="HexoJS"; icon="blog"; path=":$port"; category="app" ;;
crowdsec|lapi) name="CrowdSec"; icon="security"; category="security" ;;
netifyd) name="Netifyd"; icon="chart"; path=":$port"; category="monitoring" ;;
slimserver|squeezeboxserver) name="Lyrion"; icon="music"; path=":$port"; category="media" ;;
tor) name="Tor"; icon="onion"; category="privacy" ;;
streamlit) name="Streamlit"; icon="app"; path=":$port"; category="app" ;;
python*) name="Python App"; icon="app"; path=":$port"; category="app" ;;
*) name="$proc"; icon=""; category="other"; path=":$port" ;;
esac
fi
local external=0
case "$addr" in 0.0.0.0|::) external=1 ;; 127.0.0.1|::1) ;; *) external=1 ;; esac
json_add_object ""
json_add_int "port" "$port"
json_add_string "address" "$addr"
json_add_string "name" "$name"
json_add_string "icon" "$icon"
json_add_string "process" "$proc"
json_add_string "category" "$category"
json_add_boolean "external" "$external"
[ -n "$path" ] && [ "$external" = "1" ] && json_add_string "url" "$path"
json_close_object
done < "$TMP_SERVICES"
rm -f "$TMP_SERVICES"
json_close_array
json_dump
}
# Get proxy mode
_do_get_proxy_mode() {
json_init
local mode="direct"
local wpad_enabled=0
if [ -f "/www/wpad/wpad.dat" ]; then
wpad_enabled=1
if grep -q "SOCKS5.*9050" /www/wpad/wpad.dat 2>/dev/null; then
mode="tor"
elif grep -q "PROXY.*3128" /www/wpad/wpad.dat 2>/dev/null; then
mode="cdn"
elif grep -q "PROXY.*8080" /www/wpad/wpad.dat 2>/dev/null; then
mode="mitmproxy"
fi
fi
local dhcp_wpad=$(uci -q get dhcp.lan.dhcp_option | grep -c "252")
json_add_string "mode" "$mode"
json_add_boolean "wpad_enabled" "$wpad_enabled"
json_add_boolean "dhcp_wpad" "$dhcp_wpad"
json_add_string "pac_url" "http://192.168.255.1/wpad/wpad.dat"
json_dump
}
# Set proxy mode
_do_set_proxy_mode() {
local mode="$1"
json_init
mkdir -p /www/wpad
case "$mode" in
direct)
rm -f /www/wpad/wpad.dat
uci -q delete dhcp.lan.dhcp_option
uci commit dhcp
json_add_boolean "success" 1
json_add_string "message" "Proxy disabled - direct connections"
;;
cdn)
cat > /www/wpad/wpad.dat << 'PACEOF'
function FindProxyForURL(url, host) {
if (isPlainHostName(host) || shExpMatch(host, "*.local") || shExpMatch(host, "*.lan") ||
isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0") ||
isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0") ||
isInNet(dnsResolve(host), "192.168.0.0", "255.255.0.0") ||
isInNet(dnsResolve(host), "127.0.0.0", "255.0.0.0")) {
return "DIRECT";
}
if (url.substring(0, 5) == "http:") {
return "PROXY 192.168.255.1:3128; DIRECT";
}
return "DIRECT";
}
PACEOF
uci set dhcp.lan.dhcp_option="252,http://192.168.255.1/wpad/wpad.dat"
uci commit dhcp
json_add_boolean "success" 1
json_add_string "message" "CDN cache mode enabled - HTTP cached"
;;
tor)
cat > /www/wpad/wpad.dat << 'PACEOF'
function FindProxyForURL(url, host) {
if (isPlainHostName(host) || shExpMatch(host, "*.local") || shExpMatch(host, "*.lan") ||
isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0") ||
isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0") ||
isInNet(dnsResolve(host), "192.168.0.0", "255.255.0.0") ||
isInNet(dnsResolve(host), "127.0.0.0", "255.0.0.0")) {
return "DIRECT";
}
if (url.substring(0, 5) == "http:") {
return "PROXY 192.168.255.1:3128; DIRECT";
}
if (url.substring(0, 6) == "https:") {
return "SOCKS5 192.168.255.1:9050; DIRECT";
}
return "DIRECT";
}
PACEOF
uci set dhcp.lan.dhcp_option="252,http://192.168.255.1/wpad/wpad.dat"
uci commit dhcp
json_add_boolean "success" 1
json_add_string "message" "Tor bypass mode enabled - HTTPS through Tor"
;;
mitmproxy)
cat > /www/wpad/wpad.dat << 'PACEOF'
function FindProxyForURL(url, host) {
if (isPlainHostName(host) || shExpMatch(host, "*.local") || shExpMatch(host, "*.lan") ||
isInNet(dnsResolve(host), "10.0.0.0", "255.0.0.0") ||
isInNet(dnsResolve(host), "172.16.0.0", "255.240.0.0") ||
isInNet(dnsResolve(host), "192.168.0.0", "255.255.0.0") ||
isInNet(dnsResolve(host), "127.0.0.0", "255.0.0.0")) {
return "DIRECT";
}
return "PROXY 192.168.255.1:8080; DIRECT";
}
PACEOF
uci set dhcp.lan.dhcp_option="252,http://192.168.255.1/wpad/wpad.dat"
uci commit dhcp
json_add_boolean "success" 1
json_add_string "message" "mitmproxy mode enabled - all traffic inspectable"
;;
*)
json_add_boolean "success" 0
json_add_string "error" "Unknown mode: $mode"
;;
esac
/etc/init.d/dnsmasq restart >/dev/null 2>&1 &
json_dump
}

View File

@ -0,0 +1,236 @@
#!/bin/sh
#
# SecuBox RPCD - P2P Hub
# Peer management, catalog sharing
#
P2P_DIR="/var/lib/secubox/p2p"
P2P_PEERS_FILE="$P2P_DIR/peers.json"
P2P_CONFIG="$P2P_DIR/config.json"
# Register methods
list_methods_p2p() {
add_method "p2p_get_peers"
add_method "p2p_discover"
json_add_object "p2p_add_peer"
json_add_string "address" "string"
json_add_string "name" "string"
json_close_object
add_method_str "p2p_remove_peer" "peer_id"
add_method_str "p2p_get_peer_catalog" "peer_id"
add_method_bool "p2p_share_catalog" "enabled"
add_method "p2p_get_settings"
json_add_object "p2p_set_settings"
json_add_object "settings"
json_close_object
json_close_object
}
# Handle method calls
handle_p2p() {
local method="$1"
mkdir -p "$P2P_DIR"
case "$method" in
p2p_get_peers)
_do_p2p_get_peers
;;
p2p_discover)
_do_p2p_discover
;;
p2p_add_peer)
read_input_json
local address=$(get_input "address")
local name=$(get_input "name")
_do_p2p_add_peer "$address" "$name"
;;
p2p_remove_peer)
read_input_json
local peer_id=$(get_input "peer_id")
_do_p2p_remove_peer "$peer_id"
;;
p2p_get_peer_catalog)
read_input_json
local peer_id=$(get_input "peer_id")
_do_p2p_get_peer_catalog "$peer_id"
;;
p2p_share_catalog)
read_input_json
local enabled=$(get_input_bool "enabled")
echo "{\"sharing_enabled\":$enabled}" > "$P2P_CONFIG"
json_init
json_add_boolean "success" 1
json_add_boolean "sharing_enabled" "$enabled"
json_dump
;;
p2p_get_settings)
json_init
if [ -f "$P2P_CONFIG" ]; then
local sharing=$(jsonfilter -i "$P2P_CONFIG" -e '@.sharing_enabled' 2>/dev/null)
json_add_boolean "sharing_enabled" "${sharing:-0}"
else
json_add_boolean "sharing_enabled" 0
fi
json_add_string "hub_version" "1.0.0"
json_add_string "protocol" "http"
json_add_int "port" 8080
json_dump
;;
p2p_set_settings)
read_input_json
local sharing=$(echo "$INPUT_JSON" | jsonfilter -e '@.settings.sharing_enabled' 2>/dev/null)
echo "{\"sharing_enabled\":${sharing:-false}}" > "$P2P_CONFIG"
json_success "Settings updated"
;;
*)
return 1
;;
esac
}
# Get peers list
_do_p2p_get_peers() {
json_init
json_add_array "peers"
if [ -f "$P2P_PEERS_FILE" ]; then
local idx=0
while true; do
local peer_id=$(jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx].id" 2>/dev/null)
[ -z "$peer_id" ] && break
local peer_name=$(jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx].name" 2>/dev/null)
local peer_addr=$(jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx].address" 2>/dev/null)
local peer_status=$(jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx].status" 2>/dev/null)
local last_seen=$(jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx].last_seen" 2>/dev/null)
json_add_object ""
json_add_string "id" "$peer_id"
json_add_string "name" "${peer_name:-$peer_id}"
json_add_string "address" "$peer_addr"
json_add_string "status" "${peer_status:-unknown}"
json_add_string "last_seen" "$last_seen"
json_close_object
idx=$((idx + 1))
done
fi
json_close_array
json_dump
}
# mDNS discovery
_do_p2p_discover() {
local discovered=0
json_init
json_add_array "peers"
if command -v avahi-browse >/dev/null 2>&1; then
avahi-browse -t -r _secubox._tcp 2>/dev/null | grep -E "^\+" | while read -r line; do
local addr=$(echo "$line" | awk '{print $7}')
local name=$(echo "$line" | awk '{print $4}')
if [ -n "$addr" ]; then
json_add_object ""
json_add_string "address" "$addr"
json_add_string "name" "$name"
json_add_string "discovered" "mdns"
json_close_object
discovered=$((discovered + 1))
fi
done
fi
json_close_array
json_add_int "discovered" "$discovered"
json_dump
}
# Add peer
_do_p2p_add_peer() {
local address="$1"
local name="$2"
local peer_id="peer_$(echo "$address" | md5sum | cut -c1-8)"
[ ! -f "$P2P_PEERS_FILE" ] && echo '{"peers":[]}' > "$P2P_PEERS_FILE"
local timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
local tmp_file="${P2P_PEERS_FILE}.tmp"
{
echo '{"peers":['
if [ -f "$P2P_PEERS_FILE" ]; then
jsonfilter -i "$P2P_PEERS_FILE" -e '@.peers[*]' 2>/dev/null | while read -r p; do
echo "$p,"
done
fi
echo "{\"id\":\"$peer_id\",\"name\":\"$name\",\"address\":\"$address\",\"status\":\"added\",\"last_seen\":\"$timestamp\"}"
echo ']}'
} > "$tmp_file"
mv "$tmp_file" "$P2P_PEERS_FILE"
json_init
json_add_boolean "success" 1
json_add_string "peer_id" "$peer_id"
json_dump
}
# Remove peer
_do_p2p_remove_peer() {
local peer_id="$1"
if [ -f "$P2P_PEERS_FILE" ] && [ -n "$peer_id" ]; then
local tmp_file="${P2P_PEERS_FILE}.tmp"
{
echo '{"peers":['
local first=1
local idx=0
while true; do
local id=$(jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx].id" 2>/dev/null)
[ -z "$id" ] && break
if [ "$id" != "$peer_id" ]; then
[ "$first" -eq 0 ] && echo ","
jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx]" 2>/dev/null
first=0
fi
idx=$((idx + 1))
done
echo ']}'
} > "$tmp_file"
mv "$tmp_file" "$P2P_PEERS_FILE"
fi
json_success "Peer removed"
}
# Get peer catalog
_do_p2p_get_peer_catalog() {
local peer_id="$1"
local idx=0
local peer_addr=""
while true; do
local id=$(jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx].id" 2>/dev/null)
[ -z "$id" ] && break
if [ "$id" = "$peer_id" ]; then
peer_addr=$(jsonfilter -i "$P2P_PEERS_FILE" -e "@.peers[$idx].address" 2>/dev/null)
break
fi
idx=$((idx + 1))
done
json_init
if [ -n "$peer_addr" ]; then
local catalog=$(wget -q -O - "http://${peer_addr}:8080/api/catalog" 2>/dev/null)
if [ -n "$catalog" ]; then
echo "$catalog"
return
fi
fi
json_add_array "apps"
json_close_array
json_add_string "error" "Could not fetch catalog from peer"
json_dump
}

View File

@ -0,0 +1,104 @@
#!/bin/sh
#
# SecuBox RPCD - Profile Management
# List, get, apply, validate, export, import profiles
#
# Register methods
list_methods_profiles() {
add_method "listProfiles"
add_method_str "getProfile" "profile"
json_add_object "applyProfile"
json_add_string "profile" "string"
json_add_boolean "dryrun" "boolean"
json_close_object
add_method "rollbackProfile"
add_method_str "validateProfile" "profile"
json_add_object "export_profile"
json_add_string "name" "string"
json_add_boolean "include_feeds" "boolean"
json_close_object
json_add_object "import_profile"
json_add_string "url" "string"
json_add_string "mode" "string"
json_close_object
add_method_str "share_profile" "profile"
}
# Handle method calls
handle_profiles() {
local method="$1"
case "$method" in
listProfiles)
/usr/sbin/secubox-profile list --json
;;
getProfile)
read_input_json
local profile=$(get_input "profile")
/usr/sbin/secubox-profile show "$profile"
;;
applyProfile)
read_input_json
local profile=$(get_input "profile")
local dryrun=$(get_input "dryrun")
local result=$(/usr/sbin/secubox-profile apply "$profile" ${dryrun:+--dryrun} 2>&1)
if [ $? -eq 0 ]; then
echo '{"success":true,"message":"Profile applied successfully"}'
else
echo "{\"success\":false,\"message\":\"Failed to apply profile\",\"error\":\"$result\"}"
fi
;;
rollbackProfile)
if [ -f /usr/sbin/secubox-recovery ]; then
local result=$(/usr/sbin/secubox-recovery restore last 2>&1)
if [ $? -eq 0 ]; then
echo '{"success":true,"message":"Rolled back to last snapshot"}'
else
echo "{\"success\":false,\"message\":\"Rollback failed\",\"error\":\"$result\"}"
fi
else
echo '{"success":false,"message":"Recovery system not available"}'
fi
;;
validateProfile)
read_input_json
local profile=$(get_input "profile")
/usr/sbin/secubox-profile validate "$profile"
;;
export_profile)
read_input_json
local name=$(get_input "name")
local include_feeds=$(get_input "include_feeds")
local args=""
[ -n "$name" ] && args="$args --name \"$name\""
[ "$include_feeds" = "true" ] && args="$args --include-feeds"
local output="/tmp/secubox-profile-export-$$.json"
eval /usr/sbin/secubox-profile export $args --output "$output" >/dev/null 2>&1
if [ -f "$output" ]; then
cat "$output"
rm -f "$output"
else
json_error "Export failed"
fi
;;
import_profile)
read_input_json
local url=$(get_input "url")
local mode=$(get_input "mode")
local result=$(/usr/sbin/secubox-profile import "$url" "${mode:---merge}" 2>&1)
if [ $? -eq 0 ]; then
json_success "Profile imported"
else
json_error "$result"
fi
;;
share_profile)
read_input_json
local profile=$(get_input "profile")
/usr/sbin/secubox-profile share "$profile"
;;
*)
return 1
;;
esac
}

View File

@ -0,0 +1,102 @@
#!/bin/sh
#
# SecuBox RPCD - Skill Management
# List skills, get providers, install, check
#
# Register methods
list_methods_skills() {
add_method "list_skills"
add_method_str "get_skill_providers" "skill"
add_method_str "install_skill" "skill"
add_method_str "check_skills" "profile"
}
# Handle method calls
handle_skills() {
local method="$1"
case "$method" in
list_skills)
/usr/sbin/secubox-skill list --json
;;
get_skill_providers)
read_input_json
local skill=$(get_input "skill")
_do_get_skill_providers "$skill"
;;
install_skill)
read_input_json
local skill=$(get_input "skill")
local result=$(/usr/sbin/secubox-skill install "$skill" 2>&1)
if [ $? -eq 0 ]; then
json_init
json_add_boolean "success" 1
json_add_string "message" "Skill provider installed"
json_add_string "skill" "$skill"
json_dump
else
json_error "$result"
fi
;;
check_skills)
read_input_json
local profile=$(get_input "profile")
if [ -n "$profile" ]; then
/usr/sbin/secubox-skill check "$profile"
else
/usr/sbin/secubox-skill check
fi
;;
*)
return 1
;;
esac
}
# Get skill providers from catalog
_do_get_skill_providers() {
local skill="$1"
local CATALOG_FILE="/usr/share/secubox/catalog.json"
json_init
json_add_string "skill" "$skill"
json_add_array "providers"
if [ -f "$CATALOG_FILE" ]; then
local idx=0
while true; do
local pid=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[$idx].id" 2>/dev/null)
[ -z "$pid" ] && break
local caps=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[$idx].capabilities[@]" 2>/dev/null)
for cap in $caps; do
local cap_norm=$(echo "$cap" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
if [ "$cap_norm" = "$skill" ]; then
local pname=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[$idx].name" 2>/dev/null)
local pstatus=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[$idx].status" 2>/dev/null)
local featured=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[$idx].featured" 2>/dev/null)
json_add_object ""
json_add_string "id" "$pid"
json_add_string "name" "$pname"
json_add_string "status" "$pstatus"
json_add_boolean "featured" "$([ "$featured" = "true" ] && echo 1 || echo 0)"
local main_pkg=$(jsonfilter -i "$CATALOG_FILE" -e "@.plugins[$idx].packages.required[0]" 2>/dev/null)
local installed=0
if [ -n "$main_pkg" ] && opkg list-installed 2>/dev/null | grep -q "^$main_pkg "; then
installed=1
fi
json_add_boolean "installed" "$installed"
json_close_object
break
fi
done
idx=$((idx + 1))
done
fi
json_close_array
json_dump
}

View File

@ -0,0 +1,35 @@
#!/bin/sh
#
# SecuBox RPCD - Snapshot/Recovery Management
# Create, list, restore snapshots
#
# Register methods
list_methods_snapshots() {
add_method_str "createSnapshot" "name"
add_method "listSnapshots"
add_method_str "restoreSnapshot" "snapshot"
}
# Handle method calls
handle_snapshots() {
local method="$1"
case "$method" in
createSnapshot)
read_input_json
local name=$(get_input "name")
/usr/sbin/secubox-recovery snapshot "${name:-auto-$(date +%Y%m%d-%H%M%S)}"
;;
listSnapshots)
/usr/sbin/secubox-recovery list --json
;;
restoreSnapshot)
read_input_json
local snapshot=$(get_input "snapshot")
/usr/sbin/secubox-recovery rollback "$snapshot"
;;
*)
return 1
;;
esac
}

View File

@ -0,0 +1,156 @@
#!/bin/sh
#
# SecuBox RPCD - State & Component Management
# Component state, history, registry
#
# Register methods
list_methods_state() {
add_method_str "get_component_state" "component_id"
json_add_object "set_component_state"
json_add_string "component_id" "string"
json_add_string "new_state" "string"
json_add_string "reason" "string"
json_close_object
json_add_object "get_state_history"
json_add_string "component_id" "string"
json_add_int "limit" "integer"
json_close_object
json_add_object "list_components"
json_add_string "state_filter" "string"
json_add_string "type_filter" "string"
json_close_object
json_add_object "freeze_component"
json_add_string "component_id" "string"
json_add_string "reason" "string"
json_close_object
add_method_str "clear_error_state" "component_id"
add_method_str "get_component" "component_id"
json_add_object "list_all_components"
json_add_string "type" "string"
json_add_string "profile" "string"
json_close_object
add_method_str "get_component_tree" "component_id"
json_add_object "update_component_settings"
json_add_string "component_id" "string"
json_add_object "settings"
json_close_object
json_close_object
add_method "sync_component_registry"
}
# Handle method calls
handle_state() {
local method="$1"
case "$method" in
get_component_state)
read_input_json
local component_id=$(get_input "component_id")
/usr/sbin/secubox-state get "$component_id"
;;
set_component_state)
read_input_json
local component_id=$(get_input "component_id")
local new_state=$(get_input "new_state")
local reason=$(get_input "reason")
local result=$(/usr/sbin/secubox-state set "$component_id" "$new_state" "${reason:-manual}")
json_init
if echo "$result" | grep -q "Success:"; then
json_add_boolean "success" 1
json_add_string "message" "$result"
json_add_string "component_id" "$component_id"
json_add_string "new_state" "$new_state"
else
json_add_boolean "success" 0
json_add_string "error" "$result"
fi
json_dump
;;
get_state_history)
read_input_json
local component_id=$(get_input "component_id")
local limit=$(get_input_int "limit" 20)
/usr/sbin/secubox-state history "$component_id" "$limit"
;;
list_components)
read_input_json
local state_filter=$(get_input "state_filter")
local type_filter=$(get_input "type_filter")
local args=""
[ -n "$state_filter" ] && args="$args --state=$state_filter"
[ -n "$type_filter" ] && args="$args --type=$type_filter"
/usr/sbin/secubox-state list $args
;;
freeze_component)
read_input_json
local component_id=$(get_input "component_id")
local reason=$(get_input "reason")
local result=$(/usr/sbin/secubox-state freeze "$component_id" "${reason:-manual_freeze}")
json_init
if echo "$result" | grep -q "Success:"; 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
;;
clear_error_state)
read_input_json
local component_id=$(get_input "component_id")
local result=$(/usr/sbin/secubox-state clear-error "$component_id")
json_init
if echo "$result" | grep -q "Success:"; 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
;;
get_component)
read_input_json
local component_id=$(get_input "component_id")
/usr/sbin/secubox-component get "$component_id"
;;
list_all_components)
read_input_json
local type=$(get_input "type")
local profile=$(get_input "profile")
local args=""
[ -n "$type" ] && args="$args --type=$type"
[ -n "$profile" ] && args="$args --profile=$profile"
/usr/sbin/secubox-component list $args
;;
get_component_tree)
read_input_json
local component_id=$(get_input "component_id")
/usr/sbin/secubox-component tree "$component_id"
;;
update_component_settings)
read_input_json
local component_id=$(get_input "component_id")
json_init
json_add_boolean "success" 1
json_add_string "message" "Settings update functionality available via CLI: secubox-component set-setting"
json_dump
;;
sync_component_registry)
local result=$(/usr/sbin/secubox-sync-registry sync)
json_init
if echo "$result" | grep -q "successfully"; 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
;;
*)
return 1
;;
esac
}

File diff suppressed because it is too large Load Diff