177 lines
5.1 KiB
Python
Executable File
177 lines
5.1 KiB
Python
Executable File
"""
|
|
Configuration management pour IPWatch
|
|
Charge et valide le fichier config.yaml
|
|
"""
|
|
import yaml
|
|
from pathlib import Path
|
|
from typing import Dict, Any, List, Optional
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class AppConfig(BaseModel):
|
|
"""Configuration de l'application"""
|
|
name: str = "IPWatch"
|
|
version: str = "1.0.0"
|
|
debug: bool = False
|
|
|
|
|
|
class NetworkConfig(BaseModel):
|
|
"""Configuration réseau"""
|
|
cidr: str
|
|
gateway: Optional[str] = None
|
|
dns: Optional[List[str]] = None
|
|
|
|
|
|
class ScanConfig(BaseModel):
|
|
"""Configuration des scans"""
|
|
ping_interval: int = 60 # secondes
|
|
ping_count: int = 1 # Nombre de ping par IP
|
|
port_scan_interval: int = 300 # secondes
|
|
parallel_pings: int = 50
|
|
timeout: float = 1.0
|
|
force_vendor_update: bool = False
|
|
|
|
|
|
class PortsConfig(BaseModel):
|
|
"""Configuration des ports à scanner"""
|
|
ranges: List[str] = ["22", "80", "443", "3389", "8080"]
|
|
protocols: Optional[Dict[int, str]] = None # Mapping port -> protocole
|
|
|
|
|
|
class HistoryConfig(BaseModel):
|
|
"""Configuration de l'historique"""
|
|
retention_hours: int = 24
|
|
|
|
|
|
class UIConfig(BaseModel):
|
|
"""Configuration UI"""
|
|
offline_transparency: float = 0.5
|
|
show_mac: bool = True
|
|
show_vendor: bool = True
|
|
cell_size: int = 30
|
|
font_size: int = 10
|
|
cell_gap: float = 2
|
|
details_font_size: int = 13
|
|
details_spacing: int = 2
|
|
architecture_title_font_size: int = 18
|
|
|
|
|
|
class LinksConfig(BaseModel):
|
|
"""Configuration des liens"""
|
|
hardware_bench_url: Optional[str] = None
|
|
|
|
|
|
class ColorsConfig(BaseModel):
|
|
"""Configuration des couleurs"""
|
|
free: str = "#75715E"
|
|
online_known: str = "#A6E22E"
|
|
online_unknown: str = "#66D9EF"
|
|
offline_known: str = "#F92672"
|
|
offline_unknown: str = "#AE81FF"
|
|
mac_changed: str = "#FD971F"
|
|
network_device: str = "#1E3A8A"
|
|
|
|
|
|
class OPNsenseConfig(BaseModel):
|
|
"""Configuration OPNsense API"""
|
|
enabled: bool = False
|
|
host: str = ""
|
|
api_key: str = ""
|
|
api_secret: str = ""
|
|
verify_ssl: bool = False
|
|
protocol: str = "http" # "http" ou "https"
|
|
|
|
|
|
class ServiceDefinition(BaseModel):
|
|
"""Définition d'un service réseau (pour scan de services)"""
|
|
name: str
|
|
port: int
|
|
protocol: Optional[str] = None # http, https, ssh, rdp, smb...
|
|
description: str = ""
|
|
|
|
|
|
class DatabaseConfig(BaseModel):
|
|
"""Configuration base de données"""
|
|
path: str = "./data/db.sqlite"
|
|
|
|
|
|
class SubnetConfig(BaseModel):
|
|
"""Configuration d'un sous-réseau"""
|
|
name: str
|
|
cidr: str
|
|
start: str
|
|
end: str
|
|
description: str
|
|
|
|
|
|
class HostConfig(BaseModel):
|
|
"""Configuration d'un hôte avec sa localisation"""
|
|
name: str
|
|
location: str
|
|
ip: Optional[str] = None
|
|
ip_parent: Optional[str] = None
|
|
ip_enfant: Optional[List[str]] = None
|
|
|
|
|
|
class IPWatchConfig(BaseModel):
|
|
"""Configuration complète IPWatch"""
|
|
model_config = {"arbitrary_types_allowed": True}
|
|
|
|
app: AppConfig = Field(default_factory=AppConfig)
|
|
network: NetworkConfig
|
|
subnets: List[SubnetConfig] = Field(default_factory=list)
|
|
ip_classes: Dict[str, Any] = Field(default_factory=dict)
|
|
scan: ScanConfig = Field(default_factory=ScanConfig)
|
|
ports: PortsConfig = Field(default_factory=PortsConfig)
|
|
locations: List[str] = Field(default_factory=list)
|
|
hosts: List[HostConfig] = Field(default_factory=list)
|
|
history: HistoryConfig = Field(default_factory=HistoryConfig)
|
|
ui: UIConfig = Field(default_factory=UIConfig)
|
|
links: LinksConfig = Field(default_factory=LinksConfig)
|
|
colors: ColorsConfig = Field(default_factory=ColorsConfig)
|
|
database: DatabaseConfig = Field(default_factory=DatabaseConfig)
|
|
opnsense: OPNsenseConfig = Field(default_factory=OPNsenseConfig)
|
|
services: List[ServiceDefinition] = Field(default_factory=list)
|
|
|
|
|
|
class ConfigManager:
|
|
"""Gestionnaire de configuration singleton"""
|
|
_instance: Optional['ConfigManager'] = None
|
|
_config: Optional[IPWatchConfig] = None
|
|
|
|
def __new__(cls):
|
|
if cls._instance is None:
|
|
cls._instance = super().__new__(cls)
|
|
return cls._instance
|
|
|
|
def load_config(self, config_path: str = "./config.yaml") -> IPWatchConfig:
|
|
"""Charge la configuration depuis le fichier YAML"""
|
|
path = Path(config_path)
|
|
|
|
if not path.exists():
|
|
raise FileNotFoundError(f"Fichier de configuration non trouvé: {config_path}")
|
|
|
|
with open(path, 'r', encoding='utf-8') as f:
|
|
yaml_data = yaml.safe_load(f)
|
|
|
|
self._config = IPWatchConfig(**yaml_data)
|
|
self._config_path = config_path
|
|
return self._config
|
|
|
|
def reload_config(self) -> IPWatchConfig:
|
|
"""Recharge la configuration depuis le fichier"""
|
|
if not hasattr(self, '_config_path'):
|
|
self._config_path = "./config.yaml"
|
|
return self.load_config(self._config_path)
|
|
|
|
@property
|
|
def config(self) -> IPWatchConfig:
|
|
"""Retourne la configuration actuelle"""
|
|
if self._config is None:
|
|
raise RuntimeError("Configuration non chargée. Appelez load_config() d'abord.")
|
|
return self._config
|
|
|
|
|
|
# Instance globale
|
|
config_manager = ConfigManager()
|