04-06-2025_large_update #35
							
								
								
									
										107
									
								
								common_tools.py
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								common_tools.py
									
									
									
									
									
								
							@@ -6,7 +6,7 @@ import signal
 | 
				
			|||||||
import base64
 | 
					import base64
 | 
				
			||||||
import secrets
 | 
					import secrets
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
from subprocess import CompletedProcess, run
 | 
					from subprocess import CompletedProcess
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import tkinter as tk
 | 
					import tkinter as tk
 | 
				
			||||||
@@ -30,7 +30,7 @@ class CryptoUtil:
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def decrypt() -> str:
 | 
					    def decrypt() -> None:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Starts SSL dencrypt
 | 
					        Starts SSL dencrypt
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -54,7 +54,7 @@ class CryptoUtil:
 | 
				
			|||||||
            print(f"Error process decrypt: Code {process.returncode}")
 | 
					            print(f"Error process decrypt: Code {process.returncode}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def encrypt() -> str:
 | 
					    def encrypt() -> None:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Starts SSL encryption
 | 
					        Starts SSL encryption
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -80,7 +80,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[bool] = subprocess.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,
 | 
				
			||||||
@@ -121,7 +121,7 @@ class CryptoUtil:
 | 
				
			|||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LxTools(tk.Tk):
 | 
					class LxTools:
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Class LinuxTools methods that can also be used for other apps
 | 
					    Class LinuxTools methods that can also be used for other apps
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -183,7 +183,7 @@ class LxTools(tk.Tk):
 | 
				
			|||||||
                    break
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if primary_info:
 | 
					            if primary_info:
 | 
				
			||||||
                # Parse the geometry: WIDTHxHEIGHT+X+Y
 | 
					                # Parse the geometry: WIDTH x HEIGHT+X+Y
 | 
				
			||||||
                geometry = primary_info.split("+")
 | 
					                geometry = primary_info.split("+")
 | 
				
			||||||
                dimensions = geometry[0].split("x")
 | 
					                dimensions = geometry[0].split("x")
 | 
				
			||||||
                primary_width = int(dimensions[0])
 | 
					                primary_width = int(dimensions[0])
 | 
				
			||||||
@@ -217,31 +217,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
 | 
					 | 
				
			||||||
    def get_file_name(path: Path, i: int = 5) -> List[str]:
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Recursively searches the specified path for files and returns a list of filenames,
 | 
					 | 
				
			||||||
        with the last 'i' characters of each filename removed.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        This method is useful for obtaining filenames without specific file extensions,
 | 
					 | 
				
			||||||
        e.g., to remove '.conf' from Wireguard configuration files.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            path (Path): The directory path to search
 | 
					 | 
				
			||||||
            i (int, optional): Number of characters to remove from the end of each filename.
 | 
					 | 
				
			||||||
                            Default is 5, which typically corresponds to the length of '.conf'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Returns:
 | 
					 | 
				
			||||||
            List[str]: A list of filenames without the last 'i' characters
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Example:
 | 
					 | 
				
			||||||
            If path contains files like 'tunnel1.conf', 'tunnel2.conf' and i=5,
 | 
					 | 
				
			||||||
            the method returns ['tunnel1', 'tunnel2'].
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        lists_file = list(path.rglob("*"))
 | 
					 | 
				
			||||||
        lists_file = [conf_file.name[:-i] for conf_file in lists_file]
 | 
					 | 
				
			||||||
        return lists_file
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def get_username() -> str:
 | 
					    def get_username() -> str:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -266,11 +241,42 @@ class LxTools(tk.Tk):
 | 
				
			|||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def clean_files(TEMP_DIR: Path = None, file: Path = None) -> None:
 | 
					    def clean_files(TEMP_DIR: Path = None, file: Path = None) -> None:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        method that can be added after need to delete a folder and a file when quitting.
 | 
					        Deletes temporary files and directories for cleanup when exiting the application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This method safely removes an optional directory defined by `AppConfig.TEMP_DIR`
 | 
				
			||||||
 | 
					        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`
 | 
				
			||||||
 | 
					        are ignored if the target files or directories do not exist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Args:
 | 
					        Args:
 | 
				
			||||||
            :param file: default None
 | 
					            TEMP_DIR (Path, optional): Path to the temporary directory that should be deleted.
 | 
				
			||||||
            :param AppConfig.TEMP_DIR: default None
 | 
					                If `None`, the value of `AppConfig.TEMP_DIR` is used.
 | 
				
			||||||
 | 
					            file (Path, optional): Path to the file that should be deleted.
 | 
				
			||||||
 | 
					                If `None`, no additional file will be deleted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Returns:
 | 
				
			||||||
 | 
					            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:
 | 
				
			||||||
            shutil.rmtree(AppConfig.TEMP_DIR)
 | 
					            shutil.rmtree(AppConfig.TEMP_DIR)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
@@ -597,8 +603,20 @@ class Tunnel:
 | 
				
			|||||||
# ConfigManager with caching
 | 
					# ConfigManager with caching
 | 
				
			||||||
class ConfigManager:
 | 
					class ConfigManager:
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Universal class for managing configuration files with caching.
 | 
					    Universal class for managing configuration files with caching support.
 | 
				
			||||||
    Can be reused in different projects.
 | 
					
 | 
				
			||||||
 | 
					    This class provides a general solution to load, save, and manage configuration
 | 
				
			||||||
 | 
					    files across different projects. It uses a caching system to optimize access efficiency.
 | 
				
			||||||
 | 
					    The `init()` method initializes the configuration file path, while `load()` and `save()`
 | 
				
			||||||
 | 
					    synchronize data between the file and internal memory structures.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Key Features:
 | 
				
			||||||
 | 
					    - Caching to minimize I/O operations.
 | 
				
			||||||
 | 
					    - Default values for missing or corrupted configuration files.
 | 
				
			||||||
 | 
					    - Reusability across different projects and use cases.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The class is designed for central application configuration management, working closely
 | 
				
			||||||
 | 
					    with `ThemeManager` to dynamically manage themes or other settings.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _config = None
 | 
					    _config = None
 | 
				
			||||||
@@ -664,6 +682,23 @@ class ConfigManager:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ThemeManager:
 | 
					class ThemeManager:
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Class for central theme management and UI customization.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This static class allows dynamic adjustment of the application's appearance.
 | 
				
			||||||
 | 
					    The method `change_theme()` updates the current theme and saves
 | 
				
			||||||
 | 
					    the selection in the configuration file via `ConfigManager`.
 | 
				
			||||||
 | 
					    It ensures a consistent visual design across the entire project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Key Features:
 | 
				
			||||||
 | 
					    - Central control over themes.
 | 
				
			||||||
 | 
					    - Automatic saving of theme settings to the configuration file.
 | 
				
			||||||
 | 
					    - Tight integration with `ConfigManager` for persistent storage of preferences.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The class is designed to apply themes consistently throughout the application,
 | 
				
			||||||
 | 
					    ensuring that changes are traceable and uniform across all parts of the project.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def change_theme(root, theme_in_use, theme_name=None):
 | 
					    def change_theme(root, theme_in_use, theme_name=None):
 | 
				
			||||||
        """Change application theme centrally"""
 | 
					        """Change application theme centrally"""
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								wirepy.py
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								wirepy.py
									
									
									
									
									
								
							@@ -244,7 +244,7 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
        self.tl = Tunnel.parse_files_to_dictionary(directory=AppConfig.TEMP_DIR)
 | 
					        self.tl = Tunnel.parse_files_to_dictionary(directory=AppConfig.TEMP_DIR)
 | 
				
			||||||
        LxTools.clean_files(AppConfig.TEMP_DIR, file=None)
 | 
					        LxTools.clean_files(AppConfig.TEMP_DIR, file=None)
 | 
				
			||||||
        AppConfig.ensure_directories()
 | 
					        AppConfig.ensure_directories()
 | 
				
			||||||
        # self.tl = LxTools.get_file_name(AppConfig.TEMP_DIR)
 | 
					
 | 
				
			||||||
        for tunnels, values in self.tl.items():
 | 
					        for tunnels, values in self.tl.items():
 | 
				
			||||||
            self.l_box.insert("end", tunnels)
 | 
					            self.l_box.insert("end", tunnels)
 | 
				
			||||||
            self.l_box.update()
 | 
					            self.l_box.update()
 | 
				
			||||||
@@ -475,7 +475,7 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
        a tk.Toplevel window
 | 
					        a tk.Toplevel window
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def link_btn() -> str | None:
 | 
					        def link_btn() -> None:
 | 
				
			||||||
            webbrowser.open("https://git.ilunix.de/punix/Wire-Py")
 | 
					            webbrowser.open("https://git.ilunix.de/punix/Wire-Py")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        msg_t = _(
 | 
					        msg_t = _(
 | 
				
			||||||
@@ -583,8 +583,7 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        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)
 | 
					        if self.l_box.size() == 0:
 | 
				
			||||||
        if len(self.tl) == 0:
 | 
					 | 
				
			||||||
            Tooltip(self.btn_stst, Msg.TTIP["empty_list"], self.tooltip_state)
 | 
					            Tooltip(self.btn_stst, Msg.TTIP["empty_list"], self.tooltip_state)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            Tooltip(self.btn_stst, Msg.TTIP["start_tl"], self.tooltip_state)
 | 
					            Tooltip(self.btn_stst, Msg.TTIP["start_tl"], self.tooltip_state)
 | 
				
			||||||
@@ -908,9 +907,7 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
            if self.selected_option.get() == 0:
 | 
					            if self.selected_option.get() == 0:
 | 
				
			||||||
                ConfigManager.set("autostart", "off")
 | 
					                ConfigManager.set("autostart", "off")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                tl = [f"{file}" for file in AppConfig.CONFIG_DIR.glob("*.dat")]
 | 
					                if self.l_box.size() == 0:
 | 
				
			||||||
 | 
					 | 
				
			||||||
                if len(tl) == 0:
 | 
					 | 
				
			||||||
                    self.wg_autostart.configure(state="disabled")
 | 
					                    self.wg_autostart.configure(state="disabled")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if self.selected_option.get() >= 1:
 | 
					            if self.selected_option.get() >= 1:
 | 
				
			||||||
@@ -923,9 +920,12 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def tl_rename(self) -> None:
 | 
					    def tl_rename(self) -> None:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        method to rename a tunnel
 | 
					        Method to rename a tunnel. Validates input for length,
 | 
				
			||||||
 | 
					        special characters, and duplicate names,
 | 
				
			||||||
 | 
					        performs the renaming via `nmcli` if valid, updates
 | 
				
			||||||
 | 
					        the configuration file in the directory,
 | 
				
			||||||
 | 
					        and adjusts UI elements such as listboxes and labels.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        name_of_file = LxTools.get_file_name(AppConfig.TEMP_DIR)
 | 
					 | 
				
			||||||
        special_characters = ["\\", "/", "{", "}", " "]
 | 
					        special_characters = ["\\", "/", "{", "}", " "]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if len(self.lb_rename.get()) > 12:
 | 
					        if len(self.lb_rename.get()) > 12:
 | 
				
			||||||
@@ -955,7 +955,9 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
                Msg.STR["false_signs"],
 | 
					                Msg.STR["false_signs"],
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        elif self.lb_rename.get() in name_of_file:
 | 
					        elif self.lb_rename.get() in [
 | 
				
			||||||
 | 
					            file.stem for file in AppConfig.CONFIG_DIR.glob("*.dat")
 | 
				
			||||||
 | 
					        ]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            LxTools.msg_window(
 | 
					            LxTools.msg_window(
 | 
				
			||||||
                AppConfig.IMAGE_PATHS["icon_info"],
 | 
					                AppConfig.IMAGE_PATHS["icon_info"],
 | 
				
			||||||
@@ -1019,7 +1021,9 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
                print(e)
 | 
					                print(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def handle_tunnel_data(self, active=None, data=None) -> None:
 | 
					    def handle_tunnel_data(self, active=None, data=None) -> None:
 | 
				
			||||||
 | 
					        """Processes tunnel data from an active connection and updates
 | 
				
			||||||
 | 
					        UI elements like labels with information about address, DNS, and endpoint.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
        tunnel = active
 | 
					        tunnel = active
 | 
				
			||||||
        values = data[tunnel]
 | 
					        values = data[tunnel]
 | 
				
			||||||
        # Address Label
 | 
					        # Address Label
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,24 @@ from typing import Dict, Any
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AppConfig:
 | 
					class AppConfig:
 | 
				
			||||||
    """Central configuration class for Wire-Py application"""
 | 
					    """Central configuration and system setup manager for the Wire-Py application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This class serves as a singleton-like container for all global configuration data,
 | 
				
			||||||
 | 
					    including paths, UI settings, localization, versioning, and system-specific resources.
 | 
				
			||||||
 | 
					    It ensures that required directories, files, and services are created and configured
 | 
				
			||||||
 | 
					    before the application starts. Additionally, it provides tools for managing translations,
 | 
				
			||||||
 | 
					    default settings, and autostart functionality to maintain a consistent user experience.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Key Responsibilities:
 | 
				
			||||||
 | 
					    - Centralizes all configuration values (paths, UI preferences, localization).
 | 
				
			||||||
 | 
					    - Ensures required directories and files exist on startup.
 | 
				
			||||||
 | 
					    - Handles translation setup via `gettext` for multilingual support.
 | 
				
			||||||
 | 
					    - Manages default settings file generation.
 | 
				
			||||||
 | 
					    - Configures autostart services using systemd for user-specific launch behavior.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This class is used globally across the application to access configuration data
 | 
				
			||||||
 | 
					    consistently and perform system-level setup tasks.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Localization
 | 
					    # Localization
 | 
				
			||||||
    APP_NAME: str = "wirepy"
 | 
					    APP_NAME: str = "wirepy"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user