wip: peers

This commit is contained in:
Constantin
2025-09-13 18:56:00 +03:00
parent 3e8a1bd530
commit 4f65f95ac9
6 changed files with 1634 additions and 100 deletions
+51 -14
View File
@@ -154,16 +154,16 @@ def clear_log_context(exc):
request_context.set({})
# Initialize managers with proper directories
network_manager = NetworkManager(data_dir='./data', config_dir='./config')
wireguard_manager = WireGuardManager(data_dir='./data', config_dir='./config')
peer_registry = PeerRegistry(data_dir='./data', config_dir='./config')
email_manager = EmailManager(data_dir='./data', config_dir='./config')
calendar_manager = CalendarManager(data_dir='./data', config_dir='./config')
file_manager = FileManager(data_dir='./data', config_dir='./config')
routing_manager = RoutingManager(data_dir='./data', config_dir='./config')
cell_manager = CellManager(data_dir='./data', config_dir='./config')
app.vault_manager = VaultManager(data_dir='./data', config_dir='./config')
container_manager = ContainerManager(data_dir='./data', config_dir='./config')
network_manager = NetworkManager(data_dir='/app/data', config_dir='/app/config')
wireguard_manager = WireGuardManager(data_dir='/app/data', config_dir='/app/config')
peer_registry = PeerRegistry(data_dir='/app/data', config_dir='/app/config')
email_manager = EmailManager(data_dir='/app/data', config_dir='/app/config')
calendar_manager = CalendarManager(data_dir='/app/data', config_dir='/app/config')
file_manager = FileManager(data_dir='/app/data', config_dir='/app/config')
routing_manager = RoutingManager(data_dir='/app/data', config_dir='/app/config')
cell_manager = CellManager(data_dir='/app/data', config_dir='/app/config')
app.vault_manager = VaultManager(data_dir='/app/data', config_dir='/app/config')
container_manager = ContainerManager(data_dir='/app/data', config_dir='/app/config')
# Register services with service bus
service_bus.register_service('network', network_manager)
@@ -839,12 +839,43 @@ def get_peer_config():
if data is None or 'name' not in data:
return jsonify({"error": "Missing peer name"}), 400
# For now, return not implemented - this would need to be implemented
return jsonify({"error": "Not implemented yet"}), 501
peer_name = data['name']
# Get peer from peer registry
peer = peer_registry.get_peer(peer_name)
if not peer:
return jsonify({"config": "Peer not found"})
# Get server configuration
server_config = wireguard_manager.get_server_config()
# Generate client configuration using peer registry data
config = f"""[Interface]
PrivateKey = {peer.get('private_key', 'YOUR_PRIVATE_KEY_HERE')}
Address = {peer.get('ip', '10.0.0.2')}/32
DNS = 8.8.8.8, 1.1.1.1
[Peer]
PublicKey = {server_config.get('public_key', 'SERVER_PUBLIC_KEY_PLACEHOLDER')}
Endpoint = {server_config.get('endpoint', 'YOUR_SERVER_IP:51820')}
AllowedIPs = {peer.get('allowed_ips', '0.0.0.0/0')}
PersistentKeepalive = {peer.get('persistent_keepalive', 25)}"""
return jsonify({"config": config})
except Exception as e:
logger.error(f"Error getting peer config: {e}")
return jsonify({"error": str(e)}), 500
@app.route('/api/wireguard/server-config', methods=['GET'])
def get_server_config():
try:
# Get server configuration from WireGuard manager
config = wireguard_manager.get_server_config()
return jsonify(config)
except Exception as e:
logger.error(f"Error getting server config: {e}")
return jsonify({"error": str(e)}), 500
# Peer Registry API
@app.route('/api/peers', methods=['GET'])
def get_peers():
@@ -870,11 +901,17 @@ def add_peer():
if field not in data:
return jsonify({"error": f"Missing required field: {field}"}), 400
# Add peer to registry
# Add peer to registry with all provided fields
peer_info = {
'peer': data['name'],
'ip': data['ip'],
'public_key': data['public_key']
'public_key': data['public_key'],
'private_key': data.get('private_key'),
'server_public_key': data.get('server_public_key'),
'server_endpoint': data.get('server_endpoint'),
'allowed_ips': data.get('allowed_ips'),
'persistent_keepalive': data.get('persistent_keepalive'),
'description': data.get('description')
}
success = peer_registry.add_peer(peer_info)
+290 -1
View File
@@ -371,4 +371,293 @@ AllowedIPs = {allowed_ips}
return True
except Exception as e:
logger.error(f"Failed to restart WireGuard service: {e}")
return False
return False
def get_peer_config(self, peer_name: str) -> Optional[str]:
"""Get WireGuard client configuration for a specific peer"""
try:
# Get peer information
peers = self.get_wireguard_peers()
peer_info = None
for peer in peers:
if peer.get('name') == peer_name:
peer_info = peer
break
if not peer_info:
logger.warning(f"Peer {peer_name} not found")
return None
# Get server configuration
server_config = self._get_server_config()
# Generate client configuration
client_config = self._generate_client_config(peer_info, server_config)
return client_config
except Exception as e:
logger.error(f"Error getting peer config for {peer_name}: {e}")
return None
def _get_server_config(self) -> Dict[str, str]:
"""Get server configuration details"""
try:
# Try to read server config file
server_config_path = os.path.join(self.wg_config_dir, 'wg_confs', 'wg0.conf')
if os.path.exists(server_config_path):
with open(server_config_path, 'r') as f:
content = f.read()
# Parse server configuration
lines = content.strip().split('\n')
server_public_key = None
server_endpoint = None
server_private_key = None
# Look for server private key and endpoint
for line in lines:
line = line.strip()
if line.startswith('PrivateKey'):
server_private_key = line.split('=', 1)[1].strip()
elif line.startswith('ListenPort'):
port = line.split('=', 1)[1].strip()
# Get server IP from environment or detect it
server_ip = os.environ.get('WIREGUARD_SERVER_IP')
if not server_ip:
# Try to get the actual external IP
try:
import socket
import requests
# First try to get external IP from a service
try:
response = requests.get('https://api.ipify.org', timeout=5)
if response.status_code == 200:
server_ip = response.text.strip()
else:
raise Exception("Failed to get external IP")
except Exception:
# Fallback: try to get local IP that's not Docker internal
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
# If it's a Docker internal IP, use localhost for development
if local_ip.startswith('172.') or local_ip.startswith('192.168.'):
server_ip = "localhost"
else:
server_ip = local_ip
except Exception:
# Ultimate fallback to localhost for development
server_ip = "localhost"
server_endpoint = f"{server_ip}:{port}"
# Generate public key from private key if we have it
if server_private_key:
try:
# Use wg pubkey command to generate public key from private key
import subprocess
result = subprocess.run(['wg', 'pubkey'],
input=server_private_key,
capture_output=True, text=True, timeout=5)
if result.returncode == 0:
server_public_key = result.stdout.strip()
else:
# Fallback: try to read from existing public key file
pubkey_path = os.path.join(self.wg_config_dir, 'publickey')
if os.path.exists(pubkey_path):
with open(pubkey_path, 'r') as f:
server_public_key = f.read().strip()
else:
server_public_key = "SERVER_PUBLIC_KEY_PLACEHOLDER"
except Exception as e:
logger.warning(f"Could not generate public key: {e}")
server_public_key = "SERVER_PUBLIC_KEY_PLACEHOLDER"
else:
server_public_key = "SERVER_PUBLIC_KEY_PLACEHOLDER"
# Set default endpoint if not found
if not server_endpoint:
# Try to get the actual server IP
server_ip = os.environ.get('WIREGUARD_SERVER_IP')
if not server_ip:
# Try to get the actual external IP
try:
import socket
import requests
# First try to get external IP from a service
try:
response = requests.get('https://api.ipify.org', timeout=5)
if response.status_code == 200:
server_ip = response.text.strip()
else:
raise Exception("Failed to get external IP")
except Exception:
# Fallback: try to get local IP that's not Docker internal
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
# If it's a Docker internal IP, use localhost for development
if local_ip.startswith('172.') or local_ip.startswith('192.168.'):
server_ip = "localhost"
else:
server_ip = local_ip
except Exception:
# Ultimate fallback to localhost for development
server_ip = "localhost"
server_endpoint = f"{server_ip}:51820"
return {
'public_key': server_public_key,
'endpoint': server_endpoint,
'allowed_ips': '0.0.0.0/0'
}
except Exception as e:
logger.error(f"Error reading server config: {e}")
# Return default values
return {
'public_key': 'SERVER_PUBLIC_KEY_PLACEHOLDER',
'endpoint': 'YOUR_SERVER_IP:51820',
'allowed_ips': '0.0.0.0/0'
}
def _generate_client_config(self, peer_info: Dict[str, Any], server_config: Dict[str, str]) -> str:
"""Generate WireGuard client configuration"""
try:
# Get peer private key from peer data
peer_private_key = peer_info.get('private_key', 'YOUR_PRIVATE_KEY_HERE')
config = f"""[Interface]
PrivateKey = {peer_private_key}
Address = {peer_info.get('ip', '10.0.0.2')}/32
DNS = 8.8.8.8, 1.1.1.1
[Peer]
PublicKey = {server_config['public_key']}
Endpoint = {server_config['endpoint']}
AllowedIPs = {server_config['allowed_ips']}
PersistentKeepalive = {peer_info.get('persistent_keepalive', 25)}"""
return config
except Exception as e:
logger.error(f"Error generating client config: {e}")
return None
def get_server_config(self) -> Dict[str, str]:
"""Get server configuration details"""
try:
# Try to read server config file
server_config_path = os.path.join(self.wg_config_dir, 'wg_confs', 'wg0.conf')
logger.info(f"Looking for server config at: {server_config_path}")
logger.info(f"wg_config_dir is: {self.wg_config_dir}")
logger.info(f"File exists: {os.path.exists(server_config_path)}")
if os.path.exists(server_config_path):
with open(server_config_path, 'r') as f:
content = f.read()
# Parse server configuration
lines = content.strip().split('\n')
server_public_key = None
server_endpoint = None
server_private_key = None
# Look for server private key and endpoint
for line in lines:
line = line.strip()
if line.startswith('PrivateKey'):
server_private_key = line.split('=', 1)[1].strip()
logger.info(f"Found server private key: {server_private_key[:10]}...")
elif line.startswith('ListenPort'):
port = line.split('=', 1)[1].strip()
logger.info(f"Found listen port: {port}")
# Get server IP from environment or detect it
server_ip = os.environ.get('WIREGUARD_SERVER_IP')
if not server_ip:
# Try to get the actual external IP
try:
import socket
import requests
# First try to get external IP from a service
try:
response = requests.get('https://api.ipify.org', timeout=5)
if response.status_code == 200:
server_ip = response.text.strip()
logger.info(f"Got external IP from service: {server_ip}")
else:
raise Exception("Failed to get external IP")
except Exception:
# Fallback: try to get local IP that's not Docker internal
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
# If it's a Docker internal IP, use localhost for development
if local_ip.startswith('172.') or local_ip.startswith('192.168.'):
server_ip = "localhost"
logger.info(f"Using localhost for development (Docker internal IP: {local_ip})")
else:
server_ip = local_ip
logger.info(f"Using local IP: {server_ip}")
except Exception:
# Ultimate fallback to localhost for development
server_ip = "localhost"
logger.info("Using localhost as ultimate fallback")
server_endpoint = f"{server_ip}:{port}"
logger.info(f"Set server endpoint: {server_endpoint}")
# Generate public key from private key if we have it
if server_private_key:
try:
logger.info("Generating public key from private key...")
# Use wg pubkey command to generate public key from private key
import subprocess
result = subprocess.run(['wg', 'pubkey'],
input=server_private_key,
capture_output=True, text=True, timeout=5)
if result.returncode == 0:
server_public_key = result.stdout.strip()
logger.info(f"Generated server public key: {server_public_key[:10]}...")
else:
# Fallback: try to read from existing public key file
pubkey_path = os.path.join(self.wg_config_dir, 'publickey')
if os.path.exists(pubkey_path):
with open(pubkey_path, 'r') as f:
server_public_key = f.read().strip()
else:
server_public_key = "SERVER_PUBLIC_KEY_PLACEHOLDER"
except Exception as e:
logger.warning(f"Could not generate public key: {e}")
server_public_key = "SERVER_PUBLIC_KEY_PLACEHOLDER"
else:
server_public_key = "SERVER_PUBLIC_KEY_PLACEHOLDER"
# Set default endpoint if not found
if not server_endpoint:
# Try to get the actual server IP
server_ip = os.environ.get('WIREGUARD_SERVER_IP')
if not server_ip:
# Try to get the host IP from Docker network
try:
import socket
# Connect to a remote address to determine local IP
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
server_ip = s.getsockname()[0]
except Exception:
# Fallback to localhost
server_ip = "localhost"
server_endpoint = f"{server_ip}:51820"
return {
'public_key': server_public_key,
'endpoint': server_endpoint
}
except Exception as e:
logger.error(f"Error reading server config: {e}")
# Return default values
return {
'public_key': 'SERVER_PUBLIC_KEY_PLACEHOLDER',
'endpoint': 'YOUR_SERVER_IP:51820'
}