#!/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" # 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=$($CSCLI decisions list -o json 2>/dev/null) 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=$($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=$($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=$($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=$($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=$($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 if pgrep crowdsec >/dev/null 2>&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=$($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" if [ -x "$CSCLI" ]; then if $CSCLI lapi status >/dev/null 2>&1; then lapi_status="available" fi fi json_add_string "lapi_status" "$lapi_status" 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=$($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=$($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=$($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=$($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=$($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=$($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 decisions) local countries countries=$($CSCLI decisions list -o json 2>/dev/null | \ jsonfilter -e '@[*].country' 2>/dev/null | \ sort | uniq -c | sort -rn | head -10 | \ awk '{print "{\"country\":\"" $2 "\",\"count\":" $1 "}"}' | \ tr '\n' ',' | sed 's/,$//') json_add_string "top_countries_raw" "[$countries]" json_dump } seccubox_logs() { json_init json_add_array "entries" if [ -f /var/log/seccubox.log ]; then tail -n 80 /var/log/seccubox.log | while IFS= read -r line; do json_add_string "" "$line" done fi json_close_array 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/seccubox.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 $CSCLI help appsec >/dev/null 2>&1; then local appsec_status appsec_status=$($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=$($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 $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 $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 $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" 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 local exists=0 if $CSCLI bouncers list -o json 2>/dev/null | grep -q "\"name\":\"$bouncer_name\""; then exists=1 fi local api_key if [ "$exists" = "1" ]; then # Delete existing bouncer and re-register to get new API key $CSCLI bouncers delete "$bouncer_name" >/dev/null 2>&1 secubox_log "Deleted existing bouncer: $bouncer_name" fi # Generate API key api_key=$($CSCLI bouncers add "$bouncer_name" -o raw 2>&1) if [ -n "$api_key" ] && [ "${#api_key}" -gt 10 ] && ! echo "$api_key" | grep -qi "error"; then json_add_boolean "success" 1 json_add_string "api_key" "$api_key" json_add_string "message" "Bouncer '$bouncer_name' registered successfully" secubox_log "Registered bouncer: $bouncer_name" else json_add_boolean "success" 0 json_add_string "error" "Failed to register bouncer '$bouncer_name': $api_key" 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 $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 IPv4 set json_add_array "ipv4_blocked_ips" if [ "$ipv4_exists" = "1" ]; then local ips ips=$(nft list set ip crowdsec crowdsec-blacklists 2>/dev/null | sed -n '/elements = {/,/}/p' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' || echo "") if [ -n "$ips" ]; then local ip for ip in $ips; do json_add_string "" "$ip" done fi fi json_close_array # Get blocked IPs from IPv6 set json_add_array "ipv6_blocked_ips" if [ "$ipv6_exists" = "1" ]; then local ips ips=$(nft list set ip6 crowdsec6 crowdsec6-blacklists 2>/dev/null | sed -n '/elements = {/,/}/p' | grep -oE '([0-9a-fA-F]{0,4}:){7}[0-9a-fA-F]{0,4}' || echo "") if [ -n "$ips" ]; then local ip for ip in $ips; do json_add_string "" "$ip" done fi 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" 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 $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=$($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="" secubox_log "Starting LAPI repair..." # Step 1: Create data directory if [ ! -d "/srv/crowdsec/data" ]; then mkdir -p /srv/crowdsec/data 2>/dev/null if [ -d "/srv/crowdsec/data" ]; then steps_done="${steps_done}Created /srv/crowdsec/data; " else errors="${errors}Failed to create data directory; " fi fi # Step 2: Fix config.yaml - ensure data_dir and db_path are set local config_file="/etc/crowdsec/config.yaml" if [ -f "$config_file" ]; then # Check if data_dir is empty or missing local current_data_dir=$(grep "^ data_dir:" "$config_file" | awk '{print $2}') if [ -z "$current_data_dir" ] || [ "$current_data_dir" = "" ]; then sed -i 's|^ data_dir:.*| data_dir: /srv/crowdsec/data/|' "$config_file" steps_done="${steps_done}Fixed data_dir in config; " fi # Check if db_path is empty or missing local current_db_path=$(grep "^ db_path:" "$config_file" | awk '{print $2}') if [ -z "$current_db_path" ] || [ "$current_db_path" = "" ]; then sed -i 's|^ db_path:.*| db_path: /srv/crowdsec/data/crowdsec.db|' "$config_file" steps_done="${steps_done}Fixed db_path in config; " fi else errors="${errors}Config file not found; " fi # Step 3: Restart CrowdSec to apply config changes if /etc/init.d/crowdsec restart >/dev/null 2>&1; then steps_done="${steps_done}Restarted CrowdSec; " sleep 2 else errors="${errors}Failed to restart CrowdSec; " fi # Step 4: Re-register local machine if needed if [ -x "$CSCLI" ]; then # Check if machine is registered and working if ! $CSCLI machines list >/dev/null 2>&1; then # Force re-register if $CSCLI machines add localhost --auto --force >/dev/null 2>&1; then steps_done="${steps_done}Re-registered localhost machine; " # Restart again to apply new credentials /etc/init.d/crowdsec restart >/dev/null 2>&1 sleep 2 else errors="${errors}Failed to register machine; " fi fi fi # Step 5: Verify LAPI is now working local lapi_ok=0 if [ -x "$CSCLI" ]; then if $CSCLI lapi status >/dev/null 2>&1; then lapi_ok=1 steps_done="${steps_done}LAPI verified working" else errors="${errors}LAPI still not responding" fi fi 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 completed: $steps_done" else json_add_boolean "success" 0 json_add_string "error" "LAPI repair failed" json_add_string "steps" "$steps_done" json_add_string "errors" "$errors" secubox_log "LAPI repair failed: $errors" fi 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=$($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..." # Build enroll command local enroll_cmd="$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 $CSCLI console enable share_manual_decisions >/dev/null 2>&1 $CSCLI console enable share_tainted >/dev/null 2>&1 $CSCLI console enable share_context >/dev/null 2>&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 $CSCLI console disable share_manual_decisions >/dev/null 2>&1 $CSCLI console disable share_tainted >/dev/null 2>&1 $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 } # 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 -x 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 } # Main dispatcher case "$1" in list) echo '{"decisions":{},"alerts":{"limit":"number"},"metrics":{},"bouncers":{},"machines":{},"hub":{},"status":{},"ban":{"ip":"string","duration":"string","reason":"string"},"unban":{"ip":"string"},"stats":{},"seccubox_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":{},"console_status":{},"console_enroll":{"key":"string","name":"string"},"console_disable":{},"service_control":{"action":"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 ;; seccubox_logs) seccubox_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 ;; 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" ;; *) echo '{"error": "Unknown method"}' ;; esac ;; esac