secubox-openwrt/package/secubox/luci-app-device-intel/root/usr/libexec/rpcd/luci.device-intel
CyberMind-FR f4157811c5 fix(device-intel): Fix empty vendor column and add OUI emoji display
- Fix wrong mac-guardian DB path (clients.db -> known.db) in 3 files
- Add standalone OUI vendor fallback for ARP/DHCP-only devices
- Expand oui.tsv from ~30 to 100+ entries (GL.iNet, Bosch, Samsung, Docker, etc.)
- Add vendorDisplay() with emoji prefixes for MAC types:
  container, virtual, randomized, IoT, mesh peer

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 18:33:10 +01:00

253 lines
7.2 KiB
Bash

#!/bin/sh
#
# RPCD backend for SecuBox Device Intelligence
#
. /usr/share/libubox/jshn.sh
. /lib/functions.sh
DI_LIB="/usr/lib/secubox/device-intel"
DI_CACHE="/tmp/device-intel"
CONFIG="device-intel"
case "$1" in
list)
json_init
json_add_object "get_devices"
json_close_object
json_add_object "get_device"
json_add_string "mac" "string"
json_close_object
json_add_object "get_summary"
json_close_object
json_add_object "get_mesh_devices"
json_close_object
json_add_object "get_emulators"
json_close_object
json_add_object "get_device_types"
json_close_object
json_add_object "classify_device"
json_add_string "mac" "string"
json_close_object
json_add_object "set_device_meta"
json_add_string "mac" "string"
json_add_string "type" "string"
json_add_string "label" "string"
json_close_object
json_add_object "refresh"
json_close_object
json_dump
;;
call)
handle_call() {
case "$1" in
get_devices)
. "${DI_LIB}/functions.sh"
local devices=$(di_get_devices)
# Stream directly — devices is already JSON array
printf '{"success":true,"devices":%s}' "$devices"
;;
get_device)
read -r input
local mac=$(echo "$input" | jsonfilter -e '@.mac' 2>/dev/null)
if [ -z "$mac" ]; then
echo '{"success":false,"error":"mac is required"}'
exit 0
fi
. "${DI_LIB}/functions.sh"
local devices=$(di_get_devices)
local mac_lower=$(echo "$mac" | tr 'A-F' 'a-f')
# Extract single device from array
local device=$(echo "$devices" | jsonfilter -e "@[@.mac='${mac_lower}']" 2>/dev/null)
if [ -n "$device" ]; then
printf '{"success":true,"device":%s}' "$device"
else
echo '{"success":false,"error":"Device not found"}'
fi
;;
get_summary)
. "${DI_LIB}/functions.sh"
local summary=$(di_get_summary)
# Add emulator counts
local usb_enabled=$(uci -q get ${CONFIG}.usb.enabled)
local mqtt_enabled=$(uci -q get ${CONFIG}.mqtt.enabled)
local zigbee_enabled=$(uci -q get ${CONFIG}.zigbee.enabled)
# Count data sources
local mg_available=0
[ -f /var/run/mac-guardian/known.db ] && mg_available=1
local cg_available=0
uci -q get client-guardian.@client[0] >/dev/null 2>&1 && cg_available=1
local dhcp_available=0
[ -f /tmp/dhcp.leases ] && dhcp_available=1
local p2p_running=0
pgrep -f secubox-p2p >/dev/null 2>&1 && p2p_running=1
# Build response
local total=$(echo "$summary" | jsonfilter -e '@.total' 2>/dev/null)
local online=$(echo "$summary" | jsonfilter -e '@.online' 2>/dev/null)
local mesh=$(echo "$summary" | jsonfilter -e '@.mesh_peers' 2>/dev/null)
json_init
json_add_boolean "success" 1
json_add_int "total" "${total:-0}"
json_add_int "online" "${online:-0}"
json_add_int "mesh_peers" "${mesh:-0}"
json_add_object "emulators"
json_add_boolean "usb" "$([ "$usb_enabled" = "1" ] && echo 1 || echo 0)"
json_add_boolean "mqtt" "$([ "$mqtt_enabled" = "1" ] && echo 1 || echo 0)"
json_add_boolean "zigbee" "$([ "$zigbee_enabled" = "1" ] && echo 1 || echo 0)"
json_close_object
json_add_object "sources"
json_add_boolean "mac_guardian" "$mg_available"
json_add_boolean "client_guardian" "$cg_available"
json_add_boolean "dhcp" "$dhcp_available"
json_add_boolean "p2p" "$p2p_running"
json_close_object
json_dump
;;
get_mesh_devices)
. "${DI_LIB}/functions.sh"
local devices=$(di_get_devices)
# Filter mesh devices
printf '{"success":true,"devices":['
local first=1
echo "$devices" | jsonfilter -e '@[*]' 2>/dev/null | while read -r dev; do
local src=$(echo "$dev" | jsonfilter -e '@.source_node' 2>/dev/null)
local dtype=$(echo "$dev" | jsonfilter -e '@.device_type' 2>/dev/null)
if [ "$src" = "mesh" ] || [ "$dtype" = "mesh_peer" ]; then
[ $first -eq 1 ] && first=0 || printf ','
echo "$dev"
fi
done
printf ']}'
;;
get_emulators)
json_init
json_add_boolean "success" 1
# USB
json_add_object "usb"
json_add_boolean "enabled" "$([ "$(uci -q get ${CONFIG}.usb.enabled)" = "1" ] && echo 1 || echo 0)"
json_add_int "scan_interval" "$(uci -q get ${CONFIG}.usb.scan_interval || echo 120)"
local usb_count=$(ls -d /sys/bus/usb/devices/[0-9]* 2>/dev/null | grep -v ':' | wc -l)
json_add_int "device_count" "$usb_count"
json_close_object
# MQTT
json_add_object "mqtt"
json_add_boolean "enabled" "$([ "$(uci -q get ${CONFIG}.mqtt.enabled)" = "1" ] && echo 1 || echo 0)"
json_add_string "broker_host" "$(uci -q get ${CONFIG}.mqtt.broker_host)"
json_add_int "broker_port" "$(uci -q get ${CONFIG}.mqtt.broker_port || echo 1883)"
local mqtt_running=0
pgrep mosquitto >/dev/null 2>&1 && mqtt_running=1
json_add_boolean "broker_running" "$mqtt_running"
json_close_object
# Zigbee
json_add_object "zigbee"
json_add_boolean "enabled" "$([ "$(uci -q get ${CONFIG}.zigbee.enabled)" = "1" ] && echo 1 || echo 0)"
json_add_string "adapter" "$(uci -q get ${CONFIG}.zigbee.adapter)"
json_add_string "coordinator" "$(uci -q get ${CONFIG}.zigbee.coordinator)"
local dongle_present=0
local coord=$(uci -q get ${CONFIG}.zigbee.coordinator)
[ -c "${coord:-/dev/ttyUSB0}" ] 2>/dev/null && dongle_present=1
json_add_boolean "dongle_present" "$dongle_present"
json_close_object
json_dump
;;
get_device_types)
. "${DI_LIB}/functions.sh"
local types=$(di_get_device_types)
printf '{"success":true,"types":%s}' "$types"
;;
classify_device)
read -r input
local mac=$(echo "$input" | jsonfilter -e '@.mac' 2>/dev/null)
. "${DI_LIB}/functions.sh"
. "${DI_LIB}/classify.sh"
if [ -n "$mac" ]; then
local output=$(/usr/sbin/device-intelctl classify "$mac" 2>&1)
else
local output=$(/usr/sbin/device-intelctl classify 2>&1)
fi
json_init
json_add_boolean "success" 1
json_add_string "output" "$output"
json_dump
;;
set_device_meta)
read -r input
local mac=$(echo "$input" | jsonfilter -e '@.mac' 2>/dev/null)
local dtype=$(echo "$input" | jsonfilter -e '@.type' 2>/dev/null)
local label=$(echo "$input" | jsonfilter -e '@.label' 2>/dev/null)
if [ -z "$mac" ]; then
echo '{"success":false,"error":"mac is required"}'
exit 0
fi
local mac_lower=$(echo "$mac" | tr 'A-F' 'a-f')
local mac_clean=$(echo "$mac_lower" | tr -d ':')
# Create/update UCI section
uci set ${CONFIG}.${mac_clean}=device
uci set ${CONFIG}.${mac_clean}.mac="$mac_lower"
[ -n "$dtype" ] && uci set ${CONFIG}.${mac_clean}.type="$dtype"
[ -n "$label" ] && uci set ${CONFIG}.${mac_clean}.label="$label"
uci commit "$CONFIG"
# Invalidate cache
rm -f "${DI_CACHE}"/cache*.json 2>/dev/null
json_init
json_add_boolean "success" 1
json_add_string "message" "Device metadata updated"
json_dump
;;
refresh)
rm -f "${DI_CACHE}"/cache*.json 2>/dev/null
json_init
json_add_boolean "success" 1
json_add_string "message" "Cache invalidated"
json_dump
;;
*)
json_init
json_add_boolean "error" 1
json_add_string "message" "Unknown method: $1"
json_dump
;;
esac
}
handle_call "$2"
;;
esac
exit 0