Renamed .appstore directory to appstore (without dot prefix) to ensure proper inclusion in OpenWrt package builds. Hidden directories (starting with .) can be problematic during tarball creation and package installation. Changes: - Renamed .appstore/ to appstore/ - Updated Makefile install path references - Updated RPCD script APPSTORE_JSON path - Fixed file permissions to 644 for apps.json This fixes the issue where appstore appears empty on fresh firmware installations. New path: /usr/share/secubox/appstore/apps.json Old path: /usr/share/secubox/.appstore/apps.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2081 lines
58 KiB
Bash
Executable File
2081 lines
58 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
# SecuBox Master RPCD Backend
|
|
# Module discovery and unified status
|
|
# Copyright (C) 2025 CyberMind.fr
|
|
|
|
. /lib/functions.sh
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
get_pkg_version() {
|
|
local version=""
|
|
|
|
# OpenWrt 25.12+ uses apk packages
|
|
if command -v apk >/dev/null 2>&1; then
|
|
local apk_line=$(apk info -v luci-app-secubox 2>/dev/null | grep -E '^luci-app-secubox-[0-9]' | head -n1)
|
|
if [ -n "$apk_line" ]; then
|
|
version=$(echo "$apk_line" | sed 's/^luci-app-secubox-//' | awk '{print $1}' | sed 's/-r[0-9]*$//')
|
|
else
|
|
version=$(apk info luci-app-secubox 2>/dev/null | awk -F': ' '/^Version/ {print $2; exit}')
|
|
fi
|
|
if [ -n "$version" ]; then
|
|
echo "$version"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
# Legacy opkg metadata
|
|
local ctrl="/usr/lib/opkg/info/luci-app-secubox.control"
|
|
if [ -f "$ctrl" ]; then
|
|
version=$(awk -F': ' '/^Version/ { print $2; exit }' "$ctrl")
|
|
if [ -n "$version" ]; then
|
|
echo "$version"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
version=$(opkg list-installed luci-app-secubox 2>/dev/null | awk '{print $3}' | sed 's/-r[0-9]*$//' | head -n1)
|
|
if [ -n "$version" ]; then
|
|
echo "$version"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
local cfg_version="$(uci -q get secubox.main.version)"
|
|
if [ -n "$cfg_version" ]; then
|
|
echo "$cfg_version"
|
|
elif [ -f "/usr/share/secubox/VERSION" ]; then
|
|
head -n1 /usr/share/secubox/VERSION
|
|
else
|
|
echo "unknown"
|
|
fi
|
|
}
|
|
|
|
PKG_VERSION="$(get_pkg_version)"
|
|
|
|
PLUGIN_DIR="/usr/share/secubox/plugins"
|
|
PROFILE_DIR="/usr/share/secubox/profiles"
|
|
PROFILE_BACKUP_DIR="/etc/secubox-profiles/backups"
|
|
DEFAULT_STORAGE_PATH="/srv/secubox"
|
|
SECOBOX_APP="/usr/sbin/secubox-app"
|
|
OPKG_UPDATED=0
|
|
|
|
manifest_files() {
|
|
if [ -d "$PLUGIN_DIR/catalog" ]; then
|
|
for file in "$PLUGIN_DIR"/catalog/*.json; do
|
|
[ -f "$file" ] || continue
|
|
echo "$file"
|
|
done
|
|
fi
|
|
for file in "$PLUGIN_DIR"/*/manifest.json; do
|
|
[ -f "$file" ] || continue
|
|
echo "$file"
|
|
done
|
|
}
|
|
|
|
manifest_file_for_id() {
|
|
local id="$1"
|
|
local catalog="$PLUGIN_DIR/catalog/$id.json"
|
|
local legacy="$PLUGIN_DIR/$id/manifest.json"
|
|
if [ -f "$catalog" ]; then
|
|
printf '%s' "$catalog"
|
|
return 0
|
|
fi
|
|
if [ -f "$legacy" ]; then
|
|
printf '%s' "$legacy"
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
validate_manifest_json() {
|
|
local manifest="$1"
|
|
local id name runtime packages category
|
|
id=$(jsonfilter -s "$manifest" -e '@.id' 2>/dev/null)
|
|
name=$(jsonfilter -s "$manifest" -e '@.name' 2>/dev/null)
|
|
category=$(jsonfilter -s "$manifest" -e '@.category' 2>/dev/null)
|
|
runtime=$(jsonfilter -s "$manifest" -e '@.runtime' 2>/dev/null)
|
|
[ -n "$runtime" ] || runtime=$(jsonfilter -s "$manifest" -e '@.type' 2>/dev/null)
|
|
packages=$(jsonfilter -s "$manifest" -e '@.packages[*]' 2>/dev/null)
|
|
[ -n "$id" ] && [ -n "$name" ] && [ -n "$runtime" ] && [ -n "$category" ] && [ -n "$packages" ]
|
|
}
|
|
|
|
# Module registry - auto-detected from /usr/libexec/rpcd/
|
|
detect_modules() {
|
|
local modules=""
|
|
local scripts="luci.crowdsec-dashboard luci.netdata-dashboard luci.netifyd-dashboard luci.wireguard-dashboard luci.network-modes luci.client-guardian luci.system-hub luci.bandwidth-manager luci.auth-guardian luci.media-flow luci.vhost-manager luci.cdn-cache luci.traffic-shaper luci.ksm-manager"
|
|
|
|
for script in $scripts; do
|
|
if [ -x "/usr/libexec/rpcd/$script" ]; then
|
|
# Remove luci. prefix, remove -dashboard suffix, convert dashes to underscores
|
|
local module_id=$(echo "$script" | sed 's/^luci\.//' | sed 's/-dashboard$//' | sed 's/-/_/g')
|
|
modules="$modules $module_id"
|
|
fi
|
|
done
|
|
|
|
echo "$modules"
|
|
}
|
|
|
|
MODULES=$(detect_modules)
|
|
|
|
is_root_password_set() {
|
|
local hash
|
|
hash=$(grep '^root:' /etc/shadow 2>/dev/null | cut -d: -f2)
|
|
[ -n "$hash" ] && [ "$hash" != "!" ] && [ "$hash" != "*" ]
|
|
}
|
|
|
|
get_storage_path() {
|
|
local path
|
|
path=$(uci -q get secubox.main.storage_path)
|
|
if [ -z "$path" ]; then
|
|
path="$DEFAULT_STORAGE_PATH"
|
|
fi
|
|
echo "$path"
|
|
}
|
|
|
|
package_installed() {
|
|
local pkg="$1"
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
opkg status "$pkg" >/dev/null 2>&1 && return 0
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
apk info -e "$pkg" >/dev/null 2>&1 && return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
packages_state() {
|
|
local manifest="$1"
|
|
local total=0 installed=0 missing=0 pkg
|
|
for pkg in $(jsonfilter -s "$manifest" -e '@.packages[*]' 2>/dev/null); do
|
|
total=$((total + 1))
|
|
if package_installed "$pkg"; then
|
|
installed=$((installed + 1))
|
|
else
|
|
missing=$((missing + 1))
|
|
fi
|
|
done
|
|
if [ "$total" -eq 0 ]; then
|
|
echo "n/a"
|
|
elif [ "$missing" -eq 0 ]; then
|
|
echo "installed"
|
|
elif [ "$installed" -eq 0 ]; then
|
|
echo "missing"
|
|
else
|
|
echo "partial"
|
|
fi
|
|
}
|
|
|
|
ensure_directory() {
|
|
local dir="$1"
|
|
[ -d "$dir" ] || mkdir -p "$dir"
|
|
}
|
|
|
|
apply_network_mode() {
|
|
local mode="$1"
|
|
[ -n "$mode" ] || return
|
|
if command -v ubus >/dev/null 2>&1; then
|
|
if ubus call luci.network-modes set_mode "{\"mode\":\"$mode\"}" >/dev/null 2>&1; then
|
|
ubus call luci.network-modes apply_mode >/dev/null 2>&1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
ensure_opkg_updated() {
|
|
[ "$OPKG_UPDATED" -eq 1 ] && return
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
opkg update >/dev/null 2>&1 && OPKG_UPDATED=1
|
|
fi
|
|
}
|
|
|
|
install_package_if_missing() {
|
|
local pkg="$1"
|
|
package_installed "$pkg" && return
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
ensure_opkg_updated
|
|
opkg install "$pkg" >/dev/null 2>&1
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
apk add "$pkg" >/dev/null 2>&1
|
|
fi
|
|
}
|
|
|
|
# Check if a module is installed (supports both opkg and apk)
|
|
check_module_installed() {
|
|
local module="$1"
|
|
local package config
|
|
|
|
config_get package "$module" package ""
|
|
config_get config "$module" config ""
|
|
|
|
# Check if package is installed via apk (OpenWrt 25.12+) or opkg (24.10 and earlier)
|
|
if [ -x "/usr/bin/apk" ]; then
|
|
# OpenWrt 25.12+ uses apk
|
|
if apk list --installed 2>/dev/null | grep -q "^${package}-"; then
|
|
echo "1"
|
|
return
|
|
fi
|
|
elif [ -x "/bin/opkg" ] || [ -x "/usr/bin/opkg" ]; then
|
|
# OpenWrt 24.10 and earlier uses opkg
|
|
if opkg list-installed 2>/dev/null | grep -q "^${package} "; then
|
|
echo "1"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
# Fallback: check if config file exists
|
|
if [ -f "/etc/config/${config}" ]; then
|
|
echo "1"
|
|
else
|
|
echo "0"
|
|
fi
|
|
}
|
|
|
|
# Check if a module is enabled (UCI config)
|
|
check_module_enabled() {
|
|
local module="$1"
|
|
local enabled
|
|
|
|
config_load secubox
|
|
config_get enabled "$module" enabled "1"
|
|
|
|
echo "$enabled"
|
|
}
|
|
|
|
# Check if a module service is running
|
|
check_module_running() {
|
|
local module="$1"
|
|
local config
|
|
|
|
config_load secubox
|
|
config_get config "$module" config ""
|
|
|
|
case "$module" in
|
|
crowdsec)
|
|
pgrep -f crowdsec > /dev/null 2>&1 && echo "1" || echo "0"
|
|
;;
|
|
netdata)
|
|
pgrep -f netdata > /dev/null 2>&1 && echo "1" || echo "0"
|
|
;;
|
|
netifyd)
|
|
pgrep -f netifyd > /dev/null 2>&1 && echo "1" || echo "0"
|
|
;;
|
|
wireguard)
|
|
[ -n "$(wg show 2>/dev/null)" ] && echo "1" || echo "0"
|
|
;;
|
|
cdn_cache)
|
|
pgrep -f "nginx.*cdn-cache" > /dev/null 2>&1 && echo "1" || echo "0"
|
|
;;
|
|
*)
|
|
# Generic check via init.d
|
|
if [ -x "/etc/init.d/${config}" ]; then
|
|
/etc/init.d/${config} running > /dev/null 2>&1 && echo "1" || echo "0"
|
|
else
|
|
echo "0"
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Determine module status based on enabled + running
|
|
get_module_status() {
|
|
local enabled="$1"
|
|
local running="$2"
|
|
|
|
if [ "$enabled" = "1" ] && [ "$running" = "1" ]; then
|
|
echo "active"
|
|
elif [ "$enabled" = "1" ] && [ "$running" = "0" ]; then
|
|
echo "error"
|
|
elif [ "$enabled" = "0" ] && [ "$running" = "0" ]; then
|
|
echo "disabled"
|
|
else
|
|
echo "unknown"
|
|
fi
|
|
}
|
|
|
|
# Get overall system status
|
|
get_status() {
|
|
local total=0
|
|
local installed=0
|
|
local running=0
|
|
|
|
json_init
|
|
json_add_string "version" "$PKG_VERSION"
|
|
json_add_string "hostname" "$(uci -q get system.@system[0].hostname || echo 'SecuBox')"
|
|
json_add_boolean "enabled" "$(uci -q get secubox.main.enabled || echo 1)"
|
|
|
|
# System info
|
|
local uptime=$(cat /proc/uptime | cut -d. -f1)
|
|
local load=$(cat /proc/loadavg | cut -d' ' -f1-3)
|
|
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
|
local mem_free=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
|
|
local mem_used=$((mem_total - mem_free))
|
|
local mem_pct=$((mem_used * 100 / mem_total))
|
|
|
|
json_add_int "uptime" "$uptime"
|
|
json_add_string "load" "$load"
|
|
json_add_int "memory_total" "$mem_total"
|
|
json_add_int "memory_used" "$mem_used"
|
|
json_add_int "memory_percent" "$mem_pct"
|
|
|
|
# Count modules from UCI config (same as get_modules)
|
|
config_load secubox 2>/dev/null || true
|
|
local module_sections=$(uci -q show secubox | grep "=module$" | cut -d. -f2 | cut -d= -f1)
|
|
|
|
for module in $module_sections; do
|
|
total=$((total + 1))
|
|
local is_installed=$(check_module_installed "$module")
|
|
local is_running=$(check_module_running "$module")
|
|
|
|
if [ "$is_installed" = "1" ]; then
|
|
installed=$((installed + 1))
|
|
fi
|
|
if [ "$is_running" = "1" ]; then
|
|
running=$((running + 1))
|
|
fi
|
|
done
|
|
|
|
json_add_int "modules_total" "$total"
|
|
json_add_int "modules_installed" "$installed"
|
|
json_add_int "modules_running" "$running"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Detect real installed luci-app packages (supports both opkg and apk)
|
|
detect_real_modules() {
|
|
if [ -x "/usr/bin/apk" ]; then
|
|
# OpenWrt 25.12+ uses apk
|
|
apk list --installed 2>/dev/null | grep "^luci-app-" | grep -v "^luci-app-secubox-" | while IFS=- read -r pkg rest; do
|
|
# Parse apk output: luci-app-network-modes-0.3.1-r1 noarch {...} (license) [installed]
|
|
local package=$(echo "$pkg-$rest" | awk '{print $1}')
|
|
local version=$(echo "$package" | sed 's/^luci-app-[^-]*-//' | sed 's/-r[0-9]*$//')
|
|
local pkg_name=$(echo "$package" | sed 's/-[0-9].*//')
|
|
local module_id=$(echo "$pkg_name" | sed 's/^luci-app-//' | sed 's/-dashboard$//' | sed 's/-/_/g')
|
|
echo "$module_id:$pkg_name:$version"
|
|
done
|
|
elif [ -x "/bin/opkg" ] || [ -x "/usr/bin/opkg" ]; then
|
|
# OpenWrt 24.10 and earlier uses opkg
|
|
opkg list-installed 2>/dev/null | grep "^luci-app-" | grep -v "^luci-app-secubox " | while read package version; do
|
|
# Extract module ID from package name
|
|
local module_id=$(echo "$package" | sed 's/^luci-app-//' | sed 's/-dashboard$//' | sed 's/-/_/g')
|
|
echo "$module_id:$package:$version"
|
|
done
|
|
fi
|
|
}
|
|
|
|
# Get detailed modules list (UCI + auto-detected)
|
|
get_modules() {
|
|
json_init
|
|
json_add_array "modules"
|
|
|
|
config_load secubox 2>/dev/null || true
|
|
|
|
# Create associative array to track processed modules
|
|
local processed_modules=""
|
|
|
|
# First, add modules from UCI config
|
|
local module_sections=$(uci -q show secubox | grep "=module$" | cut -d. -f2 | cut -d= -f1)
|
|
|
|
for module in $module_sections; do
|
|
local name desc category icon color package config version
|
|
|
|
config_get name "$module" name "$module"
|
|
config_get desc "$module" description ""
|
|
config_get category "$module" category "other"
|
|
config_get icon "$module" icon "📦"
|
|
config_get color "$module" color "#64748b"
|
|
config_get package "$module" package ""
|
|
config_get config "$module" config ""
|
|
config_get version "$module" version "0.0.9"
|
|
|
|
local is_installed=$(check_module_installed "$module")
|
|
local is_enabled=$(check_module_enabled "$module")
|
|
local is_running=$(check_module_running "$module")
|
|
local status=$(get_module_status "$is_enabled" "$is_running")
|
|
|
|
# Get real version from package manager if installed
|
|
if [ "$is_installed" = "1" ] && [ -n "$package" ]; then
|
|
if [ -x "/usr/bin/apk" ]; then
|
|
# OpenWrt 25.12+ uses apk
|
|
# apk output: luci-app-network-modes-0.3.1-r1 noarch {...}
|
|
local real_version=$(apk list --installed "$package" 2>/dev/null | head -1 | awk '{print $1}' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
|
|
[ -n "$real_version" ] && version="$real_version"
|
|
elif [ -x "/bin/opkg" ] || [ -x "/usr/bin/opkg" ]; then
|
|
# OpenWrt 24.10 and earlier uses opkg
|
|
local real_version=$(opkg list-installed "$package" 2>/dev/null | awk '{print $3}' | sed 's/-.*$//')
|
|
[ -n "$real_version" ] && version="$real_version"
|
|
fi
|
|
fi
|
|
|
|
json_add_object ""
|
|
json_add_string "id" "$module"
|
|
json_add_string "name" "$name"
|
|
json_add_string "description" "$desc"
|
|
json_add_string "category" "$category"
|
|
json_add_string "icon" "$icon"
|
|
json_add_string "color" "$color"
|
|
json_add_string "package" "$package"
|
|
json_add_string "config" "$config"
|
|
json_add_string "version" "$version"
|
|
json_add_boolean "installed" "$is_installed"
|
|
json_add_boolean "enabled" "$is_enabled"
|
|
json_add_boolean "running" "$is_running"
|
|
json_add_string "status" "$status"
|
|
json_add_boolean "in_uci" "1"
|
|
json_close_object
|
|
|
|
processed_modules="$processed_modules $module"
|
|
done
|
|
|
|
# Second, add auto-detected modules not in UCI
|
|
detect_real_modules | while IFS=: read module_id package version; do
|
|
# Skip if already processed
|
|
echo "$processed_modules" | grep -q " $module_id " && continue
|
|
|
|
# Auto-detect properties based on package name
|
|
local name=$(echo "$package" | sed 's/^luci-app-//' | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++){$i=toupper(substr($i,1,1)) substr($i,2)}}1')
|
|
local category="other"
|
|
local icon="📦"
|
|
local color="#64748b"
|
|
|
|
# Auto-categorize
|
|
case "$package" in
|
|
*crowdsec*|*guardian*|*auth*)
|
|
category="security"; icon="🛡️"; color="#22c55e"
|
|
;;
|
|
*netdata*|*monitoring*)
|
|
category="monitoring"; icon="📊"; color="#00ab44"
|
|
;;
|
|
*network*|*wireguard*|*bandwidth*|*traffic*)
|
|
category="network"; icon="🌐"; color="#3b82f6"
|
|
;;
|
|
*system*|*hub*)
|
|
category="system"; icon="⚙️"; color="#6366f1"
|
|
;;
|
|
esac
|
|
|
|
local clean_module=$(echo "$module_id" | sed 's/_/-/g')
|
|
local is_enabled=$(check_module_enabled "$module_id")
|
|
local is_running=$(check_module_running "$module_id")
|
|
local status=$(get_module_status "$is_enabled" "$is_running")
|
|
|
|
json_add_object ""
|
|
json_add_string "id" "$module_id"
|
|
json_add_string "name" "$name"
|
|
json_add_string "description" "Auto-detected module"
|
|
json_add_string "category" "$category"
|
|
json_add_string "icon" "$icon"
|
|
json_add_string "color" "$color"
|
|
json_add_string "package" "$package"
|
|
json_add_string "config" "$clean_module"
|
|
json_add_string "version" "$version"
|
|
json_add_boolean "installed" "1"
|
|
json_add_boolean "enabled" "$is_enabled"
|
|
json_add_boolean "running" "$is_running"
|
|
json_add_string "status" "$status"
|
|
json_add_boolean "in_uci" "0"
|
|
json_close_object
|
|
done
|
|
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
# Get modules by category
|
|
get_modules_by_category() {
|
|
local category="$1"
|
|
|
|
json_init
|
|
json_add_array "modules"
|
|
|
|
config_load secubox 2>/dev/null || true
|
|
local processed_modules=""
|
|
|
|
# List all module sections from UCI config
|
|
local module_sections=$(uci -q show secubox | grep "=module$" | cut -d. -f2 | cut -d= -f1)
|
|
|
|
# First pass: UCI-defined modules in this category
|
|
for module in $module_sections; do
|
|
local mod_category
|
|
config_get mod_category "$module" category "other"
|
|
|
|
if [ "$mod_category" = "$category" ]; then
|
|
local name desc icon color package config version
|
|
|
|
config_get name "$module" name "$module"
|
|
config_get desc "$module" description ""
|
|
config_get icon "$module" icon "box"
|
|
config_get color "$module" color "#64748b"
|
|
config_get package "$module" package ""
|
|
config_get config "$module" config ""
|
|
config_get version "$module" version "0.0.9"
|
|
|
|
local is_installed=$(check_module_installed "$module")
|
|
local is_enabled=$(check_module_enabled "$module")
|
|
local is_running=$(check_module_running "$module")
|
|
local status=$(get_module_status "$is_enabled" "$is_running")
|
|
|
|
# Get real version from opkg if installed
|
|
if [ "$is_installed" = "1" ] && [ -n "$package" ]; then
|
|
local real_version=$(opkg list-installed "$package" 2>/dev/null | awk '{print $3}' | sed 's/-.*$//')
|
|
[ -n "$real_version" ] && version="$real_version"
|
|
fi
|
|
|
|
json_add_object ""
|
|
json_add_string "id" "$module"
|
|
json_add_string "name" "$name"
|
|
json_add_string "description" "$desc"
|
|
json_add_string "icon" "$icon"
|
|
json_add_string "color" "$color"
|
|
json_add_string "version" "$version"
|
|
json_add_string "package" "$package"
|
|
json_add_boolean "installed" "$is_installed"
|
|
json_add_boolean "enabled" "$is_enabled"
|
|
json_add_boolean "running" "$is_running"
|
|
json_add_string "status" "$status"
|
|
json_add_boolean "in_uci" "1"
|
|
json_close_object
|
|
|
|
processed_modules="$processed_modules $module"
|
|
fi
|
|
done
|
|
|
|
# Second pass: Auto-detected modules not in UCI
|
|
detect_real_modules | while IFS=: read module_id package version; do
|
|
# Skip if already processed from UCI
|
|
echo "$processed_modules" | grep -q " $module_id " && continue
|
|
|
|
# Auto-categorize
|
|
local mod_category icon color name
|
|
case "$package" in
|
|
*crowdsec*|*guardian*|*auth*)
|
|
mod_category="security"; icon="🛡️"; color="#22c55e"
|
|
;;
|
|
*netdata*|*monitoring*)
|
|
mod_category="monitoring"; icon="📊"; color="#00ab44"
|
|
;;
|
|
*network*|*wireguard*|*bandwidth*|*traffic*|*cdn*)
|
|
mod_category="network"; icon="🌐"; color="#3b82f6"
|
|
;;
|
|
*system*|*hub*|*vhost*)
|
|
mod_category="system"; icon="⚙️"; color="#6366f1"
|
|
;;
|
|
*)
|
|
mod_category="other"; icon="📦"; color="#64748b"
|
|
;;
|
|
esac
|
|
|
|
# Only include if matches requested category
|
|
if [ "$mod_category" = "$category" ]; then
|
|
# Generate nice name from package
|
|
name=$(echo "$package" | sed 's/^luci-app-//' | sed 's/-dashboard$//' | sed 's/-/ /g' | sed 's/\b\(.\)/\u\1/g')
|
|
|
|
local is_installed="1" # Must be installed if detected
|
|
local is_enabled=$(check_module_enabled "$module_id")
|
|
local is_running=$(check_module_running "$module_id")
|
|
local status=$(get_module_status "$is_enabled" "$is_running")
|
|
|
|
json_add_object ""
|
|
json_add_string "id" "$module_id"
|
|
json_add_string "name" "$name"
|
|
json_add_string "description" "Auto-detected module"
|
|
json_add_string "icon" "$icon"
|
|
json_add_string "color" "$color"
|
|
json_add_string "version" "$version"
|
|
json_add_string "package" "$package"
|
|
json_add_string "category" "$mod_category"
|
|
json_add_boolean "installed" "$is_installed"
|
|
json_add_boolean "enabled" "$is_enabled"
|
|
json_add_boolean "running" "$is_running"
|
|
json_add_string "status" "$status"
|
|
json_add_boolean "in_uci" "0"
|
|
json_close_object
|
|
fi
|
|
done
|
|
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
# Get single module info
|
|
get_module_info() {
|
|
local module="$1"
|
|
|
|
config_load secubox
|
|
|
|
local name desc category icon color package config version
|
|
|
|
config_get name "$module" name "$module"
|
|
config_get desc "$module" description ""
|
|
config_get category "$module" category "other"
|
|
config_get icon "$module" icon "box"
|
|
config_get color "$module" color "#64748b"
|
|
config_get package "$module" package ""
|
|
config_get config "$module" config ""
|
|
config_get version "$module" version "0.0.9"
|
|
|
|
local is_installed=$(check_module_installed "$module")
|
|
local is_enabled=$(check_module_enabled "$module")
|
|
local is_running=$(check_module_running "$module")
|
|
local status=$(get_module_status "$is_enabled" "$is_running")
|
|
|
|
json_init
|
|
json_add_string "id" "$module"
|
|
json_add_string "name" "$name"
|
|
json_add_string "description" "$desc"
|
|
json_add_string "category" "$category"
|
|
json_add_string "icon" "$icon"
|
|
json_add_string "color" "$color"
|
|
json_add_string "package" "$package"
|
|
json_add_string "config" "$config"
|
|
json_add_string "version" "$version"
|
|
json_add_boolean "installed" "$is_installed"
|
|
json_add_boolean "enabled" "$is_enabled"
|
|
json_add_boolean "running" "$is_running"
|
|
json_add_string "status" "$status"
|
|
json_dump
|
|
}
|
|
|
|
# Start a module
|
|
start_module() {
|
|
local module="$1"
|
|
local config
|
|
|
|
config_load secubox
|
|
config_get config "$module" config ""
|
|
|
|
if [ -x "/etc/init.d/${config}" ]; then
|
|
/etc/init.d/${config} start
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Module started"
|
|
json_dump
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Init script not found"
|
|
json_dump
|
|
fi
|
|
}
|
|
|
|
# Stop a module
|
|
stop_module() {
|
|
local module="$1"
|
|
local config
|
|
|
|
config_load secubox
|
|
config_get config "$module" config ""
|
|
|
|
if [ -x "/etc/init.d/${config}" ]; then
|
|
/etc/init.d/${config} stop
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Module stopped"
|
|
json_dump
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Init script not found"
|
|
json_dump
|
|
fi
|
|
}
|
|
|
|
# Restart a module (DEPRECATED - use disable/enable instead)
|
|
restart_module() {
|
|
local module="$1"
|
|
local config
|
|
|
|
config_load secubox
|
|
config_get config "$module" config ""
|
|
|
|
if [ -x "/etc/init.d/${config}" ]; then
|
|
/etc/init.d/${config} restart
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Module restarted"
|
|
json_dump
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Init script not found"
|
|
json_dump
|
|
fi
|
|
}
|
|
|
|
# Enable a module (NEW v0.3.1)
|
|
enable_module() {
|
|
local module="$1"
|
|
|
|
# Set enabled flag in UCI (v0.3.1)
|
|
# This only activates the module in configuration
|
|
# Use start_module() to actually start the service
|
|
uci set secubox.${module}.enabled='1'
|
|
uci commit secubox
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Module activé dans la configuration"
|
|
json_add_string "note" "Utilisez 'Démarrer' pour lancer le service"
|
|
json_dump
|
|
}
|
|
|
|
# Disable a module (NEW v0.3.1)
|
|
disable_module() {
|
|
local module="$1"
|
|
|
|
# Set disabled flag in UCI (v0.3.1)
|
|
# This only deactivates the module in configuration
|
|
# Use stop_module() to actually stop the service
|
|
uci set secubox.${module}.enabled='0'
|
|
uci commit secubox
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Module désactivé dans la configuration"
|
|
json_add_string "note" "Utilisez 'Arrêter' pour stopper le service"
|
|
json_dump
|
|
}
|
|
|
|
# Get health report
|
|
get_health() {
|
|
json_init
|
|
json_add_array "checks"
|
|
|
|
config_load secubox 2>/dev/null || true
|
|
|
|
# List all module sections from UCI config
|
|
local module_sections=$(uci -q show secubox | grep "=module$" | cut -d. -f2 | cut -d= -f1)
|
|
|
|
# Check each installed module
|
|
for module in $module_sections; do
|
|
local is_installed=$(check_module_installed "$module")
|
|
|
|
if [ "$is_installed" = "1" ]; then
|
|
local is_running=$(check_module_running "$module")
|
|
local name
|
|
|
|
config_get name "$module" name "$module"
|
|
|
|
local status="ok"
|
|
local message="Running normally"
|
|
|
|
if [ "$is_running" != "1" ]; then
|
|
status="warning"
|
|
message="Service not running"
|
|
fi
|
|
|
|
json_add_object ""
|
|
json_add_string "module" "$module"
|
|
json_add_string "name" "$name"
|
|
json_add_string "status" "$status"
|
|
json_add_string "message" "$message"
|
|
json_close_object
|
|
fi
|
|
done
|
|
|
|
json_close_array
|
|
|
|
# Overall health
|
|
local overall="healthy"
|
|
# Could add more sophisticated health checks here
|
|
|
|
json_add_string "overall" "$overall"
|
|
json_add_int "timestamp" "$(date +%s)"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Generate diagnostics bundle
|
|
get_diagnostics() {
|
|
json_init
|
|
|
|
# System info
|
|
json_add_object "system"
|
|
json_add_string "hostname" "$(uci -q get system.@system[0].hostname)"
|
|
json_add_string "model" "$(cat /tmp/sysinfo/model 2>/dev/null || echo 'Unknown')"
|
|
json_add_string "openwrt_version" "$(cat /etc/openwrt_release | grep DISTRIB_RELEASE | cut -d= -f2 | tr -d \"\')"
|
|
json_add_string "kernel" "$(uname -r)"
|
|
json_add_int "uptime" "$(cat /proc/uptime | cut -d. -f1)"
|
|
json_close_object
|
|
|
|
# Modules status
|
|
json_add_array "modules"
|
|
config_load secubox 2>/dev/null || true
|
|
local module_sections=$(uci -q show secubox | grep "=module$" | cut -d. -f2 | cut -d= -f1)
|
|
for module in $module_sections; do
|
|
local is_installed=$(check_module_installed "$module")
|
|
local is_running=$(check_module_running "$module")
|
|
|
|
json_add_object ""
|
|
json_add_string "id" "$module"
|
|
json_add_boolean "installed" "$is_installed"
|
|
json_add_boolean "running" "$is_running"
|
|
json_close_object
|
|
done
|
|
json_close_array
|
|
|
|
# Network interfaces
|
|
json_add_array "interfaces"
|
|
for iface in $(ls /sys/class/net/); do
|
|
local mac=$(cat /sys/class/net/$iface/address 2>/dev/null)
|
|
local state=$(cat /sys/class/net/$iface/operstate 2>/dev/null)
|
|
|
|
json_add_object ""
|
|
json_add_string "name" "$iface"
|
|
json_add_string "mac" "$mac"
|
|
json_add_string "state" "$state"
|
|
json_close_object
|
|
done
|
|
json_close_array
|
|
|
|
json_add_int "generated" "$(date +%s)"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get system health metrics
|
|
get_system_health() {
|
|
json_init
|
|
|
|
# CPU usage (based on load average)
|
|
local load=$(cat /proc/loadavg | cut -d' ' -f1)
|
|
local cpu_cores=$(grep -c processor /proc/cpuinfo)
|
|
local cpu_pct=$(awk "BEGIN {printf \"%.0f\", ($load / $cpu_cores) * 100}")
|
|
|
|
# Memory
|
|
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
|
local mem_avail=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
|
|
local mem_used=$((mem_total - mem_avail))
|
|
local mem_pct=$((mem_used * 100 / mem_total))
|
|
|
|
# Disk usage (root filesystem)
|
|
local disk_info=$(df / | tail -1)
|
|
local disk_total=$(echo "$disk_info" | awk '{print $2}')
|
|
local disk_used=$(echo "$disk_info" | awk '{print $3}')
|
|
local disk_pct=$(echo "$disk_info" | awk '{print $5}' | tr -d '%')
|
|
|
|
# Network stats (sum all interfaces)
|
|
local net_rx=0
|
|
local net_tx=0
|
|
for iface in $(ls /sys/class/net/ | grep -v lo); do
|
|
if [ -f "/sys/class/net/$iface/statistics/rx_bytes" ]; then
|
|
local rx=$(cat /sys/class/net/$iface/statistics/rx_bytes 2>/dev/null || echo 0)
|
|
local tx=$(cat /sys/class/net/$iface/statistics/tx_bytes 2>/dev/null || echo 0)
|
|
net_rx=$((net_rx + rx))
|
|
net_tx=$((net_tx + tx))
|
|
fi
|
|
done
|
|
|
|
# Uptime
|
|
local uptime=$(cat /proc/uptime | cut -d. -f1)
|
|
|
|
# Load averages
|
|
local load_1min=$(cat /proc/loadavg | cut -d' ' -f1)
|
|
local load_5min=$(cat /proc/loadavg | cut -d' ' -f2)
|
|
local load_15min=$(cat /proc/loadavg | cut -d' ' -f3)
|
|
|
|
json_add_object "cpu"
|
|
json_add_int "percent" "$cpu_pct"
|
|
json_add_int "cores" "$cpu_cores"
|
|
json_add_string "load_1min" "$load_1min"
|
|
json_add_string "load_5min" "$load_5min"
|
|
json_add_string "load_15min" "$load_15min"
|
|
json_close_object
|
|
|
|
json_add_object "memory"
|
|
json_add_int "percent" "$mem_pct"
|
|
json_add_int "total_kb" "$mem_total"
|
|
json_add_int "used_kb" "$mem_used"
|
|
json_add_int "available_kb" "$mem_avail"
|
|
json_close_object
|
|
|
|
json_add_object "disk"
|
|
json_add_int "percent" "$disk_pct"
|
|
json_add_int "total_kb" "$disk_total"
|
|
json_add_int "used_kb" "$disk_used"
|
|
json_close_object
|
|
|
|
json_add_object "network"
|
|
json_add_int "rx_bytes" "$net_rx"
|
|
json_add_int "tx_bytes" "$net_tx"
|
|
json_close_object
|
|
|
|
json_add_int "uptime" "$uptime"
|
|
json_add_int "timestamp" "$(date +%s)"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get aggregated alerts from all modules
|
|
get_alerts() {
|
|
json_init
|
|
json_add_array "alerts"
|
|
|
|
local alert_count=0
|
|
|
|
# Check each installed module for alerts
|
|
config_load secubox 2>/dev/null || true
|
|
|
|
# List all module sections from UCI config
|
|
local module_sections=$(uci -q show secubox | grep "=module$" | cut -d. -f2 | cut -d= -f1)
|
|
|
|
for module in $module_sections; do
|
|
local is_installed=$(check_module_installed "$module")
|
|
|
|
if [ "$is_installed" = "1" ]; then
|
|
# Check if module service is not running
|
|
local is_running=$(check_module_running "$module")
|
|
if [ "$is_running" != "1" ]; then
|
|
local name
|
|
config_get name "$module" name "$module"
|
|
|
|
json_add_object ""
|
|
json_add_string "module" "$module"
|
|
json_add_string "message" "$name service is not running"
|
|
json_add_string "severity" "warning"
|
|
json_add_int "timestamp" "$(date +%s)"
|
|
json_close_object
|
|
|
|
alert_count=$((alert_count + 1))
|
|
fi
|
|
fi
|
|
done
|
|
|
|
json_close_array
|
|
json_add_int "count" "$alert_count"
|
|
json_add_int "timestamp" "$(date +%s)"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Execute quick actions
|
|
quick_action() {
|
|
local action="$1"
|
|
|
|
json_init
|
|
|
|
case "$action" in
|
|
restart_rpcd)
|
|
/etc/init.d/rpcd restart >/dev/null 2>&1
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "RPCD service restarted"
|
|
;;
|
|
restart_uhttpd)
|
|
/etc/init.d/uhttpd restart >/dev/null 2>&1
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "uHTTPd service restarted"
|
|
;;
|
|
clear_cache)
|
|
sync
|
|
echo 3 > /proc/sys/vm/drop_caches 2>/dev/null
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "System cache cleared"
|
|
;;
|
|
backup_config)
|
|
local backup_file="/tmp/backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
|
sysupgrade -b "$backup_file" >/dev/null 2>&1
|
|
if [ -f "$backup_file" ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Configuration backup created"
|
|
json_add_string "file" "$backup_file"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Backup failed"
|
|
fi
|
|
;;
|
|
restart_network)
|
|
/etc/init.d/network restart >/dev/null 2>&1
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Network services restarted"
|
|
;;
|
|
restart_firewall)
|
|
/etc/init.d/firewall restart >/dev/null 2>&1
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Firewall restarted"
|
|
;;
|
|
*)
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Unknown action: $action"
|
|
;;
|
|
esac
|
|
|
|
json_add_int "timestamp" "$(date +%s)"
|
|
json_dump
|
|
}
|
|
|
|
# Get all dashboard data in one call
|
|
get_dashboard_data() {
|
|
json_init
|
|
|
|
# Get status info
|
|
local uptime=$(cat /proc/uptime | cut -d. -f1)
|
|
local load=$(cat /proc/loadavg | cut -d' ' -f1-3)
|
|
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
|
local mem_free=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
|
|
local mem_used=$((mem_total - mem_free))
|
|
local mem_pct=$((mem_used * 100 / mem_total))
|
|
|
|
json_add_object "status"
|
|
json_add_string "version" "$PKG_VERSION"
|
|
json_add_string "hostname" "$(uci -q get system.@system[0].hostname || echo 'SecuBox')"
|
|
json_add_int "uptime" "$uptime"
|
|
json_add_string "load" "$load"
|
|
json_add_int "memory_total" "$mem_total"
|
|
json_add_int "memory_used" "$mem_used"
|
|
json_add_int "memory_percent" "$mem_pct"
|
|
json_close_object
|
|
|
|
# Load config once for all modules
|
|
config_load secubox 2>/dev/null || true
|
|
|
|
# Get modules list
|
|
json_add_array "modules"
|
|
local total=0 installed=0 running=0
|
|
|
|
# List all module sections from UCI config
|
|
local module_sections=$(uci -q show secubox | grep "=module$" | cut -d. -f2 | cut -d= -f1)
|
|
|
|
for module in $module_sections; do
|
|
local name desc category icon color package version
|
|
config_get name "$module" name "$module"
|
|
config_get desc "$module" description ""
|
|
config_get category "$module" category "other"
|
|
config_get icon "$module" icon "box"
|
|
config_get color "$module" color "#64748b"
|
|
config_get package "$module" package ""
|
|
config_get version "$module" version "0.0.9"
|
|
|
|
local is_installed=$(check_module_installed "$module")
|
|
local is_enabled="0"
|
|
local is_running="0"
|
|
local status="disabled"
|
|
|
|
total=$((total + 1))
|
|
|
|
if [ "$is_installed" = "1" ]; then
|
|
is_enabled=$(check_module_enabled "$module")
|
|
is_running=$(check_module_running "$module")
|
|
status=$(get_module_status "$is_enabled" "$is_running")
|
|
installed=$((installed + 1))
|
|
[ "$is_running" = "1" ] && running=$((running + 1))
|
|
|
|
# Get real version from package manager if installed
|
|
if [ -n "$package" ]; then
|
|
if [ -x "/usr/bin/apk" ]; then
|
|
# OpenWrt 25.12+ uses apk
|
|
local real_version=$(apk list --installed "$package" 2>/dev/null | head -1 | awk '{print $1}' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
|
|
[ -n "$real_version" ] && version="$real_version"
|
|
elif [ -x "/bin/opkg" ] || [ -x "/usr/bin/opkg" ]; then
|
|
# OpenWrt 24.10 and earlier uses opkg
|
|
local real_version=$(opkg list-installed "$package" 2>/dev/null | awk '{print $3}' | sed 's/-.*$//')
|
|
[ -n "$real_version" ] && version="$real_version"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
json_add_object ""
|
|
json_add_string "id" "$module"
|
|
json_add_string "name" "$name"
|
|
json_add_string "description" "$desc"
|
|
json_add_string "category" "$category"
|
|
json_add_string "icon" "$icon"
|
|
json_add_string "color" "$color"
|
|
json_add_string "version" "$version"
|
|
json_add_boolean "installed" "$is_installed"
|
|
json_add_boolean "enabled" "$is_enabled"
|
|
json_add_boolean "running" "$is_running"
|
|
json_add_string "status" "$status"
|
|
json_close_object
|
|
done
|
|
json_close_array
|
|
|
|
json_add_object "counts"
|
|
json_add_int "total" "$total"
|
|
json_add_int "installed" "$installed"
|
|
json_add_int "running" "$running"
|
|
json_close_object
|
|
|
|
# Get system health
|
|
local cpu_cores=$(grep -c processor /proc/cpuinfo)
|
|
local load_val=$(echo "$load" | cut -d' ' -f1)
|
|
local cpu_pct=$(awk "BEGIN {printf \"%.0f\", ($load_val / $cpu_cores) * 100}" 2>/dev/null || echo "0")
|
|
local disk_pct=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
|
|
|
|
json_add_object "health"
|
|
json_add_int "cpu_percent" "$cpu_pct"
|
|
json_add_int "memory_percent" "$mem_pct"
|
|
json_add_int "disk_percent" "$disk_pct"
|
|
json_close_object
|
|
|
|
# Empty alerts array
|
|
json_add_array "alerts"
|
|
json_close_array
|
|
|
|
json_add_int "timestamp" "$(date +%s)"
|
|
json_dump
|
|
}
|
|
|
|
# Get theme setting
|
|
get_theme() {
|
|
local theme="dark"
|
|
|
|
# Load secubox config
|
|
if [ -f "/etc/config/secubox" ]; then
|
|
config_load secubox
|
|
config_get theme main theme "dark"
|
|
fi
|
|
|
|
json_init
|
|
json_add_string "theme" "$theme"
|
|
json_dump
|
|
}
|
|
|
|
# Persist theme setting
|
|
set_theme() {
|
|
local input theme="dark"
|
|
|
|
read -r input
|
|
[ -n "$input" ] && json_load "$input"
|
|
json_get_var theme theme "dark"
|
|
|
|
case "$theme" in
|
|
dark|light|system|cyberpunk)
|
|
;;
|
|
*)
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Invalid theme"
|
|
json_dump
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
uci -q set secubox.main.theme="$theme"
|
|
uci -q commit secubox
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "theme" "$theme"
|
|
json_add_string "message" "Theme updated"
|
|
json_dump
|
|
}
|
|
|
|
# Dismiss a specific alert
|
|
dismiss_alert() {
|
|
local alert_id="$1"
|
|
|
|
# Store dismissed alerts in tmp file
|
|
local dismissed_file="/tmp/secubox_dismissed_alerts"
|
|
|
|
# Append alert_id to dismissed list
|
|
echo "$alert_id" >> "$dismissed_file"
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Alert dismissed"
|
|
json_dump
|
|
}
|
|
|
|
# Clear all alerts
|
|
clear_alerts() {
|
|
# Clear dismissed alerts file
|
|
local dismissed_file="/tmp/secubox_dismissed_alerts"
|
|
rm -f "$dismissed_file"
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "All alerts cleared"
|
|
json_dump
|
|
}
|
|
|
|
# Fix permissions (v0.3.1)
|
|
fix_permissions() {
|
|
local fix_script="/usr/libexec/secubox/fix-permissions.sh"
|
|
|
|
if [ ! -x "$fix_script" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Fix script not found or not executable"
|
|
json_dump
|
|
return 1
|
|
fi
|
|
|
|
# Run the fix script and capture output
|
|
local output=$($fix_script 2>&1)
|
|
local exit_code=$?
|
|
|
|
json_init
|
|
if [ $exit_code -eq 0 ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Permissions fixed successfully"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Failed to fix permissions"
|
|
fi
|
|
json_add_string "output" "$output"
|
|
json_dump
|
|
}
|
|
|
|
# Main dispatcher
|
|
first_run_status() {
|
|
local timezone storage network_json mode_name mode_id storage_path
|
|
storage_path=$(get_storage_path)
|
|
local storage_ready=0
|
|
[ -d "$storage_path" ] && storage_ready=1
|
|
local password_state=0
|
|
if is_root_password_set; then
|
|
password_state=1
|
|
fi
|
|
timezone=$(uci -q get system.@system[0].timezone || echo "UTC")
|
|
mode_id="unknown"
|
|
mode_name="N/A"
|
|
if command -v ubus >/dev/null 2>&1; then
|
|
network_json=$(ubus call luci.network-modes status 2>/dev/null || printf '')
|
|
if [ -n "$network_json" ]; then
|
|
mode_id=$(jsonfilter -s "$network_json" -e '@.current_mode' 2>/dev/null || echo "$mode_id")
|
|
mode_name=$(jsonfilter -s "$network_json" -e '@.mode_name' 2>/dev/null || echo "$mode_name")
|
|
fi
|
|
fi
|
|
json_init
|
|
json_add_boolean "password_set" "$password_state"
|
|
json_add_string "timezone" "$timezone"
|
|
json_add_string "storage_path" "$storage_path"
|
|
json_add_boolean "storage_ready" "$storage_ready"
|
|
json_add_string "network_mode" "$mode_id"
|
|
json_add_string "network_mode_name" "$mode_name"
|
|
json_add_array "recommended_modes"
|
|
json_add_string "" "router"
|
|
json_add_string "" "dmz"
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
apply_first_run() {
|
|
local input
|
|
read input
|
|
json_load "$input"
|
|
json_get_var timezone timezone
|
|
json_get_var storage_path storage_path
|
|
json_get_var network_mode network_mode
|
|
json_init
|
|
json_add_array "messages"
|
|
if [ -n "$timezone" ]; then
|
|
uci set system.@system[0].timezone="$timezone"
|
|
uci set system.@system[0].zonename="$timezone"
|
|
uci commit system
|
|
if [ -f "/usr/share/zoneinfo/$timezone" ]; then
|
|
ln -sf "/usr/share/zoneinfo/$timezone" /etc/localtime
|
|
fi
|
|
json_add_string "" "Timezone updated"
|
|
fi
|
|
if [ -n "$storage_path" ]; then
|
|
mkdir -p "$storage_path"
|
|
chmod 755 "$storage_path"
|
|
uci set secubox.main.storage_path="$storage_path"
|
|
uci commit secubox
|
|
json_add_string "" "Storage prepared at $storage_path"
|
|
fi
|
|
if [ -n "$network_mode" ]; then
|
|
if command -v ubus >/dev/null 2>&1; then
|
|
if ubus call luci.network-modes set_mode "{\"mode\":\"$network_mode\"}" >/dev/null 2>&1; then
|
|
if ubus call luci.network-modes apply_mode >/dev/null 2>&1; then
|
|
json_add_string "" "Network mode $network_mode applied"
|
|
else
|
|
json_add_string "" "Failed to apply network mode"
|
|
fi
|
|
else
|
|
json_add_string "" "Mode $network_mode unsupported"
|
|
fi
|
|
else
|
|
json_add_string "" "ubus unavailable; cannot change network mode"
|
|
fi
|
|
fi
|
|
json_close_array
|
|
json_add_boolean "success" 1
|
|
json_dump
|
|
}
|
|
|
|
list_apps() {
|
|
ensure_directory "$PLUGIN_DIR"
|
|
json_init
|
|
json_add_array "apps"
|
|
local manifest_file manifest id name runtime type version description state wizard_field category maturity seen_ids=""
|
|
while IFS= read -r manifest_file; do
|
|
[ -f "$manifest_file" ] || continue
|
|
manifest=$(cat "$manifest_file")
|
|
id=$(jsonfilter -s "$manifest" -e '@.id' 2>/dev/null)
|
|
[ -n "$id" ] || continue
|
|
case " $seen_ids " in
|
|
*" $id "*) continue ;;
|
|
esac
|
|
if ! validate_manifest_json "$manifest"; then
|
|
continue
|
|
fi
|
|
seen_ids="$seen_ids $id"
|
|
name=$(jsonfilter -s "$manifest" -e '@.name' 2>/dev/null)
|
|
type=$(jsonfilter -s "$manifest" -e '@.type' 2>/dev/null)
|
|
runtime=$(jsonfilter -s "$manifest" -e '@.runtime' 2>/dev/null)
|
|
[ -n "$type" ] || type="$runtime"
|
|
version=$(jsonfilter -s "$manifest" -e '@.version' 2>/dev/null)
|
|
description=$(jsonfilter -s "$manifest" -e '@.description' 2>/dev/null)
|
|
category=$(jsonfilter -s "$manifest" -e '@.category' 2>/dev/null)
|
|
maturity=$(jsonfilter -s "$manifest" -e '@.maturity' 2>/dev/null)
|
|
state=$(packages_state "$manifest")
|
|
wizard_field=$(jsonfilter -s "$manifest" -e '@.wizard.fields[0].id' 2>/dev/null)
|
|
json_add_object
|
|
json_add_string "id" "$id"
|
|
json_add_string "name" "$name"
|
|
json_add_string "runtime" "$runtime"
|
|
json_add_string "type" "$type"
|
|
json_add_string "version" "$version"
|
|
json_add_string "description" "$description"
|
|
json_add_string "category" "$category"
|
|
json_add_string "maturity" "$maturity"
|
|
json_add_string "state" "$state"
|
|
json_add_boolean "has_wizard" "$([ -n "$wizard_field" ] && echo 1 || echo 0)"
|
|
json_close_object
|
|
done <<EOF
|
|
$(manifest_files | sort)
|
|
EOF
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
get_app_manifest() {
|
|
local input app_id file manifest state
|
|
read input
|
|
app_id=$(jsonfilter -s "$input" -e '@.app_id' 2>/dev/null)
|
|
if [ -z "$app_id" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "app_id required"
|
|
json_dump
|
|
return
|
|
fi
|
|
file=$(manifest_file_for_id "$app_id")
|
|
if [ -z "$file" ] || [ ! -f "$file" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Manifest not found"
|
|
json_dump
|
|
return
|
|
fi
|
|
manifest=$(cat "$file")
|
|
state=$(packages_state "$manifest")
|
|
json_load "$manifest"
|
|
json_add_string "state" "$state"
|
|
json_dump
|
|
}
|
|
|
|
apply_app_wizard() {
|
|
local input app_id file manifest config section fields field option value
|
|
read input
|
|
app_id=$(jsonfilter -s "$input" -e '@.app_id' 2>/dev/null)
|
|
if [ -z "$app_id" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "app_id required"
|
|
json_dump
|
|
return
|
|
fi
|
|
file=$(manifest_file_for_id "$app_id")
|
|
if [ -z "$file" ] || [ ! -f "$file" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Manifest not found"
|
|
json_dump
|
|
return
|
|
fi
|
|
manifest=$(cat "$file")
|
|
config=$(jsonfilter -s "$manifest" -e '@.wizard.uci.config' 2>/dev/null)
|
|
section=$(jsonfilter -s "$manifest" -e '@.wizard.uci.section' 2>/dev/null)
|
|
[ -n "$section" ] || section="main"
|
|
if [ -z "$config" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Wizard missing UCI config"
|
|
json_dump
|
|
return
|
|
fi
|
|
fields=$(jsonfilter -s "$manifest" -e '@.wizard.fields[*].id' 2>/dev/null)
|
|
for field in $fields; do
|
|
option=$(jsonfilter -s "$manifest" -e "@.wizard.fields[@.id='$field'].uci_option" 2>/dev/null)
|
|
[ -n "$option" ] || continue
|
|
value=$(jsonfilter -s "$input" -e "@.values.$field" 2>/dev/null)
|
|
[ -n "$value" ] || continue
|
|
uci set ${config}.${section}.${option}="$value"
|
|
done
|
|
uci commit "$config"
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_dump
|
|
}
|
|
|
|
list_profiles() {
|
|
ensure_directory "$PROFILE_DIR"
|
|
json_init
|
|
json_add_array "profiles"
|
|
local profile_file
|
|
for profile_file in "$PROFILE_DIR"/*.json; do
|
|
[ -f "$profile_file" ] || continue
|
|
local profile_json id name description network_mode apps state
|
|
profile_json=$(cat "$profile_file")
|
|
id=$(jsonfilter -s "$profile_json" -e '@.id' 2>/dev/null)
|
|
name=$(jsonfilter -s "$profile_json" -e '@.name' 2>/dev/null)
|
|
description=$(jsonfilter -s "$profile_json" -e '@.description' 2>/dev/null)
|
|
network_mode=$(jsonfilter -s "$profile_json" -e '@.network_mode' 2>/dev/null)
|
|
apps=$(jsonfilter -s "$profile_json" -e '@.apps[*]' 2>/dev/null)
|
|
state=$(packages_state "$profile_json")
|
|
[ -n "$id" ] || continue
|
|
json_add_object
|
|
json_add_string "id" "$id"
|
|
json_add_string "name" "$name"
|
|
json_add_string "description" "$description"
|
|
json_add_string "network_mode" "$network_mode"
|
|
json_add_string "state" "$state"
|
|
json_add_array "apps"
|
|
for app in $apps; do
|
|
json_add_string "" "$app"
|
|
done
|
|
json_close_array
|
|
json_close_object
|
|
done
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
apply_profile() {
|
|
local input profile_id profile_file profile_json network_mode packages apps backup_file notes=""
|
|
read input
|
|
json_load "$input"
|
|
json_get_var profile_id profile_id
|
|
json_cleanup
|
|
[ -n "$profile_id" ] || {
|
|
json_init; json_add_boolean "success" 0; json_add_string "error" "profile_id required"; json_dump; return;
|
|
}
|
|
profile_file="$PROFILE_DIR/$profile_id.json"
|
|
if [ ! -f "$profile_file" ]; then
|
|
json_init; json_add_boolean "success" 0; json_add_string "error" "Profile not found"; json_dump; return;
|
|
fi
|
|
profile_json=$(cat "$profile_file")
|
|
ensure_directory "$PROFILE_BACKUP_DIR"
|
|
local timestamp=$(date +%Y%m%d_%H%M%S)
|
|
backup_file="$PROFILE_BACKUP_DIR/profile_${profile_id}_${timestamp}.tar.gz"
|
|
tar -czf "$backup_file" /etc/config 2>/dev/null
|
|
notes="${notes}Backup saved to $backup_file\n"
|
|
uci set secubox.profile.last_backup="$backup_file"
|
|
uci set secubox.profile.last_profile="$profile_id"
|
|
uci commit secubox
|
|
network_mode=$(jsonfilter -s "$profile_json" -e '@.network_mode' 2>/dev/null)
|
|
if [ -n "$network_mode" ]; then
|
|
notes="${notes}Switched network mode to $network_mode\n"
|
|
apply_network_mode "$network_mode"
|
|
fi
|
|
packages=$(jsonfilter -s "$profile_json" -e '@.packages[*]' 2>/dev/null)
|
|
for pkg in $packages; do
|
|
install_package_if_missing "$pkg"
|
|
notes="${notes}Ensured package $pkg\n"
|
|
done
|
|
apps=$(jsonfilter -s "$profile_json" -e '@.apps[*]' 2>/dev/null)
|
|
for app in $apps; do
|
|
if [ -x "$SECOBOX_APP" ]; then
|
|
$SECOBOX_APP install "$app" >/dev/null 2>&1 && notes="${notes}Installed app $app\n"
|
|
fi
|
|
done
|
|
json_load "$profile_json"
|
|
local uci_configs=""
|
|
if json_select uci >/dev/null 2>&1; then
|
|
local entries
|
|
json_get_keys entries
|
|
for entry in $entries; do
|
|
json_select "$entry"
|
|
local cfg section option value
|
|
json_get_var cfg config
|
|
json_get_var section section
|
|
json_get_var option option
|
|
json_get_var value value
|
|
section=${section:-main}
|
|
if [ -n "$cfg" ] && [ -n "$option" ]; then
|
|
uci set ${cfg}.${section}.${option}="$value"
|
|
uci_configs="${uci_configs} $cfg"
|
|
notes="${notes}Set ${cfg}.${section}.${option}=${value}\n"
|
|
fi
|
|
json_select ..
|
|
done
|
|
json_select ..
|
|
fi
|
|
json_cleanup
|
|
local committed=""
|
|
for cfg in $uci_configs; do
|
|
case " $committed " in
|
|
*" $cfg "*) continue;;
|
|
esac
|
|
uci commit "$cfg"
|
|
committed="$committed $cfg"
|
|
done
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_array "messages"
|
|
printf '%b' "$notes" | while IFS= read -r line; do
|
|
[ -n "$line" ] && json_add_string "" "$line"
|
|
done
|
|
json_close_array
|
|
json_add_string "backup" "$backup_file"
|
|
json_dump
|
|
}
|
|
|
|
rollback_profile() {
|
|
local latest_backup
|
|
latest_backup=$(ls -t "$PROFILE_BACKUP_DIR"/profile_*.tar.gz 2>/dev/null | head -1)
|
|
if [ -z "$latest_backup" ]; then
|
|
json_init; json_add_boolean "success" 0; json_add_string "error" "No backups available"; json_dump; return;
|
|
fi
|
|
cd /
|
|
tar -xzf "$latest_backup" 2>/dev/null
|
|
/etc/init.d/network reload >/dev/null 2>&1
|
|
/etc/init.d/firewall reload >/dev/null 2>&1
|
|
/etc/init.d/dnsmasq reload >/dev/null 2>&1
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Restored $latest_backup"
|
|
json_dump
|
|
}
|
|
|
|
# ============================================================================
|
|
# App Store Functions
|
|
# ============================================================================
|
|
|
|
APPSTORE_JSON="/usr/share/secubox/appstore/apps.json"
|
|
|
|
# Get all apps from app store catalog
|
|
get_appstore_apps() {
|
|
if [ ! -f "$APPSTORE_JSON" ]; then
|
|
json_init
|
|
json_add_array "apps"
|
|
json_close_array
|
|
json_add_object "categories"
|
|
json_close_object
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
local appstore_data=$(cat "$APPSTORE_JSON")
|
|
local app_count=$(jsonfilter -s "$appstore_data" -e '@.apps[*]' | wc -l)
|
|
|
|
json_init
|
|
json_add_array "apps"
|
|
|
|
local i=0
|
|
while [ $i -lt $app_count ]; do
|
|
local app_id=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].id")
|
|
local app_name=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].name")
|
|
local app_version=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].version")
|
|
local app_category=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].category")
|
|
local app_description=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].description")
|
|
local app_icon=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].icon")
|
|
local app_status=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].status")
|
|
local app_luci=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].luci_app")
|
|
local app_notes=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].notes")
|
|
|
|
# Check if app is installed
|
|
local is_installed=0
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
opkg list-installed "$app_id" 2>/dev/null | grep -q "^$app_id " && is_installed=1
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
apk info -e "$app_id" >/dev/null 2>&1 && is_installed=1
|
|
fi
|
|
|
|
json_add_object
|
|
json_add_string "id" "$app_id"
|
|
json_add_string "name" "$app_name"
|
|
json_add_string "version" "$app_version"
|
|
json_add_string "category" "$app_category"
|
|
json_add_string "description" "$app_description"
|
|
json_add_string "icon" "$app_icon"
|
|
json_add_string "status" "$app_status"
|
|
json_add_boolean "installed" "$is_installed"
|
|
[ -n "$app_luci" ] && json_add_string "luci_app" "$app_luci"
|
|
[ -n "$app_notes" ] && json_add_string "notes" "$app_notes"
|
|
json_close_object
|
|
|
|
i=$((i + 1))
|
|
done
|
|
|
|
json_close_array
|
|
|
|
# Add categories
|
|
json_add_object "categories"
|
|
local cat_keys=$(jsonfilter -s "$appstore_data" -e '@.categories' | jsonfilter -e '@[@]')
|
|
for cat in security network iot media; do
|
|
local cat_name=$(jsonfilter -s "$appstore_data" -e "@.categories.$cat.name")
|
|
local cat_icon=$(jsonfilter -s "$appstore_data" -e "@.categories.$cat.icon")
|
|
local cat_desc=$(jsonfilter -s "$appstore_data" -e "@.categories.$cat.description")
|
|
if [ -n "$cat_name" ]; then
|
|
json_add_object "$cat"
|
|
json_add_string "name" "$cat_name"
|
|
json_add_string "icon" "$cat_icon"
|
|
json_add_string "description" "$cat_desc"
|
|
json_close_object
|
|
fi
|
|
done
|
|
json_close_object
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get single app from app store
|
|
get_appstore_app() {
|
|
local input app_id
|
|
read input
|
|
json_load "$input"
|
|
json_get_var app_id app_id
|
|
json_cleanup
|
|
|
|
if [ ! -f "$APPSTORE_JSON" ]; then
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "App store catalog not found"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
local appstore_data=$(cat "$APPSTORE_JSON")
|
|
local app_count=$(jsonfilter -s "$appstore_data" -e '@.apps[*]' | wc -l)
|
|
|
|
local i=0
|
|
while [ $i -lt $app_count ]; do
|
|
local current_id=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].id")
|
|
if [ "$current_id" = "$app_id" ]; then
|
|
# Found the app
|
|
json_init
|
|
json_add_string "id" "$current_id"
|
|
json_add_string "name" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].name")"
|
|
json_add_string "version" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].version")"
|
|
json_add_string "category" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].category")"
|
|
json_add_string "description" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].description")"
|
|
json_add_string "icon" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].icon")"
|
|
json_add_string "author" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].author")"
|
|
json_add_string "license" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].license")"
|
|
json_add_string "url" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].url")"
|
|
json_add_string "status" "$(jsonfilter -s "$appstore_data" -e "@.apps[$i].status")"
|
|
|
|
local app_luci=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].luci_app")
|
|
[ -n "$app_luci" ] && [ "$app_luci" != "null" ] && json_add_string "luci_app" "$app_luci"
|
|
|
|
local app_notes=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].notes")
|
|
[ -n "$app_notes" ] && [ "$app_notes" != "null" ] && json_add_string "notes" "$app_notes"
|
|
|
|
# Add dependencies array
|
|
json_add_array "dependencies"
|
|
local dep_count=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].dependencies[*]" | wc -l)
|
|
local j=0
|
|
while [ $j -lt $dep_count ]; do
|
|
local dep=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].dependencies[$j]")
|
|
json_add_string "" "$dep"
|
|
j=$((j + 1))
|
|
done
|
|
json_close_array
|
|
|
|
# Add tags array
|
|
json_add_array "tags"
|
|
local tag_count=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].tags[*]" | wc -l)
|
|
j=0
|
|
while [ $j -lt $tag_count ]; do
|
|
local tag=$(jsonfilter -s "$appstore_data" -e "@.apps[$i].tags[$j]")
|
|
json_add_string "" "$tag"
|
|
j=$((j + 1))
|
|
done
|
|
json_close_array
|
|
|
|
# Check installation status
|
|
local is_installed=0
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
opkg list-installed "$app_id" 2>/dev/null | grep -q "^$app_id " && is_installed=1
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
apk info -e "$app_id" >/dev/null 2>&1 && is_installed=1
|
|
fi
|
|
json_add_boolean "installed" "$is_installed"
|
|
|
|
json_dump
|
|
return
|
|
fi
|
|
i=$((i + 1))
|
|
done
|
|
|
|
# App not found
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "App not found"
|
|
json_dump
|
|
}
|
|
|
|
# Install app from app store
|
|
install_appstore_app() {
|
|
local input app_id
|
|
read input
|
|
json_load "$input"
|
|
json_get_var app_id app_id
|
|
json_cleanup
|
|
|
|
[ -z "$app_id" ] && {
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "app_id required"
|
|
json_dump
|
|
return
|
|
}
|
|
|
|
# Update package lists if not done in this session
|
|
if [ "$OPKG_UPDATED" -eq 0 ]; then
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
opkg update >/dev/null 2>&1
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
apk update >/dev/null 2>&1
|
|
fi
|
|
OPKG_UPDATED=1
|
|
fi
|
|
|
|
# Install the package
|
|
local install_output
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
install_output=$(opkg install "$app_id" 2>&1)
|
|
local ret=$?
|
|
if [ $ret -eq 0 ]; then
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "App installed successfully"
|
|
json_add_string "app_id" "$app_id"
|
|
json_dump
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Installation failed"
|
|
json_add_string "details" "$install_output"
|
|
json_dump
|
|
fi
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
install_output=$(apk add "$app_id" 2>&1)
|
|
local ret=$?
|
|
if [ $ret -eq 0 ]; then
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "App installed successfully"
|
|
json_add_string "app_id" "$app_id"
|
|
json_dump
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Installation failed"
|
|
json_add_string "details" "$install_output"
|
|
json_dump
|
|
fi
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "No package manager found"
|
|
json_dump
|
|
fi
|
|
}
|
|
|
|
# Remove app from app store
|
|
remove_appstore_app() {
|
|
local input app_id
|
|
read input
|
|
json_load "$input"
|
|
json_get_var app_id app_id
|
|
json_cleanup
|
|
|
|
[ -z "$app_id" ] && {
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "app_id required"
|
|
json_dump
|
|
return
|
|
}
|
|
|
|
# Remove the package
|
|
local remove_output
|
|
if command -v opkg >/dev/null 2>&1; then
|
|
remove_output=$(opkg remove "$app_id" 2>&1)
|
|
local ret=$?
|
|
if [ $ret -eq 0 ]; then
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "App removed successfully"
|
|
json_add_string "app_id" "$app_id"
|
|
json_dump
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Removal failed"
|
|
json_add_string "details" "$remove_output"
|
|
json_dump
|
|
fi
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
remove_output=$(apk del "$app_id" 2>&1)
|
|
local ret=$?
|
|
if [ $ret -eq 0 ]; then
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "App removed successfully"
|
|
json_add_string "app_id" "$app_id"
|
|
json_dump
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Removal failed"
|
|
json_add_string "details" "$remove_output"
|
|
json_dump
|
|
fi
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "No package manager found"
|
|
json_dump
|
|
fi
|
|
}
|
|
|
|
case "$1" in
|
|
list)
|
|
json_init
|
|
json_add_object "status"
|
|
json_close_object
|
|
json_add_object "modules"
|
|
json_close_object
|
|
json_add_object "modules_by_category"
|
|
json_add_string "category" "string"
|
|
json_close_object
|
|
json_add_object "module_info"
|
|
json_add_string "module" "string"
|
|
json_close_object
|
|
json_add_object "start_module"
|
|
json_add_string "module" "string"
|
|
json_close_object
|
|
json_add_object "stop_module"
|
|
json_add_string "module" "string"
|
|
json_close_object
|
|
json_add_object "restart_module"
|
|
json_add_string "module" "string"
|
|
json_close_object
|
|
json_add_object "enable_module"
|
|
json_add_string "module" "string"
|
|
json_close_object
|
|
json_add_object "disable_module"
|
|
json_add_string "module" "string"
|
|
json_close_object
|
|
json_add_object "check_module_enabled"
|
|
json_add_string "module" "string"
|
|
json_close_object
|
|
json_add_object "health"
|
|
json_close_object
|
|
json_add_object "diagnostics"
|
|
json_close_object
|
|
json_add_object "get_system_health"
|
|
json_close_object
|
|
json_add_object "get_alerts"
|
|
json_close_object
|
|
json_add_object "quick_action"
|
|
json_add_string "action" "string"
|
|
json_close_object
|
|
json_add_object "get_dashboard_data"
|
|
json_close_object
|
|
json_add_object "get_theme"
|
|
json_close_object
|
|
json_add_object "set_theme"
|
|
json_add_string "theme" "string"
|
|
json_close_object
|
|
json_add_object "dismiss_alert"
|
|
json_add_string "alert_id" "string"
|
|
json_close_object
|
|
json_add_object "clear_alerts"
|
|
json_close_object
|
|
json_add_object "fix_permissions"
|
|
json_close_object
|
|
json_add_object "first_run_status"
|
|
json_close_object
|
|
json_add_object "apply_first_run"
|
|
json_close_object
|
|
json_add_object "list_apps"
|
|
json_close_object
|
|
json_add_object "get_app_manifest"
|
|
json_add_string "app_id" "string"
|
|
json_close_object
|
|
json_add_object "apply_app_wizard"
|
|
json_add_string "app_id" "string"
|
|
json_close_object
|
|
json_add_object "list_profiles"
|
|
json_close_object
|
|
json_add_object "apply_profile"
|
|
json_add_string "profile_id" "string"
|
|
json_close_object
|
|
json_add_object "rollback_profile"
|
|
json_close_object
|
|
json_add_object "get_appstore_apps"
|
|
json_close_object
|
|
json_add_object "get_appstore_app"
|
|
json_add_string "app_id" "string"
|
|
json_close_object
|
|
json_add_object "install_appstore_app"
|
|
json_add_string "app_id" "string"
|
|
json_close_object
|
|
json_add_object "remove_appstore_app"
|
|
json_add_string "app_id" "string"
|
|
json_close_object
|
|
json_add_object "first_run_status"
|
|
json_close_object
|
|
json_add_object "apply_first_run"
|
|
json_close_object
|
|
json_add_object "list_apps"
|
|
json_close_object
|
|
json_add_object "get_app_manifest"
|
|
json_add_string "app_id" "string"
|
|
json_close_object
|
|
json_add_object "apply_app_wizard"
|
|
json_add_string "app_id" "string"
|
|
json_close_object
|
|
json_dump
|
|
;;
|
|
call)
|
|
case "$2" in
|
|
status)
|
|
get_status
|
|
;;
|
|
modules)
|
|
get_modules
|
|
;;
|
|
modules_by_category)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var category category "security"
|
|
get_modules_by_category "$category"
|
|
;;
|
|
module_info)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var module module ""
|
|
get_module_info "$module"
|
|
;;
|
|
start_module)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var module module ""
|
|
start_module "$module"
|
|
;;
|
|
stop_module)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var module module ""
|
|
stop_module "$module"
|
|
;;
|
|
restart_module)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var module module ""
|
|
restart_module "$module"
|
|
;;
|
|
enable_module)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var module module ""
|
|
enable_module "$module"
|
|
;;
|
|
disable_module)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var module module ""
|
|
disable_module "$module"
|
|
;;
|
|
check_module_enabled)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var module module ""
|
|
local enabled=$(check_module_enabled "$module")
|
|
json_init
|
|
json_add_boolean "enabled" "$enabled"
|
|
json_dump
|
|
;;
|
|
health)
|
|
get_health
|
|
;;
|
|
diagnostics)
|
|
get_diagnostics
|
|
;;
|
|
get_system_health)
|
|
get_system_health
|
|
;;
|
|
get_alerts)
|
|
get_alerts
|
|
;;
|
|
quick_action)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var action action ""
|
|
quick_action "$action"
|
|
;;
|
|
get_dashboard_data)
|
|
get_dashboard_data
|
|
;;
|
|
get_theme)
|
|
get_theme
|
|
;;
|
|
set_theme)
|
|
set_theme
|
|
;;
|
|
dismiss_alert)
|
|
read -r input
|
|
json_load "$input"
|
|
json_get_var alert_id alert_id ""
|
|
dismiss_alert "$alert_id"
|
|
;;
|
|
clear_alerts)
|
|
clear_alerts
|
|
;;
|
|
fix_permissions)
|
|
fix_permissions
|
|
;;
|
|
first_run_status)
|
|
first_run_status
|
|
;;
|
|
apply_first_run)
|
|
apply_first_run
|
|
;;
|
|
list_apps)
|
|
list_apps
|
|
;;
|
|
get_app_manifest)
|
|
get_app_manifest
|
|
;;
|
|
apply_app_wizard)
|
|
apply_app_wizard
|
|
;;
|
|
list_profiles)
|
|
list_profiles
|
|
;;
|
|
apply_profile)
|
|
apply_profile
|
|
;;
|
|
rollback_profile)
|
|
rollback_profile
|
|
;;
|
|
get_appstore_apps)
|
|
get_appstore_apps
|
|
;;
|
|
get_appstore_app)
|
|
get_appstore_app
|
|
;;
|
|
install_appstore_app)
|
|
install_appstore_app
|
|
;;
|
|
remove_appstore_app)
|
|
remove_appstore_app
|
|
;;
|
|
*)
|
|
echo '{"error":"Unknown method"}'
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
echo '{"error":"Unknown command"}'
|
|
;;
|
|
esac
|