k-vpn 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
k_vpn-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,66 @@
1
+ Metadata-Version: 2.3
2
+ Name: k-vpn
3
+ Version: 1.0.0
4
+ Summary: Automated CLI tool to fetch and connect to global VPN Gate servers securely.
5
+ Author: KpihX
6
+ License: MIT
7
+ Requires-Dist: typer>=0.9.0
8
+ Requires-Dist: rich>=13.0.0
9
+ Requires-Dist: requests>=2.0.0
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+
13
+ # k-vpn
14
+
15
+ **k-vpn** is a modern, automated CLI tool designed to easily fetch and connect to public VPN Gate servers directly from your terminal. Built with Python, Typer, and Rich, it offers a beautiful and interactive experience for securing your connection.
16
+
17
+ ## Features
18
+
19
+ - **Automated Fetching**: Retrieves the latest list of public VPN servers from VPN Gate.
20
+ - **Rich UI**: Displays server availability by country in a formatted table.
21
+ - **Interactive Selection**: Easily choose your desired country.
22
+ - **Secure Connection**: Automates the OpenVPN connection process using temporary configuration files.
23
+ - **Smart Defaults**: Filters for high-speed, uptime-reliable servers.
24
+
25
+ ## Prerequisites
26
+
27
+ - **Python 3.8+**
28
+ - **OpenVPN**: Must be installed and accessible via `sudo openvpn` on your system.
29
+ - **uv**: Recommended for project management and execution.
30
+
31
+ ## Installation & Usage
32
+
33
+ It is recommended to use `uv` to run this tool directly without manual environment setup.
34
+
35
+ 1. **Clone the repository:**
36
+ ```bash
37
+ git clone https://github.com/KpihX/k-vpn.git
38
+ cd k-vpn
39
+ ```
40
+
41
+ 2. **Run the tool:**
42
+ ```bash
43
+ uv run k-vpn.py
44
+ ```
45
+
46
+ The tool will verify your environment, fetch the server list, and present you with options.
47
+
48
+ ## How it Works
49
+
50
+ 1. **Fetch**: The tool downloads the CSV list from `http://www.vpngate.net/api/iphone/`.
51
+ 2. **Parse & Filter**: It parses the data, filtering for valid OpenVPN configurations.
52
+ 3. **Display**: Aggregates servers by country and displays a summary table (Country, Server Count).
53
+ 4. **Connect**:
54
+ * You select a country by its index.
55
+ * The tool picks the best server (based on score/speed) for that country.
56
+ * It decodes the base64 OpenVPN configuration.
57
+ * It creates a temporary `.ovpn` file.
58
+ * It executes `sudo openvpn --config <temp_file>` to establish the tunnel.
59
+
60
+ ## License
61
+
62
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
63
+
64
+ ## Disclaimer
65
+
66
+ This tool uses public servers from VPN Gate. The availability, speed, and security of these servers are not guaranteed by the author. Use at your own risk.
k_vpn-1.0.0/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # k-vpn
2
+
3
+ **k-vpn** is a modern, automated CLI tool designed to easily fetch and connect to public VPN Gate servers directly from your terminal. Built with Python, Typer, and Rich, it offers a beautiful and interactive experience for securing your connection.
4
+
5
+ ## Features
6
+
7
+ - **Automated Fetching**: Retrieves the latest list of public VPN servers from VPN Gate.
8
+ - **Rich UI**: Displays server availability by country in a formatted table.
9
+ - **Interactive Selection**: Easily choose your desired country.
10
+ - **Secure Connection**: Automates the OpenVPN connection process using temporary configuration files.
11
+ - **Smart Defaults**: Filters for high-speed, uptime-reliable servers.
12
+
13
+ ## Prerequisites
14
+
15
+ - **Python 3.8+**
16
+ - **OpenVPN**: Must be installed and accessible via `sudo openvpn` on your system.
17
+ - **uv**: Recommended for project management and execution.
18
+
19
+ ## Installation & Usage
20
+
21
+ It is recommended to use `uv` to run this tool directly without manual environment setup.
22
+
23
+ 1. **Clone the repository:**
24
+ ```bash
25
+ git clone https://github.com/KpihX/k-vpn.git
26
+ cd k-vpn
27
+ ```
28
+
29
+ 2. **Run the tool:**
30
+ ```bash
31
+ uv run k-vpn.py
32
+ ```
33
+
34
+ The tool will verify your environment, fetch the server list, and present you with options.
35
+
36
+ ## How it Works
37
+
38
+ 1. **Fetch**: The tool downloads the CSV list from `http://www.vpngate.net/api/iphone/`.
39
+ 2. **Parse & Filter**: It parses the data, filtering for valid OpenVPN configurations.
40
+ 3. **Display**: Aggregates servers by country and displays a summary table (Country, Server Count).
41
+ 4. **Connect**:
42
+ * You select a country by its index.
43
+ * The tool picks the best server (based on score/speed) for that country.
44
+ * It decodes the base64 OpenVPN configuration.
45
+ * It creates a temporary `.ovpn` file.
46
+ * It executes `sudo openvpn --config <temp_file>` to establish the tunnel.
47
+
48
+ ## License
49
+
50
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
51
+
52
+ ## Disclaimer
53
+
54
+ This tool uses public servers from VPN Gate. The availability, speed, and security of these servers are not guaranteed by the author. Use at your own risk.
@@ -0,0 +1,24 @@
1
+ [project]
2
+ name = "k-vpn"
3
+ version = "1.0.0"
4
+ description = "Automated CLI tool to fetch and connect to global VPN Gate servers securely."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "KpihX" }
8
+ ]
9
+ license = { text = "MIT" }
10
+ requires-python = ">=3.8"
11
+ dependencies = [
12
+ "typer>=0.9.0",
13
+ "rich>=13.0.0",
14
+ "requests>=2.0.0"
15
+ ]
16
+
17
+ [project.scripts]
18
+ k-vpn = "k_vpn.main:app"
19
+
20
+ [build-system]
21
+ requires = [
22
+ "uv_build>=0.9.21,<0.10.0",
23
+ ]
24
+ build-backend = "uv_build"
File without changes
@@ -0,0 +1,221 @@
1
+ import sys
2
+ import os
3
+ import csv
4
+ import base64
5
+ import tempfile
6
+ import subprocess
7
+ import requests
8
+ import typer
9
+ from rich.console import Console
10
+ from rich.table import Table
11
+ from rich.progress import Progress, SpinnerColumn, TextColumn
12
+ from rich.panel import Panel
13
+ from rich.prompt import Prompt
14
+ from rich import print as rprint
15
+ from typing import List, Dict, Any
16
+
17
+ app = typer.Typer(help="k-vpn: Automated VPN Gate Connector")
18
+ console = Console()
19
+
20
+ VPN_GATE_API_URL = "http://www.vpngate.net/api/iphone/"
21
+
22
+ def fetch_vpn_servers() -> List[Dict[str, Any]]:
23
+ """Fetches and parses VPN servers from VPN Gate API."""
24
+ try:
25
+ with Progress(
26
+ SpinnerColumn(),
27
+ TextColumn("[bold green]Fetching VPN server list..."),
28
+ transient=True,
29
+ ) as progress:
30
+ progress.add_task("fetch", total=None)
31
+ response = requests.get(VPN_GATE_API_URL, timeout=30)
32
+ response.raise_for_status()
33
+
34
+ # The API returns a CSV file with a header and '*' lines at the end
35
+ content = response.text
36
+ lines = content.splitlines()
37
+
38
+ # Remove comments/garbage lines (lines starting with '*' or '#')
39
+ # Keep the header line which starts with 'HostName' usually, but in the raw response
40
+ # the second line is usually the header. Let's inspect typical response.
41
+ # Typical response starts with "*vpn_servers\n#HostName,..."
42
+
43
+ csv_lines = [line for line in lines if not line.startswith('*')]
44
+
45
+ if not csv_lines:
46
+ console.print("[bold red]Error:[/bold red] Empty response from VPN Gate.")
47
+ sys.exit(1)
48
+
49
+ # The header usually starts with #HostName, strip the #
50
+ if csv_lines[0].startswith('#'):
51
+ csv_lines[0] = csv_lines[0][1:]
52
+
53
+ reader = csv.DictReader(csv_lines)
54
+ servers = []
55
+ for row in reader:
56
+ if row.get('OpenVPN_ConfigData_Base64'):
57
+ servers.append(row)
58
+
59
+ return servers
60
+
61
+ except requests.RequestException as e:
62
+ console.print(f"[bold red]Network Error:[/bold red] {e}")
63
+ sys.exit(1)
64
+ except Exception as e:
65
+ console.print(f"[bold red]Error parsing data:[/bold red] {e}")
66
+ sys.exit(1)
67
+
68
+ def group_by_country(servers: List[Dict[str, Any]]) -> Dict[str, List[Dict[str, Any]]]:
69
+ """Groups servers by country."""
70
+ grouped = {}
71
+ for server in servers:
72
+ country = server.get('CountryLong', 'Unknown')
73
+ if country not in grouped:
74
+ grouped[country] = []
75
+ grouped[country].append(server)
76
+ return grouped
77
+
78
+ @app.command()
79
+ def main():
80
+ """
81
+ Fetch VPN Gate servers and connect to a selected country.
82
+ """
83
+ console.print(Panel.fit("[bold cyan]k-vpn[/bold cyan] - Secure World Connector", border_style="cyan"))
84
+
85
+ servers = fetch_vpn_servers()
86
+
87
+ if not servers:
88
+ console.print("[yellow]No servers found.[/yellow]")
89
+ return
90
+
91
+ grouped_servers = group_by_country(servers)
92
+ sorted_countries = sorted(grouped_servers.keys())
93
+
94
+ table = Table(title="Available Countries", show_header=True, header_style="bold magenta")
95
+ table.add_column("#", style="dim", width=4, justify="right")
96
+ table.add_column("Country", style="cyan")
97
+ table.add_column("Servers", justify="right")
98
+ table.add_column("Top Speed", justify="right")
99
+
100
+ for idx, country in enumerate(sorted_countries, 1):
101
+ country_servers = grouped_servers[country]
102
+ count = len(country_servers)
103
+ # Find max speed (Speed is in bps, convert to Mbps)
104
+ max_speed = max([int(s.get('Speed', 0)) for s in country_servers]) / 1000 / 1000
105
+ table.add_row(str(idx), country, str(count), f"{max_speed:.2f} Mbps")
106
+
107
+ console.print(table)
108
+
109
+ choice = Prompt.ask(
110
+ "\nSelect a country number (or 'q' to quit)",
111
+ default="q"
112
+ )
113
+
114
+ if choice.lower() == 'q':
115
+ console.print("[bold red]Exiting...[/bold red]")
116
+ raise typer.Exit()
117
+
118
+ try:
119
+ index = int(choice) - 1
120
+ if 0 <= index < len(sorted_countries):
121
+ selected_country = sorted_countries[index]
122
+ connect_to_country(selected_country, grouped_servers[selected_country])
123
+ else:
124
+ console.print("[bold red]Invalid selection.[/bold red]")
125
+ except ValueError:
126
+ console.print("[bold red]Invalid input.[/bold red]")
127
+
128
+ def connect_to_country(country_name: str, servers: List[Dict[str, Any]]):
129
+ """Selects the best server for the country and connects."""
130
+
131
+ # Sort by Score (descending) as a proxy for quality
132
+ # VPN Gate score formula considers uptime, speed, etc.
133
+ best_server = sorted(servers, key=lambda s: int(s.get('Score', 0)), reverse=True)[0]
134
+
135
+ ip = best_server.get('IP', 'Unknown')
136
+ speed = int(best_server.get('Speed', 0)) / 1000 / 1000
137
+
138
+ console.print(f"\n[bold green]Connecting to {country_name}...[/bold green]")
139
+ console.print(f"Server IP: [cyan]{ip}[/cyan] | Speed: [yellow]{speed:.2f} Mbps[/yellow]")
140
+
141
+ ovpn_data = base64.b64decode(best_server['OpenVPN_ConfigData_Base64'])
142
+
143
+ try:
144
+ # Create a directory for configs in user home to avoid /tmp permission issues with sudo/snap
145
+ config_dir = os.path.expanduser("~/.k-vpn/configs")
146
+ os.makedirs(config_dir, exist_ok=True)
147
+
148
+ # Create credentials file (VPN Gate standard: vpn/vpn)
149
+ creds_path = os.path.join(config_dir, "vpn_creds.txt")
150
+ with open(creds_path, "w") as f:
151
+ f.write("vpn\nvpn\n")
152
+ os.chmod(creds_path, 0o600) # Only readable by current user (and root via sudo)
153
+
154
+ # Create a temporary file for the config
155
+ with tempfile.NamedTemporaryFile(mode='wb', dir=config_dir, suffix='.ovpn', delete=False) as temp_config:
156
+ temp_config.write(ovpn_data)
157
+ config_path = temp_config.name
158
+
159
+ # Ensure the file is readable only by the user
160
+ os.chmod(config_path, 0o600)
161
+
162
+ console.print(f"[dim]Config saved to {config_path}[/dim]")
163
+ console.print("[bold yellow]Launching OpenVPN (sudo required)...[/bold yellow]")
164
+
165
+ # Run OpenVPN
166
+ # --data-ciphers-fallback and --data-ciphers with AES-128-CBC
167
+ # handles older servers on OpenVPN 2.6+
168
+ cmd = [
169
+ "sudo", "openvpn",
170
+ "--config", config_path,
171
+ "--auth-user-pass", creds_path,
172
+ "--data-ciphers", "AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305:AES-128-CBC",
173
+ "--data-ciphers-fallback", "AES-128-CBC"
174
+ ]
175
+
176
+ # Use Popen to monitor output in real-time
177
+ process = subprocess.Popen(
178
+ cmd,
179
+ stdout=subprocess.PIPE,
180
+ stderr=subprocess.STDOUT,
181
+ text=True,
182
+ bufsize=1
183
+ )
184
+
185
+ connected = False
186
+ for line in iter(process.stdout.readline, ""):
187
+ console.print(line.strip())
188
+
189
+ if "Initialization Sequence Completed" in line and not connected:
190
+ connected = True
191
+ console.print("\n")
192
+ console.print(Panel(
193
+ f"[bold green]✓ SUCCESSFULLY CONNECTED[/bold green]\n"
194
+ f"[bold white]Country:[/bold white] {country_name}\n"
195
+ f"[bold white]Server IP:[/bold white] [cyan]{ip}[/cyan]\n"
196
+ f"[bold white]Speed:[/bold white] [yellow]{speed:.2f} Mbps[/yellow]",
197
+ title="[bold green]VPN Active[/bold green]",
198
+ border_style="green",
199
+ expand=False
200
+ ))
201
+ console.print("[dim]Press CTRL+C to disconnect...[/dim]\n")
202
+
203
+ process.wait()
204
+
205
+ except KeyboardInterrupt:
206
+ console.print("\n[bold red]Disconnecting and cleaning up...[/bold red]")
207
+ if 'process' in locals():
208
+ # Send SIGTERM to the sudo process, which should relay it to OpenVPN
209
+ process.terminate()
210
+ except Exception as e:
211
+ console.print(f"[bold red]Connection failed:[/bold red] {e}")
212
+ finally:
213
+ # Cleanup
214
+ if 'config_path' in locals() and os.path.exists(config_path):
215
+ os.remove(config_path)
216
+ if 'creds_path' in locals() and os.path.exists(creds_path):
217
+ os.remove(creds_path)
218
+ console.print("[dim]Temporary files cleaned up.[/dim]")
219
+
220
+ if __name__ == "__main__":
221
+ app()