secubox-openwrt/package/secubox/luci-app-avatar-tap/root/usr/libexec/rpcd/luci.avatar-tap
CyberMind-FR d01828d632 feat(avatar-tap): Add session capture and replay package
New packages for passive network tap with session replay capabilities:

secubox-avatar-tap:
- Mitmproxy-based passive session capture
- Captures authenticated sessions (cookies, auth headers, tokens)
- SQLite database for session storage
- CLI tool (avatar-tapctl) for management
- Transparent proxy mode support
- Runs inside streamlit LXC container

luci-app-avatar-tap:
- KISS-style dashboard for session management
- Real-time stats (sessions, domains, replays)
- Replay/Label/Delete actions per session
- Start/Stop controls

Designed for SecuBox Avatar authentication relay system
with future Nitrokey/GPG integration.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-06 20:41:21 +01:00

164 lines
5.9 KiB
Bash
Executable File

#!/bin/sh
# RPCD handler for Avatar Tap
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
DB_PATH="/srv/avatar-tap/sessions.db"
case "$1" in
list)
echo '{"status":{},"get_sessions":{"domain":"str","limit":"int"},"get_session":{"id":"int"},"replay":{"id":"int","url":"str","method":"str"},"label":{"id":"int","label":"str"},"delete":{"id":"int"},"start":{},"stop":{},"cleanup":{"days":"int"},"stats":{}}'
;;
call)
case "$2" in
status)
/usr/sbin/avatar-tapctl json-status
;;
get_sessions)
read -r input
json_load "$input"
json_get_var domain domain
json_get_var limit limit
[ -z "$limit" ] && limit=50
if [ ! -f "$DB_PATH" ]; then
echo '{"sessions":[]}'
exit 0
fi
if [ -n "$domain" ]; then
sessions=$(sqlite3 -json "$DB_PATH" \
"SELECT id, domain, path, method, captured_at, last_used, use_count, label, avatar_id
FROM sessions WHERE domain LIKE '%$domain%'
ORDER BY captured_at DESC LIMIT $limit" 2>/dev/null)
else
sessions=$(sqlite3 -json "$DB_PATH" \
"SELECT id, domain, path, method, captured_at, last_used, use_count, label, avatar_id
FROM sessions ORDER BY captured_at DESC LIMIT $limit" 2>/dev/null)
fi
[ -z "$sessions" ] && sessions="[]"
echo "{\"sessions\":$sessions}"
;;
get_session)
read -r input
json_load "$input"
json_get_var id id
[ -z "$id" ] && { echo '{"error":"Missing session id"}'; exit 1; }
if [ ! -f "$DB_PATH" ]; then
echo '{"error":"No database"}'
exit 1
fi
session=$(sqlite3 -json "$DB_PATH" \
"SELECT * FROM sessions WHERE id = $id" 2>/dev/null)
[ -z "$session" ] && session="null"
# Extract first element from array
echo "{\"session\":${session}}"
;;
replay)
read -r input
json_load "$input"
json_get_var id id
json_get_var url url
json_get_var method method
[ -z "$id" ] || [ -z "$url" ] && { echo '{"error":"Missing id or url"}'; exit 1; }
export AVATAR_TAP_DB="$DB_PATH"
if [ -n "$method" ]; then
result=$(python3 /usr/share/avatar-tap/replay.py replay "$id" "$url" -m "$method" 2>&1)
else
result=$(python3 /usr/share/avatar-tap/replay.py replay "$id" "$url" 2>&1)
fi
# Extract status code from output
status_code=$(echo "$result" | grep -o "Status: [0-9]*" | grep -o "[0-9]*")
[ -z "$status_code" ] && status_code=0
json_init
json_add_int "status_code" "$status_code"
json_add_string "output" "$result"
json_dump
;;
label)
read -r input
json_load "$input"
json_get_var id id
json_get_var label label
[ -z "$id" ] || [ -z "$label" ] && { echo '{"error":"Missing id or label"}'; exit 1; }
sqlite3 "$DB_PATH" "UPDATE sessions SET label = '$label' WHERE id = $id"
echo '{"success":true}'
;;
delete)
read -r input
json_load "$input"
json_get_var id id
[ -z "$id" ] && { echo '{"error":"Missing session id"}'; exit 1; }
sqlite3 "$DB_PATH" "DELETE FROM replay_log WHERE session_id = $id"
sqlite3 "$DB_PATH" "DELETE FROM sessions WHERE id = $id"
echo '{"success":true}'
;;
start)
/usr/sbin/avatar-tapctl start >/dev/null 2>&1
sleep 1
/usr/sbin/avatar-tapctl json-status
;;
stop)
/usr/sbin/avatar-tapctl stop >/dev/null 2>&1
sleep 1
/usr/sbin/avatar-tapctl json-status
;;
cleanup)
read -r input
json_load "$input"
json_get_var days days
[ -z "$days" ] && days=7
export AVATAR_TAP_DB="$DB_PATH"
result=$(python3 /usr/share/avatar-tap/replay.py cleanup -d "$days" 2>&1)
echo "{\"result\":\"$result\"}"
;;
stats)
if [ ! -f "$DB_PATH" ]; then
echo '{"total":0,"domains":0,"replays":0}'
exit 0
fi
total=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM sessions" 2>/dev/null || echo 0)
domains=$(sqlite3 "$DB_PATH" "SELECT COUNT(DISTINCT domain) FROM sessions" 2>/dev/null || echo 0)
replays=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM replay_log" 2>/dev/null || echo 0)
recent=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM sessions WHERE captured_at > strftime('%s','now','-1 hour')" 2>/dev/null || echo 0)
top_domains=$(sqlite3 -json "$DB_PATH" \
"SELECT domain, COUNT(*) as count FROM sessions GROUP BY domain ORDER BY count DESC LIMIT 5" 2>/dev/null)
[ -z "$top_domains" ] && top_domains="[]"
echo "{\"total\":$total,\"domains\":$domains,\"replays\":$replays,\"recent\":$recent,\"top_domains\":$top_domains}"
;;
*)
echo '{"error":"Unknown method"}'
;;
esac
;;
esac