- Optimize Class. Move to wg_main Import Start/StopBTN and Tooltip

This commit is contained in:
Désiré Werner Menrath 2024-10-21 22:11:24 +02:00
parent 0fe591d70c
commit cfffd590cb
4 changed files with 187 additions and 165 deletions

View File

@ -4,9 +4,13 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="940e1630-c825-4d4c-be80-bc11f543c122" name="Changes" comment=" - Add Options, Help, Update Label and Update Menubutton&#10; - Theme now separate Light and Dark&#10; - Add Own Tooltip (Class and def's) Part One">
<list default="true" id="940e1630-c825-4d4c-be80-bc11f543c122" name="Changes" comment=" - Fix a ConToDict Class when Endpoint not in Wireguard config file">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Changelog" beforeDir="false" afterPath="$PROJECT_DIR$/Changelog" afterDir="false" />
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/testtheme.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/wg_func.py" beforeDir="false" afterPath="$PROJECT_DIR$/wg_func.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/wg_main.py" beforeDir="false" afterPath="$PROJECT_DIR$/wg_main.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -29,6 +33,10 @@
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
<option name="UPDATE_TYPE" value="REBASE" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/wg_func.py" root0="SKIP_INSPECTION" />
<setting file="file://$PROJECT_DIR$/wg_main.py" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 3
}</component>
@ -596,4 +604,20 @@
<MESSAGE value=" - Add Options, Help, Update Label and Update Menubutton &#10; - Theme now separate Light and Dark" />
<option name="LAST_COMMIT_MESSAGE" value=" - Add Options, Help, Update Label and Update Menubutton &#10; - Theme now separate Light and Dark" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/wg_func.py</url>
<line>341</line>
<option name="timeStamp" value="8" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/wg_main.py</url>
<line>273</line>
<option name="timeStamp" value="11" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project>

View File

@ -1,2 +1,14 @@
# Wire-Py
Wire-Py is an easy-to-use Gui for nmcli.
Before the first use of Wire-Py, all previous tunnels with "nmcli connection delete example" should be removed.
Wire-Py can easily be imported, exported, started, popped as well as renamed and deleted.
Wire-Py runs on many distros.
Tested on Arch Linux, OpenSuse Tumbleweed,
Fedora, Debian12, Linux Mint 22 Cinnamon
With the desktops:
Xfce4, Cinnamon, Kde, and Mate, LXDE, LXQT

View File

@ -8,12 +8,12 @@ import zipfile
from datetime import datetime
from pathlib import Path
from subprocess import check_call
from tkinter import filedialog, ttk
from tkinter import ttk
import requests
''' 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year '''
version = 'v. 1.10.2024'
version = 'v. 1.10.2124'
path_to_file = Path('/etc/wire_py/wg_py')
path_to_file2 = Path('/etc/wire_py/settings')
@ -135,25 +135,6 @@ class GreenLabel:
def rowconfigure(self, param, weight):
pass
class StartStopBTN:
"""
Show Start and Stop Button in Label
"""
def __init__(self):
self.lb_frame_btn_lbox = None
self.wg_switch = None
self.btn_stst = None
self.wg_vpn_start = tk.PhotoImage(file=r'/usr/share/icons/wp-icons/48/wg_vpn-start.png')
self.wg_vpn_stop = tk.PhotoImage(file=r'/usr/share/icons/wp-icons/48/wg_vpn-stop.png')
def button_stop(self):
self.btn_stst = ttk.Button(self.lb_frame_btn_lbox, image=self.wg_vpn_stop, command=self.wg_switch, padding=0)
self.btn_stst.grid(column=0, row=0, padx=5, pady=8)
def button_start(self):
self.btn_stst = ttk.Button(self.lb_frame_btn_lbox, image=self.wg_vpn_start, command=self.wg_switch, padding=0)
self.btn_stst.grid(column=0, row=0, padx=5, pady=8)
class ConToDict:
"""
@ -281,117 +262,6 @@ class ListTunnels:
return tl
class ImportTunnel:
"""
Import Class for Wireguard config Files.
Before importing, it is checked whether PrivateKey and PublicKey are in the file.
If True then it is checked whether the PreSharedKey is already in the key file
to avoid an import error so that no double wgconf are imported.
Thus, tunnels can be renamed without the problems arise. If False then the key is written into the file.
Furthermore, it is checked whether the name is longer than 12 characters.
If True then the name is automatically shortened to 12 characters and then imported.
If in each case false comes out, a corresponding window comes to inform the user that something is wrong.
"""
def __init__(self):
self.select_tunnel = None
self.wg_switch = None
self.btn_stst = None
self.lb_tunnel = None
self.StrVar = None
self.a = None
self.l_box = None
def wg_import_select(self):
try:
filepath = filedialog.askopenfilename(initialdir=str(_u), title='Select Wireguard config File',
filetypes=[('WG config files', '*.conf')], )
with open(filepath, 'r') as file:
read = file.read()
path_split = filepath.split('/')
path_split1 = path_split[-1]
self.a = TunnelActiv.active()
if 'PrivateKey = ' in read and 'PublicKey = 'in read and 'Endpoint =' in read:
with open(filepath, 'r') as file:
key = ConToDict.covert_to_dict(file)
pre_key = key[3]
if len(pre_key) != 0:
with open('/etc/wire_py/.keys', 'r') as readfile:
p_key = readfile.readlines()
if pre_key in p_key or pre_key + '\n' in p_key:
"""img_w, img_i, w_title, w_txt hand over"""
iw = r'/usr/share/icons/wp-icons/64/error.png'
ii = r'/usr/share/icons/wp-icons/48/wg_msg.png'
wt = 'Import Error'
msg_t = 'Tunnel already available!\nPlease use another file for import'
msg_window(iw, ii, wt, msg_t)
else:
with open('/etc/wire_py/.keys', 'a') as keyfile:
keyfile.write(pre_key + '\r')
if len(path_split1) > 17:
p1 = shutil.copy(filepath, Path('/etc/wire_py/'))
path_split = path_split1[len(path_split1) - 17:]
os.rename(p1, Path('/etc/wire_py') / str(path_split))
new_conf = '/etc/wire_py/' + path_split
if self.a != '':
check_call(['nmcli', 'connection', 'down', TunnelActiv.active()])
ShowAddress.label_empty(self)
subprocess.check_output(['nmcli', 'connection', 'import', 'type',
'wireguard', 'file', new_conf], text=True)
else:
shutil.copy(filepath, Path('/etc/wire_py/'))
if self.a != '':
check_call(['nmcli', 'connection', 'down', TunnelActiv.active()])
ShowAddress.label_empty(self)
subprocess.check_output(['nmcli', 'connection', 'import', 'type',
'wireguard', 'file', filepath], text=True)
self.StrVar.set('')
self.a = TunnelActiv.active()
self.l_box.insert(0, self.a)
self.l_box.update()
self.StrVar = tk.StringVar()
self.StrVar.set(self.a)
GreenLabel.green_show_label(self)
StartStopBTN.button_stop(self)
wg_read = Path('/etc/wire_py') / str(self.a + '.conf')
with open(wg_read, 'r') as file_for_key:
data = ConToDict.covert_to_dict(file_for_key)
''' Address Label '''
ShowAddress.init_and_report(self, data)
ShowAddress.show_data(self)
check_call(['nmcli', 'con', 'mod', self.a, 'connection.autoconnect', 'no'])
Path.chmod(wg_read, 0o600)
if 'PrivateKey = ' and 'Endpoint = ' not in read:
"""img_w, img_i, w_title, w_txt hand over"""
iw = r'/usr/share/icons/wp-icons/64/error.png'
ii = r'/usr/share/icons/wp-icons/48/wg_msg.png'
wt = 'Import Error'
msg_t = 'Oh... no valid Wireguard File!\nPlease select a valid Wireguard File'
msg_window(iw, ii, wt, msg_t)
except EOFError:
pass
except TypeError:
pass
except FileNotFoundError:
pass
except subprocess.CalledProcessError:
print('Tunnel exist!')
class FileHandle:
"""
This class will display the autostart label which
@ -527,29 +397,4 @@ class ExportTunnels:
pass
class MyToolTip(tk.Toplevel):
TIP_X_OFFSET = 8
TIP_Y_OFFSET = 8
AUTO_CLEAR_TIME = 10 # Millisecond. (1/100 sec.)
def __init__(self, x_pos, y_pos, message=None, auto_clear=False):
self.x_pos = x_pos
self.y_pos = y_pos
self.message = message
self.auto_clear = auto_clear
tk.Toplevel.__init__(self)
self.overrideredirect(True)
self.message_label = ttk.Label(self, compound='left', text=self.message, padding=4)
self.message_label.pack()
self.geometry("+%d+%d" % (self.x_pos + self.TIP_X_OFFSET,
self.y_pos + self.TIP_X_OFFSET))
if self.auto_clear:
self.after(self.AUTO_CLEAR_TIME, self.clear_tip)
def clear_tip(self):
"""Remove Tool-Tip"""
self.destroy()

View File

@ -1,14 +1,16 @@
#!/usr/bin/python3
import os
import shutil
import subprocess
import tkinter as tk
from select import select
from pathlib import Path
from subprocess import check_call
from tkinter import *
from pathlib import Path
from tkinter import ttk
from wg_func import (TunnelActiv, ListTunnels, ImportTunnel, ConToDict, GreenLabel, ShowAddress, FileHandle,
ExportTunnels, OnOff, msg_window, WirePyUpdate, res, version, path_to_file2,
path_to_file3, MyToolTip)
from tkinter import filedialog, ttk
from wg_func import (TunnelActiv, ListTunnels, ConToDict, GreenLabel, ShowAddress, FileHandle,
ExportTunnels, OnOff, msg_window, WirePyUpdate, res, _u, version, path_to_file2,
path_to_file3)
tcl_path = Path('/usr/share/TK-Themes')
@ -269,6 +271,117 @@ class StartStopBTN:
self.btn_stst.bind('<Leave>', start_mouse_leave)
class ImportTunnel:
"""
Import Class for Wireguard config Files.
Before importing, it is checked whether PrivateKey and PublicKey are in the file.
If True then it is checked whether the PreSharedKey is already in the key file
to avoid an import error so that no double wgconf are imported.
Thus, tunnels can be renamed without the problems arise. If False then the key is written into the file.
Furthermore, it is checked whether the name is longer than 12 characters.
If True then the name is automatically shortened to 12 characters and then imported.
If in each case false comes out, a corresponding window comes to inform the user that something is wrong.
"""
def __init__(self):
self.select_tunnel = None
self.wg_switch = None
self.btn_stst = None
self.lb_tunnel = None
self.StrVar = None
self.a = None
self.l_box = None
def wg_import_select(self):
try:
filepath = filedialog.askopenfilename(initialdir=str(_u), title='Select Wireguard config File',
filetypes=[('WG config files', '*.conf')], )
with open(filepath, 'r') as file:
read = file.read()
path_split = filepath.split('/')
path_split1 = path_split[-1]
self.a = TunnelActiv.active()
if 'PrivateKey = ' in read and 'PublicKey = 'in read and 'Endpoint =' in read:
with open(filepath, 'r') as file:
key = ConToDict.covert_to_dict(file)
pre_key = key[3]
if len(pre_key) != 0:
with open('/etc/wire_py/.keys', 'r') as readfile:
p_key = readfile.readlines()
if pre_key in p_key or pre_key + '\n' in p_key:
"""img_w, img_i, w_title, w_txt hand over"""
iw = r'/usr/share/icons/wp-icons/64/error.png'
ii = r'/usr/share/icons/wp-icons/48/wg_msg.png'
wt = 'Import Error'
msg_t = 'Tunnel already available!\nPlease use another file for import'
msg_window(iw, ii, wt, msg_t)
else:
with open('/etc/wire_py/.keys', 'a') as keyfile:
keyfile.write(pre_key + '\r')
if len(path_split1) > 17:
p1 = shutil.copy(filepath, Path('/etc/wire_py/'))
path_split = path_split1[len(path_split1) - 17:]
os.rename(p1, Path('/etc/wire_py') / str(path_split))
new_conf = '/etc/wire_py/' + path_split
if self.a != '':
check_call(['nmcli', 'connection', 'down', TunnelActiv.active()])
ShowAddress.label_empty(self)
subprocess.check_output(['nmcli', 'connection', 'import', 'type',
'wireguard', 'file', new_conf], text=True)
else:
shutil.copy(filepath, Path('/etc/wire_py/'))
if self.a != '':
check_call(['nmcli', 'connection', 'down', TunnelActiv.active()])
ShowAddress.label_empty(self)
subprocess.check_output(['nmcli', 'connection', 'import', 'type',
'wireguard', 'file', filepath], text=True)
self.StrVar.set('')
self.a = TunnelActiv.active()
self.l_box.insert(0, self.a)
self.l_box.update()
self.StrVar = tk.StringVar()
self.StrVar.set(self.a)
GreenLabel.green_show_label(self)
StartStopBTN.button_stop(self)
wg_read = Path('/etc/wire_py') / str(self.a + '.conf')
with open(wg_read, 'r') as file_for_key:
data = ConToDict.covert_to_dict(file_for_key)
''' Address Label '''
ShowAddress.init_and_report(self, data)
ShowAddress.show_data(self)
check_call(['nmcli', 'con', 'mod', self.a, 'connection.autoconnect', 'no'])
Path.chmod(wg_read, 0o600)
if 'PrivateKey = ' and 'Endpoint = ' not in read:
"""img_w, img_i, w_title, w_txt hand over"""
iw = r'/usr/share/icons/wp-icons/64/error.png'
ii = r'/usr/share/icons/wp-icons/48/wg_msg.png'
wt = 'Import Error'
msg_t = 'Oh... no valid Wireguard File!\nPlease select a valid Wireguard File'
msg_window(iw, ii, wt, msg_t)
except EOFError:
pass
except TypeError:
pass
except FileNotFoundError:
pass
except subprocess.CalledProcessError:
print('Tunnel exist!')
class FrameWidgets(ttk.Frame):
def __init__(self, container, **kwargs):
super().__init__(container, **kwargs)
@ -751,6 +864,34 @@ class FrameWidgets(ttk.Frame):
msg_window(iw, ii, wt, msg_t)
class MyToolTip(tk.Toplevel):
TIP_X_OFFSET = 8
TIP_Y_OFFSET = 8
AUTO_CLEAR_TIME = 10 # Millisecond. (1/100 sec.)
def __init__(self, x_pos, y_pos, message=None, auto_clear=False):
self.x_pos = x_pos
self.y_pos = y_pos
self.message = message
self.auto_clear = auto_clear
tk.Toplevel.__init__(self)
self.overrideredirect(True)
self.message_label = ttk.Label(self, compound='left', text=self.message, padding=4)
self.message_label.pack()
self.geometry("+%d+%d" % (self.x_pos + self.TIP_X_OFFSET,
self.y_pos + self.TIP_X_OFFSET))
if self.auto_clear:
self.after(self.AUTO_CLEAR_TIME, self.clear_tip)
def clear_tip(self):
"""Remove Tool-Tip"""
self.destroy()
if __name__ == '__main__':
window = MainWindow()
"""