secubox-openwrt/package/secubox/luci-app-rtty-remote/root/usr/libexec/rpcd/luci.rtty-remote
CyberMind-FR 02ed4f3b34 fix(rtty-remote): Fix RPCD rpc_call JSON response format
- jshn cannot embed raw JSON in objects, use printf instead
- Return proper {"success":true,"result":{...}} format
- Handle error cases with escaped error messages

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-08 17:06:32 +01:00

338 lines
9.2 KiB
Bash

#!/bin/sh
# RPCD handler for luci-app-rtty-remote
# Provides RPC interface for RTTY Remote Control
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
# Load libraries
[ -f /usr/lib/secubox/rtty-proxy.sh ] && . /usr/lib/secubox/rtty-proxy.sh
[ -f /usr/lib/secubox/rtty-session.sh ] && . /usr/lib/secubox/rtty-session.sh
[ -f /usr/lib/secubox/rtty-auth.sh ] && . /usr/lib/secubox/rtty-auth.sh
RTTYCTL="/usr/sbin/rttyctl"
#------------------------------------------------------------------------------
# Helper functions
#------------------------------------------------------------------------------
get_config() {
local section="$1"
local option="$2"
local default="$3"
config_load rtty-remote
config_get value "$section" "$option" "$default"
echo "$value"
}
#------------------------------------------------------------------------------
# RPC Methods
#------------------------------------------------------------------------------
# Get server status
method_status() {
json_init
config_load rtty-remote
local enabled
config_get enabled main enabled '0'
json_add_boolean "enabled" "$enabled"
local port
config_get port main server_port '7681'
json_add_int "port" "$port"
# Check if running
if pgrep -f "rttyctl server-daemon" >/dev/null 2>&1; then
json_add_boolean "running" 1
else
json_add_boolean "running" 0
fi
# Stats
if [ -f /srv/rtty-remote/sessions.db ]; then
local stats=$(session_stats 2>/dev/null)
json_add_int "total_sessions" "$(echo "$stats" | jsonfilter -e '@.total_sessions' 2>/dev/null || echo 0)"
json_add_int "active_sessions" "$(echo "$stats" | jsonfilter -e '@.active_sessions' 2>/dev/null || echo 0)"
json_add_int "total_rpc_calls" "$(echo "$stats" | jsonfilter -e '@.total_rpc_calls' 2>/dev/null || echo 0)"
json_add_int "unique_nodes" "$(echo "$stats" | jsonfilter -e '@.unique_nodes' 2>/dev/null || echo 0)"
else
json_add_int "total_sessions" 0
json_add_int "active_sessions" 0
json_add_int "total_rpc_calls" 0
json_add_int "unique_nodes" 0
fi
json_dump
}
# Get mesh nodes
method_get_nodes() {
local nodes=$($RTTYCTL json-nodes 2>/dev/null)
[ -z "$nodes" ] && nodes='{"nodes":[]}'
echo "$nodes"
}
# Get single node details
method_get_node() {
local node_id
read -r input
json_load "$input"
json_get_var node_id node_id
[ -z "$node_id" ] && {
echo '{"error":"Missing node_id"}'
return
}
# Get node info from master-link or P2P
json_init
json_add_string "node_id" "$node_id"
# Try to get address
local addr=$($RTTYCTL node "$node_id" 2>&1 | grep "Address:" | awk '{print $2}')
json_add_string "address" "$addr"
# Check connectivity
if [ -n "$addr" ] && ping -c 1 -W 2 "$addr" >/dev/null 2>&1; then
json_add_string "status" "online"
else
json_add_string "status" "offline"
fi
json_dump
}
# Execute remote RPC call
method_rpc_call() {
local node_id object method params
read -r input
json_load "$input"
json_get_var node_id node_id
json_get_var object object
json_get_var method method
json_get_var params params
[ -z "$node_id" ] || [ -z "$object" ] || [ -z "$method" ] && {
echo '{"error":"Missing required parameters (node_id, object, method)"}'
return
}
# Execute via rttyctl
local result=$($RTTYCTL rpc "$node_id" "$object" "$method" "$params" 2>&1)
local rc=$?
if [ $rc -eq 0 ] && [ -n "$result" ]; then
# Check if result is valid JSON
if echo "$result" | jsonfilter -e '@' >/dev/null 2>&1; then
# Output success with embedded JSON result
printf '{"success":true,"result":%s}' "$result"
else
# Result is not JSON, wrap as string
printf '{"success":true,"result":"%s"}' "$(echo "$result" | sed 's/"/\\"/g')"
fi
else
# Error case
local err_msg=$(echo "$result" | sed 's/"/\\"/g' | tr '\n' ' ')
printf '{"success":false,"error":"%s"}' "$err_msg"
fi
}
# List remote RPCD objects
method_rpc_list() {
local node_id
read -r input
json_load "$input"
json_get_var node_id node_id
[ -z "$node_id" ] && {
echo '{"error":"Missing node_id"}'
return
}
local result=$($RTTYCTL rpc-list "$node_id" 2>&1)
echo "$result"
}
# Get sessions
method_get_sessions() {
local node_id limit
read -r input
json_load "$input"
json_get_var node_id node_id
json_get_var limit limit
[ -z "$limit" ] && limit=50
session_list "$node_id" "$limit"
}
# Start server
method_server_start() {
/etc/init.d/rtty-remote start 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Stop server
method_server_stop() {
/etc/init.d/rtty-remote stop 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Get settings
method_get_settings() {
json_init
config_load rtty-remote
json_add_object "main"
local val
config_get val main enabled '0'
json_add_boolean "enabled" "$val"
config_get val main server_port '7681'
json_add_int "server_port" "$val"
config_get val main auth_method 'master-link'
json_add_string "auth_method" "$val"
config_get val main session_ttl '3600'
json_add_int "session_ttl" "$val"
config_get val main max_sessions '10'
json_add_int "max_sessions" "$val"
json_close_object
json_add_object "security"
config_get val security require_wg '1'
json_add_boolean "require_wg" "$val"
config_get val security allowed_networks ''
json_add_string "allowed_networks" "$val"
json_close_object
json_add_object "proxy"
config_get val proxy rpc_timeout '30'
json_add_int "rpc_timeout" "$val"
config_get val proxy batch_limit '50'
json_add_int "batch_limit" "$val"
config_get val proxy cache_ttl '60'
json_add_int "cache_ttl" "$val"
json_close_object
json_dump
}
# Set settings
method_set_settings() {
read -r input
# Parse and apply settings
local enabled=$(echo "$input" | jsonfilter -e '@.main.enabled' 2>/dev/null)
[ -n "$enabled" ] && uci set rtty-remote.main.enabled="$enabled"
local port=$(echo "$input" | jsonfilter -e '@.main.server_port' 2>/dev/null)
[ -n "$port" ] && uci set rtty-remote.main.server_port="$port"
local auth=$(echo "$input" | jsonfilter -e '@.main.auth_method' 2>/dev/null)
[ -n "$auth" ] && uci set rtty-remote.main.auth_method="$auth"
local ttl=$(echo "$input" | jsonfilter -e '@.main.session_ttl' 2>/dev/null)
[ -n "$ttl" ] && uci set rtty-remote.main.session_ttl="$ttl"
uci commit rtty-remote
json_init
json_add_boolean "success" 1
json_dump
}
# Replay session
method_replay_session() {
local session_id target_node
read -r input
json_load "$input"
json_get_var session_id session_id
json_get_var target_node target_node
[ -z "$session_id" ] || [ -z "$target_node" ] && {
echo '{"error":"Missing session_id or target_node"}'
return
}
local result=$($RTTYCTL replay "$session_id" "$target_node" 2>&1)
json_init
json_add_boolean "success" 1
json_add_string "message" "$result"
json_dump
}
# Connect to node (start terminal)
method_connect() {
local node_id
read -r input
json_load "$input"
json_get_var node_id node_id
[ -z "$node_id" ] && {
echo '{"error":"Missing node_id"}'
return
}
# Get node address
local addr=$($RTTYCTL node "$node_id" 2>&1 | grep "Address:" | awk '{print $2}')
json_init
json_add_string "node_id" "$node_id"
json_add_string "address" "$addr"
json_add_string "terminal_url" "ws://localhost:7681/ws"
json_add_string "ssh_command" "ssh root@$addr"
json_dump
}
#------------------------------------------------------------------------------
# Main dispatcher
#------------------------------------------------------------------------------
case "$1" in
list)
cat << 'EOF'
{
"status": {},
"get_nodes": {},
"get_node": {"node_id": "string"},
"rpc_call": {"node_id": "string", "object": "string", "method": "string", "params": "string"},
"rpc_list": {"node_id": "string"},
"get_sessions": {"node_id": "string", "limit": 50},
"server_start": {},
"server_stop": {},
"get_settings": {},
"set_settings": {"config": "object"},
"replay_session": {"session_id": "integer", "target_node": "string"},
"connect": {"node_id": "string"}
}
EOF
;;
call)
case "$2" in
status) method_status ;;
get_nodes) method_get_nodes ;;
get_node) method_get_node ;;
rpc_call) method_rpc_call ;;
rpc_list) method_rpc_list ;;
get_sessions) method_get_sessions ;;
server_start) method_server_start ;;
server_stop) method_server_stop ;;
get_settings) method_get_settings ;;
set_settings) method_set_settings ;;
replay_session) method_replay_session ;;
connect) method_connect ;;
*)
echo '{"error":"Unknown method"}'
;;
esac
;;
esac