Replaces yt-dlp bashrc snippet with broader mediatools aliases/functions and adds a couple of standalone scripts (protonvpn-cli, audio-grabber).
748 lines
24 KiB
Bash
748 lines
24 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# ProtonVPN CLI Tool
|
|
# Path: ~/bin/protonvpn-cli or /usr/local/bin/protonvpn-cli
|
|
#
|
|
# Purpose: Command-line interface for managing ProtonVPN WireGuard connections
|
|
# Provides nordvpn-like functionality: auto-connect, country selection, speed testing
|
|
#
|
|
# Usage:
|
|
# protonvpn-cli connect [country] - Connect to fastest server (optionally from specific country)
|
|
# protonvpn-cli disconnect - Disconnect from current server
|
|
# protonvpn-cli status - Show connection status
|
|
# protonvpn-cli list [countries] - List available servers or countries
|
|
# protonvpn-cli update - Update server configurations
|
|
# protonvpn-cli speedtest - Test speeds of available servers
|
|
# protonvpn-cli help - Show this help message
|
|
|
|
set -euo pipefail
|
|
|
|
# Configuration
|
|
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly CONFIG_DIR="${HOME}/.config/protonvpn-cli"
|
|
readonly CONFIGS_DIR="${CONFIG_DIR}/configs"
|
|
readonly STATE_FILE="${CONFIG_DIR}/state.json"
|
|
readonly SPEED_CACHE="${CONFIG_DIR}/speeds.json"
|
|
readonly GENERATOR_SCRIPT="${SCRIPT_DIR}/protonvpn_generator.py"
|
|
readonly LOG_FILE="${CONFIG_DIR}/protonvpn-cli.log"
|
|
|
|
# Colors for output
|
|
readonly RED='\033[0;31m'
|
|
readonly GREEN='\033[0;32m'
|
|
readonly YELLOW='\033[1;33m'
|
|
readonly BLUE='\033[0;34m'
|
|
readonly CYAN='\033[0;36m'
|
|
readonly BOLD='\033[1m'
|
|
readonly NC='\033[0m' # No Color
|
|
|
|
# Global variables
|
|
VERBOSE=false
|
|
DRY_RUN=false
|
|
CURRENT_CONNECTION=""
|
|
|
|
#######################################
|
|
# Print colored status messages to stderr
|
|
# Arguments:
|
|
# $1 - log level (INFO, WARN, ERROR, SUCCESS)
|
|
# $2+ - message
|
|
#######################################
|
|
print_status() {
|
|
local level="$1"
|
|
shift
|
|
local timestamp
|
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
case "$level" in
|
|
"INFO")
|
|
echo -e "${BLUE}[INFO]${NC} $*" >&2
|
|
;;
|
|
"WARN")
|
|
echo -e "${YELLOW}[WARN]${NC} $*" >&2
|
|
;;
|
|
"ERROR")
|
|
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
;;
|
|
"SUCCESS")
|
|
echo -e "${GREEN}[SUCCESS]${NC} $*" >&2
|
|
;;
|
|
"DEBUG")
|
|
if [[ "$VERBOSE" == "true" ]]; then
|
|
echo -e "${CYAN}[DEBUG]${NC} $*" >&2
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# Log to file
|
|
echo "[$timestamp] [$level] $*" >> "$LOG_FILE"
|
|
}
|
|
|
|
#######################################
|
|
# Check if a command exists
|
|
# Arguments:
|
|
# $1 - command name
|
|
# Returns:
|
|
# 0 if command exists, 1 otherwise
|
|
#######################################
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
#######################################
|
|
# Check system dependencies
|
|
#######################################
|
|
check_dependencies() {
|
|
print_status "DEBUG" "Checking system dependencies..."
|
|
|
|
local missing_deps=()
|
|
|
|
# Essential commands
|
|
for cmd in wg wg-quick jq curl ping; do
|
|
if ! command_exists "$cmd"; then
|
|
missing_deps+=("$cmd")
|
|
fi
|
|
done
|
|
|
|
# Python for generator script
|
|
if ! command_exists python3; then
|
|
missing_deps+=("python3")
|
|
fi
|
|
|
|
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
|
print_status "ERROR" "Missing required dependencies: ${missing_deps[*]}"
|
|
print_status "INFO" "Install with: sudo apt update && sudo apt install wireguard-tools jq curl iputils-ping python3"
|
|
return 1
|
|
fi
|
|
|
|
# Check if running as root for WireGuard operations
|
|
if [[ $EUID -ne 0 ]] && [[ "${1:-}" != "list" ]] && [[ "${1:-}" != "status" ]] && [[ "${1:-}" != "help" ]]; then
|
|
print_status "WARN" "WireGuard operations require root privileges"
|
|
print_status "INFO" "Try: sudo $0 $*"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
#######################################
|
|
# Initialize configuration directory
|
|
#######################################
|
|
init_config() {
|
|
print_status "DEBUG" "Initializing configuration directory..."
|
|
|
|
mkdir -p "$CONFIG_DIR" "$CONFIGS_DIR"
|
|
|
|
# Create state file if it doesn't exist
|
|
if [[ ! -f "$STATE_FILE" ]]; then
|
|
echo '{"current_connection": "", "last_update": 0}' > "$STATE_FILE"
|
|
fi
|
|
|
|
# Create speed cache if it doesn't exist
|
|
if [[ ! -f "$SPEED_CACHE" ]]; then
|
|
echo '{}' > "$SPEED_CACHE"
|
|
fi
|
|
|
|
# Ensure log file exists
|
|
touch "$LOG_FILE"
|
|
}
|
|
|
|
#######################################
|
|
# Get current connection status
|
|
# Returns:
|
|
# Connection info or empty string
|
|
#######################################
|
|
get_connection_status() {
|
|
local active_interface
|
|
active_interface=$(wg show 2>/dev/null | grep -E '^interface:' | head -1 | cut -d' ' -f2 || true)
|
|
|
|
if [[ -n "$active_interface" ]]; then
|
|
# Extract server info from interface name (assuming format like wg-CH-01)
|
|
local server_info
|
|
server_info=$(echo "$active_interface" | sed 's/^wg-//')
|
|
echo "$server_info"
|
|
else
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
#######################################
|
|
# Parse WireGuard config to extract server info
|
|
# Arguments:
|
|
# $1 - config file path
|
|
#######################################
|
|
parse_config_info() {
|
|
local config_file="$1"
|
|
local server_name endpoint country
|
|
|
|
server_name=$(basename "$config_file" .conf)
|
|
endpoint=$(grep -E '^Endpoint' "$config_file" | cut -d'=' -f2 | tr -d ' ' | cut -d':' -f1)
|
|
|
|
# Extract country from filename (assuming format like wg-CH-01)
|
|
country=$(echo "$server_name" | sed 's/^wg-//' | cut -d'-' -f1)
|
|
|
|
echo "$server_name|$endpoint|$country"
|
|
}
|
|
|
|
#######################################
|
|
# List available servers or countries
|
|
# Arguments:
|
|
# $1 - "countries" to list countries, otherwise list servers
|
|
#######################################
|
|
list_servers() {
|
|
local list_type="${1:-servers}"
|
|
|
|
if [[ ! -d "$CONFIGS_DIR" ]] || [[ -z "$(ls -A "$CONFIGS_DIR" 2>/dev/null)" ]]; then
|
|
print_status "WARN" "No server configurations found. Run 'protonvpn update' first."
|
|
return 1
|
|
fi
|
|
|
|
case "$list_type" in
|
|
"countries")
|
|
print_status "INFO" "Available countries:"
|
|
local countries=()
|
|
while IFS= read -r -d '' config; do
|
|
local info
|
|
info=$(parse_config_info "$config")
|
|
local country
|
|
country=$(echo "$info" | cut -d'|' -f3)
|
|
countries+=("$country")
|
|
done < <(find "$CONFIGS_DIR" -name "*.conf" -print0)
|
|
|
|
# Sort and deduplicate countries
|
|
printf '%s\n' "${countries[@]}" | sort -u | while read -r country; do
|
|
printf " %s\n" "$country"
|
|
done
|
|
;;
|
|
*)
|
|
print_status "INFO" "Available servers:"
|
|
printf "%-20s %-15s %-10s %s\n" "SERVER" "ENDPOINT" "COUNTRY" "STATUS"
|
|
printf "%-20s %-15s %-10s %s\n" "------" "--------" "-------" "------"
|
|
|
|
local current_server
|
|
current_server=$(get_connection_status)
|
|
|
|
while IFS= read -r -d '' config; do
|
|
local info
|
|
info=$(parse_config_info "$config")
|
|
IFS='|' read -r server_name endpoint country <<< "$info"
|
|
|
|
local status="Available"
|
|
if [[ "$server_name" == *"$current_server"* ]] && [[ -n "$current_server" ]]; then
|
|
status="${GREEN}Connected${NC}"
|
|
fi
|
|
|
|
printf "%-20s %-15s %-10s %s\n" "$server_name" "$endpoint" "$country" "$status"
|
|
done < <(find "$CONFIGS_DIR" -name "*.conf" -print0 | sort -z)
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#######################################
|
|
# Test server speed/latency
|
|
# Arguments:
|
|
# $1 - server endpoint IP
|
|
# Returns:
|
|
# Latency in milliseconds or 9999 if unreachable
|
|
#######################################
|
|
test_server_speed() {
|
|
local endpoint="$1"
|
|
local latency
|
|
|
|
print_status "DEBUG" "Testing latency to $endpoint..."
|
|
|
|
# Use ping to test latency (3 packets, 2 second timeout)
|
|
if latency=$(ping -c 3 -W 2 "$endpoint" 2>/dev/null | tail -1 | awk -F '/' '{print $5}' 2>/dev/null); then
|
|
if [[ -n "$latency" ]]; then
|
|
printf "%.0f" "$latency"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# If ping fails, return high latency
|
|
echo "9999"
|
|
return 1
|
|
}
|
|
|
|
#######################################
|
|
# Find fastest server
|
|
# Arguments:
|
|
# $1 - optional country filter
|
|
# Returns:
|
|
# Path to fastest server config
|
|
#######################################
|
|
find_fastest_server() {
|
|
local country_filter="${1:-}"
|
|
local best_config=""
|
|
local best_latency=9999
|
|
local tested_count=0
|
|
local max_tests=10 # Limit tests for performance
|
|
|
|
print_status "INFO" "Finding fastest server${country_filter:+ in $country_filter}..."
|
|
|
|
# Create array of matching configs
|
|
local configs=()
|
|
while IFS= read -r -d '' config; do
|
|
if [[ -n "$country_filter" ]]; then
|
|
local info
|
|
info=$(parse_config_info "$config")
|
|
local country
|
|
country=$(echo "$info" | cut -d'|' -f3)
|
|
if [[ "$country" == "$country_filter" ]]; then
|
|
configs+=("$config")
|
|
fi
|
|
else
|
|
configs+=("$config")
|
|
fi
|
|
done < <(find "$CONFIGS_DIR" -name "*.conf" -print0)
|
|
|
|
if [[ ${#configs[@]} -eq 0 ]]; then
|
|
print_status "ERROR" "No servers found${country_filter:+ for country $country_filter}"
|
|
return 1
|
|
fi
|
|
|
|
# Shuffle array to test random subset
|
|
local shuffled_configs=()
|
|
while [[ ${#configs[@]} -gt 0 ]]; do
|
|
local index=$((RANDOM % ${#configs[@]}))
|
|
shuffled_configs+=("${configs[$index]}")
|
|
unset 'configs[$index]'
|
|
configs=("${configs[@]}") # Re-index array
|
|
done
|
|
|
|
# Test servers
|
|
for config in "${shuffled_configs[@]}"; do
|
|
if [[ $tested_count -ge $max_tests ]]; then
|
|
break
|
|
fi
|
|
|
|
local info
|
|
info=$(parse_config_info "$config")
|
|
local server_name endpoint
|
|
IFS='|' read -r server_name endpoint _ <<< "$info"
|
|
|
|
local latency
|
|
latency=$(test_server_speed "$endpoint")
|
|
|
|
print_status "DEBUG" "Server $server_name: ${latency}ms"
|
|
|
|
if (( $(echo "$latency < $best_latency" | bc -l 2>/dev/null || echo "$latency -lt $best_latency") )); then
|
|
best_latency=$latency
|
|
best_config="$config"
|
|
fi
|
|
|
|
((tested_count++))
|
|
done
|
|
|
|
if [[ -n "$best_config" ]]; then
|
|
local info
|
|
info=$(parse_config_info "$best_config")
|
|
local server_name
|
|
server_name=$(echo "$info" | cut -d'|' -f1)
|
|
print_status "SUCCESS" "Fastest server: $server_name (${best_latency}ms)"
|
|
echo "$best_config"
|
|
return 0
|
|
else
|
|
print_status "ERROR" "Could not find accessible server"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
#######################################
|
|
# Connect to VPN server
|
|
# Arguments:
|
|
# $1 - optional country or specific server
|
|
#######################################
|
|
connect_vpn() {
|
|
local target="${1:-}"
|
|
local config_file=""
|
|
|
|
# Check if already connected
|
|
local current_connection
|
|
current_connection=$(get_connection_status)
|
|
if [[ -n "$current_connection" ]]; then
|
|
print_status "INFO" "Already connected to $current_connection"
|
|
print_status "INFO" "Disconnect first with: protonvpn disconnect"
|
|
return 1
|
|
fi
|
|
|
|
# Determine which server to connect to
|
|
if [[ -z "$target" ]]; then
|
|
# Auto-select fastest server
|
|
config_file=$(find_fastest_server)
|
|
elif [[ -f "$CONFIGS_DIR/wg-${target}.conf" ]]; then
|
|
# Specific server by name
|
|
config_file="$CONFIGS_DIR/wg-${target}.conf"
|
|
print_status "INFO" "Using specific server: $target"
|
|
elif [[ ${#target} -eq 2 ]] && [[ "$target" =~ ^[A-Z]{2}$ ]]; then
|
|
# Country code - find fastest in country
|
|
config_file=$(find_fastest_server "$target")
|
|
else
|
|
# Try to find server containing the target string
|
|
local matches
|
|
mapfile -t matches < <(find "$CONFIGS_DIR" -name "*${target}*" -name "*.conf")
|
|
|
|
if [[ ${#matches[@]} -eq 1 ]]; then
|
|
config_file="${matches[0]}"
|
|
elif [[ ${#matches[@]} -gt 1 ]]; then
|
|
print_status "ERROR" "Multiple servers match '$target':"
|
|
for match in "${matches[@]}"; do
|
|
local info
|
|
info=$(parse_config_info "$match")
|
|
printf " %s\n" "$(echo "$info" | cut -d'|' -f1)" >&2
|
|
done
|
|
return 1
|
|
else
|
|
print_status "ERROR" "No server found matching '$target'"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$config_file" ]]; then
|
|
print_status "ERROR" "Failed to determine server configuration"
|
|
return 1
|
|
fi
|
|
|
|
# Extract interface name from config file
|
|
local interface_name
|
|
interface_name=$(basename "$config_file" .conf)
|
|
|
|
print_status "INFO" "Connecting to $(parse_config_info "$config_file" | cut -d'|' -f1)..."
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
print_status "INFO" "DRY RUN: Would execute: wg-quick up $config_file"
|
|
return 0
|
|
fi
|
|
|
|
# Connect using wg-quick
|
|
if wg-quick up "$config_file" >/dev/null 2>&1; then
|
|
# Update state file
|
|
jq --arg conn "$(parse_config_info "$config_file" | cut -d'|' -f1)" \
|
|
'.current_connection = $conn' "$STATE_FILE" > "${STATE_FILE}.tmp" && \
|
|
mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
|
|
print_status "SUCCESS" "Connected to $(parse_config_info "$config_file" | cut -d'|' -f1)"
|
|
|
|
# Show connection info
|
|
show_status
|
|
else
|
|
print_status "ERROR" "Failed to connect to VPN"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
#######################################
|
|
# Disconnect from VPN
|
|
#######################################
|
|
disconnect_vpn() {
|
|
local current_connection
|
|
current_connection=$(get_connection_status)
|
|
|
|
if [[ -z "$current_connection" ]]; then
|
|
print_status "INFO" "Not connected to any VPN server"
|
|
return 0
|
|
fi
|
|
|
|
print_status "INFO" "Disconnecting from $current_connection..."
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
print_status "INFO" "DRY RUN: Would disconnect from all WireGuard interfaces"
|
|
return 0
|
|
fi
|
|
|
|
# Disconnect all WireGuard interfaces
|
|
local interfaces
|
|
mapfile -t interfaces < <(wg show 2>/dev/null | grep -E '^interface:' | cut -d' ' -f2 || true)
|
|
|
|
local disconnected=false
|
|
for interface in "${interfaces[@]}"; do
|
|
if wg-quick down "$interface" >/dev/null 2>&1; then
|
|
print_status "SUCCESS" "Disconnected from $interface"
|
|
disconnected=true
|
|
fi
|
|
done
|
|
|
|
if [[ "$disconnected" == "true" ]]; then
|
|
# Update state file
|
|
jq '.current_connection = ""' "$STATE_FILE" > "${STATE_FILE}.tmp" && \
|
|
mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
else
|
|
print_status "WARN" "No active connections found to disconnect"
|
|
fi
|
|
}
|
|
|
|
#######################################
|
|
# Show current connection status
|
|
#######################################
|
|
show_status() {
|
|
local current_connection
|
|
current_connection=$(get_connection_status)
|
|
|
|
if [[ -n "$current_connection" ]]; then
|
|
print_status "INFO" "Status: ${GREEN}Connected${NC}"
|
|
printf "Server: %s\n" "$current_connection" >&2
|
|
|
|
# Show WireGuard interface details
|
|
if command_exists wg && [[ "$VERBOSE" == "true" ]]; then
|
|
print_status "DEBUG" "WireGuard interface details:"
|
|
wg show 2>/dev/null | while IFS= read -r line; do
|
|
printf " %s\n" "$line" >&2
|
|
done
|
|
fi
|
|
|
|
# Test current connection
|
|
if command_exists curl; then
|
|
local public_ip
|
|
if public_ip=$(curl -s --max-time 5 ifconfig.me 2>/dev/null); then
|
|
printf "Public IP: %s\n" "$public_ip" >&2
|
|
fi
|
|
fi
|
|
else
|
|
print_status "INFO" "Status: ${RED}Disconnected${NC}"
|
|
fi
|
|
}
|
|
|
|
#######################################
|
|
# Update server configurations
|
|
#######################################
|
|
update_configs() {
|
|
if [[ ! -f "$GENERATOR_SCRIPT" ]]; then
|
|
print_status "ERROR" "Generator script not found: $GENERATOR_SCRIPT"
|
|
print_status "INFO" "Please ensure the ProtonVPN generator script is available"
|
|
return 1
|
|
fi
|
|
|
|
print_status "INFO" "Updating server configurations..."
|
|
print_status "WARN" "This may take a while due to API rate limiting..."
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
print_status "INFO" "DRY RUN: Would run generator script to update configs"
|
|
return 0
|
|
fi
|
|
|
|
# Update OUTPUT_DIR in generator script to point to our configs directory
|
|
local temp_script="${CONFIG_DIR}/temp_generator.py"
|
|
sed "s|OUTPUT_DIR = \"./configs\"|OUTPUT_DIR = \"$CONFIGS_DIR\"|" "$GENERATOR_SCRIPT" > "$temp_script"
|
|
|
|
if python3 "$temp_script"; then
|
|
print_status "SUCCESS" "Server configurations updated"
|
|
|
|
# Update state file with last update time
|
|
jq --arg time "$(date +%s)" '.last_update = ($time | tonumber)' "$STATE_FILE" > "${STATE_FILE}.tmp" && \
|
|
mv "${STATE_FILE}.tmp" "$STATE_FILE"
|
|
|
|
# Clean up
|
|
rm -f "$temp_script"
|
|
else
|
|
print_status "ERROR" "Failed to update configurations"
|
|
rm -f "$temp_script"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
#######################################
|
|
# Run speed tests on available servers
|
|
#######################################
|
|
run_speedtest() {
|
|
local country_filter="${1:-}"
|
|
|
|
print_status "INFO" "Running speed tests${country_filter:+ for $country_filter}..."
|
|
|
|
# Create results array
|
|
declare -a results
|
|
local count=0
|
|
|
|
while IFS= read -r -d '' config; do
|
|
local info
|
|
info=$(parse_config_info "$config")
|
|
IFS='|' read -r server_name endpoint country <<< "$info"
|
|
|
|
# Apply country filter if specified
|
|
if [[ -n "$country_filter" ]] && [[ "$country" != "$country_filter" ]]; then
|
|
continue
|
|
fi
|
|
|
|
local latency
|
|
latency=$(test_server_speed "$endpoint")
|
|
|
|
results+=("$latency|$server_name|$endpoint|$country")
|
|
((count++))
|
|
|
|
printf "." >&2 # Progress indicator
|
|
done < <(find "$CONFIGS_DIR" -name "*.conf" -print0)
|
|
|
|
printf "\n" >&2
|
|
|
|
if [[ $count -eq 0 ]]; then
|
|
print_status "WARN" "No servers found to test"
|
|
return 1
|
|
fi
|
|
|
|
# Sort results by latency and display
|
|
printf "\n%-20s %-15s %-10s %s\n" "SERVER" "ENDPOINT" "COUNTRY" "LATENCY" >&2
|
|
printf "%-20s %-15s %-10s %s\n" "------" "--------" "-------" "-------" >&2
|
|
|
|
printf '%s\n' "${results[@]}" | sort -t'|' -k1 -n | while IFS='|' read -r latency server_name endpoint country; do
|
|
local latency_display
|
|
if [[ "$latency" == "9999" ]]; then
|
|
latency_display="${RED}Timeout${NC}"
|
|
else
|
|
latency_display="${latency}ms"
|
|
fi
|
|
printf "%-20s %-15s %-10s %s\n" "$server_name" "$endpoint" "$country" "$latency_display" >&2
|
|
done
|
|
}
|
|
|
|
#######################################
|
|
# Show help message
|
|
#######################################
|
|
show_help() {
|
|
cat >&2 << 'EOF'
|
|
ProtonVPN CLI - WireGuard VPN Manager
|
|
|
|
USAGE:
|
|
protonvpn <command> [options]
|
|
|
|
COMMANDS:
|
|
connect [target] Connect to VPN server
|
|
- No target: auto-select fastest server
|
|
- Country code (e.g., US, CH): fastest in country
|
|
- Server name: specific server
|
|
|
|
disconnect Disconnect from current VPN server
|
|
|
|
status Show current connection status
|
|
|
|
list [countries] List available servers or countries
|
|
|
|
update Update server configurations from ProtonVPN
|
|
|
|
speedtest [country] Test latency of available servers
|
|
|
|
help Show this help message
|
|
|
|
GLOBAL OPTIONS:
|
|
-v, --verbose Enable verbose output
|
|
-n, --dry-run Show what would be done without executing
|
|
-h, --help Show help message
|
|
|
|
EXAMPLES:
|
|
protonvpn connect # Connect to fastest available server
|
|
protonvpn connect US # Connect to fastest US server
|
|
protonvpn connect CH-01 # Connect to specific server
|
|
protonvpn list countries # List available countries
|
|
protonvpn speedtest CH # Test Swiss servers
|
|
protonvpn status # Show connection status
|
|
protonvpn disconnect # Disconnect from VPN
|
|
|
|
CONFIGURATION:
|
|
Config files: ~/.config/protonvpn/
|
|
WireGuard configs: ~/.config/protonvpn/configs/
|
|
|
|
REQUIREMENTS:
|
|
- wireguard-tools (wg, wg-quick)
|
|
- jq (JSON processing)
|
|
- curl (IP detection)
|
|
- bc (calculations)
|
|
- Root privileges for connection operations
|
|
|
|
EOF
|
|
}
|
|
|
|
#######################################
|
|
# Main function
|
|
#######################################
|
|
main() {
|
|
# Parse global options first
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-v|--verbose)
|
|
VERBOSE=true
|
|
shift
|
|
;;
|
|
-n|--dry-run)
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
-*)
|
|
print_status "ERROR" "Unknown option: $1"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Initialize configuration
|
|
init_config
|
|
|
|
# Get command
|
|
local command="${1:-help}"
|
|
shift || true
|
|
|
|
# Check dependencies for most commands
|
|
if ! check_dependencies "$command"; then
|
|
exit 1
|
|
fi
|
|
|
|
# Execute command
|
|
case "$command" in
|
|
"connect"|"c")
|
|
connect_vpn "$@"
|
|
;;
|
|
"disconnect"|"d")
|
|
disconnect_vpn
|
|
;;
|
|
"status"|"s")
|
|
show_status
|
|
;;
|
|
"list"|"l")
|
|
list_servers "$@"
|
|
;;
|
|
"update"|"u")
|
|
update_configs
|
|
;;
|
|
"speedtest"|"speed"|"test")
|
|
run_speedtest "$@"
|
|
;;
|
|
"split")
|
|
case "${1:-}" in
|
|
"enable"|"disable")
|
|
jq --arg enabled "$([[ "$1" == "enable" ]] && echo true || echo false)" '.enabled = ($enabled == "true")' "$SPLIT_TUNNEL_CONFIG" > "${SPLIT_TUNNEL_CONFIG}.tmp" && mv "${SPLIT_TUNNEL_CONFIG}.tmp" "$SPLIT_TUNNEL_CONFIG"
|
|
print_status "SUCCESS" "Split tunneling $1d"
|
|
;;
|
|
"add-local")
|
|
local network="${2:-}"
|
|
if [[ -n "$network" ]]; thenupda
|
|
jq --arg net "$network" '.local_networks += [$net] | .local_networks |= unique' "$SPLIT_TUNNEL_CONFIG" > "${SPLIT_TUNNEL_CONFIG}.tmp" && mv "${SPLIT_TUNNEL_CONFIG}.tmp" "$SPLIT_TUNNEL_CONFIG"
|
|
print_status "SUCCESS" "Added local network: $network"
|
|
fi
|
|
;;
|
|
"list")
|
|
print_status "INFO" "Split tunneling configuration:"
|
|
jq '.' "$SPLIT_TUNNEL_CONFIG"
|
|
;;
|
|
*)
|
|
print_status "ERROR" "Unknown split command. Use: enable|disable|add-local|list"
|
|
;;
|
|
esac
|
|
;;
|
|
"help"|"h"|"--help")
|
|
show_help
|
|
;;
|
|
*)
|
|
print_status "ERROR" "Unknown command: $command"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Execute main function if script is run directly
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
main "$@"
|
|
fi
|