Skip to content

Commit

Permalink
version 0.6.2
Browse files Browse the repository at this point in the history
  • Loading branch information
corrad1nho committed Jul 28, 2018
1 parent dff062b commit 459891a
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 106 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
##Changelog

version 0.6.2:
- [change] api-url for ProtonVPN updated - the one introduced in last update was out of date
- [change] added support for Windscribe's stealth feature (OpenVPN over SSL)
- [change] postrm functions added to deb/rpm/aur packages
- [change] automatic reconnections for double hop if first hop fails/disconnects
- [change] adjusted OpenVPN configs of Mullvad and Windscribe to match official ones
- [bugfix] tray icon not always updated after establishing double hop connection
- [bugfix] qomui crashes while performing latency checks when server(s) are deleted

version 0.6.1:
- [new] support for Windscribe
- [new] support for ProtonVPN
Expand Down
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Qomui (Qt OpenVPN Management UI) is an easy-to-use OpenVPN Gui for GNU/Linux wit
- command-line interface

### Screenshots
Taken on Arch/Plasma Arc Dark Theme - Qomui will adapt to your theme<br/>
Screenshots were taken on Arch Linux/Plasma Arc Dark Theme - Qomui will adapt to your theme.<br/>

<img src="screenshots/qomui_screenshot_main.png" width=250> <img src="screenshots/qomui_screenshot_option.png" width=250> <img src="screenshots/qomui_screenshot_bypass.png" width=250>

Expand All @@ -38,11 +38,11 @@ Taken on Arch/Plasma Arc Dark Theme - Qomui will adapt to your theme<br/>

#### Ubuntu

Download and install [DEB-Package](https://github.com/corrad1nho/qomui/releases/download/v0.6.1/qomui-0.6.1-amd64.deb)
Download and install [DEB-Package](https://github.com/corrad1nho/qomui/releases/download/v0.6.2/qomui-0.6.2-amd64.deb)

#### Fedora

Download and install [RPM-Package](https://github.com/corrad1nho/qomui/releases/download/v0.6.1/qomui-0.6.1-1.x86_64.rpm)
Download and install [RPM-Package](https://github.com/corrad1nho/qomui/releases/download/v0.6.2/qomui-0.6.2-1.x86_64.rpm)

#### Arch

Expand Down Expand Up @@ -111,6 +111,15 @@ qomui-cli --help
Qomui has been my first ever programming experience and a practical challenge for myself to learn a bit of Python. Hence, I'm aware that there is a lot of code that could probably be improved, streamlined and made more beautiful. I might have made some horrible mistakes, too. I'd appreciate any feedback as well as suggestions for new features.

### Changelog
version 0.6.2:
- [change] api-url for ProtonVPN updated - the one introduced in last update was out of date
- [change] added support for Windscribe's stealth feature (OpenVPN over SSL)
- [change] postrm functions added to deb/rpm/aur packages
- [change] automatic reconnections for double hop if first hop fails/disconnects
- [change] adjusted OpenVPN configs of Mullvad and Windscribe to match official ones
- [bugfix] tray icon not always updated after establishing double hop connection
- [bugfix] qomui crashes while performing latency checks when server(s) are deleted

version 0.6.1:
- [new] support for Windscribe
- [new] support for ProtonVPN
Expand All @@ -122,13 +131,3 @@ version 0.6.1:
- [bugfix] configs are not imported if url cannot be resolved
- [bugfix] old connection not killed after network change detected (in rare cases)

version 0.6.0:
- [new] support for Wireguard
- [new] cli-interface
- [change] additional parameters parsed from .desktop-files
- [change] update routine now uses dpkg/rpm if installed as DEB/RPM package - reinstall required!
- [bugfix] crashes at start when system tray not available
- [bugfix] Info for active connection sometimes not updated correctly
- [bugfix] Doublehop fails on Fedora


2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.6.1
0.6.2
119 changes: 67 additions & 52 deletions qomui/qomui_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class QomuiGui(QtWidgets.QWidget):
firewall_rules_changed = False
hop_active = 0
hop_log_monitor = 0
tun_hop = None
hop_server_dict = None
bypass_dict = {}
config_dict = {}
Expand Down Expand Up @@ -1139,23 +1140,23 @@ def networkstate(self, networkstate):

def providerChosen(self):
provider = self.addProviderBox.currentText()
if provider == "Airvpn" or provider == "PIA" or provider == "Windscribe" or provider == "ProtonVPN":

p_txt = {"Airvpn" : ("Username", "Password"),
"PIA" : ("Username", "Password"),
"Windscribe" : ("Username", "Password"),
"Mullvad" : ("Account Numner", "N.A. - Leave empty"),
"ProtonVPN" : ("OpenVPN username", "OpenVPN password")
}

if provider in SUPPORTED_PROVIDERS:
self.addProviderEdit.setVisible(False)
self.addProviderUserEdit.setPlaceholderText(_translate("Form", "Username", None))
self.addProviderPassEdit.setPlaceholderText(_translate("Form", "Password", None))
self.addProviderUserEdit.setPlaceholderText(_translate("Form", p_txt[provider][0], None))
self.addProviderPassEdit.setPlaceholderText(_translate("Form", p_txt[provider][1], None))
if provider in self.provider_list:
self.addProviderDownloadBt.setText(_translate("Form", "Update", None))
else:
self.addProviderDownloadBt.setText(_translate("Form", "Download", None))

elif provider == "Mullvad":
self.addProviderEdit.setVisible(False)
self.addProviderUserEdit.setPlaceholderText(_translate("Form", "Account Number", None))
self.addProviderPassEdit.setPlaceholderText(_translate("Form", "N.A.", None))
if provider in self.provider_list:
self.addProviderDownloadBt.setText(_translate("Form", "Update", None))
else:
self.addProviderDownloadBt.setText(_translate("Form", "Download", None))
else:
self.addProviderEdit.setVisible(True)
self.addProviderEdit.setPlaceholderText(_translate("Form",
Expand Down Expand Up @@ -1458,18 +1459,21 @@ def display_latency(self, result):
server = result[0]
latency_string = result[1]
latency_float = result[2]
old_index = self.index_list.index(server)
bisect.insort(self.latency_list, latency_float)
update_index = self.latency_list.index(latency_float)
rm = self.index_list.index(server)
self.index_list.pop(rm)
self.index_list.insert(update_index, server)
if getattr(self, server).isHidden() == True:
hidden = True
self.serverListWidget.takeItem(old_index)
self.add_server_widget(server, self.server_dict[server], insert=update_index)
self.serverListWidget.setRowHidden(update_index, hidden)
getattr(self, server).display_latency(latency_string)
try:
old_index = self.index_list.index(server)
bisect.insort(self.latency_list, latency_float)
update_index = self.latency_list.index(latency_float)
rm = self.index_list.index(server)
self.index_list.pop(rm)
self.index_list.insert(update_index, server)
if getattr(self, server).isHidden() == True:
hidden = True
self.serverListWidget.takeItem(old_index)
self.add_server_widget(server, self.server_dict[server], insert=update_index)
self.serverListWidget.setRowHidden(update_index, hidden)
getattr(self, server).display_latency(latency_string)
except ValueError:
pass

def show_favourite_servers(self, state):
self.randomSeverBt.setVisible(True)
Expand Down Expand Up @@ -1748,7 +1752,6 @@ def openvpn_log_monitor(self, reply):
self.status = "active"
self.hop_log_monitor = 0
self.WaitBar.setVisible(False)
self.show_active_connection(self.ovpn_dict, self.hop_server_dict)
try:
if self.config_dict["simpletray"] == 0:
self.trayIcon = QtGui.QIcon('%s/flags/%s.png' % (ROOTDIR,
Expand All @@ -1759,10 +1762,14 @@ def openvpn_log_monitor(self, reply):
except KeyError:
self.trayIcon = QtGui.QIcon('%s/flags/%s.png' % (ROOTDIR,
self.ovpn_dict["country"]
))
self.tray.setIcon(QtGui.QIcon(self.trayIcon))
))
finally:
self.tray.setIcon(QtGui.QIcon(self.trayIcon))
self.show_active_connection(self.ovpn_dict, self.hop_server_dict, tun_hop=self.tun_hop)
self.tun_hop = None

elif self.hop_active == 2 and self.hop_log_monitor != 1:
self.tun_hop = self.qomui_service.return_tun_device("hop")
self.hop_log_monitor = 1

with open('%s/last_server.json' % (HOMEDIR), 'w') as lserver:
Expand Down Expand Up @@ -1804,12 +1811,12 @@ def show_failmsg(self, text, information):
self.failmsg.setWindowModality(QtCore.Qt.WindowModal)
self.failmsg.show()

def show_active_connection(self, current_server, hop_dict):
def show_active_connection(self, current_server, hop_dict, tun_hop=None):
self.tray.setToolTip("Connected to %s" %self.ovpn_dict["name"])
QtWidgets.QApplication.restoreOverrideCursor()
tun = self.qomui_service.return_tun_device()
tun = self.qomui_service.return_tun_device("tun")
self.ActiveWidget.setVisible(True)
self.ActiveWidget.setText(self.ovpn_dict, self.hop_server_dict, tun)
self.ActiveWidget.setText(self.ovpn_dict, self.hop_server_dict, tun, tun_hop)
self.ActiveWidget.disconnect.connect(self.kill)
self.ActiveWidget.reconnect.connect(self.reconnect)
self.gridLayout.addWidget(self.ActiveWidget, 0, 0, 1, 3)
Expand Down Expand Up @@ -1961,24 +1968,28 @@ def apply_edit(self, modifications):
json.dump(self.server_dict, s)

if len(new_config) != 0:
if provider in SUPPORTED_PROVIDERS:
temp_file = "%s/temp/%s_config" %(HOMEDIR, provider)
with open(temp_file, "w") as config_change:
config_change.writelines(new_config)
else:
temp_file = "%s/temp/%s" %(HOMEDIR, val["path"].split("/")[1])
if modifications["apply_all"] == 1:
for k, v in self.server_dict.items():
if v["provider"] == provider:
path = "%s/temp/%s" %(HOMEDIR, v["path"].split("/")[1])
with open(path, "w") as config_change:
index = modifications["index"]
rpl = new_config[index].split(" ")
ip_insert = "%s %s %s" %(rpl[0], v["ip"], rpl[2])
new_config[index] = ip_insert
config_change.writelines(new_config)

self.qomui_service.copy_rootdir("CHANGE_%s" %provider, "%s/temp" %(HOMEDIR))
try:
if provider in SUPPORTED_PROVIDERS:
temp_file = "%s/temp/%s_config" %(HOMEDIR, provider)
with open(temp_file, "w") as config_change:
config_change.writelines(new_config)
else:
temp_file = "%s/temp/%s" %(HOMEDIR, val["path"].split("/")[1])
if modifications["apply_all"] == 1:
for k, v in self.server_dict.items():
if v["provider"] == provider:
path = "%s/temp/%s" %(HOMEDIR, v["path"].split("/")[1])
with open(path, "w") as config_change:
index = modifications["index"]
rpl = new_config[index].split(" ")
ip_insert = "%s %s %s" %(rpl[0], v["ip"], rpl[2])
new_config[index] = ip_insert
config_change.writelines(new_config)

self.qomui_service.copy_rootdir("CHANGE_%s" %provider, "%s/temp" %(HOMEDIR))

except FileNotFoundError:
pass

def search_listitem(self, key):
for row in range(self.serverListWidget.count()):
Expand Down Expand Up @@ -2298,8 +2309,9 @@ def retranslateUi(self, ConnectionWidget):
self.uploadLabel.setText(_translate("ConnectionWidget", "Upload:", None))
self.timeLabel.setText(_translate("ConnectionWidget", "Time:", None))

def setText(self, server_dict, hop_dict, tun):
def setText(self, server_dict, hop_dict, tun, tun_hop=None):
self.tun = tun
self.tun_hop = tun_hop
self.statusLabel.setText("Active Connection")
city = self.city_port_label(server_dict)
self.ServerWidget.setText(server_dict["name"], server_dict["provider"],
Expand All @@ -2318,7 +2330,7 @@ def setText(self, server_dict, hop_dict, tun):
self.hopActiveLabel.setVisible(False)

self.ServerWidget.hide_button(0)
self.calcThread = NetMon(self.tun)
self.calcThread = NetMon(self.tun, self.tun_hop)
self.calcThread.stat.connect(self.show_stats)
self.calcThread.ip.connect(self.show_ip)
self.calcThread.time.connect(self.update_time)
Expand Down Expand Up @@ -2370,18 +2382,19 @@ def __init__ (self, parent=None):

def setupUi(self, LineWidget):
self.setAutoFillBackground(True)
self.setFixedHeight(2)
self.setBackgroundRole(self.palette().Highlight)
self.setFixedHeight(1)
#self.setBackgroundRole(self.palette().Highlight)

class NetMon(QtCore.QThread):
stat = QtCore.pyqtSignal(list)
ip = QtCore.pyqtSignal(str)
time = QtCore.pyqtSignal(str)
lost = QtCore.pyqtSignal()

def __init__(self, tun):
def __init__(self, tun, tun_hop=None):
QtCore.QThread.__init__(self)
self.tun = tun
self.tun_hop = tun_hop

def run(self):
connected = True
Expand Down Expand Up @@ -2412,6 +2425,8 @@ def run(self):

try:
counter = psutil.net_io_counters(pernic=True)[self.tun]
if self.tun_hop is not None:
tun_hop_test = psutil.net_io_counters(pernic=True)[self.tun_hop]
t1 = time.time()
stat = (counter.bytes_recv, counter.bytes_sent)
DLrate, ULrate = [(now - last) / (t1 - t0) / 1024.0 for now, last in zip(stat, last_stat)]
Expand Down
34 changes: 30 additions & 4 deletions qomui/qomui_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class QomuiDbus(dbus.service.Object):
firewall_opt = 1
hop_dict = {"none" : "none"}
tun = "tun0"
tun_hop = "tun0"
connect_status = 0
config = {}
wg_connect = 0
Expand Down Expand Up @@ -121,9 +122,12 @@ def disable_ipv6(self, i):
disable_ipv6 = Popen(['sysctl', '-w', 'net.ipv6.conf.all.disable_ipv6=0'])
self.logger.info('(Re-)enabled ipv6')

@dbus.service.method(BUS_NAME, in_signature='', out_signature='s')
def return_tun_device(self):
return self.tun
@dbus.service.method(BUS_NAME, in_signature='s', out_signature='s')
def return_tun_device(self, tun):
if tun == "tun":
return self.tun
elif tun == "hop":
return self.tun_hop

@dbus.service.method(BUS_NAME, in_signature='', out_signature='')
def disconnect(self):
Expand Down Expand Up @@ -719,7 +723,12 @@ def ovpn(self, ovpn_file, h, cwd_ovpn):
if self.dns_found == 0:
self.update_dns()
elif line.find('TUN/TAP device') != -1:
self.tun = line_format.split(" ")[3]
if h == "2":
self.tun = line_format.split(" ")[3]
elif h == "1":
self.tun_hop = line_format.split(" ")[3]
else:
self.tun = line_format.split(" ")[3]
elif line.find('PUSH: Received control message:') != -1:
dns_option_1 = line_format.find('dhcp-option')
if dns_option_1 != -1:
Expand All @@ -736,9 +745,26 @@ def ovpn(self, ovpn_file, h, cwd_ovpn):
elif line.find("Restart pause, 10 second(s)") != -1:
self.reply("fail1")
self.logger.info("Connection attempt failed")
elif line.find("SIGTERM[soft,auth-failure]") != -1:
self.reply("fail1")
self.logger.info("Connection attempt failed")
elif line.find('SIGTERM[soft,auth-failure]') != -1:
self.reply("fail2")
self.logger.info("Authentication error while trying to connect")
elif line.find('write UDP: Operation not permitted') != -1:
ips = []
try:
hop_ip = self.hop_dict["ip"]
ips.append(hop_ip)
except:
pass

remote_ip = self.ovpn_dict["ip"]
ips.append(remote_ip)

for ip in ips:
rule = (['-I', 'OUTPUT', '1', '-d', '%s' %ip, '-j', 'ACCEPT'])
self.allow_ip(ip, rule)
elif line == '':
break
line = ovpn_exe.stdout.readline()
Expand Down
Loading

0 comments on commit 459891a

Please sign in to comment.