#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import math import json import re import time import logging import psutil import configparser import requests import shlex import logging from PyQt5 import QtCore, QtWidgets, QtGui try: from PyQt5 import QtWebEngineWidgetsas webengine_available = 1 except ImportError: webengine_available = 0 from qomui import config, update, monitor, plotter try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: def _fromUtf8(s): return s try: _encoding = QtWidgets.QApplication.UnicodeUTF8 def _translate(context, text, disambig): return QtWidgets.QApplication.translate(context, text, disambig, _encoding) except AttributeError: def _translate(context, text, disambig): return QtWidgets.QApplication.translate(context, text, disambig) class favouriteButton(QtWidgets.QAbstractButton): def __init__(self, parent=None): super(favouriteButton, self).__init__(parent) self.star = QtGui.QPolygonF([QtCore.QPointF(1.0, 0.5)]) for i in range(5): self.star << QtCore.QPointF(0.5 + 0.5 * math.cos(0.8 * i * math.pi), 0.5 + 0.5 * math.sin(0.8 * i * math.pi) ) def paintEvent(self, event): painter = QtGui.QPainter(self) rect = self.rect() palette = self.palette() painter.setRenderHint(QtGui.QPainter.Antialiasing, True) painter.setPen(QtCore.Qt.NoPen) if self.isChecked() == True: painter.setBrush(palette.highlight()) else: painter.setBrush(palette.buttonText()) yOffset = (rect.height() - 25) /2 painter.translate(rect.x(), rect.y() + yOffset) painter.scale(25, 25) painter.drawPolygon(self.star, QtCore.Qt.WindingFill) painter.translate(1.0, 0.0) def enterEvent(self, event): self.update() def leaveEvent(self, event): self.update() def sizeHint(self): return QtCore.QSize(25, 25) class ServerWidget(QtWidgets.QWidget): server_chosen = QtCore.pyqtSignal(str) set_hop_signal = QtCore.pyqtSignal(str) changed_favourite_signal = QtCore.pyqtSignal(tuple) def __init__ (self, show=None, parent=None): super(ServerWidget, self).__init__(parent=None) self.hidden = False self.fav = 0 self.show = show self.setMouseTracking(True) self.setupUi(self) def setupUi(self, Form): Form.setObjectName(_fromUtf8("Form")) self.horizontalLayout = QtWidgets.QHBoxLayout(Form) self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) self.iconLabel = QtWidgets.QLabel(Form) self.iconLabel.setFixedSize(QtCore.QSize(30, 30)) self.iconLabel.setLayoutDirection(QtCore.Qt.RightToLeft) self.iconLabel.setObjectName(_fromUtf8("iconLabel")) self.horizontalLayout.addWidget(self.iconLabel) self.nameLabel = QtWidgets.QLabel(Form) self.nameLabel.setObjectName(_fromUtf8("nameLabel")) self.horizontalLayout.addWidget(self.nameLabel) self.cityLabel = QtWidgets.QLabel(Form) self.cityLabel.setObjectName(_fromUtf8("cityLabel")) self.horizontalLayout.addWidget(self.cityLabel) self.horizontalLayout.addStretch() self.favouriteButton = favouriteButton(Form) self.favouriteButton.setVisible(False) self.favouriteButton.setCheckable(True) self.favouriteButton.setObjectName(_fromUtf8("favouriteButton")) self.horizontalLayout.addWidget(self.favouriteButton) self.hop_bt = QtWidgets.QPushButton(Form) self.hop_bt.setVisible(False) self.hop_bt.setObjectName(_fromUtf8("hop_bt")) self.horizontalLayout.addWidget(self.hop_bt) self.connect_bt = QtWidgets.QPushButton(Form) if self.show == None: self.connect_bt.setVisible(False) self.connect_bt.setObjectName(_fromUtf8("connect_bt")) self.horizontalLayout.addWidget(self.connect_bt) QtCore.QMetaObject.connectSlotsByName(Form) self.connect_bt.clicked.connect(self.signal) self.hop_bt.clicked.connect(self.hop_signal) self.favouriteButton.toggled.connect(self.fav_change) def setText(self, name, provider, country, city, button = "connect", fav = 0): self.name = name self.provider = provider self.city = city self.fav = fav if self.provider != "bypass": try: self.iconLabel.setPixmap(country) except TypeError: flag = '{}/flags/{}.png'.format(config.ROOTDIR, country) if not os.path.isfile(flag): flag = '{}/flags/Unknown.png'.format(config.ROOTDIR) pixmap = QtGui.QPixmap(flag).scaled(25, 25, transformMode=QtCore.Qt.SmoothTransformation ) self.iconLabel.setPixmap(pixmap) else: icon = QtGui.QIcon.fromTheme(country) self.iconLabel.setPixmap(icon.pixmap(25,25)) bold_font = QtGui.QFont() bold_font.setBold(True) bold_font.setWeight(75) bold_font.setPointSize(11) if self.fav == "on": self.favouriteButton.setChecked(True) self.nameLabel.setFont(bold_font) self.nameLabel.setText(self.name) self.cityLabel.setText(self.city) try: self.connect_bt.setText(_translate("Form", button, None)) except AttributeError: pass try: self.hop_bt.setText(_translate("Form", "hop", None)) except AttributeError: pass def hide_button(self, choice=None): self.choice = choice #self.horizontalLayout.removeWidget(self.hop_bt) self.hop_bt = None if choice == 1: self.connect_bt.setVisible(False) self.horizontalLayout.removeWidget(self.connect_bt) self.connect_bt = None def enterEvent(self, event): if self.show == None: try: self.connect_bt.setVisible(True) except AttributeError: pass try: self.hop_bt.setVisible(True) except AttributeError: pass self.cityLabel.setVisible(False) if self.fav != 0: self.favouriteButton.setVisible(True) def leaveEvent(self, event): if self.show == None: try: self.connect_bt.setVisible(False) except AttributeError: pass try: self.hop_bt.setVisible(False) except AttributeError: pass self.cityLabel.setVisible(True) self.favouriteButton.setVisible(False) def signal(self): self.server_chosen.emit(self.name) def display_latency(self, latency): self.latency = latency if self.city != "": self.cityLabel.setText("{} - {}".format(self.city, self.latency)) else: self.cityLabel.setText(latency) def setHidden(self, state): self.hidden = state def isHidden(self): return self.hidden def hop_signal(self): self.set_hop_signal.emit(self.name) def fav_change(self, change): self.changed_favourite_signal.emit((self.name, change)) def sizeHint(self): return QtCore.QSize(100, 50) class HopWidget(QtWidgets.QWidget): clear = QtCore.pyqtSignal() def __init__ (self, parent=None): super(HopWidget, self).__init__(parent) self.setupUi(self) def setupUi(self, Form): Form.setObjectName(_fromUtf8("Form")) Form.resize(100, 100) self.setAutoFillBackground(True) self.setBackgroundRole(self.palette().Base) self.verticalLayout = QtWidgets.QVBoxLayout(Form) self.hopLabel = QtWidgets.QLabel(Form) bold_font = QtGui.QFont() bold_font.setBold(True) bold_font.setWeight(75) self.hopLabel.setFont(bold_font) self.verticalLayout.addWidget(self.hopLabel) self.activeHopWidget = ServerWidget() self.verticalLayout.addWidget(self.activeHopWidget) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) self.activeHopWidget.server_chosen.connect(self.signal) def retranslateUi(self, Form): Form.setWindowTitle(_translate("Form", "Form", None)) self.hopLabel.setText(_translate("Form", "Current selection for first hop:", None)) def setText(self, server_dict): try: city = server_dict["city"] except KeyError: city = None self.activeHopWidget.setText(server_dict["name"], server_dict["provider"], server_dict["country"], city, button="clear") self.activeHopWidget.hide_button(0) def signal(self): self.clear.emit() class ProgressBarWidget(QtWidgets.QWidget): abort = QtCore.pyqtSignal(str) def __init__ (self, parent=None): super(ProgressBarWidget, self).__init__(parent) self.setupUi(self) def setupUi(self, ProgessBarWidget): self.horizontalLayout = QtWidgets.QHBoxLayout(ProgessBarWidget) self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) self.taskLabel = QtWidgets.QLabel(ProgessBarWidget) self.taskLabel.setObjectName(_fromUtf8("taskLabel")) bold_font = QtGui.QFont() bold_font.setPointSize(13) bold_font.setBold(True) bold_font.setWeight(75) self.taskLabel.setFont(bold_font) self.horizontalLayout.addWidget(self.taskLabel) self.waitBar = QtWidgets.QProgressBar(ProgessBarWidget) self.waitBar.setObjectName(_fromUtf8("waitBar")) self.horizontalLayout.addWidget(self.waitBar) self.cancelButton = QtWidgets.QPushButton(ProgessBarWidget) self.cancelButton.setObjectName(_fromUtf8("cancelButton")) self.horizontalLayout.addWidget(self.cancelButton) self.cancelButton.clicked.connect(self.cancel) self.waitBar.setRange(0, 0) def setText(self, text, action=None): self.action = action self.cancelButton.setText("cancel") if action == "upgrade": self.cancelButton.setVisible(False) self.taskLabel.setText(_translate("ProgessBarWidget", text, None)) def cancel(self): self.abort.emit(self.action) class ActiveWidget(QtWidgets.QWidget): disconnect = QtCore.pyqtSignal() reconnect = QtCore.pyqtSignal() check_update = QtCore.pyqtSignal() def __init__ (self, text, parent=None): super(ActiveWidget, self).__init__(parent) self.setupUi(self) self.text = text self.bypass = None def setupUi(self, ConnectionWidget): ConnectionWidget.setObjectName(_fromUtf8("ConnectionWidget")) self.vLayoutActive = QtWidgets.QVBoxLayout(ConnectionWidget) self.vLayoutActive.setObjectName(_fromUtf8("vLayoutActive")) self.hLayoutActive = QtWidgets.QHBoxLayout() self.hLayoutActive.setObjectName(_fromUtf8("hLayoutActive")) self.statusLabel = QtWidgets.QLabel(ConnectionWidget) bold_font = QtGui.QFont() bold_font.setPointSize(12) bold_font.setBold(True) bold_font.setWeight(75) self.statusLabel.setFont(bold_font) self.statusLabel.setObjectName(_fromUtf8("statusLabel")) self.vLayoutActive.addWidget(self.statusLabel) bold_font.setPointSize(11) self.hopCountryLabel = QtWidgets.QLabel(ConnectionWidget) self.hopCountryLabel.setFixedSize(30,30) self.hopCountryLabel.setLayoutDirection(QtCore.Qt.RightToLeft) self.hopCountryLabel.setVisible(False) self.hLayoutActive.addWidget(self.hopCountryLabel) self.hopNameLabel = QtWidgets.QLabel(ConnectionWidget) self.hopNameLabel.setLayoutDirection(QtCore.Qt.RightToLeft) self.hopNameLabel.setFont(bold_font) self.hopNameLabel.setVisible(False) self.hLayoutActive.addWidget(self.hopNameLabel) self.ServerWidget = ServerWidget(show=True, parent=ConnectionWidget) self.hLayoutActive.addWidget(self.ServerWidget) self.vLayoutActive.addLayout(self.hLayoutActive) self.ServerWidget.server_chosen.connect(self.signal) QtCore.QMetaObject.connectSlotsByName(ConnectionWidget) def setText(self, server_dict, hop_dict, tun, tun_hop=None, bypass=None): self.statusLabel.setText(self.text) self.tun = tun self.tun_hop = tun_hop self.bypass = bypass self.statusLabel.setText(self.text) city = self.city_port_label(server_dict) self.ServerWidget.setText(server_dict["name"], server_dict["provider"], server_dict["country"], city, button="disconnect") if hop_dict is not None: flag = '{}/flags/{}.png'.format(config.ROOTDIR, hop_dict["country"]) if not os.path.isfile(flag): flag = '{}/flags/Unknown.png'.format(config.ROOTDIR) pixmap = QtGui.QPixmap(flag).scaled(25, 25, transformMode=QtCore.Qt.SmoothTransformation ) self.hopCountryLabel.setPixmap(pixmap) hop_text = hop_dict["name"] + " " + chr(10145) self.hopNameLabel.setText(hop_text) self.hopCountryLabel.setVisible(True) self.hopNameLabel.setVisible(True) else: self.hopCountryLabel.setVisible(False) self.hopNameLabel.setVisible(False) self.ServerWidget.hide_button(0) def reconnect_signal(self): self.reconnect.emit() def city_port_label(self, server_dict): try: protocol = server_dict["protocol"] port = server_dict["port"] except KeyError: protocol = "" port = "" try: city = server_dict["city"] if city != "": (city) = "{} -".format(city) except KeyError: city = "" return "{} {} {}".format(city, protocol, port) def signal(self): self.disconnect.emit() class LineWidget(QtWidgets.QWidget): def __init__ (self, parent=None): super(LineWidget, self).__init__(parent) self.setupUi(self) def setupUi(self, LineWidget): self.setAutoFillBackground(True) self.setFixedHeight(1) #self.setBackgroundRole(self.palette().Highlight) class StatusOffWidget(QtWidgets.QWidget): def __init__ (self, parent=None): super(StatusOffWidget, self).__init__(parent=None) self.setupUi(self) def setupUi(self, Form): Form.setObjectName("Form") self.vLayoutStatus = QtWidgets.QVBoxLayout(Form) self.vLayoutStatus.setObjectName("vLayoutStatus") font = QtGui.QFont() font.setPointSize(11) font.setBold(True) font.setWeight(75) self.offLabel = QtWidgets.QLabel(Form) self.offLabel.setObjectName("offLabel") self.offLabel.setFont(font) self.vLayoutStatus.addWidget(self.offLabel) self.vLayoutStatus.addSpacing(40) self.qIconLabel = QtWidgets.QLabel(Form) self.qIconLabel.setObjectName("qIconLabel") self.qIconLabel.setMinimumSize(300,300) self.qIconLabel.setAlignment(QtCore.Qt.AlignCenter) self.vLayoutStatus.addWidget(self.qIconLabel) self.vLayoutStatus.addSpacing(40) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Form")) self.offLabel.setText(_translate("Form", "You are currently not connected to any VPN server ")) icon = QtGui.QIcon.fromTheme("qomui_off") self.qIconLabel.setPixmap(icon.pixmap(300,300)) class ColoredRect(QtWidgets.QFrame): def __init__ (self, color, parent=None): super(ColoredRect, self).__init__(parent) palette = QtGui.QPalette() brush = QtGui.QBrush(color) brush.setStyle(QtCore.Qt.SolidPattern) palette.setBrush(QtGui.QPalette.Window, brush) self.setPalette(palette) self.setFixedSize(10,10) self.setAutoFillBackground(True) class StatusOnWidget(QtWidgets.QWidget): reconnect = QtCore.pyqtSignal() check_update = QtCore.pyqtSignal() def __init__ (self, parent=None): super(StatusOnWidget, self).__init__(parent=None) self.setupUi(self) def setupUi(self, Form): Form.setObjectName("Form") self.vLayoutStatus = QtWidgets.QVBoxLayout(Form) self.vLayoutStatus.setObjectName("vLayoutStatus") self.ipv4Label = QtWidgets.QLabel(Form) self.ipv4Label.setObjectName("ipv4Label") self.vLayoutStatus.addWidget(self.ipv4Label) self.ipv6Label = QtWidgets.QLabel(Form) self.ipv6Label.setObjectName("ipv6Label") self.vLayoutStatus.addWidget(self.ipv6Label) self.vLayoutStatus.addSpacing(10) if webengine_available == 1: self.webView = QtWebEngineWidgets.QWebEngineView(Form) self.webView.setUrl(QtCore.QUrl("about:blank")) self.webView.setObjectName("webView") self.webView.setMinimumSize(300,300) self.webView.setMaximumSize(16000, 16000) self.vLayoutStatus.addWidget(self.webView) self.hLayoutStatus = QtWidgets.QHBoxLayout() self.hLayoutStatus.setObjectName("hLayoutStatus") self.locButton = QtWidgets.QPushButton(Form) self.locButton.setObjectName("locButton") self.hLayoutStatus.addWidget(self.locButton) self.ipleakButton = QtWidgets.QPushButton(Form) self.ipleakButton.setObjectName("ipleakButton") self.hLayoutStatus.addWidget(self.ipleakButton) self.vLayoutStatus.addLayout(self.hLayoutStatus) self.vLayoutStatus.addSpacing(25) self.locButton.clicked.connect(self.show_location) self.ipleakButton.clicked.connect(self.show_ipleak) self.netHeader = QtWidgets.QLabel(Form) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.netHeader.setFont(font) self.netHeader.setObjectName("netHeader") self.netHeader.setVisible(False) self.vLayoutStatus.addWidget(self.netHeader) self.hLayoutStatus_2 = QtWidgets.QHBoxLayout() self.hLayoutStatus_2.setObjectName("hLayoutStatus_2") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.hLayoutStatus_2.addItem(spacerItem) font.setPointSize(9) font.setBold(False) self.intLabel = QtWidgets.QLabel(Form) self.intLabel.setObjectName("intLabel") self.intLabel.setFont(font) self.hLayoutStatus_2.addWidget(self.intLabel) self.timeLabel = QtWidgets.QLabel(Form) self.timeLabel.setAlignment(QtCore.Qt.AlignCenter) self.timeLabel.setObjectName("timeLabel") self.timeLabel.setFont(font) self.hLayoutStatus_2.addWidget(self.timeLabel) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.hLayoutStatus_2.addItem(spacerItem1) self.vLayoutStatus.addLayout(self.hLayoutStatus_2) self.netGraph = plotter.PlotArea(Form) self.netGraph.setObjectName("netGraph") self.netGraph.setMinimumSize(100,100) self.vLayoutStatus.addWidget(self.netGraph) self.hLayoutStatus_3 = QtWidgets.QHBoxLayout() self.hLayoutStatus_3.setObjectName("hLayoutStatus_3") spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.hLayoutStatus_3.addItem(spacerItem2) self.downRect = ColoredRect(QtGui.QColor(255,127,42,255), parent=Form) self.hLayoutStatus_3.addWidget(self.downRect) self.downLabel = QtWidgets.QLabel(Form) self.downLabel.setObjectName("downLabel") self.downLabel.setFont(font) self.hLayoutStatus_3.addWidget(self.downLabel) self.upRect = ColoredRect(QtGui.QColor(44,162,216,255), parent=Form) self.hLayoutStatus_3.addWidget(self.upRect) self.upLabel = QtWidgets.QLabel(Form) self.upLabel.setObjectName("upLabel") self.upLabel.setFont(font) self.hLayoutStatus_3.addWidget(self.upLabel) spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.hLayoutStatus_3.addItem(spacerItem3) self.vLayoutStatus.addLayout(self.hLayoutStatus_3) self.vLayoutStatus.addSpacing(25) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Form")) self.ipv4Label.setText(_translate("Form", "<b>External IPv4 address:</b> ")) self.ipv6Label.setText(_translate("Form", "<b>External IPv6 address:</b> ")) self.netHeader.setText(_translate("Form", "Network statistics")) self.intLabel.setText(_translate("Form", "<b>Network Inferface:</b> ")) self.timeLabel.setText(_translate("Form", "<b>Uptime:</b> ")) self.downLabel.setText(_translate("Form", "<b>Download:</b>")) self.upLabel.setText(_translate("Form", "<b>Upload:</b>")) if webengine_available == 1: self.locButton.setText(_translate("Form", "Location")) self.ipleakButton.setText(_translate("Form", "ipleak.net")) def monitor_conn(self, interface, server): self.server = server self.intLabel.setText("<b>Network Inferface:</b> {}".format(interface)) self.calcThread = monitor.TunnelMon(interface, None, tun_hop=None) self.calcThread.time.connect(self.update_time) self.calcThread.stat.connect(self.update_chart) self.calcThread.ip.connect(self.show_ext_ip) self.calcThread.start() def show_ext_ip(self, ip_data): self.ip_data = ip_data self.ipv4Label.setText("<b>External IPv4 address:</b> {}".format(self.ip_data["ip4"])) self.ipv6Label.setText("<b>External IPv6 address:</b> {}".format(self.ip_data["ip6"])) if webengine_available == 1: if self.ip_data["lon"] == 0 and self.ip_data["lat"] == 0: self.show_location_failed() else: self.show_location() else: logging.error("Import Error: QtWebEngine is not available") def show_location(self): formatting = {"lat":self.ip_data["lat"], "lon":self.ip_data["lon"], "server":self.server} loc_html = """ <!DOCTYPE html> <html> <head> <title>Location</title> <link rel = "stylesheet" href = "https://unpkg.com/leaflet@1.4.0/dist/leaflet.css"/> <script src = "https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"></script> </head> <body> <div id = "map" style = "width: 98w; height: 98vh"></div> <script> var lat = {lat} var lon = {lon} var mapOptions = {{ center: [lat, lon], zoom: 6 }} var map = new L.map('map', mapOptions); var marker = L.marker([lat, lon]).addTo(map); marker.bindPopup("<b>{server}</b><br>lat: {lat} lon: {lon}"); var osmAttrib='Map data © <a href="https://openstreetmap.org">OpenStreetMap</a>' var layer = new L.TileLayer( 'http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png', {{ attribution: osmAttrib, maxZoom: 18 }}); map.addLayer(layer); </script> </body> </html> """.format(**formatting) self.webView.setVisible(True) self.webView.setHtml(loc_html) def show_location_failed(self): loc_html = """ <html> <body> <h1>Sorry, failed to determine location :(</h1> </body> </html> """ self.webView.setVisible(True) self.webView.setHtml(loc_html) def show_ipleak(self): self.webView.setUrl(QtCore.QUrl("https://ipleak.net/#dnsdetection_title")) def reset_html(self): if webengine_available == 1: self.webView.setHtml(None) def update_time(self, t): self.timeLabel.setText("<b>Uptime:</b> {}".format(t)) def update_chart(self, update): self.netGraph.addPoint(update[2], update[0]) DLrate = round(update[0] / 128, 2) DLacc = update[1] ULrate = round(update[2] / 128, 2) ULacc = update[3] unit_acc_up = "Mb" unit_acc_down = "Mb" if DLacc / 1024 >= 1: DLacc = DLacc / 1024 unit_acc_down = "Gb" if ULacc / 1024 >= 1: ULacc = ULacc / 1024 unit_acc_up = "Gb" self.downLabel.setText("<b>Download:</b> {} {} - {} Mbps".format(round(DLacc, 2), unit_acc_down, DLrate)) self.upLabel.setText("<b>Upload:</b> {} {} - {} Mbps".format(round(ULacc, 2), unit_acc_up, ULrate)) def reconnect_signal(self): self.reconnect.emit() def check_for_update(self): self.check_update.emit() class FirewallEditor(QtWidgets.QDialog): fw_change = QtCore.pyqtSignal(dict) options = [ "block_lan", "preserve_rules", "fw_gui_only" ] def __init__ (self, settings, parent=None): super(FirewallEditor, self).__init__(parent) try: with open('{}/firewall.json'.format(config.ROOTDIR), 'r') as fload: self.firewall_dict = json.load(fload) except FileNotFoundError: with open('{}/firewall_default.json'.format(config.ROOTDIR), 'r') as fload: self.firewall_dict = json.load(fload) self.config_dict = settings self.setupUi(self) self.display_rules() def setupUi(self, Form): Form.setObjectName(_fromUtf8("Form")) Form.resize(600, 700) self.verticalLayout = QtWidgets.QVBoxLayout(Form) self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) self.headerLabel = QtWidgets.QLabel(Form) bold_font = QtGui.QFont() bold_font.setPointSize(12) bold_font.setBold(True) bold_font.setWeight(75) self.headerLabel.setFont(bold_font) self.headerLabel.setObjectName(_fromUtf8("headerLabel")) self.verticalLayout.addWidget(self.headerLabel) self.block_lan_check = QtWidgets.QCheckBox() self.block_lan_check.setObjectName(_fromUtf8("headerLabel")) self.verticalLayout.addWidget(self.block_lan_check) self.fw_gui_only_check = QtWidgets.QCheckBox() self.fw_gui_only_check.setObjectName(_fromUtf8("headerLabel")) self.verticalLayout.addWidget(self.fw_gui_only_check) self.preserve_rules_check = QtWidgets.QCheckBox() self.preserve_rules_check.setObjectName(_fromUtf8("headerLabel")) self.verticalLayout.addWidget(self.preserve_rules_check) self.warnLabel = QtWidgets.QLabel(Form) self.warnLabel.setObjectName(_fromUtf8("warnLabel")) self.verticalLayout.addWidget(self.warnLabel) self.line = QtWidgets.QFrame(Form) self.line.setFrameShape(QtWidgets.QFrame.HLine) self.line.setFrameShadow(QtWidgets.QFrame.Sunken) self.line.setObjectName(_fromUtf8("line")) self.verticalLayout.addWidget(self.line) self.ipv4Label = QtWidgets.QLabel(Form) bold_font = QtGui.QFont() bold_font.setBold(True) bold_font.setWeight(75) self.ipv4Label.setFont(bold_font) self.ipv4Label.setObjectName(_fromUtf8("ipv4_on_lbl")) self.verticalLayout.addWidget(self.ipv4Label) self.ipv4Edit = QtWidgets.QPlainTextEdit(Form) self.ipv4Edit.setObjectName(_fromUtf8("ipv4_on_edit")) self.verticalLayout.addWidget(self.ipv4Edit) self.ipv6Label = QtWidgets.QLabel(Form) bold_font = QtGui.QFont() bold_font.setBold(True) bold_font.setWeight(75) self.ipv6Label.setFont(bold_font) self.ipv6Label.setObjectName(_fromUtf8("ipv6_on_lbl_2")) self.verticalLayout.addWidget(self.ipv6Label) self.ipv6Edit = QtWidgets.QPlainTextEdit(Form) self.ipv6Edit.setObjectName(_fromUtf8("ipv6_on_edit")) self.verticalLayout.addWidget(self.ipv6Edit) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) self.horizontalLayout.addStretch() self.restoreButton = QtWidgets.QPushButton(Form) self.restoreButton.setObjectName(_fromUtf8("saveButton")) self.horizontalLayout.addWidget(self.restoreButton) self.saveButton = QtWidgets.QPushButton(Form) self.saveButton.setObjectName(_fromUtf8("saveButton")) self.horizontalLayout.addWidget(self.saveButton) self.cancelButton = QtWidgets.QPushButton(Form) self.cancelButton.setObjectName(_fromUtf8("cancelButton")) self.horizontalLayout.addWidget(self.cancelButton) self.verticalLayout.addLayout(self.horizontalLayout) self.retranslateUi(Form) self.set_options() QtCore.QMetaObject.connectSlotsByName(Form) self.cancelButton.clicked.connect(self.cancel) self.saveButton.clicked.connect(self.save_rules) self.restoreButton.clicked.connect(self.restore) def retranslateUi(self, Form): Form.setWindowTitle(_translate("Form", "Edit firewall", None)) self.headerLabel.setText(_translate("Form", "Configure firewall", None)) self.warnLabel.setText(_translate("Form", "Warning: Only for advanced users ", None)) self.block_lan_check.setText(_translate("Form", "Block lan/private networks", None)) self.fw_gui_only_check.setText(_translate("Form", "Activate firewall only when gui is running", None)) self.preserve_rules_check.setText(_translate("Form", "Preserve pre-existing firewall rules", None)) self.ipv4Label.setText(_translate("Form", "IPv4 rules", None)) self.ipv6Label.setText(_translate("Form", "IPv6 rules", None)) self.saveButton.setText(_translate("Form", "Save", None)) self.saveButton.setIcon(QtGui.QIcon.fromTheme("dialog-ok")) self.cancelButton.setText(_translate("Form", "Cancel", None)) self.cancelButton.setIcon(QtGui.QIcon.fromTheme("dialog-no")) self.restoreButton.setText(_translate("Form", "Restore defaults", None)) self.restoreButton.setIcon(QtGui.QIcon.fromTheme("view-refresh")) def set_options(self): for option in self.options: try: if self.config_dict[option] == 1: getattr(self, "{}_check".format(option)).setCheckState(2) else: getattr(self, "{}_check".format(option)).setCheckState(0) except KeyError: getattr(self, "{}_check".format(option)).setCheckState(0) def display_rules(self): for rule in self.firewall_dict["ipv4rules"]: self.ipv4Edit.appendPlainText(' '.join(rule)) for rule in self.firewall_dict["ipv6rules"]: self.ipv6Edit.appendPlainText(' '.join(rule)) def restore(self): self.ipv4Edit.clear() self.ipv6Edit.clear() with open('{}/firewall_default.json'.format(config.ROOTDIR), 'r') as fload: self.firewall_dict = json.load(fload) self.display_rules() def save_rules(self): new_ipv4_rules = [] new_ipv6_rules = [] for line in self.ipv4Edit.toPlainText().split("\n"): new_ipv4_rules.append(shlex.split(line)) for line in self.ipv6Edit.toPlainText().split("\n"): new_ipv6_rules.append(shlex.split(line)) self.firewall_dict["ipv4rules"] = new_ipv4_rules self.firewall_dict["ipv6rules"] = new_ipv6_rules with open ("{}/firewall_temp.json".format(config.HOMEDIR), "w") as firedump: json.dump(self.firewall_dict, firedump) for option in self.options: if getattr(self, "{}_check".format(option)).checkState() == 2: self.config_dict[option] = 1 else: self.config_dict[option] = 0 self.hide() self.fw_change.emit(self.config_dict) def cancel(self): self.hide() class AppSelector(QtWidgets.QDialog): app_chosen = QtCore.pyqtSignal(tuple) def __init__ (self, parent=None): super(AppSelector, self).__init__(parent) self.setupUi(self) self.get_desktop_files() def setupUi(self, Form): Form.setObjectName(_fromUtf8("Form")) Form.resize(600, 700) self.verticalLayout = QtWidgets.QVBoxLayout(Form) self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) self.installedLabel = QtWidgets.QLabel(Form) self.verticalLayout.addWidget(self.installedLabel) self.appListWidget = QtWidgets.QListWidget(Form) self.verticalLayout.addWidget(self.appListWidget) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): Form.setWindowTitle(_translate("Form", "Choose an application", None)) self.installedLabel.setText(_translate("Form", "Applications installed on your system:", None )) def get_desktop_files(self): self.bypassAppList = [] directories = ["{}/.local/share/applications".format(os.path.expanduser("~")), "/usr/share/applications", "/usr/local/share/applications" ] for d in directories: try: for f in os.listdir(d): if f.endswith(".desktop"): desktop_file = os.path.join(d, f) c = configparser.ConfigParser() c.read(desktop_file) try: if c["Desktop Entry"]["NoDisplay"] == "true": pass else: name = c["Desktop Entry"]["Name"] icon = c["Desktop Entry"]["Icon"] logging.debug("Adding {} to bypass app list".format(name)) self.bypassAppList.append((name, icon, desktop_file)) except KeyError: name = c["Desktop Entry"]["Name"] icon = c["Desktop Entry"]["Icon"] logging.debug("Adding {} to bypass app list".format(name)) self.bypassAppList.append((name, icon, desktop_file)) except Exception as e: logging.error(e) logging.error("Failed to add {} to bypass app list".format(name)) self.bypassAppList = sorted(self.bypassAppList) self.pop_AppList() def pop_AppList(self): self.appListWidget.clear() for entry in self.bypassAppList: item = QtWidgets.QListWidgetItem() self.appListWidget.addItem(item) item.setText(entry[0]) item.setIcon(QtGui.QIcon.fromTheme(entry[1])) self.appListWidget.itemClicked.connect(self.chosen) def chosen(self): self.app_chosen.emit(self.bypassAppList[self.appListWidget.currentRow()]) self.hide() class ModifyServer(QtWidgets.QDialog): modified = QtCore.pyqtSignal(dict) def __init__ (self, key=None, server_info=None, parent=None): super(ModifyServer, self).__init__(parent) self.key = key self.server_info = server_info self.config_change = 0 self.provider = self.server_info["provider"] self.setupUi(self) self.load_config_file() def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(419, 480) self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) self.verticalLayout.setObjectName("verticalLayout") self.nameLabel = QtWidgets.QLabel(Dialog) bold_font = QtGui.QFont() bold_font.setBold(True) bold_font.setWeight(75) self.nameLabel.setFont(bold_font) self.nameLabel.setObjectName("nameLabel") self.verticalLayout.addWidget(self.nameLabel) self.nameEdit = QtWidgets.QLineEdit(Dialog) self.nameEdit.setObjectName("nameEdit") self.verticalLayout.addWidget(self.nameEdit) self.iconLabel = QtWidgets.QLabel(Dialog) bold_font = QtGui.QFont() bold_font.setBold(True) bold_font.setWeight(75) self.iconLabel.setFont(bold_font) self.iconLabel.setObjectName("iconLabel") self.verticalLayout.addWidget(self.iconLabel) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.countryEdit = QtWidgets.QLineEdit(Dialog) self.countryEdit.setObjectName("countryEdit") self.horizontalLayout.addWidget(self.countryEdit) self.countryHintLabel = QtWidgets.QLabel(Dialog) self.countryHintLabel.setObjectName("countryHintLabel") self.horizontalLayout.addWidget(self.countryHintLabel) self.verticalLayout.addLayout(self.horizontalLayout) self.line = QtWidgets.QFrame(Dialog) self.line.setFrameShape(QtWidgets.QFrame.HLine) self.line.setFrameShadow(QtWidgets.QFrame.Sunken) self.line.setObjectName("line") self.verticalLayout.addWidget(self.line) self.configLabel = QtWidgets.QLabel(Dialog) bold_font = QtGui.QFont() bold_font.setBold(True) bold_font.setWeight(75) self.configLabel.setFont(bold_font) self.configLabel.setObjectName("configLabel") self.verticalLayout.addWidget(self.configLabel) self.changeAllBox = QtWidgets.QCheckBox(Dialog) self.changeAllBox.setCheckable(True) self.changeAllBox.setChecked(True) self.changeAllBox.setObjectName("changeAllBox") self.verticalLayout.addWidget(self.changeAllBox) self.configBrowser = QtWidgets.QTextEdit(Dialog) self.configBrowser.setObjectName("configBrowser") self.verticalLayout.addWidget(self.configBrowser) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") self.verticalLayout.addWidget(self.buttonBox) self.retranslateUi(Dialog) self.changeAllBox.toggled.connect(self.block_option) self.buttonBox.accepted.connect(self.accept_change) self.buttonBox.rejected.connect(self.reject_change) self.configBrowser.textChanged.connect(self.config_changed) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Edit server")) self.nameLabel.setText(_translate("Dialog", "Name:")) self.nameEdit.setText(self.server_info["name"]) self.iconLabel.setText(_translate("Dialog", "Country:")) self.countryHintLabel.setText(_translate("Dialog", "Preferably use country codes\n" "Example: US for United States")) self.countryEdit.setText(self.server_info["country"]) self.configLabel.setText(_translate("Dialog", "Edit Configuration File:")) self.changeAllBox.setText(_translate("Dialog", "Apply changes to all configuration files of {}".format(self.provider))) def block_option(self, state): if self.provider in config.SUPPORTED_PROVIDERS and state is False: self.changeAllBox.setChecked(True) def load_config_file(self): try: if self.server_info["tunnel"] == "WireGuard": self.configBrowser.setVisible(False) self.configLabel.setVisible(False) self.changeAllBox.setVisible(False) self.resize(419, 150) else: self.display_config() except KeyError: self.display_config() def display_config(self): if self.provider in config.SUPPORTED_PROVIDERS: conf = "{}/{}/openvpn.conf".format(config.ROOTDIR, self.provider) else: conf = "{}/{}".format(config.ROOTDIR, self.server_info["path"]) splt = os.path.splitext(conf) mod = "{}_MOD.{}".format(splt[0], splt[1]) if os.path.exists(mod): conf = mod with open (conf, "r") as config_edit: self.old_config = config_edit.readlines() for line in self.old_config: self.configBrowser.append(line.split("\n")[0]) def config_changed(self): self.config_change = 1 def reject_change(self): self.hide() def accept_change(self): change_all = 0 self.server_info["name"] = self.nameEdit.text() country_change = self.countryEdit.text() if len(country_change) == 2: country = update.country_translate(country_change) if country == "Unknown": country = country_change else: country = country_change self.server_info["country"] = country if self.config_change == 1: new_config = [] remote_index = 0 new_config = self.configBrowser.toPlainText().split("\n") for index, line in enumerate(new_config): if line.startswith("remote "): remote_index = index line_format = "{}\n".format(line) new_config[index] = line_format if new_config != self.old_config: if self.provider in config.SUPPORTED_PROVIDERS: temp_file = "{}_config".format(self.provider) else: temp_file = self.server_info["path"].split("/")[1] temp_folder = "{}/temp".format(config.HOMEDIR) if not os.path.exists(temp_folder): os.makedirs(temp_folder) with open("{}/{}".format(temp_folder, temp_file), "w") as update_config: update_config.writelines(new_config) else: remote_index = 0 new_config = [] if self.changeAllBox.isChecked() == True: change_all = 1 change_dict = {"info_update" : self.server_info, "key" : self.key, "config_change" : new_config, "index" : remote_index, "apply_all" : change_all } self.modified.emit(change_dict) self.hide()