mirror of
https://github.com/aljazceru/Chasing-Your-Tail-NG.git
synced 2025-12-18 15:54:25 +01:00
175 lines
6.6 KiB
Python
175 lines
6.6 KiB
Python
"""
|
|
Secure ignore list loader - replaces dangerous exec() calls
|
|
"""
|
|
import json
|
|
import pathlib
|
|
import re
|
|
from typing import List, Optional
|
|
import logging
|
|
from input_validation import InputValidator
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class SecureIgnoreLoader:
|
|
"""Secure loader for MAC and SSID ignore lists"""
|
|
|
|
@staticmethod
|
|
def validate_mac_address(mac: str) -> bool:
|
|
"""Validate MAC address format using secure validator"""
|
|
return InputValidator.validate_mac_address(mac)
|
|
|
|
@staticmethod
|
|
def validate_ssid(ssid: str) -> bool:
|
|
"""Validate SSID using secure validator"""
|
|
return InputValidator.validate_ssid(ssid)
|
|
|
|
@classmethod
|
|
def load_mac_list(cls, file_path: pathlib.Path) -> List[str]:
|
|
"""
|
|
Securely load MAC address ignore list
|
|
Supports both JSON and Python list formats
|
|
"""
|
|
if not file_path.exists():
|
|
logger.warning(f"MAC ignore list not found: {file_path}")
|
|
return []
|
|
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read().strip()
|
|
|
|
# Try JSON format first
|
|
if content.startswith('[') and content.endswith(']'):
|
|
try:
|
|
mac_list = json.loads(content)
|
|
if not isinstance(mac_list, list):
|
|
raise ValueError("JSON content is not a list")
|
|
except json.JSONDecodeError:
|
|
# Fall back to Python list parsing
|
|
mac_list = cls._parse_python_list(content, 'ignore_list')
|
|
else:
|
|
# Parse Python variable assignment
|
|
mac_list = cls._parse_python_list(content, 'ignore_list')
|
|
|
|
# Validate all MAC addresses
|
|
validated_macs = []
|
|
for mac in mac_list:
|
|
if isinstance(mac, str) and cls.validate_mac_address(mac):
|
|
validated_macs.append(mac.upper()) # Normalize to uppercase
|
|
else:
|
|
logger.warning(f"Invalid MAC address skipped: {mac}")
|
|
|
|
logger.info(f"Loaded {len(validated_macs)} valid MAC addresses")
|
|
return validated_macs
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error loading MAC list from {file_path}: {e}")
|
|
return []
|
|
|
|
@classmethod
|
|
def load_ssid_list(cls, file_path: pathlib.Path) -> List[str]:
|
|
"""
|
|
Securely load SSID ignore list
|
|
Supports both JSON and Python list formats
|
|
"""
|
|
if not file_path.exists():
|
|
logger.warning(f"SSID ignore list not found: {file_path}")
|
|
return []
|
|
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read().strip()
|
|
|
|
# Try JSON format first
|
|
if content.startswith('[') and content.endswith(']'):
|
|
try:
|
|
ssid_list = json.loads(content)
|
|
if not isinstance(ssid_list, list):
|
|
raise ValueError("JSON content is not a list")
|
|
except json.JSONDecodeError:
|
|
# Fall back to Python list parsing
|
|
ssid_list = cls._parse_python_list(content, 'non_alert_ssid_list')
|
|
else:
|
|
# Parse Python variable assignment
|
|
ssid_list = cls._parse_python_list(content, 'non_alert_ssid_list')
|
|
|
|
# Validate all SSIDs
|
|
validated_ssids = []
|
|
for ssid in ssid_list:
|
|
if isinstance(ssid, str) and cls.validate_ssid(ssid):
|
|
validated_ssids.append(ssid)
|
|
else:
|
|
logger.warning(f"Invalid SSID skipped: {ssid}")
|
|
|
|
logger.info(f"Loaded {len(validated_ssids)} valid SSIDs")
|
|
return validated_ssids
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error loading SSID list from {file_path}: {e}")
|
|
return []
|
|
|
|
@staticmethod
|
|
def _parse_python_list(content: str, variable_name: str) -> List[str]:
|
|
"""
|
|
Safely parse Python list assignment without exec()
|
|
Only handles simple list assignments like: var_name = ['item1', 'item2']
|
|
"""
|
|
# Remove comments and extra whitespace
|
|
lines = [line.split('#')[0].strip() for line in content.split('\n')]
|
|
content_clean = ' '.join(lines)
|
|
|
|
# Look for variable assignment pattern
|
|
pattern = rf'{re.escape(variable_name)}\s*=\s*(\[.*?\])'
|
|
match = re.search(pattern, content_clean, re.DOTALL)
|
|
|
|
if not match:
|
|
raise ValueError(f"Could not find {variable_name} assignment")
|
|
|
|
list_str = match.group(1)
|
|
|
|
# Use json.loads for safe parsing (requires proper JSON format)
|
|
try:
|
|
# Replace single quotes with double quotes for JSON compatibility
|
|
json_str = list_str.replace("'", '"')
|
|
return json.loads(json_str)
|
|
except json.JSONDecodeError as e:
|
|
raise ValueError(f"Could not parse list as JSON: {e}")
|
|
|
|
@classmethod
|
|
def save_mac_list(cls, mac_list: List[str], file_path: pathlib.Path) -> None:
|
|
"""Save MAC list in secure JSON format"""
|
|
# Validate all MACs before saving
|
|
valid_macs = [mac.upper() for mac in mac_list if cls.validate_mac_address(mac)]
|
|
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
json.dump(valid_macs, f, indent=2)
|
|
|
|
logger.info(f"Saved {len(valid_macs)} MAC addresses to {file_path}")
|
|
|
|
@classmethod
|
|
def save_ssid_list(cls, ssid_list: List[str], file_path: pathlib.Path) -> None:
|
|
"""Save SSID list in secure JSON format"""
|
|
# Validate all SSIDs before saving
|
|
valid_ssids = [ssid for ssid in ssid_list if cls.validate_ssid(ssid)]
|
|
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
json.dump(valid_ssids, f, indent=2)
|
|
|
|
logger.info(f"Saved {len(valid_ssids)} SSIDs to {file_path}")
|
|
|
|
|
|
def load_ignore_lists(config: dict) -> tuple[List[str], List[str]]:
|
|
"""
|
|
Convenience function to load both MAC and SSID ignore lists
|
|
Returns: (mac_list, ssid_list)
|
|
"""
|
|
loader = SecureIgnoreLoader()
|
|
|
|
# Load MAC ignore list
|
|
mac_path = pathlib.Path('./ignore_lists') / config['paths']['ignore_lists']['mac']
|
|
mac_list = loader.load_mac_list(mac_path)
|
|
|
|
# Load SSID ignore list
|
|
ssid_path = pathlib.Path('./ignore_lists') / config['paths']['ignore_lists']['ssid']
|
|
ssid_list = loader.load_ssid_list(ssid_path)
|
|
|
|
return mac_list, ssid_list |