From 5afb02c8154c4d22f9b0db247fa68b9b0488652b Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Thu, 1 Jan 2026 16:48:02 +0100 Subject: [PATCH] refactor(luci-app-secubox): remove RPCD backend, depend on secubox-core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves package conflict where both luci-app-secubox and secubox-core were providing /usr/libexec/rpcd/luci.secubox. Changes: - Remove RPCD backend (luci.secubox) from luci-app-secubox - Add secubox-core as a dependency - Update Makefile to reflect new architecture - Remove RPCD file references from helper scripts - Update documentation Architecture: - secubox-core (v0.8.0): Provides framework + RPCD backend - luci-app-secubox (v0.7.0): Provides LuCI web UI only πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- luci-app-secubox/Makefile | 9 +- luci-app-secubox/README.md | 3 +- .../root/etc/uci-defaults/99-secubox | 3 +- .../root/usr/libexec/rpcd/luci.secubox | 2080 ----------------- .../usr/libexec/secubox/fix-permissions.sh | 2 +- 5 files changed, 8 insertions(+), 2089 deletions(-) delete mode 100755 luci-app-secubox/root/usr/libexec/rpcd/luci.secubox diff --git a/luci-app-secubox/Makefile b/luci-app-secubox/Makefile index 6d9783a9..773dc320 100644 --- a/luci-app-secubox/Makefile +++ b/luci-app-secubox/Makefile @@ -8,18 +8,17 @@ PKG_MAINTAINER:=CyberMind LUCI_TITLE:=LuCI - SecuBox Hub (Central Dashboard) LUCI_DESCRIPTION:=Central control hub for all SecuBox modules. Provides unified dashboard, module status, system health monitoring, and quick actions. -LUCI_DEPENDS:=+luci-base +rpcd +curl +jq +LUCI_DEPENDS:=+luci-base +rpcd +curl +jq +secubox-core LUCI_PKGARCH:=all -# File permissions (CRITICAL: RPCD scripts MUST be executable 755) +# File permissions (CRITICAL: Helper scripts MUST be executable 755) # Format: path:owner:group:mode -# - RPCD scripts: 755 (executable by root, required for ubus calls) # - Helper scripts: 755 (if executable) # - Data files: 644 (readable by all - INSTALL_DATA sets this automatically) # - Directories: 755 (set automatically by INSTALL_DIR) # - CSS/JS files: 644 (set automatically by luci.mk) -PKG_FILE_MODES:=/usr/libexec/rpcd/luci.secubox:root:root:755 \ - /usr/libexec/secubox/fix-permissions.sh:root:root:755 +# Note: RPCD backend is now provided by secubox-core package +PKG_FILE_MODES:=/usr/libexec/secubox/fix-permissions.sh:root:root:755 include $(TOPDIR)/feeds/luci/luci.mk diff --git a/luci-app-secubox/README.md b/luci-app-secubox/README.md index fe061e3d..9d8c7fdd 100644 --- a/luci-app-secubox/README.md +++ b/luci-app-secubox/README.md @@ -170,10 +170,11 @@ luci-app-secubox/ └── root/ β”œβ”€β”€ etc/config/secubox # UCI configuration └── usr/ - β”œβ”€β”€ libexec/rpcd/secubox # RPCD backend └── share/ β”œβ”€β”€ luci/menu.d/luci-app-secubox.json └── rpcd/acl.d/luci-app-secubox.json + + # Note: RPCD backend (luci.secubox) is provided by secubox-core package ``` ## License diff --git a/luci-app-secubox/root/etc/uci-defaults/99-secubox b/luci-app-secubox/root/etc/uci-defaults/99-secubox index 2f55805e..b5774479 100755 --- a/luci-app-secubox/root/etc/uci-defaults/99-secubox +++ b/luci-app-secubox/root/etc/uci-defaults/99-secubox @@ -3,8 +3,7 @@ # SecuBox UCI Defaults # Copyright (C) 2025 CyberMind.fr -# Set proper permissions -chmod +x /usr/libexec/rpcd/secubox 2>/dev/null || true +# Note: RPCD backend is now provided by secubox-core package # Reload rpcd to register new methods /etc/init.d/rpcd reload 2>/dev/null || true diff --git a/luci-app-secubox/root/usr/libexec/rpcd/luci.secubox b/luci-app-secubox/root/usr/libexec/rpcd/luci.secubox deleted file mode 100755 index cab428fd..00000000 --- a/luci-app-secubox/root/usr/libexec/rpcd/luci.secubox +++ /dev/null @@ -1,2080 +0,0 @@ -#!/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 </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 diff --git a/luci-app-secubox/root/usr/libexec/secubox/fix-permissions.sh b/luci-app-secubox/root/usr/libexec/secubox/fix-permissions.sh index 53c79abc..e3aa11f0 100644 --- a/luci-app-secubox/root/usr/libexec/secubox/fix-permissions.sh +++ b/luci-app-secubox/root/usr/libexec/secubox/fix-permissions.sh @@ -21,8 +21,8 @@ log_error() { fix_rpcd_permissions() { log_info "Fixing RPCD script permissions..." + # Note: luci.secubox backend is now provided by secubox-core package local rpcd_scripts=" - /usr/libexec/rpcd/luci.secubox /usr/libexec/rpcd/luci.system-hub /usr/libexec/rpcd/luci.network-modes /usr/libexec/rpcd/luci.crowdsec-dashboard