11 Commits

Author SHA1 Message Date
08bef8fe6e add_wp_app_config.py for central configuration 2025-04-30 09:49:57 +02:00
2e94a324a6 add wp_app_config.py for central configuration 2025-04-30 09:48:40 +02:00
18ed97bf20 delete empty row 2025-04-29 16:20:07 +02:00
5dcfc91621 replace more "with open" 2025-04-29 15:09:56 +02:00
5fb4e68867 methods optimized-13:24 2025-04-29 13:25:03 +02:00
19d413ea97 optimized remove with open 2025-04-29 12:32:23 +02:00
213f772f40 methods optimized in wirepy and cls_mth_fc 2025-04-29 11:39:05 +02:00
6f02724daa with opening reduced 2025-04-29 09:02:06 +02:00
53f66ea76d method info and update to staticmethod 2025-04-28 21:16:21 +02:00
3039dbecb0 now only methodologies within the class 2025-04-28 19:55:44 +02:00
eadc2a06bf methods optimized 2025-04-28 12:35:19 +02:00
11 changed files with 546 additions and 479 deletions

44
.idea/workspace.xml generated
View File

@ -5,7 +5,7 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="940e1630-c825-4d4c-be80-bc11f543c122" name="Changes" comment=" - Update Translate Files"> <list default="true" id="940e1630-c825-4d4c-be80-bc11f543c122" name="Changes" comment=" - Update Translate Files">
<change beforePath="$PROJECT_DIR$/cls_mth_fc.py" beforeDir="false" afterPath="$PROJECT_DIR$/cls_mth_fc.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/wirepy.py" beforeDir="false" afterPath="$PROJECT_DIR$/wirepy.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/wirepy.py" beforeDir="false" afterPath="$PROJECT_DIR$/wirepy.py" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
@ -43,28 +43,28 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent">{ <component name="PropertiesComponent"><![CDATA[{
&quot;keyToString&quot;: { "keyToString": {
&quot;ASKED_ADD_EXTERNAL_FILES&quot;: &quot;true&quot;, "ASKED_ADD_EXTERNAL_FILES": "true",
&quot;Python.INSTALL.executor&quot;: &quot;Run&quot;, "Python.INSTALL.executor": "Run",
&quot;Python.cls_mth_fc.executor&quot;: &quot;Run&quot;, "Python.cls_mth_fc.executor": "Run",
&quot;Python.install.executor&quot;: &quot;Run&quot;, "Python.install.executor": "Run",
&quot;Python.main.executor&quot;: &quot;Run&quot;, "Python.main.executor": "Run",
&quot;Python.messagebox.executor&quot;: &quot;Run&quot;, "Python.messagebox.executor": "Run",
&quot;Python.start_wg.executor&quot;: &quot;Run&quot;, "Python.start_wg.executor": "Run",
&quot;Python.testtheme.executor&quot;: &quot;Run&quot;, "Python.testtheme.executor": "Run",
&quot;Python.wg_func.executor&quot;: &quot;Run&quot;, "Python.wg_func.executor": "Run",
&quot;Python.wg_main.executor&quot;: &quot;Run&quot;, "Python.wg_main.executor": "Run",
&quot;Python.wirepy.executor&quot;: &quot;Run&quot;, "Python.wirepy.executor": "Run",
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;, "RunOnceActivity.ShowReadmeOnStart": "true",
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;, "RunOnceActivity.git.unshallow": "true",
&quot;Shell Script.install.executor&quot;: &quot;Run&quot;, "Shell Script.install.executor": "Run",
&quot;Shell Script.run_as.executor&quot;: &quot;Run&quot;, "Shell Script.run_as.executor": "Run",
&quot;git-widget-placeholder&quot;: &quot;21-04-2025-new-tooltip&quot;, "git-widget-placeholder": "28-04-2025-more-methods-and-optimize-methods",
&quot;last_opened_file_path&quot;: &quot;/home/punix/Pyapps/wire-py&quot;, "last_opened_file_path": "/home/punix/Pyapps/wire-py",
&quot;settings.editor.selected.configurable&quot;: &quot;ml.llm.LLMConfigurable&quot; "settings.editor.selected.configurable": "ml.llm.LLMConfigurable"
} }
}</component> }]]></component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS"> <key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/lx-icons" /> <recent name="$PROJECT_DIR$/lx-icons" />

View File

@ -41,7 +41,7 @@ My standard System: Linux Mint 22 Cinnamon
- Fix ipv6 in Config File on import - Fix ipv6 in Config File on import
- Wirepy run now as user - Wirepy run now as user
- settings, keys and Config Files now in ~/.config/wire_py - settings, AppConfig.KEYS_FILE and Config Files now in ~/.config/wire_py
- For new users, the required files are created and autostart service is started. - For new users, the required files are created and autostart service is started.
- Tunnels are now read from the directory to view them in the list. - Tunnels are now read from the directory to view them in the list.
To display only own tunnels, and read errors are minimized. To display only own tunnels, and read errors are minimized.

Binary file not shown.

View File

@ -14,14 +14,14 @@ from datetime import datetime
from pathlib import Path from pathlib import Path
from subprocess import check_call, CompletedProcess from subprocess import check_call, CompletedProcess
from tkinter import ttk, Toplevel from tkinter import ttk, Toplevel
from wp_app_config import AppConfig
import requests import requests
APP = "wirepy" # Translate
LOCALE_DIR = "/usr/share/locale/" AppConfig.APP_NAME
locale.bindtextdomain(APP, LOCALE_DIR) locale.bindtextdomain(AppConfig.APP_NAME, AppConfig.LOCALE_DIR)
gettext.bindtextdomain(APP, LOCALE_DIR) gettext.bindtextdomain(AppConfig.APP_NAME, AppConfig.LOCALE_DIR)
gettext.textdomain(APP) gettext.textdomain(AppConfig.APP_NAME)
_ = gettext.gettext _ = gettext.gettext
@ -41,7 +41,7 @@ class Create:
pth: Path = Path.home() / ".config/wire_py" pth: Path = Path.home() / ".config/wire_py"
pth.mkdir(parents=True, exist_ok=True) pth.mkdir(parents=True, exist_ok=True)
sett: Path = Path.home() / ".config/wire_py/settings" sett: Path = Path.home() / ".config/wire_py/settings"
ks: Path = Path.home() / ".config/wire_py/keys" AppConfig.KEYS_FILE
if sett.exists(): if sett.exists():
pass pass
@ -50,11 +50,11 @@ class Create:
sett.touch() sett.touch()
sett.write_text("[UPDATES]\non\n[THEME]\nlight\n[TOOLTIP]\nTrue\n[AUTOSTART ON]\noff\n") sett.write_text("[UPDATES]\non\n[THEME]\nlight\n[TOOLTIP]\nTrue\n[AUTOSTART ON]\noff\n")
if ks.exists(): if AppConfig.KEYS_FILE.exists():
pass pass
else: else:
ks.touch() AppConfig.KEYS_FILE.touch()
@staticmethod @staticmethod
def files_for_autostart() -> None: def files_for_autostart() -> None:
@ -80,11 +80,11 @@ class Create:
def make_dir() -> None: def make_dir() -> None:
"""Folder Name "tlecdewg" = Tunnel Encrypt Decrypt Wireguard""" """Folder Name "tlecdewg" = Tunnel Encrypt Decrypt Wireguard"""
folder_path: Path = Path("/tmp/tlecdcwg/") AppConfig.TEMP_DIR: Path = Path("/tmp/tlecdcwg/")
if folder_path.exists(): if AppConfig.TEMP_DIR.exists():
pass pass
else: else:
folder_path.mkdir() AppConfig.TEMP_DIR.mkdir()
@staticmethod @staticmethod
def decrypt() -> None: def decrypt() -> None:
@ -135,19 +135,18 @@ class LxTools(tk.Tk):
""" """
log_name: str = f"{Path.home()}"[6:] log_name: str = f"{Path.home()}"[6:]
file: Path = Path.home() / "/tmp/.log_user" file: Path = Path.home() / "/tmp/.log_user"
with open(file, "w", encoding="utf-8") as f: Path(file).write_text(log_name, encoding="utf-8")
f.write(log_name)
@staticmethod @staticmethod
def clean_files(folder_path: Path = None, file: Path = None) -> None: def clean_files(TEMP_DIR: Path = None, file: Path = None) -> None:
""" """
method that can be added after need to delete a folder and a file when quitting. method that can be added after need to delete a folder and a file when quitting.
Args: Args:
:param file: default None :param file: default None
:param folder_path: default None :param AppConfig.TEMP_DIR: default None
""" """
if folder_path is not None: if AppConfig.TEMP_DIR is not None:
shutil.rmtree(folder_path) shutil.rmtree(AppConfig.TEMP_DIR)
if file is not None: if file is not None:
Path.unlink(file) Path.unlink(file)
@ -156,14 +155,22 @@ class LxTools(tk.Tk):
""" """
method that writes in file whether tooltip is displayed or not method that writes in file whether tooltip is displayed or not
""" """
with open(path, "r", encoding="utf-8") as set_f2: lines = Path(path).read_text(encoding="utf-8")
lines2 = set_f2.readlines() if "False\n" in lines:
if "False\n" in lines2:
tip = False tip = False
else: else:
tip = True tip = True
return tip return tip
def theme_change(self) -> None:
lines = AppConfig.SETTINGS_FILE.read_text()
if "light\n" in lines:
self.tk.call("set_theme", "light")
else:
self.tk.call("set_theme", "dark")
@staticmethod @staticmethod
def msg_window(img_w: str, img_i: str, w_title: str, w_txt: str, txt2: Optional[str] = None, def msg_window(img_w: str, img_i: str, w_title: str, w_txt: str, txt2: Optional[str] = None,
com: Optional[str] = None) -> None: com: Optional[str] = None) -> None:
@ -394,8 +401,8 @@ class Tunnel:
""" """
Returns a list of Wireguard tunnel names Returns a list of Wireguard tunnel names
""" """
folder_path: Path = Path("/tmp/tlecdcwg/") AppConfig.TEMP_DIR: Path = Path("/tmp/tlecdcwg/")
wg_s: List[str] = os.listdir(folder_path) wg_s: List[str] = os.listdir(AppConfig.TEMP_DIR)
return wg_s return wg_s

10
install
View File

@ -17,7 +17,7 @@ install_file_with(){
exit 0 exit 0
else else
sudo apt install python3-tk && \ sudo apt install python3-tk && \
sudo cp -fv wirepy.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ sudo cp -fv wirepy.py start_wg.py wp_app_config.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \
sudo cp -uR lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \ sudo cp -uR lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \
sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \
sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \ sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \
@ -43,7 +43,7 @@ install_arch_d(){
exit 0 exit 0
else else
sudo pacman -S --noconfirm tk python3 python-requests && \ sudo pacman -S --noconfirm tk python3 python-requests && \
sudo cp -fv wirepy.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ sudo cp -fv wirepy.py start_wg.py wp_app_config.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \
sudo cp -uR lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \ sudo cp -uR lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \
sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \
sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \ sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \
@ -120,7 +120,7 @@ install(){
exit 0 exit 0
else else
sudo dnf install python3-tkinter -y sudo dnf install python3-tkinter -y
sudo cp -fv wirepy.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ sudo cp -fv wirepy.py start_wg.py wp_app_config.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \
sudo cp -uR lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \ sudo cp -uR lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \
sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \
sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \ sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \
@ -145,7 +145,7 @@ install(){
rm -r ~/.config/wire_py && rm -r ~/.config/systemd rm -r ~/.config/wire_py && rm -r ~/.config/systemd
exit 0 exit 0
else else
sudo cp -fv wirepy.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ sudo cp -fv wirepy.py start_wg.py wp_app_config.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \
sudo cp -uR lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \ sudo cp -uR lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \
sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \
sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \ sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \
@ -181,7 +181,7 @@ install(){
remove(){ remove(){
sudo rm -f /usr/local/bin/wirepy /usr/local/bin/wirepy.py /usr/local/bin/start_wg.py \ sudo rm -f /usr/local/bin/wirepy /usr/local/bin/wirepy.py /usr/local/bin/start_wg.py \
/usr/local/bin/cls_mth_fc.py /usr/local/bin/ssl_encrypt.py /usr/local/bin/ssl_decrypt.py /usr/local/bin/wp_app_config.py cls_mth_fc.py /usr/local/bin/ssl_encrypt.py /usr/local/bin/ssl_decrypt.py
if [ $? -ne 0 ] if [ $? -ne 0 ]
then then
exit 0 exit 0

View File

@ -5,14 +5,12 @@ import os
import shutil import shutil
from pathlib import Path from pathlib import Path
from subprocess import check_call from subprocess import check_call
from wp_app_config import AppConfig
uname: Path = Path("/tmp/.log_user") uname: Path = Path("/tmp/.log_user")
with open(uname, "r", encoding="utf-8") as f: log_name = Path(uname).read_text(encoding="utf-8")
log_name = f.readline()
# Folder Name "tlecdewg" = Tunnel Encrypt Decrypt Wireguard
folder_path: Path = Path("/tmp/tlecdcwg/")
keyfile: Path = Path(f"/home/{log_name}/.config/wire_py/pbwgk.pem") keyfile: Path = Path(f"/home/{log_name}/.config/wire_py/pbwgk.pem")
PKEYFILE: Path = "/usr/local/etc/ssl/pwgk.pem" PKEYFILE: Path = "/usr/local/etc/ssl/pwgk.pem"
@ -21,15 +19,16 @@ if not keyfile.is_file():
check_call(["openssl", "rsa", "-in", PKEYFILE, "-out", keyfile, "-outform", "PEM", "-pubout"]) check_call(["openssl", "rsa", "-in", PKEYFILE, "-out", keyfile, "-outform", "PEM", "-pubout"])
shutil.chown(keyfile, 1000, 1000) shutil.chown(keyfile, 1000, 1000)
folder_path2 = f"/home/{log_name}/.config/wire_py/" AppConfig.TEMP_DIR2 = f"/home/{log_name}/.config/wire_py/"
detl: list[str] = os.listdir(folder_path2) detl: list[str] = os.listdir(AppConfig.TEMP_DIR2)
os.chdir(folder_path2) os.chdir(AppConfig.TEMP_DIR2)
detl.remove("keys") detl.remove("keys")
detl.remove("settings") detl.remove("settings")
if os.path.exists(f"{folder_path2}pbwgk.pem"): if os.path.exists(f"{AppConfig.TEMP_DIR2}pbwgk.pem"):
detl.remove("pbwgk.pem") detl.remove("pbwgk.pem")
for detunnels in detl: for detunnels in detl:
tlname2 = f"{detunnels[:-4]}.conf" tlname2 = f"{detunnels[:-4]}.conf"
extpath = f"{folder_path}/{tlname2}" extpath = f"{AppConfig.TEMP_DIR}/{tlname2}"
check_call(["openssl", "pkeyutl", "-decrypt", "-inkey", PKEYFILE, "-in", detunnels, "-out", extpath]) check_call(["openssl", "pkeyutl", "-decrypt", "-inkey", PKEYFILE, "-in", detunnels,
"-out", extpath])
shutil.chown(extpath, 1000, 1000) shutil.chown(extpath, 1000, 1000)

View File

@ -6,13 +6,13 @@ import shutil
from pathlib import Path from pathlib import Path
from subprocess import check_call from subprocess import check_call
from wp_app_config import AppConfig
uname: Path = Path("/tmp/.log_user") uname: Path = Path("/tmp/.log_user")
with open(uname, "r", encoding="utf-8") as f: log_name = Path(uname).read_text(encoding="utf-8")
log_name: str = f.readline()
keyfile: Path = Path(f"/home/{log_name}/.config/wire_py/pbwgk.pem") keyfile: Path = Path(f"/home/{log_name}/.config/wire_py/pbwgk.pem")
folder_path: Path = Path("/tmp/tlecdcwg/")
PKEYFILE = "/usr/local/etc/ssl/pwgk.pem" PKEYFILE = "/usr/local/etc/ssl/pwgk.pem"
if not keyfile.is_file(): if not keyfile.is_file():
@ -20,28 +20,28 @@ if not keyfile.is_file():
check_call(["openssl", "rsa", "-in", PKEYFILE, "-out", keyfile, "-outform", "PEM", "-pubout"]) check_call(["openssl", "rsa", "-in", PKEYFILE, "-out", keyfile, "-outform", "PEM", "-pubout"])
shutil.chown(keyfile, 1000, 1000) shutil.chown(keyfile, 1000, 1000)
if folder_path.exists(): if AppConfig.TEMP_DIR.exists():
tl = os.listdir(f"{folder_path}") tl = os.listdir(f"{AppConfig.TEMP_DIR}")
CPTH: str = f"{keyfile}" CPTH: str = f"{keyfile}"
CRYPTFILES: str = CPTH[:-9] CRYPTFILES: str = CPTH[:-9]
if keyfile.exists() and len(tl) != 0: if keyfile.exists() and len(tl) != 0:
for tunnels in tl: for tunnels in tl:
sourcetl: str = f"{folder_path}/{tunnels}" sourcetl: str = f"{AppConfig.TEMP_DIR}/{tunnels}"
tlname: str = f"{CRYPTFILES}{tunnels[:-5]}.dat" tlname: str = f"{CRYPTFILES}{tunnels[:-5]}.dat"
check_call(["openssl", "pkeyutl", "-encrypt", "-inkey", keyfile, "-pubin", "-in", sourcetl, "-out", check_call(["openssl", "pkeyutl", "-encrypt", "-inkey", keyfile, "-pubin", "-in", sourcetl, "-out",
tlname,]) tlname,])
else: else:
if folder_path.exists(): if AppConfig.TEMP_DIR.exists():
tl: list[str] = os.listdir(f"{folder_path}") tl: list[str] = os.listdir(f"{AppConfig.TEMP_DIR}")
CPTH: str = f"{keyfile}" CPTH: str = f"{keyfile}"
CRYPTFILES: str = CPTH[:-9] CRYPTFILES: str = CPTH[:-9]
if keyfile.exists() and len(tl) != 0: if keyfile.exists() and len(tl) != 0:
for tunnels in tl: for tunnels in tl:
sourcetl: str = f"{folder_path}/{tunnels}" sourcetl: str = f"{AppConfig.TEMP_DIR}/{tunnels}"
tlname: str = f"{CRYPTFILES}{tunnels[:-5]}.dat" tlname: str = f"{CRYPTFILES}{tunnels[:-5]}.dat"
check_call(["openssl", "pkeyutl", "-encrypt", "-inkey", keyfile, "-pubin", "-in", sourcetl, "-out", check_call(["openssl", "pkeyutl", "-encrypt", "-inkey", keyfile, "-pubin", "-in", sourcetl, "-out",
tlname]) tlname])

View File

@ -7,12 +7,9 @@ from subprocess import check_call
path_to_file = Path(Path.home() / ".config/wire_py/settings") path_to_file = Path(Path.home() / ".config/wire_py/settings")
with open(path_to_file, "r", encoding="utf-8") as a_con: a_con = Path(path_to_file).read_text(encoding="utf-8").splitlines(keepends=True)
a_con = a_con[7].strip()
# This function is for the independent autostarted of the previously selected tunnel if a_con != "off":
lines = a_con.readlines()
a_con = lines[7].strip()
if a_con != "off":
check_call(["nmcli", "connection", "up", a_con]) check_call(["nmcli", "connection", "up", a_con])
else: else:
pass pass

641
wirepy.py
View File

@ -15,29 +15,26 @@ from subprocess import check_call
from tkinter import TclError, filedialog, ttk from tkinter import TclError, filedialog, ttk
from cls_mth_fc import (Create, GiteaUpdate, Tooltip, Tunnel, LxTools) from cls_mth_fc import (Create, GiteaUpdate, Tooltip, Tunnel, LxTools)
from wp_app_config import AppConfig
LxTools.uos() LxTools.uos()
Create.dir_and_files() Create.dir_and_files()
Create.make_dir() Create.make_dir()
Create.decrypt() Create.decrypt()
tcl_path: Path = Path("/usr/share/TK-Themes") tips = LxTools.if_tip(AppConfig.SETTINGS_FILE)
set_file: Path = Path(Path.home() / ".config/wire_py/settings")
tips = LxTools.if_tip(set_file)
folder_path: Path = Path("/tmp/tlecdcwg/")
user_file = Path("/tmp/.log_user")
# 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year # 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year
VERSION: str = "v. 2.04.1725" VERSION: str = "v. 2.04.1725"
res = GiteaUpdate.api_down("https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases", VERSION, set_file) res = GiteaUpdate.api_down("https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases", VERSION, AppConfig.SETTINGS_FILE)
# Translate # Translate
APP = "wirepy" AppConfig.APP_NAME
LOCALE_DIR = "/usr/share/locale/" locale.bindtextdomain(AppConfig.APP_NAME, AppConfig.LOCALE_DIR)
locale.bindtextdomain(APP, LOCALE_DIR) gettext.bindtextdomain(AppConfig.APP_NAME, AppConfig.LOCALE_DIR)
gettext.bindtextdomain(APP, LOCALE_DIR) gettext.textdomain(AppConfig.APP_NAME)
gettext.textdomain(APP)
_ = gettext.gettext _ = gettext.gettext
img_w: str = r"/usr/share/icons/lx-icons/64/info.png" img_w: str = r"/usr/share/icons/lx-icons/64/info.png"
@ -50,35 +47,28 @@ ie:str = _("Import Error")
pfit: str = _("Please first import tunnel") pfit: str = _("Please first import tunnel")
pstl: str = _("Please select a tunnel from the list") pstl: str = _("Please select a tunnel from the list")
LxTools.sigi(folder_path, user_file) LxTools.sigi(AppConfig.TEMP_DIR, AppConfig.USER_FILE)
class Wirepy(tk.Tk): class Wirepy(tk.Tk):
""" """
Class Wirepy this is the Main Window of wirepy Class Wirepy this is the Main Window of wirepy
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.my_tool_tip = None self.my_tool_tip = None
self.x_width = 600 self.x_width = AppConfig.UI_CONFIG["window_size"][0]
self.y_height = 383 self.y_height = AppConfig.UI_CONFIG["window_size"][1]
self.monitor_center_x = int(self.winfo_screenwidth() / 2 - (self.x_width / 2)) self.monitor_center_x = int(self.winfo_screenwidth() / 2 - (self.x_width / 2))
self.monitor_center_y = int(self.winfo_screenheight() / 2 - (self.y_height / 2)) self.monitor_center_y = int(self.winfo_screenheight() / 2 - (self.y_height / 2))
self.resizable(width=False, height=False) self.resizable(AppConfig.UI_CONFIG["resizable_window"][0], AppConfig.UI_CONFIG["resizable_window"][1])
self.title("Wire-Py") self.title(AppConfig.UI_CONFIG["window_title"])
self.geometry(f"{self.x_width}x{self.y_height}+{self.monitor_center_x}+{self.monitor_center_y}") self.geometry(f"{self.x_width}x{self.y_height}+{self.monitor_center_x}+{self.monitor_center_y}")
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
self.style = ttk.Style(self) self.style = ttk.Style(self)
self.tk.call("source", f"{tcl_path}/water.tcl") self.tk.call("source", f"{AppConfig.SYSTEM_PATHS["tcl_path"]}/water.tcl")
with open(set_file, "r", encoding="utf-8") as read_file: LxTools.theme_change(self)
lines = read_file.readlines()
if "light\n" in lines:
self.tk.call("set_theme", "light")
else:
self.tk.call("set_theme", "dark")
# Load the image file from the disk # Load the image file from the disk
self.wg_icon = tk.PhotoImage(file=r"/usr/share/icons/lx-icons/48/wg_vpn.png") self.wg_icon = tk.PhotoImage(file=r"/usr/share/icons/lx-icons/48/wg_vpn.png")
@ -93,7 +83,6 @@ class FrameWidgets(ttk.Frame):
""" """
ttk frame class for better structure ttk frame class for better structure
""" """
def __init__(self, container, **kwargs): def __init__(self, container, **kwargs):
super().__init__(container, **kwargs) super().__init__(container, **kwargs)
@ -110,79 +99,6 @@ class FrameWidgets(ttk.Frame):
self.exp_pic = tk.PhotoImage(file=r"/usr/share/icons/lx-icons/48/wg_export.png") self.exp_pic = tk.PhotoImage(file=r"/usr/share/icons/lx-icons/48/wg_export.png")
self.warning_pic = tk.PhotoImage(file=r"/usr/share/icons/lx-icons/64/error.png") self.warning_pic = tk.PhotoImage(file=r"/usr/share/icons/lx-icons/64/error.png")
def update():
"""
Set on or off in file
"""
if set_update.get() == 1:
with open(set_file, "r", encoding="utf-8") as set_f2:
lines2 = set_f2.readlines()
lines2[1] = "off\n"
with open(set_file, "w", encoding="utf-8") as set_f2:
set_f2.writelines(lines2)
if set_update.get() == 0:
with open(set_file, "r", encoding="utf-8") as set_f2:
lines2 = set_f2.readlines()
lines2[1] = "on\n"
with open(set_file, "w", encoding="utf-8") as set_f2:
set_f2.writelines(lines2)
def theme_change_light():
"""
Set a light theme
"""
if self.tk.call("ttk::style", "theme", "use") == "water-dark":
self.tk.call("set_theme", "light")
with open(set_file, "r", encoding="utf-8") as theme_set2:
lines3 = theme_set2.readlines()
lines3[3] = "light\n"
with open(set_file, "w", encoding="utf-8") as theme_set2:
theme_set2.writelines(lines3)
self.color_label()
def theme_change_dark():
"""
Set a dark theme
"""
if not self.tk.call("ttk::style", "theme", "use") == "water-dark":
self.tk.call("set_theme", "dark")
with open(set_file, "r", encoding="utf-8") as theme_set2:
lines4 = theme_set2.readlines()
lines4[3] = "dark\n"
with open(set_file, "w", encoding="utf-8") as theme_set2:
theme_set2.writelines(lines4)
self.color_label()
def tooltip():
"""
Set True or False in a file
"""
if set_tip.get():
with open(set_file, "r", encoding="utf-8") as set_f2:
lines2 = set_f2.readlines()
lines2[5] = "False\n"
with open(set_file, "w", encoding="utf-8") as set_f2:
set_f2.writelines(lines2)
else:
with open(set_file, "r", encoding="utf-8") as set_f2:
lines2 = set_f2.readlines()
lines2[5] = "True\n"
with open(set_file, "w", encoding="utf-8") as set_f2:
set_f2.writelines(lines2)
def info():
def link_btn():
webbrowser.open("https://git.ilunix.de/punix/Wire-Py")
msg_t = _("Wire-Py a simple Wireguard Gui for Linux systems.\n\n"
"Wire-Py is open source software written in Python.\n\n"
"Email: polunga40@unity-mail.de also likes for donation.\n\n"
"Use without warranty!\n")
LxTools.msg_window(img_i, img_i, _("Info"), msg_t, _("Go to Wire-Py git"), link_btn)
# Frame for Menu # Frame for Menu
self.menu_frame = ttk.Frame(self) self.menu_frame = ttk.Frame(self)
self.menu_frame.configure(relief="flat") self.menu_frame.configure(relief="flat")
@ -204,15 +120,16 @@ class FrameWidgets(ttk.Frame):
set_tip = tk.BooleanVar() set_tip = tk.BooleanVar()
self.settings = tk.Menu(self, relief="flat") self.settings = tk.Menu(self, relief="flat")
self.options_btn.configure(menu=self.settings, style="Toolbutton") self.options_btn.configure(menu=self.settings, style="Toolbutton")
self.settings.add_checkbutton(label=_("Disable Updates"), command=update, variable=set_update) self.settings.add_checkbutton(label=_("Disable Updates"),
self.settings.add_checkbutton(label=_("Disable Tooltips"), command=tooltip, variable=set_tip) command=lambda: self.update_setting(set_update.get()), variable=set_update)
self.settings.add_command(label=_("Light"), command=theme_change_light) self.settings.add_checkbutton(label=_("Disable Tooltips"),
self.settings.add_command(label=_("Dark"), command=theme_change_dark) command=lambda: self.tooltip(set_tip.get()), variable=set_tip)
self.settings.add_command(label=_("Light"), command=self.theme_change_light)
self.settings.add_command(label=_("Dark"), command=self.theme_change_dark)
# About BTN Menu / Label # About BTN Menu / Label
self.about_btn = ttk.Button( self.about_btn = ttk.Button(
self.menu_frame, text=_("About"), style="Toolbutton", command=info self.menu_frame, text=_("About"), style="Toolbutton", command=self.about)
)
self.about_btn.grid(column=2, columnspan=2, row=0) self.about_btn.grid(column=2, columnspan=2, row=0)
self.readme = tk.Menu(self) self.readme = tk.Menu(self)
@ -306,23 +223,12 @@ class FrameWidgets(ttk.Frame):
self.peer.config(font=("Ubuntu", 9)) self.peer.config(font=("Ubuntu", 9))
self.peer.grid(column=0, row=4, sticky="we", padx=130) self.peer.grid(column=0, row=4, sticky="we", padx=130)
def enable_check_box(_):
"""
checkbox for enable autostart Tunnel
"""
Create.files_for_autostart()
if self.l_box.size() != 0:
self.wg_autostart.configure(state="normal")
self.lb_rename.config(state="normal")
self.lb_rename.delete(0, tk.END)
self.btn_rename.config(state="normal")
# Listbox with Scrollbar # Listbox with Scrollbar
self.l_box = tk.Listbox(self.lb_frame_btn_lbox, selectmode="single") self.l_box = tk.Listbox(self.lb_frame_btn_lbox, selectmode="single")
self.l_box.config(relief="ridge", font=("Ubuntu", 12, "bold")) self.l_box.config(relief="ridge", font=("Ubuntu", 12, "bold"))
self.l_box.grid(column=1, rowspan=4, row=0, sticky="ns") self.l_box.grid(column=1, rowspan=4, row=0, sticky="ns")
self.l_box.event_add("<<ClickEvent>>", "<Button-1>") self.l_box.event_add("<<ClickEvent>>", "<Button-1>")
self.l_box.bind("<<ClickEvent>>", enable_check_box) self.l_box.bind("<<ClickEvent>>", self.enable_check_box)
self.scrollbar = ttk.Scrollbar(self.lb_frame_btn_lbox, orient="vertical", command=self.l_box.yview) self.scrollbar = ttk.Scrollbar(self.lb_frame_btn_lbox, orient="vertical", command=self.l_box.yview)
self.scrollbar.grid(column=1, rowspan=4, row=0, sticky="nse") self.scrollbar.grid(column=1, rowspan=4, row=0, sticky="nse")
self.l_box.configure(yscrollcommand=self.scrollbar.set) self.l_box.configure(yscrollcommand=self.scrollbar.set)
@ -336,13 +242,7 @@ class FrameWidgets(ttk.Frame):
# Button Vpn # Button Vpn
if self.a != "": if self.a != "":
self.stop() self.stop()
wg_read = f"/tmp/tlecdcwg/{self.a}.conf" data = self.handle_tunnel_data(self.a)
with open(wg_read, "r", encoding="utf-8") as file:
data = Tunnel.con_to_dict(file)
# Address Label
self.init_and_report(data)
self.show_data()
else: else:
self.start() self.start()
@ -350,7 +250,7 @@ class FrameWidgets(ttk.Frame):
self.add = tk.StringVar() self.add = tk.StringVar()
self.DNS = tk.StringVar() self.DNS = tk.StringVar()
self.enp = tk.StringVar() self.enp = tk.StringVar()
self.label_empty() self.reset_fields()
self.show_data() self.show_data()
# Button Import # Button Import
@ -359,77 +259,8 @@ class FrameWidgets(ttk.Frame):
Tooltip(self.btn_i, _("Click to import a Wireguard Tunnel"), tips) Tooltip(self.btn_i, _("Click to import a Wireguard Tunnel"), tips)
def delete():
"""
delete Wireguard Tunnel
"""
try:
self.select_tunnel = self.l_box.curselection()
select_tl = self.l_box.get(self.select_tunnel[0])
with open(f"/tmp/tlecdcwg/{select_tl}.conf", "r+", encoding="utf-8") as file2:
key = Tunnel.con_to_dict(file2)
pre_key = key[3]
check_call(["nmcli", "connection", "delete", select_tl])
self.l_box.delete(self.select_tunnel[0])
with open(set_file, "r", encoding="utf-8") as set_f6:
lines6 = set_f6.readlines()
if (
select_tl == lines6[7].strip()
and "off\n" not in lines6[7].strip()
):
lines6[7] = "off\n"
with open(set_file, "w", encoding="utf-8") as set_f7:
set_f7.writelines(lines6)
self.selected_option.set(0)
self.autoconnect_var.set(_("no Autoconnect"))
is_encrypt = Path.home() / f".config/wire_py/{select_tl}.dat"
if is_encrypt.is_file():
Path.unlink(f"{Path.home()}/.config/wire_py/{select_tl}.dat")
Path.unlink(f"/tmp/tlecdcwg/{select_tl}.conf")
with open(f"{Path.home()}/.config/wire_py/keys", "r", encoding="utf-8") as readfile:
with open(f"{Path.home()}/.config/wire_py/keys2", "w", encoding="utf-8") as writefile:
for line in readfile:
if pre_key not in line.strip("\n"):
writefile.write(line)
file_one = Path(f"{Path.home()}/.config/wire_py/keys2")
file_two = file_one.with_name("keys")
file_one.replace(file_two)
self.wg_autostart.configure(state="disabled")
# for disabling checkbox when Listbox empty
if self.l_box.size() == 0:
self.wg_autostart.configure(state="disabled")
self.lb_rename.configure(state="disabled")
Tooltip(self.wg_autostart, _("You must have at least one\ntunnel in the list,to use the autostart")
, tips)
Tooltip(self.btn_exp, _("No Tunnels in List for Export"), tips)
Tooltip(self.btn_stst, _("No tunnels to start in the list"), tips)
Tooltip(self.lb_rename, _("To rename a tunnel, at least one must be in the list"), tips, )
self.lb_rename.insert(0, _("Max. 12 characters!"))
if self.a != "" and self.a == select_tl:
self.str_var.set(value="")
self.start()
self.l_box.update()
# Address Label
self.add.set("")
self.DNS.set("")
self.enp.set("")
except IndexError:
if self.l_box.size() != 0:
LxTools.msg_window(img_w, img_i2, sl, pstl)
else:
LxTools.msg_window(img_w, img_i2, sl, pfit)
# Button Trash # Button Trash
self.btn_tr = ttk.Button(self.lb_frame_btn_lbox, image=self.tr_pic, command=delete, padding=0, self.btn_tr = ttk.Button(self.lb_frame_btn_lbox, image=self.tr_pic, command=self.delete, padding=0,
style="CButton.TButton") style="CButton.TButton")
self.btn_tr.grid(column=0, row=2, padx=15, pady=8) self.btn_tr.grid(column=0, row=2, padx=15, pady=8)
@ -459,8 +290,185 @@ class FrameWidgets(ttk.Frame):
else: else:
Tooltip(self.lb_rename, _("To rename a tunnel, at least one must be in the list"), tips) Tooltip(self.lb_rename, _("To rename a tunnel, at least one must be in the list"), tips)
def tl_rename(): # Button Rename
self.btn_rename = ttk.Button(self.lb_frame4, text=_("Rename"), state="disable", command=self.tl_rename,
padding=4, style="RnButton.TButton")
self.btn_rename.grid(column=3, row=0, padx=5, pady=10, sticky="ne")
# Check Buttons
self.selected_option = tk.IntVar()
self.autoconnect_var = tk.StringVar()
self.autoconnect_var.set(f"{self.auto_con}")
# Frame for Labels, Entry and Button
self.autoconnect = ttk.Label(self.lb_frame3, textvariable=self.autoconnect_var, width=15)
self.autoconnect.config(font=("Ubuntu", 11))
self.autoconnect.grid(column=1, row=0, sticky="e", pady=19)
self.wg_autostart = ttk.Checkbutton(self.lb_frame3, text=_("Autoconnect on:"), variable=self.selected_option,
command=self.box_set)
self.wg_autostart.grid(column=0, row=0, pady=15, padx=15, sticky="nw")
if self.l_box.size() >= 1 and len(self.l_box.curselection()) >= 1:
Tooltip(self.wg_autostart, _("To use the autostart, enable this Checkbox"), tips)
if self.l_box.size() == 0:
Tooltip(self.wg_autostart, _("You must have at least one\ntunnel in the list,to use the autostart"), tips)
else:
Tooltip(self.wg_autostart, _("To use the autostart, a tunnel must be selected from the list"), tips)
self.on_off()
@staticmethod
def about() -> None:
"""
a tk.Toplevel window
"""
def link_btn() -> str | None:
webbrowser.open("https://git.ilunix.de/punix/Wire-Py")
msg_t = _("Wire-Py a simple Wireguard Gui for Linux systems.\n\n"
"Wire-Py is open source software written in Python.\n\n"
"Email: polunga40@unity-mail.de also likes for donation.\n\n"
"Use without warranty!\n")
LxTools.msg_window(img_i, img_i, _("Info"), msg_t, _("Go to Wire-Py git"), link_btn)
def theme_change_light(self) -> None:
"""
Set a light theme
"""
if self.tk.call("ttk::style", "theme", "use") == "water-dark":
self.tk.call("set_theme", "light")
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) # (keepends=True) = not changed
lines[3] = 'light\n'
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
self.color_label()
def theme_change_dark(self) -> None:
"""
Set a dark theme
"""
if not self.tk.call("ttk::style", "theme", "use") == "water-dark":
self.tk.call("set_theme", "dark")
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
lines[3] = 'dark\n'
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
self.color_label()
@staticmethod
def update_setting(update_res) -> None:
"""
write off or on in file
Args:
update_res (int): argument that is passed contains 0 or 1
"""
if update_res == 1:
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
lines[1] = 'off\n'
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
else:
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
lines[1] = 'on\n'
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
@staticmethod
def tooltip(tip) -> None:
"""
write True or False in a file
Args:
tip (bool): argument that is passed contains True or False
"""
if tip:
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
lines[5] = 'False\n'
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
else:
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
lines[5] = 'True\n'
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
def enable_check_box(self, _) -> None:
"""
checkbox for enable autostart Tunnel
"""
Create.files_for_autostart()
if self.l_box.size() != 0:
self.wg_autostart.configure(state="normal")
self.lb_rename.config(state="normal")
self.lb_rename.delete(0, tk.END)
self.btn_rename.config(state="normal")
def delete(self) -> None:
"""
delete Wireguard Tunnel
"""
try:
self.select_tunnel = self.l_box.curselection()
select_tl = self.l_box.get(self.select_tunnel[0])
with open(f"/tmp/tlecdcwg/{select_tl}.conf", "r+", encoding="utf-8") as file2:
key = Tunnel.con_to_dict(file2)
pre_key = key[3]
check_call(["nmcli", "connection", "delete", select_tl])
self.l_box.delete(self.select_tunnel[0])
with open(AppConfig.SETTINGS_FILE, "r", encoding="utf-8") as set_f6:
lines6 = set_f6.readlines()
if (select_tl == lines6[7].strip()
and "off\n" not in lines6[7].strip()):
lines6[7] = "off\n"
with open(AppConfig.SETTINGS_FILE, "w", encoding="utf-8") as set_f7:
set_f7.writelines(lines6)
self.selected_option.set(0)
self.autoconnect_var.set(_("no Autoconnect"))
is_encrypt = Path.home() / f".config/wire_py/{select_tl}.dat"
if is_encrypt.is_file():
Path.unlink(f"{Path.home()}/.config/wire_py/{select_tl}.dat")
Path.unlink(f"/tmp/tlecdcwg/{select_tl}.conf")
with open(keys, "r", encoding="utf-8") as readfile:
with open(f"{Path.home()}/.config/wire_py/keys2", "w", encoding="utf-8") as writefile:
for line in readfile:
if pre_key not in line.strip("\n"):
writefile.write(line)
file_one = Path(f"{Path.home()}/.config/wire_py/keys2")
file_two = file_one.with_name("keys")
file_one.replace(file_two)
self.wg_autostart.configure(state="disabled")
# for disabling checkbox when Listbox empty
if self.l_box.size() == 0:
self.wg_autostart.configure(state="disabled")
self.lb_rename.configure(state="disabled")
Tooltip(self.wg_autostart, _("You must have at least one\ntunnel in the list,to use the autostart")
, tips)
Tooltip(self.btn_exp, _("No Tunnels in List for Export"), tips)
Tooltip(self.btn_stst, _("No tunnels to start in the list"), tips)
Tooltip(self.lb_rename, _("To rename a tunnel, at least one must be in the list"), tips, )
self.lb_rename.insert(0, _("Max. 12 characters!"))
if self.a != "" and self.a == select_tl:
self.str_var.set(value="")
self.start()
self.l_box.update()
self.reset_fields()
except IndexError:
if self.l_box.size() != 0:
LxTools.msg_window(img_w, img_i2, sl, pstl)
else:
LxTools.msg_window(img_w, img_i2, sl, pfit)
def tl_rename(self) -> None:
"""
method to rename a tunnel
"""
special_characters = ["\\", "/", "{", "}", " "] special_characters = ["\\", "/", "{", "}", " "]
if len(self.lb_rename.get()) > 12: if len(self.lb_rename.get()) > 12:
@ -497,11 +505,11 @@ class FrameWidgets(ttk.Frame):
if self.a != "" and self.a == select_tl: if self.a != "" and self.a == select_tl:
self.a = Tunnel.active() self.a = Tunnel.active()
self.str_var.set(value=self.a) self.str_var.set(value=self.a)
with open(set_file, "r", encoding="utf-8") as set_f5: with open(AppConfig.SETTINGS_FILE, "r", encoding="utf-8") as set_f5:
lines5 = set_f5.readlines() lines5 = set_f5.readlines()
if select_tl == lines5[7].strip() and "off\n" not in lines5[7].strip(): if select_tl == lines5[7].strip() and "off\n" not in lines5[7].strip():
lines5[7] = new_a_connect lines5[7] = new_a_connect
with open(set_file, "w", encoding="utf-8") as theme_set5: with open(AppConfig.SETTINGS_FILE, "w", encoding="utf-8") as theme_set5:
theme_set5.writelines(lines5) theme_set5.writelines(lines5)
self.autoconnect_var.set(value=new_a_connect) self.autoconnect_var.set(value=new_a_connect)
@ -511,51 +519,13 @@ class FrameWidgets(ttk.Frame):
LxTools.msg_window(img_w, img_i2, rnp, pstl) LxTools.msg_window(img_w, img_i2, rnp, pstl)
# Button Rename except subprocess.CalledProcessError:
self.btn_rename = ttk.Button(self.lb_frame4, text=_("Rename"), state="disable", command=tl_rename, padding=4, pass
style="RnButton.TButton")
self.btn_rename.grid(column=3, row=0, padx=5, pady=10, sticky="ne")
# Check Buttons def import_sl(self) -> None:
self.selected_option = tk.IntVar()
self.autoconnect_var = tk.StringVar()
self.autoconnect_var.set(self.auto_con)
# Frame for Labels, Entry and Button
self.autoconnect = ttk.Label(self.lb_frame3, textvariable=self.autoconnect_var, width=15)
self.autoconnect.config(font=("Ubuntu", 11))
self.autoconnect.grid(column=1, row=0, sticky="e", pady=19)
self.wg_autostart = ttk.Checkbutton(self.lb_frame3, text=_("Autoconnect on:"), variable=self.selected_option,
command=self.box_set)
self.wg_autostart.grid(column=0, row=0, pady=15, padx=15, sticky="nw")
if self.l_box.size() >= 1 and len(self.l_box.curselection()) >= 1:
Tooltip(self.wg_autostart, _("To use the autostart, enable this Checkbox"), tips)
if self.l_box.size() == 0:
Tooltip(self.wg_autostart, _("You must have at least one\ntunnel in the list,to use the autostart"), tips)
else:
Tooltip(self.wg_autostart, _("To use the autostart, a tunnel must be selected from the list"), tips)
self.on_off()
def import_sl(self):
""" """
Import Methode for Wireguard config Files. validity check of 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 arising.
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.
""" """
Create.dir_and_files() Create.dir_and_files()
try: try:
@ -566,15 +536,13 @@ class FrameWidgets(ttk.Frame):
read = file.read() read = file.read()
path_split = filepath.split("/") path_split = filepath.split("/")
path_split1 = path_split[-1] path_split1 = path_split[-1]
self.a = Tunnel.active()
if "PrivateKey = " in read and "PublicKey = " in read and "Endpoint =" in read: if "PrivateKey = " in read and "PublicKey = " in read and "Endpoint =" in read:
with open(filepath, "r", encoding="utf-8") as file: with open(filepath, "r", encoding="utf-8") as file:
key = Tunnel.con_to_dict(file) key = Tunnel.con_to_dict(file)
pre_key = key[3] pre_key = key[3]
if len(pre_key) != 0: if len(pre_key) != 0:
with open(f"{Path.home()}/.config/wire_py/keys", "r", encoding="utf-8") as readfile: p_key = keys.read_text(encoding="utf-8")
p_key = readfile.readlines()
if pre_key in p_key or f"{pre_key}\n" in p_key: if pre_key in p_key or f"{pre_key}\n" in p_key:
msg_t = _("Tunnel already available!\nPlease use another file for import") msg_t = _("Tunnel already available!\nPlease use another file for import")
@ -582,7 +550,7 @@ class FrameWidgets(ttk.Frame):
else: else:
with open(f"{Path.home()}/.config/wire_py/keys", "a", encoding="utf-8") as keyfile: with open(keys, "a", encoding="utf-8") as keyfile:
keyfile.write(f"{pre_key}\r") keyfile.write(f"{pre_key}\r")
if len(path_split1) > 17: if len(path_split1) > 17:
p1 = shutil.copy(filepath, "/tmp/tlecdcwg/") p1 = shutil.copy(filepath, "/tmp/tlecdcwg/")
@ -590,8 +558,8 @@ class FrameWidgets(ttk.Frame):
os.rename(p1, f"/tmp/tlecdcwg/{path_split}") os.rename(p1, f"/tmp/tlecdcwg/{path_split}")
new_conf = f"/tmp/tlecdcwg/{path_split}" new_conf = f"/tmp/tlecdcwg/{path_split}"
if self.a != "": if self.a != "":
check_call(["nmcli", "connection", "down", Tunnel.active()]) check_call(["nmcli", "connection", "down", self.a])
self.label_empty() self.reset_fields()
subprocess.check_output(["nmcli", "connection", "import", "type", subprocess.check_output(["nmcli", "connection", "import", "type",
"wireguard", "file", new_conf], text=True) "wireguard", "file", new_conf], text=True)
@ -601,8 +569,8 @@ class FrameWidgets(ttk.Frame):
else: else:
shutil.copy(filepath, "/tmp/tlecdcwg/") shutil.copy(filepath, "/tmp/tlecdcwg/")
if self.a != "": if self.a != "":
check_call(["nmcli", "connection", "down", Tunnel.active()]) check_call(["nmcli", "connection", "down", self.a])
self.label_empty() self.reset_fields()
subprocess.check_output(["nmcli", "connection", "import", "type", subprocess.check_output(["nmcli", "connection", "import", "type",
"wireguard", "file", filepath], text=True) "wireguard", "file", filepath], text=True)
@ -619,8 +587,6 @@ class FrameWidgets(ttk.Frame):
Tooltip(self.wg_autostart, _("To use the autostart, enable this Checkbox"), tips) Tooltip(self.wg_autostart, _("To use the autostart, enable this Checkbox"), tips)
# Tooltip(self.l_box, _("List of available tunnels"))
Tooltip(self.btn_tr, _("Click to delete a Wireguard Tunnel\nSelect from the list!") Tooltip(self.btn_tr, _("Click to delete a Wireguard Tunnel\nSelect from the list!")
, tips,) , tips,)
@ -635,15 +601,8 @@ class FrameWidgets(ttk.Frame):
self.str_var.set(self.a) self.str_var.set(self.a)
self.color_label() self.color_label()
self.stop() self.stop()
wg_read = f"/tmp/tlecdcwg/{self.a}.conf" data = self.handle_tunnel_data(self.a)
with open(wg_read, "r", encoding="utf-8") as file_for_key:
data = Tunnel.con_to_dict(file_for_key)
# Address Label
self.init_and_report(data)
self.show_data()
check_call(["nmcli", "con", "mod", self.a, "connection.autoconnect", "no"]) check_call(["nmcli", "con", "mod", self.a, "connection.autoconnect", "no"])
Path.chmod(wg_read, 0o600)
if ("PrivateKey = " in read) and ("Endpoint = " in read): if ("PrivateKey = " in read) and ("Endpoint = " in read):
pass pass
@ -661,9 +620,25 @@ class FrameWidgets(ttk.Frame):
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print("Tunnel exist!") print("Tunnel exist!")
def box_set(self): def handle_tunnel_data(self, tunnel_name: str) -> tuple[str, str, str, str | None]:
"""_summary_
Args:
tunnel_name (str): name of a tunnel
Returns:
tuple[str, str]: tuple with tunnel data
""" """
This Method will display the autostart label which wg_read = f"/tmp/tlecdcwg/{tunnel_name}.conf"
with open(wg_read, "r", encoding="utf-8") as file:
data = Tunnel.con_to_dict(file)
self.init_and_report(data)
self.show_data()
return data
def box_set(self) -> None:
"""
This Method will display the autostarted label which
Tunnel is automatically started regardless of the active tunnel. Tunnel is automatically started regardless of the active tunnel.
The selected tunnel is written into a file to read it after the start of the system. The selected tunnel is written into a file to read it after the start of the system.
""" """
@ -672,11 +647,9 @@ class FrameWidgets(ttk.Frame):
select_tl = self.l_box.get(select_tunnel[0]) select_tl = self.l_box.get(select_tunnel[0])
if self.selected_option.get() == 0: if self.selected_option.get() == 0:
with open(set_file, "r", encoding="utf-8") as set_f3: lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
lines3 = set_f3.readlines() lines[7] = 'off\n'
lines3[7] = "off\n" Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
with open(set_file, "w", encoding="utf-8") as set_f3:
set_f3.writelines(lines3)
tl = Tunnel.list() tl = Tunnel.list()
@ -684,31 +657,28 @@ class FrameWidgets(ttk.Frame):
self.wg_autostart.configure(state="disabled") self.wg_autostart.configure(state="disabled")
if self.selected_option.get() >= 1: if self.selected_option.get() >= 1:
with open(set_file, "r", encoding="utf-8") as set_f3: lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
lines3 = set_f3.readlines() lines[7] = select_tl
lines3[7] = select_tl Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
with open(set_file, "w", encoding="utf-8") as set_f3:
set_f3.writelines(lines3)
except IndexError: except IndexError:
self.selected_option.set(1) self.selected_option.set(1)
self.on_off() self.on_off()
def on_off(self): def on_off(self) -> None:
""" """
Here it is checked whether the path to the file is there, if not, it is created. Here it is checked whether the path to the file is there, if not, it is created.
Set (on), the selected tunnel is displayed in the label. Set (on), the selected tunnel is displayed in the label.
At (off) the label is first emptied then filled with No Autoconnect At (off) the label is first emptied then filled with No Autoconnect
""" """
with open(set_file, "r", encoding="utf-8") as set_f4: lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
lines4 = set_f4.readlines()
if lines4[7] != "off\n": if lines[7] != "off\n":
print(f"{lines4[7]} starts automatically when the system starts.") print(f"{lines[7]} starts automatically when the system starts.")
self.selected_option.set(1) self.selected_option.set(1)
self.autoconnect_var.set("") self.autoconnect_var.set("")
self.auto_con = lines4[7] self.auto_con = lines[7]
else: else:
self.selected_option.set(0) self.selected_option.set(0)
@ -722,12 +692,11 @@ class FrameWidgets(ttk.Frame):
self.autoconnect.config(font=("Ubuntu", 11)) self.autoconnect.config(font=("Ubuntu", 11))
self.autoconnect.grid(column=1, row=0, sticky="e", pady=19) self.autoconnect.grid(column=1, row=0, sticky="e", pady=19)
def init_and_report(self, data=None): def init_and_report(self, data=None) -> None:
""" """
Displays the value address, DNS and peer in the labels Displays the value address, DNS and peer in the labels
or empty it again or empty it again
""" """
# Address Label # Address Label
self.add = tk.StringVar() self.add = tk.StringVar()
self.add.set(f"{_("Address: ")}{data[0]}") self.add.set(f"{_("Address: ")}{data[0]}")
@ -736,19 +705,18 @@ class FrameWidgets(ttk.Frame):
self.enp = tk.StringVar() self.enp = tk.StringVar()
self.enp.set(f"{_("Endpoint: ")}{data[2]}") self.enp.set(f"{_("Endpoint: ")}{data[2]}")
def label_empty(self): def reset_fields(self) -> None:
""" """
empty labels reset data from labels
""" """
self.add.set("") fields = [self.add, self.DNS, self.enp]
self.DNS.set("") for field in fields:
self.enp.set("") field.set("")
def show_data(self): def show_data(self) -> None:
""" """
shows data in the label shows data in the label
""" """
# Address Label # Address Label
self.address = ttk.Label(self.lb_frame, textvariable=self.add, foreground="#0071ff") self.address = ttk.Label(self.lb_frame, textvariable=self.add, foreground="#0071ff")
self.address.grid(column=0, row=5, sticky="w", padx=10, pady=6) self.address.grid(column=0, row=5, sticky="w", padx=10, pady=6)
@ -764,20 +732,22 @@ class FrameWidgets(ttk.Frame):
self.endpoint.grid(column=0, row=8, sticky="w", padx=10, pady=20) self.endpoint.grid(column=0, row=8, sticky="w", padx=10, pady=20)
self.endpoint.config(font=("Ubuntu", 9)) self.endpoint.config(font=("Ubuntu", 9))
def stop(self): def stop(self) -> None:
""" """
Stop Button Stop Button
""" """
self.btn_stst = ttk.Button(self.lb_frame_btn_lbox, image=self.wg_vpn_stop, command=self.wg_switch, padding=0) self.btn_stst = ttk.Button(self.lb_frame_btn_lbox, image=self.wg_vpn_stop,
command=lambda: self.wg_switch("stop"), padding=0)
self.btn_stst.grid(column=0, row=0, padx=5, pady=8) self.btn_stst.grid(column=0, row=0, padx=5, pady=8)
Tooltip(self.btn_stst, _("Click to stop selected Wireguard Tunnel"), tips) Tooltip(self.btn_stst, _("Click to stop selected Wireguard Tunnel"), tips)
def start(self): def start(self) -> None:
""" """
Start Button Start Button
""" """
self.btn_stst = ttk.Button(self.lb_frame_btn_lbox, image=self.wg_vpn_start, command=self.wg_switch, padding=0) self.btn_stst = ttk.Button(self.lb_frame_btn_lbox, image=self.wg_vpn_start,
command=lambda: self.wg_switch("start"), padding=0)
self.btn_stst.grid(column=0, row=0, padx=5, pady=8) self.btn_stst.grid(column=0, row=0, padx=5, pady=8)
tl = Tunnel.list() tl = Tunnel.list()
@ -786,13 +756,11 @@ class FrameWidgets(ttk.Frame):
else: else:
Tooltip(self.btn_stst, _("Click to start selected Wireguard Tunnel"), tips) Tooltip(self.btn_stst, _("Click to start selected Wireguard Tunnel"), tips)
def color_label(self): def color_label(self) -> None:
""" """
View activ Tunnel in the color green or yellow View activ Tunnel in the color green or yellow
""" """
lines = AppConfig.SETTINGS_FILE.read_text()
with open(set_file, "r", encoding="utf-8") as read_file:
lines = read_file.readlines()
if "light\n" in lines: if "light\n" in lines:
self.lb_tunnel = ttk.Label(self, textvariable=self.str_var, foreground="green") self.lb_tunnel = ttk.Label(self, textvariable=self.str_var, foreground="green")
@ -802,50 +770,22 @@ class FrameWidgets(ttk.Frame):
self.lb_tunnel.config(font=("Ubuntu", 11, "bold")) self.lb_tunnel.config(font=("Ubuntu", 11, "bold"))
self.lb_tunnel.grid(column=2, padx=10, row=1) self.lb_tunnel.grid(column=2, padx=10, row=1)
def wg_switch(self): def wg_switch(self, event=None) -> None:
""" """
switch Tunnel method change from labels and buttons Deals with switching the VPN connection
""" """
self.a = Tunnel.active()
try: try:
if self.a == "": if self.a == "":
self.start()
self.select_tunnel = self.l_box.curselection() self.select_tunnel = self.l_box.curselection()
select_tl = self.l_box.get(self.select_tunnel[0]) select_tl = self.l_box.get(self.select_tunnel[0])
check_call(["nmcli", "connection", "up", select_tl]) self.handle_connection_state("start", select_tl)
wg_read = f"/tmp/tlecdcwg/{select_tl}.conf"
with open(wg_read, "r", encoding="utf-8") as file:
data = Tunnel.con_to_dict(file)
# Address Label else:
self.init_and_report(data)
self.show_data()
# Button Start/Stop data = self.handle_tunnel_data(self.a)
self.stop() if data:
self.a = Tunnel.active()
self.str_var = tk.StringVar()
self.str_var.set(self.a)
self.color_label()
elif self.a != "": self.handle_connection_state("stop")
# Button Start/Stop
self.stop()
check_call(["nmcli", "connection", "down", self.a])
# Button Start/Stop
self.start()
self.a = Tunnel.active()
self.str_var.set("")
self.color_label()
# Address Label
self.add.set("")
self.DNS.set("")
self.enp.set("")
self.show_data()
except IndexError: except IndexError:
@ -857,6 +797,49 @@ class FrameWidgets(ttk.Frame):
LxTools.msg_window(img_w, img_i2, sl, pfit) LxTools.msg_window(img_w, img_i2, sl, pfit)
def handle_connection_state(self, action: str, tunnel_name: str = None) -> None:
"""
central management for connection states
Args:
action (str): "start", "stop" or "toggle"
tunnel_name (str, optional): name of a tunnel for a start-option. defaults to None.
"""
if action == "stop":
if self.a:
check_call(["nmcli", "connection", "down", self.a])
self.update_connection_display()
self.reset_fields()
self.start()
elif action == "start":
if tunnel_name or self.a:
target_tunnel = tunnel_name or self.a
check_call(["nmcli", "connection", "up", target_tunnel])
self.update_connection_display()
data = self.handle_tunnel_data(self.a)
self.init_and_report(data)
self.show_data()
self.color_label()
self.stop()
elif action == "toggle":
if self.a:
self.handle_connection_state("stop")
else:
self.handle_connection_state("start")
def update_connection_display(self) -> None:
"""
Updated the display after connection changes
"""
self.a = Tunnel.active()
if not hasattr(self, "str_var"):
self.str_var = tk.StringVar()
self.str_var.set(self.a)
self.color_label()
self.show_data()
if __name__ == "__main__": if __name__ == "__main__":
window = Wirepy() window = Wirepy()
@ -871,5 +854,5 @@ if __name__ == "__main__":
window.tk.call("set", "::tk::dialog::file::showHiddenVar", "0") window.tk.call("set", "::tk::dialog::file::showHiddenVar", "0")
window.mainloop() window.mainloop()
LxTools.clean_files(folder_path, user_file) LxTools.clean_files(AppConfig.TEMP_DIR, AppConfig.USER_FILE)
sys.exit(0) sys.exit(0)

81
wp_app_config.py Normal file
View File

@ -0,0 +1,81 @@
from pathlib import Path
from typing import Dict, Any
class AppConfig:
"""Central configuration class for the application"""
# Base paths
BASE_DIR = Path.home()
CONFIG_DIR = BASE_DIR / ".config/wire_py"
TEMP_DIR = Path("/tmp/tlecdcwg")
USER_FILE = Path("/tmp/.log_user")
# Configuration files
SETTINGS_FILE = CONFIG_DIR / "settings"
KEYS_FILE = CONFIG_DIR / "keys"
AUTOSTART_SERVICE = Path.home() / ".config/systemd/user/wg_start.service"
# Localization
APP_NAME = "wirepy"
LOCALE_DIR = "/usr/share/locale/"
# Default settings
DEFAULT_SETTINGS = {
"updates": "on",
"theme": "light",
"tooltip": True,
"autostart": "off"
}
# UI configuration
UI_CONFIG = {
"window_title": "Wire-Py",
"window_size": (600, 383),
"font_family": "Ubuntu",
"font_size": 11,
"resizable_window": (False, False)
}
# System-dependent paths
SYSTEM_PATHS = {
"ssl_decrypt": "/usr/local/bin/ssl_decrypt.py",
"ssl_encrypt": "/usr/local/bin/ssl_encrypt.py",
"tcl_path": "/usr/share/TK-Themes"
}
@classmethod
def ensure_directories(cls) -> None:
"""Ensures that all required directories exist"""
cls.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
cls.TEMP_DIR.mkdir(parents=True, exist_ok=True)
@classmethod
def create_default_settings(cls) -> None:
"""Creates default settings if they don't exist"""
if not cls.SETTINGS_FILE.exists():
content = "\n".join(f"[{k.upper()}]\n{v}" for k, v in cls.DEFAULT_SETTINGS.items())
cls.SETTINGS_FILE.write_text(content)
@classmethod
def get_image_paths(cls) -> Dict[str, Path]:
"""Returns paths to UI images"""
return {
"main_icon": cls.CONFIG_DIR / "images/main.png",
"warning": cls.CONFIG_DIR / "images/warning.png",
"success": cls.CONFIG_DIR / "images/success.png",
"error": cls.CONFIG_DIR / "images/error.png"
}
@classmethod
def get_autostart_content(cls) -> str:
"""Returns the content for the autostart service file"""
return """[Unit]
Description=Automatic Tunnel Start
After=network-online.target
[Service]
Type=oneshot
ExecStartPre=/bin/sleep 5
ExecStart=/usr/local/bin/start_wg.py
[Install]
WantedBy=default.target"""