diff --git a/MANIFEST.in b/MANIFEST.in index 4fc7f4b..d2e8a03 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,6 @@ include protonvpn_linux_gui/resources/main.glade -include protonvpn_linux_gui/resources/*.png -include protonvpn_linux_gui/resources/flags/*.png +include protonvpn_linux_gui/resources/main.css +include protonvpn_linux_gui/resources/img/logo/*.png +include protonvpn_linux_gui/resources/img/utils/*.png +include protonvpn_linux_gui/resources/img/flags/large/*.jpg +include protonvpn_linux_gui/resources/img/flags/small/*.png \ No newline at end of file diff --git a/Pipfile b/Pipfile index 303888d..122664d 100644 --- a/Pipfile +++ b/Pipfile @@ -9,4 +9,5 @@ verify_ssl = true requests = "*" pycairo = "*" pygobject = "*" -protonvpn-cli = "==2.2.2" \ No newline at end of file +protonvpn-cli = "==2.2.2" +configparser = "==4.0.2" diff --git a/Pipfile.lock b/Pipfile.lock index fe26066..9eece8f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,12 +1,10 @@ { "_meta": { "hash": { - "sha256": "541236b320ff6ae8c57660779fb3aa6e2e86d817ddb2c8522971885fe8f36bbe" + "sha256": "1937a0e30719c92a5f2ec9dad6e2ea5e2f4525cf426f5ce9e98b8e5486462419" }, "pipfile-spec": 6, - "requires": { - "python_version": "3.8" - }, + "requires": {}, "sources": [ { "name": "pypi", @@ -18,10 +16,10 @@ "default": { "certifi": { "hashes": [ - "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", - "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" + "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304", + "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" ], - "version": "==2019.11.28" + "version": "==2020.4.5.1" }, "chardet": { "hashes": [ @@ -30,6 +28,14 @@ ], "version": "==3.0.4" }, + "configparser": { + "hashes": [ + "sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c", + "sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df" + ], + "index": "pypi", + "version": "==4.0.2" + }, "docopt": { "hashes": [ "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" diff --git a/README.md b/README.md index 33c4656..bbf61cb 100644 --- a/README.md +++ b/README.md @@ -223,22 +223,22 @@ If you would like to launch the GUI without having to type in your sudo password # GUI Layout

- Logo + Dashboard

- Logo + General Settings

- Logo + Connection Settings

- Logo + Advanced Settings

- Logo + About

diff --git a/protonvpn_linux_gui/constants.py b/protonvpn_linux_gui/constants.py index 932cf78..f4f34ea 100644 --- a/protonvpn_linux_gui/constants.py +++ b/protonvpn_linux_gui/constants.py @@ -1,10 +1,16 @@ +import os try: - from protonvpn_cli.constants import VERSION as cli_version + from protonvpn_cli.constants import VERSION as cli_version, USER except: cli_version = "Not installed" -VERSION = "1.8.3" + +VERSION = "2.0.0" GITHUB_URL_RELEASE = "https://github.com/calexandru2018/protonvpn-linux-gui/releases/latest" +# GUI configurations +GUI_CONFIG_DIR = os.path.join(os.path.expanduser("~{0}".format(USER)), ".pvpn-gui") +GUI_CONFIG_FILE = os.path.join(GUI_CONFIG_DIR, "pvpn-gui.cfg") + # Tray configuration naming TRAY_CFG_SERVERLOAD = "display_serverload" TRAY_CFG_SERVENAME = "display_server" diff --git a/protonvpn_linux_gui/gui.py b/protonvpn_linux_gui/gui.py index 0e65be4..3ce5004 100644 --- a/protonvpn_linux_gui/gui.py +++ b/protonvpn_linux_gui/gui.py @@ -1,5 +1,6 @@ # Default package import import os +import re import sys import pathlib from threading import Thread @@ -7,12 +8,13 @@ try: # ProtonVPN base CLI package import - from protonvpn_cli.constants import (CONFIG_FILE, CONFIG_DIR) #noqa + from protonvpn_cli.constants import (CONFIG_FILE) #noqa # ProtonVPN helper funcitons - from protonvpn_cli.utils import check_root, get_config_value, change_file_owner #noqa + from protonvpn_cli.utils import check_root, get_config_value, change_file_owner, is_connected, set_config_value #noqa except: - sys.exit(1) + print("Unable to import from CLI, can not find CLI modules.") + pass # Import GUI logger from .gui_logger import gui_logger @@ -25,14 +27,16 @@ message_dialog, check_for_updates, get_gui_processes, - find_cli + find_cli, + get_gui_config, + set_gui_config ) # Import functions that are called with threads from .thread_functions import( quick_connect, + custom_quick_connect, disconnect, - refresh_server_list, random_connect, last_connect, connect_to_selected_server, @@ -46,19 +50,21 @@ purge_configurations, kill_duplicate_gui_process, load_content_on_start, - update_autoconnect, - tray_configurations + update_connect_preference, + tray_configurations, + update_split_tunneling_status, + reload_secure_core_servers ) # Import version -from .constants import VERSION, HELP_TEXT +from .constants import VERSION, HELP_TEXT, GUI_CONFIG_DIR # PyGObject import import gi # Gtk3 import gi.require_version('Gtk', '3.0') -from gi.repository import Gtk +from gi.repository import Gtk, Gdk class Handler: """Handler that has all callback functions. @@ -69,11 +75,20 @@ def __init__(self, interface): self.messagedialog_label = self.interface.get_object("message_dialog_label") self.messagedialog_sub_label = self.interface.get_object("message_dialog_sub_label") self.messagedialog_spinner = self.interface.get_object("message_dialog_spinner") + self.conn_disc_button_label = self.interface.get_object("main_conn_disc_button_label") self.messagedialog_sub_label.hide() + self.main_initial_tab = 0 + self.settings_initial_tab = 0 + try: + self.onload_dns_protection = get_config_value("USER", "dns_leak_protection") + self.onload_dns_custom = get_config_value("USER", "custom_dns") + except: + self.onload_dns_protection = 0 + self.onload_dns_custom = "none" # Login BUTTON HANDLER def on_login_button_clicked(self, button): - """Button/Event handler to intialize user account. Calls populate_server_list(server_list_object) to populate server list. + """Button/Event handler to intialize user account. Calls populate_server_list(server_tree_store) to populate server list. """ self.messagedialog_sub_label.hide() @@ -102,11 +117,11 @@ def server_filter_input_key_release(self, object, event): """Event handler, to filter servers after each key release """ user_filter_by = object.get_text() - server_list_object = self.interface.get_object("ServerTreeStore") - tree_view_object = self.interface.get_object("ServerList") + server_tree_store = self.interface.get_object("ServerTreeStore") + tree_view_object = self.interface.get_object("TreeViewServerList") # Creates a new filter from a ListStore/TreeStore - n_filter = server_list_object.filter_new() + n_filter = server_tree_store.filter_new() # set_visible_func: # first_param: filter function @@ -122,63 +137,15 @@ def server_filter_input_key_release(self, object, event): def column_filter(self, model, iter, data=None): """Filter by columns and returns the corresponding rows """ - treeview = self.interface.get_object("ServerList") + treeview = self.interface.get_object("TreeViewServerList") for col in range(0, treeview.get_n_columns()): - value = model.get_value(iter, col).lower(); - if data.lower() in value.lower(): - return True - else: - continue - - def connect_to_selected_server_button_clicked(self, button): - """Button/Event handler to connect to selected server - """ - self.messagedialog_sub_label.hide() - selected_server = { - "selected_server": False, - "selected_country": False - } - - # Get the server list object - server_list = self.interface.get_object("ServerList").get_selection() - - # Get the selected server - (model, pathlist) = server_list.get_selected_rows() - - for path in pathlist : - tree_iter = model.get_iter(path) - - # the second param of get_value() specifies the column number, starting at 0 - user_selected_server = model.get_value(tree_iter, 1) - - # Check if user selected a specific server - if len(user_selected_server) == 0: - selected_server["selected_country"] = model.get_value(tree_iter, 0) - else: - selected_server["selected_server"] = user_selected_server - - if not selected_server["selected_server"] and not selected_server["selected_country"]: - self.messagedialog_spinner.hide() - self.messagedialog_label.set_markup("No server was selected!\nPlease select a server before attempting to connect.") - gui_logger.debug("[!] No server was selected to be connected to.") - else: - # Set text and show spinner - if selected_server["selected_server"]: - msg = "Connecting to {0}.".format(selected_server["selected_server"]) - else: - msg = "Connecting to the quickest server in {0}.".format(selected_server["selected_country"]) - - self.messagedialog_label.set_markup(msg) - self.messagedialog_spinner.show() - - gui_logger.debug(">>> Starting \"connect_to_selected_server\" thread.") - - thread = Thread(target=connect_to_selected_server, args=[self.interface, selected_server, self.messagedialog_label, self.messagedialog_spinner]) - thread.daemon = True - thread.start() - - self.messagedialog_window.show() + value = model.get_value(iter, col); + if isinstance(value, str): + if data.lower() in value.lower(): + return True + else: + continue def quick_connect_button_clicked(self, button): """Button/Event handler to connect to the fastest server @@ -189,7 +156,10 @@ def quick_connect_button_clicked(self, button): gui_logger.debug(">>> Starting \"quick_connect\" thread.") - thread = Thread(target=quick_connect, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) + thread = Thread(target=quick_connect, args=[{ + "interface":self.interface, + "messagedialog_label": self.messagedialog_label, + "messagedialog_spinner": self.messagedialog_spinner}]) thread.daemon = True thread.start() @@ -229,7 +199,10 @@ def random_connect_button_clicked(self, button): gui_logger.debug(">>> Starting \"random_connect\" thread.") - thread = Thread(target=random_connect, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) + thread = Thread(target=random_connect, args=[{ + "interface":self.interface, + "messagedialog_label": self.messagedialog_label, + "messagedialog_spinner": self.messagedialog_spinner}]) thread.daemon = True thread.start() @@ -250,22 +223,6 @@ def disconnect_button_clicked(self, button): self.messagedialog_window.show() - 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. - """ - self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Refreshing server list...") - self.messagedialog_spinner.show() - - gui_logger.debug(">>> Starting \"refresh_server_list\" thread.") - - thread = Thread(target=refresh_server_list, args=[self.interface, self.messagedialog_window, self.messagedialog_spinner]) - thread.daemon = True - thread.start() - - self.messagedialog_window.show() - def about_menu_button_clicked(self, button): """Button /Event handler to open About dialog """ @@ -324,7 +281,7 @@ def configuration_menu_button_clicked(self, button): load_configurations(self.interface) # To avoid getting the ConfigurationsWindow destroyed and not being re-rendered again - def ConfigurationsWindow_delete_event(self, object, event): + def SettingsWindow_delete_event(self, object, event): """On Delete handler is used to hide the window so it renders next time the dialog is called -Returns:Boolean @@ -372,159 +329,488 @@ def update_user_pass_button_clicked(self, button): thread.start() self.messagedialog_window.show() - - # Disable custom DNS input if not selected custom DNS - def dns_preferens_combobox_changed(self, combobox): - """Button/Event handler that is triggered whenever combo box value is changed. - """ - # DNS ComboBox - # 0 - Leak Protection Enabled - # 1 - Custom DNS - # 2 - None - - dns_custom_input = self.interface.get_object("dns_custom_input") - - if combobox.get_active() == 0 or combobox.get_active() == 2: - dns_custom_input.set_property('sensitive', False) - else: - dns_custom_input.set_property('sensitive', True) - # Update DNS Configurations - def update_dns_button_clicked(self, button): - """Button/Event handler to update DNS protection + # Update Default OpenVPN protocol + def update_protocol_combobox_changed(self, object): + """Button/Event handler to update OpenVP Protocol """ - self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Updating DNS configurations...") - self.messagedialog_spinner.show() + autoconnect_setting = get_config_value("USER", "default_protocol") - gui_logger.debug(">>> Starting \"update_dns\" thread.") + tree_iter = object.get_active_iter() - thread = Thread(target=update_dns, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) - thread.daemon = True - thread.start() + if tree_iter is not None: + model = object.get_model() + index, protocol = model[tree_iter][:2] + protocol = protocol.lower() + if protocol.lower() != autoconnect_setting.lower(): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating default OpenVPN Protocol...") + self.messagedialog_spinner.show() - self.messagedialog_window.show() + gui_logger.debug(">>> Starting \"update_protocol_combobox_changed\" thread.") + + thread = Thread(target=update_def_protocol, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner, protocol]) + thread.daemon = True + thread.start() - # Update ProtonVPN Plan - def update_pvpn_plan_button_clicked(self, button): - """Button/Event handler to update ProtonVPN Plan + self.messagedialog_window.show() + + def update_split_tunneling_button_clicked(self, button): + """Button/Event handler to update Split Tunneling """ self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Updating ProtonVPN Plan...") + self.messagedialog_label.set_markup("Updating split tunneling configurations...") self.messagedialog_spinner.show() - gui_logger.debug(">>> Starting \"update_pvpn_plan\" thread.") + gui_logger.debug(">>> Starting \"update_split_tunneling\" thread.") - thread = Thread(target=update_pvpn_plan, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) + thread = Thread(target=update_split_tunneling, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) thread.daemon = True thread.start() - self.messagedialog_window.show() - - # Update Default OpenVPN protocol - def update_def_protocol_button_clicked(self, button): - """Button/Event handler to update OpenVP Protocol + self.messagedialog_window.show() + + def tray_data_tx_combobox_changed(self, object): + display_data_tx = get_gui_config("tray_tab", "display_data_tx") + tree_iter = object.get_active_iter() + if tree_iter is not None: + model = object.get_model() + option, display = model[tree_iter][:2] + if option != int(display_data_tx): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating tray settings...") + self.messagedialog_spinner.show() + gui_logger.debug(">>> Starting \"tray_data_tx_combobox_changed\" thread.") + thread = Thread(target=tray_configurations, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + option, + "tray_data_tx_combobox"]) + thread.daemon = True + thread.start() + self.messagedialog_window.show() + + def tray_servername_combobox_changed(self, object): + display_data_tx = get_gui_config("tray_tab", "display_server") + tree_iter = object.get_active_iter() + if tree_iter is not None: + model = object.get_model() + option, display = model[tree_iter][:2] + if option != int(display_data_tx): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating tray settings...") + self.messagedialog_spinner.show() + gui_logger.debug(">>> Starting \"tray_servername_combobox_changed\" thread.") + thread = Thread(target=tray_configurations, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + option, + "tray_servername_combobox"]) + thread.daemon = True + thread.start() + self.messagedialog_window.show() + + def tray_time_connected_combobox_changed(self, object): + display_data_tx = get_gui_config("tray_tab", "display_time_conn") + tree_iter = object.get_active_iter() + if tree_iter is not None: + model = object.get_model() + option, display = model[tree_iter][:2] + if option != int(display_data_tx): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating tray settings...") + self.messagedialog_spinner.show() + gui_logger.debug(">>> Starting \"tray_servername_combobox_changed\" thread.") + thread = Thread(target=tray_configurations, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + option, + "tray_time_connected_combobox"]) + thread.daemon = True + thread.start() + self.messagedialog_window.show() + + def tray_serverload_combobox_changed(self, object): + display_data_tx = get_gui_config("tray_tab", "display_serverload") + tree_iter = object.get_active_iter() + if tree_iter is not None: + model = object.get_model() + option, display = model[tree_iter][:2] + if option != int(display_data_tx): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating tray settings...") + self.messagedialog_spinner.show() + gui_logger.debug(">>> Starting \"tray_servername_combobox_changed\" thread.") + thread = Thread(target=tray_configurations, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + option, + "tray_serverload_combobox"]) + thread.daemon = True + thread.start() + self.messagedialog_window.show() + + def purge_configurations_button_clicked(self, button): + """Button/Event handler to purge configurations """ self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Updating default OpenVPN Protocol...") + self.messagedialog_label.set_markup("Purging configurations configurations...") self.messagedialog_spinner.show() - gui_logger.debug(">>> Starting \"update_def_protocol\" thread.") + gui_logger.debug(">>> Starting \"purge_configurations\" thread.") - thread = Thread(target=update_def_protocol, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) + thread = Thread(target=purge_configurations, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) thread.daemon = True thread.start() self.messagedialog_window.show() - - # Autoconnect on boot - def autoconnect_button_clicked(self, button): - """Button/Event handler to update autoconnect - """ - self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Updating autoconnect settings...") - self.messagedialog_spinner.show() - gui_logger.debug(">>> Starting \"autoconnect_button_clicked\" thread.") + def main_notebook_switch_page(self, notebook, selected_tab, actual_tab_index): + countries_tab = self.interface.get_object("countries_tab_label") + profiles_tab = self.interface.get_object("profiles_tab_label") + + countries_content_holder = self.interface.get_object("countries_content_holder") + profiles_content_holder = self.interface.get_object("profiles_content_holder") - thread = Thread(target=update_autoconnect, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) - thread.daemon = True - thread.start() + countries_tab_style = countries_tab.get_style_context() + profiles_tab_style = profiles_tab.get_style_context() + + countries_content_holder_style = countries_content_holder.get_style_context() + profiles_content_holder_style = profiles_content_holder.get_style_context() - self.messagedialog_window.show() + if self.main_initial_tab < actual_tab_index: + # Profiles selected + countries_tab_style.remove_class("active_tab") + countries_tab_style.add_class("inactive_tab") - # Kill Switch - def killswitch_combobox_changed(self, combobox): - """Event handler that reactes when the combobox value changes - - If killswitch is enabled, then it disables the split tunneling input and button - """ - if combobox.get_active() == 0: - self.interface.get_object("split_tunneling_textview").set_property('sensitive', True) - self.interface.get_object("update_split_tunneling_button").set_property('sensitive', True) + profiles_tab_style.remove_class("inactive_tab") + profiles_tab_style.add_class("active_tab") else: - self.interface.get_object("split_tunneling_textview").set_property('sensitive', False) - self.interface.get_object("update_split_tunneling_button").set_property('sensitive', False) + # Countries selected + countries_tab_style.remove_class("inactive_tab") + countries_tab_style.add_class("active_tab") - def update_killswitch_button_clicked(self, button): - """Button/Event handler to update Killswitch - """ - self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Updating killswitch configurations...") - self.messagedialog_spinner.show() + profiles_tab_style.remove_class("active_tab") + profiles_tab_style.add_class("inactive_tab") - gui_logger.debug(">>> Starting \"update_killswitch\" thread.") + def settings_notebook_switch_page(self, notebook, selected_tab, actual_tab_index): + general_tab = self.interface.get_object("general_tab_label") + general_content_holder = self.interface.get_object("general_content_holder") + + sys_tray_tab = self.interface.get_object("sys_tray_tab_label") + sys_tray_content_holder = self.interface.get_object("sys_tray_content_holder") - thread = Thread(target=update_killswitch, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) - thread.daemon = True - thread.start() + connection_tab = self.interface.get_object("connection_tab_label") + connection_content_holder = self.interface.get_object("connection_content_holder") - self.messagedialog_window.show() + account_tab = self.interface.get_object("account_tab_label") + account_content_holder = self.interface.get_object("account_content_holder") - def update_split_tunneling_button_clicked(self, button): - """Button/Event handler to update Split Tunneling - """ - self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Updating split tunneling configurations...") - self.messagedialog_spinner.show() + general_tab_style = general_tab.get_style_context() + sys_tray_tab_style = sys_tray_tab.get_style_context() + connection_tab_style = connection_tab.get_style_context() + account_tab_style = account_tab.get_style_context() - gui_logger.debug(">>> Starting \"update_split_tunneling\" thread.") + if actual_tab_index == 0: + # General selected + general_tab_style.add_class("active_tab") + general_tab_style.remove_class("inactive_tab") + + sys_tray_tab_style.remove_class("active_tab") + sys_tray_tab_style.add_class("inactive_tab") - thread = Thread(target=update_split_tunneling, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) - thread.daemon = True - thread.start() + connection_tab_style.add_class("inactive_tab") + connection_tab_style.remove_class("active_tab") + + account_tab_style.add_class("inactive_tab") + account_tab_style.remove_class("active_tab") + + elif actual_tab_index == 1: + # System tray selected + # General selected + general_tab_style.remove_class("active_tab") + general_tab_style.add_class("inactive_tab") + + sys_tray_tab_style.add_class("active_tab") + sys_tray_tab_style.remove_class("inactive_tab") - self.messagedialog_window.show() - - def update_tray_configurations_button_clicked(self, button): - """Button/Event handler to update Tray display configurations + connection_tab_style.add_class("inactive_tab") + connection_tab_style.remove_class("active_tab") + + account_tab_style.add_class("inactive_tab") + account_tab_style.remove_class("active_tab") + + elif actual_tab_index == 2: + # Connection selected + general_tab_style.remove_class("active_tab") + general_tab_style.add_class("inactive_tab") + + sys_tray_tab_style.remove_class("active_tab") + sys_tray_tab_style.add_class("inactive_tab") + + connection_tab_style.remove_class("inactive_tab") + connection_tab_style.add_class("active_tab") + + account_tab_style.add_class("inactive_tab") + account_tab_style.remove_class("active_tab") + + elif actual_tab_index == 3: + # Account selected + general_tab_style.remove_class("active_tab") + general_tab_style.add_class("inactive_tab") + + sys_tray_tab_style.remove_class("active_tab") + sys_tray_tab_style.add_class("inactive_tab") + + connection_tab_style.add_class("inactive_tab") + connection_tab_style.remove_class("active_tab") + + account_tab_style.remove_class("inactive_tab") + account_tab_style.add_class("active_tab") + + def main_conn_disc_button_label(self, button): + """Button/Event handler to connect to the fastest server """ self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Updating tray display configurations...") - self.messagedialog_spinner.show() - gui_logger.debug(">>> Starting \"tray_configurations\" thread.") + gui_logger.debug(">>> Starting \"main_conn_disc_button_label\" thread.") + + server_list = self.interface.get_object("TreeViewServerList").get_selection() + (model, pathlist) = server_list.get_selected_rows() + + user_selected_server = False + + for path in pathlist : + tree_iter = model.get_iter(path) + # the second param of get_value() specifies the column number, starting at 0 + user_selected_server = model.get_value(tree_iter, 1) + + server_list.unselect_all() + + target = custom_quick_connect + message = "Connecting to the fastest server..." + + if get_gui_config("conn_tab","quick_connect") != "dis": + message = "Connecting to custom quick connect..." + + if is_connected() and not user_selected_server: + target = disconnect + message = "Disconnecting..." - thread = Thread(target=tray_configurations, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) + if user_selected_server: + target = connect_to_selected_server + message = "Connecting to {}".format(user_selected_server) + + self.messagedialog_label.set_markup(message) + self.messagedialog_spinner.show() + + thread = Thread(target=target, args=[{ + "interface":self.interface, + "user_selected_server": user_selected_server, + "messagedialog_label": self.messagedialog_label, + "messagedialog_spinner": self.messagedialog_spinner}]) thread.daemon = True thread.start() self.messagedialog_window.show() - def purge_configurations_button_clicked(self, button): - """Button/Event handler to purge configurations - """ + def TreeViewServerList_cursor_changed(self, treeview): self.messagedialog_sub_label.hide() - self.messagedialog_label.set_markup("Purging configurations configurations...") - self.messagedialog_spinner.show() - gui_logger.debug(">>> Starting \"purge_configurations\" thread.") + # Get the selected server + (model, pathlist) = treeview.get_selection().get_selected_rows() - thread = Thread(target=purge_configurations, args=[self.interface, self.messagedialog_label, self.messagedialog_spinner]) - thread.daemon = True - thread.start() + for path in pathlist : + tree_iter = model.get_iter(path) + # the second param of get_value() specifies the column number, starting at 0 + user_selected_server = model.get_value(tree_iter, 1) - self.messagedialog_window.show() + try: + self.conn_disc_button_label.set_markup("Connecto to {}".format(user_selected_server)) + except UnboundLocalError: + self.conn_disc_button_label.set_markup("Quick Connect") + + def update_dns_leak_switch_changed(self, object, state): + dns_protection = get_config_value("USER", "dns_leak_protection") + # dns_custom = get_config_value("USER", "custom_dns") + if dns_protection == "0": + update_to = "1" + elif dns_protection != "0": + update_to = "0" + + if (state and dns_protection == "0") or (not state and dns_protection != "0"): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating DNS leak settings...") + self.messagedialog_spinner.show() + # set_config_value("USER", "dns_leak_protection", "0") + thread = Thread(target=update_dns, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + update_to]) + thread.daemon = True + thread.start() + + self.messagedialog_window.show() + def update_killswitch_switch_changed(self, object, state): + killswitch_protection = get_config_value("USER", "killswitch") + if killswitch_protection == "0": + update_to = "1" + else: + update_to = "0" + + if (state and killswitch_protection == "0") or (not state and killswitch_protection != "0"): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating Killswitch settings...") + self.messagedialog_spinner.show() + # set_config_value("USER", "dns_leak_protection", "0") + thread = Thread(target=update_killswitch, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + update_to]) + thread.daemon = True + thread.start() + + self.messagedialog_window.show() + + def update_autoconnect_combobox_changed(self, object): + autoconnect_setting = get_gui_config("conn_tab", "autoconnect") + + tree_iter = object.get_active_iter() + + if tree_iter is not None: + model = object.get_model() + country_command, country_display = model[tree_iter][:2] + + if country_command != autoconnect_setting: + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating autoconnect settings...") + self.messagedialog_spinner.show() + + gui_logger.debug(">>> Starting \"update_autoconnect_combobox_changed\" thread.") + + thread = Thread(target=update_connect_preference, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + country_command, + country_display]) + thread.daemon = True + thread.start() + + self.messagedialog_window.show() + + def update_quick_connect_combobox_changed(self, object): + autoconnect_setting = get_gui_config("conn_tab", "quick_connect") + + tree_iter = object.get_active_iter() + + if tree_iter is not None: + model = object.get_model() + country_command, country_display = model[tree_iter][:2] + + if country_command != autoconnect_setting: + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating quick connect settings...") + self.messagedialog_spinner.show() + + gui_logger.debug(">>> Starting \"update_quick_connect_combobox_changed\" thread.") + + thread = Thread(target=update_connect_preference, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + country_command, + country_display, + True]) + thread.daemon = True + thread.start() + + self.messagedialog_window.show() + + def split_tunneling_switch_changed(self, object, state): + split_tunnel_grid = self.interface.get_object("split_tunneling_grid") + split_tunnel = get_config_value("USER", "split_tunnel") + + if split_tunnel == "0": + update_to = "1" + else: + update_to = "0" + + if state: + split_tunnel_grid.show() + else: + + split_tunnel_grid.hide() + + if (state and split_tunnel == "0") or (not state and split_tunnel != "0"): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating split tunneling settings...") + self.messagedialog_spinner.show() + thread = Thread(target=update_split_tunneling_status, args=[ + self.messagedialog_label, + self.messagedialog_spinner, + update_to]) + thread.daemon = True + thread.start() + + self.messagedialog_window.show() + + def update_tier_combobox_changed(self, object): + tier = int(get_config_value("USER", "tier")) + + tree_iter = object.get_active_iter() + + if tree_iter is not None: + model = object.get_model() + selected_tier, tier_display = model[tree_iter][:2] + + if selected_tier != tier: + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Updating ProtoVPN plan...") + self.messagedialog_spinner.show() + + gui_logger.debug(">>> Starting \"update_tier_combobox_changed\" thread.") + + thread = Thread(target=update_pvpn_plan, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + int(selected_tier+1), + tier_display]) + thread.daemon = True + thread.start() + + self.messagedialog_window.show() + + def secure_core_switch_changed(self, object, state): + display_secure_core = get_gui_config("connections", "display_secure_core") + + if display_secure_core == "False": + update_to = "True" + else: + update_to = "False" + + if (state and display_secure_core == "False") or (not state and display_secure_core != "False"): + self.messagedialog_sub_label.hide() + self.messagedialog_label.set_markup("Loading {} servers...".format("secure-core" if update_to == "True" else "non secure-core")) + self.messagedialog_spinner.show() + thread = Thread(target=reload_secure_core_servers, args=[ + self.interface, + self.messagedialog_label, + self.messagedialog_spinner, + update_to]) + thread.daemon = True + thread.start() + + self.messagedialog_window.show() + def initialize_gui(): """Initializes the GUI --- @@ -549,9 +835,20 @@ def initialize_gui(): else: glade_path = glade_path + path + "/" - + interface.add_from_file(glade_path[:-1]) + css = re.sub("main.glade", "main.css", glade_path) + + style_provider = Gtk.CssProvider() + style_provider.load_from_path(css[:-1]) + + Gtk.StyleContext.add_provider_for_screen( + Gdk.Screen.get_default(), + style_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ) + messagedialog_window = interface.get_object("MessageDialog") messagedialog_label = interface.get_object("message_dialog_label") messagedialog_spinner = interface.get_object("message_dialog_spinner") @@ -582,13 +879,17 @@ def initialize_gui(): interface.connect_signals(Handler(interface)) check_root() + + if not os.path.isdir(GUI_CONFIG_DIR): + os.mkdir(GUI_CONFIG_DIR) + gui_logger.debug("Config Directory created") + change_file_owner(GUI_CONFIG_DIR) + gui_logger.debug("\n______________________________________\n\n\tINITIALIZING NEW GUI WINDOW\n______________________________________\n") - try: - change_file_owner(os.path.join(CONFIG_DIR, "protonvpn-gui.log")) - except NameError: - gui_logger.debug("[!] Could not CONFIG_DIR.") - sys.exit(1) + change_file_owner(os.path.join(GUI_CONFIG_DIR, "protonvpn-gui.log")) + except: + pass if len(get_gui_processes()) > 1: gui_logger.debug("[!] Two processes were found. Displaying MessageDialog to inform user.") @@ -609,13 +910,13 @@ def initialize_gui(): messagedialog_label.set_markup(response['message']) messagedialog_spinner.hide() + - if not os.path.isfile(CONFIG_FILE): + if not os.path.isfile(CONFIG_FILE): gui_logger.debug(">>> Loading LoginWindow") window = interface.get_object("LoginWindow") dashboard = interface.get_object("DashboardWindow") dashboard.connect("destroy", Gtk.main_quit) - window.show() else: window = interface.get_object("DashboardWindow") gui_logger.debug(">>> Loading DashboardWindow") @@ -640,9 +941,6 @@ def initialize_gui(): thread = Thread(target=load_content_on_start, args=[objects]) thread.daemon = True thread.start() - - # indicator(Gtk) window.show() - Gtk.main() diff --git a/protonvpn_linux_gui/gui_logger.py b/protonvpn_linux_gui/gui_logger.py index b3a5e4c..9a9f97b 100644 --- a/protonvpn_linux_gui/gui_logger.py +++ b/protonvpn_linux_gui/gui_logger.py @@ -2,21 +2,21 @@ import os from logging.handlers import RotatingFileHandler -try: - from protonvpn_cli.constants import CONFIG_DIR -except: - pass +from .constants import GUI_CONFIG_DIR def get_logger(): """Create the logger. """ + if not os.path.isdir(GUI_CONFIG_DIR): + os.mkdir(GUI_CONFIG_DIR) + formatter = logging.Formatter("%(asctime)s — %(name)s — %(levelname)s — %(funcName)s:%(lineno)d — %(message)s") log = logging.getLogger("protonvpn-linux-gui") log.setLevel(logging.DEBUG) #logging.basicConfig(filename=LOG_FILE, level=logging.DEBUG) try: - LOGFILE = os.path.join(CONFIG_DIR, "protonvpn-gui.log") + LOGFILE = os.path.join(GUI_CONFIG_DIR, "protonvpn-gui.log") file_handler = RotatingFileHandler(LOGFILE, maxBytes=3145728, backupCount=1) file_handler.setFormatter(formatter) log.addHandler(file_handler) diff --git a/protonvpn_linux_gui/resources/flags/__init__.py b/protonvpn_linux_gui/resources/img/__init__.py similarity index 100% rename from protonvpn_linux_gui/resources/flags/__init__.py rename to protonvpn_linux_gui/resources/img/__init__.py diff --git a/protonvpn_linux_gui/resources/img/flags/__init__.py b/protonvpn_linux_gui/resources/img/flags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/protonvpn_linux_gui/resources/img/flags/large/__init__.py b/protonvpn_linux_gui/resources/img/flags/large/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/protonvpn_linux_gui/resources/img/flags/large/ad.jpg b/protonvpn_linux_gui/resources/img/flags/large/ad.jpg new file mode 100644 index 0000000..bead8a9 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ad.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ae.jpg b/protonvpn_linux_gui/resources/img/flags/large/ae.jpg new file mode 100644 index 0000000..87c2c21 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ae.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/af.jpg b/protonvpn_linux_gui/resources/img/flags/large/af.jpg new file mode 100644 index 0000000..a6c9fa5 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/af.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ag.jpg b/protonvpn_linux_gui/resources/img/flags/large/ag.jpg new file mode 100644 index 0000000..c8eef79 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ag.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/al.jpg b/protonvpn_linux_gui/resources/img/flags/large/al.jpg new file mode 100644 index 0000000..e68c7f5 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/al.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/am.jpg b/protonvpn_linux_gui/resources/img/flags/large/am.jpg new file mode 100644 index 0000000..49e89ad Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/am.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ao.jpg b/protonvpn_linux_gui/resources/img/flags/large/ao.jpg new file mode 100644 index 0000000..443b1f7 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ao.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ar.jpg b/protonvpn_linux_gui/resources/img/flags/large/ar.jpg new file mode 100644 index 0000000..257bdfe Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ar.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/at.jpg b/protonvpn_linux_gui/resources/img/flags/large/at.jpg new file mode 100644 index 0000000..360af32 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/at.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/au.jpg b/protonvpn_linux_gui/resources/img/flags/large/au.jpg new file mode 100644 index 0000000..66e65ed Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/au.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/az.jpg b/protonvpn_linux_gui/resources/img/flags/large/az.jpg new file mode 100644 index 0000000..2940e10 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/az.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ba.jpg b/protonvpn_linux_gui/resources/img/flags/large/ba.jpg new file mode 100644 index 0000000..7f19d4b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ba.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bb.jpg b/protonvpn_linux_gui/resources/img/flags/large/bb.jpg new file mode 100644 index 0000000..3da8637 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bb.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bd.jpg b/protonvpn_linux_gui/resources/img/flags/large/bd.jpg new file mode 100644 index 0000000..a5b829b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bd.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/be.jpg b/protonvpn_linux_gui/resources/img/flags/large/be.jpg new file mode 100644 index 0000000..3663645 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/be.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bf.jpg b/protonvpn_linux_gui/resources/img/flags/large/bf.jpg new file mode 100644 index 0000000..83a97f8 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bf.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bg.jpg b/protonvpn_linux_gui/resources/img/flags/large/bg.jpg new file mode 100644 index 0000000..a78ae7c Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bg.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bh.jpg b/protonvpn_linux_gui/resources/img/flags/large/bh.jpg new file mode 100644 index 0000000..e00e2fc Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bh.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bi.jpg b/protonvpn_linux_gui/resources/img/flags/large/bi.jpg new file mode 100644 index 0000000..39646ac Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bi.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bj.jpg b/protonvpn_linux_gui/resources/img/flags/large/bj.jpg new file mode 100644 index 0000000..9e0d559 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bj.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bn.jpg b/protonvpn_linux_gui/resources/img/flags/large/bn.jpg new file mode 100644 index 0000000..baa793b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bo.jpg b/protonvpn_linux_gui/resources/img/flags/large/bo.jpg new file mode 100644 index 0000000..00546c2 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bo.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/br.jpg b/protonvpn_linux_gui/resources/img/flags/large/br.jpg new file mode 100644 index 0000000..1b348c7 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/br.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bs.jpg b/protonvpn_linux_gui/resources/img/flags/large/bs.jpg new file mode 100644 index 0000000..8b9737f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bs.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bt.jpg b/protonvpn_linux_gui/resources/img/flags/large/bt.jpg new file mode 100644 index 0000000..33a40c2 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bt.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bw.jpg b/protonvpn_linux_gui/resources/img/flags/large/bw.jpg new file mode 100644 index 0000000..a96f576 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bw.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/by.jpg b/protonvpn_linux_gui/resources/img/flags/large/by.jpg new file mode 100644 index 0000000..11fa16f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/by.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/bz.jpg b/protonvpn_linux_gui/resources/img/flags/large/bz.jpg new file mode 100644 index 0000000..3f28257 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/bz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ca.jpg b/protonvpn_linux_gui/resources/img/flags/large/ca.jpg new file mode 100644 index 0000000..add9055 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ca.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cd.jpg b/protonvpn_linux_gui/resources/img/flags/large/cd.jpg new file mode 100644 index 0000000..125e6d0 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cd.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cf.jpg b/protonvpn_linux_gui/resources/img/flags/large/cf.jpg new file mode 100644 index 0000000..8cf7539 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cf.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cg.jpg b/protonvpn_linux_gui/resources/img/flags/large/cg.jpg new file mode 100644 index 0000000..6dfe5f4 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cg.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ch.jpg b/protonvpn_linux_gui/resources/img/flags/large/ch.jpg new file mode 100644 index 0000000..5be3725 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ch.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ci.jpg b/protonvpn_linux_gui/resources/img/flags/large/ci.jpg new file mode 100644 index 0000000..4d2b358 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ci.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ck.jpg b/protonvpn_linux_gui/resources/img/flags/large/ck.jpg new file mode 100644 index 0000000..aa2fc38 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ck.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cl.jpg b/protonvpn_linux_gui/resources/img/flags/large/cl.jpg new file mode 100644 index 0000000..5c5841f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cl.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cm.jpg b/protonvpn_linux_gui/resources/img/flags/large/cm.jpg new file mode 100644 index 0000000..1abb3b4 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cn.jpg b/protonvpn_linux_gui/resources/img/flags/large/cn.jpg new file mode 100644 index 0000000..4dc8c36 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/co.jpg b/protonvpn_linux_gui/resources/img/flags/large/co.jpg new file mode 100644 index 0000000..fad4920 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/co.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cr.jpg b/protonvpn_linux_gui/resources/img/flags/large/cr.jpg new file mode 100644 index 0000000..c7ff9dc Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cu.jpg b/protonvpn_linux_gui/resources/img/flags/large/cu.jpg new file mode 100644 index 0000000..48b69bf Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cu.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cv.jpg b/protonvpn_linux_gui/resources/img/flags/large/cv.jpg new file mode 100644 index 0000000..ca0a180 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cv.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cy.jpg b/protonvpn_linux_gui/resources/img/flags/large/cy.jpg new file mode 100644 index 0000000..0f772aa Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cy.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/cz.jpg b/protonvpn_linux_gui/resources/img/flags/large/cz.jpg new file mode 100644 index 0000000..d0b6bdf Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/cz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/de.jpg b/protonvpn_linux_gui/resources/img/flags/large/de.jpg new file mode 100644 index 0000000..5282f91 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/de.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/dj.jpg b/protonvpn_linux_gui/resources/img/flags/large/dj.jpg new file mode 100644 index 0000000..f90c7c6 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/dj.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/dk.jpg b/protonvpn_linux_gui/resources/img/flags/large/dk.jpg new file mode 100644 index 0000000..94a500c Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/dk.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/dm.jpg b/protonvpn_linux_gui/resources/img/flags/large/dm.jpg new file mode 100644 index 0000000..fdaa18b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/dm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/do.jpg b/protonvpn_linux_gui/resources/img/flags/large/do.jpg new file mode 100644 index 0000000..f051ccd Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/do.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/dz.jpg b/protonvpn_linux_gui/resources/img/flags/large/dz.jpg new file mode 100644 index 0000000..4be9041 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/dz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ec.jpg b/protonvpn_linux_gui/resources/img/flags/large/ec.jpg new file mode 100644 index 0000000..3649a0f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ec.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ee.jpg b/protonvpn_linux_gui/resources/img/flags/large/ee.jpg new file mode 100644 index 0000000..521ab8a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ee.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/eg.jpg b/protonvpn_linux_gui/resources/img/flags/large/eg.jpg new file mode 100644 index 0000000..5821641 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/eg.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/eh.jpg b/protonvpn_linux_gui/resources/img/flags/large/eh.jpg new file mode 100644 index 0000000..26b7b1b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/eh.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/er.jpg b/protonvpn_linux_gui/resources/img/flags/large/er.jpg new file mode 100644 index 0000000..c74f416 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/er.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/es.jpg b/protonvpn_linux_gui/resources/img/flags/large/es.jpg new file mode 100644 index 0000000..720cc8f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/es.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/et.jpg b/protonvpn_linux_gui/resources/img/flags/large/et.jpg new file mode 100644 index 0000000..0b66a05 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/et.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/fi.jpg b/protonvpn_linux_gui/resources/img/flags/large/fi.jpg new file mode 100644 index 0000000..3b231ce Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/fi.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/fj.jpg b/protonvpn_linux_gui/resources/img/flags/large/fj.jpg new file mode 100644 index 0000000..8418a49 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/fj.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/fm.jpg b/protonvpn_linux_gui/resources/img/flags/large/fm.jpg new file mode 100644 index 0000000..674e302 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/fm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/fr.jpg b/protonvpn_linux_gui/resources/img/flags/large/fr.jpg new file mode 100644 index 0000000..d80419f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/fr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ga.jpg b/protonvpn_linux_gui/resources/img/flags/large/ga.jpg new file mode 100644 index 0000000..e8ed011 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ga.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gb.jpg b/protonvpn_linux_gui/resources/img/flags/large/gb.jpg new file mode 100644 index 0000000..a3a8ffb Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gb.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gd.jpg b/protonvpn_linux_gui/resources/img/flags/large/gd.jpg new file mode 100644 index 0000000..99901d0 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gd.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ge.jpg b/protonvpn_linux_gui/resources/img/flags/large/ge.jpg new file mode 100644 index 0000000..32ddeee Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ge.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gh.jpg b/protonvpn_linux_gui/resources/img/flags/large/gh.jpg new file mode 100644 index 0000000..f13a812 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gh.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gm.jpg b/protonvpn_linux_gui/resources/img/flags/large/gm.jpg new file mode 100644 index 0000000..9636ed7 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gn.jpg b/protonvpn_linux_gui/resources/img/flags/large/gn.jpg new file mode 100644 index 0000000..901b2d8 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gq.jpg b/protonvpn_linux_gui/resources/img/flags/large/gq.jpg new file mode 100644 index 0000000..c0fdc41 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gq.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gr.jpg b/protonvpn_linux_gui/resources/img/flags/large/gr.jpg new file mode 100644 index 0000000..dd02d9c Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gt.jpg b/protonvpn_linux_gui/resources/img/flags/large/gt.jpg new file mode 100644 index 0000000..42cd87e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gt.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gw.jpg b/protonvpn_linux_gui/resources/img/flags/large/gw.jpg new file mode 100644 index 0000000..b3647b3 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gw.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/gy.jpg b/protonvpn_linux_gui/resources/img/flags/large/gy.jpg new file mode 100644 index 0000000..3f10704 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/gy.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/hn.jpg b/protonvpn_linux_gui/resources/img/flags/large/hn.jpg new file mode 100644 index 0000000..d6561d7 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/hn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/hr.jpg b/protonvpn_linux_gui/resources/img/flags/large/hr.jpg new file mode 100644 index 0000000..d32a28b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/hr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ht.jpg b/protonvpn_linux_gui/resources/img/flags/large/ht.jpg new file mode 100644 index 0000000..1617392 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ht.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/hu.jpg b/protonvpn_linux_gui/resources/img/flags/large/hu.jpg new file mode 100644 index 0000000..f39c42b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/hu.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/id.jpg b/protonvpn_linux_gui/resources/img/flags/large/id.jpg new file mode 100644 index 0000000..a364167 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/id.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ie.jpg b/protonvpn_linux_gui/resources/img/flags/large/ie.jpg new file mode 100644 index 0000000..47eda2a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ie.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/il.jpg b/protonvpn_linux_gui/resources/img/flags/large/il.jpg new file mode 100644 index 0000000..f9ecd19 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/il.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/in.jpg b/protonvpn_linux_gui/resources/img/flags/large/in.jpg new file mode 100644 index 0000000..c022fb9 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/in.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/iq.jpg b/protonvpn_linux_gui/resources/img/flags/large/iq.jpg new file mode 100644 index 0000000..6a4c91e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/iq.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ir.jpg b/protonvpn_linux_gui/resources/img/flags/large/ir.jpg new file mode 100644 index 0000000..e63ee3c Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ir.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/is.jpg b/protonvpn_linux_gui/resources/img/flags/large/is.jpg new file mode 100644 index 0000000..dc88315 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/is.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/it.jpg b/protonvpn_linux_gui/resources/img/flags/large/it.jpg new file mode 100644 index 0000000..4be0968 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/it.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/jm.jpg b/protonvpn_linux_gui/resources/img/flags/large/jm.jpg new file mode 100644 index 0000000..21c55ff Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/jm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/jo.jpg b/protonvpn_linux_gui/resources/img/flags/large/jo.jpg new file mode 100644 index 0000000..afdbaf2 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/jo.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/jp.jpg b/protonvpn_linux_gui/resources/img/flags/large/jp.jpg new file mode 100644 index 0000000..161e33b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/jp.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ke.jpg b/protonvpn_linux_gui/resources/img/flags/large/ke.jpg new file mode 100644 index 0000000..e21eeed Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ke.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/kg.jpg b/protonvpn_linux_gui/resources/img/flags/large/kg.jpg new file mode 100644 index 0000000..b9d378f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/kg.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/kh.jpg b/protonvpn_linux_gui/resources/img/flags/large/kh.jpg new file mode 100644 index 0000000..23bc05a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/kh.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ki.jpg b/protonvpn_linux_gui/resources/img/flags/large/ki.jpg new file mode 100644 index 0000000..07a1a85 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ki.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/km.jpg b/protonvpn_linux_gui/resources/img/flags/large/km.jpg new file mode 100644 index 0000000..63cd536 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/km.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/kn.jpg b/protonvpn_linux_gui/resources/img/flags/large/kn.jpg new file mode 100644 index 0000000..0700ba9 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/kn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/kp.jpg b/protonvpn_linux_gui/resources/img/flags/large/kp.jpg new file mode 100644 index 0000000..fbfa233 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/kp.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/kr.jpg b/protonvpn_linux_gui/resources/img/flags/large/kr.jpg new file mode 100644 index 0000000..68aec1a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/kr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/kw.jpg b/protonvpn_linux_gui/resources/img/flags/large/kw.jpg new file mode 100644 index 0000000..f518984 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/kw.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/kz.jpg b/protonvpn_linux_gui/resources/img/flags/large/kz.jpg new file mode 100644 index 0000000..12c3fc3 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/kz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/la.jpg b/protonvpn_linux_gui/resources/img/flags/large/la.jpg new file mode 100644 index 0000000..3b3b0bd Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/la.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/lb.jpg b/protonvpn_linux_gui/resources/img/flags/large/lb.jpg new file mode 100644 index 0000000..1d937b6 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/lb.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/lc.jpg b/protonvpn_linux_gui/resources/img/flags/large/lc.jpg new file mode 100644 index 0000000..e71912d Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/lc.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/li.jpg b/protonvpn_linux_gui/resources/img/flags/large/li.jpg new file mode 100644 index 0000000..c05db10 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/li.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/lk.jpg b/protonvpn_linux_gui/resources/img/flags/large/lk.jpg new file mode 100644 index 0000000..be8bf0b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/lk.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/lr.jpg b/protonvpn_linux_gui/resources/img/flags/large/lr.jpg new file mode 100644 index 0000000..975498a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/lr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ls.jpg b/protonvpn_linux_gui/resources/img/flags/large/ls.jpg new file mode 100644 index 0000000..e76cf12 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ls.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/lt.jpg b/protonvpn_linux_gui/resources/img/flags/large/lt.jpg new file mode 100644 index 0000000..861de5d Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/lt.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/lu.jpg b/protonvpn_linux_gui/resources/img/flags/large/lu.jpg new file mode 100644 index 0000000..395fa0b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/lu.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/lv.jpg b/protonvpn_linux_gui/resources/img/flags/large/lv.jpg new file mode 100644 index 0000000..b32d47a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/lv.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ly.jpg b/protonvpn_linux_gui/resources/img/flags/large/ly.jpg new file mode 100644 index 0000000..020dcff Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ly.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ma.jpg b/protonvpn_linux_gui/resources/img/flags/large/ma.jpg new file mode 100644 index 0000000..743f43d Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ma.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mc.jpg b/protonvpn_linux_gui/resources/img/flags/large/mc.jpg new file mode 100644 index 0000000..309e28a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mc.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/md.jpg b/protonvpn_linux_gui/resources/img/flags/large/md.jpg new file mode 100644 index 0000000..b1cf5bb Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/md.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/me.jpg b/protonvpn_linux_gui/resources/img/flags/large/me.jpg new file mode 100644 index 0000000..861b759 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/me.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mg.jpg b/protonvpn_linux_gui/resources/img/flags/large/mg.jpg new file mode 100644 index 0000000..7186f24 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mg.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mh.jpg b/protonvpn_linux_gui/resources/img/flags/large/mh.jpg new file mode 100644 index 0000000..19a3d12 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mh.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mk.jpg b/protonvpn_linux_gui/resources/img/flags/large/mk.jpg new file mode 100644 index 0000000..7730bb4 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mk.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ml.jpg b/protonvpn_linux_gui/resources/img/flags/large/ml.jpg new file mode 100644 index 0000000..9bf5d45 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ml.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mm.jpg b/protonvpn_linux_gui/resources/img/flags/large/mm.jpg new file mode 100644 index 0000000..aa5e80e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mn.jpg b/protonvpn_linux_gui/resources/img/flags/large/mn.jpg new file mode 100644 index 0000000..7e418c4 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mr.jpg b/protonvpn_linux_gui/resources/img/flags/large/mr.jpg new file mode 100644 index 0000000..6c3e97c Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mt.jpg b/protonvpn_linux_gui/resources/img/flags/large/mt.jpg new file mode 100644 index 0000000..776bbb6 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mt.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mu.jpg b/protonvpn_linux_gui/resources/img/flags/large/mu.jpg new file mode 100644 index 0000000..6cf8691 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mu.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mv.jpg b/protonvpn_linux_gui/resources/img/flags/large/mv.jpg new file mode 100644 index 0000000..160a000 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mv.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mw.jpg b/protonvpn_linux_gui/resources/img/flags/large/mw.jpg new file mode 100644 index 0000000..9c49dd9 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mw.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mx.jpg b/protonvpn_linux_gui/resources/img/flags/large/mx.jpg new file mode 100644 index 0000000..83d3e3a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mx.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/my.jpg b/protonvpn_linux_gui/resources/img/flags/large/my.jpg new file mode 100644 index 0000000..55bf07e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/my.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/mz.jpg b/protonvpn_linux_gui/resources/img/flags/large/mz.jpg new file mode 100644 index 0000000..ac3f76b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/mz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/na.jpg b/protonvpn_linux_gui/resources/img/flags/large/na.jpg new file mode 100644 index 0000000..76d417e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/na.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ne.jpg b/protonvpn_linux_gui/resources/img/flags/large/ne.jpg new file mode 100644 index 0000000..db79425 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ne.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ng.jpg b/protonvpn_linux_gui/resources/img/flags/large/ng.jpg new file mode 100644 index 0000000..afbbac8 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ng.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ni.jpg b/protonvpn_linux_gui/resources/img/flags/large/ni.jpg new file mode 100644 index 0000000..0fb3238 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ni.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/nl.jpg b/protonvpn_linux_gui/resources/img/flags/large/nl.jpg new file mode 100644 index 0000000..c9ffacc Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/nl.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/no.jpg b/protonvpn_linux_gui/resources/img/flags/large/no.jpg new file mode 100644 index 0000000..ba470e6 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/no.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/np.jpg b/protonvpn_linux_gui/resources/img/flags/large/np.jpg new file mode 100644 index 0000000..bbde4ad Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/np.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/nr.jpg b/protonvpn_linux_gui/resources/img/flags/large/nr.jpg new file mode 100644 index 0000000..234076a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/nr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/nu.jpg b/protonvpn_linux_gui/resources/img/flags/large/nu.jpg new file mode 100644 index 0000000..cd6087e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/nu.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/nz.jpg b/protonvpn_linux_gui/resources/img/flags/large/nz.jpg new file mode 100644 index 0000000..a6bf83d Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/nz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/om.jpg b/protonvpn_linux_gui/resources/img/flags/large/om.jpg new file mode 100644 index 0000000..37c9421 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/om.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/pa.jpg b/protonvpn_linux_gui/resources/img/flags/large/pa.jpg new file mode 100644 index 0000000..32bc201 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/pa.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/pe.jpg b/protonvpn_linux_gui/resources/img/flags/large/pe.jpg new file mode 100644 index 0000000..e5bb5e7 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/pe.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/pg.jpg b/protonvpn_linux_gui/resources/img/flags/large/pg.jpg new file mode 100644 index 0000000..79d2e3a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/pg.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ph.jpg b/protonvpn_linux_gui/resources/img/flags/large/ph.jpg new file mode 100644 index 0000000..caa3b6d Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ph.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/pk.jpg b/protonvpn_linux_gui/resources/img/flags/large/pk.jpg new file mode 100644 index 0000000..02c81c7 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/pk.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/pl.jpg b/protonvpn_linux_gui/resources/img/flags/large/pl.jpg new file mode 100644 index 0000000..be16cbc Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/pl.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ps.jpg b/protonvpn_linux_gui/resources/img/flags/large/ps.jpg new file mode 100644 index 0000000..45b02bb Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ps.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/pt.jpg b/protonvpn_linux_gui/resources/img/flags/large/pt.jpg new file mode 100644 index 0000000..5405868 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/pt.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/pw.jpg b/protonvpn_linux_gui/resources/img/flags/large/pw.jpg new file mode 100644 index 0000000..dfc1ac7 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/pw.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/py.jpg b/protonvpn_linux_gui/resources/img/flags/large/py.jpg new file mode 100644 index 0000000..2a17d6b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/py.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/qa.jpg b/protonvpn_linux_gui/resources/img/flags/large/qa.jpg new file mode 100644 index 0000000..bb60905 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/qa.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ro.jpg b/protonvpn_linux_gui/resources/img/flags/large/ro.jpg new file mode 100644 index 0000000..c3b11c2 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ro.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/rs.jpg b/protonvpn_linux_gui/resources/img/flags/large/rs.jpg new file mode 100644 index 0000000..30e7488 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/rs.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ru.jpg b/protonvpn_linux_gui/resources/img/flags/large/ru.jpg new file mode 100644 index 0000000..0a041ad Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ru.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/rw.jpg b/protonvpn_linux_gui/resources/img/flags/large/rw.jpg new file mode 100644 index 0000000..cece4cf Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/rw.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sa.jpg b/protonvpn_linux_gui/resources/img/flags/large/sa.jpg new file mode 100644 index 0000000..c59bbaf Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sa.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sb.jpg b/protonvpn_linux_gui/resources/img/flags/large/sb.jpg new file mode 100644 index 0000000..e338d0e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sb.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sc.jpg b/protonvpn_linux_gui/resources/img/flags/large/sc.jpg new file mode 100644 index 0000000..00d7ed4 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sc.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sd.jpg b/protonvpn_linux_gui/resources/img/flags/large/sd.jpg new file mode 100644 index 0000000..1feb7d4 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sd.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/se.jpg b/protonvpn_linux_gui/resources/img/flags/large/se.jpg new file mode 100644 index 0000000..50f6162 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/se.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sg.jpg b/protonvpn_linux_gui/resources/img/flags/large/sg.jpg new file mode 100644 index 0000000..2f79988 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sg.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/si.jpg b/protonvpn_linux_gui/resources/img/flags/large/si.jpg new file mode 100644 index 0000000..d87d557 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/si.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sk.jpg b/protonvpn_linux_gui/resources/img/flags/large/sk.jpg new file mode 100644 index 0000000..d78f785 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sk.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sl.jpg b/protonvpn_linux_gui/resources/img/flags/large/sl.jpg new file mode 100644 index 0000000..75600e0 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sl.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sm.jpg b/protonvpn_linux_gui/resources/img/flags/large/sm.jpg new file mode 100644 index 0000000..3c4f5bf Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sn.jpg b/protonvpn_linux_gui/resources/img/flags/large/sn.jpg new file mode 100644 index 0000000..4288f37 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/so.jpg b/protonvpn_linux_gui/resources/img/flags/large/so.jpg new file mode 100644 index 0000000..933079f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/so.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sr.jpg b/protonvpn_linux_gui/resources/img/flags/large/sr.jpg new file mode 100644 index 0000000..e78256c Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ss.jpg b/protonvpn_linux_gui/resources/img/flags/large/ss.jpg new file mode 100644 index 0000000..e27acb6 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ss.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/st.jpg b/protonvpn_linux_gui/resources/img/flags/large/st.jpg new file mode 100644 index 0000000..0bf6234 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/st.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sv.jpg b/protonvpn_linux_gui/resources/img/flags/large/sv.jpg new file mode 100644 index 0000000..a7a35e8 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sv.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sy.jpg b/protonvpn_linux_gui/resources/img/flags/large/sy.jpg new file mode 100644 index 0000000..699ee17 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sy.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/sz.jpg b/protonvpn_linux_gui/resources/img/flags/large/sz.jpg new file mode 100644 index 0000000..100fa69 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/sz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/td.jpg b/protonvpn_linux_gui/resources/img/flags/large/td.jpg new file mode 100644 index 0000000..9a9d40a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/td.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tg.jpg b/protonvpn_linux_gui/resources/img/flags/large/tg.jpg new file mode 100644 index 0000000..686985b Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tg.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/th.jpg b/protonvpn_linux_gui/resources/img/flags/large/th.jpg new file mode 100644 index 0000000..3cb7233 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/th.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tj.jpg b/protonvpn_linux_gui/resources/img/flags/large/tj.jpg new file mode 100644 index 0000000..3a07ac8 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tj.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tl.jpg b/protonvpn_linux_gui/resources/img/flags/large/tl.jpg new file mode 100644 index 0000000..d5b470e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tl.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tm.jpg b/protonvpn_linux_gui/resources/img/flags/large/tm.jpg new file mode 100644 index 0000000..1f8c477 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tn.jpg b/protonvpn_linux_gui/resources/img/flags/large/tn.jpg new file mode 100644 index 0000000..70e48eb Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/to.jpg b/protonvpn_linux_gui/resources/img/flags/large/to.jpg new file mode 100644 index 0000000..da10eb2 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/to.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tr.jpg b/protonvpn_linux_gui/resources/img/flags/large/tr.jpg new file mode 100644 index 0000000..4a2247d Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tr.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tt.jpg b/protonvpn_linux_gui/resources/img/flags/large/tt.jpg new file mode 100644 index 0000000..6f626bc Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tt.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tv.jpg b/protonvpn_linux_gui/resources/img/flags/large/tv.jpg new file mode 100644 index 0000000..a21912f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tv.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tw.jpg b/protonvpn_linux_gui/resources/img/flags/large/tw.jpg new file mode 100644 index 0000000..1d1ddd3 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tw.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/tz.jpg b/protonvpn_linux_gui/resources/img/flags/large/tz.jpg new file mode 100644 index 0000000..204bc80 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/tz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ua.jpg b/protonvpn_linux_gui/resources/img/flags/large/ua.jpg new file mode 100644 index 0000000..f2e575e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ua.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ug.jpg b/protonvpn_linux_gui/resources/img/flags/large/ug.jpg new file mode 100644 index 0000000..30abd62 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ug.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/us.jpg b/protonvpn_linux_gui/resources/img/flags/large/us.jpg new file mode 100644 index 0000000..c6f437f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/us.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/uy.jpg b/protonvpn_linux_gui/resources/img/flags/large/uy.jpg new file mode 100644 index 0000000..61e572f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/uy.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/uz.jpg b/protonvpn_linux_gui/resources/img/flags/large/uz.jpg new file mode 100644 index 0000000..acb9da4 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/uz.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/va.jpg b/protonvpn_linux_gui/resources/img/flags/large/va.jpg new file mode 100644 index 0000000..8e1e43a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/va.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/vc.jpg b/protonvpn_linux_gui/resources/img/flags/large/vc.jpg new file mode 100644 index 0000000..6776ecb Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/vc.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ve.jpg b/protonvpn_linux_gui/resources/img/flags/large/ve.jpg new file mode 100644 index 0000000..60e0681 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ve.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/vn.jpg b/protonvpn_linux_gui/resources/img/flags/large/vn.jpg new file mode 100644 index 0000000..6f1f98c Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/vn.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/vu.jpg b/protonvpn_linux_gui/resources/img/flags/large/vu.jpg new file mode 100644 index 0000000..2f6a58a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/vu.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ws.jpg b/protonvpn_linux_gui/resources/img/flags/large/ws.jpg new file mode 100644 index 0000000..bf2bb5f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ws.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/xk.jpg b/protonvpn_linux_gui/resources/img/flags/large/xk.jpg new file mode 100644 index 0000000..527fa5c Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/xk.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/ye.jpg b/protonvpn_linux_gui/resources/img/flags/large/ye.jpg new file mode 100644 index 0000000..724dcdb Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/ye.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/za.jpg b/protonvpn_linux_gui/resources/img/flags/large/za.jpg new file mode 100644 index 0000000..0f45e5f Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/za.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/zm.jpg b/protonvpn_linux_gui/resources/img/flags/large/zm.jpg new file mode 100644 index 0000000..de4ada9 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/zm.jpg differ diff --git a/protonvpn_linux_gui/resources/img/flags/large/zw.jpg b/protonvpn_linux_gui/resources/img/flags/large/zw.jpg new file mode 100644 index 0000000..7c3c7f2 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/flags/large/zw.jpg differ diff --git a/protonvpn_linux_gui/resources/flags/Afghanistan.png b/protonvpn_linux_gui/resources/img/flags/small/Afghanistan.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Afghanistan.png rename to protonvpn_linux_gui/resources/img/flags/small/Afghanistan.png diff --git a/protonvpn_linux_gui/resources/flags/Albania.png b/protonvpn_linux_gui/resources/img/flags/small/Albania.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Albania.png rename to protonvpn_linux_gui/resources/img/flags/small/Albania.png diff --git a/protonvpn_linux_gui/resources/flags/Algeria.png b/protonvpn_linux_gui/resources/img/flags/small/Algeria.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Algeria.png rename to protonvpn_linux_gui/resources/img/flags/small/Algeria.png diff --git a/protonvpn_linux_gui/resources/flags/Andorra.png b/protonvpn_linux_gui/resources/img/flags/small/Andorra.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Andorra.png rename to protonvpn_linux_gui/resources/img/flags/small/Andorra.png diff --git a/protonvpn_linux_gui/resources/flags/Argentina.png b/protonvpn_linux_gui/resources/img/flags/small/Argentina.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Argentina.png rename to protonvpn_linux_gui/resources/img/flags/small/Argentina.png diff --git a/protonvpn_linux_gui/resources/flags/Armenia.png b/protonvpn_linux_gui/resources/img/flags/small/Armenia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Armenia.png rename to protonvpn_linux_gui/resources/img/flags/small/Armenia.png diff --git a/protonvpn_linux_gui/resources/flags/Australia.png b/protonvpn_linux_gui/resources/img/flags/small/Australia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Australia.png rename to protonvpn_linux_gui/resources/img/flags/small/Australia.png diff --git a/protonvpn_linux_gui/resources/flags/Austria.png b/protonvpn_linux_gui/resources/img/flags/small/Austria.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Austria.png rename to protonvpn_linux_gui/resources/img/flags/small/Austria.png diff --git a/protonvpn_linux_gui/resources/flags/Azerbaijan.png b/protonvpn_linux_gui/resources/img/flags/small/Azerbaijan.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Azerbaijan.png rename to protonvpn_linux_gui/resources/img/flags/small/Azerbaijan.png diff --git a/protonvpn_linux_gui/resources/flags/Bahamas.png b/protonvpn_linux_gui/resources/img/flags/small/Bahamas.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Bahamas.png rename to protonvpn_linux_gui/resources/img/flags/small/Bahamas.png diff --git a/protonvpn_linux_gui/resources/flags/Bangladesh.png b/protonvpn_linux_gui/resources/img/flags/small/Bangladesh.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Bangladesh.png rename to protonvpn_linux_gui/resources/img/flags/small/Bangladesh.png diff --git a/protonvpn_linux_gui/resources/flags/Belarus.png b/protonvpn_linux_gui/resources/img/flags/small/Belarus.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Belarus.png rename to protonvpn_linux_gui/resources/img/flags/small/Belarus.png diff --git a/protonvpn_linux_gui/resources/flags/Belgium.png b/protonvpn_linux_gui/resources/img/flags/small/Belgium.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Belgium.png rename to protonvpn_linux_gui/resources/img/flags/small/Belgium.png diff --git a/protonvpn_linux_gui/resources/flags/Bosnia and Herzegovina.png b/protonvpn_linux_gui/resources/img/flags/small/Bosnia and Herzegovina.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Bosnia and Herzegovina.png rename to protonvpn_linux_gui/resources/img/flags/small/Bosnia and Herzegovina.png diff --git a/protonvpn_linux_gui/resources/flags/Brazil.png b/protonvpn_linux_gui/resources/img/flags/small/Brazil.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Brazil.png rename to protonvpn_linux_gui/resources/img/flags/small/Brazil.png diff --git a/protonvpn_linux_gui/resources/flags/Bulgaria.png b/protonvpn_linux_gui/resources/img/flags/small/Bulgaria.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Bulgaria.png rename to protonvpn_linux_gui/resources/img/flags/small/Bulgaria.png diff --git a/protonvpn_linux_gui/resources/flags/Cameroon.png b/protonvpn_linux_gui/resources/img/flags/small/Cameroon.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Cameroon.png rename to protonvpn_linux_gui/resources/img/flags/small/Cameroon.png diff --git a/protonvpn_linux_gui/resources/flags/Canada.png b/protonvpn_linux_gui/resources/img/flags/small/Canada.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Canada.png rename to protonvpn_linux_gui/resources/img/flags/small/Canada.png diff --git a/protonvpn_linux_gui/resources/flags/Chile.png b/protonvpn_linux_gui/resources/img/flags/small/Chile.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Chile.png rename to protonvpn_linux_gui/resources/img/flags/small/Chile.png diff --git a/protonvpn_linux_gui/resources/flags/China.png b/protonvpn_linux_gui/resources/img/flags/small/China.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/China.png rename to protonvpn_linux_gui/resources/img/flags/small/China.png diff --git a/protonvpn_linux_gui/resources/flags/Colombia.png b/protonvpn_linux_gui/resources/img/flags/small/Colombia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Colombia.png rename to protonvpn_linux_gui/resources/img/flags/small/Colombia.png diff --git a/protonvpn_linux_gui/resources/flags/Costa Rica.png b/protonvpn_linux_gui/resources/img/flags/small/Costa Rica.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Costa Rica.png rename to protonvpn_linux_gui/resources/img/flags/small/Costa Rica.png diff --git a/protonvpn_linux_gui/resources/flags/Croatia.png b/protonvpn_linux_gui/resources/img/flags/small/Croatia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Croatia.png rename to protonvpn_linux_gui/resources/img/flags/small/Croatia.png diff --git a/protonvpn_linux_gui/resources/flags/Cuba.png b/protonvpn_linux_gui/resources/img/flags/small/Cuba.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Cuba.png rename to protonvpn_linux_gui/resources/img/flags/small/Cuba.png diff --git a/protonvpn_linux_gui/resources/flags/Cyprus.png b/protonvpn_linux_gui/resources/img/flags/small/Cyprus.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Cyprus.png rename to protonvpn_linux_gui/resources/img/flags/small/Cyprus.png diff --git a/protonvpn_linux_gui/resources/flags/Czech Republic.png b/protonvpn_linux_gui/resources/img/flags/small/Czech Republic.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Czech Republic.png rename to protonvpn_linux_gui/resources/img/flags/small/Czech Republic.png diff --git a/protonvpn_linux_gui/resources/flags/Denmark.png b/protonvpn_linux_gui/resources/img/flags/small/Denmark.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Denmark.png rename to protonvpn_linux_gui/resources/img/flags/small/Denmark.png diff --git a/protonvpn_linux_gui/resources/flags/Ecuador.png b/protonvpn_linux_gui/resources/img/flags/small/Ecuador.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Ecuador.png rename to protonvpn_linux_gui/resources/img/flags/small/Ecuador.png diff --git a/protonvpn_linux_gui/resources/flags/Egypt.png b/protonvpn_linux_gui/resources/img/flags/small/Egypt.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Egypt.png rename to protonvpn_linux_gui/resources/img/flags/small/Egypt.png diff --git a/protonvpn_linux_gui/resources/flags/Estonia.png b/protonvpn_linux_gui/resources/img/flags/small/Estonia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Estonia.png rename to protonvpn_linux_gui/resources/img/flags/small/Estonia.png diff --git a/protonvpn_linux_gui/resources/flags/Finland.png b/protonvpn_linux_gui/resources/img/flags/small/Finland.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Finland.png rename to protonvpn_linux_gui/resources/img/flags/small/Finland.png diff --git a/protonvpn_linux_gui/resources/flags/France.png b/protonvpn_linux_gui/resources/img/flags/small/France.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/France.png rename to protonvpn_linux_gui/resources/img/flags/small/France.png diff --git a/protonvpn_linux_gui/resources/flags/Georgia.png b/protonvpn_linux_gui/resources/img/flags/small/Georgia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Georgia.png rename to protonvpn_linux_gui/resources/img/flags/small/Georgia.png diff --git a/protonvpn_linux_gui/resources/flags/Germany.png b/protonvpn_linux_gui/resources/img/flags/small/Germany.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Germany.png rename to protonvpn_linux_gui/resources/img/flags/small/Germany.png diff --git a/protonvpn_linux_gui/resources/flags/Greece.png b/protonvpn_linux_gui/resources/img/flags/small/Greece.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Greece.png rename to protonvpn_linux_gui/resources/img/flags/small/Greece.png diff --git a/protonvpn_linux_gui/resources/flags/Hong Kong.png b/protonvpn_linux_gui/resources/img/flags/small/Hong Kong.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Hong Kong.png rename to protonvpn_linux_gui/resources/img/flags/small/Hong Kong.png diff --git a/protonvpn_linux_gui/resources/flags/Hungary.png b/protonvpn_linux_gui/resources/img/flags/small/Hungary.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Hungary.png rename to protonvpn_linux_gui/resources/img/flags/small/Hungary.png diff --git a/protonvpn_linux_gui/resources/flags/Iceland.png b/protonvpn_linux_gui/resources/img/flags/small/Iceland.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Iceland.png rename to protonvpn_linux_gui/resources/img/flags/small/Iceland.png diff --git a/protonvpn_linux_gui/resources/flags/India.png b/protonvpn_linux_gui/resources/img/flags/small/India.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/India.png rename to protonvpn_linux_gui/resources/img/flags/small/India.png diff --git a/protonvpn_linux_gui/resources/flags/Indonesia.png b/protonvpn_linux_gui/resources/img/flags/small/Indonesia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Indonesia.png rename to protonvpn_linux_gui/resources/img/flags/small/Indonesia.png diff --git a/protonvpn_linux_gui/resources/flags/Ireland.png b/protonvpn_linux_gui/resources/img/flags/small/Ireland.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Ireland.png rename to protonvpn_linux_gui/resources/img/flags/small/Ireland.png diff --git a/protonvpn_linux_gui/resources/flags/Israel.png b/protonvpn_linux_gui/resources/img/flags/small/Israel.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Israel.png rename to protonvpn_linux_gui/resources/img/flags/small/Israel.png diff --git a/protonvpn_linux_gui/resources/flags/Italy.png b/protonvpn_linux_gui/resources/img/flags/small/Italy.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Italy.png rename to protonvpn_linux_gui/resources/img/flags/small/Italy.png diff --git a/protonvpn_linux_gui/resources/flags/Jamaica.png b/protonvpn_linux_gui/resources/img/flags/small/Jamaica.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Jamaica.png rename to protonvpn_linux_gui/resources/img/flags/small/Jamaica.png diff --git a/protonvpn_linux_gui/resources/flags/Japan.png b/protonvpn_linux_gui/resources/img/flags/small/Japan.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Japan.png rename to protonvpn_linux_gui/resources/img/flags/small/Japan.png diff --git a/protonvpn_linux_gui/resources/flags/Latvia.png b/protonvpn_linux_gui/resources/img/flags/small/Latvia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Latvia.png rename to protonvpn_linux_gui/resources/img/flags/small/Latvia.png diff --git a/protonvpn_linux_gui/resources/flags/Libya.png b/protonvpn_linux_gui/resources/img/flags/small/Libya.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Libya.png rename to protonvpn_linux_gui/resources/img/flags/small/Libya.png diff --git a/protonvpn_linux_gui/resources/flags/Lithuania.png b/protonvpn_linux_gui/resources/img/flags/small/Lithuania.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Lithuania.png rename to protonvpn_linux_gui/resources/img/flags/small/Lithuania.png diff --git a/protonvpn_linux_gui/resources/flags/Luxembourg.png b/protonvpn_linux_gui/resources/img/flags/small/Luxembourg.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Luxembourg.png rename to protonvpn_linux_gui/resources/img/flags/small/Luxembourg.png diff --git a/protonvpn_linux_gui/resources/flags/Macedonia, Republic of.png b/protonvpn_linux_gui/resources/img/flags/small/Macedonia, Republic of.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Macedonia, Republic of.png rename to protonvpn_linux_gui/resources/img/flags/small/Macedonia, Republic of.png diff --git a/protonvpn_linux_gui/resources/flags/Malaysia.png b/protonvpn_linux_gui/resources/img/flags/small/Malaysia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Malaysia.png rename to protonvpn_linux_gui/resources/img/flags/small/Malaysia.png diff --git a/protonvpn_linux_gui/resources/flags/Mexico.png b/protonvpn_linux_gui/resources/img/flags/small/Mexico.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Mexico.png rename to protonvpn_linux_gui/resources/img/flags/small/Mexico.png diff --git a/protonvpn_linux_gui/resources/flags/Moldova.png b/protonvpn_linux_gui/resources/img/flags/small/Moldova.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Moldova.png rename to protonvpn_linux_gui/resources/img/flags/small/Moldova.png diff --git a/protonvpn_linux_gui/resources/flags/Myanmar.png b/protonvpn_linux_gui/resources/img/flags/small/Myanmar.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Myanmar.png rename to protonvpn_linux_gui/resources/img/flags/small/Myanmar.png diff --git a/protonvpn_linux_gui/resources/flags/Netherlands.png b/protonvpn_linux_gui/resources/img/flags/small/Netherlands.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Netherlands.png rename to protonvpn_linux_gui/resources/img/flags/small/Netherlands.png diff --git a/protonvpn_linux_gui/resources/flags/New Zealand.png b/protonvpn_linux_gui/resources/img/flags/small/New Zealand.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/New Zealand.png rename to protonvpn_linux_gui/resources/img/flags/small/New Zealand.png diff --git a/protonvpn_linux_gui/resources/flags/Norway.png b/protonvpn_linux_gui/resources/img/flags/small/Norway.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Norway.png rename to protonvpn_linux_gui/resources/img/flags/small/Norway.png diff --git a/protonvpn_linux_gui/resources/flags/Philippines.png b/protonvpn_linux_gui/resources/img/flags/small/Philippines.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Philippines.png rename to protonvpn_linux_gui/resources/img/flags/small/Philippines.png diff --git a/protonvpn_linux_gui/resources/flags/Poland.png b/protonvpn_linux_gui/resources/img/flags/small/Poland.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Poland.png rename to protonvpn_linux_gui/resources/img/flags/small/Poland.png diff --git a/protonvpn_linux_gui/resources/flags/Portugal.png b/protonvpn_linux_gui/resources/img/flags/small/Portugal.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Portugal.png rename to protonvpn_linux_gui/resources/img/flags/small/Portugal.png diff --git a/protonvpn_linux_gui/resources/flags/Romania.png b/protonvpn_linux_gui/resources/img/flags/small/Romania.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Romania.png rename to protonvpn_linux_gui/resources/img/flags/small/Romania.png diff --git a/protonvpn_linux_gui/resources/flags/Russia.png b/protonvpn_linux_gui/resources/img/flags/small/Russia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Russia.png rename to protonvpn_linux_gui/resources/img/flags/small/Russia.png diff --git a/protonvpn_linux_gui/resources/flags/Serbia.png b/protonvpn_linux_gui/resources/img/flags/small/Serbia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Serbia.png rename to protonvpn_linux_gui/resources/img/flags/small/Serbia.png diff --git a/protonvpn_linux_gui/resources/flags/Singapore.png b/protonvpn_linux_gui/resources/img/flags/small/Singapore.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Singapore.png rename to protonvpn_linux_gui/resources/img/flags/small/Singapore.png diff --git a/protonvpn_linux_gui/resources/flags/Slovakia.png b/protonvpn_linux_gui/resources/img/flags/small/Slovakia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Slovakia.png rename to protonvpn_linux_gui/resources/img/flags/small/Slovakia.png diff --git a/protonvpn_linux_gui/resources/flags/Slovenia.png b/protonvpn_linux_gui/resources/img/flags/small/Slovenia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Slovenia.png rename to protonvpn_linux_gui/resources/img/flags/small/Slovenia.png diff --git a/protonvpn_linux_gui/resources/flags/South Africa.png b/protonvpn_linux_gui/resources/img/flags/small/South Africa.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/South Africa.png rename to protonvpn_linux_gui/resources/img/flags/small/South Africa.png diff --git a/protonvpn_linux_gui/resources/flags/South Korea.png b/protonvpn_linux_gui/resources/img/flags/small/South Korea.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/South Korea.png rename to protonvpn_linux_gui/resources/img/flags/small/South Korea.png diff --git a/protonvpn_linux_gui/resources/flags/Spain.png b/protonvpn_linux_gui/resources/img/flags/small/Spain.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Spain.png rename to protonvpn_linux_gui/resources/img/flags/small/Spain.png diff --git a/protonvpn_linux_gui/resources/flags/Sweden.png b/protonvpn_linux_gui/resources/img/flags/small/Sweden.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Sweden.png rename to protonvpn_linux_gui/resources/img/flags/small/Sweden.png diff --git a/protonvpn_linux_gui/resources/flags/Switzerland.png b/protonvpn_linux_gui/resources/img/flags/small/Switzerland.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Switzerland.png rename to protonvpn_linux_gui/resources/img/flags/small/Switzerland.png diff --git a/protonvpn_linux_gui/resources/flags/Taiwan.png b/protonvpn_linux_gui/resources/img/flags/small/Taiwan.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Taiwan.png rename to protonvpn_linux_gui/resources/img/flags/small/Taiwan.png diff --git a/protonvpn_linux_gui/resources/flags/Thailand.png b/protonvpn_linux_gui/resources/img/flags/small/Thailand.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Thailand.png rename to protonvpn_linux_gui/resources/img/flags/small/Thailand.png diff --git a/protonvpn_linux_gui/resources/flags/Tunisia.png b/protonvpn_linux_gui/resources/img/flags/small/Tunisia.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Tunisia.png rename to protonvpn_linux_gui/resources/img/flags/small/Tunisia.png diff --git a/protonvpn_linux_gui/resources/flags/Turkey.png b/protonvpn_linux_gui/resources/img/flags/small/Turkey.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Turkey.png rename to protonvpn_linux_gui/resources/img/flags/small/Turkey.png diff --git a/protonvpn_linux_gui/resources/flags/Ukraine.png b/protonvpn_linux_gui/resources/img/flags/small/Ukraine.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Ukraine.png rename to protonvpn_linux_gui/resources/img/flags/small/Ukraine.png diff --git a/protonvpn_linux_gui/resources/flags/United Arab Emirates.png b/protonvpn_linux_gui/resources/img/flags/small/United Arab Emirates.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/United Arab Emirates.png rename to protonvpn_linux_gui/resources/img/flags/small/United Arab Emirates.png diff --git a/protonvpn_linux_gui/resources/flags/United Kingdom.png b/protonvpn_linux_gui/resources/img/flags/small/United Kingdom.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/United Kingdom.png rename to protonvpn_linux_gui/resources/img/flags/small/United Kingdom.png diff --git a/protonvpn_linux_gui/resources/flags/United States.png b/protonvpn_linux_gui/resources/img/flags/small/United States.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/United States.png rename to protonvpn_linux_gui/resources/img/flags/small/United States.png diff --git a/protonvpn_linux_gui/resources/flags/Unknown.png b/protonvpn_linux_gui/resources/img/flags/small/Unknown.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Unknown.png rename to protonvpn_linux_gui/resources/img/flags/small/Unknown.png diff --git a/protonvpn_linux_gui/resources/flags/Viet Nam.png b/protonvpn_linux_gui/resources/img/flags/small/Viet Nam.png similarity index 100% rename from protonvpn_linux_gui/resources/flags/Viet Nam.png rename to protonvpn_linux_gui/resources/img/flags/small/Viet Nam.png diff --git a/protonvpn_linux_gui/resources/img/flags/small/__init__.py b/protonvpn_linux_gui/resources/img/flags/small/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/protonvpn_linux_gui/resources/img/logo/__init__.py b/protonvpn_linux_gui/resources/img/logo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/protonvpn_linux_gui/resources/img/logo/protonvpn-logo-white.png b/protonvpn_linux_gui/resources/img/logo/protonvpn-logo-white.png new file mode 100644 index 0000000..7088c5e Binary files /dev/null and b/protonvpn_linux_gui/resources/img/logo/protonvpn-logo-white.png differ diff --git a/protonvpn_linux_gui/resources/protonvpn_logo.png b/protonvpn_linux_gui/resources/img/logo/protonvpn_logo.png similarity index 100% rename from protonvpn_linux_gui/resources/protonvpn_logo.png rename to protonvpn_linux_gui/resources/img/logo/protonvpn_logo.png diff --git a/protonvpn_linux_gui/resources/protonvpn_logo_alt.png b/protonvpn_linux_gui/resources/img/logo/protonvpn_logo_alt.png similarity index 100% rename from protonvpn_linux_gui/resources/protonvpn_logo_alt.png rename to protonvpn_linux_gui/resources/img/logo/protonvpn_logo_alt.png diff --git a/protonvpn_linux_gui/resources/protonvpn_logo_full.png b/protonvpn_linux_gui/resources/img/logo/protonvpn_logo_full.png similarity index 100% rename from protonvpn_linux_gui/resources/protonvpn_logo_full.png rename to protonvpn_linux_gui/resources/img/logo/protonvpn_logo_full.png diff --git a/protonvpn_linux_gui/resources/img/logo/protonvpn_sign_green.png b/protonvpn_linux_gui/resources/img/logo/protonvpn_sign_green.png new file mode 100644 index 0000000..2c622fa Binary files /dev/null and b/protonvpn_linux_gui/resources/img/logo/protonvpn_sign_green.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/__init__.py b/protonvpn_linux_gui/resources/img/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/protonvpn_linux_gui/resources/img/utils/bitrate-download-arrow.png b/protonvpn_linux_gui/resources/img/utils/bitrate-download-arrow.png new file mode 100644 index 0000000..5c02402 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/bitrate-download-arrow.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/bitrate-upload-arrow.png b/protonvpn_linux_gui/resources/img/utils/bitrate-upload-arrow.png new file mode 100644 index 0000000..15a11c0 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/bitrate-upload-arrow.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/fastest.png b/protonvpn_linux_gui/resources/img/utils/fastest.png new file mode 100644 index 0000000..1d915e7 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/fastest.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/hamburger-menu-icon (copy).png b/protonvpn_linux_gui/resources/img/utils/hamburger-menu-icon (copy).png new file mode 100644 index 0000000..cdb21f3 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/hamburger-menu-icon (copy).png differ diff --git a/protonvpn_linux_gui/resources/img/utils/hamburger-menu-icon.png b/protonvpn_linux_gui/resources/img/utils/hamburger-menu-icon.png new file mode 100644 index 0000000..1f4dc72 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/hamburger-menu-icon.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/info-green.png b/protonvpn_linux_gui/resources/img/utils/info-green.png new file mode 100644 index 0000000..e67e83a Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/info-green.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/normal.png b/protonvpn_linux_gui/resources/img/utils/normal.png new file mode 100755 index 0000000..74e9147 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/normal.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/p2p-arrows.png b/protonvpn_linux_gui/resources/img/utils/p2p-arrows.png new file mode 100755 index 0000000..089e026 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/p2p-arrows.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/plus-server.png b/protonvpn_linux_gui/resources/img/utils/plus-server.png new file mode 100755 index 0000000..bd008f5 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/plus-server.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/random.png b/protonvpn_linux_gui/resources/img/utils/random.png new file mode 100644 index 0000000..88afef9 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/random.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/search.png b/protonvpn_linux_gui/resources/img/utils/search.png new file mode 100644 index 0000000..e28e0b6 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/search.png differ diff --git a/protonvpn_linux_gui/resources/img/utils/tor-onion.png b/protonvpn_linux_gui/resources/img/utils/tor-onion.png new file mode 100755 index 0000000..a383c35 Binary files /dev/null and b/protonvpn_linux_gui/resources/img/utils/tor-onion.png differ diff --git a/protonvpn_linux_gui/resources/main.css b/protonvpn_linux_gui/resources/main.css new file mode 100644 index 0000000..a6408d8 --- /dev/null +++ b/protonvpn_linux_gui/resources/main.css @@ -0,0 +1,174 @@ +headerbar.default-decoration { + padding-top: 3px; + padding-bottom: 3px; + min-height: 0px; + font-size: 0.8em; + background-color: green; +} + +.default_background{ + background-color: rgba(62, 68, 73, 1); + color: white; +} +.overlay_background{ + background-color: rgba(52, 58, 63, 1); + color: white; +} + +.white_text{ + color: white; +} + +.top_menu_hamburger{ + margin-top: 2px; + margin-bottom: 2px; +} + +.text_hamburger_identation{ + margin-left: -20px; +} + +.initialize_profile_btn{ + background-color: transparent; + color: white; + padding: 10px 50px; + border-style: solid; + border-width: 2px; + border-radius: 20px; + transition: all .115s ease-in-out; +} + +.initialize_profile_btn:hover { + border-color: transparent; + background-color: rgb(86, 179, 102); +} + + +.banner_shadow{ + box-shadow: 64px 64px 12px 40px rgba(0,0,0,0.4); +} + +.default_main_tab_conf{ + padding: 20px 70px; + background-color: red; + color: white; + margin-top: -6px; + margin-bottom: -6px; + transition: all .115s ease-in-out; +} + +.test{ + background-color: red; + color: red; +} +.active_tab{ + color: white; + background-color: rgba(62, 68, 73, 1); +} + +.inactive_tab{ + background-color: rgba(55, 61, 66, 1); + color: gray; +} + +.left_tab{ + /* border-top-right-radius: 80px; */ + margin-left: -20px; + margin-right: -25px; + +} +.right_tab{ + /* border-top-left-radius: 80px; */ + margin-right: -20px; +} + +.countries_content_style{ + padding: 5px 10px; + /* transition: all 5s ease-in-out; */ +} + +.profiles_tab_content{ + padding: 10px 15px; +} + +.profile_grid{ + padding: 20px; +} + +.profile_buttons{ + padding: 5px 5px; + color: white; + background-color: rgba(68, 73, 78, 1); +} + +.server_list_bakground_row_selected{ + background-color: black; +} + +.server_list_bakground_row:hover, .menu_list_hover:hover{ + background-color: rgb(86, 179, 102); +} + +/* +|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +----------------------- Settings Window ----------------------- +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +*/ + +.settings_label_bg{ + background-color: rgba(45, 51, 56, 1); +} +.settings_label{ + padding: 30px 50px; +} + +.settings_notebook_grid{ + padding: 30px 100px; + padding-bottom: 200px; +} + +.default_settings_tab_conf{ + padding: 15px 40px; + /* background-color: transparent; */ + margin-top: -6px; + margin-bottom: -6px; + transition: all .115s ease-in-out; +} + +.settings_left_tab{ + /* border-top-left-radius: 20px; */ + /* border-top-right-radius: 20px; */ + margin-left: -20px; + /* padding-right: 60px; */ +} + +.settings_center_left_tab{ + margin-left: -24px; + /* border-top-left-radius: 20px; + border-top-right-radius: 20px; */ +} +.settings_center_right_tab{ + margin-left: -24px; + /* border-top-left-radius: 20px; + border-top-right-radius: 20px; */ +} + +.settings_right_tab{ + /* border-top-left-radius: 20px; */ + /* border-top-right-radius: 20px; */ + margin-left: -24px; + margin-right: -20px; + /* padding-left: 60px; */ +} + +.split_tunnling_list{ + background-color: rgba(52, 58, 63, 1); + color: white; + padding: 10px 10px; + /* border-radius: 5px; */ +} +.split_tunnling_list text{ + background-color: rgba(52, 58, 63, 1); + color: white; + /* border-radius: 5px; */ +} diff --git a/protonvpn_linux_gui/resources/main.glade b/protonvpn_linux_gui/resources/main.glade index 343baab..3956cda 100644 --- a/protonvpn_linux_gui/resources/main.glade +++ b/protonvpn_linux_gui/resources/main.glade @@ -1,36 +1,204 @@ - + + + + + + + + False + ProtonVPN GUI - About + False + True + center-always + True + img/logo/protonvpn_logo.png + notification + True + False + False + center + Unofficial ProntVPN GUI for Linux + Proton Technologies AG + Based on protonvpn-cli-ng + https://github.com/calexandru2018/protonvpn-linux-gui + Github Repo + calexandru2018 + img/logo/protonvpn-logo-white.png + gpl-3-0 + + + + + + + False + center + 15 + 15 + 30 + 30 + vertical + 2 + + + False + True + spread + + + + + + + + + + False + True + 0 + + + + + + + + True + False + center + True + True + + + True + False + center + 50 + 20 + True + start + + + + + + + + + Update + True + True + True + + + + + True + True + 3 + + + + + Help + True + True + True + + + + + True + True + 4 + + + + + 0 + 2 + 3 + + + + + + + + + + + + + + + + + + + + + + + + True + True + 3 + + + + + + + + + + - - - - - - - + - - - 0 - Enable DNS Leak Protection - - - 1 - Configure Custom DNS Server - - - 2 - None - - @@ -56,13 +224,14 @@ Main Window + 200 True True ProtonVPN GUI - Login center-always - 440 + 150 250 - protonvpn_logo.png + img/logo/protonvpn_logo.png center True False @@ -71,12 +240,12 @@ - 100 - 0 True False center center + 50 + 50 10 10 True @@ -86,23 +255,20 @@ True False + center 20 10 - + True - True - True - 10 - 10 - True - False - False - * + False + 30 + 40 + img/logo/protonvpn-logo-white.png 0 - 2 + 0 @@ -110,11 +276,12 @@ True False 10 - 10 - Password + 30 + Unofficial ProtonVPN Linux GUI + fill - + @@ -122,13 +289,13 @@ 1 - - - + 0 - 1 + 0 @@ -137,45 +304,62 @@ False 20 10 + True + True - - 10 - 0 + True - True - True - 10 - 10 - True - False - 30 + False + start + Start on Boot + + + 0 - 3 + 0 - + + 50 True - False - 30 - 40 - protonvpn_logo_full.png + True + end - 0 + 3 0 + + + + + + + + + 0 + 4 + + + + + True + False + 30 + 20 + True + True True False 10 10 - Username - fill + ProtonVPN Plan @@ -183,127 +367,45 @@ 0 - 2 + 0 + 4 - + + Free True - False - 10 - 30 - Unofficial ProtonVPN Linux GUI - fill - - - - + True + False + start + True + True + 0 1 - - - 0 - 0 - - - - - True - False - 20 - vertical - - - - - - Initialize Profile - True - True - True - center - 10 - 10 - True - - - - push-button - - - - - True - True - 1 - - - - - - - - 0 - 4 - - - - - True - False - 20 - 10 - True - True - - - True - False - 10 - 10 - ProtonVPN Plan - - - - - - - 0 - 1 - 4 - - - - - Free - True - True - False - True - True - - - 0 - 2 - - Basic True True False + center True True member_free + 1 - 2 + 1 @@ -312,13 +414,17 @@ True True False + center True True member_free + 2 - 2 + 1 @@ -327,80 +433,92 @@ True True False + baseline True True member_free + 3 - 2 + 1 - - - - - - - - - - - - + 0 - 2 + 3 True False - center 20 10 - True - True - - TCP + True - True - False - 15 - True - True + False + start + 10 + 10 + Password + + + + - 1 - 2 + 0 + 0 - - UDP + True True - False - 15 - True - True - protocol_tcp_checkbox + True + True + False + False + * + - 2 - 2 + 0 + 1 + + + + 0 + 2 + + + + + True + False True False + start 10 10 - Default OpenVPN Protocol + Username + fill @@ -408,36 +526,90 @@ 0 - 1 - 4 + 0 + 3 - - - - - - - - - - - - - + + True + True + True + True + False + 30 + + + + 0 + 1 + 3 + + + + 0 + 1 + + + + + True + False + center + 50 + 30 - + + True + True + True + center + 10 + 10 + True + + + + True + False + Login + + + + + + + + + push-button + + + + + + 0 + 0 + 0 - 3 + 5 + + 400 @@ -448,7 +620,7 @@ True center True - protonvpn_logo.png + img/logo/protonvpn_logo.png dialog True True @@ -478,12 +650,25 @@ - Close True True True True + + + True + False + Close + + + + + + + True @@ -512,6 +697,9 @@ + True @@ -552,2184 +740,1967 @@ 2 + + - + - - - - - - - - - + + + + + + 0 + TCP + + + 1 + UDP + + + + - - - - - - + + + + - + - - + + 0 - Do not display + Free 1 - Display + Basic + + + 2 + Plus + + + 3 + Visionary - - 680 - 720 - False - True - True - ProtonVPN GUI - Configurations - center - 680 - 520 - protonvpn_logo.png - west - + + + + + + + + + + 0 + Do not display + + + 1 + Display + + + + + 400 + 400 + False + + 420 + 420 True True in + 720 + 720 + 720 + 720 + 420 + 420 True False + True + True + 420 + 420 True False - center - 30 - 30 - 15 - - - True - False - center - 20 - Configurations - - - - - - - 0 - 0 - - + True + True + True - - 400 + True False - 15 - 30 - 40 - 5 - 15 - True - - - True - True - False - False - - - - 1 - 2 - 3 - - - - - True - False - Password: - - - 0 - 2 - - - - - True - False - Username: - - - 0 - 1 - - - - - True - True - False - - - 1 - 1 - 3 - - True False - 10 - 10 - User Information + Settings - + + 0 0 - 4 - - - - - Update User - 150 - True - True - True - center - end - 10 - - - - 1 - 3 - 2 - - - - - - + 0 - 1 + 0 + 3 - - 477 + True - False - 15 - 15 - 40 - 5 - 25 - True - - - Free - True - True - False - True - True - - - 0 - 1 - - - - - Visionary - True - True - False - True - member_free_update_checkbox - - - 3 - 1 - - - - - Plus - True - True - False - True - member_free_update_checkbox - - - 2 - 1 - - + True + False + True + - - Basic + True - True - False - True - member_free_update_checkbox + False + 25 + True + + + True + False + start + Username + + + + + + + 0 + 0 + + + + + True + False + start + Password + + + + + + + 0 + 1 + + + + + 150 + True + True + True + center + end + + + + True + False + Update + + + + + + 1 + 2 + + + + + True + True + False + + + 1 + 0 + + + + + True + True + False + False + + + + 1 + 1 + + + + + True + False + start + Show notifications + + + + + + + 0 + 7 + + + + + True + True + end + center + + + 1 + 7 + + + + + True + True + end + center + + + 1 + 6 + + + + + True + True + end + center + + + 1 + 5 + + + + + True + False + start + Start on boot + + + + + + + 0 + 6 + + + + + True + False + start + Start Minimized + + + + + + + 0 + 5 + + + + + True + False + start + ProtonVPN Plan + + + + + + + 0 + 4 + + + + + True + False + TierListStore + 0 + + + + + 1 + + + + + 1 + 4 + + + + + + + + + + + + - 1 - 1 + True - - + + True False - 10 - 10 - ProtonVPN Plan + True + General + - 0 - 0 - 4 + True + False - - Update Plan - 150 + True - True - True - center - end - 10 - + False + 25 + True + + + True + False + start + 10 + 10 + Data Transmitted + + + + + + + 0 + 0 + + + + + True + False + start + 10 + 10 + Servername + + + + + + + 0 + 1 + + + + + True + False + start + 10 + 10 + Time Connected + + + + + + + 0 + 2 + + + + + True + False + start + 10 + 10 + Server Load + + + + + + + 0 + 3 + + + + + True + False + Tray_Configurations + 0 + False + 1 + 0 + + + + + 1 + + + + + 1 + 0 + + + + + True + False + Tray_Configurations + 0 + False + 1 + 0 + + + + + 1 + + + + + 1 + 1 + + + + + True + False + Tray_Configurations + 0 + False + 1 + 0 + + + + + 1 + + + + + 1 + 2 + + + + + True + False + Tray_Configurations + 0 + False + 1 + 0 + + + + + 1 + + + + + 1 + 3 + + + - 1 - 2 - 2 + 1 - - - - - - - - - 0 - 3 - - - - - 400 - True - False - 15 - 30 - 40 - 5 - 15 - True - - + + True False - 10 - 10 - DNS Management + System Tray + - 0 - 0 - 4 - - - - - True - False - True - False - - - 1 - 2 - 3 + 1 + False - + True False - DNS Preference - - - 0 - 1 - - - - - True - False - Custom DNS: - - - 0 - 2 - - - - - True - False - DNSListStore - 2 - False - 1 - 0 - + 25 + True + + + True + False + start + Auto Connect + + + + + + + 0 + 0 + + - - - 1 - + + True + False + start + Quick Connect + + + + + + + 0 + 1 + + + + True + False + AutoconnectListStore + False + 1 + 2 + + + + + 1 + + + + + 1 + 0 + + + + + True + False + AutoconnectListStore + False + 1 + 0 + + + + + 1 + + + + + 1 + 1 + + + + + True + False + start + Default Protocol + + + + + + + 0 + 2 + + + + + True + False + ProtocolListStore + 0 + + + + + 1 + + + + + 1 + 2 + + + - 1 - 1 - 3 - - - - - Update DNS - 150 - True - True - True - center - end - 10 - - - - 1 - 3 - 2 + 2 - - - - - - - - - 0 - 2 - - - - - 477 - True - False - 15 - 15 - 40 - 5 - 25 - True - - + + True False - 10 - 10 - Default OpenVPN Protocol + True + Connection + - 0 - 0 - 4 - - - - - TCP - True - True - False - True - True - - - 1 - 1 - - - - - UDP - True - True - False - True - protocol_tcp_update_checkbox - - - 2 - 1 + 2 + True + False - - Update Protocol - 150 + True - True - True - center - end - 10 - + False + 25 + True + + + True + False + start + Kill Switch + + + + + + + 0 + 0 + + + + + True + False + start + DNS Leak Protection + + + + + + + 0 + 1 + + + + + True + False + start + Split Tunneling + + + + + + + 0 + 2 + + + + + True + True + end + center + + + + 1 + 1 + + + + + True + True + end + center + + + + 1 + 0 + + + + + True + True + end + center + + + + 1 + 2 + + + + + False + 10 + True + + + True + True + True + True + + + + 1 + 3 + + + + + True + False + start + IP: + + + + + + 1 + 2 + + + + + 150 + True + True + True + end + end + + + + True + False + Update + + + + + + 1 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 3 + 2 + + + - 1 - 2 - 2 + 3 - - - - - - - - - - - - - - - 0 - 4 - - - - - 477 - True - False - 15 - 15 - 40 - 15 - 15 - True - - + + True False - 10 - 10 - Purge Configurations + True + Advanced + - 0 - 0 - 4 - - - - - False - By purging your configurations, all af your saved data such as username, password, cached servers, logs and previous connection information will be lost! - fill - True - word-char - 1 - 30 - - - 0 - 1 - 4 - - - - - Purge Configurations - 150 - True - True - True - center - 10 - - - - 1 - 2 - 2 + 3 + True + False - - - - - - + 0 - 9 + 1 + 3 + 2 + + + + + + + + + + True + False + gtk-delete + + + True + False + img/utils/hamburger-menu-icon (copy).png + 3 + + + + + -1 + True + True + True + ProtonVPN GUI - Dashboard + False + center-always + img/logo/protonvpn_logo.png + center + + + + + + 460 + -1 + True + True + True + etched-in + 412 + 400 + 450 + 740 + True + True + + + 460 + True + False + True + none + + + 460 + -1 + True + False + True + True - + True False - 15 - 15 - 40 - 5 - 15 - True + True + out - + + -1 True False - 10 - 10 - Split Tunneling - - - - - - - 0 - 0 - 4 - - - - - 477 - 300 - True - True - in + True + vertical + 2 - + + 460 + 250 True False + True - + True - True + False + + + True + False + 0.5 + img/logo/protonvpn_logo.png + + + -90 + -65 + + + + + + -1 + + + + + True + False + 35 + 35 + 30 + 50 + True + 7 + True + + + Delete Profile + True + True + True + start + center + gtk-delete-profile + none + True + + + + 0 + 4 + + + + + -1 + True + False + end + True + fill + + + + + + 1 + 1 + + + + + True + True + True + baseline + 10 + 10 + none + + + + True + False + + + + + + + + + + 0 + 5 + 2 + + + + + -1 + True + False + end + True + fill + + + + + + 1 + 0 + + + + + -1 + True + False + start + True + + + + + + 0 + 1 + + + + + -1 + True + False + start + True + + + + + + 0 + 2 + + + + + -1 + True + False + start + True + + + + + + 0 + 3 + + + + + True + False + end + 5 + + + True + False + img/utils/bitrate-download-arrow.png + + + 1 + 0 + + + + + -1 + True + False + True + fill + + + + + + 0 + 0 + + + + + 1 + 3 + + + + + True + False + end + 5 + + + True + False + img/utils/bitrate-upload-arrow.png + + + 1 + 0 + + + + + -1 + True + False + start + True + fill + + + + + + 0 + 0 + + + + + 1 + 2 + + + + + True + False + + + False + img/logo/protonvpn_sign_green.png + + + 0 + 0 + + + + + -1 + True + False + start + True + + + + + + + 1 + 0 + + + + + 0 + 0 + + + + + + + True + + + + 0 + 0 + - - - 0 - 1 - 4 - - - - - Update Tunneling - 150 - True - True - True - center - end - 10 - - - - 1 - 2 - 2 - - - - - - - + + + 450 + 300 + True + True + True + True + True + False + True + + + + 460 + 400 + True + False + True + vertical + 15 + + + True + False + + + True + False + start + 10 + 10 + 10 + True + Secure Core + + + 1 + 0 + + + + + 50 + True + True + start + center + 15 + + + + 0 + 0 + + + + + + False + True + 0 + + + + + True + True + False + edit-find-symbolic + Search for country or server + + + + + False + True + 1 + + + + + -1 + True + True + True + True + True + never + always + in + True + True + + + True + True + True + True + natural + ServerTreeStore + False + country_col + 1 + + + + multiple + + + + + 5 + fixed + Flag + True + + + + 0 + + + + + + + 5 + fixed + Country + True + True + 0 + + + + 1 + + + + + + + 5 + fixed + Plus Servers + True + + + + 2 + + + + + + + True + 5 + fixed + Feature + True + True + + + + 3 + + + + + + + 5 + fixed + Load + True + True + + + + 4 + + + + + + + + + + + False + True + 2 + + + + + + True + + + + + True + False + True + True + Countries + fill + True + + + + + + + + True + False + + + + + True + False + vertical + 5 + + + True + True + True + + + + True + False + + + True + False + 10 + Fastest + + + + + + 1 + 0 + + + + + True + False + img/utils/fastest.png + + + 0 + 0 + + + + + + + + + False + True + 0 + + + + + True + True + True + + + + True + False + + + True + False + img/utils/random.png + + + 0 + 0 + + + + + True + False + 10 + Random + + + + + + 1 + 0 + + + + + + + + + False + True + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + True + + + + + True + False + True + True + Profiles + fill + True + 0.5 + + + + + + + + 1 + True + False + + + + + + 0 + 1 + + + + + 0 - 7 + 1 + 3 - - 400 + True False - 40 - 5 - 15 - True - - - True - False - 10 - 10 - Kill Switch - - - - - - - 0 - 0 - 4 - - - - - True - False - Setting - - - 0 - 1 - - - - - True - False - KillSwitchListStore - 0 - False - 1 - 0 - - - - - 1 - - - - - 1 - 1 - 3 - - - - - Update Kill Switch - 150 - True - True - True - center - end - 10 - - - - 1 - 3 - 2 - - - - - - - - - - - - - - - - - - - - + True + True + img/logo/protonvpn_logo_full.png - 0 - 6 + 1 + 1 + 3 + 3 - - 400 + True False - 40 - 5 - 15 - True - + True False - 10 - 10 - Autoconnect on Boot - - - - - - - 0 - 0 - 4 - - - - - Update Autoconnect - 150 - True - True - True - center - 10 - + protonvpn-logo + False + True + - - 1 - 3 - 2 - - + True False - AutoconnectListStore - False - 1 - 0 - - - - 1 - + gtk-justify-fill + False + True + + + True + False + + + True + False + Configurations + + + + + + + True + False + Diagnose + + + + + + + True + False + + + + + True + False + Disconnect + True + + + + + + + True + False + + + + + True + False + About + True + + + + + + + True + False + + + + + True + False + Exit + + + + + + - - 1 - 1 - 3 - - - - - True - False - Setting - - - 0 - 1 - - - - - - - - - - - - - - - - - - - + 0 - 5 - - - - - 477 - True - False - 40 - 15 - 15 - True - - - True - False - 10 - 10 - Tray Configurations - - - - - - - 0 - 0 - 8 - - - - - Update Tray - 150 - True - True - True - center - 10 - - - - 1 - 3 - 6 - - - - - True - False - Tray_Configurations - 0 - False - 1 - 0 - - - - 1 - - - - - 0 - 2 - 2 - - - - - True - False - Tray_Configurations - 0 - False - 1 - 0 - - - - 1 - - - - - 2 - 2 - 2 - - - - - True - False - Tray_Configurations - 0 - False - 1 - 0 - - - - 1 - - - - - 4 - 2 - 2 - - - - - True - False - 10 - 10 - Data Transmitted - - - - - - - 0 - 1 - 2 - - - - - True - False - 10 - 10 - Servername - - - - - - - 2 - 1 - 2 - - - - - True - False - 10 - 10 - Time Connected - - - - - - - 4 - 1 - 2 - - - - - True - False - 10 - 10 - Server Load - - - - - - - 6 - 1 - 2 - - - - - True - False - Tray_Configurations - 0 - False - 1 - 0 - - - - 1 - - - - - 6 - 2 - 2 - - - - - - - - - - - 0 - 8 - - - - - - - - - - - True - False - gtk-execute - True - - - True - False - gtk-preferences - - - True - True - True - True - ProtonVPN GUI - Dashboard - center-always - 440 - 250 - protonvpn_logo.png - center - True - - - - - - True - False - vertical - - - True - False - - - True - False - _File - True - - - True - False - - - Configurations - True - False - gtk-preferences - False - True - - - - - - True - False - - - - - gtk-quit - True - False - True - True - True - - - - - - - - - True - False - _Help - True - - - True - False - - - gtk-about - True - False - True - True - True - - - - - - Diagnose - True - False - gtk-execute - False - True - - - - - - - - - - False - True - 0 - - - - - True - False - True - 80 - 80 - 15 - 15 - True - 1 - - - True - False - 30 - 20 - protonvpn_logo_full.png - - - 0 - 0 - 4 - - - - - False - True - 5 - 1 - - - - - True - False - center - 60 - 60 - True - 150 - True - - - True - False - 30 - 100 - 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 - fill - - - - - - - 1 - 0 - - - - - -1 - True - False - start - True - DNS Protection: - fill - - - - - - - 0 - 1 - - - - - -1 - True - False - start - True - 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 - 0 - 2 - 10 - - - - - True - False - 20 - 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 - 0 - 4 - 10 - - - - - False - True - 2 - - - - - -1 - 4 - True - False - 30 - 30 - 30 - 30 - True - True - 10 - True - - - 350 - 300 - True - True - True - 15 - 15 - True - True - never - always - in - 100 - True - True - - - 100 - True - True - baseline - True - True - natural - ServerTreeStore - country_col - True - True - horizontal - True - - - multiple - - - - - True - fixed - Country - True - True - 0 - - - - 0 - - - - - - - True - fixed - Server# - True - 1 - - - - 1 - - - - - - - True - fixed - Tier - True - True - 2 - - - - 2 - - - - - - - True - fixed - Load - True - 3 - - - - 3 - - - - - - - True - fixed - Feature - True - True - 4 - - - - 4 - - - - - - - - - 0 - 1 - 4 - - - - - gtk-disconnect - True - True - True - end - True - True - - - - 3 - 2 - - - - - gtk-connect - True - True - True - end - True - True - - - - 3 - 0 - - - - - gtk-refresh - True - True - True - start - True - right - True - - - - 0 - 0 - - - - - Reconnect - True - True - True - start - - - - 0 - 2 - - - - - Fastest Connect - True - True - True - center - - - - 2 - 2 - - - - - Random Connect - True - True - True - start - 30 - - - - 1 - 2 - - - - - True - True - False - Type to filter... - - - - 1 - 0 - 2 - - - - - False - True - 3 - - - - - - - - - - False - ProtonVPN GUI - About - False - True - center-always - True - protonvpn_logo.png - dialog - True - False - False - center - DashboardWindow - Unofficial ProntVPN GUI for Linux - Proton Technologies AG - Based on protonvpn-cli-ng - https://github.com/calexandru2018/protonvpn-linux-gui - Github Repo - calexandru2018 - protonvpn_logo_full.png - gpl-3-0 - - - - - - - False - center - 15 - 15 - 30 - 30 - vertical - 2 - - - False - True - spread - - - - - - - - - False - True - 0 - - - - - - - - True - False - center - True - True - - - True - False - center - 20 - start - - - - - - - - - Update - True - True - True - - - - True - True - 3 - - - - - Help - True - True - True - - - - True - True - 4 + 0 + 4 + - - 0 - 2 - 3 - - - - - - - - - - - - - - - - - - - + - - True - True - 3 - - - - + + diff --git a/protonvpn_linux_gui/thread_functions.py b/protonvpn_linux_gui/thread_functions.py index 0bdc3f5..8db2003 100644 --- a/protonvpn_linux_gui/thread_functions.py +++ b/protonvpn_linux_gui/thread_functions.py @@ -25,14 +25,25 @@ get_gui_processes, manage_autoconnect, populate_autoconnect_list, - get_server_protocol_from_cli + get_server_protocol_from_cli, + get_gui_config, + set_gui_config ) # Import GUI logger from .gui_logger import gui_logger # Import constants -from .constants import VERSION, GITHUB_URL_RELEASE, TRAY_CFG_SERVERLOAD, TRAY_CFG_SERVENAME, TRAY_CFG_DATA_TX, TRAY_CFG_TIME_CONN, TRAY_CFG_DICT +from .constants import ( + VERSION, + GITHUB_URL_RELEASE, + TRAY_CFG_SERVERLOAD, + TRAY_CFG_SERVENAME, + TRAY_CFG_DATA_TX, + TRAY_CFG_TIME_CONN, + TRAY_CFG_DICT, + GUI_CONFIG_FILE +) # PyGObject import import gi @@ -130,25 +141,73 @@ def on_login(interface, username_field, password_field, messagedialog_label, use gui_logger.debug("Passfile created") os.chmod(PASSFILE, 0o600) + gui_config = configparser.ConfigParser() + gui_config["connections"] = { + "display_secure_core": False + } + gui_config["general_tab"] = { + "start_min": False, + "start_on_boot": False, + "show_notifications": False, + } + gui_config["tray_tab"] = { + TRAY_CFG_DATA_TX: "0", + TRAY_CFG_SERVENAME: "0", + TRAY_CFG_TIME_CONN: "0", + TRAY_CFG_SERVERLOAD: "0", + } + gui_config["conn_tab"] = { + "autoconnect": "dis", + "quick_connect": "dis", + } + + with open(GUI_CONFIG_FILE, "w") as f: + gui_config.write(f) + change_file_owner(GUI_CONFIG_FILE) + gui_logger.debug("pvpn-gui.cfg initialized") + set_config_value("USER", "initialized", 1) load_on_start({"interface":interface, "gui_enabled": True, "messagedialog_label": messagedialog_label}) +def reload_secure_core_servers(interface, messagedialog_label, messagedialog_spinner, update_to): + """Function that reloads server list to either secure-core or non-secure-core. + """ + # Sleep is needed because it takes a second to update the information, + # which makes the button "lag". Temporary solution. + time.sleep(1) + gui_logger.debug(">>> Running \"update_reload_secure_core_serverslabels_server_list\".") + + set_gui_config("connections", "display_secure_core", update_to) + + # update_labels_server_list(interface) + populate_servers_dict = { + "tree_object": interface.get_object("ServerTreeStore"), + "servers": False + } + + gobject.idle_add(populate_server_list, populate_servers_dict) + + messagedialog_label.set_markup("Displaying {} servers!".format("secure-core" if update_to == "True" else "non secure-core")) + messagedialog_spinner.hide() + + gui_logger.debug(">>> Ended tasks in \"reload_secure_core_servers\" thread.") + # Dashboard hanlder -def connect_to_selected_server(interface, selected_server, messagedialog_label, messagedialog_spinner): +def connect_to_selected_server(*args): """Function that either connects by selected server or selected country. """ protocol = get_config_value("USER", "default_protocol") gui_logger.debug(">>> Running \"openvpn_connect\".") - + # Check if it should connect to country or server - if not selected_server["selected_country"]: - result = subprocess.run(["protonvpn", "connect", selected_server["selected_server"], "-p", protocol], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if "#" in args[0]["user_selected_server"]: + result = subprocess.run(["protonvpn", "connect", args[0]["user_selected_server"], "-p", protocol], stdout=subprocess.PIPE, stderr=subprocess.PIPE) gui_logger.debug(">>> Log during connection to specific server: {}".format(result)) else: for k, v in country_codes.items(): - if v == selected_server["selected_country"]: + if v == args[0]["user_selected_server"]: selected_country = k break result = subprocess.run(["protonvpn", "connect", "--cc", selected_country, "-p", protocol], stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -161,11 +220,11 @@ def connect_to_selected_server(interface, selected_server, messagedialog_label, if server_protocol: display_message = "You are connect to {} via {}!".format(server_protocol, protocol.upper()) - messagedialog_label.set_markup(display_message) - messagedialog_spinner.hide() + args[0]["messagedialog_label"].set_markup(display_message) + args[0]["messagedialog_spinner"].hide() update_labels_dict = { - "interface": interface, + "interface": args[0]["interface"], "servers": False, "disconnecting": False, "conn_info": False @@ -175,7 +234,60 @@ def connect_to_selected_server(interface, selected_server, messagedialog_label, gui_logger.debug(">>> Ended tasks in \"openvpn_connect\" thread.") -def quick_connect(interface, messagedialog_label, messagedialog_spinner): +def custom_quick_connect(*args): + """Make a custom quick connection + """ + quick_conn_pref = get_gui_config("conn_tab","quick_connect") + protocol = get_config_value("USER","default_protocol") + + display_message = "" + command = "--fastest" + country = False + + if quick_conn_pref == "fast": + command="-f" + elif quick_conn_pref == "rand": + command="-r" + elif quick_conn_pref == "p2p": + command="--p2p" + elif quick_conn_pref == "sc": + command="--sc" + elif quick_conn_pref == "tor": + command="--tor" + else: + command="--cc" + country=quick_conn_pref.upper() + + command_list = ["protonvpn", "connect", command, "-p" ,protocol] + if country: + command_list = ["protonvpn", "connect", command, country, "-p" ,protocol] + + result = subprocess.run(command_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + update_labels_dict = { + "interface": args[0]["interface"], + "servers": False, + "disconnecting": False, + "conn_info": False + } + + server_protocol = get_server_protocol_from_cli(result) + + display_message = result.stdout.decode() + + if server_protocol: + display_message = "You are connect to {} via {}!".format(server_protocol, protocol.upper()) + + args[0]["messagedialog_label"].set_markup(display_message) + args[0]["messagedialog_spinner"].hide() + + gui_logger.debug(">>> Result: \"{0}\"".format(result)) + + update_labels_status(update_labels_dict) + + gui_logger.debug(">>> Ended tasks in \"custom_quick_connect\" thread.") + +def quick_connect(*args): """Function that connects to the quickest server. """ protocol = get_config_value("USER", "default_protocol") @@ -186,7 +298,7 @@ def quick_connect(interface, messagedialog_label, messagedialog_spinner): result = subprocess.run(["protonvpn", "connect", "--fastest", "-p", protocol], stdout=subprocess.PIPE, stderr=subprocess.PIPE) update_labels_dict = { - "interface": interface, + "interface": args[0]["interface"], "servers": False, "disconnecting": False, "conn_info": False @@ -198,8 +310,8 @@ def quick_connect(interface, messagedialog_label, messagedialog_spinner): if server_protocol: display_message = "You are connect to {} via {}!".format(server_protocol, protocol.upper()) - messagedialog_label.set_markup(display_message) - messagedialog_spinner.hide() + args[0]["messagedialog_label"].set_markup(display_message) + args[0]["messagedialog_spinner"].hide() gui_logger.debug(">>> Result: \"{0}\"".format(result)) @@ -269,11 +381,11 @@ def random_connect(interface, messagedialog_label, messagedialog_spinner): gui_logger.debug(">>> Ended tasks in \"random_c\" thread.") -def disconnect(interface, messagedialog_label, messagedialog_spinner): +def disconnect(*args): """Function that disconnects from the VPN. """ update_labels_dict = { - "interface": interface, + "interface": args[0]["interface"], "servers": False, "disconnecting": True, "conn_info": False @@ -283,36 +395,14 @@ def disconnect(interface, messagedialog_label, messagedialog_spinner): result = subprocess.run(["protonvpn", "disconnect"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - messagedialog_label.set_markup(result.stdout.decode()) - messagedialog_spinner.hide() + args[0]["messagedialog_label"].set_markup(result.stdout.decode()) + args[0]["messagedialog_spinner"].hide() gui_logger.debug(">>> Result: \"{0}\"".format(result)) update_labels_status(update_labels_dict) gui_logger.debug(">>> Ended tasks in \"disconnect\" thread.") - -def refresh_server_list(interface, messagedialog_window, messagedialog_spinner): - """Function that refreshes dashboard labels and server list. - """ - # Sleep is needed because it takes a second to update the information, - # which makes the button "lag". Temporary solution. - time.sleep(1) - - gui_logger.debug(">>> Running \"update_labels_server_list\".") - - # update_labels_server_list(interface) - populate_servers_dict = { - "tree_object": interface.get_object("ServerTreeStore"), - "servers": False - } - - gobject.idle_add(populate_server_list, populate_servers_dict) - - messagedialog_window.hide() - messagedialog_spinner.hide() - - gui_logger.debug(">>> Ended tasks in \"update_labels_server_list\" thread.") # Preferences/Configuration menu HANDLERS def update_user_pass(interface, messagedialog_label, messagedialog_spinner): @@ -346,79 +436,29 @@ def update_user_pass(interface, messagedialog_label, messagedialog_spinner): gui_logger.debug(">>> Ended tasks in \"set_username_password\" thread.") -def update_dns(interface, messagedialog_label, messagedialog_spinner): +def update_dns(interface, messagedialog_label, messagedialog_spinner, dns_value): """Function that updates DNS settings. """ - dns_combobox = interface.get_object("dns_preferens_combobox") - text_message = "" - custom_dns_ip = "The following IPs were added:\n" - - if (not dns_combobox.get_active() == 0) and (not dns_combobox.get_active() == 2): - dns_leak_protection = 0 - - custom_dns = interface.get_object("dns_custom_input").get_text() - - if len(custom_dns) == 0: - messagedialog_spinner.hide() - messagedialog_label.set_markup("Custom DNS field input can not be left empty.") - gui_logger.debug("[!] Custom DNS field left emtpy.") - return - - custom_dns = custom_dns.split(" ") - - for ip in custom_dns: - if not is_valid_ip(ip): - messagedialog_spinner.hide() - messagedialog_label.set_markup("{0} is not valid.\nNone of the DNS were added, please try again with a different DNS.".format(ip)) - gui_logger.debug("[!] Invalid IP \"{0}\".".format(ip)) - return - custom_dns_ip = custom_dns_ip + " " + ip + "\n" - - text_message = "custom setting" - - elif dns_combobox.get_active() == 2: - dns_leak_protection = 0 - custom_dns = None - interface.get_object("dns_custom_input").set_text("") - text_message = "disabled" - else: - dns_leak_protection = 1 - custom_dns = None - interface.get_object("dns_custom_input").set_text("") - text_message = "enabled" - gui_logger.debug(">>> Running \"set_dns_protection\".") - - set_config_value("USER", "dns_leak_protection", dns_leak_protection) - set_config_value("USER", "custom_dns", custom_dns) + set_config_value("USER", "dns_leak_protection", dns_value) + # set_config_value("USER", "custom_dns", custom_dns) - messagedialog_label.set_markup("DNS Management updated to {0}!\n{1}".format(text_message, "" if not custom_dns else custom_dns_ip)) + messagedialog_label.set_markup("DNS Management updated to {0}!".format("enabled" if dns_value == "1" else "disabled")) messagedialog_spinner.hide() gui_logger.debug(">>> Result: \"{0}\"".format("DNS Management updated.")) - gui_logger.debug(">>> Ended tasks in \"set_dns_protection\" thread.") + gui_logger.debug(">>> Ended tasks in \"dns_leak_switch_clicked\" thread.") -def update_pvpn_plan(interface, messagedialog_label, messagedialog_spinner): +def update_pvpn_plan(interface, messagedialog_label, messagedialog_spinner, tier, tier_display): """Function that updates ProtonVPN plan. """ - protonvpn_plan = 0 + + protonvpn_plan = tier visionary_compare = 0 - protonvpn_plans = {1: "Free", 2: "Basic", 3: "Plus", 4: "Visionary"} - protonvpn_radios = { - 1: interface.get_object("member_free_update_checkbox").get_active(), - 2: interface.get_object("member_basic_update_checkbox").get_active(), - 3: interface.get_object("member_plus_update_checkbox").get_active(), - 4: interface.get_object("member_visionary_update_checkbox").get_active() - } gui_logger.debug(">>> Running \"set_protonvpn_tier\".") - for k,v in protonvpn_radios.items(): - if v == True: - protonvpn_plan = int(k) - break - visionary_compare = protonvpn_plan if protonvpn_plan == 4: protonvpn_plan = 3 @@ -428,14 +468,14 @@ def update_pvpn_plan(interface, messagedialog_label, messagedialog_spinner): set_config_value("USER", "tier", str(protonvpn_plan)) - messagedialog_label.set_markup("ProtonVPN Plan has been updated to {}!\nServers list will be refreshed.".format(protonvpn_plans[4 if visionary_compare == 4 else int(protonvpn_plan+1)])) + messagedialog_label.set_markup("ProtonVPN Plan has been updated to {}!\nServers list will be refreshed.".format(tier_display)) messagedialog_spinner.hide() gui_logger.debug(">>> Result: \"{0}\"".format("ProtonVPN Plan has been updated!")) time.sleep(1.5) - # load_on_start({"interface":interface, "gui_enabled": True}) + load_on_start({"interface":interface, "gui_enabled": True}) populate_servers_dict = { "tree_object": interface.get_object("ServerTreeStore"), "servers": False @@ -445,11 +485,9 @@ def update_pvpn_plan(interface, messagedialog_label, messagedialog_spinner): gui_logger.debug(">>> Ended tasks in \"set_protonvpn_tier\" thread.") -def update_def_protocol(interface, messagedialog_label, messagedialog_spinner): +def update_def_protocol(interface, messagedialog_label, messagedialog_spinner, openvpn_protocol): """Function that updates default protocol. """ - openvpn_protocol = 'tcp' if interface.get_object('protocol_tcp_update_checkbox').get_active() == True else 'udp' - gui_logger.debug(">>> Running \"set_default_protocol\".") set_config_value("USER", "default_protocol", openvpn_protocol) @@ -459,95 +497,87 @@ def update_def_protocol(interface, messagedialog_label, messagedialog_spinner): gui_logger.debug(">>> Ended tasks in \"set_default_protocol\" thread.") -def update_autoconnect(interface, messagedialog_label, messagedialog_spinner): +def update_connect_preference(interface, messagedialog_label, messagedialog_spinner, user_choice, display_choice, quick_connect=False): """Function that updates autoconnect. """ - autoconnect_combobox = interface.get_object("autoconnect_combobox") - active_choice = autoconnect_combobox.get_active() - selected_country = False - display_text = "disabled" + active_choice = user_choice - gui_logger.debug(">>> Running \"update_autoconnect\".") + gui_logger.debug(">>> Running \"update_connect_preference\".") - set_config_value("USER", "autoconnect", active_choice) # autoconnect_alternatives = ["dis", "fast", "rand", "p2p", "sc", "tor"] - manage_autoconnect(mode="disable") - - if active_choice == 1: - manage_autoconnect(mode="enable", command="connect -f") - display_text = "fastest" - elif active_choice == 2: - manage_autoconnect(mode="enable", command="connect -r") - display_text = "random" - elif active_choice == 3: - manage_autoconnect(mode="enable", command="connect --p2p") - display_text = "peer2peer" - elif active_choice == 4: - manage_autoconnect(mode="enable", command="connect --sc") - display_text = "secure-core" - elif active_choice == 5: - manage_autoconnect(mode="enable", command="connect --tor") - display_text = "tor" - elif active_choice > 5: - # Connect to a specific country - country_list = populate_autoconnect_list(interface, return_list=True) - selected_country = country_list[active_choice] - for k, v in country_codes.items(): - if v == selected_country: - selected_country = k - display_text = v - break - if not selected_country: - print("[!] Unable to find country code") - return False - manage_autoconnect(mode="enable", command="connect --cc " + selected_country.upper()) + if not quick_connect: + manage_autoconnect(mode="disable") + + if active_choice == "dis": + pass + elif active_choice == "fast": + manage_autoconnect(mode="enable", command="connect -f") + elif active_choice == "rand": + manage_autoconnect(mode="enable", command="connect -r") + elif active_choice == "p2p": + manage_autoconnect(mode="enable", command="connect --p2p") + elif active_choice == "sc": + manage_autoconnect(mode="enable", command="connect --sc") + elif active_choice == "tor": + manage_autoconnect(mode="enable", command="connect --tor") + else: + # Connect to a specific country + manage_autoconnect(mode="enable", command="connect --cc " + active_choice.upper()) + + set_gui_config("conn_tab", "autoconnect", active_choice) + else: + set_gui_config("conn_tab", "quick_connect", active_choice) - messagedialog_label.set_markup("Autoconnect setting updated to connect to {}!".format(display_text)) + messagedialog_label.set_markup("{} setting updated to connect to {}!".format("Autoconnect" if not quick_connect else "Quick connect", display_choice)) messagedialog_spinner.hide() gui_logger.debug(">>> Ended tasks in \"update_autoconnect\" thread.") -def update_killswitch(interface, messagedialog_label, messagedialog_spinner): +def update_killswitch(interface, messagedialog_label, messagedialog_spinner, ks_value): """Function that updates killswitch configurations. """ - ks_combobox = interface.get_object("killswitch_combobox") - killswitch = ks_combobox.get_active() - split_tunnel_message = "" + set_config_value("USER", "killswitch", ks_value) - if int(killswitch) == 0: - split_tunnel_extra_message = "disabled" - elif int(killswitch) == 1: - split_tunnel_extra_message = "enabled but blocks access to/from LAN" - elif int(killswitch) == 2: - split_tunnel_extra_message = "enabled and allows access to/from LAN" + # Update killswitch label + result = "Kill Switch configuration updated to {}!".format("enabled" if ks_value == "1" else "disabled") + messagedialog_label.set_markup() + messagedialog_spinner.hide() - gui_logger.debug(">>> Running \"set_killswitch\".") + gui_logger.debug(">>> Result: \"{0}\"".format(result)) - if killswitch and int(get_config_value("USER", "split_tunnel")): - set_config_value("USER", "split_tunnel", 0) - split_tunnel_message = "Kill Switch can't be used with Split Tunneling.\nSplit Tunneling has been disabled.\n" + gui_logger.debug(">>> Ended tasks in \"update_killswitch_switch_changed\" thread.") - set_config_value("USER", "killswitch", killswitch) +def update_split_tunneling_status(messagedialog_label, messagedialog_spinner, update_to): - # Update killswitch label - killswitch_status = "Disabled" if str(killswitch) == "0" else "Enabled" - killswitch_label = interface.get_object("killswitch_label") - killswitch_label.set_markup('{0}'.format(killswitch_status)) - result = split_tunnel_message + "Kill Switch configuration updated to {}!".format(split_tunnel_extra_message) + if update_to == "1": + result = "Split tunneling has been enabled!\n" + else: + if os.path.isfile(SPLIT_TUNNEL_FILE): + os.remove(SPLIT_TUNNEL_FILE) + result = "Split tunneling has been disabled!\n" + + if int(get_config_value("USER", "killswitch")): + set_config_value("USER", "killswitch", 0) + + result = result + "Split Tunneling can't be used with Kill Switch, Kill Switch has been disabled!\n\n" + time.sleep(1) + + set_config_value("USER", "split_tunnel", update_to) + messagedialog_label.set_markup(result) messagedialog_spinner.hide() gui_logger.debug(">>> Result: \"{0}\"".format(result)) - gui_logger.debug(">>> Ended tasks in \"set_killswitch\" thread.") + gui_logger.debug(">>> Ended tasks in \"set_split_tunnel\" thread.") def update_split_tunneling(interface, messagedialog_label, messagedialog_spinner): """Function that updates split tunneling configurations. """ - result = "Split tunneling configurations updated!\n" + result = "Split tunneling configurations updated!\n" split_tunneling_buffer = interface.get_object("split_tunneling_textview").get_buffer() # Get text takes a start_iter, end_iter and the buffer itself as last param @@ -565,7 +595,7 @@ def update_split_tunneling(interface, messagedialog_label, messagedialog_spinner for ip in split_tunneling_content: if not is_valid_ip(ip): messagedialog_spinner.hide() - messagedialog_label.set_markup("{0} is not valid.!\nNone of the IP's were added, please try again with a different IP.".format(ip)) + messagedialog_label.set_markup("{0} is not valid!\nNone of the IP's were added, please try again with a different IP.".format(ip)) gui_logger.debug("[!] Invalid IP \"{0}\".".format(ip)) return @@ -608,21 +638,23 @@ def update_split_tunneling(interface, messagedialog_label, messagedialog_spinner gui_logger.debug(">>> Ended tasks in \"set_split_tunnel\" thread.") -def tray_configurations(interface, messagedialog_label, messagedialog_spinner): +def tray_configurations(interface, messagedialog_label, messagedialog_spinner, setting_value, setting_display): """Function to update what the tray should display. """ gui_logger.debug(">>> Running \"tray_configurations\".") - - response_list = [] - custom_msg = "" - for k,v in TRAY_CFG_DICT.items(): - combobox_val = interface.get_object(k).get_active() - set_config_value("USER", v, combobox_val) - response_list.append("Display" if combobox_val == 1 else "Do not display") - - custom_msg = "Data Transmitted: {0}\nServername: {1}\nTime Connected: {2}\nServer load: {3}".format(*response_list) - - result = "Tray configurations updated!\n\n" + custom_msg + msg = '' + if "serverload" in setting_display: + msg = "server load" + elif "server" in setting_display: + msg = "server name" + elif "data" in setting_display: + msg = "data transmission" + elif "time" in setting_display: + msg = "time connected" + + set_gui_config("tray_tab", TRAY_CFG_DICT[setting_display], setting_value) + + result = "Tray {0} is {1}!".format(msg, "displayed" if setting_value == 1 else "hidden") messagedialog_label.set_markup(result) messagedialog_spinner.hide() diff --git a/protonvpn_linux_gui/tray_icon.py b/protonvpn_linux_gui/tray_icon.py index 6bc9c73..81aae49 100644 --- a/protonvpn_linux_gui/tray_icon.py +++ b/protonvpn_linux_gui/tray_icon.py @@ -27,6 +27,8 @@ except: sys.exit(1) +from .utils import get_gui_config, set_gui_config + from .constants import TRAY_CFG_SERVERLOAD, TRAY_CFG_SERVENAME, TRAY_CFG_DATA_TX, TRAY_CFG_TIME_CONN from .gui_logger import gui_logger @@ -208,25 +210,25 @@ def get_tray_settings(self): } try: - resp_dict["display_serverload"] = int(get_config_value("USER", TRAY_CFG_SERVERLOAD)) + resp_dict["display_serverload"] = int(get_gui_config("USER", TRAY_CFG_SERVERLOAD)) except KeyError: gui_logger.debug("[!] Could not find display_serverload in config file: ".format(KeyError)) pass try: - resp_dict["display_server"] = int(get_config_value("USER", TRAY_CFG_SERVENAME)) + resp_dict["display_server"] = int(get_gui_config("USER", TRAY_CFG_SERVENAME)) except KeyError: gui_logger.debug("[!] Could not find display_server in config file: ".format(KeyError)) pass try: - resp_dict["display_data_tx"] = int(get_config_value("USER", TRAY_CFG_DATA_TX)) + resp_dict["display_data_tx"] = int(get_gui_config("USER", TRAY_CFG_DATA_TX)) except KeyError: gui_logger.debug("[!] Could not find display_data_tx in config file: ".format(KeyError)) pass try: - resp_dict["display_time_conn"] = int(get_config_value("USER", TRAY_CFG_TIME_CONN)) + resp_dict["display_time_conn"] = int(get_gui_config("USER", TRAY_CFG_TIME_CONN)) except KeyError: gui_logger.debug("[!] Could not find display_time_conn in config file: ".format(KeyError)) pass diff --git a/protonvpn_linux_gui/utils.py b/protonvpn_linux_gui/utils.py index 3601375..68cf979 100644 --- a/protonvpn_linux_gui/utils.py +++ b/protonvpn_linux_gui/utils.py @@ -1,11 +1,14 @@ import re +import os import sys import time -import datetime import requests +import datetime import subprocess -from threading import Thread +import collections +import configparser import concurrent.futures +from threading import Thread try: from protonvpn_cli.utils import ( @@ -24,7 +27,8 @@ from protonvpn_cli.constants import SPLIT_TUNNEL_FILE, USER, CONFIG_FILE, PASSFILE from protonvpn_cli.utils import change_file_owner, make_ovpn_template, set_config_value except: - sys.exit(1) + print("Unable to import from CLI, can not find CLI modules.") + pass from .constants import ( PATH_AUTOCONNECT_SERVICE, @@ -35,7 +39,8 @@ TRAY_CFG_SERVENAME, TRAY_CFG_DATA_TX, TRAY_CFG_TIME_CONN, - TRAY_CFG_DICT + TRAY_CFG_DICT, + GUI_CONFIG_FILE ) from .gui_logger import gui_logger @@ -45,7 +50,29 @@ # Gtk3 import gi.require_version('Gtk', '3.0') -from gi.repository import GObject as gobject, Gtk +from gi.repository import GObject as gobject, Gtk, GdkPixbuf + +def get_gui_config(group, key): + """Return specific value from GUI_CONFIG_FILE as string""" + config = configparser.ConfigParser() + config.read(GUI_CONFIG_FILE) + + return config[group][key] + + +def set_gui_config(group, key, value): + """Write a specific value to GUI_CONFIG_FILE""" + + config = configparser.ConfigParser() + config.read(GUI_CONFIG_FILE) + config[group][key] = str(value) + + gui_logger.debug( + "Writing {0} to [{1}] in config file".format(key, group) + ) + + with open(GUI_CONFIG_FILE, "w+") as f: + config.write(f) def get_server_protocol_from_cli(raw_result, return_protocol=False): """Function that collects servername and protocol from CLI print statement after establishing connection. @@ -273,7 +300,6 @@ def prepare_initilizer(username_field, password_field, interface): """ # Get user specified protocol protonvpn_plan = '' - openvpn_protocol = 'tcp' if interface.get_object('protocol_tcp_checkbox').get_active() == True else 'udp' protonvpn_plans = { '1': interface.get_object('member_free').get_active(), @@ -292,7 +318,7 @@ def prepare_initilizer(username_field, password_field, interface): 'username': username_field, 'password': password_field, 'protonvpn_plan': int(protonvpn_plan), - 'openvpn_protocol': openvpn_protocol + 'openvpn_protocol': "tcp" } return user_data @@ -308,6 +334,14 @@ def load_on_start(params_dict): params_dict["messagedialog_label"].set_markup("Populating dashboard...") except: pass + + display_secure_core = get_gui_config("connections", "display_secure_core") + secure_core_switch = params_dict["interface"].get_object("secure_core_switch") + + if display_secure_core == "True": + secure_core_switch.set_state(True) + else: + secure_core_switch.set_state(False) update_labels_server_list(params_dict["interface"], conn_info=conn) return True @@ -347,7 +381,7 @@ def update_labels_server_list(interface, server_tree_list_object=False, conn_inf gobject.idle_add(populate_server_list, populate_servers_dict) def update_labels_status(update_labels_dict): - """Function that updates labels, calls on left_grid_update_labels and right_grid_update_labels. + """Function prepares data to update labels. """ gui_logger.debug(">>> Running \"update_labels_status\" getting servers, is_connected and connected_server.") @@ -364,76 +398,37 @@ def update_labels_status(update_labels_dict): except: connected_server = False - left_grid_update_labels(update_labels_dict["interface"], servers, is_vpn_connected, connected_server, update_labels_dict["disconnecting"]) - right_grid_update_labels(update_labels_dict["interface"], servers, is_vpn_connected, connected_server, update_labels_dict["disconnecting"], conn_info=update_labels_dict["conn_info"]) - -def left_grid_update_labels(interface, servers, is_connected, connected_server, disconnecting): - """Function that updates the labels that are position within the left-side of the dashboard grid. - """ - gui_logger.debug(">>> Running \"left_grid_update_labels\".") - - # 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"} - connected_to_protocol = False - - # Check and set VPN status label. Get also protocol status if vpn is connected - if is_connected != True or disconnecting: - vpn_status_label.set_markup('Disconnected') - else: - vpn_status_label.set_markup('Connected') - try: - connected_to_protocol = get_config_value("metadata", "connected_proto") - except KeyError: - connected_to_protocol = False - - # 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') - - # Update time connected label - gobject.timeout_add_seconds(1, update_connection_time, {"is_connected":is_connected, "label":time_connected_label}) - - # Check and set killswitch label - killswitch_setting = get_config_value("USER", "killswitch") - killswitch_status = "Disabled" if killswitch_setting == "0" else "Enabled" - 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 - - feature = all_features[feature] if not disconnecting and is_connected else "" - server_features_label.set_markup('{0}'.format(feature.upper())) + update_labels(update_labels_dict["interface"], servers, is_vpn_connected, connected_server, update_labels_dict["disconnecting"], conn_info=update_labels_dict["conn_info"]) -def right_grid_update_labels(interface, servers, is_connected, connected_server, disconnecting, conn_info=False): - """Function that updates the labels that are position within the right-side of the dashboard grid. +def update_labels(interface, servers, is_connected, connected_server, disconnecting, conn_info=False): + """Function that updates the labels. """ gui_logger.debug(">>> Running \"right_grid_update_labels\".") # Right grid + time_connected_label = interface.get_object("time_connected_label") + protocol_label = interface.get_object("protocol_label") + conn_disc_button_label = interface.get_object("main_conn_disc_button_label") 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") + isp_label = interface.get_object("isp_label") data_received_label = interface.get_object("data_received_label") data_sent_label = interface.get_object("data_sent_label") + background_large_flag = interface.get_object("background_large_flag") + protonvpn_sign_green = interface.get_object("protonvpn_sign_green") + + CURRDIR = os.path.dirname(os.path.abspath(__file__)) + flags_base_path = CURRDIR+"/resources/img/flags/large/" + + # Get and set server load label + try: + load = get_server_value(connected_server, "Load", servers) + except: + load = False + + load = "{0}% Load".format(load) if load and is_connected else "" + server_load_label.set_markup('{0}'.format(load)) # Get and set IP labels. Get also country and ISP if not conn_info: @@ -447,20 +442,33 @@ def right_grid_update_labels(interface, servers, is_connected, connected_server, else: ip, isp, country = conn_info - country_isp = "" + country + "/" + isp + "" - ip_label.set_markup(ip) + country_cc = False - # 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)) + for k,v in country_codes.items(): + if k == country: + if is_connected: + try: + flag_path = flags_base_path+"{}.jpg".format(k.lower()) + background_large_flag.set_from_file(flag_path) + except: + pass + + country_cc = v + + protonvpn_sign_green.hide() + country_server = country_cc + + if is_connected: + country_server = country_server + " >> " + connected_server + protonvpn_sign_green.show() # 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)) + + country_label.set_markup(country_server) + ip_label.set_markup(ip) + + isp_label.set_markup(isp) # Get and set city label try: @@ -468,15 +476,33 @@ def right_grid_update_labels(interface, servers, is_connected, connected_server, 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) # Update sent and received data gobject.timeout_add_seconds(1, update_sent_received_data, {"received_label": data_received_label, "sent_label": data_sent_label}) + # Left grid + all_features = {0: "Normal", 1: "Secure-Core", 2: "Tor", 4: "P2P"} + protocol = "No VPN Connection" + + # Check and set VPN status label. Get also protocol status if vpn is connected + conn_disc_button = "Quick Connect" + if is_connected and not disconnecting: + try: + connected_to_protocol = get_config_value("metadata", "connected_proto") + protocol = 'OpenVPN >> {0}'.format(connected_to_protocol.upper()) + except KeyError: + pass + conn_disc_button = "Disconnect" + + conn_disc_button_label.set_markup(conn_disc_button) + # Check and set DNS status label + dns_enabled = get_config_value("USER", "dns_leak_protection") + + # Update time connected label + gobject.timeout_add_seconds(1, update_connection_time, {"is_connected":is_connected, "label":time_connected_label}) + + # Check and set protocol label + protocol_label.set_markup(protocol) def update_sent_received_data(dict_labels): tx_amount, rx_amount = get_transferred_data() @@ -510,132 +536,134 @@ def update_connection_time(dict_data): def load_configurations(interface): """Function that sets and populates user configurations before showing the configurations window. """ - pref_dialog = interface.get_object("ConfigurationsWindow") - - username = get_config_value("USER", "username") - dns_leak_protection = get_config_value("USER", "dns_leak_protection") - custom_dns = get_config_value("USER", "custom_dns") - tier = int(get_config_value("USER", "tier")) + 1 - default_protocol = get_config_value("USER", "default_protocol") - killswitch = get_config_value("USER", "killswitch") + # pref_dialog = interface.get_object("ConfigurationsWindow") + pref_dialog = interface.get_object("SettingsWindow") + + load_general_settings(interface) + load_tray_settings(interface) + load_connection_settings(interface) + load_advanced_settings(interface) + + pref_dialog.show() - # Populate username +def load_general_settings(interface): username_field = interface.get_object("update_username_input") - username_field.set_text(username) + pvpn_plan_combobox = interface.get_object("update_tier_combobox") - # Set DNS combobox - dns_combobox = interface.get_object("dns_preferens_combobox") - dns_custom_input = interface.get_object("dns_custom_input") + username = get_config_value("USER", "username") + tier = int(get_config_value("USER", "tier")) - # DNS ComboBox - # 0 - Leak Protection Enabled - # 1 - Custom DNS - # 2 - None + # Populate username + username_field.set_text(username) + # Set tier + pvpn_plan_combobox.set_active(tier) - if dns_leak_protection == '1': - dns_combobox.set_active(0) - elif dns_leak_protection != '1' and custom_dns.lower != "none": - dns_combobox.set_active(1) - dns_custom_input.set_property('sensitive', True) - else: - dns_combobox.set_active(2) - - dns_custom_input.set_text(custom_dns) - # Set ProtonVPN Plan - protonvpn_plans = { - 1: interface.get_object("member_free_update_checkbox"), - 2: interface.get_object("member_basic_update_checkbox"), - 3: interface.get_object("member_plus_update_checkbox"), - 4: interface.get_object("member_visionary_update_checkbox") - } - - for tier_val, object in protonvpn_plans.items(): - if tier_val == tier: - object.set_active(True) - break +def load_tray_settings(interface): + # Load tray configurations + for k,v in TRAY_CFG_DICT.items(): + setter = 0 + try: + setter = int(get_gui_config("tray_tab", v)) + except KeyError: + gui_logger.debug("[!] Unable to find {} key.".format(v)) - # Set OpenVPN Protocol - interface.get_object("protocol_tcp_update_checkbox").set_active(True) if default_protocol == "tcp" else interface.get_object("protocol_udp_update_checkbox").set_active(True) + combobox = interface.get_object(k) + combobox.set_active(setter) +def load_connection_settings(interface): # Set Autoconnect on boot combobox - populate_autoconnect_list(interface) - autoconnect_combobox = interface.get_object("autoconnect_combobox") + server_list = populate_autoconnect_list(interface, return_list=True) + # Get objects + update_autoconnect_combobox = interface.get_object("update_autoconnect_combobox") + update_quick_connect_combobox = interface.get_object("update_quick_connect_combobox") + update_protocol_combobox = interface.get_object("update_protocol_combobox") + + #Get values try: - autoconnect_setting = get_config_value("USER", "autoconnect") + autoconnect_setting = get_gui_config("conn_tab", "autoconnect") except KeyError: autoconnect_setting = 0 + try: + quick_connect_setting = get_gui_config("conn_tab", "quick_connect") + except KeyError: + quick_connect = 0 + default_protocol = get_config_value("USER", "default_protocol") - autoconnect_combobox.set_active(int(autoconnect_setting)) - - # Set Kill Switch combobox - killswitch_combobox = interface.get_object("killswitch_combobox") + # Get indexes + autoconnect_index = list(server_list.keys()).index(autoconnect_setting) + quick_connect_index = list(server_list.keys()).index(quick_connect_setting) - killswitch_combobox.set_active(int(killswitch)) + # Set values + update_autoconnect_combobox.set_active(autoconnect_index) + update_quick_connect_combobox.set_active(quick_connect_index) + update_protocol_combobox.set_active(0) if default_protocol == "tcp" else update_protocol_combobox.set_active(1) - # Populate Split Tunelling - split_tunneling = interface.get_object("split_tunneling_textview") +def load_advanced_settings(interface): + # User values + dns_leak_protection = get_config_value("USER", "dns_leak_protection") + custom_dns = get_config_value("USER", "custom_dns") + killswitch = get_config_value("USER", "killswitch") + split_tunnel = 0 - # Check if killswtich is != 0, if it is then disable split tunneling Function - if killswitch != '0': - split_tunneling.set_property('sensitive', False) - interface.get_object("update_split_tunneling_button").set_property('sensitive', False) - - split_tunneling_buffer = split_tunneling.get_buffer() - content = "" try: - with open(SPLIT_TUNNEL_FILE) as f: - lines = f.readlines() - - for line in lines: - content = content + line - - split_tunneling_buffer.set_text(content) + split_tunnel = get_config_value("USER", "split_tunnel") + except KeyError: + pass - except FileNotFoundError: - split_tunneling_buffer.set_text(content) + # Object + dns_leak_switch = interface.get_object("update_dns_leak_switch") + killswitch_switch = interface.get_object("update_killswitch_switch") + split_tunneling_switch = interface.get_object("split_tunneling_switch") + split_tunneling_list = interface.get_object("split_tunneling_textview") - # Load tray configurations - for k,v in TRAY_CFG_DICT.items(): - setter = 0 - try: - setter = int(get_config_value("USER", v)) - except KeyError: - gui_logger.debug("[!] Unable to find {} key.".format(v)) + # Set DNS Protection + if dns_leak_protection == '1': + # if dns_leak_protection == '1' or (dns_leak_protection != '1' and custom_dns.lower() != "none"): + dns_leak_switch.set_state(True) + else: + dns_leak_switch.set_state(False) - combobox = interface.get_object(k) - combobox.set_active(setter) + # Set Kill Switch + if killswitch != '0': + killswitch_switch.set_state(True) + else: + killswitch_switch.set_state(False) - + # Populate Split Tunelling + # Check if killswtich is != 0, if it is then disable split tunneling Function + if killswitch != '0': + killswitch_switch.set_state(True) + else: + killswitch_switch.set_state(False) - # display_server = 0 - # display_data_tx = 0 - # display_time_conn = 0 + if split_tunnel != '0': + split_tunneling_switch.set_state(True) + if killswitch != '0': + split_tunneling_list.set_property('sensitive', False) + interface.get_object("update_split_tunneling_button").set_property('sensitive', False) + + split_tunneling_buffer = split_tunneling_list.get_buffer() + content = "" + try: + with open(SPLIT_TUNNEL_FILE) as f: + lines = f.readlines() - - # try: - # display_server = int(get_config_value("USER", TRAY_CFG_SERVENAME)) - # except KeyError: - # gui_logger.debug("[!] Unable to find display_server key.") - # try: - # display_time_conn = int(get_config_value("USER", TRAY_CFG_TIME_CONN)) - # except KeyError: - # gui_logger.debug("[!] Unable to find display_time_conn key.") - - # tray_data_tx_combobox = interface.get_object("tray_data_tx_combobox") - # tray_servername_combobox = interface.get_object("tray_servername_combobox") - # tray_time_connected_combobox = interface.get_object("tray_time_connected_combobox") - - # tray_data_tx_combobox.set_active(display_data_tx) - # tray_servername_combobox.set_active(display_server) - # tray_time_connected_combobox.set_active(display_time_conn) + for line in lines: + content = content + line - pref_dialog.show() + split_tunneling_buffer.set_text(content) + except FileNotFoundError: + split_tunneling_buffer.set_text(content) + else: + split_tunneling_switch.set_state(False) def populate_server_list(populate_servers_dict): """Function that updates server list. """ + only_secure_core = True if get_gui_config("connections", "display_secure_core") == "True" else False + pull_server_data(force=True) features = {0: "Normal", 1: "Secure-Core", 2: "Tor", 4: "P2P"} @@ -656,29 +684,92 @@ def populate_server_list(populate_servers_dict): countries[country] = [] countries[country].append(server["Name"]) - country_servers = {} + country_servers = {} + + # Order server list by country alphabetically + countries = collections.OrderedDict(sorted(countries.items())) + for country in countries: - country_servers[country] = sorted( - countries[country], - key=lambda s: get_server_value(s, "Load", servers) - ) + country_servers[country] = sorted(countries[country], key=lambda s: get_server_value(s, "Load", servers)) populate_servers_dict["tree_object"].clear() - + + CURRDIR = os.path.dirname(os.path.abspath(__file__)) + flags_base_path = CURRDIR+"/resources/img/flags/small/" + features_base_path = CURRDIR+"/resources/img/utils/" + + # Create empty image + empty_path = features_base_path+"normal.png" + empty_pix = empty = GdkPixbuf.Pixbuf.new_from_file_at_size(empty_path, 15,15) + # Create P2P image + p2p_path = features_base_path+"p2p-arrows.png" + p2p_pix = empty = GdkPixbuf.Pixbuf.new_from_file_at_size(p2p_path, 15,15) + # Create TOR image + tor_path = features_base_path+"tor-onion.png" + tor_pix = empty = GdkPixbuf.Pixbuf.new_from_file_at_size(tor_path, 15,15) + # Create Plus image + plus_server_path = features_base_path+"plus-server.png" + plus_pix = GdkPixbuf.Pixbuf.new_from_file_at_size(plus_server_path, 15,15) + for country in country_servers: + for k,v in country_codes.items(): + if country == v: + flag_path = flags_base_path+"{}.png".format(v) + break + else: + flag_path = flags_base_path+"Unknown.png" + + # Get average load and highest feature + avrg_load, country_feature = get_country_avrg_features(country, country_servers, servers, features) + + flag = GdkPixbuf.Pixbuf.new_from_file_at_size(flag_path, 15,15) + + # Check plus servers + if country_feature == "normal" or country_feature == "p2p": + plus_feature = empty_pix + else: + plus_feature = plus_pix - avrg_load, country_features = get_country_avrg_features(country, country_servers, servers, features) + # Check correct feature + if country_feature == "normal" or country_feature == "secure-core": + feature = empty_pix + elif country_feature == "p2p": + feature = p2p_pix + elif country_feature == "tor": + feature = tor_pix - country_row = populate_servers_dict["tree_object"].append(None, [country, "", "", avrg_load, country_features]) + if country_feature == "secure-core" and only_secure_core: + country_row = populate_servers_dict["tree_object"].append(None, [flag, country, plus_feature, feature, avrg_load]) + elif not only_secure_core: + country_row = populate_servers_dict["tree_object"].append(None, [flag, country, plus_feature, feature, avrg_load]) for servername in country_servers[country]: + secure_core = False load = str(get_server_value(servername, "Load", servers)).rjust(3, " ") - load = load + "%" - - feature = features[get_server_value(servername, 'Features', servers)] + load = load + "%" tier = server_tiers[get_server_value(servername, "Tier", servers)] + + if not "Plus/Visionary".lower() == tier.lower(): + plus_feature = empty_pix + else: + plus_feature = plus_pix + + server_feature = features[get_server_value(servername, 'Features', servers)].lower() + + if server_feature == "Normal".lower(): + feature = empty_pix + elif server_feature == "P2P".lower(): + feature = p2p_pix + elif server_feature == "Tor".lower(): + feature = tor_pix + else: + # Should be secure core + secure_core = True - populate_servers_dict["tree_object"].append(country_row, [country, servername, tier, load, feature]) + if secure_core and only_secure_core: + populate_servers_dict["tree_object"].append(country_row, [empty_pix, servername, plus_feature, feature, load]) + elif not secure_core and not only_secure_core: + populate_servers_dict["tree_object"].append(country_row, [empty_pix, servername, plus_feature, feature, load]) def get_country_avrg_features(country, country_servers, servers, features): """Function that returns average load and features of a specific country. @@ -689,22 +780,42 @@ def get_country_avrg_features(country, country_servers, servers, features): # Variable for feature per country features_per_country = set() + order_dict = { + "normal": 0, + "p2p": 1, + "tor": 2, + "secure-core": 3, + } + top_choice = 0 + for servername in country_servers[country]: # Get average per country load_sum = load_sum + int(str(get_server_value(servername, "Load", servers)).rjust(3, " ")) count += 1 - + # Get features per country feature = features[get_server_value(servername, 'Features', servers)] features_per_country.add(feature) # Convert set to list country_feature_list = list(features_per_country) + + for feature in country_feature_list: + for k,v in order_dict.items(): + if feature.lower() == k.lower(): + if top_choice < v: + top_choice = v + + if top_choice == 0: + top_choice = "normal" + elif top_choice == 1: + top_choice = "p2p" + elif top_choice == 2: + top_choice = "tor" + else: + top_choice = "secure-core" - return ( - str(int(round(load_sum/count)))+"%", - ' / '.join(str(feature) for feature in country_feature_list) if len(country_feature_list) > 1 else country_feature_list[0] - ) + return (str(int(round(load_sum/count)))+"%", top_choice) def populate_autoconnect_list(interface, return_list=False): """Function that populates autoconnect dropdown list. @@ -721,7 +832,8 @@ def populate_autoconnect_list(interface, return_list=False): "tor": "Tor (Plus/Visionary)" } autoconnect_alternatives = ["dis", "fast", "rand", "p2p", "sc", "tor"] - return_values = [] + # return_values = collections.OrderedDict() + return_values = collections.OrderedDict() for server in servers: country = get_country_name(server["ExitCountry"]) @@ -734,17 +846,17 @@ def populate_autoconnect_list(interface, return_list=False): for alt in autoconnect_alternatives: if alt in other_choice_dict: - if return_list: - return_values.append(other_choice_dict[alt]) - else: - autoconnect_liststore.append([alt, other_choice_dict[alt]]) + # if return_list: + return_values[alt] = other_choice_dict[alt] + # else: + autoconnect_liststore.append([alt, other_choice_dict[alt], alt]) else: for k,v in country_codes.items(): if alt.lower() == v.lower(): - if return_list: - return_values.append(v) - else: - autoconnect_liststore.append([k, v]) + # if return_list: + return_values[k] = v + # else: + autoconnect_liststore.append([k, v, k]) if return_list: return return_values diff --git a/requirements.txt b/requirements.txt index e20fa44..3c79c5d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ # Call with pip install -r requirements.txt requests==2.23.0 protonvpn-cli==2.2.2 +configparser==4.0.2 diff --git a/setup.py b/setup.py index f4d129a..0f3c80e 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,11 @@ packages=[ "protonvpn_linux_gui", "protonvpn_linux_gui.resources", - "protonvpn_linux_gui.resources.flags", + "protonvpn_linux_gui.resources.img.flags", + "protonvpn_linux_gui.resources.img.flags.small", + "protonvpn_linux_gui.resources.img.flags.large", + "protonvpn_linux_gui.resources.img.logo", + "protonvpn_linux_gui.resources.img.utils", ], entry_points={ "console_scripts": [ @@ -37,7 +41,8 @@ url="https://github.com/calexandru2018/protonvpn-linux-gui", install_requires=[ "protonvpn-cli==2.2.2", - "requests==2.23.0" + "requests==2.23.0", + "configparser==4.0.2" ], python_requires=">=3.5", classifiers=[