nas16-scripts/CrowdSec/cs_notifier.sh
2026-07-26 21:21:03 -04:00

100 lines
3.4 KiB
Bash

#!/bin/bash
# =============================================================
# CrowdSec Local Attack Notifier
# Host: NAS16 (192.168.150.40)
# Target: CrowdSec LAPI on HAS (192.168.150.30:8080)
# Schedule: Every 5 minutes via OMV Scheduled Jobs
#
# Local (crowdsec origin) decisions are appended to:
# /var/log/crowdsec-notifier/local_pending.json
# and batched into a 4-hour digest by cs_local_digest.sh.
#
# CAPI decisions continue to be appended to capi_digest.json
# and sent as a midnight summary by cs_digest.sh (unchanged).
# =============================================================
LAPI_URL="http://192.168.150.30:8080"
API_KEY="K1nZ5TYeyl18adqw7+dop/po9gHZNQvsuLz78lla/34"
STARTUP_FLAG="/var/log/crowdsec-notifier/stream_initialized.flag"
LOCAL_PENDING="/var/log/crowdsec-notifier/local_pending.json"
CAPI_DIGEST="/var/log/crowdsec-notifier/capi_digest.json"
LOG_FILE="/var/log/crowdsec-notifier/notifier.log"
mkdir -p /var/log/crowdsec-notifier
touch "$CAPI_DIGEST"
touch "$LOCAL_PENDING"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"; }
log "--- cs_notifier run start ---"
# --- First run: initialize stream cursor silently ---
if [[ ! -f "$STARTUP_FLAG" ]]; then
log "First run — initializing stream cursor. No emails will be sent."
INIT_RESPONSE=$(curl -s --max-time 60 \
-H "X-Api-Key: $API_KEY" \
"${LAPI_URL}/v1/decisions/stream?startup=true")
if [[ -z "$INIT_RESPONSE" ]]; then
log "ERROR: Empty response from LAPI during startup. Will retry next run."
exit 1
fi
NEW_COUNT=$(echo "$INIT_RESPONSE" | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(len(data.get('new') or []))
" 2>/dev/null)
log "Stream cursor initialized. Skipped $NEW_COUNT existing decisions. Ready for live monitoring."
touch "$STARTUP_FLAG"
log "--- cs_notifier run complete (init) ---"
exit 0
fi
# --- Normal run: fetch only new decisions since last call ---
RESPONSE=$(curl -s --max-time 30 \
-H "X-Api-Key: $API_KEY" \
"${LAPI_URL}/v1/decisions/stream?startup=false")
HTTP_CHECK=$(echo "$RESPONSE" | python3 -c "import sys,json; json.load(sys.stdin); print('ok')" 2>/dev/null)
if [[ "$HTTP_CHECK" != "ok" ]]; then
log "ERROR: Invalid response from LAPI stream endpoint"
exit 1
fi
# --- Parse and route new decisions ---
NEW_LOCAL_COUNT=0
NEW_CAPI_COUNT=0
while IFS= read -r decision; do
[[ -z "$decision" ]] && continue
ORIGIN=$(echo "$decision" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('origin',''))" 2>/dev/null)
if [[ "$ORIGIN" == "crowdsec" ]]; then
# Append to pending local digest — cs_local_digest.sh will send every 4 hours
echo "$decision" >> "$LOCAL_PENDING"
NEW_LOCAL_COUNT=$((NEW_LOCAL_COUNT + 1))
elif [[ "$ORIGIN" == "CAPI" ]]; then
# Append to CAPI digest — cs_digest.sh will send at midnight
echo "$decision" >> "$CAPI_DIGEST"
NEW_CAPI_COUNT=$((NEW_CAPI_COUNT + 1))
fi
done < <(echo "$RESPONSE" | python3 -c "
import sys, json
data = json.load(sys.stdin)
new = data.get('new') or []
for item in new:
print(json.dumps(item))
")
CAPI_TODAY=$(wc -l < "$CAPI_DIGEST" 2>/dev/null | tr -d ' ')
CAPI_TODAY=${CAPI_TODAY:-0}
LOCAL_PENDING_COUNT=$(wc -l < "$LOCAL_PENDING" 2>/dev/null | tr -d ' ')
LOCAL_PENDING_COUNT=${LOCAL_PENDING_COUNT:-0}
log "New local: $NEW_LOCAL_COUNT (pending total: $LOCAL_PENDING_COUNT) | New CAPI: $NEW_CAPI_COUNT | CAPI today: $CAPI_TODAY"
log "--- cs_notifier run complete ---"