fix message window a path errors
This commit is contained in:
parent
c56b42df3e
commit
f4a51f0050
302
common_tools.py
302
common_tools.py
@ -1,7 +1,5 @@
|
||||
""" Classes Method and Functions for lx Apps """
|
||||
|
||||
import gettext
|
||||
import locale
|
||||
import os
|
||||
import shutil
|
||||
import signal
|
||||
@ -20,6 +18,7 @@ import requests
|
||||
# Translate
|
||||
_ = AppConfig.setup_translations()
|
||||
|
||||
|
||||
class Create:
|
||||
"""
|
||||
This class is for the creation of the folders and files
|
||||
@ -43,7 +42,9 @@ class Create:
|
||||
|
||||
else:
|
||||
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():
|
||||
pass
|
||||
@ -66,9 +67,11 @@ class Create:
|
||||
|
||||
else:
|
||||
wg_ser.touch()
|
||||
wg_ser.write_text("[Unit]\nDescription=Automatic Tunnel Start\nAfter=network-online.target\n\n[Service]\n"
|
||||
"Type=oneshot\nExecStartPre=/bin/sleep 5\nExecStart=/usr/local/bin/start_wg.py\n[Install]"
|
||||
"\nWantedBy=default.target")
|
||||
wg_ser.write_text(
|
||||
"[Unit]\nDescription=Automatic Tunnel Start\nAfter=network-online.target\n\n[Service]\n"
|
||||
"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"])
|
||||
|
||||
@staticmethod
|
||||
@ -85,8 +88,12 @@ class Create:
|
||||
"""
|
||||
Starts SSL dencrypt
|
||||
"""
|
||||
process: CompletedProcess[str] = subprocess.run(["pkexec", "/usr/local/bin/ssl_decrypt.py"],
|
||||
stdout=subprocess.PIPE, text=True, check=True)
|
||||
process: CompletedProcess[str] = subprocess.run(
|
||||
["pkexec", "/usr/local/bin/ssl_decrypt.py"],
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
path: Path = Path.home() / ".config/wire_py/"
|
||||
file_in_path: list[Path] = list(path.rglob("*.dat"))
|
||||
if file_in_path:
|
||||
@ -102,8 +109,12 @@ class Create:
|
||||
"""
|
||||
Starts SSL encryption
|
||||
"""
|
||||
process: CompletedProcess[str] = subprocess.run(["pkexec", "/usr/local/bin/ssl_encrypt.py"],
|
||||
stdout=subprocess.PIPE, text=True, check=True)
|
||||
process: CompletedProcess[str] = subprocess.run(
|
||||
["pkexec", "/usr/local/bin/ssl_encrypt.py"],
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
print(process.stdout)
|
||||
if process.returncode == 0:
|
||||
print("All Files successfully encrypted...")
|
||||
@ -123,40 +134,44 @@ class LxTools(tk.Tk):
|
||||
def center_window_cross_platform(window, width, height):
|
||||
"""
|
||||
Centers a window on the primary monitor in a way that works on both X11 and Wayland
|
||||
|
||||
|
||||
Args:
|
||||
window: The tkinter window to center
|
||||
width: Window width
|
||||
height: Window height
|
||||
"""
|
||||
# Calculate the position before showing the window
|
||||
|
||||
|
||||
# First attempt: Try to use GDK if available (works on both X11 and Wayland)
|
||||
try:
|
||||
import gi
|
||||
gi.require_version('Gdk', '3.0')
|
||||
|
||||
gi.require_version("Gdk", "3.0")
|
||||
from gi.repository import Gdk
|
||||
|
||||
|
||||
display = Gdk.Display.get_default()
|
||||
monitor = display.get_primary_monitor() or display.get_monitor(0)
|
||||
geometry = monitor.get_geometry()
|
||||
scale_factor = monitor.get_scale_factor()
|
||||
|
||||
|
||||
# Calculate center position on primary monitor
|
||||
x = geometry.x + (geometry.width - width // scale_factor) // 2
|
||||
y = geometry.y + (geometry.height - height // scale_factor) // 2
|
||||
|
||||
|
||||
# Set window geometry
|
||||
window.geometry(f"{width}x{height}+{x}+{y}")
|
||||
return
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
|
||||
|
||||
# Second attempt: Try xrandr for X11
|
||||
try:
|
||||
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
|
||||
primary_info = None
|
||||
for line in output.splitlines():
|
||||
@ -167,7 +182,7 @@ class LxTools(tk.Tk):
|
||||
primary_info = part
|
||||
break
|
||||
break
|
||||
|
||||
|
||||
if primary_info:
|
||||
# Parse the geometry: WIDTHxHEIGHT+X+Y
|
||||
geometry = primary_info.split("+")
|
||||
@ -176,32 +191,33 @@ class LxTools(tk.Tk):
|
||||
primary_height = int(dimensions[1])
|
||||
primary_x = int(geometry[1])
|
||||
primary_y = int(geometry[2])
|
||||
|
||||
|
||||
# Calculate center position on primary monitor
|
||||
x = primary_x + (primary_width - width) // 2
|
||||
y = primary_y + (primary_height - height) // 2
|
||||
|
||||
|
||||
# Set window geometry
|
||||
window.geometry(f"{width}x{height}+{x}+{y}")
|
||||
return
|
||||
except (subprocess.SubprocessError, ImportError, IndexError, ValueError):
|
||||
pass
|
||||
|
||||
|
||||
# Final fallback: Use standard Tkinter method
|
||||
screen_width = window.winfo_screenwidth()
|
||||
screen_height = window.winfo_screenheight()
|
||||
|
||||
|
||||
# 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 > 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
|
||||
screen_width = screen_width // 2
|
||||
|
||||
|
||||
x = (screen_width - width) // 2
|
||||
y = (screen_height - height) // 2
|
||||
window.geometry(f"{width}x{height}+{x}+{y}")
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_file_name(path: Path, i: int = 5) -> List[str]:
|
||||
"""
|
||||
@ -253,8 +269,14 @@ class LxTools(tk.Tk):
|
||||
Path.unlink(file)
|
||||
|
||||
@staticmethod
|
||||
def msg_window(image_path: Path, image_path2: Path, w_title: str, w_txt: str, txt2: Optional[str] = None,
|
||||
com: Optional[str] = None) -> None:
|
||||
def msg_window(
|
||||
image_path: Path,
|
||||
image_path2: Path,
|
||||
w_title: str,
|
||||
w_txt: str,
|
||||
txt2: Optional[str] = None,
|
||||
com: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates message windows
|
||||
|
||||
@ -269,29 +291,44 @@ class LxTools(tk.Tk):
|
||||
msg.resizable(width=False, height=False)
|
||||
msg.title(w_title)
|
||||
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.grid(column=1, row=0)
|
||||
|
||||
if txt2 is not None and com is not None:
|
||||
label.config(font=("Ubuntu", 11), padx=15, justify="left")
|
||||
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)
|
||||
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)
|
||||
|
||||
else:
|
||||
label.config(font=("Ubuntu", 11), padx=15)
|
||||
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)
|
||||
|
||||
AppConfig.IMAGE_PATHS["icon_vpn"]: tk.PhotoImage = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_vpn"])
|
||||
msg.iconphoto(True, AppConfig.IMAGE_PATHS["icon_vpn"])
|
||||
# Lade das Icon für das Fenster
|
||||
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.rowconfigure(0, weight=1)
|
||||
msg.winfo_toplevel()
|
||||
@ -317,15 +354,22 @@ class LxTools(tk.Tk):
|
||||
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)
|
||||
if n.startswith("SIG") and "_" not in n)
|
||||
signals_to_names_dict: Dict[int, str] = dict(
|
||||
(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
|
||||
if signum in (signal.SIGINT, signal.SIGTERM):
|
||||
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)
|
||||
print("Breakdown by user...")
|
||||
sys.exit(exit_code)
|
||||
@ -343,7 +387,8 @@ class LxTools(tk.Tk):
|
||||
class Tunnel:
|
||||
"""
|
||||
Class of Methods for Wire-Py
|
||||
"""
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def con_to_dict(cls, file: TextIO) -> Tuple[str, str, str, Optional[str]]:
|
||||
"""
|
||||
@ -394,7 +439,11 @@ class 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:
|
||||
active = ""
|
||||
else:
|
||||
@ -413,8 +462,14 @@ class Tunnel:
|
||||
return wg_s
|
||||
|
||||
@staticmethod
|
||||
def export(image_path: Path = None, image_path2: Path = None, image_path3: Path = None, image_path4: Path = None,
|
||||
title: Dict = None, window_msg: Dict = None) -> None:
|
||||
def export(
|
||||
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.
|
||||
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:
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
pass
|
||||
@ -459,15 +529,16 @@ class ConfigManager:
|
||||
Universal class for managing configuration files with caching.
|
||||
Can be reused in different projects.
|
||||
"""
|
||||
|
||||
_config = None
|
||||
_config_file = None
|
||||
|
||||
|
||||
@classmethod
|
||||
def init(cls, config_file):
|
||||
"""Initial the Configmanager with the given config file"""
|
||||
cls._config_file = config_file
|
||||
cls._config = None # Reset the cache
|
||||
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
"""Load the config file and return the config as dict"""
|
||||
@ -475,44 +546,45 @@ class ConfigManager:
|
||||
try:
|
||||
lines = Path(cls._config_file).read_text(encoding="utf-8").splitlines()
|
||||
cls._config = {
|
||||
'updates': lines[1].strip(),
|
||||
'theme': lines[3].strip(),
|
||||
'tooltips': lines[5].strip() == "True", # is converted here to boolean!!!
|
||||
'autostart': lines[7].strip() if len(lines) > 7 else 'off'
|
||||
"updates": lines[1].strip(),
|
||||
"theme": lines[3].strip(),
|
||||
"tooltips": lines[5].strip()
|
||||
== "True", # is converted here to boolean!!!
|
||||
"autostart": lines[7].strip() if len(lines) > 7 else "off",
|
||||
}
|
||||
except (IndexError, FileNotFoundError):
|
||||
# DeDefault values in case of error
|
||||
cls._config = {
|
||||
'updates': 'on',
|
||||
'theme': 'light',
|
||||
'tooltips': "True", # Default Value as string !
|
||||
'autostart': 'off'
|
||||
"updates": "on",
|
||||
"theme": "light",
|
||||
"tooltips": "True", # Default Value as string !
|
||||
"autostart": "off",
|
||||
}
|
||||
return cls._config
|
||||
|
||||
|
||||
@classmethod
|
||||
def save(cls):
|
||||
"""Save the config to the config file"""
|
||||
if cls._config:
|
||||
lines = [
|
||||
'# Configuration\n',
|
||||
"# Configuration\n",
|
||||
f"{cls._config['updates']}\n",
|
||||
'# Theme\n',
|
||||
"# Theme\n",
|
||||
f"{cls._config['theme']}\n",
|
||||
'# Tooltips\n',
|
||||
"# Tooltips\n",
|
||||
f"{str(cls._config['tooltips'])}\n",
|
||||
'# Autostart\n',
|
||||
f"{cls._config['autostart']}\n"
|
||||
"# 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
|
||||
def set(cls, key, value):
|
||||
"""Sets a configuration value and saves the change"""
|
||||
cls.load()
|
||||
cls._config[key] = value
|
||||
cls.save()
|
||||
|
||||
|
||||
@classmethod
|
||||
def get(cls, key, default=None):
|
||||
"""Returns a configuration value"""
|
||||
@ -545,42 +617,48 @@ class GiteaUpdate:
|
||||
update_api_url: Update API URL
|
||||
version: Current version
|
||||
update_setting: Update setting from ConfigManager (on/off)
|
||||
|
||||
|
||||
Returns:
|
||||
New version or status message
|
||||
"""
|
||||
# If updates are disabled, return immediately
|
||||
if update_setting != "on":
|
||||
return "False"
|
||||
|
||||
|
||||
try:
|
||||
response: requests.Response = requests.get(update_api_url, timeout=10)
|
||||
response.raise_for_status() # Raise exception for HTTP errors
|
||||
|
||||
|
||||
response_data = response.json()
|
||||
if not response_data:
|
||||
return "No Updates"
|
||||
|
||||
|
||||
latest_version = response_data[0].get("tag_name")
|
||||
if not latest_version:
|
||||
return "Invalid API Response"
|
||||
|
||||
|
||||
# Compare versions (strip 'v. ' prefix if present)
|
||||
current_version = version[3:] if version.startswith("v. ") else version
|
||||
|
||||
|
||||
if current_version != latest_version:
|
||||
return latest_version
|
||||
else:
|
||||
return "No Updates"
|
||||
|
||||
|
||||
except requests.exceptions.RequestException:
|
||||
return "No Internet Connection!"
|
||||
except (ValueError, KeyError, IndexError):
|
||||
return "Invalid API Response"
|
||||
|
||||
@staticmethod
|
||||
def download(urld: str, res: str, image_path: Path = None, image_path2: Path = None, image_path3: Path = None,
|
||||
image_path4: Path = None) -> None:
|
||||
def download(
|
||||
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
|
||||
|
||||
@ -600,35 +678,57 @@ class GiteaUpdate:
|
||||
|
||||
wt: str = _("Download Successful")
|
||||
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:
|
||||
|
||||
wt: str = _("Download error")
|
||||
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:
|
||||
|
||||
wt: str = _("Download error")
|
||||
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
|
||||
from common_tools.py import Tooltip
|
||||
example: Tooltip(label, "Show tooltip on label")
|
||||
example: Tooltip(button, "Show tooltip on button")
|
||||
example: Tooltip(widget, "Text", state_var=tk.BooleanVar())
|
||||
example: Tooltip(widget, "Text", state_var=tk.BooleanVar(), x_offset=20, y_offset=10)
|
||||
|
||||
|
||||
info: label and button are parent widgets.
|
||||
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()
|
||||
"""
|
||||
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"""
|
||||
self.widget: Any = widget
|
||||
self.text: str = text
|
||||
@ -636,55 +736,59 @@ class Tooltip():
|
||||
self.state_var = state_var
|
||||
self.x_offset = x_offset
|
||||
self.y_offset = y_offset
|
||||
|
||||
|
||||
# Initial binding based on current state
|
||||
self.update_bindings()
|
||||
|
||||
|
||||
# Add trace to the state_var if provided
|
||||
if self.state_var is not None:
|
||||
self.state_var.trace_add("write", self.update_bindings)
|
||||
|
||||
|
||||
def update_bindings(self, *args) -> None:
|
||||
"""Updates the bindings based on the current state"""
|
||||
# Remove existing bindings first
|
||||
self.widget.unbind("<Enter>")
|
||||
self.widget.unbind("<Leave>")
|
||||
|
||||
|
||||
# Add new bindings if tooltips are enabled
|
||||
if self.state_var is None or self.state_var.get():
|
||||
self.widget.bind("<Enter>", self.show_tooltip)
|
||||
self.widget.bind("<Leave>", self.hide_tooltip)
|
||||
|
||||
|
||||
def show_tooltip(self, event: Optional[Any] = None) -> None:
|
||||
"""Shows the tooltip"""
|
||||
if self.tooltip_window or not self.text:
|
||||
return
|
||||
|
||||
|
||||
x: int
|
||||
y: int
|
||||
cx: int
|
||||
cy: int
|
||||
|
||||
|
||||
x, y, cx, cy = self.widget.bbox("insert")
|
||||
x += self.widget.winfo_rootx() + self.x_offset
|
||||
y += self.widget.winfo_rooty() + self.y_offset
|
||||
|
||||
|
||||
self.tooltip_window = tw = tk.Toplevel(self.widget)
|
||||
tw.wm_overrideredirect(True)
|
||||
tw.wm_geometry(f"+{x}+{y}")
|
||||
|
||||
|
||||
label: tk.Label = tk.Label(
|
||||
tw, text=self.text, background="lightgreen", foreground="black",
|
||||
relief="solid", borderwidth=1, padx=5, pady=5
|
||||
tw,
|
||||
text=self.text,
|
||||
background="lightgreen",
|
||||
foreground="black",
|
||||
relief="solid",
|
||||
borderwidth=1,
|
||||
padx=5,
|
||||
pady=5,
|
||||
)
|
||||
label.grid()
|
||||
|
||||
|
||||
self.tooltip_window.after(2200, lambda: tw.destroy())
|
||||
|
||||
|
||||
def hide_tooltip(self, event: Optional[Any] = None) -> None:
|
||||
"""Hides the tooltip"""
|
||||
if self.tooltip_window:
|
||||
self.tooltip_window.destroy()
|
||||
self.tooltip_window = None
|
||||
|
||||
|
@ -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()
|
||||
|
@ -12,11 +12,24 @@ uname: Path = Path("/tmp/.log_user")
|
||||
log_name = Path(uname).read_text(encoding="utf-8")
|
||||
|
||||
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():
|
||||
|
||||
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)
|
||||
|
||||
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:
|
||||
tlname2 = f"{detunnels[:-4]}.conf"
|
||||
extpath = f"{AppConfig.TEMP_DIR}/{tlname2}"
|
||||
check_call(["openssl", "pkeyutl", "-decrypt", "-inkey", AppConfig.SYSTEM_PATHS["pkey_path"], "-in", detunnels,
|
||||
"-out", extpath])
|
||||
check_call(
|
||||
[
|
||||
"openssl",
|
||||
"pkeyutl",
|
||||
"-decrypt",
|
||||
"-inkey",
|
||||
AppConfig.SYSTEM_PATHS["pkey_path"],
|
||||
"-in",
|
||||
detunnels,
|
||||
"-out",
|
||||
extpath,
|
||||
]
|
||||
)
|
||||
shutil.chown(extpath, 1000, 1000)
|
||||
|
@ -8,15 +8,26 @@ from subprocess import check_call
|
||||
from common_tools import LxTools
|
||||
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():
|
||||
|
||||
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)
|
||||
|
||||
if AppConfig.TEMP_DIR.exists():
|
||||
@ -28,8 +39,20 @@ if not keyfile.is_file():
|
||||
for tunnels in tl:
|
||||
sourcetl: str = f"{AppConfig.TEMP_DIR}/{tunnels}"
|
||||
tlname: str = f"{CRYPTFILES}{tunnels[:-5]}.dat"
|
||||
check_call(["openssl", "pkeyutl", "-encrypt", "-inkey", keyfile, "-pubin", "-in", sourcetl, "-out",
|
||||
tlname,])
|
||||
check_call(
|
||||
[
|
||||
"openssl",
|
||||
"pkeyutl",
|
||||
"-encrypt",
|
||||
"-inkey",
|
||||
keyfile,
|
||||
"-pubin",
|
||||
"-in",
|
||||
sourcetl,
|
||||
"-out",
|
||||
tlname,
|
||||
]
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
@ -42,5 +65,17 @@ else:
|
||||
for tunnels in tl:
|
||||
sourcetl: str = f"{AppConfig.TEMP_DIR}/{tunnels}"
|
||||
tlname: str = f"{CRYPTFILES}{tunnels[:-5]}.dat"
|
||||
check_call(["openssl", "pkeyutl", "-encrypt", "-inkey", keyfile, "-pubin", "-in", sourcetl, "-out",
|
||||
tlname])
|
||||
check_call(
|
||||
[
|
||||
"openssl",
|
||||
"pkeyutl",
|
||||
"-encrypt",
|
||||
"-inkey",
|
||||
keyfile,
|
||||
"-pubin",
|
||||
"-in",
|
||||
sourcetl,
|
||||
"-out",
|
||||
tlname,
|
||||
]
|
||||
)
|
||||
|
@ -1,7 +1,8 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
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 subprocess import check_call
|
||||
|
||||
|
536
wirepy.py
536
wirepy.py
@ -2,8 +2,6 @@
|
||||
"""
|
||||
this script is a simple GUI for managing Wireguard Tunnels
|
||||
"""
|
||||
import gettext
|
||||
import locale
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
@ -14,7 +12,15 @@ from pathlib import Path
|
||||
from subprocess import check_call
|
||||
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
|
||||
|
||||
LxTools.uos()
|
||||
@ -22,26 +28,30 @@ Create.dir_and_files()
|
||||
Create.make_dir()
|
||||
Create.decrypt()
|
||||
|
||||
|
||||
class Wirepy(tk.Tk):
|
||||
"""
|
||||
Class Wirepy this is the Main Window of wirepy
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Hide the window initially
|
||||
self.withdraw()
|
||||
|
||||
|
||||
self.my_tool_tip = None
|
||||
self.x_width = AppConfig.UI_CONFIG["window_size"][0]
|
||||
self.y_height = AppConfig.UI_CONFIG["window_size"][1]
|
||||
|
||||
|
||||
# Set the window size
|
||||
self.geometry(f"{self.x_width}x{self.y_height}")
|
||||
self.resizable(AppConfig.UI_CONFIG["resizable_window"][0],
|
||||
AppConfig.UI_CONFIG["resizable_window"][1])
|
||||
self.resizable(
|
||||
AppConfig.UI_CONFIG["resizable_window"][0],
|
||||
AppConfig.UI_CONFIG["resizable_window"][1],
|
||||
)
|
||||
self.title(AppConfig.UI_CONFIG["window_title"])
|
||||
|
||||
|
||||
self.columnconfigure(0, weight=1)
|
||||
self.rowconfigure(0, weight=1)
|
||||
self.tk.call("source", f"{AppConfig.SYSTEM_PATHS['tcl_path']}/water.tcl")
|
||||
@ -57,10 +67,10 @@ class Wirepy(tk.Tk):
|
||||
|
||||
# Add the widgets
|
||||
FrameWidgets(self).grid()
|
||||
|
||||
|
||||
# Center the window on the primary monitor
|
||||
LxTools.center_window_cross_platform(self, self.x_width, self.y_height)
|
||||
|
||||
|
||||
# Now show the window after it has been positioned
|
||||
self.after(10, self.deiconify)
|
||||
|
||||
@ -69,9 +79,10 @@ class FrameWidgets(ttk.Frame):
|
||||
"""
|
||||
ttk frame class for better structure
|
||||
"""
|
||||
|
||||
def __init__(self, container, **kwargs):
|
||||
super().__init__(container, **kwargs)
|
||||
|
||||
|
||||
self.lb_tunnel = None
|
||||
self.btn_stst = None
|
||||
self.endpoint = None
|
||||
@ -100,13 +111,16 @@ class FrameWidgets(ttk.Frame):
|
||||
else:
|
||||
# If it's a string or something else
|
||||
self.tooltip_state.set(str(state) == "True")
|
||||
|
||||
self.tooltip_label = tk.StringVar() # StringVar-Variable for tooltip label for view Disabled/Enabled
|
||||
self.tooltip_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_foreground = tk.StringVar(value="red")
|
||||
|
||||
self.tooltip_label = (
|
||||
tk.StringVar()
|
||||
) # StringVar-Variable for tooltip label for view Disabled/Enabled
|
||||
self.tooltip_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_foreground = tk.StringVar(value="red")
|
||||
|
||||
# Frame for Menu
|
||||
self.menu_frame = ttk.Frame(self)
|
||||
@ -118,7 +132,9 @@ class FrameWidgets(ttk.Frame):
|
||||
self.version_lb.config(font=("Ubuntu", 11), foreground="#00c4ff")
|
||||
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.grid(column=1, columnspan=1, row=0)
|
||||
@ -128,27 +144,37 @@ class FrameWidgets(ttk.Frame):
|
||||
self.set_update = tk.IntVar()
|
||||
self.settings = tk.Menu(self, relief="flat")
|
||||
self.options_btn.configure(menu=self.settings, style="Toolbutton")
|
||||
self.settings.add_checkbutton(label=_("Disable Updates"),
|
||||
command=lambda: self.update_setting(self.set_update.get()), variable=self.set_update)
|
||||
self.settings.add_checkbutton(
|
||||
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.grid(column=4, columnspan=3, row=0, padx=10)
|
||||
self.updates_lb.grid_remove()
|
||||
self.update_label.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)
|
||||
|
||||
# Tooltip Menu
|
||||
self.settings.add_command(label=self.tooltip_label.get(), command=self.tooltips_toggle)
|
||||
# Label show dark or light
|
||||
self.settings.add_command(
|
||||
label=self.tooltip_label.get(), command=self.tooltips_toggle
|
||||
)
|
||||
# Label show dark or light
|
||||
self.theme_label = tk.StringVar()
|
||||
self.update_theme_label()
|
||||
self.settings.add_command(label=self.theme_label.get(), command=self.on_theme_toggle)
|
||||
self.update_theme_label()
|
||||
self.settings.add_command(
|
||||
label=self.theme_label.get(), command=self.on_theme_toggle
|
||||
)
|
||||
|
||||
# About BTN Menu / Label
|
||||
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.readme = tk.Menu(self)
|
||||
|
||||
@ -172,7 +198,9 @@ class FrameWidgets(ttk.Frame):
|
||||
# Bottom Frame 4
|
||||
self.lb_frame3 = ttk.Frame(self)
|
||||
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
|
||||
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.event_add("<<ClickEvent>>", "<Button-1>")
|
||||
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.l_box.configure(yscrollcommand=self.scrollbar.set)
|
||||
|
||||
@ -230,14 +260,24 @@ class FrameWidgets(ttk.Frame):
|
||||
self.show_data()
|
||||
|
||||
# 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)
|
||||
|
||||
Tooltip(self.btn_i, Msg.TTIP["import_tl"], self.tooltip_state)
|
||||
|
||||
# Button Trash
|
||||
self.btn_tr = ttk.Button(self.lb_frame_btn_lbox, image=self.tr_pic, command=self.delete, padding=0,
|
||||
style="CButton.TButton")
|
||||
self.btn_tr = ttk.Button(
|
||||
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)
|
||||
|
||||
if self.l_box.size() == 0:
|
||||
@ -246,12 +286,20 @@ class FrameWidgets(ttk.Frame):
|
||||
Tooltip(self.btn_tr, Msg.TTIP["trash_tl"], self.tooltip_state)
|
||||
|
||||
# Button Export
|
||||
self.btn_exp = ttk.Button(self.lb_frame_btn_lbox, image=self.exp_pic,
|
||||
command=lambda: Tunnel.export(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 = ttk.Button(
|
||||
self.lb_frame_btn_lbox,
|
||||
image=self.exp_pic,
|
||||
command=lambda: Tunnel.export(
|
||||
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)
|
||||
|
||||
if self.l_box.size() == 0:
|
||||
@ -266,13 +314,31 @@ class FrameWidgets(ttk.Frame):
|
||||
self.lb_rename.config(state="disable")
|
||||
|
||||
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:
|
||||
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
|
||||
self.btn_rename = ttk.Button(self.lb_frame4, text=_("Rename"), state="disable", command=self.tl_rename,
|
||||
padding=4, style="RnButton.TButton")
|
||||
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
|
||||
@ -281,22 +347,46 @@ class FrameWidgets(ttk.Frame):
|
||||
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 = 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 = 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, 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:
|
||||
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:
|
||||
|
||||
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()
|
||||
|
||||
@ -316,10 +406,10 @@ class FrameWidgets(ttk.Frame):
|
||||
def update_ui_for_update(self, res):
|
||||
"""Update UI elements based on update check result"""
|
||||
# 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()
|
||||
delattr(self, 'update_btn')
|
||||
|
||||
delattr(self, "update_btn")
|
||||
|
||||
if res == "False":
|
||||
self.set_update.set(value=1)
|
||||
self.update_label.set(_("Update search off"))
|
||||
@ -328,44 +418,50 @@ class FrameWidgets(ttk.Frame):
|
||||
self.update_foreground.set("")
|
||||
# Set tooltip for the label
|
||||
Tooltip(self.updates_lb, self.update_tooltip.get(), self.tooltip_state)
|
||||
|
||||
|
||||
elif res == "No Internet Connection!":
|
||||
self.update_label.set(_("No Server Connection!"))
|
||||
self.update_foreground.set("red")
|
||||
# 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":
|
||||
self.update_label.set(_("No Updates"))
|
||||
self.update_tooltip.set(_("Congratulations! Wire-Py is up to date"))
|
||||
self.update_foreground.set("")
|
||||
# Set tooltip for the label
|
||||
Tooltip(self.updates_lb, self.update_tooltip.get(), self.tooltip_state)
|
||||
|
||||
|
||||
else:
|
||||
self.set_update.set(value=0)
|
||||
update_text = f"Update {res} {_('available!')}"
|
||||
|
||||
# Clear the label text since we'll show the button instead
|
||||
self.update_label.set("")
|
||||
|
||||
|
||||
# Create the update button
|
||||
self.update_btn = ttk.Menubutton(self.menu_frame, text=update_text)
|
||||
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.update_btn.configure(menu=self.download, style="Toolbutton")
|
||||
self.download.add_command(
|
||||
label=_("Download"),
|
||||
command=lambda: GiteaUpdate.download(
|
||||
f"{AppConfig.DOWNLOAD_URL}/{res}.zip",
|
||||
res,
|
||||
res,
|
||||
AppConfig.IMAGE_PATHS["icon_info"],
|
||||
AppConfig.IMAGE_PATHS["icon_vpn"],
|
||||
AppConfig.IMAGE_PATHS["icon_error"],
|
||||
AppConfig.IMAGE_PATHS["icon_msg"]
|
||||
)
|
||||
AppConfig.IMAGE_PATHS["icon_msg"],
|
||||
),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@ -373,15 +469,26 @@ class FrameWidgets(ttk.Frame):
|
||||
"""
|
||||
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")
|
||||
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(
|
||||
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:
|
||||
"""write off or on in file
|
||||
Args:
|
||||
@ -398,14 +505,16 @@ class FrameWidgets(ttk.Frame):
|
||||
# When enabling updates, we need to actually check for updates
|
||||
try:
|
||||
# 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
|
||||
if hasattr(self, 'update_btn'):
|
||||
if hasattr(self, "update_btn"):
|
||||
self.update_btn.grid_forget()
|
||||
if hasattr(self, 'updates_lb'):
|
||||
if hasattr(self, "updates_lb"):
|
||||
self.updates_lb.grid_forget()
|
||||
|
||||
|
||||
# Now update the UI with the fresh result
|
||||
self.update_ui_for_update(res)
|
||||
except Exception as e:
|
||||
@ -431,10 +540,10 @@ class FrameWidgets(ttk.Frame):
|
||||
ConfigManager.set("tooltips", str(new_bool_state))
|
||||
# Update the tooltip_state variable for immediate effect
|
||||
self.tooltip_state.set(new_bool_state)
|
||||
|
||||
|
||||
# Update the menu label
|
||||
self.tooltip_update_label()
|
||||
|
||||
|
||||
# Update the menu entry - find the correct index
|
||||
# This assumes it's the third item (index 2) in your menu
|
||||
self.settings.entryconfigure(1, label=self.tooltip_label.get())
|
||||
@ -461,8 +570,12 @@ class FrameWidgets(ttk.Frame):
|
||||
"""
|
||||
Start Button
|
||||
"""
|
||||
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 = 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)
|
||||
|
||||
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
|
||||
"""
|
||||
if ConfigManager.get("theme") == "light":
|
||||
|
||||
self.lb_tunnel = ttk.Label(self, textvariable=self.str_var, foreground="green")
|
||||
if ConfigManager.get("theme") == "light":
|
||||
|
||||
self.lb_tunnel = ttk.Label(
|
||||
self, textvariable=self.str_var, foreground="green"
|
||||
)
|
||||
|
||||
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.grid(column=2, padx=10, row=1)
|
||||
@ -505,8 +622,12 @@ class FrameWidgets(ttk.Frame):
|
||||
"""
|
||||
Stop Button
|
||||
"""
|
||||
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 = 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)
|
||||
|
||||
Tooltip(self.btn_stst, Msg.TTIP["stop_tl"], self.tooltip_state)
|
||||
@ -525,58 +646,91 @@ class FrameWidgets(ttk.Frame):
|
||||
Create.dir_and_files()
|
||||
try:
|
||||
filepath = filedialog.askopenfilename(
|
||||
initialdir=f"{Path.home()}",
|
||||
initialdir=f"{Path.home()}",
|
||||
title=_("Select Wireguard config File"),
|
||||
filetypes=[(_("WG config files"), "*.conf")]
|
||||
filetypes=[(_("WG config files"), "*.conf")],
|
||||
)
|
||||
|
||||
|
||||
# Überprüfe, ob der Benutzer den Dialog abgebrochen hat
|
||||
if not filepath:
|
||||
print("File import: abort by user...")
|
||||
return
|
||||
|
||||
|
||||
with open(filepath, "r", encoding="utf-8") as file:
|
||||
read = file.read()
|
||||
|
||||
|
||||
path_split = filepath.split("/")
|
||||
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:
|
||||
key = Tunnel.con_to_dict(file)
|
||||
pre_key = key[3]
|
||||
|
||||
|
||||
if len(pre_key) != 0:
|
||||
p_key = AppConfig.KEYS_FILE.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
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:
|
||||
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")
|
||||
|
||||
|
||||
if len(path_split1) > 17:
|
||||
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}")
|
||||
new_conf = f"{AppConfig.TEMP_DIR}/{path_split}"
|
||||
|
||||
|
||||
if self.a != "":
|
||||
check_call(["nmcli", "connection", "down", self.a])
|
||||
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()
|
||||
else:
|
||||
shutil.copy(filepath, f"{AppConfig.TEMP_DIR}/")
|
||||
|
||||
|
||||
if self.a != "":
|
||||
check_call(["nmcli", "connection", "down", self.a])
|
||||
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()
|
||||
|
||||
|
||||
self.str_var.set("")
|
||||
self.a = Tunnel.active()
|
||||
self.l_box.insert(0, self.a)
|
||||
@ -584,23 +738,45 @@ class FrameWidgets(ttk.Frame):
|
||||
self.l_box.selection_clear(0, tk.END)
|
||||
self.l_box.update()
|
||||
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_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.str_var = tk.StringVar()
|
||||
self.str_var.set(self.a)
|
||||
self.color_label()
|
||||
self.stop()
|
||||
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):
|
||||
pass
|
||||
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:
|
||||
print(e)
|
||||
@ -618,15 +794,16 @@ class FrameWidgets(ttk.Frame):
|
||||
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:
|
||||
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()):
|
||||
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)
|
||||
@ -637,7 +814,9 @@ class FrameWidgets(ttk.Frame):
|
||||
Path.unlink(f"{Path.home()}/.config/wire_py/{select_tl}.dat")
|
||||
Path.unlink(f"/tmp/tlecdcwg/{select_tl}.conf")
|
||||
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:
|
||||
if pre_key not in line.strip("\n"):
|
||||
writefile.write(line)
|
||||
@ -650,8 +829,13 @@ class FrameWidgets(ttk.Frame):
|
||||
if self.l_box.size() == 0:
|
||||
self.wg_autostart.configure(state="disabled")
|
||||
self.lb_rename.configure(state="disabled")
|
||||
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,
|
||||
)
|
||||
|
||||
Tooltip(self.btn_exp, Msg.TTIP["export_tl_info"], 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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
"""
|
||||
@ -691,7 +885,11 @@ class FrameWidgets(ttk.Frame):
|
||||
Set (on), the selected tunnel is displayed in the label.
|
||||
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":
|
||||
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.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.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])
|
||||
|
||||
if self.selected_option.get() == 0:
|
||||
lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
|
||||
lines[7] = 'off\n'
|
||||
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
|
||||
lines = (
|
||||
Path(AppConfig.SETTINGS_FILE)
|
||||
.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)
|
||||
|
||||
@ -737,9 +946,15 @@ class FrameWidgets(ttk.Frame):
|
||||
self.wg_autostart.configure(state="disabled")
|
||||
|
||||
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
|
||||
Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
|
||||
Path(AppConfig.SETTINGS_FILE).write_text(
|
||||
"".join(lines), encoding="utf-8"
|
||||
)
|
||||
|
||||
except IndexError:
|
||||
self.selected_option.set(1)
|
||||
@ -755,19 +970,39 @@ class FrameWidgets(ttk.Frame):
|
||||
|
||||
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:
|
||||
|
||||
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()):
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
@ -776,7 +1011,17 @@ class FrameWidgets(ttk.Frame):
|
||||
select_tl = self.l_box.get(self.select_tunnel[0])
|
||||
|
||||
# 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")
|
||||
destination = source.with_name(f"{self.lb_rename.get()}.conf")
|
||||
source.replace(destination)
|
||||
@ -787,12 +1032,14 @@ class FrameWidgets(ttk.Frame):
|
||||
self.l_box.update()
|
||||
new_a_connect = self.lb_rename.get()
|
||||
self.lb_rename.delete(0, tk.END)
|
||||
|
||||
|
||||
with open(AppConfig.SETTINGS_FILE, "r", encoding="utf-8") as set_f5:
|
||||
lines5 = set_f5.readlines()
|
||||
if select_tl == lines5[7].strip() and "off\n" not in lines5[7].strip():
|
||||
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)
|
||||
self.autoconnect_var.set(value=new_a_connect)
|
||||
self.update_connection_display()
|
||||
@ -800,14 +1047,19 @@ class FrameWidgets(ttk.Frame):
|
||||
|
||||
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:
|
||||
pass
|
||||
|
||||
except EOFError as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def init_and_report(self, data=None) -> None:
|
||||
"""
|
||||
Displays the value address, DNS and peer in the labels
|
||||
@ -826,7 +1078,9 @@ class FrameWidgets(ttk.Frame):
|
||||
shows data in the 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.config(font=("Ubuntu", 9))
|
||||
|
||||
@ -836,7 +1090,9 @@ class FrameWidgets(ttk.Frame):
|
||||
self.dns.config(font=("Ubuntu", 9))
|
||||
|
||||
# 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.config(font=("Ubuntu", 9))
|
||||
|
||||
@ -851,7 +1107,7 @@ class FrameWidgets(ttk.Frame):
|
||||
self.handle_connection_state("start", select_tl)
|
||||
|
||||
else:
|
||||
|
||||
|
||||
data = self.handle_tunnel_data(self.a)
|
||||
if data:
|
||||
|
||||
@ -861,11 +1117,21 @@ class FrameWidgets(ttk.Frame):
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
"""
|
||||
|
@ -6,9 +6,10 @@ import locale
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
class AppConfig:
|
||||
"""Central configuration class for Wire-Py application"""
|
||||
|
||||
|
||||
# Localization
|
||||
APP_NAME: str = "wirepy"
|
||||
LOCALE_DIR: Path = Path("/usr/share/locale/")
|
||||
@ -23,32 +24,30 @@ class AppConfig:
|
||||
SETTINGS_FILE: Path = CONFIG_DIR / "settings"
|
||||
KEYS_FILE: Path = CONFIG_DIR / "keys"
|
||||
AUTOSTART_SERVICE: Path = Path.home() / ".config/systemd/user/wg_start.service"
|
||||
|
||||
|
||||
# Updates
|
||||
# 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year
|
||||
VERSION: str = "v. 2.04.1725"
|
||||
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"
|
||||
|
||||
|
||||
# UI configuration
|
||||
UI_CONFIG: Dict[str, Any] = {
|
||||
"window_title": "Wire-Py",
|
||||
"window_size": (600, 383),
|
||||
"font_family": "Ubuntu",
|
||||
"font_size": 11,
|
||||
"resizable_window": (False, False)
|
||||
"resizable_window": (False, False),
|
||||
}
|
||||
|
||||
|
||||
# System-dependent paths
|
||||
SYSTEM_PATHS: Dict[str, str]= {
|
||||
SYSTEM_PATHS: Dict[str, str] = {
|
||||
"ssl_decrypt": "/usr/local/bin/ssl_decrypt.py",
|
||||
"ssl_encrypt": "/usr/local/bin/ssl_encrypt.py",
|
||||
"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
|
||||
IMAGE_PATHS: Dict[str, str] = {
|
||||
"icon_vpn": "/usr/share/icons/lx-icons/48/wg_vpn.png",
|
||||
@ -59,16 +58,15 @@ class AppConfig:
|
||||
"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_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
|
||||
def setup_translations() -> gettext.gettext:
|
||||
"""
|
||||
Initialize translations and set the translation function
|
||||
Special method for translating strings in this file
|
||||
|
||||
|
||||
Returns:
|
||||
The gettext translation function
|
||||
"""
|
||||
@ -82,14 +80,16 @@ class AppConfig:
|
||||
"""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())
|
||||
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"""
|
||||
@ -97,14 +97,14 @@ class AppConfig:
|
||||
"main_icon": cls.SYSTEM_PATHS["image_path"] / "48/wg_vpn.png",
|
||||
"warning": cls.CONFIG_DIR / "images/warning.png",
|
||||
"success": cls.CONFIG_DIR / "images/success.png",
|
||||
"error": cls.CONFIG_DIR / "images/error.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
|
||||
|
||||
return """[Unit]Description=Automatic Tunnel Start
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
@ -114,29 +114,32 @@ ExecStart=/usr/local/bin/start_wg.py
|
||||
[Install]
|
||||
WantedBy=default.target"""
|
||||
|
||||
|
||||
# here is inizialize the class for translate strrings
|
||||
_ = AppConfig.setup_translations()
|
||||
|
||||
|
||||
class Msg:
|
||||
"""
|
||||
A utility class that provides centralized access to translated message strings.
|
||||
|
||||
|
||||
This class contains a dictionary of message strings used throughout the Wire-Py application.
|
||||
All strings are prepared for translation using gettext. The short key names make the code
|
||||
more concise while maintaining readability.
|
||||
|
||||
|
||||
Attributes:
|
||||
STR (dict): A dictionary mapping short keys to translated message strings.
|
||||
Keys are abbreviated for brevity but remain descriptive.
|
||||
|
||||
|
||||
Usage:
|
||||
Import this class and access messages using the dictionary:
|
||||
`Msg.STR["sel_tl"]` returns the translated "Select tunnel" message.
|
||||
|
||||
|
||||
Note:
|
||||
Ensure that gettext translation is properly initialized before
|
||||
accessing these strings to ensure correct localization.
|
||||
"""
|
||||
|
||||
STR: Dict[str, str] = {
|
||||
# Strings for messages
|
||||
"sel_tl": _("Select tunnel"),
|
||||
@ -150,31 +153,38 @@ class Msg:
|
||||
"sel_list": _("Please select a tunnel from the list"),
|
||||
"sign_len": _("The new name may contain only 12 characters"),
|
||||
"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"),
|
||||
"no_valid_file": _("Oh... no valid Wireguard File!\nPlease select a valid Wireguard File"),
|
||||
"tl_exist": _("Tunnel already available!\nPlease use another file for import")
|
||||
|
||||
}
|
||||
"no_valid_file": _(
|
||||
"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] = {
|
||||
#Strings for Tooltips
|
||||
# Strings for Tooltips
|
||||
"settings": _("Click for Settings"),
|
||||
"import_tl": _("Click to import a Wireguard Tunnel"),
|
||||
"start_tl": _("Click to start selected Wireguard Tunnel"),
|
||||
"empty_list": _("No tunnels to start in the list"),
|
||||
"stop_tl": _("Click to stop 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"),
|
||||
"trash_tl": _("Click to delete a Wireguard Tunnel\nSelect from the list!"),
|
||||
"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"),
|
||||
"start_tl_info": _("Click to start selected Wireguard Tunnel"),
|
||||
"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"),
|
||||
"list_auto_info": _("To use the autostart, a tunnel must be selected from the list"),
|
||||
"download": _("Click to download new version")
|
||||
|
||||
"list_auto_info": _(
|
||||
"To use the autostart, a tunnel must be selected from the list"
|
||||
),
|
||||
"download": _("Click to download new version"),
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user