#!/usr/bin/env bash
#
# onx-modsec-rules-list — /etc/httpd/modsecurity.d/owasp-crs/rules/*.conf parse → JSON katalog.
#
# Output: {"rules":[{rule_id, category, tag, severity, description, phase}], "total":N}

set -euo pipefail

# Common OWASP CRS install paths (distro-dependent)
declare -a CRS_PATHS=(
    "/etc/httpd/modsecurity.d/owasp-crs/rules"
    "/etc/modsecurity.d/owasp-crs/rules"
    "/usr/local/owasp-crs/rules"
    "/etc/nginx/modsec/coreruleset/rules"
)

rules_dir=""
for p in "${CRS_PATHS[@]}"; do
    if [[ -d "$p" ]]; then
        rules_dir="$p"
        break
    fi
done

if [[ -z "$rules_dir" ]]; then
    jq -nc '{ok:false,error:"OWASP CRS rules directory not found",rules:[],total:0}' >&2
    exit 2
fi

# Parse SecRule blocks: id, tag, severity, msg
tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT

count=0
first=1
echo "[" > "$tmp"

for conf in "$rules_dir"/*.conf; do
    [[ -f "$conf" ]] || continue

    # Each SecRule can span multiple lines (backslash continuation)
    # awk: collapse continuation lines, then process
    awk '
        /\\\s*$/ { sub(/\\\s*$/, ""); line = line $0; next }
        { line = line $0; print line; line = "" }
    ' "$conf" | grep -E '^[[:space:]]*SecRule' | while IFS= read -r rule_line; do
        # Extract id, tag, severity, msg from action list
        rule_id=$(echo "$rule_line" | grep -oE 'id:[0-9]+' | head -1 | cut -d: -f2 || echo "")
        [[ -z "$rule_id" ]] && continue

        tag=$(echo "$rule_line" | grep -oE "tag:'[^']+'" | head -1 | sed "s/tag:'//;s/'$//" || echo "")
        [[ -z "$tag" ]] && tag=$(echo "$rule_line" | grep -oE "tag:[^,]+" | head -1 | cut -d: -f2 || echo "")

        severity=$(echo "$rule_line" | grep -oE "severity:'[A-Z]+'" | head -1 | sed "s/severity:'//;s/'$//" || echo "")
        [[ -z "$severity" ]] && severity=$(echo "$rule_line" | grep -oE "severity:[A-Z]+" | head -1 | cut -d: -f2 || echo "INFO")

        msg=$(echo "$rule_line" | grep -oE "msg:'[^']+'" | head -1 | sed "s/msg:'//;s/'$//" || echo "")
        [[ -z "$msg" ]] && msg="$(basename "$conf" .conf | tr '_' ' ')"

        phase=$(echo "$rule_line" | grep -oE 'phase:[0-9]' | head -1 | cut -d: -f2 || echo "2")

        # Category: derive from filename or first tag
        category=$(basename "$conf" .conf | sed 's/^REQUEST-[0-9]\+-//;s/^[0-9]\+-//;s/_/ /g' | head -c 40)

        # JSON record
        rec=$(jq -nc \
            --arg rule_id "$rule_id" \
            --arg category "$category" \
            --arg tag "$tag" \
            --arg severity "$severity" \
            --arg description "$msg" \
            --argjson phase "$phase" \
            --argjson enabled "true" \
            '{rule_id:$rule_id, category:$category, tag:$tag, severity:$severity, description:$description, phase:$phase, enabled:$enabled}')

        if [[ $first -eq 0 ]]; then
            echo "," >> "$tmp"
        fi
        first=0
        echo "$rec" >> "$tmp"
        count=$((count + 1))
    done
done
echo "]" >> "$tmp"

rules_json="$(cat "$tmp")"

jq -nc --argjson rules "$rules_json" --argjson total "$count" \
    '{ok:true, rules:$rules, total:$total}'
