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:
parent
872038341a
commit
e28f7b952f
@ -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/
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
236
package/secubox/secubox-core/root/usr/lib/secubox/rpcd.d/p2p.sh
Normal file
236
package/secubox/secubox-core/root/usr/lib/secubox/rpcd.d/p2p.sh
Normal 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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
Loading…
Reference in New Issue
Block a user