diff --git a/custom_pvpn_cli_ng/protonvpn_cli/connection.py b/custom_pvpn_cli_ng/protonvpn_cli/connection.py index ea8a0e4..932e0ad 100644 --- a/custom_pvpn_cli_ng/protonvpn_cli/connection.py +++ b/custom_pvpn_cli_ng/protonvpn_cli/connection.py @@ -162,7 +162,9 @@ def fastest(protocol=None, gui_enabled=False): server_pool.append(server) fastest_server = get_fastest_server(server_pool) - openvpn_connect(fastest_server, protocol, gui_enabled) + if gui_enabled: + return openvpn_connect(fastest_server, protocol, gui_enabled) + openvpn_connect(fastest_server, protocol) def country_f(country_code, protocol=None): @@ -348,7 +350,7 @@ def disconnect(passed=False): logger.debug("No connection found") -def status(): +def status(gui_enabled=False): """ Display the current VPN status diff --git a/protonvpn_linux_gui/constants.py b/protonvpn_linux_gui/constants.py index f5f1afc..569fa38 100644 --- a/protonvpn_linux_gui/constants.py +++ b/protonvpn_linux_gui/constants.py @@ -1,4 +1,4 @@ -VERSION = "1.1.5" +VERSION = "1.2.0" PATH_AUTOCONNECT_SERVICE = "/etc/systemd/system/protonvpn-autoconnect.service" TEMPLATE =""" [Unit] diff --git a/protonvpn_linux_gui/gui.py b/protonvpn_linux_gui/gui.py index cc3498f..1061797 100644 --- a/protonvpn_linux_gui/gui.py +++ b/protonvpn_linux_gui/gui.py @@ -3,6 +3,8 @@ import re import sys import pathlib +from threading import Thread +import time # ProtonVPN base CLI package import from custom_pvpn_cli_ng.protonvpn_cli.constants import (USER, CONFIG_FILE, CONFIG_DIR, VERSION) @@ -110,6 +112,9 @@ def connect_to_selected_server_button_clicked(self, button): connection.openvpn_connect(selected_server, protocol) update_labels_status(self.interface) + # def log_result(self, res): + # return res + def quick_connect_button_clicked(self, button): """Button/Event handler to connect to the fastest server """ @@ -138,9 +143,11 @@ def disconnect_button_clicked(self, button): def refresh_server_list_button_clicked(self, button): """Button/Event handler to refresh/repopulate server list + - At the moment, will also refresh the Dashboard information, this will be fixed in the future. """ server_list_object = self.interface.get_object("ServerListStore") populate_server_list(server_list_object) + update_labels_status(self.interface) def about_menu_button_clicked(self, button): """Button /Event handlerto open About dialog @@ -299,27 +306,20 @@ def purge_configurations_button_clicked(self, button): cli.purge_configuration(gui_enabled=True) class initialize_gui: - """Initializes a GUI - ----- - The GUI only makes external calls to the cli commands. - ----- - Will request for the same data protonvpn init to initialize a user: - -Username - -Password - -Plan - -Protocol - - There are two ways of starting this GUI, either by reversing the commented code so that it can be launched as part of the CLI: + """Initializes the GUI --- - -protonvpn gui: - This will start from within the main CLI menu. Gui is invoked through cli() - - Or leave it be as it is, and configuration is setup during installation with "pip3 install -e .", this way it can be launched as a separte command from the usual CLI: - -protonvpn-gui: - This will start the GUI without invoking cli() + If user has not initialized a profile, the GUI will ask for the following data: + - Username + - Password + - Plan + - Protocol + + sudo protonvpn-gui + - Will start the GUI without invoking cli() """ def __init__(self): check_root() + interface = Gtk.Builder() posixPath = pathlib.PurePath(pathlib.Path(__file__).parent.absolute().joinpath("resources/main.glade")) @@ -338,6 +338,7 @@ def __init__(self): window = interface.get_object("LoginWindow") else: window = interface.get_object("Dashboard") + window.connect("destroy", Gtk.main_quit) load_on_start(interface) window.show() diff --git a/protonvpn_linux_gui/resources/main.glade b/protonvpn_linux_gui/resources/main.glade index 9b08c17..68f6c36 100644 --- a/protonvpn_linux_gui/resources/main.glade +++ b/protonvpn_linux_gui/resources/main.glade @@ -1358,7 +1358,7 @@ ProtonVPN Unofficial GUI: calexandru2018 80 80 15 - 35 + 15 True 1 @@ -1387,157 +1387,507 @@ ProtonVPN Unofficial GUI: calexandru2018 True False - center + center 60 60 - 20 - 5 - - - -1 - True - False - start - False - VPN Status: - fill - - - - - - - 0 - 0 - - + True + 150 + True - - -1 + True False - start - True - DNS Protection: - fill - - - - + 30 + 20 + True + + + -1 + True + False + start + True + Time connected: + fill + + + + + + + 0 + 2 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 2 + + + + + -1 + True + False + start + False + VPN Status: + fill + + + + + + + 0 + 0 + + + + + -1 + True + False + start + True + Running + fill + + + + + + + 1 + 0 + + + + + -1 + True + False + start + True + DNS Protection: + fill + + + + + + + 0 + 1 + + + + + -1 + True + False + start + True + Custom + fill + + + + + + + 1 + 1 + + + + + -1 + True + False + start + True + Killswitch Setting: + fill + + + + + + + 0 + 3 + + + + + -1 + True + False + start + True + Protocol: + fill + + + + + + + 0 + 4 + + + + + -1 + True + False + start + True + Features: + fill + + + + + + + 0 + 5 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 3 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 4 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 5 + + 0 - 1 - - - - - -1 - True - False - start - True - Running - fill - - - - - - - - 1 - 0 - - - - - -1 - True - False - start - True - Custom - fill - - - - - - - - 1 - 1 - - - - - -1 - True - False - end - 40 - IP: - - - - - - - 2 0 + 2 + 10 - - -1 + True False - end - 40 - Country: - - - - + 100 + 20 + True + + + -1 + True + False + start + True + + + + + + + 1 + 0 + + + + + -1 + True + False + start + Country: + + + + + + + 0 + 4 + + + + + -1 + True + False + start + True + + + + + + + 1 + 4 + + + + + -1 + True + False + start + City: + + + + + + + 0 + 3 + + + + + -1 + True + False + start + Server: + + + + + + + 0 + 2 + + + + + -1 + True + False + start + Load: + + + + + + + 0 + 1 + + + + + -1 + True + False + start + Received: + + + + + + + 0 + 5 + + + + + -1 + True + False + start + Sent: + + + + + + + 0 + 6 + + + + + -1 + True + False + start + IP: + + + + + + + 0 + 0 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 1 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 2 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 3 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 5 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 6 + + 2 - 1 - - - - - -1 - True - False - start - True - - - - - - - 3 - 1 - - - - - -1 - True - False - start - True - - - - - - - 3 0 + 4 + 10 @@ -1549,6 +1899,8 @@ ProtonVPN Unofficial GUI: calexandru2018 + -1 + 4 True False 30 diff --git a/protonvpn_linux_gui/resources/main.glade~ b/protonvpn_linux_gui/resources/main.glade~ index 68dc6b0..7ab4f66 100644 --- a/protonvpn_linux_gui/resources/main.glade~ +++ b/protonvpn_linux_gui/resources/main.glade~ @@ -1358,7 +1358,7 @@ ProtonVPN Unofficial GUI: calexandru2018 80 80 15 - 35 + 15 True 1 @@ -1375,38 +1375,6 @@ ProtonVPN Unofficial GUI: calexandru2018 4 - - - Start on Boot - True - True - True - - - - 1 - 1 - - - - - Disable start on boot - True - True - True - - - - 2 - 1 - - - - - - - - False @@ -1419,157 +1387,510 @@ ProtonVPN Unofficial GUI: calexandru2018 True False - center + center 60 60 - 20 - 5 - - - -1 - True - False - start - False - VPN Status: - fill - - - - - - - 0 - 0 - - + True + 150 + True - - -1 + True False - start - True - DNS Protection: - fill - - - - + 30 + 20 + True + + + -1 + True + False + start + True + Time connected: + fill + + + + + + + 0 + 2 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 2 + + + + + -1 + True + False + start + False + VPN Status: + fill + + + + + + + 0 + 0 + + + + + -1 + True + False + start + True + Running + fill + + + + + + + 1 + 0 + + + + + -1 + True + False + start + True + DNS Protection: + fill + + + + + + + 0 + 1 + + + + + -1 + True + False + start + True + Custom + fill + + + + + + + 1 + 1 + + + + + -1 + True + False + start + True + Killswitch Setting: + fill + + + + + + + 0 + 3 + + + + + -1 + True + False + start + True + Protocol: + fill + + + + + + + 0 + 4 + + + + + -1 + True + False + start + True + Features: + fill + + + + + + + 0 + 5 + + + + + -1 + True + False + start + True + fill + + + + + + + + 1 + 3 + + + + + -1 + True + False + start + True + fill + + + + + + + + 1 + 4 + + + + + -1 + True + False + start + True + fill + + + + + + + + 1 + 5 + + 0 - 1 - - - - - -1 - True - False - start - True - Running - fill - - - - - - - - 1 - 0 - - - - - -1 - True - False - start - True - Custom - fill - - - - - - - - 1 - 1 - - - - - -1 - True - False - end - 40 - IP: - - - - - - - 2 0 + 2 + 10 - - -1 + True False - end - 40 - Country: - - - - + 100 + 20 + True + + + -1 + True + False + start + True + + + + + + + 1 + 0 + + + + + -1 + True + False + start + Country: + + + + + + + 0 + 4 + + + + + -1 + True + False + start + True + + + + + + + 1 + 4 + + + + + -1 + True + False + start + City: + + + + + + + 0 + 3 + + + + + -1 + True + False + start + Server: + + + + + + + 0 + 2 + + + + + -1 + True + False + start + Load: + + + + + + + 0 + 1 + + + + + -1 + True + False + start + Received: + + + + + + + 0 + 5 + + + + + -1 + True + False + start + Sent: + + + + + + + 0 + 6 + + + + + -1 + True + False + start + IP: + + + + + + + 0 + 0 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 1 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 2 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 3 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 5 + + + + + -1 + True + False + start + True + fill + + + + + + + 1 + 6 + + 2 - 1 - - - - - -1 - True - False - start - True - - - - - - - 3 - 1 - - - - - -1 - True - False - start - True - - - - - - - 3 0 + 4 + 10 @@ -1581,6 +1902,8 @@ ProtonVPN Unofficial GUI: calexandru2018 + -1 + 4 True False 30 diff --git a/protonvpn_linux_gui/utils.py b/protonvpn_linux_gui/utils.py index 675e8a3..0261c6c 100644 --- a/protonvpn_linux_gui/utils.py +++ b/protonvpn_linux_gui/utils.py @@ -3,6 +3,8 @@ import shutil import fileinput import subprocess +import time +import datetime from custom_pvpn_cli_ng.protonvpn_cli.utils import ( pull_server_data, @@ -13,9 +15,12 @@ set_config_value, check_root, is_connected, - get_ip_info + get_ip_info, + get_transferred_data ) +from custom_pvpn_cli_ng.protonvpn_cli.connection import status + from custom_pvpn_cli_ng.protonvpn_cli.constants import SPLIT_TUNNEL_FILE from .constants import PATH_AUTOCONNECT_SERVICE, TEMPLATE @@ -68,33 +73,128 @@ def load_on_start(interface): def update_labels_status(interface): """Updates labels status """ - vpn_status_label = interface.get_object("vpn_status_label") - dns_status_label = interface.get_object("dns_status_label") - ip_label = interface.get_object("ip_label") - country_label = interface.get_object("country_label") + servers = get_servers() + protonvpn_conn_check = is_connected() + is_vpn_connected = True if protonvpn_conn_check else False + try: + connected_server = get_config_value("metadata", "connected_server") + except: + connected_server = False + left_grid_update_labels(interface, servers, is_vpn_connected, connected_server) + right_grid_update_labels(interface, servers, is_vpn_connected, connected_server) + +def left_grid_update_labels(interface, servers, is_connected, connected_server): + """ + """ - # Check VPN status - if is_connected() != True: - vpn_status_label.set_markup('Not Running') + # Left grid + vpn_status_label = interface.get_object("vpn_status_label") + dns_status_label = interface.get_object("dns_status_label") + time_connected_label = interface.get_object("time_connected_label") + killswitch_label = interface.get_object("killswitch_label") + protocol_label = interface.get_object("openvpn_protocol_label") + server_features_label = interface.get_object("server_features_label") + + all_features = {0: "Normal", 1: "Secure-Core", 2: "Tor", 4: "P2P"} + connection_time = False + connected_to_protocol = False + + # Check and set VPN status label. Get also protocol status if vpn is connected + if is_connected != True: + vpn_status_label.set_markup('Disconnected') else: - vpn_status_label.set_markup('Running') + vpn_status_label.set_markup('Connected') + try: + connected_time = get_config_value("metadata", "connected_time") + connection_time = time.time() - int(connected_time) + connection_time = str(datetime.timedelta(seconds=connection_time)).split(".")[0] + connected_to_protocol = get_config_value("metadata", "connected_proto") + except KeyError: + connection_time = False + connected_to_protocol = False - # Check DNS status + # Check and set DNS status label dns_enabled = get_config_value("USER", "dns_leak_protection") if int(dns_enabled) != 1: dns_status_label.set_markup('Not Enabled') else: dns_status_label.set_markup('Enabled') - ip, isp, country = get_ip_info(gui_enbled=True) + # Set time connected label + connection_time = connection_time if connection_time else "" + time_connected_label.set_markup('{0}'.format(connection_time)) + + # Check and set killswitch label + connected_time = get_config_value("USER", "killswitch") + killswitch_status = "Enabled" if connected_time == 0 else "Disabled" + killswitch_label.set_markup('{0}'.format(killswitch_status)) + + # Check and set protocol label + connected_to_protocol = connected_to_protocol if connected_to_protocol else "" + protocol_label.set_markup('{0}'.format(connected_to_protocol)) + + # Check and set feature label + try: + feature = get_server_value(connected_server, "Features", servers) + except: + feature = False - ip = "" + ip + "" - country_isp = "" + country + "/" + isp + "" + feature = all_features[feature] if is_connected else "" + server_features_label.set_markup('{0}'.format(feature)) +def right_grid_update_labels(interface, servers, is_connected, connected_server): + """ + """ + + # Right grid + ip_label = interface.get_object("ip_label") + server_load_label = interface.get_object("server_load_label") + server_name_label = interface.get_object("server_name_label") + server_city_label = interface.get_object("server_city_label") + country_label = interface.get_object("country_label") + data_received_label = interface.get_object("data_received_label") + data_sent_label = interface.get_object("data_sent_label") + + tx_amount, rx_amount = get_transferred_data() + + # Get and set IP labels. Get also country and ISP + ip, isp, country = get_ip_info(gui_enbled=True) + country_isp = "" + country + "/" + isp + "" ip_label.set_markup(ip) + + # Get and set server load label + try: + load = get_server_value(connected_server, "Load", servers) + except: + load = False + load = "{0}%".format(load) if load and is_connected else "" + server_load_label.set_markup('{0}'.format(load)) + + # Get and set server name + connected_server = connected_server if connected_server and is_connected else "" + server_name_label.set_markup('{0}'.format(connected_server)) + + # Get and set city label + try: + city = get_server_value(connected_server, "City", servers) + except: + city = False + city = city if city else "" + server_city_label.set_markup('{0}'.format(city)) + + # Set country label and ISP labels + ip = "" + ip + "" country_label.set_markup(country_isp) + # Get and set recieved data + rx_amount = rx_amount if is_connected else "" + data_received_label.set_markup('{0}'.format(rx_amount)) + + # Get and set sent data + tx_amount = tx_amount if is_connected else "" + data_sent_label.set_markup('{0}'.format(tx_amount)) + def load_configurations(interface): """Set and populate user configurations before showing the configurations window """ @@ -212,6 +312,12 @@ def populate_server_list(server_list_object): server_list_object.append([country, servername, tier, load, feature]) +# Autoconnect +# +# To- do +# +# Autoconnect + def manage_autoconnect(mode): """Manages autoconnect functionality """