- workspace: capmetro-monitor, github-notifications, model-selector - workspace-security: vt-monitor, monitor-unauthorized - workspace-home: cron-manager, monitor-unauthorized - extensions: vt-sentinel (VT-Sentinel plugin) Includes sync.sh for pull/push, README, AGENTS.md, .gitignore.
124 lines
3.7 KiB
Bash
Executable File
124 lines
3.7 KiB
Bash
Executable File
#!/bin/bash
|
|
# Thread index manager for monitor-unauthorized
|
|
#
|
|
# Maintains a local JSON index of Discord threads so the cron-wrapper
|
|
# can determine whether to create a new thread or update an existing one.
|
|
#
|
|
# The index is populated BY THE AGENT (not by this script) because only
|
|
# the agent has access to OpenClaw session/thread listing tools.
|
|
#
|
|
# This script provides helper operations:
|
|
# bash index-threads.sh lookup <ip> — find thread for an IP (exit 0 = found)
|
|
# bash index-threads.sh status — check if index exists and is fresh
|
|
# bash index-threads.sh record <ip> <session_key> — add/update an entry
|
|
# bash index-threads.sh needs-refresh — exit 0 if index is missing/stale
|
|
#
|
|
# Index location: STATE_DIR/thread-index.json
|
|
# Format:
|
|
# {
|
|
# "indexed_at": "2026-02-16T12:00:00Z",
|
|
# "channel_id": "1471181304782389381",
|
|
# "threads": {
|
|
# "1.2.3.4": {
|
|
# "session_key": "agent:security:discord:channel:1471181304782389381:thread:🚨 1.2.3.4 — unauthorized gateway access",
|
|
# "thread_name": "🚨 1.2.3.4 — unauthorized gateway access",
|
|
# "first_indexed": "2026-02-10T08:00:00Z",
|
|
# "last_updated": "2026-02-16T12:00:00Z",
|
|
# "update_count": 3
|
|
# }
|
|
# }
|
|
# }
|
|
|
|
set -e
|
|
|
|
STATE_DIR="/home/node/.openclaw/workspace-security/memory"
|
|
INDEX_FILE="$STATE_DIR/thread-index.json"
|
|
CHANNEL_ID="1471181304782389381"
|
|
MAX_AGE=86400 # 24 hours before considered stale
|
|
|
|
mkdir -p "$STATE_DIR"
|
|
|
|
# Initialize empty index if missing
|
|
init_index() {
|
|
if [ ! -f "$INDEX_FILE" ] || [ ! -s "$INDEX_FILE" ]; then
|
|
jq -n --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg ch "$CHANNEL_ID" \
|
|
'{indexed_at: $ts, channel_id: $ch, threads: {}}' > "$INDEX_FILE"
|
|
fi
|
|
}
|
|
|
|
# Check if index needs refresh (missing, empty, or stale)
|
|
needs_refresh() {
|
|
if [ ! -f "$INDEX_FILE" ] || [ ! -s "$INDEX_FILE" ]; then
|
|
echo "missing"
|
|
return 0
|
|
fi
|
|
local age=$(( $(date +%s) - $(stat -c%Y "$INDEX_FILE" 2>/dev/null || echo 0) ))
|
|
if [ "$age" -gt "$MAX_AGE" ]; then
|
|
echo "stale"
|
|
return 0
|
|
fi
|
|
echo "fresh"
|
|
return 1
|
|
}
|
|
|
|
# Look up a thread by IP
|
|
lookup() {
|
|
local ip="$1"
|
|
init_index
|
|
local result
|
|
result=$(jq -e --arg ip "$ip" '.threads[$ip] // empty' "$INDEX_FILE" 2>/dev/null)
|
|
if [ -n "$result" ]; then
|
|
echo "$result"
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
# Record a thread entry for an IP
|
|
record() {
|
|
local ip="$1"
|
|
local session_key="$2"
|
|
local thread_name="${3:-🚨 $ip — unauthorized gateway access}"
|
|
local now
|
|
now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
|
|
init_index
|
|
|
|
local tmp
|
|
tmp=$(mktemp)
|
|
jq --arg ip "$ip" \
|
|
--arg sk "$session_key" \
|
|
--arg tn "$thread_name" \
|
|
--arg now "$now" \
|
|
'
|
|
.threads[$ip] = (
|
|
(.threads[$ip] // {first_indexed: $now, update_count: 0}) |
|
|
.session_key = $sk |
|
|
.thread_name = $tn |
|
|
.last_updated = $now |
|
|
.update_count = (.update_count + 1)
|
|
)
|
|
' "$INDEX_FILE" > "$tmp" && mv "$tmp" "$INDEX_FILE"
|
|
echo '{"ok":true}'
|
|
}
|
|
|
|
# Print index status
|
|
status() {
|
|
init_index
|
|
local count
|
|
count=$(jq '.threads | length' "$INDEX_FILE")
|
|
local indexed_at
|
|
indexed_at=$(jq -r '.indexed_at' "$INDEX_FILE")
|
|
local age=$(( $(date +%s) - $(stat -c%Y "$INDEX_FILE" 2>/dev/null || echo 0) ))
|
|
echo "{\"entries\":$count,\"indexed_at\":\"$indexed_at\",\"age_seconds\":$age,\"stale\":$([ $age -gt $MAX_AGE ] && echo true || echo false)}"
|
|
}
|
|
|
|
# Dispatch
|
|
case "${1:-status}" in
|
|
lookup) lookup "$2" ;;
|
|
record) record "$2" "$3" "$4" ;;
|
|
status) status ;;
|
|
needs-refresh) needs_refresh ;;
|
|
*) echo "Usage: $0 {lookup|record|status|needs-refresh} [args...]" >&2; exit 1 ;;
|
|
esac
|