Last active
February 9, 2023 12:38
-
-
Save jonasjancarik/d5b73a1c1274defd290304db1cb0dfaf to your computer and use it in GitHub Desktop.
ProtonVPN from Terminal - use a random config file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
echo -e "\n\nDownloading custom ProtonVPN scripts...\n\n" | |
curl -s -o ~/protonvpn.sh "https://gist.githubusercontent.com/jonasjancarik/d5b73a1c1274defd290304db1cb0dfaf/raw/protonvpn.sh?$RANDOM" | |
chmod +x ~/protonvpn.sh | |
curl -s -o ~/Desktop/protonvpn_script.desktop "https://gist.githubusercontent.com/jonasjancarik/d5b73a1c1274defd290304db1cb0dfaf/raw/protonvpn_script.desktop?$RANDOM" | |
chmod 755 ~/Desktop/protonvpn_script.desktop | |
gio set ~/Desktop/protonvpn_script.desktop metadata::trusted true | |
curl -s -o ~/Desktop/protonvpn_disconnect.desktop "https://gist.githubusercontent.com/jonasjancarik/d5b73a1c1274defd290304db1cb0dfaf/raw/protonvpn_disconnect.desktop?$RANDOM" | |
chmod 755 ~/Desktop/protonvpn_disconnect.desktop | |
gio set ~/Desktop/protonvpn_disconnect.desktop metadata::trusted true | |
echo -e "\n\n\e[32m$(tput bold)The script is now installed.$(tput sgr0)\e[0m \nUse the \"ProtonVPN (Free)\" shortcut on the desktop to launch it.\n\n" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
################ | |
# Auto-update # | |
################ | |
# Get the path of the currently installed script | |
current_script_path=~/protonvpn.sh | |
# Get the hash of the currently installed script | |
current_script_hash=$(sha256sum $current_script_path | awk '{print $1}') | |
# Download the latest version of this script | |
latest_script_hash=$(set -o pipefail && curl -s https://gist.githubusercontent.com/jonasjancarik/d5b73a1c1274defd290304db1cb0dfaf/raw/protonvpn.sh?$RANDOM | sha256sum | awk '{print $1}') | |
# Check if the curl command was successful | |
if [ $? -ne 0 ]; then | |
echo "${YELLOW}WARNING${ENDCOLOR}: unable to check for updates." | |
else | |
# Compare the hashes of the two scripts | |
if [ ! "$current_script_hash" == "$latest_script_hash" ]; then | |
read -p "Update available, do you want to download it? (yes/no)" response | |
if [ "$(echo "$response" | tr '[:upper:]' '[:lower:]')" == "yes" ]; then | |
echo -e "\nDownloading update to ~/Downloads/protonvpn_install.sh..." | |
curl -s https://gist.githubusercontent.com/jonasjancarik/d5b73a1c1274defd290304db1cb0dfaf/raw/install.sh?$RANDOM > ~/Downloads/protonvpn_install.sh | |
chmod +x ~/Downloads/protonvpn_install.sh | |
echo -e "\nUpdate downloaded, running the install script..." | |
exec ~/Downloads/protonvpn_install.sh # also exits the current script | |
else | |
echo "Update skipped." | |
fi | |
fi | |
fi | |
################ | |
# Main script # | |
################ | |
zip_file=~/Downloads/ProtonVPN_server_configs.zip | |
config_dir=~/protonvpn_configs | |
checksum_file="$config_dir/checksum.txt" | |
auth_fail_counter_file="$config_dir/auth_fail_counter.txt" | |
# colors | |
RED="\e[31m" | |
GREEN="\e[32m" | |
YELLOW="\e[33m" | |
ENDCOLOR="\e[0m" | |
child_process_exit_code="" | |
# https://www.baeldung.com/linux/background-process-get-exit-code | |
handle_sigchld() { | |
if [ -n "$pid" -a ! -d "/proc/$pid" ]; then | |
wait $pid | |
child_process_exit_code=$? | |
# echo pid $pid terminated with exit code $child_process_exit_code | |
unset pid | |
fi | |
} | |
extract_files() { | |
# create the target directory if it doesn't exist | |
mkdir -p "$config_dir" | |
# remove all .ovpn files from the target directory | |
find "$config_dir" -type f -name "*.ovpn" -delete 2>/dev/null | |
# extract the files, silently | |
# unzip -q -o "$zip_file" -d "$config_dir" 'jp*' | |
unzip -q -o "$zip_file" -d "$config_dir" | |
# store the new checksum | |
echo "$new_checksum" >"$checksum_file" | |
} | |
retry_prompt_result="" | |
retry_prompt() { | |
# ask user to retry or exit | |
read -p "Retry? (yes/no)" response | |
if [ "$(echo "$response" | tr '[:upper:]' '[:lower:]')" == "yes" ]; then | |
retry_prompt_result="true" | |
else | |
retry_prompt_result="false" | |
echo "Exiting..." | |
exit 1 | |
fi | |
} | |
check_zip_file() { | |
config_files=$(find "$config_dir" -type f -name "*.ovpn" 2>/dev/null) | |
if [ -f "$zip_file" ]; then | |
# zip file exists | |
# calculate checksum of the zip file | |
new_checksum=$(sha256sum "$zip_file" | awk '{print $1}') | |
if [[ $(find "$zip_file" -mtime +30) ]]; then | |
echo -e "${YELLOW}WARNING${ENDCOLOR}: The ProtonVPN server configs zip file is older than 30 days. It is recommended to download a new one." | |
fi | |
if [ -f "$checksum_file" ]; then | |
# read stored checksum | |
old_checksum=$(cat "$checksum_file") | |
# compare new and stored checksums | |
if [ "$new_checksum" != "$old_checksum" ]; then | |
# checksums are different, extract the files | |
extract_files | |
fi | |
else | |
# checksum file doesn't exist, extract the files | |
extract_files | |
fi | |
else | |
# zip file doesn't exist | |
if [[ -z "$config_files" ]]; then | |
echo -e "\n${RED}ERROR${ENDCOLOR}: No .ovpn config files found in the $config_dir directory. The configs zip file has to be in ~/Downloads to create those." | |
echo -e "\nPlease download it from https://account.protonvpn.com/downloads#openvpn-configuration-files under OpenVPN configuration files. \n\n Choose these options: \n 1. Select platform: GNU/Linux \n 2. Select protocol: UDP \n 3. Select config file and download: Free server configs \n 4. Click on Download all configurations under the table. \n\n Make sure the downloaded file is in the Downloads folder and that its name is ProtonVPN_server_configs.zip. \n " | |
# ask user to retry or exit | |
retry_prompt | |
if [ "$retry_prompt_result" == "true" ]; then | |
check_zip_file | |
fi | |
else | |
echo -e "\n${YELLOW}WARNING${ENDCOLOR}: The ProtonVPN server configs zip file was not found. It should be in the ~/Downloads directory to help keep the configs up-to-date. \n\n Please download it from https://account.protonvpn.com/downloads#openvpn-configuration-files under OpenVPN configuration files. \n\n Choose these options: \n 1. Select platform: GNU/Linux \n 2. Select protocol: UDP \n 3. Select config file and download: Free server configs \n 4. Click on Download all configurations under the table. \n\n Make sure the downloaded file is in the Downloads folder and that its name is ProtonVPN_server_configs.zip. \n " | |
fi | |
fi | |
} | |
check_zip_file | |
if ! ls "$config_dir"/*.ovpn 1>/dev/null 2>&1; then | |
echo -e "\n${YELLOW}WARNING${ENDCOLOR}: No configuration files found in the directory $config_dir. Trying to get them from the downloaded configs file...\n" | |
extract_files | |
fi | |
# Check if the current version of update-resolv-conf script is different from the one at GitHub | |
update_resolv_conf_file="/etc/openvpn/update-resolv-conf" | |
update_resolv_conf_url="https://raw.githubusercontent.com/ProtonVPN/scripts/master/update-resolv-conf.sh" | |
if [ -f "$update_resolv_conf_file" ]; then | |
local_hash=$(sha256sum "$update_resolv_conf_file" | awk '{print $1}') | |
remote_hash=$(wget -qO- "$update_resolv_conf_url" | sha256sum | awk '{print $1}') | |
if [ "$local_hash" != "$remote_hash" ]; then | |
echo "Backing up the current version of update-resolv-conf script to $update_resolv_conf_file.bak" | |
sudo cp "$update_resolv_conf_file" "$update_resolv_conf_file.bak" | |
sudo wget "$update_resolv_conf_url" -O "$update_resolv_conf_file" | |
sudo chmod +x "$update_resolv_conf_file" | |
fi | |
else | |
sudo wget "$update_resolv_conf_url" -O "$update_resolv_conf_file" | |
sudo chmod +x "$update_resolv_conf_file" | |
fi | |
# check if the credentials.txt file exists, if not, ask the user to provide credentials | |
credentials_file="$config_dir/credentials.txt" | |
if [ ! -f "$credentials_file" ]; then | |
echo -e "We need special login details for this - i.e. not your regular ProtonVPN password. Get them from the OpenVPN/IKEv2 username section at https://account.protonvpn.com/account#openvpn\n" | |
read -p "Username: " username | |
read -p "Password: " password | |
echo "$username" >"$credentials_file" | |
echo "$password" >>"$credentials_file" | |
rm -f "$auth_fail_counter_file" | |
fi | |
if ! sudo -n true 2>/dev/null; then | |
echo -e "Please enter your password to enable the connection: " | |
# dummy sudo command to enable sudo for this session | |
sudo -v | |
fi | |
attempt_counter=0 | |
random_config_file="" | |
no_config_files_left() { | |
# echo a message starting with an empty line | |
echo -e "\n${RED}ERROR${ENDCOLOR}: No configuration files left in the directory $config_dir." | |
echo -e "Removing the configs zip file to prevent reusing outdated configs..." | |
rm -f $zip_file | |
echo -e "\nPlease download a new one from https://account.protonvpn.com/downloads#openvpn-configuration-files under OpenVPN configuration files. \n\n Choose these options: \n 1. Select platform: GNU/Linux \n 2. Select protocol: UDP \n 3. Select config file and download: Free server configs \n 4. Click on Download all configurations under the table. \n\n Make sure the downloaded file is in the Downloads folder and that its name is ProtonVPN_server_configs.zip. \n " | |
retry_prompt | |
if [ "$retry_prompt_result" == "true" ]; then | |
exec $current_script_path | |
else | |
exit 1 | |
fi | |
} | |
choose_country() { | |
# ask the user what country they want to connect through, JP, US or NL: | |
echo -e "\nPlease choose a country to connect through: \n 1. Japan \n 2. United States \n 3. Netherlands \n" | |
read -p "Enter a number: " country_number | |
if [ "$country_number" == "1" ]; then | |
country="jp" | |
country_full="Japan" | |
elif [ "$country_number" == "2" ]; then | |
country="us" | |
country_full="the United States" | |
elif [ "$country_number" == "3" ]; then | |
country="nl" | |
country_full="the Netherlands" | |
else | |
echo -e "\n${RED}ERROR${ENDCOLOR}: Invalid input. Please enter a number between 1 and 3.\n" | |
choose_country | |
fi | |
} | |
choose_country | |
echo -e "\n" | |
# start OpenVPN using the credentials file and the randomly chosen .ovpn file | |
while true; do | |
if ls "$config_dir"/*.ovpn 1>/dev/null 2>&1; then | |
# store a random config file in the variable random_config_file | |
random_config_file=$(find $config_dir -name "$country*.ovpn" | shuf -n 1) | |
else | |
no_config_files_left | |
fi | |
if [ "$attempt_counter" -ge 1 ]; then | |
echo -e "Trying configuration file: $random_config_file..." | |
fi | |
# create the logs directory if it doesn't exist | |
mkdir -p $config_dir/log | |
# clear the log file | |
truncate -s 0 $config_dir/log/openvpn.log | |
# kill any previously open OpenVPN processes - redirect errors to /dev/null | |
sudo killall openvpn 2>/dev/null | |
# count the number of lines in the config file which start with "remote " | |
# number_of_servers=$(grep -c "^remote " "$random_config_file") | |
# start OpenVPN in the background | |
# sudo openvpn --mute-replay-warnings --config "$random_config_file" --auth-user-pass $credentials_file --connect-timeout 10 --connect-retry-max 1 --resolv-retry $number_of_servers --log $config_dir/log/openvpn.log & | |
sudo openvpn --mute-replay-warnings --config "$random_config_file" --auth-user-pass $credentials_file --connect-timeout 10 --connect-retry 0 --connect-retry-max 1 --log $config_dir/log/openvpn.log & | |
# save the PID of the OpenVPN process | |
pid=$! | |
# echo $pid # for debugging | |
# Trap signals and kill the subprocess when the script is interrupted or terminated | |
trap "if ps -p $pid > /dev/null; then kill $pid; fi" SIGINT SIGTERM INT TERM SIGHUP EXIT | |
trap handle_sigchld SIGCHLD | |
connection_detected="false" | |
counter=0 | |
# wait for the OpenVPN process to finish | |
while kill -0 $pid 2> /dev/null; do | |
if ! $connection_detected; then | |
echo -ne "\r${YELLOW}Connecting through ${country_full} using ProtonVPN... (${counter} seconds)${ENDCOLOR}" | |
# increment counter | |
counter=$((counter+1)) | |
fi | |
# check if the connection was successful | |
if ! $connection_detected && sudo grep -q "Initialization Sequence Completed" "$config_dir/log/openvpn.log"; then | |
connection_detected="true" | |
echo -ne "\r" | |
tput el | |
echo -e "${GREEN}You are now connected through ${country_full} using ProtonVPN.${ENDCOLOR}" | |
echo -e "\r- To disconnect, press Ctrl+C" | |
echo -e "\r- If you just close this window, you may have to use the 'Disconnect ProtonVPN' shortcut on the desktop to actually disconnect." | |
echo "0" >> "$auth_fail_counter_file" | |
ip_api_response="" | |
get_ip_details() { | |
ip_api_response=$(curl -s http://ip-api.com/json/?fields=country,regionName,city,zip,lat,lon,isp,query) | |
} | |
api_details_obtained="false" | |
# try to get the IP details 5 times | |
for i in {1..5}; do | |
get_ip_details | |
if [ $? -eq 0 ]; then | |
api_details_obtained="true" | |
echo -e "\n\r" | |
# clear line | |
tput el | |
echo -e "You are connected through this location:" | |
query=$(echo $ip_api_response | jq -r '.query') | |
country=$(echo $ip_api_response | jq -r '.country') | |
regionName=$(echo $ip_api_response | jq -r '.regionName') | |
city=$(echo $ip_api_response | jq -r '.city') | |
zip=$(echo $ip_api_response | jq -r '.zip') | |
lat=$(echo $ip_api_response | jq -r '.lat') | |
lon=$(echo $ip_api_response | jq -r '.lon') | |
isp=$(echo $ip_api_response | jq -r '.isp') | |
org=$(echo $ip_api_response | jq -r '.org') | |
echo -en "\n\rIP:\t\t$query" | |
echo -en "\n\rCountry:\t$country" | |
echo -en "\n\rRegion:\t\t$regionName" | |
echo -en "\n\rCity:\t\t$city" | |
echo -en "\n\rZip:\t\t$zip" | |
echo -en "\n\rLat:\t\t$lat, lon: $lon" | |
echo -en "\n\rISP:\t\t$isp" | |
echo -en "\n\rOrg.:\t\t$org" | |
echo -e "\n\r" | |
break | |
fi | |
sleep 1 | |
done | |
fi | |
if ! $connection_detected; then | |
sleep 1 | |
fi | |
done | |
echo -e "\n" | |
echo -ne "\r" | |
# echo $pid # for debugging | |
# echo $! # for debugging | |
# echo $? # for debugging | |
# reset trap | |
trap - SIGINT SIGTERM | |
echo -e "\n" | |
if [ $child_process_exit_code -ne 0 ]; then | |
echo "OpenVPN connection failed." | |
if sudo grep -qE "(All connections have been connect-retry-max.*times unsuccessful, exiting)|(Cannot resolve host address)" "$config_dir/log/openvpn.log"; then | |
echo "The current configuration file is not working. Renaming it to ${random_config_file}_old" | |
mv "$random_config_file" "${random_config_file}_old" | |
if [ $(ls "$config_dir"/*.ovpn | wc -l) -eq 0 ]; then # todo: redirect errors | |
no_config_files_left | |
else | |
echo -e "\n\r" | |
read -p "Do you want to try again with a different configuration file? (yes/no)" answer | |
if [ "$(echo "$answer" | tr '[:upper:]' '[:lower:]')" != "yes" ]; then | |
echo "Exiting." | |
exit 0 | |
fi | |
attempt_counter=$((attempt_counter + 1)) | |
fi | |
else | |
echo -e "\n\rAn unknown error occurred. Exiting.\n\r" | |
read -n1 -p "Press any key to exit." | |
echo -e "\n\r" | |
exit 1 | |
fi | |
else | |
# for some reason auth fail does not exit with a non-zero exit code | |
if sudo grep -q "AUTH: Received control message: AUTH_FAILED" "$config_dir/log/openvpn.log"; then | |
echo -e "\n\rAuthentication failed." | |
# load the counter file | |
if [ ! -f "$auth_fail_counter_file" ]; then | |
echo "1" >> "$auth_fail_counter_file" | |
auth_fail_count=1 | |
echo -e "\rSometimes this is temporary. Please try again.\n" | |
else | |
auth_fail_count=$(cat "$auth_fail_counter_file") | |
auth_fail_count=$((auth_fail_count + 1)) | |
echo "$auth_fail_count" > "$auth_fail_counter_file" | |
read -p "This may be temporary, but your saved login details have already failed ${auth_fail_count} times. Would you like to remove them? (yes/no)" answer | |
if [ "$answer" = "yes" ]; then | |
mv "$credentials_file" "$credentials_file"_old | |
rm "$auth_fail_counter_file" | |
echo -e "Your login details have been removed (backed up to ${credentials_file}_old). Please try again." | |
exit 0 | |
fi | |
fi | |
read -n1 -p "Press any key to exit." | |
echo -e "\n" | |
exit 1 | |
fi | |
echo -e "\nOpenVPN connection closed.\n\r" | |
read -n1 -p "Press any key to exit." | |
echo -e "\n\r" | |
exit 0 | |
fi | |
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Desktop Entry] | |
Type=Application | |
Name=Disconnect ProtonVPN (Free) | |
Exec=sh -c "sudo killall openvpn 2>/dev/null" | |
Icon=gnome-globe-net | |
Terminal=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Desktop Entry] | |
Type=Application | |
Name=ProtonVPN (Free) | |
Exec=sh -c "~/protonvpn.sh" | |
Icon=gnome-globe-net | |
Terminal=true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Install with
curl -s "https://gist.githubusercontent.com/jonasjancarik/d5b73a1c1274defd290304db1cb0dfaf/raw/install.sh?$RANDOM" | bash