Skip to content

Commit ed0c2e7

Browse files
Update json2apache.py
1 parent 4c01d41 commit ed0c2e7

1 file changed

Lines changed: 26 additions & 17 deletions

File tree

json2apache.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from pathlib import Path
66
from typing import List, Dict, Set, Tuple, Optional
77
from functools import lru_cache
8+
from collections import defaultdict # Import defaultdict
89

910
# --- Configuration ---
1011
LOG_LEVEL = logging.INFO # Adjust as needed (DEBUG, INFO, WARNING, ERROR)
@@ -21,19 +22,19 @@
2122

2223
# Unsupported ModSecurity directives (expand as needed)
2324
UNSUPPORTED_PATTERNS = [
24-
"@pmFromFile", # File lookups not directly supported
25+
"@pmFromFile", # File lookups not directly supported
2526
# You might handle some of these with ctl:ruleRemoveTargetById later
2627
]
2728
# Supported ModSecurity operators and their rough translations (for logging/info)
2829
SUPPORTED_OPERATORS = {
29-
"@rx": "Regular Expression",
30-
"@streq": "String Equals",
31-
"@contains": "Contains String",
32-
"@beginsWith": "Begins With",
33-
"@endsWith": "Ends With",
34-
"@within": "Contained Within",
35-
"@ipMatch": "IP Address Match",
36-
# ... add more as needed
30+
"@rx": "Regular Expression",
31+
"@streq": "String Equals",
32+
"@contains": "Contains String",
33+
"@beginsWith": "Begins With",
34+
"@endsWith": "Ends With",
35+
"@within": "Contained Within",
36+
"@ipMatch": "IP Address Match",
37+
# ... add more as needed
3738
}
3839

3940
# --- Logging Setup ---
@@ -78,7 +79,7 @@ def _determine_variables(location: str) -> str:
7879
# Add other location mappings as needed
7980
else:
8081
logger.warning(f"Unknown location '{location}', defaulting to REQUEST_URI")
81-
return "REQUEST_URI" # Default variable
82+
return "REQUEST_URI" # Default variable
8283

8384

8485
def generate_apache_waf(rules: List[Dict]) -> None:
@@ -93,16 +94,24 @@ def generate_apache_waf(rules: List[Dict]) -> None:
9394

9495
for rule in rules:
9596
rule_id = rule.get("id", "no_id") # Get rule ID
96-
if not isinstance(rule_id, int): # check if is an int
97-
# Extract ID from rule and convert to an integer
97+
if not isinstance(rule_id, int): # check if is an int
98+
# Extract ID from rule and convert to an integer
9899
match = re.search(r'id:(\d+)', rule_id)
99-
rule_id = int(match.group(1)) if match else rule_id_counter
100-
rule_id_counter += 1
100+
if match:
101+
try:
102+
rule_id = int(match.group(1))
103+
except ValueError:
104+
logger.warning(f"Invalid rule ID '{match.group(1)}' in rule: {rule}. Using generated ID.")
105+
rule_id = rule_id_counter
106+
rule_id_counter += 1
107+
else:
108+
rule_id = rule_id_counter
109+
rule_id_counter += 1
101110

102111
category = rule.get("category", "generic").lower()
103112
pattern = rule["pattern"]
104-
location = rule.get("location", "REQUEST_URI") # Set a default variable
105-
severity = rule.get("severity", "CRITICAL").upper() # CRITICAL, ERROR, WARNING, NOTICE
113+
location = rule.get("location", "REQUEST_URI") # Set a default variable
114+
severity = rule.get("severity", "CRITICAL").upper() # CRITICAL, ERROR, WARNING, NOTICE
106115
# --- Operator Handling ---
107116
operator_used = "Unknown" # Default
108117
for op in SUPPORTED_OPERATORS:
@@ -133,7 +142,7 @@ def generate_apache_waf(rules: List[Dict]) -> None:
133142
phase=2, # Phase 2 (request body processing) is common, adjust if needed
134143
actions=DEFAULT_ACTIONS,
135144
)
136-
categorized_rules[category].add(rule_str) # added into a dict
145+
categorized_rules[category].add(rule_str) # added into a dict
137146

138147

139148
# --- File Output ---

0 commit comments

Comments
 (0)