readme refreshed
This commit is contained in:
+35
-4
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user