add security fixes, port hardening, and expanded QA coverage
Security fixes: - Replace debug=True with env-driven FLASK_DEBUG in app.py - Add _safe_path helper and path-traversal protection to all 6 file routes in file_manager.py - Add peer_name regex and input validation (public_key, name, endpoint_ip) in wireguard_manager.py - Stop returning private key from GET /api/wireguard/keys; return only public_key + has_private_key boolean - Fix is_local_request() XFF bypass by checking remote_addr only, ignoring X-Forwarded-For - Remove duplicate get_all_configs / get_config_summary methods from config_manager.py DevOps: - Bind 6 internal service ports to 127.0.0.1 in docker-compose.yml (radicale, webdav, api, webui, rainloop, filegator) - Move WebDAV credentials to env vars (WEBDAV_USER, WEBDAV_PASS) - Pin flask, flask-cors, requests, cryptography, docker to secure minimum versions in requirements.txt QA (560 tests, 0 failures): - tests/test_wireguard_endpoints.py: 18 new endpoint tests - tests/test_file_endpoints.py: 24 new endpoint tests incl. path traversal - tests/test_container_manager.py: expanded from 2 to 30 tests - tests/test_config_backup_restore_http.py: 25 new tests (new file) - tests/test_config_apply.py: 9 new tests (new file) Docs: - Rewrite README.md with accurate architecture, ports, env vars, security notes - Rewrite QUICKSTART.md with verified commands Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ WireGuard Manager for Personal Internet Cell
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import base64
|
||||
import socket
|
||||
@@ -92,6 +93,8 @@ class WireGuardManager(BaseServiceManager):
|
||||
|
||||
def generate_peer_keys(self, peer_name: str) -> Dict[str, str]:
|
||||
"""Generate a keypair for a peer, save to keys_dir/peers/, return as base64."""
|
||||
if not isinstance(peer_name, str) or not re.match(r'^[A-Za-z0-9_.-]{1,64}$', peer_name):
|
||||
raise ValueError(f"Invalid peer_name: {peer_name!r}")
|
||||
priv_bytes, pub_bytes = self._generate_keypair()
|
||||
priv_b64 = base64.b64encode(priv_bytes).decode()
|
||||
pub_b64 = base64.b64encode(pub_bytes).decode()
|
||||
@@ -332,7 +335,16 @@ class WireGuardManager(BaseServiceManager):
|
||||
Passing full-tunnel or split-tunnel CIDRs here would cause the server
|
||||
to route all internet or LAN traffic to that peer — breaking everything.
|
||||
"""
|
||||
import ipaddress
|
||||
import ipaddress, re as _re
|
||||
if not isinstance(public_key, str) or not _re.match(r'^[A-Za-z0-9+/]{43}=$', public_key.strip()):
|
||||
return False # invalid WireGuard public key
|
||||
if name and not _re.match(r'^[A-Za-z0-9_. -]{1,64}$', name):
|
||||
return False # reject names with newlines/brackets
|
||||
if endpoint_ip:
|
||||
try:
|
||||
ipaddress.ip_address(endpoint_ip.strip())
|
||||
except ValueError:
|
||||
return False
|
||||
try:
|
||||
# Enforce /32: reject any CIDR wider than a single host
|
||||
for cidr in (c.strip() for c in allowed_ips.split(',')):
|
||||
|
||||
Reference in New Issue
Block a user