"""Configuration generator for mGuard routers.""" from dataclasses import dataclass from typing import Optional import json @dataclass class GatewayConfig: """Gateway configuration data.""" name: str vpn_server: str vpn_port: int ca_cert: str client_cert: str client_key: str ta_key: Optional[str] = None class ConfigGenerator: """Generate configuration files for mGuard routers.""" @staticmethod def generate_openvpn_config(config: GatewayConfig) -> str: """Generate OpenVPN client configuration. Args: config: Gateway configuration data Returns: OpenVPN config file content """ ovpn = f"""# OpenVPN Client Configuration # Generated for: {config.name} client dev tun proto udp remote {config.vpn_server} {config.vpn_port} resolv-retry infinite nobind persist-key persist-tun remote-cert-tls server cipher AES-256-GCM auth SHA256 verb 3 {config.ca_cert} {config.client_cert} {config.client_key} """ if config.ta_key: ovpn += f""" {config.ta_key} key-direction 1 """ return ovpn @staticmethod def generate_atv_vpn_section(config: GatewayConfig) -> str: """Generate ATV configuration section for VPN. Note: This is a simplified version. Real ATV files have a more complex structure that should be merged with existing config. Args: config: Gateway configuration data Returns: ATV config section """ # ATV is essentially a key-value format # This is a simplified representation atv_section = f""" [vpn_client_1] enabled = 1 name = {config.name} type = openvpn remote = {config.vpn_server} port = {config.vpn_port} protocol = udp cipher = AES-256-GCM """ return atv_section @staticmethod def generate_mguard_script( gateway_name: str, endpoints: list[dict] ) -> str: """Generate mGuard CLI script for firewall configuration. Args: gateway_name: Name of the gateway endpoints: List of endpoint configurations Returns: Shell script for mGuard CLI """ script = f"""#!/bin/bash # Firewall configuration script for {gateway_name} # Run this on the mGuard via SSH MBIN="/Packages/mguard-api_0/mbin" echo "Configuring firewall rules for {gateway_name}..." """ for i, ep in enumerate(endpoints): rule_name = f"endpoint_{i}_{ep['name'].replace(' ', '_')}" script += f""" # Rule for {ep['name']} $MBIN/action fwrules/add \\ --name "{rule_name}" \\ --source "any" \\ --destination "{ep['internal_ip']}" \\ --port "{ep['port']}" \\ --protocol "{ep['protocol']}" \\ --action "accept" """ script += """ echo "Firewall rules configured." $MBIN/action config/save echo "Configuration saved." """ return script def create_provisioning_package( gateway_name: str, vpn_server: str, vpn_port: int, ca_cert: str, client_cert: str, client_key: str, endpoints: list[dict], output_dir: str = "." ) -> dict: """Create a complete provisioning package. Args: gateway_name: Name of the gateway vpn_server: VPN server address vpn_port: VPN server port ca_cert: CA certificate content client_cert: Client certificate content client_key: Client private key content endpoints: List of endpoint configurations output_dir: Output directory for files Returns: Dictionary with file paths """ from pathlib import Path output_path = Path(output_dir) output_path.mkdir(parents=True, exist_ok=True) config = GatewayConfig( name=gateway_name, vpn_server=vpn_server, vpn_port=vpn_port, ca_cert=ca_cert, client_cert=client_cert, client_key=client_key ) # Generate OpenVPN config ovpn_content = ConfigGenerator.generate_openvpn_config(config) ovpn_file = output_path / f"{gateway_name}.ovpn" ovpn_file.write_text(ovpn_content) # Generate firewall script fw_script = ConfigGenerator.generate_mguard_script(gateway_name, endpoints) fw_file = output_path / f"{gateway_name}_firewall.sh" fw_file.write_text(fw_script) # Generate info JSON info = { "gateway_name": gateway_name, "vpn_server": vpn_server, "vpn_port": vpn_port, "endpoints": endpoints } info_file = output_path / f"{gateway_name}_info.json" info_file.write_text(json.dumps(info, indent=2)) return { "ovpn": str(ovpn_file), "firewall_script": str(fw_file), "info": str(info_file) }