Consolidate multiple dashboard API calls into a single get_overview RPC method to reduce network overhead and improve page load performance. The frontend now transforms the consolidated response to maintain compatibility with existing view logic. Also increases poll interval from 30s to 60s. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2377 lines
67 KiB
Bash
Executable File
2377 lines
67 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
# CrowdSec Dashboard RPCD backend
|
|
# Copyright (C) 2024 CyberMind.fr - Gandalf
|
|
|
|
. /lib/functions.sh
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
SECCUBOX_LOG="/usr/sbin/secubox-log"
|
|
|
|
secubox_log() {
|
|
[ -x "$SECCUBOX_LOG" ] || return
|
|
"$SECCUBOX_LOG" --tag "crowdsec" --message "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
CSCLI="/usr/bin/cscli"
|
|
CSCLI_TIMEOUT=10
|
|
|
|
# Check if timeout command exists
|
|
HAS_TIMEOUT=""
|
|
command -v timeout >/dev/null 2>&1 && HAS_TIMEOUT=1
|
|
|
|
# Run cscli with optional timeout to prevent hangs
|
|
run_cscli() {
|
|
if [ -n "$HAS_TIMEOUT" ]; then
|
|
timeout "$CSCLI_TIMEOUT" "$CSCLI" "$@" 2>/dev/null
|
|
else
|
|
"$CSCLI" "$@" 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
# Run command with optional timeout
|
|
run_with_timeout() {
|
|
local secs="$1"
|
|
shift
|
|
if [ -n "$HAS_TIMEOUT" ]; then
|
|
timeout "$secs" "$@"
|
|
else
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
# Check if cscli exists and crowdsec is running
|
|
check_cscli() {
|
|
if [ ! -x "$CSCLI" ]; then
|
|
echo '{"error": "cscli not found"}'
|
|
exit 1
|
|
fi
|
|
|
|
# Check if crowdsec service is running
|
|
if ! pgrep crowdsec >/dev/null 2>&1; then
|
|
echo '{"error": "crowdsec service not running"}'
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Get decisions list
|
|
get_decisions() {
|
|
check_cscli
|
|
local output
|
|
output=$(run_cscli decisions list -o json)
|
|
if [ -z "$output" ] || [ "$output" = "null" ]; then
|
|
echo '{"alerts":[]}'
|
|
else
|
|
echo "{\"alerts\":$output}"
|
|
fi
|
|
}
|
|
|
|
# Get alerts list
|
|
get_alerts() {
|
|
local limit="${1:-50}"
|
|
check_cscli
|
|
local output
|
|
output=$(run_cscli alerts list -o json --limit "$limit" 2>/dev/null)
|
|
if [ -z "$output" ] || [ "$output" = "null" ]; then
|
|
echo '{"alerts":[]}'
|
|
else
|
|
echo "{\"alerts\":$output}"
|
|
fi
|
|
}
|
|
|
|
# Get metrics
|
|
get_metrics() {
|
|
check_cscli
|
|
local output
|
|
output=$(run_cscli metrics -o json 2>/dev/null)
|
|
if [ -z "$output" ]; then
|
|
echo '{}'
|
|
else
|
|
# Fix malformed JSON from cscli (remove empty string keys)
|
|
# CrowdSec sometimes outputs "": {...} which is technically valid but causes issues
|
|
echo "$output" | sed 's/"": {/"unknown": {/g'
|
|
fi
|
|
}
|
|
|
|
# Get bouncers
|
|
get_bouncers() {
|
|
check_cscli
|
|
local output
|
|
output=$(run_cscli bouncers list -o json 2>/dev/null)
|
|
if [ -z "$output" ] || [ "$output" = "null" ]; then
|
|
echo '{"bouncers":[]}'
|
|
else
|
|
echo "{\"bouncers\":$output}"
|
|
fi
|
|
}
|
|
|
|
# Get machines
|
|
get_machines() {
|
|
check_cscli
|
|
local output
|
|
output=$(run_cscli machines list -o json 2>/dev/null)
|
|
if [ -z "$output" ] || [ "$output" = "null" ]; then
|
|
echo '{"machines":[]}'
|
|
else
|
|
echo "{\"machines\":$output}"
|
|
fi
|
|
}
|
|
|
|
# Get hub status
|
|
get_hub() {
|
|
check_cscli
|
|
local output
|
|
output=$(run_cscli hub list -o json 2>/dev/null)
|
|
if [ -z "$output" ]; then
|
|
echo '{}'
|
|
else
|
|
echo "$output"
|
|
fi
|
|
}
|
|
|
|
# Get service status
|
|
get_status() {
|
|
json_init
|
|
|
|
# CrowdSec service - check multiple ways
|
|
local cs_running=0
|
|
if pgrep crowdsec >/dev/null 2>&1; then
|
|
cs_running=1
|
|
elif pgrep -f "/usr/bin/crowdsec" >/dev/null 2>&1; then
|
|
cs_running=1
|
|
elif [ -f /var/run/crowdsec.pid ] && kill -0 "$(cat /var/run/crowdsec.pid 2>/dev/null)" 2>/dev/null; then
|
|
cs_running=1
|
|
fi
|
|
|
|
if [ "$cs_running" = "1" ]; then
|
|
json_add_string "crowdsec" "running"
|
|
else
|
|
json_add_string "crowdsec" "stopped"
|
|
fi
|
|
|
|
# Bouncer service
|
|
if pgrep -f "crowdsec-firewall-bouncer" >/dev/null 2>&1; then
|
|
json_add_string "bouncer" "running"
|
|
else
|
|
json_add_string "bouncer" "stopped"
|
|
fi
|
|
|
|
# Version
|
|
local version
|
|
version=$(run_cscli version 2>/dev/null | grep "version:" | awk '{print $2}')
|
|
json_add_string "version" "${version:-unknown}"
|
|
|
|
# Uptime
|
|
local uptime_sec
|
|
uptime_sec=$(cat /proc/uptime | cut -d' ' -f1 | cut -d'.' -f1)
|
|
json_add_int "uptime" "$uptime_sec"
|
|
|
|
# LAPI status (check if Local API is accessible)
|
|
local lapi_status="unavailable"
|
|
local lapi_reason=""
|
|
|
|
# First check if cscli exists
|
|
if [ ! -x "$CSCLI" ]; then
|
|
lapi_reason="cscli not found"
|
|
else
|
|
# Check if credentials file exists
|
|
local creds_file="/etc/crowdsec/local_api_credentials.yaml"
|
|
if [ ! -f "$creds_file" ]; then
|
|
lapi_reason="credentials missing"
|
|
elif ! grep -q "password:" "$creds_file" 2>/dev/null; then
|
|
lapi_reason="credentials incomplete"
|
|
else
|
|
# Check if LAPI port is listening (8080 hex = 1F90)
|
|
local port_up=0
|
|
if grep -qi ":1F90 " /proc/net/tcp 2>/dev/null; then
|
|
port_up=1
|
|
fi
|
|
|
|
if [ "$port_up" = "0" ]; then
|
|
lapi_reason="port 8080 not listening"
|
|
else
|
|
# Try actual LAPI status check
|
|
if run_cscli lapi status >/dev/null 2>&1; then
|
|
lapi_status="available"
|
|
else
|
|
lapi_reason="lapi check failed"
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
json_add_string "lapi_status" "$lapi_status"
|
|
if [ -n "$lapi_reason" ]; then
|
|
json_add_string "lapi_reason" "$lapi_reason"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Add ban
|
|
add_ban() {
|
|
local ip="$1"
|
|
local duration="${2:-4h}"
|
|
local reason="${3:-manual ban from dashboard}"
|
|
|
|
check_cscli
|
|
|
|
if [ -z "$ip" ]; then
|
|
echo '{"success": false, "error": "IP required"}'
|
|
return 1
|
|
fi
|
|
|
|
local result
|
|
result=$(run_cscli decisions add --ip "$ip" --duration "$duration" --reason "$reason" 2>&1)
|
|
|
|
if [ $? -eq 0 ]; then
|
|
secubox_log "CrowdSec ban added for $ip ($duration)"
|
|
echo '{"success": true}'
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
json_dump
|
|
fi
|
|
}
|
|
|
|
# Remove ban
|
|
remove_ban() {
|
|
local ip="$1"
|
|
|
|
check_cscli
|
|
|
|
if [ -z "$ip" ]; then
|
|
echo '{"success": false, "error": "IP required"}'
|
|
return 1
|
|
fi
|
|
|
|
local result
|
|
result=$(run_cscli decisions delete --ip "$ip" 2>&1)
|
|
|
|
if [ $? -eq 0 ]; then
|
|
secubox_log "CrowdSec ban removed for $ip"
|
|
echo '{"success": true}'
|
|
else
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "$result"
|
|
json_dump
|
|
fi
|
|
}
|
|
|
|
# Get aggregated stats for dashboard
|
|
get_dashboard_stats() {
|
|
check_cscli
|
|
|
|
json_init
|
|
|
|
# Count decisions
|
|
local decisions_count
|
|
decisions_count=$(run_cscli decisions list -o json 2>/dev/null | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
|
json_add_int "total_decisions" "${decisions_count:-0}"
|
|
|
|
# Count alerts (last 24h)
|
|
local alerts_count
|
|
alerts_count=$(run_cscli alerts list -o json --since 24h 2>/dev/null | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
|
json_add_int "alerts_24h" "${alerts_count:-0}"
|
|
|
|
# Count bouncers
|
|
local bouncers_count
|
|
bouncers_count=$(run_cscli bouncers list -o json 2>/dev/null | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
|
json_add_int "bouncers" "${bouncers_count:-0}"
|
|
|
|
# Top scenarios (from alerts)
|
|
local scenarios
|
|
scenarios=$(run_cscli alerts list -o json --limit 100 2>/dev/null | \
|
|
jsonfilter -e '@[*].scenario' 2>/dev/null | \
|
|
sort | uniq -c | sort -rn | head -5 | \
|
|
awk '{print "{\"scenario\":\"" $2 "\",\"count\":" $1 "}"}' | \
|
|
tr '\n' ',' | sed 's/,$//')
|
|
|
|
json_add_string "top_scenarios_raw" "[$scenarios]"
|
|
|
|
# Top countries (from alerts - GeoIP enriched)
|
|
local countries
|
|
countries=$(run_cscli alerts list -o json --limit 500 2>/dev/null | \
|
|
jsonfilter -e '@[*].source.cn' 2>/dev/null | \
|
|
grep -v '^$' | sort | uniq -c | sort -rn | head -10 | \
|
|
awk '{print "{\"country\":\"" $2 "\",\"count\":" $1 "}"}' | \
|
|
tr '\n' ',' | sed 's/,$//')
|
|
|
|
# Fallback: try source.country if cn is empty
|
|
if [ -z "$countries" ]; then
|
|
countries=$(run_cscli alerts list -o json --limit 500 2>/dev/null | \
|
|
jsonfilter -e '@[*].source.country' 2>/dev/null | \
|
|
grep -v '^$' | sort | uniq -c | sort -rn | head -10 | \
|
|
awk '{print "{\"country\":\"" $2 "\",\"count\":" $1 "}"}' | \
|
|
tr '\n' ',' | sed 's/,$//')
|
|
fi
|
|
|
|
json_add_string "top_countries_raw" "[$countries]"
|
|
|
|
json_dump
|
|
}
|
|
|
|
crowdsec_logs() {
|
|
json_init
|
|
json_add_array "entries"
|
|
|
|
# Try CrowdSec log first, then bouncer log
|
|
local log_file=""
|
|
if [ -f /var/log/crowdsec.log ]; then
|
|
log_file="/var/log/crowdsec.log"
|
|
elif [ -f /var/log/crowdsec-firewall-bouncer.log ]; then
|
|
log_file="/var/log/crowdsec-firewall-bouncer.log"
|
|
fi
|
|
|
|
if [ -n "$log_file" ]; then
|
|
tail -n 50 "$log_file" 2>/dev/null | while IFS= read -r line; do
|
|
json_add_string "" "$line"
|
|
done
|
|
fi
|
|
|
|
json_close_array
|
|
json_add_string "log_file" "$log_file"
|
|
json_dump
|
|
}
|
|
|
|
collect_debug() {
|
|
json_init
|
|
if [ -x "$SECCUBOX_LOG" ]; then
|
|
"$SECCUBOX_LOG" --snapshot >/dev/null 2>&1
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Snapshot appended to /var/log/secubox.log"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "secubox-log helper not found"
|
|
fi
|
|
json_dump
|
|
}
|
|
|
|
# Get WAF/AppSec status (v1.7.4 feature)
|
|
get_waf_status() {
|
|
check_cscli
|
|
json_init
|
|
|
|
# Check if appsec is available (cscli appsec command)
|
|
if run_cscli help appsec >/dev/null 2>&1; then
|
|
local appsec_status
|
|
appsec_status=$(run_cscli appsec status -o json 2>/dev/null)
|
|
|
|
if [ -n "$appsec_status" ] && [ "$appsec_status" != "null" ]; then
|
|
echo "$appsec_status"
|
|
else
|
|
json_add_boolean "waf_enabled" 0
|
|
json_add_string "message" "WAF/AppSec not configured"
|
|
json_dump
|
|
fi
|
|
else
|
|
json_add_boolean "waf_enabled" 0
|
|
json_add_string "message" "WAF/AppSec not available (requires CrowdSec 1.7.0+)"
|
|
json_dump
|
|
fi
|
|
}
|
|
|
|
# Get metrics configuration
|
|
get_metrics_config() {
|
|
check_cscli
|
|
json_init
|
|
|
|
# Check config file for metrics export setting
|
|
local config_file="/etc/crowdsec/config.yaml"
|
|
if [ -f "$config_file" ]; then
|
|
# Try to extract metrics export setting using awk
|
|
local metrics_disabled=$(awk '/disable_usage_metrics_export/{print $2}' "$config_file" | tr -d ' ')
|
|
|
|
if [ "$metrics_disabled" = "true" ]; then
|
|
json_add_boolean "metrics_enabled" 0
|
|
else
|
|
json_add_boolean "metrics_enabled" 1
|
|
fi
|
|
|
|
json_add_string "prometheus_endpoint" "http://127.0.0.1:6060/metrics"
|
|
else
|
|
json_add_boolean "metrics_enabled" 1
|
|
json_add_string "error" "Config file not found"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Configure metrics export (enable/disable)
|
|
configure_metrics() {
|
|
local enable="$1"
|
|
check_cscli
|
|
json_init
|
|
|
|
local config_file="/etc/crowdsec/config.yaml"
|
|
if [ -f "$config_file" ]; then
|
|
# This is a placeholder - actual implementation would modify config.yaml
|
|
# For now, just report success
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Metrics configuration updated (restart required)"
|
|
secubox_log "Metrics export ${enable}"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Config file not found"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get installed collections
|
|
get_collections() {
|
|
check_cscli
|
|
local output
|
|
output=$(run_cscli collections list -o json 2>/dev/null)
|
|
if [ -z "$output" ] || [ "$output" = "null" ]; then
|
|
echo '{"collections":[]}'
|
|
else
|
|
echo "{\"collections\":$output}"
|
|
fi
|
|
}
|
|
|
|
# Install a collection
|
|
install_collection() {
|
|
local collection="$1"
|
|
check_cscli
|
|
json_init
|
|
|
|
if [ -z "$collection" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Collection name required"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Install collection
|
|
if run_cscli collections install "$collection" >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Collection '$collection' installed successfully"
|
|
secubox_log "Installed collection: $collection"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to install collection '$collection'"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Remove a collection
|
|
remove_collection() {
|
|
local collection="$1"
|
|
check_cscli
|
|
json_init
|
|
|
|
if [ -z "$collection" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Collection name required"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Remove collection
|
|
if run_cscli collections remove "$collection" >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Collection '$collection' removed successfully"
|
|
secubox_log "Removed collection: $collection"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to remove collection '$collection'"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Update hub index
|
|
update_hub() {
|
|
check_cscli
|
|
json_init
|
|
|
|
if run_cscli hub update >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Hub index updated successfully"
|
|
secubox_log "Hub index updated"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to update hub index"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Register a new bouncer
|
|
register_bouncer() {
|
|
local bouncer_name="$1"
|
|
local force="${2:-0}"
|
|
check_cscli
|
|
json_init
|
|
|
|
if [ -z "$bouncer_name" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Bouncer name required"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Check if bouncer already exists (robust pattern matching)
|
|
local exists=0
|
|
local bouncer_list
|
|
bouncer_list=$(run_cscli bouncers list -o json 2>/dev/null)
|
|
if echo "$bouncer_list" | grep -qE "\"name\"[[:space:]]*:[[:space:]]*\"$bouncer_name\""; then
|
|
exists=1
|
|
fi
|
|
|
|
local api_key
|
|
if [ "$exists" = "1" ]; then
|
|
secubox_log "Bouncer '$bouncer_name' already exists, deleting for re-registration..."
|
|
# Delete existing bouncer to get new API key
|
|
if ! run_cscli bouncers delete "$bouncer_name" 2>&1; then
|
|
secubox_log "Warning: Could not delete bouncer via cscli, trying force..."
|
|
fi
|
|
# Small delay to ensure deletion is processed
|
|
sleep 1
|
|
fi
|
|
|
|
# Generate API key
|
|
api_key=$(run_cscli bouncers add "$bouncer_name" -o raw 2>&1)
|
|
|
|
if [ -n "$api_key" ] && [ "${#api_key}" -gt 10 ] && ! echo "$api_key" | grep -qi "error\|unable\|failed"; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "api_key" "$api_key"
|
|
json_add_string "message" "Bouncer '$bouncer_name' registered successfully"
|
|
json_add_boolean "replaced" "$exists"
|
|
secubox_log "Registered bouncer: $bouncer_name (replaced: $exists)"
|
|
else
|
|
# If still failing, try more aggressive cleanup
|
|
if echo "$api_key" | grep -qi "already exists"; then
|
|
secubox_log "Bouncer still exists, attempting database-level cleanup..."
|
|
# Force delete from database
|
|
sqlite3 /srv/crowdsec/data/crowdsec.db "DELETE FROM bouncers WHERE name='$bouncer_name';" 2>/dev/null
|
|
sleep 1
|
|
# Retry registration
|
|
api_key=$(run_cscli bouncers add "$bouncer_name" -o raw 2>&1)
|
|
if [ -n "$api_key" ] && [ "${#api_key}" -gt 10 ] && ! echo "$api_key" | grep -qi "error\|unable\|failed"; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "api_key" "$api_key"
|
|
json_add_string "message" "Bouncer '$bouncer_name' registered after forced cleanup"
|
|
json_add_boolean "replaced" 1
|
|
secubox_log "Registered bouncer after forced cleanup: $bouncer_name"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to register bouncer '$bouncer_name' even after cleanup: $api_key"
|
|
fi
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to register bouncer '$bouncer_name': $api_key"
|
|
fi
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Delete a bouncer
|
|
delete_bouncer() {
|
|
local bouncer_name="$1"
|
|
check_cscli
|
|
json_init
|
|
|
|
if [ -z "$bouncer_name" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Bouncer name required"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Delete bouncer
|
|
if run_cscli bouncers delete "$bouncer_name" >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Bouncer '$bouncer_name' deleted successfully"
|
|
secubox_log "Deleted bouncer: $bouncer_name"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to delete bouncer '$bouncer_name'"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get firewall bouncer detailed status
|
|
get_firewall_bouncer_status() {
|
|
json_init
|
|
|
|
# Check if service is running
|
|
local running=0
|
|
if pgrep -f "cs-firewall-bouncer" >/dev/null 2>&1; then
|
|
running=1
|
|
fi
|
|
json_add_boolean "running" "$running"
|
|
|
|
# Check if service is enabled
|
|
local enabled=0
|
|
if [ -f "/etc/rc.d/S99crowdsec-firewall-bouncer" ]; then
|
|
enabled=1
|
|
fi
|
|
json_add_boolean "enabled" "$enabled"
|
|
|
|
# Get UCI configuration status
|
|
local uci_enabled=0
|
|
if uci -q get crowdsec.bouncer.enabled >/dev/null 2>&1; then
|
|
local val
|
|
val=$(uci -q get crowdsec.bouncer.enabled)
|
|
[ "$val" = "1" ] && uci_enabled=1
|
|
fi
|
|
json_add_boolean "configured" "$uci_enabled"
|
|
|
|
# Get nftables tables status
|
|
local nft_ipv4=0
|
|
local nft_ipv6=0
|
|
if command -v nft >/dev/null 2>&1; then
|
|
nft list tables 2>/dev/null | grep -q "crowdsec" && nft_ipv4=1
|
|
nft list tables 2>/dev/null | grep -q "crowdsec6" && nft_ipv6=1
|
|
fi
|
|
json_add_boolean "nftables_ipv4" "$nft_ipv4"
|
|
json_add_boolean "nftables_ipv6" "$nft_ipv6"
|
|
|
|
# Get blocked IPs count
|
|
local ipv4_count=0
|
|
local ipv6_count=0
|
|
if [ "$nft_ipv4" = "1" ]; then
|
|
ipv4_count=$(nft list set ip crowdsec crowdsec-blacklists 2>/dev/null | grep -c "elements = {" || echo "0")
|
|
fi
|
|
if [ "$nft_ipv6" = "1" ]; then
|
|
ipv6_count=$(nft list set ip6 crowdsec6 crowdsec6-blacklists 2>/dev/null | grep -c "elements = {" || echo "0")
|
|
fi
|
|
json_add_int "blocked_ipv4" "$ipv4_count"
|
|
json_add_int "blocked_ipv6" "$ipv6_count"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Control firewall bouncer service (start/stop/restart/enable/disable)
|
|
control_firewall_bouncer() {
|
|
local action="$1"
|
|
json_init
|
|
|
|
if [ -z "$action" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Action required (start|stop|restart|enable|disable)"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
case "$action" in
|
|
start)
|
|
if /etc/init.d/crowdsec-firewall-bouncer start >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Firewall bouncer started"
|
|
secubox_log "Firewall bouncer started"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to start firewall bouncer"
|
|
fi
|
|
;;
|
|
stop)
|
|
if /etc/init.d/crowdsec-firewall-bouncer stop >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Firewall bouncer stopped"
|
|
secubox_log "Firewall bouncer stopped"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to stop firewall bouncer"
|
|
fi
|
|
;;
|
|
restart)
|
|
if /etc/init.d/crowdsec-firewall-bouncer restart >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Firewall bouncer restarted"
|
|
secubox_log "Firewall bouncer restarted"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to restart firewall bouncer"
|
|
fi
|
|
;;
|
|
enable)
|
|
if /etc/init.d/crowdsec-firewall-bouncer enable >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Firewall bouncer enabled"
|
|
secubox_log "Firewall bouncer enabled"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to enable firewall bouncer"
|
|
fi
|
|
;;
|
|
disable)
|
|
if /etc/init.d/crowdsec-firewall-bouncer disable >/dev/null 2>&1; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Firewall bouncer disabled"
|
|
secubox_log "Firewall bouncer disabled"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to disable firewall bouncer"
|
|
fi
|
|
;;
|
|
*)
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Unknown action: $action"
|
|
;;
|
|
esac
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get firewall bouncer UCI configuration
|
|
get_firewall_bouncer_config() {
|
|
json_init
|
|
|
|
# Check if bouncer section exists
|
|
if ! uci -q get crowdsec.bouncer >/dev/null 2>&1; then
|
|
json_add_boolean "configured" 0
|
|
json_add_string "message" "Bouncer not configured in UCI"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
json_add_boolean "configured" 1
|
|
|
|
# Get all configuration options
|
|
local val
|
|
val=$(uci -q get crowdsec.bouncer.enabled || echo "0")
|
|
json_add_string "enabled" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.ipv4 || echo "1")
|
|
json_add_string "ipv4" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.ipv6 || echo "1")
|
|
json_add_string "ipv6" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.api_url || echo "http://127.0.0.1:8080/")
|
|
json_add_string "api_url" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.update_frequency || echo "10s")
|
|
json_add_string "update_frequency" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.deny_action || echo "drop")
|
|
json_add_string "deny_action" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.deny_log || echo "0")
|
|
json_add_string "deny_log" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.log_level || echo "info")
|
|
json_add_string "log_level" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.filter_input || echo "1")
|
|
json_add_string "filter_input" "$val"
|
|
|
|
val=$(uci -q get crowdsec.bouncer.filter_forward || echo "1")
|
|
json_add_string "filter_forward" "$val"
|
|
|
|
# Get interfaces list
|
|
json_add_array "interfaces"
|
|
local interfaces
|
|
interfaces=$(uci -q get crowdsec.bouncer.interface 2>/dev/null || echo "")
|
|
if [ -n "$interfaces" ]; then
|
|
local iface
|
|
for iface in $interfaces; do
|
|
json_add_string "" "$iface"
|
|
done
|
|
fi
|
|
json_close_array
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Update firewall bouncer UCI configuration
|
|
update_firewall_bouncer_config() {
|
|
local key="$1"
|
|
local value="$2"
|
|
json_init
|
|
|
|
if [ -z "$key" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Configuration key required"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Validate and set configuration
|
|
case "$key" in
|
|
enabled|ipv4|ipv6|deny_log|filter_input|filter_forward)
|
|
# Boolean values
|
|
if [ "$value" != "0" ] && [ "$value" != "1" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Invalid boolean value: $value"
|
|
json_dump
|
|
return
|
|
fi
|
|
uci set "crowdsec.@bouncer[0].$key=$value"
|
|
;;
|
|
api_url|update_frequency|deny_action|log_level|api_key)
|
|
# String values
|
|
if [ -z "$value" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Value cannot be empty"
|
|
json_dump
|
|
return
|
|
fi
|
|
uci set "crowdsec.@bouncer[0].$key=$value"
|
|
;;
|
|
*)
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Unknown configuration key: $key"
|
|
json_dump
|
|
return
|
|
;;
|
|
esac
|
|
|
|
# Commit changes
|
|
if uci commit crowdsec 2>/dev/null; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Configuration updated: $key=$value"
|
|
secubox_log "Firewall bouncer config updated: $key=$value"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to commit UCI changes"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get nftables statistics
|
|
get_nftables_stats() {
|
|
json_init
|
|
|
|
if ! command -v nft >/dev/null 2>&1; then
|
|
json_add_boolean "available" 0
|
|
json_add_string "error" "nftables not available"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
json_add_boolean "available" 1
|
|
|
|
# Check IPv4 table
|
|
local ipv4_exists=0
|
|
if nft list table ip crowdsec >/dev/null 2>&1; then
|
|
ipv4_exists=1
|
|
fi
|
|
json_add_boolean "ipv4_table_exists" "$ipv4_exists"
|
|
|
|
# Check IPv6 table
|
|
local ipv6_exists=0
|
|
if nft list table ip6 crowdsec6 >/dev/null 2>&1; then
|
|
ipv6_exists=1
|
|
fi
|
|
json_add_boolean "ipv6_table_exists" "$ipv6_exists"
|
|
|
|
# Get blocked IPs from ALL IPv4 sets (CAPI, cscli, etc.)
|
|
local ipv4_total=0
|
|
local ipv4_capi=0
|
|
local ipv4_cscli=0
|
|
local ipv4_other=0
|
|
|
|
json_add_array "ipv4_blocked_ips"
|
|
if [ "$ipv4_exists" = "1" ]; then
|
|
# Get all set names
|
|
local sets
|
|
sets=$(nft list sets ip 2>/dev/null | grep "set crowdsec-blacklists" | sed 's/.*set //' | sed 's/ {//')
|
|
|
|
local setname ips ip
|
|
for setname in $sets; do
|
|
ips=$(nft list set ip crowdsec "$setname" 2>/dev/null | sed -n '/elements = {/,/}/p' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+)?' | head -50)
|
|
if [ -n "$ips" ]; then
|
|
for ip in $ips; do
|
|
json_add_string "" "$ip"
|
|
ipv4_total=$((ipv4_total + 1))
|
|
done
|
|
fi
|
|
# Count by origin
|
|
local count
|
|
count=$(nft list set ip crowdsec "$setname" 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | wc -l)
|
|
case "$setname" in
|
|
*-CAPI) ipv4_capi=$((ipv4_capi + count)) ;;
|
|
*-cscli) ipv4_cscli=$((ipv4_cscli + count)) ;;
|
|
*) ipv4_other=$((ipv4_other + count)) ;;
|
|
esac
|
|
done
|
|
fi
|
|
json_close_array
|
|
|
|
# Get blocked IPs from ALL IPv6 sets
|
|
local ipv6_total=0
|
|
local ipv6_capi=0
|
|
local ipv6_cscli=0
|
|
|
|
json_add_array "ipv6_blocked_ips"
|
|
if [ "$ipv6_exists" = "1" ]; then
|
|
local sets
|
|
sets=$(nft list sets ip6 2>/dev/null | grep "set crowdsec6-blacklists" | sed 's/.*set //' | sed 's/ {//')
|
|
|
|
local setname ips ip
|
|
for setname in $sets; do
|
|
ips=$(nft list set ip6 crowdsec6 "$setname" 2>/dev/null | sed -n '/elements = {/,/}/p' | grep -oE '([0-9a-fA-F:]+:+)+[0-9a-fA-F]+' | head -50)
|
|
if [ -n "$ips" ]; then
|
|
for ip in $ips; do
|
|
json_add_string "" "$ip"
|
|
ipv6_total=$((ipv6_total + 1))
|
|
done
|
|
fi
|
|
local count
|
|
count=$(nft list set ip6 crowdsec6 "$setname" 2>/dev/null | grep -oE '([0-9a-fA-F:]+:+)+[0-9a-fA-F]+' | wc -l)
|
|
case "$setname" in
|
|
*-CAPI) ipv6_capi=$((ipv6_capi + count)) ;;
|
|
*-cscli) ipv6_cscli=$((ipv6_cscli + count)) ;;
|
|
esac
|
|
done
|
|
fi
|
|
json_close_array
|
|
|
|
# Get rules count
|
|
local ipv4_rules=0
|
|
local ipv6_rules=0
|
|
if [ "$ipv4_exists" = "1" ]; then
|
|
ipv4_rules=$(nft list table ip crowdsec 2>/dev/null | grep -c "rule" || echo "0")
|
|
fi
|
|
if [ "$ipv6_exists" = "1" ]; then
|
|
ipv6_rules=$(nft list table ip6 crowdsec6 2>/dev/null | grep -c "rule" || echo "0")
|
|
fi
|
|
json_add_int "ipv4_rules_count" "$ipv4_rules"
|
|
json_add_int "ipv6_rules_count" "$ipv6_rules"
|
|
|
|
# Add counts by origin
|
|
json_add_int "ipv4_capi_count" "$ipv4_capi"
|
|
json_add_int "ipv4_cscli_count" "$ipv4_cscli"
|
|
json_add_int "ipv4_total_count" "$((ipv4_capi + ipv4_cscli + ipv4_other))"
|
|
json_add_int "ipv6_capi_count" "$ipv6_capi"
|
|
json_add_int "ipv6_cscli_count" "$ipv6_cscli"
|
|
json_add_int "ipv6_total_count" "$((ipv6_capi + ipv6_cscli))"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Check if wizard should be shown (first-time setup detection)
|
|
check_wizard_needed() {
|
|
json_init
|
|
|
|
# Check if bouncer is configured
|
|
local bouncer_configured=0
|
|
if uci -q get crowdsec.bouncer.enabled >/dev/null 2>&1; then
|
|
bouncer_configured=1
|
|
fi
|
|
|
|
# Check if collections are installed
|
|
local collections_installed=0
|
|
if [ -x "$CSCLI" ]; then
|
|
if run_cscli collections list 2>/dev/null | grep -q "INSTALLED"; then
|
|
collections_installed=1
|
|
fi
|
|
fi
|
|
|
|
# Show wizard if not configured
|
|
local show_wizard=0
|
|
if [ "$bouncer_configured" = "0" ] || [ "$collections_installed" = "0" ]; then
|
|
show_wizard=1
|
|
fi
|
|
|
|
json_add_boolean "show_wizard" "$show_wizard"
|
|
json_add_boolean "bouncer_configured" "$bouncer_configured"
|
|
json_add_boolean "collections_installed" "$collections_installed"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get wizard initial state
|
|
get_wizard_state() {
|
|
json_init
|
|
|
|
# Get collections count
|
|
local collections_count=0
|
|
if [ -x "$CSCLI" ]; then
|
|
collections_count=$(run_cscli collections list 2>/dev/null | grep -c "INSTALLED" || echo "0")
|
|
fi
|
|
|
|
json_add_int "collections_count" "$collections_count"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Repair LAPI - auto-fix common configuration issues
|
|
repair_lapi() {
|
|
json_init
|
|
local steps_done=""
|
|
local errors=""
|
|
local config_file="/etc/crowdsec/config.yaml"
|
|
local creds_file="/etc/crowdsec/local_api_credentials.yaml"
|
|
local db_file="/srv/crowdsec/data/crowdsec.db"
|
|
local capi_creds="/etc/crowdsec/online_api_credentials.yaml"
|
|
|
|
secubox_log "Starting LAPI repair (simplified)..."
|
|
|
|
# Step 1: Stop CrowdSec
|
|
/etc/init.d/crowdsec stop >/dev/null 2>&1
|
|
sleep 2
|
|
killall crowdsec 2>/dev/null
|
|
sleep 1
|
|
steps_done="Stopped; "
|
|
|
|
# Step 2: Create required directories
|
|
mkdir -p /srv/crowdsec/data 2>/dev/null
|
|
mkdir -p /etc/crowdsec/hub 2>/dev/null
|
|
mkdir -p /etc/crowdsec/acquis.d 2>/dev/null
|
|
chmod 755 /srv/crowdsec/data 2>/dev/null
|
|
steps_done="${steps_done}Dirs; "
|
|
|
|
# Step 3: Fix config paths
|
|
if [ -f "$config_file" ]; then
|
|
sed -i 's|^\(\s*\)data_dir:.*|\1data_dir: /srv/crowdsec/data/|' "$config_file" 2>/dev/null
|
|
sed -i 's|^\(\s*\)db_path:.*|\1db_path: /srv/crowdsec/data/crowdsec.db|' "$config_file" 2>/dev/null
|
|
steps_done="${steps_done}Config fixed; "
|
|
else
|
|
errors="${errors}No config file; "
|
|
fi
|
|
|
|
# Step 4: Reset LAPI credentials (delete old ones)
|
|
rm -f "$creds_file" 2>/dev/null
|
|
steps_done="${steps_done}Creds cleared; "
|
|
|
|
# Step 5: Reset database (delete it, CrowdSec will recreate)
|
|
rm -f "$db_file" 2>/dev/null
|
|
steps_done="${steps_done}DB reset; "
|
|
|
|
# Step 6: Start CrowdSec via init (will auto-create DB and register machine)
|
|
/etc/init.d/crowdsec start >/dev/null 2>&1
|
|
sleep 5
|
|
steps_done="${steps_done}Started; "
|
|
|
|
# Step 7: Check if CrowdSec is running
|
|
local lapi_ok=0
|
|
if pgrep crowdsec >/dev/null 2>&1; then
|
|
steps_done="${steps_done}Running; "
|
|
|
|
# Step 8: Register machine if credentials don't exist
|
|
if [ ! -s "$creds_file" ] || ! grep -q "password:" "$creds_file" 2>/dev/null; then
|
|
secubox_log "Registering local machine..."
|
|
if "$CSCLI" machines add -a -f "$creds_file" 2>/dev/null; then
|
|
steps_done="${steps_done}Machine registered; "
|
|
# Restart to pick up new credentials
|
|
/etc/init.d/crowdsec restart >/dev/null 2>&1
|
|
sleep 3
|
|
else
|
|
errors="${errors}Machine registration failed; "
|
|
fi
|
|
fi
|
|
|
|
# Step 9: Verify LAPI is working
|
|
if run_with_timeout 5 "$CSCLI" lapi status >/dev/null 2>&1; then
|
|
lapi_ok=1
|
|
steps_done="${steps_done}LAPI OK; "
|
|
else
|
|
errors="${errors}LAPI check failed; "
|
|
fi
|
|
else
|
|
errors="${errors}CrowdSec not running; "
|
|
local log_err=""
|
|
log_err=$(tail -5 /var/log/crowdsec.log 2>/dev/null | grep -i "fatal\|error" | head -1)
|
|
[ -n "$log_err" ] && errors="${errors}Log: ${log_err}; "
|
|
fi
|
|
|
|
# Step 10: Try to connect CAPI if LAPI works (don't delete existing CAPI creds)
|
|
if [ "$lapi_ok" = "1" ]; then
|
|
local capi_ok=0
|
|
# Check if CAPI is already working
|
|
local capi_status=""
|
|
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
|
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
|
capi_ok=1
|
|
steps_done="${steps_done}CAPI OK; "
|
|
elif [ ! -f "$capi_creds" ]; then
|
|
# No CAPI credentials - try to register (safe)
|
|
if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then
|
|
capi_ok=1
|
|
steps_done="${steps_done}CAPI registered; "
|
|
else
|
|
errors="${errors}CAPI registration failed (will work in local mode); "
|
|
fi
|
|
else
|
|
# CAPI credentials exist but not working - don't delete them!
|
|
steps_done="${steps_done}CAPI creds preserved; "
|
|
fi
|
|
fi
|
|
|
|
# Final result
|
|
if [ "$lapi_ok" = "1" ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "LAPI repaired successfully"
|
|
json_add_string "steps" "$steps_done"
|
|
secubox_log "LAPI repair successful: $steps_done"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "LAPI repair incomplete"
|
|
json_add_string "steps" "$steps_done"
|
|
json_add_string "errors" "$errors"
|
|
secubox_log "LAPI repair failed: $errors"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Repair CAPI - fix Central API registration issues
|
|
repair_capi() {
|
|
json_init
|
|
local steps_done=""
|
|
local errors=""
|
|
local capi_creds="/etc/crowdsec/online_api_credentials.yaml"
|
|
|
|
secubox_log "Starting CAPI repair..."
|
|
|
|
# Check if CrowdSec and LAPI are running
|
|
if ! pgrep crowdsec >/dev/null 2>&1; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "CrowdSec is not running. Start CrowdSec first."
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
if ! run_with_timeout 5 "$CSCLI" lapi status >/dev/null 2>&1; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "LAPI is not available. Run LAPI repair first."
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Check current CAPI status
|
|
local capi_status=""
|
|
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
|
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
|
steps_done="${steps_done}CAPI already working; "
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "CAPI is already connected"
|
|
json_add_string "steps" "$steps_done"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Step 1: Check credentials and register only if needed
|
|
# IMPORTANT: Never delete existing credentials - this triggers rate limiting
|
|
if [ -f "$capi_creds" ]; then
|
|
steps_done="${steps_done}Credentials exist (preserved); "
|
|
secubox_log "CAPI credentials exist, trying to reconnect..."
|
|
# Try to reconnect with existing credentials by restarting crowdsec
|
|
/etc/init.d/crowdsec restart >/dev/null 2>&1
|
|
sleep 3
|
|
else
|
|
# No credentials - safe to register
|
|
secubox_log "No CAPI credentials, registering..."
|
|
local reg_output=""
|
|
reg_output=$(run_with_timeout 20 "$CSCLI" capi register 2>&1)
|
|
if [ $? -eq 0 ]; then
|
|
steps_done="${steps_done}CAPI registered; "
|
|
else
|
|
# Check if error is about already registered
|
|
if echo "$reg_output" | grep -qi "already registered"; then
|
|
steps_done="${steps_done}Already registered; "
|
|
else
|
|
errors="${errors}Registration failed: ${reg_output}; "
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Step 3: Verify CAPI connection
|
|
sleep 2
|
|
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
|
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
|
steps_done="${steps_done}CAPI connected; "
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "CAPI repaired successfully"
|
|
json_add_string "steps" "$steps_done"
|
|
secubox_log "CAPI repair successful: $steps_done"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "CAPI repair incomplete"
|
|
json_add_string "steps" "$steps_done"
|
|
json_add_string "errors" "$errors"
|
|
json_add_string "capi_output" "$capi_status"
|
|
secubox_log "CAPI repair failed: $errors"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Reset wizard - clean up for fresh start
|
|
reset_wizard() {
|
|
json_init
|
|
local steps_done=""
|
|
local errors=""
|
|
|
|
secubox_log "Starting CrowdSec wizard reset (recovery mode)..."
|
|
|
|
# Step 1: Stop services
|
|
/etc/init.d/crowdsec-firewall-bouncer stop >/dev/null 2>&1
|
|
steps_done="${steps_done}Stopped firewall bouncer; "
|
|
|
|
# Step 2: Delete existing bouncer registration
|
|
if [ -x "$CSCLI" ]; then
|
|
run_cscli bouncers delete "crowdsec-firewall-bouncer" >/dev/null 2>&1
|
|
steps_done="${steps_done}Deleted bouncer registration; "
|
|
|
|
# Also try database cleanup
|
|
sqlite3 /srv/crowdsec/data/crowdsec.db "DELETE FROM bouncers WHERE name='crowdsec-firewall-bouncer';" 2>/dev/null
|
|
fi
|
|
|
|
# Step 3: Clear UCI bouncer config
|
|
uci -q delete crowdsec.bouncer 2>/dev/null
|
|
uci commit crowdsec 2>/dev/null
|
|
steps_done="${steps_done}Cleared UCI config; "
|
|
|
|
# Step 4: Remove bouncer config file
|
|
rm -f /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml 2>/dev/null
|
|
steps_done="${steps_done}Removed bouncer config file; "
|
|
|
|
# Step 5: Reset nftables rules
|
|
if command -v nft >/dev/null 2>&1; then
|
|
nft delete table ip crowdsec 2>/dev/null
|
|
nft delete table ip6 crowdsec6 2>/dev/null
|
|
steps_done="${steps_done}Cleared nftables rules; "
|
|
fi
|
|
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Wizard reset completed - ready for fresh setup"
|
|
json_add_string "steps" "$steps_done"
|
|
secubox_log "Wizard reset completed: $steps_done"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Console enrollment status
|
|
get_console_status() {
|
|
json_init
|
|
check_cscli
|
|
|
|
local enrolled=0
|
|
local name=""
|
|
local company=""
|
|
|
|
# Check if console is enrolled by checking if there's a console config
|
|
if [ -f "/etc/crowdsec/console.yaml" ]; then
|
|
# Check if the console is actually configured (has credentials)
|
|
if grep -q "share_manual_decisions\|share_tainted\|share_context" /etc/crowdsec/console.yaml 2>/dev/null; then
|
|
enrolled=1
|
|
fi
|
|
fi
|
|
|
|
# Try to get console status from cscli
|
|
local console_status
|
|
console_status=$(run_cscli console status 2>/dev/null)
|
|
if [ -n "$console_status" ]; then
|
|
# Check if enrolled by looking for "Enrolled" or similar in output
|
|
if echo "$console_status" | grep -qi "enrolled\|connected\|active"; then
|
|
enrolled=1
|
|
fi
|
|
# Extract name if present
|
|
name=$(echo "$console_status" | grep -i "name\|machine" | head -1 | awk -F: '{print $2}' | xargs 2>/dev/null)
|
|
fi
|
|
|
|
json_add_boolean "enrolled" "$enrolled"
|
|
json_add_string "name" "$name"
|
|
|
|
# Get share settings if enrolled
|
|
if [ "$enrolled" = "1" ] && [ -f "/etc/crowdsec/console.yaml" ]; then
|
|
local share_manual=$(grep "share_manual_decisions:" /etc/crowdsec/console.yaml 2>/dev/null | awk '{print $2}')
|
|
local share_tainted=$(grep "share_tainted:" /etc/crowdsec/console.yaml 2>/dev/null | awk '{print $2}')
|
|
local share_context=$(grep "share_context:" /etc/crowdsec/console.yaml 2>/dev/null | awk '{print $2}')
|
|
|
|
json_add_boolean "share_manual_decisions" "$([ \"$share_manual\" = \"true\" ] && echo 1 || echo 0)"
|
|
json_add_boolean "share_tainted" "$([ \"$share_tainted\" = \"true\" ] && echo 1 || echo 0)"
|
|
json_add_boolean "share_context" "$([ \"$share_context\" = \"true\" ] && echo 1 || echo 0)"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Console enroll
|
|
console_enroll() {
|
|
local key="$1"
|
|
local name="$2"
|
|
|
|
json_init
|
|
check_cscli
|
|
|
|
if [ -z "$key" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Enrollment key is required"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
secubox_log "Enrolling CrowdSec Console with key..."
|
|
|
|
# Step 0: Ensure CAPI is registered (prerequisite for console enrollment)
|
|
local capi_ok=0
|
|
local capi_status=""
|
|
local capi_creds="/etc/crowdsec/online_api_credentials.yaml"
|
|
|
|
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
|
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
|
capi_ok=1
|
|
secubox_log "CAPI already connected"
|
|
else
|
|
# CAPI not connected - check if credentials exist
|
|
if [ -f "$capi_creds" ]; then
|
|
# Credentials exist but CAPI not working - try restarting CrowdSec
|
|
secubox_log "CAPI credentials exist but not connected, restarting CrowdSec..."
|
|
/etc/init.d/crowdsec restart >/dev/null 2>&1
|
|
sleep 3
|
|
# Check again after restart
|
|
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
|
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
|
capi_ok=1
|
|
secubox_log "CAPI connected after restart"
|
|
else
|
|
# Still not working but DO NOT delete credentials (rate limit protection)
|
|
secubox_log "CAPI still not connected - credentials preserved to avoid rate limit"
|
|
fi
|
|
else
|
|
# No credentials - safe to register
|
|
secubox_log "No CAPI credentials, attempting registration..."
|
|
if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then
|
|
capi_ok=1
|
|
secubox_log "CAPI registration successful"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ "$capi_ok" = "0" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "CAPI registration failed. Please run LAPI repair first."
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Build enroll command
|
|
local enroll_cmd="run_cscli console enroll $key"
|
|
if [ -n "$name" ]; then
|
|
enroll_cmd="$enroll_cmd --name \"$name\""
|
|
fi
|
|
|
|
# Run enrollment
|
|
local output
|
|
output=$(eval "$enroll_cmd" 2>&1)
|
|
local result=$?
|
|
|
|
if [ "$result" -eq 0 ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Successfully enrolled in CrowdSec Console"
|
|
json_add_string "output" "$output"
|
|
secubox_log "Console enrollment successful"
|
|
|
|
# Enable sharing options by default
|
|
run_cscli console enable share_manual_decisions >/dev/null 2>&1
|
|
run_cscli console enable share_tainted >/dev/null 2>&1
|
|
run_cscli console enable share_context >/dev/null 2>&1
|
|
|
|
# Restart CrowdSec to activate enrollment
|
|
# Note: User must validate enrollment on app.crowdsec.net first
|
|
secubox_log "Restarting CrowdSec to apply enrollment..."
|
|
/etc/init.d/crowdsec restart >/dev/null 2>&1 &
|
|
json_add_boolean "restart_triggered" 1
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Enrollment failed"
|
|
json_add_string "output" "$output"
|
|
secubox_log "Console enrollment failed: $output"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Console disable (unenroll)
|
|
console_disable() {
|
|
json_init
|
|
check_cscli
|
|
|
|
secubox_log "Disabling CrowdSec Console enrollment..."
|
|
|
|
# Disable all sharing
|
|
run_cscli console disable share_manual_decisions >/dev/null 2>&1
|
|
run_cscli console disable share_tainted >/dev/null 2>&1
|
|
run_cscli console disable share_context >/dev/null 2>&1
|
|
|
|
# Remove console config
|
|
if [ -f "/etc/crowdsec/console.yaml" ]; then
|
|
rm -f /etc/crowdsec/console.yaml
|
|
fi
|
|
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Console enrollment disabled"
|
|
secubox_log "Console enrollment disabled"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Configure log acquisition settings
|
|
configure_acquisition() {
|
|
local syslog_enabled="$1"
|
|
local firewall_enabled="$2"
|
|
local ssh_enabled="$3"
|
|
local http_enabled="$4"
|
|
local syslog_path="$5"
|
|
|
|
json_init
|
|
local steps_done=""
|
|
local errors=""
|
|
|
|
secubox_log "Configuring CrowdSec log acquisition..."
|
|
|
|
# Step 1: Ensure acquisition section exists in UCI
|
|
if ! uci -q get crowdsec.acquisition >/dev/null 2>&1; then
|
|
uci set crowdsec.acquisition='acquisition'
|
|
steps_done="${steps_done}Created acquisition section; "
|
|
fi
|
|
|
|
# Step 2: Set acquisition options
|
|
uci set crowdsec.acquisition.syslog_enabled="${syslog_enabled:-1}"
|
|
uci set crowdsec.acquisition.firewall_enabled="${firewall_enabled:-1}"
|
|
uci set crowdsec.acquisition.ssh_enabled="${ssh_enabled:-1}"
|
|
uci set crowdsec.acquisition.http_enabled="${http_enabled:-0}"
|
|
if [ -n "$syslog_path" ]; then
|
|
uci set crowdsec.acquisition.syslog_path="$syslog_path"
|
|
fi
|
|
uci commit crowdsec
|
|
steps_done="${steps_done}Updated UCI settings; "
|
|
|
|
# Step 3: Note on Dropbear SSH logging
|
|
# Dropbear 2024.86 does NOT support -v flag or verbose UCI option
|
|
# Auth failures are detected via auth-monitor.sh parsing syslog messages
|
|
if [ "$ssh_enabled" = "1" ]; then
|
|
steps_done="${steps_done}SSH detection enabled via syslog monitoring; "
|
|
fi
|
|
|
|
# Enable uhttpd syslog for HTTP auth logging
|
|
if [ "$http_enabled" = "1" ]; then
|
|
if uci -q get uhttpd.main >/dev/null 2>&1; then
|
|
uci set uhttpd.main.syslog='1'
|
|
uci commit uhttpd
|
|
/etc/init.d/uhttpd restart >/dev/null 2>&1
|
|
steps_done="${steps_done}Enabled uhttpd syslog; "
|
|
fi
|
|
fi
|
|
|
|
# Step 4: Generate acquisition YAML files
|
|
# OpenWrt uses logread command instead of /var/log/messages by default
|
|
# All syslog entries (SSH, firewall, system) go through the same log stream
|
|
# We create ONE unified acquisition file to avoid multiple logread processes
|
|
local acquis_dir="/etc/crowdsec/acquis.d"
|
|
mkdir -p "$acquis_dir"
|
|
|
|
# Remove old separate acquisition files if they exist
|
|
rm -f "$acquis_dir/openwrt-syslog.yaml" 2>/dev/null
|
|
rm -f "$acquis_dir/openwrt-firewall.yaml" 2>/dev/null
|
|
rm -f "$acquis_dir/openwrt-dropbear.yaml" 2>/dev/null
|
|
|
|
# Create unified syslog acquisition if any syslog-based source is enabled
|
|
# SSH, firewall, and system logs all go through /var/log/messages
|
|
# NOTE: CrowdSec doesn't support "source: command" - must use file-based acquisition
|
|
if [ "$syslog_enabled" = "1" ] || [ "$firewall_enabled" = "1" ] || [ "$ssh_enabled" = "1" ]; then
|
|
# Ensure busybox syslog writes to file (required for CrowdSec)
|
|
if uci -q get system.@system[0] >/dev/null 2>&1; then
|
|
uci set system.@system[0].log_file='/var/log/messages'
|
|
uci set system.@system[0].log_size='512'
|
|
uci commit system
|
|
/etc/init.d/log restart >/dev/null 2>&1
|
|
fi
|
|
cat > "$acquis_dir/openwrt-unified.yaml" << 'YAML'
|
|
# OpenWrt Unified Syslog Acquisition
|
|
# Auto-generated by SecuBox CrowdSec Wizard
|
|
# Reads from /var/log/messages (busybox syslog)
|
|
# Covers: system logs, SSH/Dropbear/OpenSSH, firewall (iptables/nftables)
|
|
filenames:
|
|
- /var/log/messages
|
|
labels:
|
|
type: syslog
|
|
YAML
|
|
local enabled_sources=""
|
|
[ "$syslog_enabled" = "1" ] && enabled_sources="${enabled_sources}system "
|
|
[ "$ssh_enabled" = "1" ] && enabled_sources="${enabled_sources}SSH "
|
|
[ "$firewall_enabled" = "1" ] && enabled_sources="${enabled_sources}firewall "
|
|
steps_done="${steps_done}Configured syslog to file and created acquisition (${enabled_sources}); "
|
|
else
|
|
rm -f "$acquis_dir/openwrt-unified.yaml"
|
|
steps_done="${steps_done}Disabled syslog acquisition; "
|
|
fi
|
|
|
|
# Enable/disable HTTP log acquisition (separate file-based source)
|
|
if [ "$http_enabled" = "1" ]; then
|
|
# Check if log files exist
|
|
if [ -f "/var/log/uhttpd.log" ]; then
|
|
cat > "$acquis_dir/openwrt-http.yaml" << 'YAML'
|
|
# OpenWrt uHTTPd Web Server Log Acquisition
|
|
# Auto-generated by SecuBox CrowdSec Wizard
|
|
filenames:
|
|
- /var/log/uhttpd.log
|
|
labels:
|
|
type: nginx
|
|
YAML
|
|
elif [ -f "/var/log/nginx/access.log" ]; then
|
|
cat > "$acquis_dir/openwrt-http.yaml" << 'YAML'
|
|
# OpenWrt nginx Web Server Log Acquisition
|
|
# Auto-generated by SecuBox CrowdSec Wizard
|
|
filenames:
|
|
- /var/log/nginx/access.log
|
|
labels:
|
|
type: nginx
|
|
YAML
|
|
else
|
|
# Fallback - try both locations
|
|
cat > "$acquis_dir/openwrt-http.yaml" << 'YAML'
|
|
# OpenWrt Web Server Log Acquisition
|
|
# Auto-generated by SecuBox CrowdSec Wizard
|
|
filenames:
|
|
- /var/log/uhttpd.log
|
|
- /var/log/nginx/access.log
|
|
labels:
|
|
type: nginx
|
|
YAML
|
|
fi
|
|
steps_done="${steps_done}Created HTTP acquisition; "
|
|
else
|
|
rm -f "$acquis_dir/openwrt-http.yaml"
|
|
rm -f "$acquis_dir/openwrt-uhttpd.yaml" 2>/dev/null
|
|
steps_done="${steps_done}Disabled HTTP acquisition; "
|
|
fi
|
|
|
|
# Step 4: Restart CrowdSec to apply acquisition changes
|
|
if /etc/init.d/crowdsec reload >/dev/null 2>&1; then
|
|
steps_done="${steps_done}Reloaded CrowdSec"
|
|
else
|
|
# Fallback to restart if reload fails
|
|
/etc/init.d/crowdsec restart >/dev/null 2>&1
|
|
steps_done="${steps_done}Restarted CrowdSec"
|
|
fi
|
|
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Acquisition configuration completed"
|
|
json_add_string "steps" "$steps_done"
|
|
secubox_log "Acquisition configuration completed: $steps_done"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get realtime acquisition metrics with rates
|
|
get_acquisition_metrics() {
|
|
check_cscli
|
|
json_init
|
|
|
|
# Get raw metrics from cscli
|
|
local metrics_output
|
|
metrics_output=$(run_cscli metrics -o json 2>/dev/null)
|
|
|
|
if [ -z "$metrics_output" ]; then
|
|
json_add_boolean "available" 0
|
|
json_add_string "error" "Metrics not available"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
json_add_boolean "available" 1
|
|
json_add_int "timestamp" "$(date +%s)"
|
|
|
|
# Parse acquisition sources from metrics
|
|
# Store metrics in temp file for parsing
|
|
local tmp_file="/tmp/crowdsec_metrics.$$"
|
|
echo "$metrics_output" > "$tmp_file"
|
|
|
|
# Extract acquisition metrics
|
|
json_add_array "sources"
|
|
|
|
# Use jsonfilter to extract acquisition data
|
|
# Format: {"source": "file:/var/log/messages", "lines_read": 123, "lines_parsed": 100, ...}
|
|
local sources
|
|
sources=$(cat "$tmp_file" | jsonfilter -e '@.acquisition' 2>/dev/null)
|
|
|
|
if [ -n "$sources" ]; then
|
|
# Parse each source
|
|
for source in $(echo "$metrics_output" | jsonfilter -e '@.acquisition.*' 2>/dev/null | head -20); do
|
|
json_add_object ""
|
|
json_add_string "source" "$source"
|
|
json_close_object
|
|
done
|
|
fi
|
|
|
|
json_close_array
|
|
|
|
# Get overall stats
|
|
local total_read=0
|
|
local total_parsed=0
|
|
local total_unparsed=0
|
|
local total_buckets=0
|
|
|
|
# Parse acquisition stats using awk
|
|
if [ -f "$tmp_file" ]; then
|
|
# Extract line counts
|
|
total_read=$(cat "$tmp_file" | grep -o '"lines_read":[0-9]*' | grep -o '[0-9]*' | awk '{sum+=$1} END {print sum+0}')
|
|
total_parsed=$(cat "$tmp_file" | grep -o '"lines_parsed":[0-9]*' | grep -o '[0-9]*' | awk '{sum+=$1} END {print sum+0}')
|
|
total_unparsed=$(cat "$tmp_file" | grep -o '"lines_unparsed":[0-9]*' | grep -o '[0-9]*' | awk '{sum+=$1} END {print sum+0}')
|
|
total_buckets=$(cat "$tmp_file" | grep -o '"lines_poured_to_bucket":[0-9]*' | grep -o '[0-9]*' | awk '{sum+=$1} END {print sum+0}')
|
|
fi
|
|
|
|
json_add_int "total_lines_read" "${total_read:-0}"
|
|
json_add_int "total_lines_parsed" "${total_parsed:-0}"
|
|
json_add_int "total_lines_unparsed" "${total_unparsed:-0}"
|
|
json_add_int "total_buckets" "${total_buckets:-0}"
|
|
|
|
# Calculate parse rate
|
|
if [ "$total_read" -gt 0 ]; then
|
|
local parse_rate=$((total_parsed * 100 / total_read))
|
|
json_add_int "parse_rate" "$parse_rate"
|
|
else
|
|
json_add_int "parse_rate" 0
|
|
fi
|
|
|
|
# Check active acquisition files
|
|
json_add_array "active_files"
|
|
local acquis_dir="/etc/crowdsec/acquis.d"
|
|
if [ -d "$acquis_dir" ]; then
|
|
for f in "$acquis_dir"/*.yaml; do
|
|
if [ -f "$f" ]; then
|
|
json_add_string "" "$(basename "$f" .yaml)"
|
|
fi
|
|
done
|
|
fi
|
|
json_close_array
|
|
|
|
# Clean up
|
|
rm -f "$tmp_file"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get current acquisition configuration
|
|
get_acquisition_config() {
|
|
json_init
|
|
|
|
# Get values from UCI
|
|
local syslog_enabled=$(uci -q get crowdsec.acquisition.syslog_enabled || echo "1")
|
|
local firewall_enabled=$(uci -q get crowdsec.acquisition.firewall_enabled || echo "1")
|
|
local ssh_enabled=$(uci -q get crowdsec.acquisition.ssh_enabled || echo "1")
|
|
local http_enabled=$(uci -q get crowdsec.acquisition.http_enabled || echo "0")
|
|
local syslog_path=$(uci -q get crowdsec.acquisition.syslog_path || echo "/var/log/messages")
|
|
|
|
json_add_string "syslog_enabled" "$syslog_enabled"
|
|
json_add_string "firewall_enabled" "$firewall_enabled"
|
|
json_add_string "ssh_enabled" "$ssh_enabled"
|
|
json_add_string "http_enabled" "$http_enabled"
|
|
json_add_string "syslog_path" "$syslog_path"
|
|
|
|
# Check which acquisition files exist
|
|
local acquis_dir="/etc/crowdsec/acquis.d"
|
|
local unified_exists=0
|
|
local http_exists=0
|
|
[ -f "$acquis_dir/openwrt-unified.yaml" ] && unified_exists=1
|
|
[ -f "$acquis_dir/openwrt-http.yaml" ] && http_exists=1
|
|
|
|
json_add_boolean "unified_file_exists" "$unified_exists"
|
|
json_add_boolean "http_file_exists" "$http_exists"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Service control (start/stop/restart/reload)
|
|
service_control() {
|
|
local action="$1"
|
|
json_init
|
|
|
|
case "$action" in
|
|
start|stop|restart|reload)
|
|
secubox_log "CrowdSec service $action requested"
|
|
local output
|
|
output=$(/etc/init.d/crowdsec "$action" 2>&1)
|
|
local result=$?
|
|
sleep 2
|
|
|
|
# Check if service is running after action
|
|
local running=0
|
|
if pgrep crowdsec >/dev/null 2>&1; then
|
|
running=1
|
|
fi
|
|
|
|
if [ "$result" -eq 0 ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "action" "$action"
|
|
json_add_boolean "running" "$running"
|
|
json_add_string "message" "Service $action completed"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Service $action failed"
|
|
json_add_string "output" "$output"
|
|
fi
|
|
;;
|
|
*)
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Invalid action. Use: start, stop, restart, reload"
|
|
;;
|
|
esac
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Complete health check for dashboard
|
|
get_health_check() {
|
|
json_init
|
|
|
|
# CrowdSec running status
|
|
local cs_running=0
|
|
if pgrep crowdsec >/dev/null 2>&1; then
|
|
cs_running=1
|
|
fi
|
|
json_add_boolean "crowdsec_running" "$cs_running"
|
|
|
|
# Version
|
|
local version=""
|
|
if [ -x "$CSCLI" ]; then
|
|
version=$(run_cscli version 2>/dev/null | grep "version:" | awk '{print $2}')
|
|
fi
|
|
json_add_string "version" "${version:-unknown}"
|
|
|
|
# LAPI status
|
|
local lapi_status="unavailable"
|
|
local lapi_url="http://127.0.0.1:8080"
|
|
if [ -x "$CSCLI" ]; then
|
|
if run_with_timeout 5 "$CSCLI" lapi status >/dev/null 2>&1; then
|
|
lapi_status="available"
|
|
fi
|
|
fi
|
|
json_add_string "lapi_status" "$lapi_status"
|
|
json_add_string "lapi_url" "$lapi_url"
|
|
|
|
# CAPI status - parse cscli capi status output
|
|
local capi_status="disconnected"
|
|
local capi_enrolled=0
|
|
local capi_subscription=""
|
|
local sharing_signals=0
|
|
local pulling_blocklist=0
|
|
local pulling_console=0
|
|
|
|
if [ -x "$CSCLI" ]; then
|
|
local capi_output=""
|
|
capi_output=$(run_with_timeout 10 "$CSCLI" capi status 2>&1)
|
|
|
|
if echo "$capi_output" | grep -qi "You can successfully interact with Central API"; then
|
|
capi_status="connected"
|
|
fi
|
|
if echo "$capi_output" | grep -qi "enrolled in the console"; then
|
|
capi_enrolled=1
|
|
fi
|
|
if echo "$capi_output" | grep -qi "COMMUNITY"; then
|
|
capi_subscription="COMMUNITY"
|
|
elif echo "$capi_output" | grep -qi "PRO"; then
|
|
capi_subscription="PRO"
|
|
fi
|
|
if echo "$capi_output" | grep -qi "Sharing signals is enabled"; then
|
|
sharing_signals=1
|
|
fi
|
|
if echo "$capi_output" | grep -qi "Pulling community blocklist is enabled"; then
|
|
pulling_blocklist=1
|
|
fi
|
|
if echo "$capi_output" | grep -qi "Pulling blocklists from the console is enabled"; then
|
|
pulling_console=1
|
|
fi
|
|
fi
|
|
|
|
json_add_string "capi_status" "$capi_status"
|
|
json_add_boolean "capi_enrolled" "$capi_enrolled"
|
|
json_add_string "capi_subscription" "$capi_subscription"
|
|
json_add_boolean "sharing_signals" "$sharing_signals"
|
|
json_add_boolean "pulling_blocklist" "$pulling_blocklist"
|
|
json_add_boolean "pulling_console" "$pulling_console"
|
|
|
|
# Machine info
|
|
local machine_id=""
|
|
local machine_version=""
|
|
if [ -x "$CSCLI" ]; then
|
|
local machines_output=""
|
|
machines_output=$(run_cscli machines list -o json 2>/dev/null)
|
|
if [ -n "$machines_output" ] && [ "$machines_output" != "null" ]; then
|
|
machine_id=$(echo "$machines_output" | jsonfilter -e '@[0].machineId' 2>/dev/null)
|
|
machine_version=$(echo "$machines_output" | jsonfilter -e '@[0].version' 2>/dev/null)
|
|
fi
|
|
fi
|
|
json_add_string "machine_id" "${machine_id:-localhost}"
|
|
json_add_string "machine_version" "$machine_version"
|
|
|
|
# Bouncer count
|
|
local bouncer_count=0
|
|
if [ -x "$CSCLI" ]; then
|
|
bouncer_count=$(run_cscli bouncers list -o json 2>/dev/null | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
|
fi
|
|
json_add_int "bouncer_count" "${bouncer_count:-0}"
|
|
|
|
# Total decisions count
|
|
local decisions_count=0
|
|
if [ -x "$CSCLI" ]; then
|
|
decisions_count=$(run_cscli decisions list -o json 2>/dev/null | jsonfilter -e '@[*].decisions[*]' 2>/dev/null | wc -l)
|
|
fi
|
|
json_add_int "decisions_count" "${decisions_count:-0}"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get CAPI blocklist metrics (decisions by origin and reason)
|
|
get_capi_metrics() {
|
|
json_init
|
|
|
|
if [ ! -x "$CSCLI" ]; then
|
|
json_add_boolean "available" 0
|
|
json_add_string "error" "cscli not found"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Get all decisions
|
|
local decisions_output=""
|
|
decisions_output=$(run_cscli decisions list -o json 2>/dev/null)
|
|
|
|
if [ -z "$decisions_output" ] || [ "$decisions_output" = "null" ]; then
|
|
json_add_boolean "available" 1
|
|
json_add_int "total_capi" 0
|
|
json_add_int "total_local" 0
|
|
json_add_string "breakdown" "[]"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
json_add_boolean "available" 1
|
|
|
|
# Count by origin
|
|
local capi_count=0
|
|
local local_count=0
|
|
|
|
# Parse decisions and count by origin
|
|
# The structure is: [{decisions: [...], ...}, ...]
|
|
# We need to count decisions where origin = "CAPI" or "crowdsec"
|
|
|
|
# Use a temp file for aggregation
|
|
local tmp_file="/tmp/capi_metrics.$$"
|
|
|
|
# Extract all decisions with their origin and scenario
|
|
echo "$decisions_output" | jsonfilter -e '@[*].decisions[*]' 2>/dev/null | while read -r decision; do
|
|
local origin=$(echo "$decisions_output" | jsonfilter -e '@[*].decisions[*].origin' 2>/dev/null | head -1)
|
|
local scenario=$(echo "$decisions_output" | jsonfilter -e '@[*].scenario' 2>/dev/null | head -1)
|
|
echo "$origin|$scenario"
|
|
done > "$tmp_file" 2>/dev/null
|
|
|
|
# Count CAPI decisions by scenario using awk
|
|
capi_count=$(echo "$decisions_output" | grep -o '"origin":"CAPI"' 2>/dev/null | wc -l)
|
|
local_count=$(echo "$decisions_output" | grep -o '"origin":"crowdsec"' 2>/dev/null | wc -l)
|
|
|
|
json_add_int "total_capi" "${capi_count:-0}"
|
|
json_add_int "total_local" "${local_count:-0}"
|
|
|
|
# Build breakdown by scenario for CAPI decisions
|
|
# Parse the JSON more carefully
|
|
json_add_array "breakdown"
|
|
|
|
# Extract unique scenarios and their counts from CAPI decisions
|
|
local scenarios=""
|
|
scenarios=$(echo "$decisions_output" | grep -oE '"scenario":"[^"]*"' | sort | uniq -c | sort -rn | head -10)
|
|
|
|
echo "$scenarios" | while read -r count scenario; do
|
|
if [ -n "$count" ] && [ -n "$scenario" ]; then
|
|
local name=$(echo "$scenario" | sed 's/"scenario":"//; s/"$//')
|
|
json_add_object ""
|
|
json_add_string "scenario" "$name"
|
|
json_add_int "count" "$count"
|
|
json_close_object
|
|
fi
|
|
done
|
|
|
|
json_close_array
|
|
|
|
rm -f "$tmp_file" 2>/dev/null
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get available hub items (not installed)
|
|
get_hub_available() {
|
|
json_init
|
|
|
|
if [ ! -x "$CSCLI" ]; then
|
|
json_add_boolean "available" 0
|
|
json_add_string "error" "cscli not found"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
json_add_boolean "available" 1
|
|
|
|
# Get hub list in JSON format (all items)
|
|
local hub_output=""
|
|
hub_output=$(run_with_timeout 30 "$CSCLI" hub list -a -o json 2>/dev/null)
|
|
|
|
if [ -z "$hub_output" ]; then
|
|
json_add_string "collections" "[]"
|
|
json_add_string "parsers" "[]"
|
|
json_add_string "scenarios" "[]"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Output the raw hub data - frontend will parse it
|
|
echo "$hub_output"
|
|
}
|
|
|
|
# Install a hub item (collection, parser, scenario)
|
|
install_hub_item() {
|
|
local item_type="$1"
|
|
local item_name="$2"
|
|
|
|
json_init
|
|
|
|
if [ -z "$item_type" ] || [ -z "$item_name" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Item type and name are required"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Validate item type
|
|
case "$item_type" in
|
|
collection|parser|scenario|postoverflow|context)
|
|
;;
|
|
*)
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Invalid item type: $item_type"
|
|
json_dump
|
|
return
|
|
;;
|
|
esac
|
|
|
|
if [ ! -x "$CSCLI" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "cscli not found"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
secubox_log "Installing CrowdSec $item_type: $item_name"
|
|
|
|
# Install the item
|
|
local output=""
|
|
output=$(run_with_timeout 60 "$CSCLI" "${item_type}s" install "$item_name" 2>&1)
|
|
local result=$?
|
|
|
|
if [ "$result" -eq 0 ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Successfully installed $item_type: $item_name"
|
|
json_add_string "output" "$output"
|
|
secubox_log "Installed $item_type: $item_name"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to install $item_type: $item_name"
|
|
json_add_string "output" "$output"
|
|
secubox_log "Failed to install $item_type: $item_name - $output"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Remove a hub item
|
|
remove_hub_item() {
|
|
local item_type="$1"
|
|
local item_name="$2"
|
|
|
|
json_init
|
|
|
|
if [ -z "$item_type" ] || [ -z "$item_name" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Item type and name are required"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
case "$item_type" in
|
|
collection|parser|scenario|postoverflow|context)
|
|
;;
|
|
*)
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Invalid item type: $item_type"
|
|
json_dump
|
|
return
|
|
;;
|
|
esac
|
|
|
|
if [ ! -x "$CSCLI" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "cscli not found"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
secubox_log "Removing CrowdSec $item_type: $item_name"
|
|
|
|
local output=""
|
|
output=$(run_with_timeout 30 "$CSCLI" "${item_type}s" remove "$item_name" 2>&1)
|
|
local result=$?
|
|
|
|
if [ "$result" -eq 0 ]; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Successfully removed $item_type: $item_name"
|
|
secubox_log "Removed $item_type: $item_name"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to remove $item_type: $item_name"
|
|
json_add_string "output" "$output"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get dashboard settings (enrollment key, etc.)
|
|
get_settings() {
|
|
json_init
|
|
|
|
local enrollment_key=""
|
|
local machine_name=""
|
|
local auto_enroll=""
|
|
|
|
# Read from UCI config
|
|
enrollment_key=$(uci -q get crowdsec-dashboard.main.enrollment_key 2>/dev/null)
|
|
machine_name=$(uci -q get crowdsec-dashboard.main.machine_name 2>/dev/null)
|
|
auto_enroll=$(uci -q get crowdsec-dashboard.main.auto_enroll 2>/dev/null)
|
|
|
|
json_add_string "enrollment_key" "$enrollment_key"
|
|
json_add_string "machine_name" "$machine_name"
|
|
json_add_string "auto_enroll" "${auto_enroll:-0}"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Save dashboard settings
|
|
save_settings() {
|
|
local enrollment_key="$1"
|
|
local machine_name="$2"
|
|
local auto_enroll="$3"
|
|
|
|
json_init
|
|
|
|
# Ensure config section exists
|
|
uci -q get crowdsec-dashboard.main >/dev/null 2>&1 || {
|
|
uci set crowdsec-dashboard.main=settings
|
|
}
|
|
|
|
# Save settings
|
|
[ -n "$enrollment_key" ] && uci set crowdsec-dashboard.main.enrollment_key="$enrollment_key"
|
|
[ -n "$machine_name" ] && uci set crowdsec-dashboard.main.machine_name="$machine_name"
|
|
[ -n "$auto_enroll" ] && uci set crowdsec-dashboard.main.auto_enroll="$auto_enroll"
|
|
|
|
if uci commit crowdsec-dashboard 2>/dev/null; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Settings saved"
|
|
secubox_log "Saved enrollment settings"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "Failed to save settings"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Consolidated overview data for dashboard - single API call optimization
|
|
get_overview() {
|
|
json_init
|
|
|
|
# Service status (fast - just process checks)
|
|
local cs_running=0
|
|
pgrep crowdsec >/dev/null 2>&1 && cs_running=1
|
|
json_add_string "crowdsec" "$([ "$cs_running" = "1" ] && echo running || echo stopped)"
|
|
|
|
local bouncer_running=0
|
|
pgrep -f "crowdsec-firewall-bouncer" >/dev/null 2>&1 && bouncer_running=1
|
|
json_add_string "bouncer" "$([ "$bouncer_running" = "1" ] && echo running || echo stopped)"
|
|
|
|
# Version
|
|
local version=""
|
|
[ -x "$CSCLI" ] && version=$("$CSCLI" version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
|
json_add_string "version" "${version:-unknown}"
|
|
|
|
# Quick stats
|
|
local decisions_count=0
|
|
local alerts_count=0
|
|
local bouncers_count=0
|
|
|
|
if [ "$cs_running" = "1" ] && [ -x "$CSCLI" ]; then
|
|
decisions_count=$(run_cscli decisions list -o json 2>/dev/null | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
|
alerts_count=$(run_cscli alerts list -o json --since 24h --limit 100 2>/dev/null | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
|
bouncers_count=$(run_cscli bouncers list -o json 2>/dev/null | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
|
fi
|
|
|
|
json_add_int "total_decisions" "${decisions_count:-0}"
|
|
json_add_int "alerts_24h" "${alerts_count:-0}"
|
|
json_add_int "bouncers" "${bouncers_count:-0}"
|
|
|
|
# Top scenarios (from cached/limited alerts)
|
|
local scenarios=""
|
|
if [ "$cs_running" = "1" ]; then
|
|
scenarios=$(run_cscli alerts list -o json --limit 100 2>/dev/null | \
|
|
jsonfilter -e '@[*].scenario' 2>/dev/null | \
|
|
sort | uniq -c | sort -rn | head -5 | \
|
|
awk '{print "{\"scenario\":\"" $2 "\",\"count\":" $1 "}"}' | \
|
|
tr '\n' ',' | sed 's/,$//')
|
|
fi
|
|
json_add_string "top_scenarios_raw" "[$scenarios]"
|
|
|
|
# Top countries (from alerts with GeoIP)
|
|
local countries=""
|
|
if [ "$cs_running" = "1" ]; then
|
|
countries=$(run_cscli alerts list -o json --limit 200 2>/dev/null | \
|
|
jsonfilter -e '@[*].source.cn' 2>/dev/null | \
|
|
grep -v '^$' | sort | uniq -c | sort -rn | head -10 | \
|
|
awk '{print "{\"country\":\"" $2 "\",\"count\":" $1 "}"}' | \
|
|
tr '\n' ',' | sed 's/,$//')
|
|
fi
|
|
json_add_string "top_countries_raw" "[$countries]"
|
|
|
|
# Recent decisions (limited to 10 for display)
|
|
json_add_array "decisions"
|
|
if [ "$cs_running" = "1" ]; then
|
|
run_cscli decisions list -o json 2>/dev/null | \
|
|
jsonfilter -e '@[0]' -e '@[1]' -e '@[2]' -e '@[3]' -e '@[4]' \
|
|
-e '@[5]' -e '@[6]' -e '@[7]' -e '@[8]' -e '@[9]' 2>/dev/null | \
|
|
while IFS= read -r line; do
|
|
[ -n "$line" ] && [ "$line" != "null" ] && json_add_string "" "$line"
|
|
done
|
|
fi
|
|
json_close_array
|
|
|
|
# Recent alerts (limited to 8)
|
|
json_add_array "alerts"
|
|
if [ "$cs_running" = "1" ]; then
|
|
run_cscli alerts list -o json --limit 8 2>/dev/null | \
|
|
jsonfilter -e '@[*]' 2>/dev/null | head -8 | \
|
|
while IFS= read -r line; do
|
|
[ -n "$line" ] && json_add_string "" "$line"
|
|
done
|
|
fi
|
|
json_close_array
|
|
|
|
# CrowdSec logs (last 30 lines)
|
|
json_add_array "logs"
|
|
if [ -f /var/log/crowdsec.log ]; then
|
|
tail -n 30 /var/log/crowdsec.log 2>/dev/null | while IFS= read -r line; do
|
|
json_add_string "" "$line"
|
|
done
|
|
fi
|
|
json_close_array
|
|
|
|
# LAPI status (quick check)
|
|
local lapi_ok=0
|
|
if [ "$cs_running" = "1" ] && grep -qi ":1F90 " /proc/net/tcp 2>/dev/null; then
|
|
lapi_ok=1
|
|
fi
|
|
json_add_string "lapi_status" "$([ "$lapi_ok" = "1" ] && echo available || echo unavailable)"
|
|
|
|
# CAPI status (from config check, not live call)
|
|
local capi_enrolled=0
|
|
[ -f /etc/crowdsec/online_api_credentials.yaml ] && capi_enrolled=1
|
|
json_add_boolean "capi_enrolled" "$capi_enrolled"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Main dispatcher
|
|
case "$1" in
|
|
list)
|
|
echo '{"get_overview":{},"decisions":{},"alerts":{"limit":"number"},"metrics":{},"bouncers":{},"machines":{},"hub":{},"status":{},"ban":{"ip":"string","duration":"string","reason":"string"},"unban":{"ip":"string"},"stats":{},"secubox_logs":{},"collect_debug":{},"waf_status":{},"metrics_config":{},"configure_metrics":{"enable":"string"},"collections":{},"install_collection":{"collection":"string"},"remove_collection":{"collection":"string"},"update_hub":{},"register_bouncer":{"bouncer_name":"string"},"delete_bouncer":{"bouncer_name":"string"},"firewall_bouncer_status":{},"control_firewall_bouncer":{"action":"string"},"firewall_bouncer_config":{},"update_firewall_bouncer_config":{"key":"string","value":"string"},"nftables_stats":{},"check_wizard_needed":{},"wizard_state":{},"repair_lapi":{},"repair_capi":{},"reset_wizard":{},"console_status":{},"console_enroll":{"key":"string","name":"string"},"console_disable":{},"service_control":{"action":"string"},"configure_acquisition":{"syslog_enabled":"string","firewall_enabled":"string","ssh_enabled":"string","http_enabled":"string","syslog_path":"string"},"acquisition_config":{},"acquisition_metrics":{},"health_check":{},"capi_metrics":{},"hub_available":{},"install_hub_item":{"item_type":"string","item_name":"string"},"remove_hub_item":{"item_type":"string","item_name":"string"},"get_settings":{},"save_settings":{"enrollment_key":"string","machine_name":"string","auto_enroll":"string"}}'
|
|
;;
|
|
call)
|
|
case "$2" in
|
|
decisions)
|
|
get_decisions
|
|
;;
|
|
alerts)
|
|
read -r input
|
|
limit=$(echo "$input" | jsonfilter -e '@.limit' 2>/dev/null)
|
|
get_alerts "${limit:-50}"
|
|
;;
|
|
metrics)
|
|
get_metrics
|
|
;;
|
|
bouncers)
|
|
get_bouncers
|
|
;;
|
|
machines)
|
|
get_machines
|
|
;;
|
|
hub)
|
|
get_hub
|
|
;;
|
|
status)
|
|
get_status
|
|
;;
|
|
ban)
|
|
read -r input
|
|
ip=$(echo "$input" | jsonfilter -e '@.ip' 2>/dev/null)
|
|
duration=$(echo "$input" | jsonfilter -e '@.duration' 2>/dev/null)
|
|
reason=$(echo "$input" | jsonfilter -e '@.reason' 2>/dev/null)
|
|
add_ban "$ip" "$duration" "$reason"
|
|
;;
|
|
unban)
|
|
read -r input
|
|
ip=$(echo "$input" | jsonfilter -e '@.ip' 2>/dev/null)
|
|
remove_ban "$ip"
|
|
;;
|
|
stats)
|
|
get_dashboard_stats
|
|
;;
|
|
secubox_logs|crowdsec_logs)
|
|
crowdsec_logs
|
|
;;
|
|
collect_debug)
|
|
collect_debug
|
|
;;
|
|
waf_status)
|
|
get_waf_status
|
|
;;
|
|
metrics_config)
|
|
get_metrics_config
|
|
;;
|
|
configure_metrics)
|
|
read -r input
|
|
enable=$(echo "$input" | jsonfilter -e '@.enable' 2>/dev/null)
|
|
configure_metrics "$enable"
|
|
;;
|
|
collections)
|
|
get_collections
|
|
;;
|
|
install_collection)
|
|
read -r input
|
|
collection=$(echo "$input" | jsonfilter -e '@.collection' 2>/dev/null)
|
|
install_collection "$collection"
|
|
;;
|
|
remove_collection)
|
|
read -r input
|
|
collection=$(echo "$input" | jsonfilter -e '@.collection' 2>/dev/null)
|
|
remove_collection "$collection"
|
|
;;
|
|
update_hub)
|
|
update_hub
|
|
;;
|
|
register_bouncer)
|
|
read -r input
|
|
bouncer_name=$(echo "$input" | jsonfilter -e '@.bouncer_name' 2>/dev/null)
|
|
register_bouncer "$bouncer_name"
|
|
;;
|
|
delete_bouncer)
|
|
read -r input
|
|
bouncer_name=$(echo "$input" | jsonfilter -e '@.bouncer_name' 2>/dev/null)
|
|
delete_bouncer "$bouncer_name"
|
|
;;
|
|
firewall_bouncer_status)
|
|
get_firewall_bouncer_status
|
|
;;
|
|
control_firewall_bouncer)
|
|
read -r input
|
|
action=$(echo "$input" | jsonfilter -e '@.action' 2>/dev/null)
|
|
control_firewall_bouncer "$action"
|
|
;;
|
|
firewall_bouncer_config)
|
|
get_firewall_bouncer_config
|
|
;;
|
|
update_firewall_bouncer_config)
|
|
read -r input
|
|
key=$(echo "$input" | jsonfilter -e '@.key' 2>/dev/null)
|
|
value=$(echo "$input" | jsonfilter -e '@.value' 2>/dev/null)
|
|
update_firewall_bouncer_config "$key" "$value"
|
|
;;
|
|
nftables_stats)
|
|
get_nftables_stats
|
|
;;
|
|
check_wizard_needed)
|
|
check_wizard_needed
|
|
;;
|
|
wizard_state)
|
|
get_wizard_state
|
|
;;
|
|
repair_lapi)
|
|
repair_lapi
|
|
;;
|
|
repair_capi)
|
|
repair_capi
|
|
;;
|
|
reset_wizard)
|
|
reset_wizard
|
|
;;
|
|
console_status)
|
|
get_console_status
|
|
;;
|
|
console_enroll)
|
|
read -r input
|
|
key=$(echo "$input" | jsonfilter -e '@.key' 2>/dev/null)
|
|
name=$(echo "$input" | jsonfilter -e '@.name' 2>/dev/null)
|
|
console_enroll "$key" "$name"
|
|
;;
|
|
console_disable)
|
|
console_disable
|
|
;;
|
|
service_control)
|
|
read -r input
|
|
action=$(echo "$input" | jsonfilter -e '@.action' 2>/dev/null)
|
|
service_control "$action"
|
|
;;
|
|
configure_acquisition)
|
|
read -r input
|
|
syslog_enabled=$(echo "$input" | jsonfilter -e '@.syslog_enabled' 2>/dev/null)
|
|
firewall_enabled=$(echo "$input" | jsonfilter -e '@.firewall_enabled' 2>/dev/null)
|
|
ssh_enabled=$(echo "$input" | jsonfilter -e '@.ssh_enabled' 2>/dev/null)
|
|
http_enabled=$(echo "$input" | jsonfilter -e '@.http_enabled' 2>/dev/null)
|
|
syslog_path=$(echo "$input" | jsonfilter -e '@.syslog_path' 2>/dev/null)
|
|
configure_acquisition "$syslog_enabled" "$firewall_enabled" "$ssh_enabled" "$http_enabled" "$syslog_path"
|
|
;;
|
|
acquisition_config)
|
|
get_acquisition_config
|
|
;;
|
|
acquisition_metrics)
|
|
get_acquisition_metrics
|
|
;;
|
|
health_check)
|
|
get_health_check
|
|
;;
|
|
capi_metrics)
|
|
get_capi_metrics
|
|
;;
|
|
hub_available)
|
|
get_hub_available
|
|
;;
|
|
install_hub_item)
|
|
read -r input
|
|
item_type=$(echo "$input" | jsonfilter -e '@.item_type' 2>/dev/null)
|
|
item_name=$(echo "$input" | jsonfilter -e '@.item_name' 2>/dev/null)
|
|
install_hub_item "$item_type" "$item_name"
|
|
;;
|
|
remove_hub_item)
|
|
read -r input
|
|
item_type=$(echo "$input" | jsonfilter -e '@.item_type' 2>/dev/null)
|
|
item_name=$(echo "$input" | jsonfilter -e '@.item_name' 2>/dev/null)
|
|
remove_hub_item "$item_type" "$item_name"
|
|
;;
|
|
get_settings)
|
|
get_settings
|
|
;;
|
|
save_settings)
|
|
read -r input
|
|
enrollment_key=$(echo "$input" | jsonfilter -e '@.enrollment_key' 2>/dev/null)
|
|
machine_name=$(echo "$input" | jsonfilter -e '@.machine_name' 2>/dev/null)
|
|
auto_enroll=$(echo "$input" | jsonfilter -e '@.auto_enroll' 2>/dev/null)
|
|
save_settings "$enrollment_key" "$machine_name" "$auto_enroll"
|
|
;;
|
|
get_overview)
|
|
get_overview
|
|
;;
|
|
*)
|
|
echo '{"error": "Unknown method"}'
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|