readme refreshed

This commit is contained in:
2026-02-05 08:50:11 +01:00
parent 1de7f5b593
commit 14b770af55
15 changed files with 1453 additions and 27 deletions
+35 -4
View File
@@ -1,6 +1,7 @@
"""Client configuration."""
import os
import sys
from pathlib import Path
# Application info
@@ -10,13 +11,43 @@ APP_VERSION = "1.0.0"
# Default server settings
DEFAULT_SERVER_URL = "http://localhost:8000"
# OpenVPN paths
# OpenVPN binary search paths by platform
OPENVPN_PATHS_WINDOWS = [
r"C:\Program Files\OpenVPN\bin\openvpn.exe",
r"C:\Program Files (x86)\OpenVPN\bin\openvpn.exe",
r"C:\Program Files\OpenVPN Connect\ovpnconnector.exe",
]
OPENVPN_PATHS_LINUX = [
"/usr/sbin/openvpn",
"/usr/bin/openvpn",
"/usr/local/sbin/openvpn",
"/usr/local/bin/openvpn",
"/opt/openvpn/sbin/openvpn",
"/snap/bin/openvpn",
]
OPENVPN_PATHS_MACOS = [
"/usr/local/sbin/openvpn",
"/usr/local/bin/openvpn",
"/opt/homebrew/bin/openvpn",
"/opt/homebrew/sbin/openvpn",
"/usr/local/opt/openvpn/sbin/openvpn",
]
# Determine platform
if os.name == 'nt': # Windows
OPENVPN_EXE = r"C:\Program Files\OpenVPN\bin\openvpn.exe"
OPENVPN_SEARCH_PATHS = OPENVPN_PATHS_WINDOWS
OPENVPN_CONFIG_DIR = Path.home() / "OpenVPN" / "config"
else: # Linux/Mac
OPENVPN_EXE = "/usr/sbin/openvpn"
elif sys.platform == 'darwin': # macOS
OPENVPN_SEARCH_PATHS = OPENVPN_PATHS_MACOS
OPENVPN_CONFIG_DIR = Path.home() / ".openvpn"
else: # Linux
OPENVPN_SEARCH_PATHS = OPENVPN_PATHS_LINUX
OPENVPN_CONFIG_DIR = Path.home() / ".openvpn"
# Legacy variable for compatibility
OPENVPN_EXE = OPENVPN_SEARCH_PATHS[0] if OPENVPN_SEARCH_PATHS else "openvpn"
# Ensure config directory exists
OPENVPN_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
+61 -16
View File
@@ -1,13 +1,15 @@
"""OpenVPN process management."""
import os
import sys
import shutil
import subprocess
import tempfile
from pathlib import Path
from typing import Optional
from dataclasses import dataclass
from config import OPENVPN_EXE, OPENVPN_CONFIG_DIR
from config import OPENVPN_SEARCH_PATHS, OPENVPN_CONFIG_DIR
@dataclass
@@ -25,27 +27,61 @@ class VPNManager:
self.process: Optional[subprocess.Popen] = None
self.config_file: Optional[Path] = None
self.log_file: Optional[Path] = None
self._openvpn_path: Optional[str] = None
def find_openvpn_binary(self) -> Optional[str]:
"""Find the OpenVPN binary on the system.
Searches platform-specific paths and returns the first found binary.
Returns None if not found.
"""
if self._openvpn_path:
return self._openvpn_path
# First, check configured search paths
for path in OPENVPN_SEARCH_PATHS:
if Path(path).exists() and Path(path).is_file():
self._openvpn_path = path
return path
# Try to find via PATH environment (works on all platforms)
openvpn_in_path = shutil.which("openvpn")
if openvpn_in_path:
self._openvpn_path = openvpn_in_path
return openvpn_in_path
# macOS: Check for Tunnelblick's bundled OpenVPN
if sys.platform == 'darwin':
tunnelblick_base = Path("/Applications/Tunnelblick.app/Contents/Resources/openvpn")
if tunnelblick_base.exists():
# Find latest openvpn version directory
for version_dir in sorted(tunnelblick_base.glob("openvpn-*"), reverse=True):
openvpn_binary = version_dir / "openvpn"
if openvpn_binary.exists():
self._openvpn_path = str(openvpn_binary)
return str(openvpn_binary)
return None
def check_openvpn_installed(self) -> bool:
"""Check if OpenVPN is installed."""
if os.name == 'nt':
return Path(OPENVPN_EXE).exists()
else:
try:
subprocess.run(["which", "openvpn"], capture_output=True, check=True)
return True
except subprocess.CalledProcessError:
return False
return self.find_openvpn_binary() is not None
def connect(self, config_content: str) -> VPNStatus:
"""Connect using provided OpenVPN config."""
if self.process and self.process.poll() is None:
return VPNStatus(connected=False, error="Already connected")
if not self.check_openvpn_installed():
openvpn_binary = self.find_openvpn_binary()
if not openvpn_binary:
return VPNStatus(
connected=False,
error="OpenVPN is not installed. Please install OpenVPN first."
error="OpenVPN is not installed. Please install OpenVPN first.\n\n"
"Installation:\n"
" Linux (Debian/Ubuntu): sudo apt install openvpn\n"
" Linux (Fedora/RHEL): sudo dnf install openvpn\n"
" macOS: brew install openvpn\n"
" Windows: Download from https://openvpn.net/community-downloads/"
)
# Write config to temp file
@@ -57,16 +93,15 @@ class VPNManager:
try:
if os.name == 'nt':
# Windows: Use OpenVPN GUI or direct call
# Note: Requires admin privileges
# Windows: Direct call (requires admin privileges)
self.process = subprocess.Popen(
[OPENVPN_EXE, "--config", str(self.config_file), "--log", str(self.log_file)],
[openvpn_binary, "--config", str(self.config_file), "--log", str(self.log_file)],
creationflags=subprocess.CREATE_NO_WINDOW
)
else:
# Linux: Use sudo openvpn
# Linux/macOS: Use sudo openvpn
self.process = subprocess.Popen(
["sudo", "openvpn", "--config", str(self.config_file), "--log", str(self.log_file)],
["sudo", openvpn_binary, "--config", str(self.config_file), "--log", str(self.log_file)],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
@@ -142,3 +177,13 @@ class VPNManager:
def is_connected(self) -> bool:
"""Check if VPN is connected."""
return self.process is not None and self.process.poll() is None
def get_openvpn_info(self) -> dict:
"""Get information about the OpenVPN installation."""
binary = self.find_openvpn_binary()
return {
"installed": binary is not None,
"path": binary,
"platform": sys.platform,
"search_paths": OPENVPN_SEARCH_PATHS
}