return and back to back

This commit is contained in:
Désiré Werner Menrath 2025-05-24 18:12:05 +02:00
parent b764547d16
commit 68580d0ded
3 changed files with 47 additions and 71 deletions

View File

@ -10,7 +10,7 @@ from subprocess import CompletedProcess, run
import re import re
import sys import sys
import tkinter as tk import tkinter as tk
from typing import Optional, Dict, Any, NoReturn, List from typing import Optional, Dict, Any, NoReturn
import zipfile import zipfile
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@ -84,7 +84,7 @@ class CryptoUtil:
Checks if the private key already exists in the system using an external script. Checks if the private key already exists in the system using an external script.
Returns True only if the full key is found exactly (no partial match). Returns True only if the full key is found exactly (no partial match).
""" """
process: CompletedProcess[bool] = run( process: CompletedProcess[str] = run(
["pkexec", "/usr/local/bin/match_found.py", key], ["pkexec", "/usr/local/bin/match_found.py", key],
capture_output=True, capture_output=True,
text=True, text=True,
@ -120,7 +120,8 @@ class CryptoUtil:
decoded = base64.b64decode(key) decoded = base64.b64decode(key)
if len(decoded) != 32: # 32 bytes = 256 bits if len(decoded) != 32: # 32 bytes = 256 bits
return False return False
except Exception: except Exception as e:
logging.error(f"Error on decode Base64: {e}", exc_info=True)
return False return False
return True return True
@ -158,7 +159,7 @@ class LxTools:
geometry = monitor.get_geometry() geometry = monitor.get_geometry()
scale_factor = monitor.get_scale_factor() scale_factor = monitor.get_scale_factor()
# Calculate center position on primary monitor # Calculate center position on the primary monitor
x = geometry.x + (geometry.width - width // scale_factor) // 2 x = geometry.x + (geometry.width - width // scale_factor) // 2
y = geometry.y + (geometry.height - height // scale_factor) // 2 y = geometry.y + (geometry.height - height // scale_factor) // 2
@ -196,14 +197,14 @@ class LxTools:
primary_x = int(geometry[1]) primary_x = int(geometry[1])
primary_y = int(geometry[2]) primary_y = int(geometry[2])
# Calculate center position on primary monitor # Calculate center position on the primary monitor
x = primary_x + (primary_width - width) // 2 x = primary_x + (primary_width - width) // 2
y = primary_y + (primary_height - height) // 2 y = primary_y + (primary_height - height) // 2
# Set window geometry # Set window geometry
window.geometry(f"{width}x{height}+{x}+{y}") window.geometry(f"{width}x{height}+{x}+{y}")
return return
except (subprocess.SubprocessError, ImportError, IndexError, ValueError): except (ImportError, IndexError, ValueError):
pass pass
# Final fallback: Use standard Tkinter method # Final fallback: Use standard Tkinter method
@ -215,7 +216,7 @@ class LxTools:
if ( if (
screen_width > screen_height * 1.8 screen_width > screen_height * 1.8
): # Heuristic for detecting multiple monitors ): # Heuristic for detecting multiple monitors
# Assume primary monitor is on the left half # Assume the primary monitor is on the left half
screen_width = screen_width // 2 screen_width = screen_width // 2
x = (screen_width - width) // 2 x = (screen_width - width) // 2
@ -223,7 +224,7 @@ class LxTools:
window.geometry(f"{width}x{height}+{x}+{y}") window.geometry(f"{width}x{height}+{x}+{y}")
@staticmethod @staticmethod
def clean_files(TEMP_DIR: Path = None, file: Path = None) -> None: def clean_files(tmp_dir: Path = AppConfig.TEMP_DIR, file: Path = None) -> None:
""" """
Deletes temporary files and directories for cleanup when exiting the application. Deletes temporary files and directories for cleanup when exiting the application.
@ -231,34 +232,13 @@ class LxTools:
and a single file to free up resources at the end of the program's execution. and a single file to free up resources at the end of the program's execution.
All operations are performed securely, and errors such as `FileNotFoundError` All operations are performed securely, and errors such as `FileNotFoundError`
are ignored if the target files or directories do not exist. are ignored if the target files or directories do not exist.
:param tmp_dir: (Path, optional): Path to the temporary directory that should be deleted.
Args:
TEMP_DIR (Path, optional): Path to the temporary directory that should be deleted.
If `None`, the value of `AppConfig.TEMP_DIR` is used. If `None`, the value of `AppConfig.TEMP_DIR` is used.
file (Path, optional): Path to the file that should be deleted. :param file: (Path, optional): Path to the file that should be deleted.
If `None`, no additional file will be deleted. If `None`, no additional file will be deleted.
Returns: Returns:
None: The method does not return any value. None: The method does not return any value.
Examples:
- Without parameters:
```python
Tooltip.clean_files()
```
Deletes the temporary directory defined in the configuration (`AppConfig.TEMP_DIR`).
- With an explicit file path:
```python
Tooltip.clean_files(file=Path("temp/file.txt"))
```
Deletes the file `file.txt`, if it exists, and ignores errors.
- Both parameters:
```python
Tooltip.clean(TEMP_DIR=Path("/tmp/data"), file=Path("log.txt"))
```
Deletes the directory `/tmp/data` and the file `log.txt`, if they exist.
""" """
if AppConfig.TEMP_DIR is not None: if AppConfig.TEMP_DIR is not None:
@ -282,8 +262,10 @@ class LxTools:
""" """
Creates message windows Creates message windows
:argument AppConfig.IMAGE_PATHS["icon_info"] = Image for TK window which is displayed to the left of the text :param image_path2:
:argument AppConfig.IMAGE_PATHS["icon_vpn"] = Image for Task Icon :param image_path:
AppConfig.IMAGE_PATHS["icon_info"] = Image for TK window which is displayed to the left of the text
AppConfig.IMAGE_PATHS["icon_vpn"] = Image for Task Icon
:argument w_title = Windows Title :argument w_title = Windows Title
:argument w_txt = Text for Tk Window :argument w_txt = Text for Tk Window
:argument txt2 = Text for Button two :argument txt2 = Text for Button two
@ -294,7 +276,7 @@ class LxTools:
msg.title(w_title) msg.title(w_title)
msg.configure(pady=15, padx=15) msg.configure(pady=15, padx=15)
# load first image for window # load first image for a window
try: try:
msg.img = tk.PhotoImage(file=image_path) msg.img = tk.PhotoImage(file=image_path)
msg.i_window = tk.Label(msg, image=msg.img) msg.i_window = tk.Label(msg, image=msg.img)
@ -394,7 +376,7 @@ class Tunnel:
@staticmethod @staticmethod
def parse_files_to_dictionary( def parse_files_to_dictionary(
directory: Path = None, filepath: str = None, content: str = None directory: Path = None, filepath: str = None, content: str = None
) -> dict | str | None: ) -> tuple[dict, str] | dict | None:
data = {} data = {}
if filepath is not None: if filepath is not None:
@ -530,7 +512,7 @@ class Tunnel:
return active if active is not None else "" return active if active is not None else ""
@staticmethod @staticmethod
def export() -> bool: def export() -> bool | 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
@ -582,6 +564,11 @@ class Tunnel:
) )
return False return False
except zipfile.BadZipFile as e:
logging.error(f"Invalid ZIP file: {e}")
return False
except TypeError:
pass
except Exception as e: except Exception as e:
logging.error(f"Export failed: {str(e)}") logging.error(f"Export failed: {str(e)}")
LxTools.msg_window( LxTools.msg_window(
@ -591,12 +578,6 @@ class Tunnel:
Msg.STR["exp_try"], Msg.STR["exp_try"],
) )
return False return False
except zipfile.BadZipFile as e:
logging.error(f"Invalid ZIP file: {e}")
return False
except TypeError:
pass
finally: finally:
LxTools.clean_files(AppConfig.TEMP_DIR) LxTools.clean_files(AppConfig.TEMP_DIR)
@ -649,7 +630,7 @@ class ConfigManager:
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
@ -714,7 +695,7 @@ class GiteaUpdate:
""" """
Calling download requests the download URL of the running script, Calling download requests the download URL of the running script,
the taskbar image for the Download OK window, the taskbar image for the the taskbar image for the Download OK window, the taskbar image for the
Download error window and the variable res Download error window, and the variable res
""" """
@staticmethod @staticmethod
@ -771,13 +752,12 @@ class GiteaUpdate:
""" """
Downloads new version of wirepy Downloads new version of wirepy
Args: :param urld: Download URL
urld: Download URL :param res: Result filename
res: Result filename :param image_path: AppConfig.IMAGE_PATHS["icon_info"]: Image for TK window which is displayed to the left of the text
AppConfig.IMAGE_PATHS["icon_info"]: Image for TK window which is displayed to the left of the text :param image_path2: AppConfig.IMAGE_PATHS["icon_vpn"]: Image for Task Icon
AppConfig.IMAGE_PATHS["icon_vpn"]: Image for Task Icon :param image_path3: AppConfig.IMAGE_PATHS["icon_error"]: Image for TK window which is displayed to the left of the text
AppConfig.IMAGE_PATHS["icon_error"]: Image for TK window which is displayed to the left of the text :param image_path4: AppConfig.IMAGE_PATHS["icon_msg"]: Image for Task Icon
AppConfig.IMAGE_PATHS["icon_msg"]: Image for Task Icon
""" """
try: try:
to_down: str = f"wget -qP {Path.home()} {" "} {urld}" to_down: str = f"wget -qP {Path.home()} {" "} {urld}"
@ -846,7 +826,7 @@ class Tooltip:
self.x_offset = x_offset self.x_offset = x_offset
self.y_offset = y_offset self.y_offset = y_offset
# Initial binding based on current state # Initial binding based on the current state
self.update_bindings() self.update_bindings()
# Add trace to the state_var if provided # Add trace to the state_var if provided

View File

@ -400,7 +400,7 @@ class FrameWidgets(ttk.Frame):
# Update the labels based on the result # Update the labels based on the result
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 an 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()
@ -412,13 +412,13 @@ class FrameWidgets(ttk.Frame):
self.update_tooltip.set(_("Updates you have disabled")) self.update_tooltip.set(_("Updates you have disabled"))
# Clear the foreground color as requested # Clear the foreground color as requested
self.update_foreground.set("") self.update_foreground.set("")
# Set tooltip for the label # Set the tooltip for the label
Tooltip(self.updates_lb, self.update_tooltip.get(), self.tooltip_state) Tooltip(self.updates_lb, self.update_tooltip.get(), self.tooltip_state)
elif res == "No Internet Connection!": elif res == "No Internet Connection!":
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 the tooltip for "No Server Connection"
Tooltip( Tooltip(
self.updates_lb, self.updates_lb,
_("Could not connect to update server"), _("Could not connect to update server"),
@ -429,7 +429,7 @@ class FrameWidgets(ttk.Frame):
self.update_label.set(_("No Updates")) self.update_label.set(_("No Updates"))
self.update_tooltip.set(_("Congratulations! Wire-Py is up to date")) self.update_tooltip.set(_("Congratulations! Wire-Py is up to date"))
self.update_foreground.set("") self.update_foreground.set("")
# Set tooltip for the label # Set the tooltip for the label
Tooltip(self.updates_lb, self.update_tooltip.get(), self.tooltip_state) Tooltip(self.updates_lb, self.update_tooltip.get(), self.tooltip_state)
else: else:
@ -505,7 +505,7 @@ class FrameWidgets(ttk.Frame):
AppConfig.UPDATE_URL, AppConfig.VERSION, "on" AppConfig.UPDATE_URL, AppConfig.VERSION, "on"
) )
# Make sure UI is updated regardless of previous state # Make sure the UI is updated regardless of the 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"):
@ -550,8 +550,8 @@ class FrameWidgets(ttk.Frame):
# This assumes it's the third item (index 2) in your menu # This assumes it's the third item (index 2) in your menu
self.settings.entryconfigure(1, label=self.tooltip_label.get()) self.settings.entryconfigure(1, label=self.tooltip_label.get())
def update_theme_label(self) -> str: def update_theme_label(self) -> None:
"""Update the theme label based on current theme""" """Update the theme label based on the current theme"""
current_theme = ConfigManager.get("theme") current_theme = ConfigManager.get("theme")
if current_theme == "light": if current_theme == "light":
self.theme_label.set(_("Dark")) self.theme_label.set(_("Dark"))
@ -751,14 +751,10 @@ class FrameWidgets(ttk.Frame):
Msg.STR["imp_err"], Msg.STR["imp_err"],
Msg.STR["no_valid_file"], Msg.STR["no_valid_file"],
) )
except IsADirectoryError: except (IsADirectoryError, TypeError, FileNotFoundError):
print("File import: abort by user...") print("File import: abort by user...")
except EOFError as e: except EOFError as e:
print(e) print(e)
except TypeError:
print("File import: abort by user...")
except FileNotFoundError:
print("File import: abort by user...")
def delete(self) -> None: def delete(self) -> None:
""" """

View File

@ -76,7 +76,7 @@ class AppConfig:
} }
# System-dependent paths # System-dependent paths
SYSTEM_PATHS: Dict[str, str] = { SYSTEM_PATHS: Dict[str, Path] = {
"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",
@ -84,7 +84,7 @@ class AppConfig:
} }
# Images and icons paths # Images and icons paths
IMAGE_PATHS: Dict[str, str] = { IMAGE_PATHS: Dict[str, Path] = {
"icon_vpn": "/usr/share/icons/lx-icons/48/wg_vpn.png", "icon_vpn": "/usr/share/icons/lx-icons/48/wg_vpn.png",
"icon_msg": "/usr/share/icons/lx-icons/48/wg_msg.png", "icon_msg": "/usr/share/icons/lx-icons/48/wg_msg.png",
"icon_import": "/usr/share/icons/lx-icons/48/wg_import.png", "icon_import": "/usr/share/icons/lx-icons/48/wg_import.png",
@ -127,9 +127,9 @@ class AppConfig:
cls.SETTINGS_FILE.write_text(content) cls.SETTINGS_FILE.write_text(content)
@classmethod @classmethod
def get_autostart_content(cls) -> str: def get_autostart_content(cls) -> None:
"""Returns the content for the autostart service file""" """Returns the content for an autostart service file"""
SYSTEMD_FILE: list[str] = [ systemd_file: list[str] = [
"[Unit]", "[Unit]",
"Description=Automatic Tunnel Start", "Description=Automatic Tunnel Start",
"After=network-online.target", "After=network-online.target",
@ -147,7 +147,7 @@ class AppConfig:
if not cls.AUTOSTART_SERVICE.is_file(): if not cls.AUTOSTART_SERVICE.is_file():
content = "\n".join([line for line in SYSTEMD_FILE]) content = "\n".join([line for line in systemd_file])
cls.AUTOSTART_SERVICE.write_text(content) cls.AUTOSTART_SERVICE.write_text(content)
process: CompletedProcess[str] = run( process: CompletedProcess[str] = run(
@ -161,7 +161,7 @@ class AppConfig:
logging.error(f"{process.stderr} Code: {process.returncode}", exc_info=True) logging.error(f"{process.stderr} Code: {process.returncode}", exc_info=True)
# here is inizialize the class for translate strrings # here is initializing the class for translation strings
_ = AppConfig.setup_translations() _ = AppConfig.setup_translations()