fix message window a path errors

This commit is contained in:
Désiré Werner Menrath 2025-05-07 20:25:09 +02:00
parent c56b42df3e
commit f4a51f0050
7 changed files with 724 additions and 299 deletions

View File

@ -1,7 +1,5 @@
""" Classes Method and Functions for lx Apps """ """ Classes Method and Functions for lx Apps """
import gettext
import locale
import os import os
import shutil import shutil
import signal import signal
@ -20,6 +18,7 @@ import requests
# Translate # Translate
_ = AppConfig.setup_translations() _ = AppConfig.setup_translations()
class Create: class Create:
""" """
This class is for the creation of the folders and files This class is for the creation of the folders and files
@ -43,7 +42,9 @@ class Create:
else: else:
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 AppConfig.KEYS_FILE.exists(): if AppConfig.KEYS_FILE.exists():
pass pass
@ -66,9 +67,11 @@ class Create:
else: else:
wg_ser.touch() wg_ser.touch()
wg_ser.write_text("[Unit]\nDescription=Automatic Tunnel Start\nAfter=network-online.target\n\n[Service]\n" wg_ser.write_text(
"Type=oneshot\nExecStartPre=/bin/sleep 5\nExecStart=/usr/local/bin/start_wg.py\n[Install]" "[Unit]\nDescription=Automatic Tunnel Start\nAfter=network-online.target\n\n[Service]\n"
"\nWantedBy=default.target") "Type=oneshot\nExecStartPre=/bin/sleep 5\nExecStart=/usr/local/bin/start_wg.py\n[Install]"
"\nWantedBy=default.target"
)
check_call(["systemctl", "--user", "enable", "wg_start.service"]) check_call(["systemctl", "--user", "enable", "wg_start.service"])
@staticmethod @staticmethod
@ -85,8 +88,12 @@ class Create:
""" """
Starts SSL dencrypt Starts SSL dencrypt
""" """
process: CompletedProcess[str] = subprocess.run(["pkexec", "/usr/local/bin/ssl_decrypt.py"], process: CompletedProcess[str] = subprocess.run(
stdout=subprocess.PIPE, text=True, check=True) ["pkexec", "/usr/local/bin/ssl_decrypt.py"],
stdout=subprocess.PIPE,
text=True,
check=True,
)
path: Path = Path.home() / ".config/wire_py/" path: Path = Path.home() / ".config/wire_py/"
file_in_path: list[Path] = list(path.rglob("*.dat")) file_in_path: list[Path] = list(path.rglob("*.dat"))
if file_in_path: if file_in_path:
@ -102,8 +109,12 @@ class Create:
""" """
Starts SSL encryption Starts SSL encryption
""" """
process: CompletedProcess[str] = subprocess.run(["pkexec", "/usr/local/bin/ssl_encrypt.py"], process: CompletedProcess[str] = subprocess.run(
stdout=subprocess.PIPE, text=True, check=True) ["pkexec", "/usr/local/bin/ssl_encrypt.py"],
stdout=subprocess.PIPE,
text=True,
check=True,
)
print(process.stdout) print(process.stdout)
if process.returncode == 0: if process.returncode == 0:
print("All Files successfully encrypted...") print("All Files successfully encrypted...")
@ -134,7 +145,8 @@ class LxTools(tk.Tk):
# First attempt: Try to use GDK if available (works on both X11 and Wayland) # First attempt: Try to use GDK if available (works on both X11 and Wayland)
try: try:
import gi import gi
gi.require_version('Gdk', '3.0')
gi.require_version("Gdk", "3.0")
from gi.repository import Gdk from gi.repository import Gdk
display = Gdk.Display.get_default() display = Gdk.Display.get_default()
@ -155,7 +167,10 @@ class LxTools(tk.Tk):
# Second attempt: Try xrandr for X11 # Second attempt: Try xrandr for X11
try: try:
import subprocess import subprocess
output = subprocess.check_output(["xrandr", "--query"], universal_newlines=True)
output = subprocess.check_output(
["xrandr", "--query"], universal_newlines=True
)
# Parse the output to find the primary monitor # Parse the output to find the primary monitor
primary_info = None primary_info = None
@ -193,7 +208,9 @@ class LxTools(tk.Tk):
# Try to make an educated guess for multi-monitor setups # Try to make an educated guess for multi-monitor setups
# If screen width is much larger than height, assume multiple monitors side by side # If screen width is much larger than height, assume multiple monitors side by side
if screen_width > screen_height * 1.8: # Heuristic for detecting multiple monitors if (
screen_width > screen_height * 1.8
): # Heuristic for detecting multiple monitors
# Assume primary monitor is on the left half # Assume primary monitor is on the left half
screen_width = screen_width // 2 screen_width = screen_width // 2
@ -201,7 +218,6 @@ class LxTools(tk.Tk):
y = (screen_height - height) // 2 y = (screen_height - height) // 2
window.geometry(f"{width}x{height}+{x}+{y}") window.geometry(f"{width}x{height}+{x}+{y}")
@staticmethod @staticmethod
def get_file_name(path: Path, i: int = 5) -> List[str]: def get_file_name(path: Path, i: int = 5) -> List[str]:
""" """
@ -253,8 +269,14 @@ class LxTools(tk.Tk):
Path.unlink(file) Path.unlink(file)
@staticmethod @staticmethod
def msg_window(image_path: Path, image_path2: Path, w_title: str, w_txt: str, txt2: Optional[str] = None, def msg_window(
com: Optional[str] = None) -> None: image_path: Path,
image_path2: Path,
w_title: str,
w_txt: str,
txt2: Optional[str] = None,
com: Optional[str] = None,
) -> None:
""" """
Creates message windows Creates message windows
@ -269,29 +291,44 @@ class LxTools(tk.Tk):
msg.resizable(width=False, height=False) msg.resizable(width=False, height=False)
msg.title(w_title) msg.title(w_title)
msg.configure(pady=15, padx=15) msg.configure(pady=15, padx=15)
msg.img = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_info"])
msg.i_window = tk.Label(msg, image=msg.img) # Lade das erste Bild für das Fenster
try:
msg.img = tk.PhotoImage(file=image_path)
msg.i_window = tk.Label(msg, image=msg.img)
except Exception as e:
print(f"Fehler beim Laden des Fensterbildes: {e}")
msg.i_window = tk.Label(msg, text="Bild nicht gefunden")
label: tk.Label = tk.Label(msg, text=w_txt) label: tk.Label = tk.Label(msg, text=w_txt)
label.grid(column=1, row=0) label.grid(column=1, row=0)
if txt2 is not None and com is not None: if txt2 is not None and com is not None:
label.config(font=("Ubuntu", 11), padx=15, justify="left") label.config(font=("Ubuntu", 11), padx=15, justify="left")
msg.i_window.grid(column=0, row=0, sticky="nw") msg.i_window.grid(column=0, row=0, sticky="nw")
button2: ttk.Button = ttk.Button(msg, text=f"{txt2}", command=com, padding=4) button2: ttk.Button = ttk.Button(
msg, text=f"{txt2}", command=com, padding=4
)
button2.grid(column=0, row=1, sticky="e", columnspan=2) button2.grid(column=0, row=1, sticky="e", columnspan=2)
button: ttk.Button = ttk.Button(msg, text="OK", command=msg.destroy, padding=4) button: ttk.Button = ttk.Button(
msg, text="OK", command=msg.destroy, padding=4
)
button.grid(column=0, row=1, sticky="w", columnspan=2) button.grid(column=0, row=1, sticky="w", columnspan=2)
else: else:
label.config(font=("Ubuntu", 11), padx=15) label.config(font=("Ubuntu", 11), padx=15)
msg.i_window.grid(column=0, row=0) msg.i_window.grid(column=0, row=0)
button: ttk.Button = ttk.Button(msg, text="OK", command=msg.destroy, padding=4) button: ttk.Button = ttk.Button(
msg, text="OK", command=msg.destroy, padding=4
)
button.grid(column=0, columnspan=2, row=1) button.grid(column=0, columnspan=2, row=1)
AppConfig.IMAGE_PATHS["icon_vpn"]: tk.PhotoImage = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_vpn"]) # Lade das Icon für das Fenster
msg.iconphoto(True, AppConfig.IMAGE_PATHS["icon_vpn"]) try:
icon = tk.PhotoImage(file=image_path2)
msg.iconphoto(True, icon)
except Exception as e:
print(f"Fehler beim Laden des Fenstericons: {e}")
msg.columnconfigure(0, weight=1) msg.columnconfigure(0, weight=1)
msg.rowconfigure(0, weight=1) msg.rowconfigure(0, weight=1)
msg.winfo_toplevel() msg.winfo_toplevel()
@ -317,15 +354,22 @@ class LxTools(tk.Tk):
NoReturn since the function either exits the program or continues execution NoReturn since the function either exits the program or continues execution
""" """
signals_to_names_dict: Dict[int, str] = dict((getattr(signal, n), n) for n in dir(signal) signals_to_names_dict: Dict[int, str] = dict(
if n.startswith("SIG") and "_" not in n) (getattr(signal, n), n)
for n in dir(signal)
if n.startswith("SIG") and "_" not in n
)
signal_name: str = signals_to_names_dict.get(signum, f"Unnamed signal: {signum}") signal_name: str = signals_to_names_dict.get(
signum, f"Unnamed signal: {signum}"
)
# End program for certain signals, report to others only reception # End program for certain signals, report to others only reception
if signum in (signal.SIGINT, signal.SIGTERM): if signum in (signal.SIGINT, signal.SIGTERM):
exit_code: int = 1 exit_code: int = 1
print(f"\nSignal {signal_name} {signum} received. => Aborting with exit code {exit_code}.") print(
f"\nSignal {signal_name} {signum} received. => Aborting with exit code {exit_code}."
)
LxTools.clean_files(file_path, file) LxTools.clean_files(file_path, file)
print("Breakdown by user...") print("Breakdown by user...")
sys.exit(exit_code) sys.exit(exit_code)
@ -344,6 +388,7 @@ class Tunnel:
""" """
Class of Methods for Wire-Py Class of Methods for Wire-Py
""" """
@classmethod @classmethod
def con_to_dict(cls, file: TextIO) -> Tuple[str, str, str, Optional[str]]: def con_to_dict(cls, file: TextIO) -> Tuple[str, str, str, Optional[str]]:
""" """
@ -394,7 +439,11 @@ class Tunnel:
""" """
Shows the Active Tunnel Shows the Active Tunnel
""" """
active = (os.popen('nmcli con show --active | grep -iPo "(.*)(wireguard)"').read().split()) active = (
os.popen('nmcli con show --active | grep -iPo "(.*)(wireguard)"')
.read()
.split()
)
if not active: if not active:
active = "" active = ""
else: else:
@ -413,8 +462,14 @@ class Tunnel:
return wg_s return wg_s
@staticmethod @staticmethod
def export(image_path: Path = None, image_path2: Path = None, image_path3: Path = None, image_path4: Path = None, def export(
title: Dict = None, window_msg: Dict = None) -> None: image_path: Path = None,
image_path2: Path = None,
image_path3: Path = None,
image_path4: Path = None,
title: Dict = None,
window_msg: Dict = None,
) -> None:
""" """
This will export the tunnels. This will export the tunnels.
A zipfile with the current date and time is created A zipfile with the current date and time is created
@ -439,15 +494,30 @@ class Tunnel:
with zipfile.ZipFile(f"{wg_tar}.zip", "r") as zf: with zipfile.ZipFile(f"{wg_tar}.zip", "r") as zf:
if len(zf.namelist()) != 0: if len(zf.namelist()) != 0:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_vpn"], Msg.STR["exp_succ"], Msg.STR["exp_in_home"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_vpn"],
Msg.STR["exp_succ"],
Msg.STR["exp_in_home"],
)
else: else:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["exp_err"], Msg.STR["exp_try"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_error"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["exp_err"],
Msg.STR["exp_try"],
)
else: else:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["sel_tl"], Msg.STR["tl_first"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["sel_tl"],
Msg.STR["tl_first"],
)
except TypeError: except TypeError:
pass pass
@ -459,6 +529,7 @@ class ConfigManager:
Universal class for managing configuration files with caching. Universal class for managing configuration files with caching.
Can be reused in different projects. Can be reused in different projects.
""" """
_config = None _config = None
_config_file = None _config_file = None
@ -475,18 +546,19 @@ class ConfigManager:
try: try:
lines = Path(cls._config_file).read_text(encoding="utf-8").splitlines() lines = Path(cls._config_file).read_text(encoding="utf-8").splitlines()
cls._config = { cls._config = {
'updates': lines[1].strip(), "updates": lines[1].strip(),
'theme': lines[3].strip(), "theme": lines[3].strip(),
'tooltips': lines[5].strip() == "True", # is converted here to boolean!!! "tooltips": lines[5].strip()
'autostart': lines[7].strip() if len(lines) > 7 else 'off' == "True", # is converted here to boolean!!!
"autostart": lines[7].strip() if len(lines) > 7 else "off",
} }
except (IndexError, FileNotFoundError): except (IndexError, FileNotFoundError):
# DeDefault values in case of error # DeDefault values in case of error
cls._config = { cls._config = {
'updates': 'on', "updates": "on",
'theme': 'light', "theme": "light",
'tooltips': "True", # Default Value as string ! "tooltips": "True", # Default Value as string !
'autostart': 'off' "autostart": "off",
} }
return cls._config return cls._config
@ -495,16 +567,16 @@ class ConfigManager:
"""Save the config to the config file""" """Save the config to the config file"""
if cls._config: if cls._config:
lines = [ lines = [
'# Configuration\n', "# Configuration\n",
f"{cls._config['updates']}\n", f"{cls._config['updates']}\n",
'# Theme\n', "# Theme\n",
f"{cls._config['theme']}\n", f"{cls._config['theme']}\n",
'# Tooltips\n', "# Tooltips\n",
f"{str(cls._config['tooltips'])}\n", f"{str(cls._config['tooltips'])}\n",
'# Autostart\n', "# Autostart\n",
f"{cls._config['autostart']}\n" f"{cls._config['autostart']}\n",
] ]
Path(cls._config_file).write_text(''.join(lines), encoding="utf-8") Path(cls._config_file).write_text("".join(lines), encoding="utf-8")
@classmethod @classmethod
def set(cls, key, value): def set(cls, key, value):
@ -579,8 +651,14 @@ class GiteaUpdate:
return "Invalid API Response" return "Invalid API Response"
@staticmethod @staticmethod
def download(urld: str, res: str, image_path: Path = None, image_path2: Path = None, image_path3: Path = None, def download(
image_path4: Path = None) -> None: urld: str,
res: str,
image_path: Path = None,
image_path2: Path = None,
image_path3: Path = None,
image_path4: Path = None,
) -> None:
""" """
Downloads new version of wirepy Downloads new version of wirepy
@ -600,22 +678,37 @@ class GiteaUpdate:
wt: str = _("Download Successful") wt: str = _("Download Successful")
msg_t: str = _("Your zip file is in home directory") msg_t: str = _("Your zip file is in home directory")
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_vpn"], wt, msg_t) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_vpn"],
wt,
msg_t,
)
else: else:
wt: str = _("Download error") wt: str = _("Download error")
msg_t: str = _("Download failed! Please try again") msg_t: str = _("Download failed! Please try again")
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"], wt, msg_t) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_error"],
AppConfig.IMAGE_PATHS["icon_msg"],
wt,
msg_t,
)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
wt: str = _("Download error") wt: str = _("Download error")
msg_t: str = _("Download failed! No internet connection!") msg_t: str = _("Download failed! No internet connection!")
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"], wt, msg_t) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_error"],
AppConfig.IMAGE_PATHS["icon_msg"],
wt,
msg_t,
)
class Tooltip(): class Tooltip:
"""Class for Tooltip """Class for Tooltip
from common_tools.py import Tooltip from common_tools.py import Tooltip
example: Tooltip(label, "Show tooltip on label") example: Tooltip(label, "Show tooltip on label")
@ -627,8 +720,15 @@ class Tooltip():
NOTE: When using with state_var, pass the tk.BooleanVar object directly, NOTE: When using with state_var, pass the tk.BooleanVar object directly,
NOT its value. For example: use state_var=my_bool_var, NOT state_var=my_bool_var.get() NOT its value. For example: use state_var=my_bool_var, NOT state_var=my_bool_var.get()
""" """
def __init__(self, widget: Any, text: str, state_var: Optional[tk.BooleanVar] = None,
x_offset: int = 65, y_offset: int = 40) -> None: def __init__(
self,
widget: Any,
text: str,
state_var: Optional[tk.BooleanVar] = None,
x_offset: int = 65,
y_offset: int = 40,
) -> None:
"""Tooltip Class""" """Tooltip Class"""
self.widget: Any = widget self.widget: Any = widget
self.text: str = text self.text: str = text
@ -674,8 +774,14 @@ class Tooltip():
tw.wm_geometry(f"+{x}+{y}") tw.wm_geometry(f"+{x}+{y}")
label: tk.Label = tk.Label( label: tk.Label = tk.Label(
tw, text=self.text, background="lightgreen", foreground="black", tw,
relief="solid", borderwidth=1, padx=5, pady=5 text=self.text,
background="lightgreen",
foreground="black",
relief="solid",
borderwidth=1,
padx=5,
pady=5,
) )
label.grid() label.grid()
@ -686,5 +792,3 @@ class Tooltip():
if self.tooltip_window: if self.tooltip_window:
self.tooltip_window.destroy() self.tooltip_window.destroy()
self.tooltip_window = None self.tooltip_window = None

View File

@ -1,15 +0,0 @@
#!/usr/bin/python3
from pathlib import Path
from subprocess import check_call
from tkinter import filedialog, ttk
from common_tools import Create, LxTools
from wp_app_config import AppConfig, Msg
import gettext
import locale
import os
import shutil
import subprocess
from typing import Optional, Dict, Any, NoReturn, TextIO, Tuple, List
# Translate
_ = AppConfig.setup_translations()

View File

@ -12,11 +12,24 @@ uname: Path = Path("/tmp/.log_user")
log_name = Path(uname).read_text(encoding="utf-8") log_name = Path(uname).read_text(encoding="utf-8")
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"
if not keyfile.is_file(): if not keyfile.is_file():
check_call(["openssl", "rsa", "-in", AppConfig.SYSTEM_PATHS["pkey_path"], "-out", keyfile, "-outform", "PEM", "-pubout"]) check_call(
[
"openssl",
"rsa",
"-in",
AppConfig.SYSTEM_PATHS["pkey_path"],
"-out",
keyfile,
"-outform",
"PEM",
"-pubout",
]
)
shutil.chown(keyfile, 1000, 1000) shutil.chown(keyfile, 1000, 1000)
AppConfig.TEMP_DIR2 = f"/home/{log_name}/.config/wire_py/" AppConfig.TEMP_DIR2 = f"/home/{log_name}/.config/wire_py/"
@ -29,6 +42,17 @@ if os.path.exists(f"{AppConfig.TEMP_DIR2}pbwgk.pem"):
for detunnels in detl: for detunnels in detl:
tlname2 = f"{detunnels[:-4]}.conf" tlname2 = f"{detunnels[:-4]}.conf"
extpath = f"{AppConfig.TEMP_DIR}/{tlname2}" extpath = f"{AppConfig.TEMP_DIR}/{tlname2}"
check_call(["openssl", "pkeyutl", "-decrypt", "-inkey", AppConfig.SYSTEM_PATHS["pkey_path"], "-in", detunnels, check_call(
"-out", extpath]) [
"openssl",
"pkeyutl",
"-decrypt",
"-inkey",
AppConfig.SYSTEM_PATHS["pkey_path"],
"-in",
detunnels,
"-out",
extpath,
]
)
shutil.chown(extpath, 1000, 1000) shutil.chown(extpath, 1000, 1000)

View File

@ -8,15 +8,26 @@ from subprocess import check_call
from common_tools import LxTools from common_tools import LxTools
from wp_app_config import AppConfig from wp_app_config import AppConfig
#uname: Path = Path("/tmp/.log_user")
#log_name = AppConfig.USER_FILE.read_text(encoding="utf-8") keyfile: Path = Path(
f"/home/{AppConfig.USER_FILE.read_text(encoding="utf-8")}/.config/wire_py/pbwgk.pem"
keyfile: Path = Path(f"/home/{AppConfig.USER_FILE.read_text(encoding="utf-8")}/.config/wire_py/pbwgk.pem") )
if not keyfile.is_file(): if not keyfile.is_file():
check_call(["openssl", "rsa", "-in", AppConfig.SYSTEM_PATHS["pkey_path"], "-out", keyfile, "-outform", "PEM", "-pubout"]) check_call(
[
"openssl",
"rsa",
"-in",
AppConfig.SYSTEM_PATHS["pkey_path"],
"-out",
keyfile,
"-outform",
"PEM",
"-pubout",
]
)
shutil.chown(keyfile, 1000, 1000) shutil.chown(keyfile, 1000, 1000)
if AppConfig.TEMP_DIR.exists(): if AppConfig.TEMP_DIR.exists():
@ -28,8 +39,20 @@ if not keyfile.is_file():
for tunnels in tl: for tunnels in tl:
sourcetl: str = f"{AppConfig.TEMP_DIR}/{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(
tlname,]) [
"openssl",
"pkeyutl",
"-encrypt",
"-inkey",
keyfile,
"-pubin",
"-in",
sourcetl,
"-out",
tlname,
]
)
else: else:
@ -42,5 +65,17 @@ else:
for tunnels in tl: for tunnels in tl:
sourcetl: str = f"{AppConfig.TEMP_DIR}/{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(
tlname]) [
"openssl",
"pkeyutl",
"-encrypt",
"-inkey",
keyfile,
"-pubin",
"-in",
sourcetl,
"-out",
tlname,
]
)

View File

@ -2,6 +2,7 @@
""" """
This script belongs to wirepy and is for the auto start of the tunnel This script belongs to wirepy and is for the auto start of the tunnel
""" """
from pathlib import Path from pathlib import Path
from subprocess import check_call from subprocess import check_call

454
wirepy.py
View File

@ -2,8 +2,6 @@
""" """
this script is a simple GUI for managing Wireguard Tunnels this script is a simple GUI for managing Wireguard Tunnels
""" """
import gettext
import locale
import os import os
import shutil import shutil
import subprocess import subprocess
@ -14,7 +12,15 @@ from pathlib import Path
from subprocess import check_call from subprocess import check_call
from tkinter import TclError, filedialog, ttk from tkinter import TclError, filedialog, ttk
from common_tools import (ConfigManager, ThemeManager, Create, GiteaUpdate, Tunnel, Tooltip, LxTools) from common_tools import (
ConfigManager,
ThemeManager,
Create,
GiteaUpdate,
Tunnel,
Tooltip,
LxTools,
)
from wp_app_config import AppConfig, Msg from wp_app_config import AppConfig, Msg
LxTools.uos() LxTools.uos()
@ -22,10 +28,12 @@ Create.dir_and_files()
Create.make_dir() Create.make_dir()
Create.decrypt() Create.decrypt()
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)
@ -38,8 +46,10 @@ class Wirepy(tk.Tk):
# Set the window size # Set the window size
self.geometry(f"{self.x_width}x{self.y_height}") self.geometry(f"{self.x_width}x{self.y_height}")
self.resizable(AppConfig.UI_CONFIG["resizable_window"][0], self.resizable(
AppConfig.UI_CONFIG["resizable_window"][1]) AppConfig.UI_CONFIG["resizable_window"][0],
AppConfig.UI_CONFIG["resizable_window"][1],
)
self.title(AppConfig.UI_CONFIG["window_title"]) self.title(AppConfig.UI_CONFIG["window_title"])
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
@ -69,6 +79,7 @@ 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)
@ -101,13 +112,16 @@ class FrameWidgets(ttk.Frame):
# If it's a string or something else # If it's a string or something else
self.tooltip_state.set(str(state) == "True") self.tooltip_state.set(str(state) == "True")
self.tooltip_label = tk.StringVar() # StringVar-Variable for tooltip label for view Disabled/Enabled self.tooltip_label = (
tk.StringVar()
) # StringVar-Variable for tooltip label for view Disabled/Enabled
self.tooltip_update_label() self.tooltip_update_label()
self.update_label = tk.StringVar() # StringVar-Variable for update label self.update_label = tk.StringVar() # StringVar-Variable for update label
self.update_tooltip = tk.StringVar() # StringVar-Variable for update tooltip please not remove! self.update_tooltip = (
tk.StringVar()
) # StringVar-Variable for update tooltip please not remove!
self.update_foreground = tk.StringVar(value="red") self.update_foreground = tk.StringVar(value="red")
# 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")
@ -118,7 +132,9 @@ class FrameWidgets(ttk.Frame):
self.version_lb.config(font=("Ubuntu", 11), foreground="#00c4ff") self.version_lb.config(font=("Ubuntu", 11), foreground="#00c4ff")
self.version_lb.grid(column=0, row=0, rowspan=4, padx=10) self.version_lb.grid(column=0, row=0, rowspan=4, padx=10)
Tooltip(self.version_lb, f"Version: {AppConfig.VERSION[2:]}", self.tooltip_state) Tooltip(
self.version_lb, f"Version: {AppConfig.VERSION[2:]}", self.tooltip_state
)
self.options_btn = ttk.Menubutton(self.menu_frame, text=_("Options")) self.options_btn = ttk.Menubutton(self.menu_frame, text=_("Options"))
self.options_btn.grid(column=1, columnspan=1, row=0) self.options_btn.grid(column=1, columnspan=1, row=0)
@ -128,27 +144,37 @@ class FrameWidgets(ttk.Frame):
self.set_update = tk.IntVar() self.set_update = tk.IntVar()
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"), self.settings.add_checkbutton(
command=lambda: self.update_setting(self.set_update.get()), variable=self.set_update) label=_("Disable Updates"),
command=lambda: self.update_setting(self.set_update.get()),
variable=self.set_update,
)
self.updates_lb = ttk.Label(self.menu_frame, textvariable=self.update_label) self.updates_lb = ttk.Label(self.menu_frame, textvariable=self.update_label)
self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10) self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10)
self.updates_lb.grid_remove() self.updates_lb.grid_remove()
self.update_label.trace_add("write", self.update_label_display) self.update_label.trace_add("write", self.update_label_display)
self.update_foreground.trace_add("write", self.update_label_display) self.update_foreground.trace_add("write", self.update_label_display)
res = GiteaUpdate.api_down(AppConfig.UPDATE_URL, AppConfig.VERSION, ConfigManager.get("updates")) res = GiteaUpdate.api_down(
AppConfig.UPDATE_URL, AppConfig.VERSION, ConfigManager.get("updates")
)
self.update_ui_for_update(res) self.update_ui_for_update(res)
# Tooltip Menu # Tooltip Menu
self.settings.add_command(label=self.tooltip_label.get(), command=self.tooltips_toggle) self.settings.add_command(
label=self.tooltip_label.get(), command=self.tooltips_toggle
)
# Label show dark or light # Label show dark or light
self.theme_label = tk.StringVar() self.theme_label = tk.StringVar()
self.update_theme_label() self.update_theme_label()
self.settings.add_command(label=self.theme_label.get(), command=self.on_theme_toggle) self.settings.add_command(
label=self.theme_label.get(), command=self.on_theme_toggle
)
# 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=self.about) 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)
@ -172,7 +198,9 @@ class FrameWidgets(ttk.Frame):
# Bottom Frame 4 # Bottom Frame 4
self.lb_frame3 = ttk.Frame(self) self.lb_frame3 = ttk.Frame(self)
self.lb_frame3.configure(relief="flat") self.lb_frame3.configure(relief="flat")
self.lb_frame3.grid(column=0, row=5, columnspan=4, sticky="snew", padx=2, pady=2) self.lb_frame3.grid(
column=0, row=5, columnspan=4, sticky="snew", padx=2, pady=2
)
# Bottom Frame 5 # Bottom Frame 5
self.lb_frame4 = ttk.Frame(self) self.lb_frame4 = ttk.Frame(self)
@ -205,7 +233,9 @@ class FrameWidgets(ttk.Frame):
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>>", self.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)
@ -230,14 +260,24 @@ class FrameWidgets(ttk.Frame):
self.show_data() self.show_data()
# Button Import # Button Import
self.btn_i = ttk.Button(self.lb_frame_btn_lbox, image=self.imp_pic, command=self.import_sl, padding=0) self.btn_i = ttk.Button(
self.lb_frame_btn_lbox,
image=self.imp_pic,
command=self.import_sl,
padding=0,
)
self.btn_i.grid(column=0, row=1, padx=15, pady=8) self.btn_i.grid(column=0, row=1, padx=15, pady=8)
Tooltip(self.btn_i, Msg.TTIP["import_tl"], self.tooltip_state) Tooltip(self.btn_i, Msg.TTIP["import_tl"], self.tooltip_state)
# Button Trash # Button Trash
self.btn_tr = ttk.Button(self.lb_frame_btn_lbox, image=self.tr_pic, command=self.delete, padding=0, self.btn_tr = ttk.Button(
style="CButton.TButton") self.lb_frame_btn_lbox,
image=self.tr_pic,
command=self.delete,
padding=0,
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)
if self.l_box.size() == 0: if self.l_box.size() == 0:
@ -246,11 +286,19 @@ class FrameWidgets(ttk.Frame):
Tooltip(self.btn_tr, Msg.TTIP["trash_tl"], self.tooltip_state) Tooltip(self.btn_tr, Msg.TTIP["trash_tl"], self.tooltip_state)
# Button Export # Button Export
self.btn_exp = ttk.Button(self.lb_frame_btn_lbox, image=self.exp_pic, self.btn_exp = ttk.Button(
command=lambda: Tunnel.export(AppConfig.IMAGE_PATHS["icon_info"], self.lb_frame_btn_lbox,
AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_error"], image=self.exp_pic,
AppConfig.IMAGE_PATHS["icon_msg"], command=lambda: Tunnel.export(
Msg.STR["sel_tl"], Msg.STR["tl_first"]), padding=0) AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_vpn"],
AppConfig.IMAGE_PATHS["icon_error"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["sel_tl"],
Msg.STR["tl_first"],
),
padding=0,
)
self.btn_exp.grid(column=0, row=3, padx=15, pady=8) self.btn_exp.grid(column=0, row=3, padx=15, pady=8)
@ -266,13 +314,31 @@ class FrameWidgets(ttk.Frame):
self.lb_rename.config(state="disable") self.lb_rename.config(state="disable")
if self.l_box.size() != 0: if self.l_box.size() != 0:
Tooltip(self.lb_rename, Msg.TTIP["rename_tl"], self.tooltip_state, x_offset= -120, y_offset=-70) Tooltip(
self.lb_rename,
Msg.TTIP["rename_tl"],
self.tooltip_state,
x_offset=-120,
y_offset=-70,
)
else: else:
Tooltip(self.lb_rename, Msg.TTIP["rename_tl_info"], self.tooltip_state, x_offset=-180, y_offset=-50) Tooltip(
self.lb_rename,
Msg.TTIP["rename_tl_info"],
self.tooltip_state,
x_offset=-180,
y_offset=-50,
)
# Button Rename # Button Rename
self.btn_rename = ttk.Button(self.lb_frame4, text=_("Rename"), state="disable", command=self.tl_rename, self.btn_rename = ttk.Button(
padding=4, style="RnButton.TButton") 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") self.btn_rename.grid(column=3, row=0, padx=5, pady=10, sticky="ne")
# Check Buttons # Check Buttons
@ -281,22 +347,46 @@ class FrameWidgets(ttk.Frame):
self.autoconnect_var.set(f"{self.auto_con}") self.autoconnect_var.set(f"{self.auto_con}")
# Frame for Labels, Entry and Button # Frame for Labels, Entry and Button
self.autoconnect = ttk.Label(self.lb_frame3, textvariable=self.autoconnect_var, width=15) self.autoconnect = ttk.Label(
self.lb_frame3, textvariable=self.autoconnect_var, width=15
)
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)
self.wg_autostart = ttk.Checkbutton(self.lb_frame3, text=_("Autoconnect on:"), variable=self.selected_option, self.wg_autostart = ttk.Checkbutton(
command=self.box_set) 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") 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: if self.l_box.size() >= 1 and len(self.l_box.curselection()) >= 1:
Tooltip(self.wg_autostart, Msg.TTIP["autostart"], self.tooltip_state, x_offset=-10, y_offset=-40) Tooltip(
self.wg_autostart,
Msg.TTIP["autostart"],
self.tooltip_state,
x_offset=-10,
y_offset=-40,
)
if self.l_box.size() == 0: if self.l_box.size() == 0:
Tooltip(self.wg_autostart, Msg.TTIP["autostart_info"], self.tooltip_state, x_offset=30, y_offset=-50) Tooltip(
self.wg_autostart,
Msg.TTIP["autostart_info"],
self.tooltip_state,
x_offset=30,
y_offset=-50,
)
else: else:
Tooltip(self.wg_autostart, Msg.TTIP["autostart"], self.tooltip_state, x_offset=-10, y_offset=-40) Tooltip(
self.wg_autostart,
Msg.TTIP["autostart"],
self.tooltip_state,
x_offset=-10,
y_offset=-40,
)
self.on_off() self.on_off()
@ -316,9 +406,9 @@ class FrameWidgets(ttk.Frame):
def update_ui_for_update(self, res): def update_ui_for_update(self, res):
"""Update UI elements based on update check result""" """Update UI elements based on update check result"""
# First, remove the update button if it exists to avoid conflicts # First, remove the update button if it exists to avoid conflicts
if hasattr(self, 'update_btn'): if hasattr(self, "update_btn"):
self.update_btn.grid_forget() self.update_btn.grid_forget()
delattr(self, 'update_btn') delattr(self, "update_btn")
if res == "False": if res == "False":
self.set_update.set(value=1) self.set_update.set(value=1)
@ -333,7 +423,11 @@ class FrameWidgets(ttk.Frame):
self.update_label.set(_("No Server Connection!")) self.update_label.set(_("No Server Connection!"))
self.update_foreground.set("red") self.update_foreground.set("red")
# Set tooltip for "No Server Connection" # Set tooltip for "No Server Connection"
Tooltip(self.updates_lb, _("Could not connect to update server"), self.tooltip_state) Tooltip(
self.updates_lb,
_("Could not connect to update server"),
self.tooltip_state,
)
elif res == "No Updates": elif res == "No Updates":
self.update_label.set(_("No Updates")) self.update_label.set(_("No Updates"))
@ -352,7 +446,9 @@ class FrameWidgets(ttk.Frame):
# Create the update button # Create the update button
self.update_btn = ttk.Menubutton(self.menu_frame, text=update_text) self.update_btn = ttk.Menubutton(self.menu_frame, text=update_text)
self.update_btn.grid(column=4, columnspan=3, row=0, padx=0) self.update_btn.grid(column=4, columnspan=3, row=0, padx=0)
Tooltip(self.update_btn, _("Click to download new version"), self.tooltip_state) Tooltip(
self.update_btn, _("Click to download new version"), self.tooltip_state
)
self.download = tk.Menu(self, relief="flat") self.download = tk.Menu(self, relief="flat")
self.update_btn.configure(menu=self.download, style="Toolbutton") self.update_btn.configure(menu=self.download, style="Toolbutton")
@ -364,8 +460,8 @@ class FrameWidgets(ttk.Frame):
AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_vpn"],
AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_error"],
AppConfig.IMAGE_PATHS["icon_msg"] AppConfig.IMAGE_PATHS["icon_msg"],
) ),
) )
@staticmethod @staticmethod
@ -373,15 +469,26 @@ class FrameWidgets(ttk.Frame):
""" """
a tk.Toplevel window a tk.Toplevel window
""" """
def link_btn() -> str | None: def link_btn() -> str | None:
webbrowser.open("https://git.ilunix.de/punix/Wire-Py") webbrowser.open("https://git.ilunix.de/punix/Wire-Py")
msg_t = _("Wire-Py a simple Wireguard Gui for Linux systems.\n\n" msg_t = _(
"Wire-Py is open source software written in Python.\n\n" "Wire-Py a simple Wireguard Gui for Linux systems.\n\n"
"Email: polunga40@unity-mail.de also likes for donation.\n\n" "Wire-Py is open source software written in Python.\n\n"
"Use without warranty!\n") "Email: polunga40@unity-mail.de also likes for donation.\n\n"
"Use without warranty!\n"
)
LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_vpn"],
AppConfig.IMAGE_PATHS["icon_vpn"],
_("Info"),
msg_t,
_("Go to Wire-Py git"),
link_btn,
)
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_vpn"], _("Info"), msg_t, _("Go to Wire-Py git"), link_btn)
def update_setting(self, update_res) -> None: def update_setting(self, update_res) -> None:
"""write off or on in file """write off or on in file
Args: Args:
@ -398,12 +505,14 @@ class FrameWidgets(ttk.Frame):
# When enabling updates, we need to actually check for updates # When enabling updates, we need to actually check for updates
try: try:
# Force a fresh check by passing "on" as the update setting # Force a fresh check by passing "on" as the update setting
res = GiteaUpdate.api_down(AppConfig.UPDATE_URL, AppConfig.VERSION, "on") res = GiteaUpdate.api_down(
AppConfig.UPDATE_URL, AppConfig.VERSION, "on"
)
# Make sure UI is updated regardless of previous state # Make sure UI is updated regardless of previous state
if hasattr(self, 'update_btn'): if hasattr(self, "update_btn"):
self.update_btn.grid_forget() self.update_btn.grid_forget()
if hasattr(self, 'updates_lb'): if hasattr(self, "updates_lb"):
self.updates_lb.grid_forget() self.updates_lb.grid_forget()
# Now update the UI with the fresh result # Now update the UI with the fresh result
@ -461,8 +570,12 @@ class FrameWidgets(ttk.Frame):
""" """
Start Button Start Button
""" """
self.btn_stst = ttk.Button(self.lb_frame_btn_lbox, image=self.wg_vpn_start, self.btn_stst = ttk.Button(
command=lambda: self.wg_switch("start"), padding=0) 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 = LxTools.get_file_name(AppConfig.TEMP_DIR) tl = LxTools.get_file_name(AppConfig.TEMP_DIR)
@ -491,12 +604,16 @@ class FrameWidgets(ttk.Frame):
""" """
View activ Tunnel in the color green or yellow View activ Tunnel in the color green or yellow
""" """
if ConfigManager.get("theme") == "light": if ConfigManager.get("theme") == "light":
self.lb_tunnel = ttk.Label(self, textvariable=self.str_var, foreground="green") self.lb_tunnel = ttk.Label(
self, textvariable=self.str_var, foreground="green"
)
else: else:
self.lb_tunnel = ttk.Label(self, textvariable=self.str_var, foreground="yellow") self.lb_tunnel = ttk.Label(
self, textvariable=self.str_var, foreground="yellow"
)
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)
@ -505,8 +622,12 @@ class FrameWidgets(ttk.Frame):
""" """
Stop Button Stop Button
""" """
self.btn_stst = ttk.Button(self.lb_frame_btn_lbox, image=self.wg_vpn_stop, self.btn_stst = ttk.Button(
command=lambda: self.wg_switch("stop"), padding=0) 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, Msg.TTIP["stop_tl"], self.tooltip_state) Tooltip(self.btn_stst, Msg.TTIP["stop_tl"], self.tooltip_state)
@ -527,7 +648,7 @@ class FrameWidgets(ttk.Frame):
filepath = filedialog.askopenfilename( filepath = filedialog.askopenfilename(
initialdir=f"{Path.home()}", initialdir=f"{Path.home()}",
title=_("Select Wireguard config File"), title=_("Select Wireguard config File"),
filetypes=[(_("WG config files"), "*.conf")] filetypes=[(_("WG config files"), "*.conf")],
) )
# Überprüfe, ob der Benutzer den Dialog abgebrochen hat # Überprüfe, ob der Benutzer den Dialog abgebrochen hat
@ -541,7 +662,11 @@ class FrameWidgets(ttk.Frame):
path_split = filepath.split("/") path_split = filepath.split("/")
path_split1 = path_split[-1] path_split1 = path_split[-1]
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]
@ -550,14 +675,21 @@ class FrameWidgets(ttk.Frame):
p_key = AppConfig.KEYS_FILE.read_text(encoding="utf-8") p_key = AppConfig.KEYS_FILE.read_text(encoding="utf-8")
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:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["imp_err"], Msg.STR["tl_exist"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_error"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["imp_err"],
Msg.STR["tl_exist"],
)
else: else:
with open(AppConfig.KEYS_FILE, "a", encoding="utf-8") as keyfile: with open(
AppConfig.KEYS_FILE, "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, AppConfig.TEMP_DIR) p1 = shutil.copy(filepath, AppConfig.TEMP_DIR)
path_split = path_split1[len(path_split1) - 17:] path_split = path_split1[len(path_split1) - 17 :]
os.rename(p1, f"{AppConfig.TEMP_DIR}/{path_split}") os.rename(p1, f"{AppConfig.TEMP_DIR}/{path_split}")
new_conf = f"{AppConfig.TEMP_DIR}/{path_split}" new_conf = f"{AppConfig.TEMP_DIR}/{path_split}"
@ -565,7 +697,18 @@ class FrameWidgets(ttk.Frame):
check_call(["nmcli", "connection", "down", self.a]) check_call(["nmcli", "connection", "down", self.a])
self.reset_fields() self.reset_fields()
subprocess.check_output(["nmcli", "connection", "import", "type", "wireguard", "file", new_conf], text=True) subprocess.check_output(
[
"nmcli",
"connection",
"import",
"type",
"wireguard",
"file",
new_conf,
],
text=True,
)
Create.encrypt() Create.encrypt()
else: else:
shutil.copy(filepath, f"{AppConfig.TEMP_DIR}/") shutil.copy(filepath, f"{AppConfig.TEMP_DIR}/")
@ -574,7 +717,18 @@ class FrameWidgets(ttk.Frame):
check_call(["nmcli", "connection", "down", self.a]) check_call(["nmcli", "connection", "down", self.a])
self.reset_fields() self.reset_fields()
subprocess.check_output(["nmcli", "connection", "import", "type", "wireguard", "file", filepath], text=True) subprocess.check_output(
[
"nmcli",
"connection",
"import",
"type",
"wireguard",
"file",
filepath,
],
text=True,
)
Create.encrypt() Create.encrypt()
self.str_var.set("") self.str_var.set("")
@ -585,10 +739,18 @@ class FrameWidgets(ttk.Frame):
self.l_box.update() self.l_box.update()
self.l_box.selection_set(0) self.l_box.selection_set(0)
Tooltip(self.wg_autostart, Msg.TTIP["autostart"], self.tooltip_state, x_offset=-10, y_offset=-40) Tooltip(
self.wg_autostart,
Msg.TTIP["autostart"],
self.tooltip_state,
x_offset=-10,
y_offset=-40,
)
Tooltip(self.btn_tr, Msg.TTIP["trash_tl"], self.tooltip_state) Tooltip(self.btn_tr, Msg.TTIP["trash_tl"], self.tooltip_state)
Tooltip(self.btn_exp, Msg.TTIP["export_tl"], self.tooltip_state) Tooltip(self.btn_exp, Msg.TTIP["export_tl"], self.tooltip_state)
Tooltip(self.btn_rename, Msg.TTIP["rename_tl"], self.tooltip_state) Tooltip(
self.btn_rename, Msg.TTIP["rename_tl"], self.tooltip_state
)
self.lb_rename.insert(0, "Max. 12 characters!") self.lb_rename.insert(0, "Max. 12 characters!")
self.str_var = tk.StringVar() self.str_var = tk.StringVar()
@ -596,11 +758,25 @@ class FrameWidgets(ttk.Frame):
self.color_label() self.color_label()
self.stop() self.stop()
data = self.handle_tunnel_data(self.a) data = self.handle_tunnel_data(self.a)
check_call(["nmcli", "con", "mod", self.a, "connection.autoconnect", "no"]) check_call(
[
"nmcli",
"con",
"mod",
self.a,
"connection.autoconnect",
"no",
]
)
elif ("PrivateKey = " in read) and ("Endpoint = " in read): elif ("PrivateKey = " in read) and ("Endpoint = " in read):
pass pass
else: else:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["imp_err"], Msg.STR["no_valid_file"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_error"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["imp_err"],
Msg.STR["no_valid_file"],
)
except EOFError as e: except EOFError as e:
print(e) print(e)
@ -618,15 +794,16 @@ class FrameWidgets(ttk.Frame):
try: try:
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])
with open(f"/tmp/tlecdcwg/{select_tl}.conf", "r+", encoding="utf-8") as file2: with open(
f"/tmp/tlecdcwg/{select_tl}.conf", "r+", encoding="utf-8"
) as file2:
key = Tunnel.con_to_dict(file2) key = Tunnel.con_to_dict(file2)
pre_key = key[3] pre_key = key[3]
check_call(["nmcli", "connection", "delete", select_tl]) check_call(["nmcli", "connection", "delete", select_tl])
self.l_box.delete(self.select_tunnel[0]) self.l_box.delete(self.select_tunnel[0])
with open(AppConfig.SETTINGS_FILE, "r", encoding="utf-8") as set_f6: with open(AppConfig.SETTINGS_FILE, "r", encoding="utf-8") as set_f6:
lines6 = set_f6.readlines() lines6 = set_f6.readlines()
if (select_tl == lines6[7].strip() if select_tl == lines6[7].strip() and "off\n" not in lines6[7].strip():
and "off\n" not in lines6[7].strip()):
lines6[7] = "off\n" lines6[7] = "off\n"
with open(AppConfig.SETTINGS_FILE, "w", encoding="utf-8") as set_f7: with open(AppConfig.SETTINGS_FILE, "w", encoding="utf-8") as set_f7:
set_f7.writelines(lines6) set_f7.writelines(lines6)
@ -637,7 +814,9 @@ class FrameWidgets(ttk.Frame):
Path.unlink(f"{Path.home()}/.config/wire_py/{select_tl}.dat") Path.unlink(f"{Path.home()}/.config/wire_py/{select_tl}.dat")
Path.unlink(f"/tmp/tlecdcwg/{select_tl}.conf") Path.unlink(f"/tmp/tlecdcwg/{select_tl}.conf")
with open(AppConfig.KEYS_FILE, "r", encoding="utf-8") as readfile: with open(AppConfig.KEYS_FILE, "r", encoding="utf-8") as readfile:
with open(f"{Path.home()}/.config/wire_py/keys2", "w", encoding="utf-8") as writefile: with open(
f"{Path.home()}/.config/wire_py/keys2", "w", encoding="utf-8"
) as writefile:
for line in readfile: for line in readfile:
if pre_key not in line.strip("\n"): if pre_key not in line.strip("\n"):
writefile.write(line) writefile.write(line)
@ -650,8 +829,13 @@ class FrameWidgets(ttk.Frame):
if self.l_box.size() == 0: if self.l_box.size() == 0:
self.wg_autostart.configure(state="disabled") self.wg_autostart.configure(state="disabled")
self.lb_rename.configure(state="disabled") self.lb_rename.configure(state="disabled")
Tooltip(self.wg_autostart, Msg.TTIP["autostart_info"] Tooltip(
, self.tooltip_state, x_offset=30, y_offset=-50) self.wg_autostart,
Msg.TTIP["autostart_info"],
self.tooltip_state,
x_offset=30,
y_offset=-50,
)
Tooltip(self.btn_exp, Msg.TTIP["export_tl_info"], self.tooltip_state) Tooltip(self.btn_exp, Msg.TTIP["export_tl_info"], self.tooltip_state)
Tooltip(self.btn_stst, Msg.TTIP["empty_list"], self.tooltip_state) Tooltip(self.btn_stst, Msg.TTIP["empty_list"], self.tooltip_state)
@ -668,11 +852,21 @@ class FrameWidgets(ttk.Frame):
if self.l_box.size() != 0: if self.l_box.size() != 0:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["sel_tl"], Msg.STR["sel_list"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["sel_tl"],
Msg.STR["sel_list"],
)
else: else:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["sel_tl"], Msg.STR["tl_first"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["sel_tl"],
Msg.STR["tl_first"],
)
def enable_check_box(self, _) -> None: def enable_check_box(self, _) -> None:
""" """
@ -691,7 +885,11 @@ class FrameWidgets(ttk.Frame):
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
""" """
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) lines = (
Path(AppConfig.SETTINGS_FILE)
.read_text(encoding="utf-8")
.splitlines(keepends=True)
)
if lines[7] != "off\n": if lines[7] != "off\n":
print(f"{lines[7]} starts automatically when the system starts.") print(f"{lines[7]} starts automatically when the system starts.")
@ -707,7 +905,12 @@ class FrameWidgets(ttk.Frame):
self.autoconnect_var = tk.StringVar() self.autoconnect_var = tk.StringVar()
self.autoconnect_var.set(self.auto_con) self.autoconnect_var.set(self.auto_con)
self.autoconnect = ttk.Label(self.lb_frame3, textvariable=self.autoconnect_var, foreground="#0071ff", width=15) self.autoconnect = ttk.Label(
self.lb_frame3,
textvariable=self.autoconnect_var,
foreground="#0071ff",
width=15,
)
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)
@ -727,9 +930,15 @@ 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:
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) lines = (
lines[7] = 'off\n' Path(AppConfig.SETTINGS_FILE)
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") .read_text(encoding="utf-8")
.splitlines(keepends=True)
)
lines[7] = "off\n"
Path(AppConfig.SETTINGS_FILE).write_text(
"".join(lines), encoding="utf-8"
)
tl = LxTools.get_file_name(AppConfig.TEMP_DIR) tl = LxTools.get_file_name(AppConfig.TEMP_DIR)
@ -737,9 +946,15 @@ 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:
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) lines = (
Path(AppConfig.SETTINGS_FILE)
.read_text(encoding="utf-8")
.splitlines(keepends=True)
)
lines[7] = select_tl lines[7] = select_tl
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") Path(AppConfig.SETTINGS_FILE).write_text(
"".join(lines), encoding="utf-8"
)
except IndexError: except IndexError:
self.selected_option.set(1) self.selected_option.set(1)
@ -755,19 +970,39 @@ class FrameWidgets(ttk.Frame):
if len(self.lb_rename.get()) > 12: if len(self.lb_rename.get()) > 12:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["ren_err"], Msg.STR["sign_len"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["ren_err"],
Msg.STR["sign_len"],
)
elif len(self.lb_rename.get()) == 0: elif len(self.lb_rename.get()) == 0:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["ren_err"], Msg.STR["zero_signs"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["ren_err"],
Msg.STR["zero_signs"],
)
elif any(ch in special_characters for ch in self.lb_rename.get()): elif any(ch in special_characters for ch in self.lb_rename.get()):
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["ren_err"], Msg.STR["false_signs"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["ren_err"],
Msg.STR["false_signs"],
)
elif self.lb_rename.get() in name_of_file: elif self.lb_rename.get() in name_of_file:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["ren_err"], Msg.STR["is_in_use"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["ren_err"],
Msg.STR["is_in_use"],
)
else: else:
@ -776,7 +1011,17 @@ class FrameWidgets(ttk.Frame):
select_tl = self.l_box.get(self.select_tunnel[0]) select_tl = self.l_box.get(self.select_tunnel[0])
# nmcli connection modify old connection.id iphone # nmcli connection modify old connection.id iphone
subprocess.check_output(["nmcli", "connection", "modify", select_tl, "connection.id", self.lb_rename.get()], text=True) subprocess.check_output(
[
"nmcli",
"connection",
"modify",
select_tl,
"connection.id",
self.lb_rename.get(),
],
text=True,
)
source = Path(f"/tmp/tlecdcwg/{select_tl}.conf") source = Path(f"/tmp/tlecdcwg/{select_tl}.conf")
destination = source.with_name(f"{self.lb_rename.get()}.conf") destination = source.with_name(f"{self.lb_rename.get()}.conf")
source.replace(destination) source.replace(destination)
@ -792,7 +1037,9 @@ class FrameWidgets(ttk.Frame):
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(AppConfig.SETTINGS_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)
self.update_connection_display() self.update_connection_display()
@ -800,7 +1047,12 @@ class FrameWidgets(ttk.Frame):
except IndexError: except IndexError:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["ren_err"], Msg.STR["sel_list"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["ren_err"],
Msg.STR["sel_list"],
)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
@ -826,7 +1078,9 @@ class FrameWidgets(ttk.Frame):
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)
self.address.config(font=("Ubuntu", 9)) self.address.config(font=("Ubuntu", 9))
@ -836,7 +1090,9 @@ class FrameWidgets(ttk.Frame):
self.dns.config(font=("Ubuntu", 9)) self.dns.config(font=("Ubuntu", 9))
# Endpoint Label # Endpoint Label
self.endpoint = ttk.Label(self.lb_frame2, textvariable=self.enp, foreground="#0071ff") self.endpoint = ttk.Label(
self.lb_frame2, textvariable=self.enp, foreground="#0071ff"
)
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))
@ -861,11 +1117,21 @@ class FrameWidgets(ttk.Frame):
if self.l_box.size() != 0: if self.l_box.size() != 0:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["sel_tl"], Msg.STR["sel_list"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["sel_tl"],
Msg.STR["sel_list"],
)
else: else:
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["sel_tl"], Msg.STR["tl_first"]) LxTools.msg_window(
AppConfig.IMAGE_PATHS["icon_info"],
AppConfig.IMAGE_PATHS["icon_msg"],
Msg.STR["sel_tl"],
Msg.STR["tl_first"],
)
def handle_connection_state(self, action: str, tunnel_name: str = None) -> None: def handle_connection_state(self, action: str, tunnel_name: str = None) -> None:
""" """

View File

@ -6,6 +6,7 @@ import locale
from pathlib import Path from pathlib import Path
from typing import Dict, Any from typing import Dict, Any
class AppConfig: class AppConfig:
"""Central configuration class for Wire-Py application""" """Central configuration class for Wire-Py application"""
@ -30,23 +31,21 @@ class AppConfig:
UPDATE_URL: str = "https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases" UPDATE_URL: str = "https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases"
DOWNLOAD_URL: str = "https://git.ilunix.de/punix/Wire-Py/archive" DOWNLOAD_URL: str = "https://git.ilunix.de/punix/Wire-Py/archive"
# UI configuration # UI configuration
UI_CONFIG: Dict[str, Any] = { UI_CONFIG: Dict[str, Any] = {
"window_title": "Wire-Py", "window_title": "Wire-Py",
"window_size": (600, 383), "window_size": (600, 383),
"font_family": "Ubuntu", "font_family": "Ubuntu",
"font_size": 11, "font_size": 11,
"resizable_window": (False, False) "resizable_window": (False, False),
} }
# System-dependent paths # System-dependent paths
SYSTEM_PATHS: Dict[str, str]= { SYSTEM_PATHS: Dict[str, str] = {
"ssl_decrypt": "/usr/local/bin/ssl_decrypt.py", "ssl_decrypt": "/usr/local/bin/ssl_decrypt.py",
"ssl_encrypt": "/usr/local/bin/ssl_encrypt.py", "ssl_encrypt": "/usr/local/bin/ssl_encrypt.py",
"tcl_path": "/usr/share/TK-Themes", "tcl_path": "/usr/share/TK-Themes",
"pkey_path": "/usr/local/etc/ssl/pwgk.pem" "pkey_path": "/usr/local/etc/ssl/pwgk.pem",
} }
# Images and icons paths # Images and icons paths
@ -59,8 +58,7 @@ class AppConfig:
"icon_start": "/usr/share/icons/lx-icons/48/wg_vpn-start.png", "icon_start": "/usr/share/icons/lx-icons/48/wg_vpn-start.png",
"icon_stop": "/usr/share/icons/lx-icons/48/wg_vpn-stop.png", "icon_stop": "/usr/share/icons/lx-icons/48/wg_vpn-stop.png",
"icon_info": "/usr/share/icons/lx-icons/64/info.png", "icon_info": "/usr/share/icons/lx-icons/64/info.png",
"icon_error": "/usr/share/icons/lx-icons/64/error.png" "icon_error": "/usr/share/icons/lx-icons/64/error.png",
} }
@staticmethod @staticmethod
@ -87,7 +85,9 @@ class AppConfig:
def create_default_settings(cls) -> None: def create_default_settings(cls) -> None:
"""Creates default settings if they don't exist""" """Creates default settings if they don't exist"""
if not cls.SETTINGS_FILE.exists(): if not cls.SETTINGS_FILE.exists():
content = "\n".join(f"[{k.upper()}]\n{v}" for k, v in cls.DEFAULT_SETTINGS.items()) content = "\n".join(
f"[{k.upper()}]\n{v}" for k, v in cls.DEFAULT_SETTINGS.items()
)
cls.SETTINGS_FILE.write_text(content) cls.SETTINGS_FILE.write_text(content)
@classmethod @classmethod
@ -97,14 +97,14 @@ class AppConfig:
"main_icon": cls.SYSTEM_PATHS["image_path"] / "48/wg_vpn.png", "main_icon": cls.SYSTEM_PATHS["image_path"] / "48/wg_vpn.png",
"warning": cls.CONFIG_DIR / "images/warning.png", "warning": cls.CONFIG_DIR / "images/warning.png",
"success": cls.CONFIG_DIR / "images/success.png", "success": cls.CONFIG_DIR / "images/success.png",
"error": cls.CONFIG_DIR / "images/error.png" "error": cls.CONFIG_DIR / "images/error.png",
} }
@classmethod @classmethod
def get_autostart_content(cls) -> str: def get_autostart_content(cls) -> str:
"""Returns the content for the autostart service file""" """Returns the content for the autostart service file"""
return """[Unit]
Description=Automatic Tunnel Start return """[Unit]Description=Automatic Tunnel Start
After=network-online.target After=network-online.target
[Service] [Service]
@ -114,9 +114,11 @@ ExecStart=/usr/local/bin/start_wg.py
[Install] [Install]
WantedBy=default.target""" WantedBy=default.target"""
# here is inizialize the class for translate strrings # here is inizialize the class for translate strrings
_ = AppConfig.setup_translations() _ = AppConfig.setup_translations()
class Msg: class Msg:
""" """
A utility class that provides centralized access to translated message strings. A utility class that provides centralized access to translated message strings.
@ -137,6 +139,7 @@ class Msg:
Ensure that gettext translation is properly initialized before Ensure that gettext translation is properly initialized before
accessing these strings to ensure correct localization. accessing these strings to ensure correct localization.
""" """
STR: Dict[str, str] = { STR: Dict[str, str] = {
# Strings for messages # Strings for messages
"sel_tl": _("Select tunnel"), "sel_tl": _("Select tunnel"),
@ -150,31 +153,38 @@ class Msg:
"sel_list": _("Please select a tunnel from the list"), "sel_list": _("Please select a tunnel from the list"),
"sign_len": _("The new name may contain only 12 characters"), "sign_len": _("The new name may contain only 12 characters"),
"zero_signs": _("At least one character must be entered"), "zero_signs": _("At least one character must be entered"),
"false signs": _("No valid sign. These must not be used.\nBlank, Slash, Backslash and { }\n"), "false signs": _(
"No valid sign. These must not be used.\nBlank, Slash, Backslash and { }\n"
),
"is_in_use": _("The tunnel is already in use"), "is_in_use": _("The tunnel is already in use"),
"no_valid_file": _("Oh... no valid Wireguard File!\nPlease select a valid Wireguard File"), "no_valid_file": _(
"tl_exist": _("Tunnel already available!\nPlease use another file for import") "Oh... no valid Wireguard File!\nPlease select a valid Wireguard File"
),
"tl_exist": _("Tunnel already available!\nPlease use another file for import"),
} }
TTIP: Dict[str, str] = { TTIP: Dict[str, str] = {
#Strings for Tooltips # Strings for Tooltips
"settings": _("Click for Settings"), "settings": _("Click for Settings"),
"import_tl": _("Click to import a Wireguard Tunnel"), "import_tl": _("Click to import a Wireguard Tunnel"),
"start_tl": _("Click to start selected Wireguard Tunnel"), "start_tl": _("Click to start selected Wireguard Tunnel"),
"empty_list": _("No tunnels to start in the list"), "empty_list": _("No tunnels to start in the list"),
"stop_tl": _("Click to stop selected Wireguard Tunnel"), "stop_tl": _("Click to stop selected Wireguard Tunnel"),
"del_tl": _("Click to delete selected Wireguard Tunnel"), "del_tl": _("Click to delete selected Wireguard Tunnel"),
"rename_tl": _("To rename a tunnel, you need to\nselect a tunnel from the list"), "rename_tl": _(
"To rename a tunnel, you need to\nselect a tunnel from the list"
),
"export_tl": _(" Click to export all\nWireguard Tunnel to Zipfile"), "export_tl": _(" Click to export all\nWireguard Tunnel to Zipfile"),
"trash_tl": _("Click to delete a Wireguard Tunnel\nSelect from the list!"), "trash_tl": _("Click to delete a Wireguard Tunnel\nSelect from the list!"),
"autostart": _("To use the autostart, enable this Checkbox"), "autostart": _("To use the autostart, enable this Checkbox"),
"autostart_info": _("You must have at least one\ntunnel in the list,to use the autostart"), "autostart_info": _(
"You must have at least one\ntunnel in the list,to use the autostart"
),
"export_tl_info": _("No Tunnels in List for Export"), "export_tl_info": _("No Tunnels in List for Export"),
"start_tl_info": _("Click to start selected Wireguard Tunnel"), "start_tl_info": _("Click to start selected Wireguard Tunnel"),
"rename_tl_info": _("To rename a tunnel, at least one must be in the list"), "rename_tl_info": _("To rename a tunnel, at least one must be in the list"),
"trash_tl_info": _("No tunnels to delete in the list"), "trash_tl_info": _("No tunnels to delete in the list"),
"list_auto_info": _("To use the autostart, a tunnel must be selected from the list"), "list_auto_info": _(
"download": _("Click to download new version") "To use the autostart, a tunnel must be selected from the list"
),
"download": _("Click to download new version"),
} }