Compare commits
	
		
			53 Commits
		
	
	
		
			13832d916f
			...
			28-04-2025
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0cdad100b6 | |||
| 2cdc40f414 | |||
| 2311661735 | |||
| c10667ec21 | |||
| 08bef8fe6e | |||
| 2e94a324a6 | |||
| 18ed97bf20 | |||
| 5dcfc91621 | |||
| 5fb4e68867 | |||
| 19d413ea97 | |||
| 213f772f40 | |||
| 6f02724daa | |||
| 53f66ea76d | |||
| 3039dbecb0 | |||
| eadc2a06bf | |||
| 4eb9d6acd4 | |||
| 97ea07d34b | |||
| cd625d173d | |||
| 950e04a246 | |||
| 1a853d4ff1 | |||
| f6204c9071 | |||
| f9ecd54e0a | |||
| 67ff24f0b6 | |||
| af702f297b | |||
| d2a57b329b | |||
| 87943b2489 | |||
| c43c12f961 | |||
| 3bab0710a4 | |||
| aa66f4dc68 | |||
| c220951781 | |||
| 6c0662c62c | |||
| 5753a35d6c | |||
| 47bdfbfb17 | |||
| 2a3bf2bbcb | |||
| 8896f59efd | |||
| c58a630e25 | |||
| dc6f8cb094 | |||
| dcda647e90 | |||
| 2a995eabd5 | |||
| ea750b0cfc | |||
| 980ce3c7a7 | |||
| 28cc423138 | |||
| 39550b392d | |||
| 582ef21042 | |||
| ca58ac86a4 | |||
| 177fa1cc34 | |||
| ca1a7a6b94 | |||
| a49c5b00e1 | |||
| 75a247797d | |||
| 4b019b0c1f | |||
| ab78eb4f59 | |||
| 9f3f0246b4 | |||
| 5302aae807 | 
							
								
								
									
										3
									
								
								.idea/dictionaries/project.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,3 @@ | ||||
| <component name="ProjectDictionaryState"> | ||||
|   <dictionary name="project" /> | ||||
| </component> | ||||
							
								
								
									
										2
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						| @@ -3,5 +3,5 @@ | ||||
|   <component name="Black"> | ||||
|     <option name="sdkName" value="Python 3.12 (wire-py)" /> | ||||
|   </component> | ||||
|   <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (wire-py)" project-jdk-type="Python SDK" /> | ||||
|   <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" /> | ||||
| </project> | ||||
							
								
								
									
										2
									
								
								.idea/wire-py.iml
									
									
									
										generated
									
									
									
								
							
							
						
						| @@ -4,7 +4,7 @@ | ||||
|     <content url="file://$MODULE_DIR$"> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/.venv" /> | ||||
|     </content> | ||||
|     <orderEntry type="inheritedJdk" /> | ||||
|     <orderEntry type="jdk" jdkName="Python 3.12" jdkType="Python SDK" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										50
									
								
								.idea/workspace.xml
									
									
									
										generated
									
									
									
								
							
							
						
						| @@ -5,8 +5,12 @@ | ||||
|   </component> | ||||
|   <component name="ChangeListManager"> | ||||
|     <list default="true" id="940e1630-c825-4d4c-be80-bc11f543c122" name="Changes" comment=" - Update Translate Files"> | ||||
|       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> | ||||
|       <change afterPath="$PROJECT_DIR$/.vscode/settings.json" afterDir="false" /> | ||||
|       <change beforePath="$PROJECT_DIR$/cls_mth_fc.py" beforeDir="false" afterPath="$PROJECT_DIR$/cls_mth_fc.py" afterDir="false" /> | ||||
|       <change beforePath="$PROJECT_DIR$/ssl_decrypt.py" beforeDir="false" afterPath="$PROJECT_DIR$/ssl_decrypt.py" afterDir="false" /> | ||||
|       <change beforePath="$PROJECT_DIR$/ssl_encrypt.py" beforeDir="false" afterPath="$PROJECT_DIR$/ssl_encrypt.py" afterDir="false" /> | ||||
|       <change beforePath="$PROJECT_DIR$/wirepy.py" beforeDir="false" afterPath="$PROJECT_DIR$/wirepy.py" afterDir="false" /> | ||||
|       <change beforePath="$PROJECT_DIR$/wp_app_config.py" beforeDir="false" afterPath="$PROJECT_DIR$/wp_app_config.py" afterDir="false" /> | ||||
|     </list> | ||||
|     <option name="SHOW_DIALOG" value="false" /> | ||||
|     <option name="HIGHLIGHT_CONFLICTS" value="true" /> | ||||
| @@ -30,14 +34,13 @@ | ||||
|     <option name="UPDATE_TYPE" value="REBASE" /> | ||||
|   </component> | ||||
|   <component name="HighlightingSettingsPerFile"> | ||||
|     <setting file="file://$PROJECT_DIR$/wg_func.py" root0="SKIP_INSPECTION" /> | ||||
|     <setting file="file://$PROJECT_DIR$/wg_main.py" root0="FORCE_HIGHLIGHTING" /> | ||||
|     <setting file="file:///usr/local/bin/ssl_decrypt.py" root0="SKIP_INSPECTION" /> | ||||
|   </component> | ||||
|   <component name="ProjectColorInfo">{ | ||||
|   "associatedIndex": 3 | ||||
| }</component> | ||||
|   <component name="ProjectId" id="2kSbZdjOvr0wsVJSNcaMwSfVaxR" /> | ||||
|   <component name="ProjectLevelVcsManager" settingsEditedManually="true"> | ||||
|   <component name="ProjectLevelVcsManager"> | ||||
|     <ConfirmationsSetting value="2" id="Add" /> | ||||
|   </component> | ||||
|   <component name="ProjectViewState"> | ||||
| @@ -48,6 +51,7 @@ | ||||
|   "keyToString": { | ||||
|     "ASKED_ADD_EXTERNAL_FILES": "true", | ||||
|     "Python.INSTALL.executor": "Run", | ||||
|     "Python.cls_mth_fc.executor": "Run", | ||||
|     "Python.install.executor": "Run", | ||||
|     "Python.main.executor": "Run", | ||||
|     "Python.messagebox.executor": "Run", | ||||
| @@ -55,12 +59,14 @@ | ||||
|     "Python.testtheme.executor": "Run", | ||||
|     "Python.wg_func.executor": "Run", | ||||
|     "Python.wg_main.executor": "Run", | ||||
|     "Python.wirepy.executor": "Run", | ||||
|     "RunOnceActivity.ShowReadmeOnStart": "true", | ||||
|     "RunOnceActivity.git.unshallow": "true", | ||||
|     "Shell Script.install.executor": "Run", | ||||
|     "Shell Script.run_as.executor": "Run", | ||||
|     "git-widget-placeholder": "1.11.1024", | ||||
|     "git-widget-placeholder": "28-04-2025-more-methods-and-optimize-methods", | ||||
|     "last_opened_file_path": "/home/punix/Pyapps/wire-py", | ||||
|     "settings.editor.selected.configurable": "reference.settingsdialog.IDE.editor.colors" | ||||
|     "settings.editor.selected.configurable": "ml.llm.LLMConfigurable" | ||||
|   } | ||||
| }</component> | ||||
|   <component name="RecentsManager"> | ||||
| @@ -75,7 +81,7 @@ | ||||
|       <recent name="$PROJECT_DIR$/wire-py" /> | ||||
|     </key> | ||||
|   </component> | ||||
|   <component name="RunManager" selected="Python.wg_main"> | ||||
|   <component name="RunManager" selected="Python.wirepy"> | ||||
|     <configuration name="start_wg" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true"> | ||||
|       <module name="wire-py" /> | ||||
|       <option name="ENV_FILES" value="" /> | ||||
| @@ -120,8 +126,31 @@ | ||||
|       <option name="INPUT_FILE" value="" /> | ||||
|       <method v="2" /> | ||||
|     </configuration> | ||||
|     <configuration name="wirepy" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true"> | ||||
|       <module name="wire-py" /> | ||||
|       <option name="ENV_FILES" value="" /> | ||||
|       <option name="INTERPRETER_OPTIONS" value="" /> | ||||
|       <option name="PARENT_ENVS" value="true" /> | ||||
|       <envs> | ||||
|         <env name="PYTHONUNBUFFERED" value="1" /> | ||||
|       </envs> | ||||
|       <option name="SDK_HOME" value="" /> | ||||
|       <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> | ||||
|       <option name="IS_MODULE_SDK" value="true" /> | ||||
|       <option name="ADD_CONTENT_ROOTS" value="true" /> | ||||
|       <option name="ADD_SOURCE_ROOTS" value="true" /> | ||||
|       <option name="SCRIPT_NAME" value="$PROJECT_DIR$/wirepy.py" /> | ||||
|       <option name="PARAMETERS" value="" /> | ||||
|       <option name="SHOW_COMMAND_LINE" value="false" /> | ||||
|       <option name="EMULATE_TERMINAL" value="false" /> | ||||
|       <option name="MODULE_MODE" value="false" /> | ||||
|       <option name="REDIRECT_INPUT" value="false" /> | ||||
|       <option name="INPUT_FILE" value="" /> | ||||
|       <method v="2" /> | ||||
|     </configuration> | ||||
|     <recent_temporary> | ||||
|       <list> | ||||
|         <item itemvalue="Python.wirepy" /> | ||||
|         <item itemvalue="Python.start_wg" /> | ||||
|       </list> | ||||
|     </recent_temporary> | ||||
| @@ -129,7 +158,7 @@ | ||||
|   <component name="SharedIndexes"> | ||||
|     <attachedChunks> | ||||
|       <set> | ||||
|         <option value="bundled-python-sdk-8336bb23522e-31b6be0877a2-com.jetbrains.pycharm.community.sharedIndexes.bundled-PC-241.19072.16" /> | ||||
|         <option value="bundled-python-sdk-348a24fa61fa-5312c7369657-com.jetbrains.pycharm.community.sharedIndexes.bundled-PC-251.23774.444" /> | ||||
|       </set> | ||||
|     </attachedChunks> | ||||
|   </component> | ||||
| @@ -600,6 +629,11 @@ | ||||
|           <line>1128</line> | ||||
|           <option name="timeStamp" value="3" /> | ||||
|         </line-breakpoint> | ||||
|         <line-breakpoint enabled="true" suspend="THREAD" type="python-line"> | ||||
|           <url>file://$PROJECT_DIR$/ssl_decrypt.py</url> | ||||
|           <line>3</line> | ||||
|           <option name="timeStamp" value="4" /> | ||||
|         </line-breakpoint> | ||||
|       </breakpoints> | ||||
|     </breakpoint-manager> | ||||
|   </component> | ||||
|   | ||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,3 @@ | ||||
| { | ||||
|     "workbench.settings.openDefaultSettings": true | ||||
| } | ||||
							
								
								
									
										26
									
								
								Changelog
									
									
									
									
									
								
							
							
						
						| @@ -6,7 +6,29 @@ My standard System: Linux Mint 22 Cinnamon | ||||
|  - os import in cls_mth_fc.py replaced by other methods | ||||
|  - If Wire-Py already runs, prevent further start | ||||
|  - for loops with lists replaced by List Comprehensions | ||||
|  - Crypt and Decrypt Config Files in ~/.config/wire_py | ||||
|  | ||||
|  | ||||
|    ### Added | ||||
| 13-04-0725 | ||||
|  | ||||
|  - Installer update for Open Suse Tumbleweed and Leap | ||||
|  - add symbolic link wirepy.py  | ||||
|  | ||||
|  | ||||
|    ### Added | ||||
| 09-04-0725 | ||||
|  | ||||
|  - Installer now with query and remove | ||||
|  - Icons merged | ||||
|  | ||||
|  | ||||
|    ### Added | ||||
| 07-04-0725 | ||||
|  | ||||
|  - Installers will support other systems again | ||||
|  - Installer is now finished clean with wrong password | ||||
|  - Rename wg_main to wirepy  | ||||
|  | ||||
|  | ||||
|    ### Added | ||||
| 03-03-2025 | ||||
| @@ -19,7 +41,7 @@ My standard System: Linux Mint 22 Cinnamon | ||||
|  | ||||
|  - Fix ipv6 in Config File on import | ||||
|  - Wirepy run now as user | ||||
|  - settings, keys and Config Files now in ~/.config/wire_py | ||||
|  - settings, AppConfig.KEYS_FILE and Config Files now in ~/.config/wire_py | ||||
|  - For new users, the required files are created and autostart service is started.  | ||||
|  - Tunnels are now read from the directory to view them in the list.  | ||||
|    To display only own tunnels, and read errors are minimized. | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| [Desktop Entry] | ||||
| Type=Application | ||||
| Name=Wire-Py | ||||
| Exec=/usr/local/bin/wg_main.py | ||||
| Exec=/usr/local/bin/wirepy.py | ||||
| Terminal=false | ||||
| Categories=Network; | ||||
| Icon=/usr/share/icons/wp-icons/128/wg_vpn.png | ||||
| Icon=/usr/share/icons/lx-icons/128/wg_vpn.png | ||||
							
								
								
									
										
											BIN
										
									
								
								__pycache__/manage_tunnel.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								__pycache__/wp_app_config.cpython-312.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										648
									
								
								cls_mth_fc.py
									
									
									
									
									
								
							
							
						
						| @@ -1,361 +1,513 @@ | ||||
| """ Classes Method and functions for lx apps """ | ||||
| """ Classes Method and Functions for lx Apps """ | ||||
|  | ||||
| import gettext | ||||
| import locale | ||||
| import os | ||||
| import shutil | ||||
| from subprocess import check_call | ||||
| import signal | ||||
| import subprocess | ||||
| import sys | ||||
| import tkinter as tk | ||||
| from typing import Optional, Dict, Any, NoReturn, TextIO, Tuple, List | ||||
| import zipfile | ||||
| from datetime import datetime | ||||
| from pathlib import Path | ||||
| from tkinter import ttk | ||||
| from subprocess import check_call, CompletedProcess | ||||
| from tkinter import ttk, Toplevel | ||||
| from wp_app_config import AppConfig, Msg | ||||
| import requests | ||||
|  | ||||
| # Translate | ||||
| _ = AppConfig.setup_translations() | ||||
|  | ||||
| APP = 'wirepy' | ||||
| LOCALE_DIR = "/usr/share/locale/" | ||||
| locale.bindtextdomain(APP, LOCALE_DIR) | ||||
| gettext.bindtextdomain(APP, LOCALE_DIR) | ||||
| gettext.textdomain(APP) | ||||
| _ = gettext.gettext | ||||
|  | ||||
| wg_set = Path(Path.home() / '.config/wire_py/settings')   | ||||
|  | ||||
| class Create(): | ||||
| class Create: | ||||
|     """ | ||||
|     This class is for the creation of the folders and files | ||||
|     required by Wire-Py, as well as for decryption | ||||
|     the tunnel from the user's home directory  | ||||
|     the tunnel from the user's home directory | ||||
|     """ | ||||
|  | ||||
|     @staticmethod     | ||||
|     def dir_and_files(): | ||||
|     @staticmethod | ||||
|     def dir_and_files() -> None: | ||||
|         """ | ||||
|         check and create folders and files if not present | ||||
|         """ | ||||
|  | ||||
|         pth = Path.home() / '.config/wire_py' | ||||
|         pth: Path = Path.home() / ".config/wire_py" | ||||
|         pth.mkdir(parents=True, exist_ok=True) | ||||
|         sett = Path.home() / '.config/wire_py/settings' | ||||
|         ks = Path.home() / '.config/wire_py/keys' | ||||
|         sett: Path = Path.home() / ".config/wire_py/settings" | ||||
|         AppConfig.KEYS_FILE | ||||
|  | ||||
|         if sett.exists(): | ||||
|             pass | ||||
|  | ||||
|         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 ks.exists(): | ||||
|         if AppConfig.KEYS_FILE.exists(): | ||||
|             pass | ||||
|  | ||||
|         else: | ||||
|             ks.touch() | ||||
|             AppConfig.KEYS_FILE.touch() | ||||
|  | ||||
|     @staticmethod | ||||
|     def files_for_autostart(): | ||||
|     def files_for_autostart() -> None: | ||||
|         """ | ||||
|         check and create a file for auto start if not present and enable the service | ||||
|         """ | ||||
|  | ||||
|         pth2 = Path.home() / '.config/systemd/user' | ||||
|         pth2: Path = Path.home() / ".config/systemd/user" | ||||
|         pth2.mkdir(parents=True, exist_ok=True) | ||||
|         wg_ser = Path.home() / '.config/systemd/user/wg_start.service' | ||||
|         wg_ser: Path = Path.home() / ".config/systemd/user/wg_start.service" | ||||
|  | ||||
|         if wg_ser.exists(): | ||||
|             pass | ||||
|  | ||||
|         else: | ||||
|             wg_ser.touch() | ||||
|             wg_ser.write_text('[Unit]\nDescription=Automatic Tunnel Start\nAfter=network-online.target' | ||||
|                               '\n\n[Service]\nType=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']) | ||||
|             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 | ||||
|     def make_dir(): | ||||
|         ''' Dirname "tlecdewg" = Tunnel Encrypt Decrypt Wireguard ''' | ||||
|     def make_dir() -> None: | ||||
|         """Folder Name "tlecdewg" = Tunnel Encrypt Decrypt Wireguard""" | ||||
|  | ||||
|         dirname = Path('/tmp/tlecdcwg/') | ||||
|         if dirname.exists(): | ||||
|         if AppConfig.TEMP_DIR.exists(): | ||||
|             pass | ||||
|         else: | ||||
|             dirname.mkdir() | ||||
|             AppConfig.TEMP_DIR.mkdir() | ||||
|  | ||||
|     @staticmethod | ||||
|     def decrypt(): | ||||
|         process = subprocess.run(['pkexec', '/usr/local/bin/ssl_decrypt.py'], stdout=subprocess.PIPE, text=True) | ||||
|         #print(process.stdout) | ||||
|         if process.returncode == 0: | ||||
|             print('File successfully decrypted...') | ||||
|     def decrypt() -> None: | ||||
|         """ | ||||
|         Starts SSL dencrypt | ||||
|         """ | ||||
|         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: | ||||
|             if process.returncode == 0: | ||||
|                 print("File successfully decrypted...") | ||||
|             else: | ||||
|                 print(f"Error with the following code... {process.returncode}") | ||||
|         else: | ||||
|             print(f'Error with the following code... {process.returncode}') | ||||
|              | ||||
|             print(_("Ready for import")) | ||||
|  | ||||
|     @staticmethod | ||||
|     def encrypt(): | ||||
|         process = subprocess.run(['pkexec', '/usr/local/bin/ssl_encrypt.py'], stdout=subprocess.PIPE, text=True) | ||||
|     def encrypt() -> None: | ||||
|         """ | ||||
|         Starts SSL encryption | ||||
|         """ | ||||
|         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...') | ||||
|             print("All Files successfully encrypted...") | ||||
|         else: | ||||
|             print(f'Error with the following code... {process.returncode}')       | ||||
|          | ||||
| class UOS: | ||||
|     """  | ||||
|     The class is only for unixoidal systems "UOS" = UnixOS | ||||
|      | ||||
|     """ | ||||
|      | ||||
|     """  | ||||
|     This method displays the user name of the logged-in user,  | ||||
|     even if you are rooted in a shell | ||||
|     """ | ||||
|     @staticmethod | ||||
|     def username(): | ||||
|         logname = str(Path.home())[6:] | ||||
|         file = Path.home() / '/tmp/.loguser' | ||||
|         with open(file, "w") as f: | ||||
|             f.write(logname) | ||||
|             print(f"Error with the following code... {process.returncode}") | ||||
|  | ||||
|  | ||||
|  | ||||
| class GiteaUpdate: | ||||
| class LxTools(tk.Tk): | ||||
|     """ | ||||
|     Calling api_down requests the URL and the version of the running script. | ||||
|     Example: version = 'v. 1.1.1.1' GiteaUpdate.api_down(http://example.de, version) | ||||
|  | ||||
|     Calling download requests the download URL of the running script, | ||||
|     the taskbar image for the “Download OK” window, the taskbar image for the | ||||
|     “Download error” window and the variable res | ||||
|     Class LinuxTools methods that can also be used for other apps | ||||
|     """ | ||||
|     @staticmethod | ||||
|     def api_down(update_api_url, version): | ||||
|         try: | ||||
|             response = requests.get(update_api_url) | ||||
|             response_dict = response.json() | ||||
|             response_dict = response_dict[0] | ||||
|             with open(wg_set, 'r') as set_file: | ||||
|                 set_file = set_file.read() | ||||
|                 if 'on\n' in set_file: | ||||
|                     if version[3:] != response_dict['tag_name']: | ||||
|                         return response_dict['tag_name'] | ||||
|                     else: | ||||
|                         return 'No Updates' | ||||
|                 else: | ||||
|                     return 'False' | ||||
|         except requests.exceptions.ConnectionError: | ||||
|             return 'No Internet Connection!' | ||||
|  | ||||
|     def __init__(self, *args: Any, **kwargs: Any) -> None: | ||||
|         super().__init__(*args, **kwargs) | ||||
|  | ||||
|     @staticmethod | ||||
|     def download(urld, down_ok_image, down_not_ok_image, res): | ||||
|         try: | ||||
|             to_down = 'wget -qP ' + str(Path.home()) + ' ' + urld | ||||
|             result = subprocess.call(to_down, shell=True) | ||||
|             if result == 0: | ||||
|                 shutil.chown(str(Path.home()) + f'/{res}.zip', 1000, 1000) | ||||
|                 """img_w, img_i, w_title, w_txt hand over""" | ||||
|                 iw = r'/usr/share/icons/lx-icons/64/info.png' | ||||
|                 ii = down_ok_image | ||||
|                 wt = _('Download Successful') | ||||
|                 msg_t = _('Your zip file is in home directory') | ||||
|                 msg_window(iw, ii, wt, msg_t) | ||||
|     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 | ||||
|     def uos() -> None: | ||||
|         """ | ||||
|         uos = LOGIN USERNAME | ||||
|  | ||||
|         This method displays the username of the logged-in user, | ||||
|         even if you are rooted in a shell | ||||
|         """ | ||||
|         log_name: str = f"{Path.home()}"[6:] | ||||
|         file: Path = Path.home() / "/tmp/.log_user" | ||||
|         Path(file).write_text(log_name, encoding="utf-8") | ||||
|  | ||||
|     @staticmethod | ||||
|     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. | ||||
|         Args: | ||||
|             :param file: default None | ||||
|             :param AppConfig.TEMP_DIR: default None | ||||
|         """ | ||||
|         if AppConfig.TEMP_DIR is not None: | ||||
|             shutil.rmtree(AppConfig.TEMP_DIR) | ||||
|         if file is not None: | ||||
|             Path.unlink(file) | ||||
|  | ||||
|     @staticmethod | ||||
|     def if_tip(path: Path) -> bool: | ||||
|         """ | ||||
|         method that writes in file whether tooltip is displayed or not | ||||
|         """ | ||||
|         lines = Path(path).read_text(encoding="utf-8") | ||||
|         if "False\n" in lines: | ||||
|             tip = False | ||||
|         else: | ||||
|             tip = True | ||||
|         return tip | ||||
|              | ||||
|     @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: | ||||
|         """ | ||||
|         Creates message windows | ||||
|  | ||||
|         :argument AppConfig.IMAGE_PATHS["icon_info"] = Image for TK window which is displayed to the left of the text | ||||
|         :argument AppConfig.IMAGE_PATHS["icon_vpn"] = Image for Task Icon | ||||
|         :argument w_title = Windows Title | ||||
|         :argument w_txt = Text for Tk Window | ||||
|         :argument txt2 = Text for Button two | ||||
|         :argument com = function for Button command | ||||
|         """ | ||||
|         msg: tk.Toplevel = tk.Toplevel() | ||||
|         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) | ||||
|  | ||||
|         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.grid(column=0, row=1, sticky="e", columnspan=2) | ||||
|             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.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"]) | ||||
|         msg.columnconfigure(0, weight=1) | ||||
|         msg.rowconfigure(0, weight=1) | ||||
|         msg.winfo_toplevel() | ||||
|  | ||||
|     @staticmethod | ||||
|     def sigi(file_path: Optional[Path] = None, file: Optional[Path] = None) -> None: | ||||
|         """ | ||||
|         Function for cleanup after a program interruption | ||||
|  | ||||
|         :param file: Optional - File to be deleted | ||||
|         :param file_path: Optional - Directory to be deleted | ||||
|         """ | ||||
|  | ||||
|         def signal_handler(signum: int, frame: Any) -> NoReturn: | ||||
|             """ | ||||
|             Determines clear text names for signal numbers and handles signals | ||||
|  | ||||
|             Args: | ||||
|                 signum: The signal number | ||||
|                 frame: The current stack frame | ||||
|  | ||||
|             Returns: | ||||
|                 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) | ||||
|  | ||||
|             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}.") | ||||
|                 LxTools.clean_files(file_path, file) | ||||
|                 print("Breakdown by user...") | ||||
|                 sys.exit(exit_code) | ||||
|             else: | ||||
|                 """img_w, img_i, w_title, w_txt hand over""" | ||||
|                 iw = r'/usr/share/icons/lx-icons/64/error.png' | ||||
|                 ii = down_not_ok_image | ||||
|                 wt = _('Download error') | ||||
|                 msg_t = _('Download failed! Please try again') | ||||
|                 msg_window(iw, ii, wt, msg_t) | ||||
|         except subprocess.CalledProcessError: | ||||
|             """img_w, img_i, w_title, w_txt hand over""" | ||||
|             iw = r'/usr/share/icons/lx-icons/64/error.png' | ||||
|             ii = down_not_ok_image | ||||
|             wt = _('Download error') | ||||
|             msg_t = _('Download failed! No internet connection!') | ||||
|             msg_window(iw, ii, wt, msg_t) | ||||
|                 print(f"Signal {signum} received and ignored.") | ||||
|                 LxTools.clean_files(file_path, file) | ||||
|                 print("Process unexpectedly ended...") | ||||
|  | ||||
|  | ||||
| def msg_window(img_w, img_i, w_title, w_txt, txt2=None, com=None): | ||||
|     """ | ||||
|     Function for different message windows for the user. with 4 arguments to be passed. | ||||
|     To create messages with your own images, icons, and titles. As an alternative to Python Messagebox. | ||||
|     Paths to images must be specified: r'/usr/share/icons/lx-icons/64/info.png' | ||||
|     img_w = Image for Tk Window | ||||
|     img_i = Image for Icon | ||||
|     w_title = Windows Title | ||||
|     w_txt = Text for Tk Window | ||||
|     txt2 = Text for Button two | ||||
|     com = function for Button command | ||||
|     """ | ||||
|     msg = tk.Toplevel() | ||||
|     msg.resizable(width=False, height=False) | ||||
|     msg.title(w_title) | ||||
|     msg.configure(pady=15, padx=15) | ||||
|     msg.img = tk.PhotoImage(file=img_w) | ||||
|     msg.i_window = tk.Label(msg, image=msg.img) | ||||
|  | ||||
|     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(msg, text=f'{txt2}', command=com, padding=4) | ||||
|         button2.grid(column=0, row=1, sticky='e', columnspan=2) | ||||
|         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(msg, text='OK', command=msg.destroy, padding=4) | ||||
|         button.grid(column=0, columnspan=2, row=1) | ||||
|  | ||||
|     img_i = tk.PhotoImage(file=img_i) | ||||
|     msg.iconphoto(True, img_i) | ||||
|     msg.columnconfigure(0, weight=1) | ||||
|     msg.rowconfigure(0, weight=1) | ||||
|     msg.winfo_toplevel() | ||||
|         # Register signal handlers for various signals | ||||
|         signal.signal(signal.SIGINT, signal_handler) | ||||
|         signal.signal(signal.SIGTERM, signal_handler) | ||||
|         signal.signal(signal.SIGHUP, signal_handler) | ||||
|  | ||||
|  | ||||
| class Tunnel: | ||||
|     """ | ||||
|     Class of Methods for Wire-Py | ||||
|     """ | ||||
|  | ||||
|     """ | ||||
|     The config file is packed into a dictionary, | ||||
|     to display the values Address , DNS and Peer in the labels | ||||
|     """ | ||||
|     """  | ||||
|     @classmethod | ||||
|     def con_to_dict(cls, file): | ||||
|     def con_to_dict(cls, file: TextIO) -> Tuple[str, str, str, Optional[str]]: | ||||
|         """ | ||||
|         Returns tuple of (address, dns, endpoint, pre_key) | ||||
|         """ | ||||
|  | ||||
|         dictlist = [] | ||||
|         dictlist: List[str] = [] | ||||
|         for lines in file.readlines(): | ||||
|             line_plit = lines.split() | ||||
|             line_plit: List[str] = lines.split() | ||||
|             dictlist = dictlist + line_plit | ||||
|         dictlist.remove('[Interface]') | ||||
|         dictlist.remove('[Peer]') | ||||
|         dictlist.remove("[Interface]") | ||||
|         dictlist.remove("[Peer]") | ||||
|         for items in dictlist: | ||||
|             if items == '=': | ||||
|             if items == "=": | ||||
|                 dictlist.remove(items) | ||||
|             if items == "::/0": | ||||
|                 dictlist.remove(items) | ||||
|             if items == '::/0': | ||||
|                 dictlist.remove(items)     | ||||
|  | ||||
|         ''' Here is the beginning (Loop) of convert List to Dictionary ''' | ||||
|         # Here is the beginning (Loop) of convert List to Dictionary | ||||
|         for _ in dictlist: | ||||
|             a = [dictlist[0], dictlist[1]] | ||||
|             b = [dictlist[2], dictlist[3]] | ||||
|             c = [dictlist[4], dictlist[5]] | ||||
|             d = [dictlist[6], dictlist[7]] | ||||
|             e = [dictlist[8], dictlist[9]] | ||||
|             f = [dictlist[10], dictlist[11]] | ||||
|             g = [dictlist[12], dictlist[13]] | ||||
|             h = [dictlist[14], dictlist[15]] | ||||
|             new_list = [a, b, c, d, e, f, g, h] | ||||
|             final_dict = {} | ||||
|             a: List[str] = [dictlist[0], dictlist[1]] | ||||
|             b: List[str] = [dictlist[2], dictlist[3]] | ||||
|             c: List[str] = [dictlist[4], dictlist[5]] | ||||
|             d: List[str] = [dictlist[6], dictlist[7]] | ||||
|             e: List[str] = [dictlist[8], dictlist[9]] | ||||
|             f: List[str] = [dictlist[10], dictlist[11]] | ||||
|             g: List[str] = [dictlist[12], dictlist[13]] | ||||
|             h: List[str] = [dictlist[14], dictlist[15]] | ||||
|             new_list: List[List[str]] = [a, b, c, d, e, f, g, h] | ||||
|             final_dict: Dict[str, str] = {} | ||||
|             for elements in new_list: | ||||
|                 final_dict[elements[0]] = elements[1] | ||||
|  | ||||
|             ''' end... result a Dictionary ''' | ||||
|             # end... result a Dictionary | ||||
|  | ||||
|         address = final_dict['Address'] | ||||
|         dns = final_dict['DNS'] | ||||
|         if ',' in dns: | ||||
|         address: str = final_dict["Address"] | ||||
|         dns: str = final_dict["DNS"] | ||||
|         if "," in dns: | ||||
|             dns = dns[:-1] | ||||
|         endpoint = final_dict['Endpoint'] | ||||
|         if 'PresharedKey' in final_dict: | ||||
|             pre_key = final_dict['PresharedKey'] | ||||
|         else: | ||||
|             pre_key = final_dict['PreSharedKey'] | ||||
|         endpoint: str = final_dict["Endpoint"] | ||||
|         pre_key: Optional[str] = final_dict.get("PresharedKey") | ||||
|         if pre_key is None: | ||||
|             pre_key: Optional[str] = final_dict.get("PreSharedKey") | ||||
|         return address, dns, endpoint, pre_key | ||||
|  | ||||
|     """ | ||||
|     Shows the Active Tunnel | ||||
|     """ | ||||
|     @staticmethod | ||||
|     def active(): | ||||
|  | ||||
|         active = os.popen('nmcli con show --active | grep -iPo "(.*)(wireguard)"').read().split() | ||||
|     def active() -> str: | ||||
|         """ | ||||
|         Shows the Active Tunnel | ||||
|         """ | ||||
|         active = (os.popen('nmcli con show --active | grep -iPo "(.*)(wireguard)"').read().split()) | ||||
|         if not active: | ||||
|             active = '' | ||||
|             active = "" | ||||
|         else: | ||||
|             active = active[0] | ||||
|  | ||||
|         return active | ||||
|  | ||||
|     """ | ||||
|     Shows all existing Wireguard tunnels a login user | ||||
|     """ | ||||
|     @staticmethod | ||||
|     def list(): | ||||
|          | ||||
|         dirname = Path('/tmp/tlecdcwg/') | ||||
|         wg_s = os.listdir(dirname) | ||||
|     def list() -> List[str]: | ||||
|         """ | ||||
|         Returns a list of Wireguard tunnel names | ||||
|         """ | ||||
|         AppConfig.TEMP_DIR: Path = Path("/tmp/tlecdcwg/") | ||||
|         wg_s: List[str] = os.listdir(AppConfig.TEMP_DIR) | ||||
|  | ||||
|         return wg_s | ||||
|  | ||||
|  | ||||
|     """ | ||||
|     This will export the tunnels. | ||||
|     A zipfile with current date and time is created | ||||
|     in the user's home directory with correct right | ||||
|     """ | ||||
|     @staticmethod | ||||
|     def export(): | ||||
|         now_time = datetime.now() | ||||
|         now_datetime = now_time.strftime('wg-exp-' + '%m-%d-%Y' + '-' + '%H:%M') | ||||
|         tl = Tunnel.list() | ||||
|     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 | ||||
|         in the user's home directory with the correct right | ||||
|         Args: | ||||
|             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 | ||||
|             AppConfig.IMAGE_PATHS["icon_error"]: Image for TK window which is displayed to the left of the text | ||||
|             AppConfig.IMAGE_PATHS["icon_msg"]: Image for Task Icon | ||||
|         """ | ||||
|         now_time: datetime = datetime.now() | ||||
|         now_datetime: str = now_time.strftime("wg-exp-%m-%d-%Y-%H:%M") | ||||
|         tl: List[str] = Tunnel.list() | ||||
|  | ||||
|         try: | ||||
|             if len(tl) != 0: | ||||
|                 wg_tar = str(Path.home()) + '/' + now_datetime | ||||
|                 shutil.copytree('/tmp/tlecdcwg/', '/tmp/wire_py', dirs_exist_ok=True) | ||||
|                 source = Path('/tmp/wire_py') | ||||
|                 shutil.make_archive(wg_tar, 'zip', source) | ||||
|                 #shutil.chown(wg_tar + '.zip', 1000, 1000) | ||||
|                 wg_tar: str = f"{Path.home()}/{now_datetime}" | ||||
|                 shutil.copytree("/tmp/tlecdcwg/", "/tmp/wire_py", dirs_exist_ok=True) | ||||
|                 source: Path = Path("/tmp/wire_py") | ||||
|                 shutil.make_archive(wg_tar, "zip", source) | ||||
|                 shutil.rmtree(source) | ||||
|                 with zipfile.ZipFile((wg_tar + '.zip'), 'r') as zf: | ||||
|                 with zipfile.ZipFile(f"{wg_tar}.zip", "r") as zf: | ||||
|                     if len(zf.namelist()) != 0: | ||||
|  | ||||
|                         """img_w, img_i, w_title, w_txt hand over""" | ||||
|                         iw = r'/usr/share/icons/lx-icons/64/info.png' | ||||
|                         ii = r'/usr/share/icons/wp-icons/48/wg_vpn.png' | ||||
|                         wt = _('Export Successful') | ||||
|                         msg_t = _('Your zip file is in home directory') | ||||
|                         msg_window(iw, ii, wt, msg_t) | ||||
|                         LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_vpn"], Msg.STR["exp_succ"], Msg.STR["exp_in_home"]) | ||||
|  | ||||
|                     else: | ||||
|  | ||||
|                         """img_w, img_i, w_title, w_txt hand over""" | ||||
|                         iw = r'/usr/share/icons/lx-icons/64/error.png' | ||||
|                         ii = r'/usr/share/icons/wp-icons/48/wg_msg.png' | ||||
|                         wt = _('Export error') | ||||
|                         msg_t = _('Export failed! Please try again') | ||||
|                         msg_window(iw, ii, wt, msg_t) | ||||
|                         LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["exp_err"], Msg.STR["exp_try"]) | ||||
|  | ||||
|             else: | ||||
|  | ||||
|                 """img_w, img_i, w_title, w_txt hand over""" | ||||
|                 iw = r'/usr/share/icons/lx-icons/64/info.png' | ||||
|                 ii = r'/usr/share/icons/wp-icons/48/wg_msg.png' | ||||
|                 wt = _('Select tunnel') | ||||
|                 msg_t = _('Please first import tunnel') | ||||
|                 msg_window(iw, ii, wt, msg_t) | ||||
|                 LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["sel_tl"], Msg.STR["tl_first"]) | ||||
|  | ||||
|         except TypeError: | ||||
|             pass | ||||
|  | ||||
|  | ||||
| class Tipi: | ||||
| class GiteaUpdate: | ||||
|     """ | ||||
|     Class for Tooltip setting write in File | ||||
|     Calling request path to file | ||||
|     Calling download requests the download URL of the running script, | ||||
|     the taskbar image for the “Download OK” window, the taskbar image for the | ||||
|     “Download error” window and the variable res | ||||
|     """ | ||||
|     @staticmethod | ||||
|     def if_tip(path): | ||||
|         with open(path, 'r') as set_file2: | ||||
|             lines2 = set_file2.readlines() | ||||
|             if 'False\n' in lines2: | ||||
|                 return False | ||||
|             else: | ||||
|                 return True | ||||
|  | ||||
|     @staticmethod | ||||
|     def api_down(update_api_url: str, version: str, file: Optional[Path] = None) -> str: | ||||
|         """ | ||||
|         Checks for updates via API | ||||
|          | ||||
|         Args: | ||||
|             update_api_url: Update API URL | ||||
|             version: Current version | ||||
|             file: Optional - Configuration file | ||||
|              | ||||
|         Returns: | ||||
|             New version or status message | ||||
|         """ | ||||
|         try: | ||||
|             response: requests.Response = requests.get(update_api_url, timeout=10) | ||||
|             response_dict: Any = response.json() | ||||
|             response_dict: Dict[str, Any] = response_dict[0] | ||||
|             with open(file, "r", encoding="utf-8") as set_f: | ||||
|                 set_f = set_f.read() | ||||
|                 if "on\n" in set_f: | ||||
|                     if version[3:] != response_dict["tag_name"]: | ||||
|                         req: str = response_dict["tag_name"] | ||||
|                     else: | ||||
|                         req: str = "No Updates" | ||||
|                 else: | ||||
|                     req: str = "False" | ||||
|                 return req | ||||
|         except requests.exceptions.RequestException: | ||||
|             req: str = "No Internet Connection!" | ||||
|             return req | ||||
|  | ||||
|     @staticmethod | ||||
|     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 | ||||
|  | ||||
|         Args: | ||||
|             urld: Download URL | ||||
|             res: Result filename | ||||
|             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 | ||||
|             AppConfig.IMAGE_PATHS["icon_error"]: Image for TK window which is displayed to the left of the text | ||||
|             AppConfig.IMAGE_PATHS["icon_msg"]: Image for Task Icon | ||||
|         """ | ||||
|         try: | ||||
|             to_down: str = f"wget -qP {Path.home()} {" "} {urld}" | ||||
|             result: int = subprocess.call(to_down, shell=True) | ||||
|             if result == 0: | ||||
|                 shutil.chown(f"{Path.home()}/{res}.zip", 1000, 1000) | ||||
|  | ||||
|                 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) | ||||
|  | ||||
|             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) | ||||
|  | ||||
|         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) | ||||
|  | ||||
|  | ||||
| class Tooltip: | ||||
|     """ | ||||
|     class for Tooltip | ||||
|  | ||||
|     import Tooltip | ||||
|  | ||||
|     example: Tooltip(label, "Show tooltip on label") | ||||
|     example: Tooltip(button, "Show tooltip on button") | ||||
|     info: label and button are parent. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, widget: Any, text: str, tips: Optional[bool] = None) -> None: | ||||
|         """ | ||||
|         Tooltip Class | ||||
|         """ | ||||
|  | ||||
|         self.widget: Any = widget | ||||
|         self.text: str = text | ||||
|         self.tooltip_window: Optional[Toplevel] = None | ||||
|         if tips: | ||||
|             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() + 65 | ||||
|         y += self.widget.winfo_rooty() + 40 | ||||
|         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) | ||||
|         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 | ||||
|                         | ||||
							
								
								
									
										313
									
								
								install
									
									
									
									
									
								
							
							
						
						| @@ -8,128 +8,221 @@ install_file_with(){ | ||||
|   clear | ||||
|   mkdir -p ~/.config/wire_py && touch ~/.config/wire_py/keys && cp -u settings ~/.config/wire_py/ && \ | ||||
|   mkdir -p ~/.config/systemd/user && cp -u wg_start.service ~/.config/systemd/user/ && \ | ||||
|   systemctl --user enable wg_start.service | ||||
|   sudo cp -f org.sslcrypt.policy /usr/share/polkit-1/actions/ && \ | ||||
|   sudo apt install python3-tk && \ | ||||
|   sudo cp -fv wg_main.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ | ||||
|   sudo cp -uR wp-icons lx-icons /usr/share/icons/ &&  sudo cp -uR TK-Themes /usr/share/ && \ | ||||
|   sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ | ||||
|   sudo ln -sf /usr/local/bin/wg_main.py /usr/local/bin/wirepy && \ | ||||
|   sudo cp -f Wire-Py.desktop /usr/share/applications/  | ||||
|   systemctl --user enable wg_start.service >/dev/null 2>&1 | ||||
|   sudo cp -f org.sslcrypt.policy /usr/share/polkit-1/actions/  | ||||
|   if [ $? -ne 0 ] | ||||
|     then  | ||||
|       systemctl --user disable wg_start.service | ||||
|       rm -r ~/.config/wire_py && rm -r ~/.config/systemd | ||||
|       exit 0 | ||||
|   else  | ||||
|     sudo apt install python3-tk && \ | ||||
|     sudo cp -fv wirepy.py start_wg.py wp_app_config.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ | ||||
|     sudo cp -uR lx-icons /usr/share/icons/ &&  sudo cp -uR TK-Themes /usr/share/ && \ | ||||
|     sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ | ||||
|     sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \ | ||||
|     sudo ln -sf /usr/local/bin/wirepy.py /usr/local/bin/wirepy | ||||
|     sudo mkdir -p /usr/local/etc/ssl | ||||
|     if [ ! -f /usr/local/etc/ssl/pwgk.pem ] | ||||
|       then | ||||
|         sudo openssl genrsa -out /usr/local/etc/ssl/pwgk.pem 4096 | ||||
|     fi | ||||
|   fi   | ||||
|   } | ||||
|  | ||||
| install_arch_d(){ | ||||
|   clear | ||||
|   sudo pacman -S --noconfirm tk python3 python-requests && \ | ||||
|   sudo cp -u wg_main.py start_wg.py cls_mth_fc.py && \ | ||||
|   sudo mkdir -p /etc/wire_py && sudo touch /etc/wire_py/keys && sudo cp -u settings  /etc/wire_py/ && \ | ||||
|   sudo cp -uR wp-icons lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \ | ||||
|   sudo chown -R root:root /etc/wire_py && sudo chmod 755 /etc/wire_py && \ | ||||
|   sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ | ||||
|   sudo ln -sf /usr/bin/wirepy.py /usr/local/bin/wirepy && \ | ||||
|   sudo cp -u org.wirepy.policy /usr/share/polkit-1/actions/ && \ | ||||
|   sudo cp -u Wire-Py.desktop /usr/share/applications/ && \ | ||||
|   sudo cp -u org.sslcrypt.policy /usr/share/polkit-1/actions/ && \ | ||||
|   sudo cp -u wg_start.service /lib/systemd/system/ && \ | ||||
|   sudo systemctl enable wg_start.service | ||||
|   mkdir -p ~/.config/wire_py && touch ~/.config/wire_py/keys && cp -u settings ~/.config/wire_py/ && \ | ||||
|   mkdir -p ~/.config/systemd/user && cp -u wg_start.service ~/.config/systemd/user/ && \ | ||||
|   systemctl --user enable wg_start.service >/dev/null 2>&1 | ||||
|   sudo cp -f org.sslcrypt.policy /usr/share/polkit-1/actions/ | ||||
|   if [ $? -ne 0 ] | ||||
|     then  | ||||
|         systemctl --user disable wg_start.service | ||||
|         rm -r ~/.config/wire_py && rm -r ~/.config/systemd | ||||
|         exit 0 | ||||
|   else  | ||||
|     sudo pacman -S --noconfirm tk python3 python-requests && \ | ||||
|     sudo cp -fv wirepy.py start_wg.py wp_app_config.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ | ||||
|     sudo cp -uR lx-icons /usr/share/icons/ &&  sudo cp -uR TK-Themes /usr/share/ && \ | ||||
|     sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ | ||||
|     sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \ | ||||
|     sudo ln -sf /usr/local/bin/wirepy.py /usr/local/bin/wirepy  | ||||
|     sudo mkdir -p /usr/local/etc/ssl | ||||
|     if [ ! -f /usr/local/etc/ssl/pwgk.pem ] | ||||
|       then | ||||
|         sudo openssl genrsa -out /usr/local/etc/ssl/pwgk.pem 4096 | ||||
|     fi    | ||||
|     | ||||
|   fi  | ||||
|   } | ||||
|  | ||||
| if grep -i 'debian' /etc/os-release > /dev/null 2>&1 | ||||
|   then | ||||
|     groups > /tmp/isgroup | ||||
|     if grep 'sudo' /tmp/isgroup | ||||
|       then | ||||
| install(){ | ||||
|   if grep -i 'debian' /etc/os-release > /dev/null 2>&1 | ||||
|     then | ||||
|       groups > /tmp/isgroup | ||||
|       if grep 'sudo' /tmp/isgroup | ||||
|         then | ||||
|           install_file_with | ||||
|       else | ||||
|         echo -e "$BLUE"The installer found that they are not in the group sudo."" | ||||
|         echo -e "with "$RED"su -"$BLUE" "they can enter the root shell in which they then"" | ||||
|         echo -e "enter "$GREEN""usermod -aG sudo $USER.""$BLUE"" | ||||
|         echo -e ""after logging in from the system, they can then run Wire-Py install again." $NORMAL" | ||||
|         read -n 1 -s -r -p $"Press Enter to exit" | ||||
|         clear | ||||
|         exit 0 | ||||
|  | ||||
|     else | ||||
|       fi | ||||
|  | ||||
|   elif grep -i 'mint\|ubuntu\|pop|' /etc/os-release > /dev/null 2>&1 | ||||
|     then | ||||
|         install_file_with | ||||
|  | ||||
|   elif grep -i 'arch' /etc/os-release > /dev/null 2>&1 | ||||
|     then | ||||
|       groups > /tmp/isgroup | ||||
|       clear | ||||
|       if grep 'wheel' /tmp/isgroup | ||||
|         then | ||||
|             install_arch_d | ||||
|       else | ||||
|           echo "The installer found that they are not in the group sudo." | ||||
|           echo "The sudoers file must be edited with" | ||||
|           echo -e "$RED""su -""$NORMAL" | ||||
|           echo -e "$GREEN"""EDITOR=nano visudo"""$NORMAL" | ||||
|           echo "Find the line:" | ||||
|           echo "## Uncomment to allow members of group wheel to execute any command" | ||||
|           echo "remove '#' on  # %wheel ALL=(ALL) ALL and save the file" | ||||
|           echo -e "then enter "$GREEN"gpasswd -a $USER wheel.""$NORMAL" | ||||
|           echo "after logging in from the system, they can then run Wire-Py install again." | ||||
|           read -n 1 -s -r -p $"Press Enter to exit" | ||||
|           clear | ||||
|           exit 0 | ||||
|  | ||||
|       fi | ||||
|  | ||||
|   elif grep -i '|manjaro\|garuda\|endeavour|' /etc/os-release > /dev/null 2>&1 | ||||
|       then | ||||
|           install_arch_d | ||||
|  | ||||
|   elif grep -i 'fedora' /etc/os-release > /dev/null 2>&1 | ||||
|     then | ||||
|       clear | ||||
|       mkdir -p ~/.config/wire_py && touch ~/.config/wire_py/keys && cp -u settings ~/.config/wire_py/ && \ | ||||
|       mkdir -p ~/.config/systemd/user && cp -u wg_start.service ~/.config/systemd/user/ && \ | ||||
|       systemctl --user enable wg_start.service >/dev/null 2>&1 | ||||
|       sudo cp -f org.sslcrypt.policy /usr/share/polkit-1/actions/ | ||||
|       if [ $? -ne 0 ] | ||||
|         then  | ||||
|             systemctl --user disable wg_start.service | ||||
|             rm -r ~/.config/wire_py && rm -r ~/.config/systemd | ||||
|             exit 0 | ||||
|       else | ||||
|         sudo dnf install python3-tkinter -y | ||||
|         sudo cp -fv wirepy.py start_wg.py wp_app_config.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ | ||||
|         sudo cp -uR lx-icons /usr/share/icons/ &&  sudo cp -uR TK-Themes /usr/share/ && \ | ||||
|         sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ | ||||
|         sudo cp -fv Wire-Py.desktop /usr/share/applications/  && \ | ||||
|         sudo ln -sf /usr/local/bin/wirepy.py /usr/local/bin/wirepy | ||||
|         sudo mkdir -p /usr/local/etc/ssl | ||||
|         if [ ! -f /usr/local/etc/ssl/pwgk.pem ] | ||||
|           then | ||||
|             sudo openssl genrsa -out /usr/local/etc/ssl/pwgk.pem 4096 | ||||
|         fi | ||||
|  | ||||
|       fi | ||||
|   elif grep -i 'suse' /etc/os-release > /dev/null 2>&1 | ||||
|     then | ||||
|       clear | ||||
|       mkdir -p ~/.config/wire_py && touch ~/.config/wire_py/keys && cp -u settings ~/.config/wire_py/ && \ | ||||
|       mkdir -p ~/.config/systemd/user && cp -u wg_start.service ~/.config/systemd/user/ && \ | ||||
|       systemctl --user enable wg_start.service >/dev/null 2>&1 | ||||
|       sudo cp -f org.sslcrypt.policy /usr/share/polkit-1/actions/ | ||||
|       if [ $? -ne 0 ] | ||||
|         then  | ||||
|           systemctl --user disable wg_start.service | ||||
|           rm -r ~/.config/wire_py && rm -r ~/.config/systemd | ||||
|           exit 0 | ||||
|       else  | ||||
|         sudo cp -fv wirepy.py start_wg.py wp_app_config.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \ | ||||
|         sudo cp -uR lx-icons /usr/share/icons/ &&  sudo cp -uR TK-Themes /usr/share/ && \ | ||||
|         sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ | ||||
|         sudo cp -fv Wire-Py.desktop /usr/share/applications/ && \ | ||||
|         sudo ln -sf /usr/local/bin/wirepy.py /usr/local/bin/wirepy  | ||||
|         sudo mkdir -p /usr/local/etc/ssl | ||||
|         if [ ! -f /usr/local/etc/ssl/pwgk.pem ] | ||||
|           then | ||||
|             sudo openssl genrsa -out /usr/local/etc/ssl/pwgk.pem 4096 | ||||
|         fi | ||||
|         if grep -i 'Tumbleweed' /etc/os-release > /dev/null 2>&1 | ||||
|           then | ||||
|             sudo zypper install python313-tk | ||||
|         else | ||||
|           sudo zypper install python36-tk | ||||
|         fi | ||||
|                | ||||
|       fi | ||||
|        | ||||
|   else | ||||
|       clear | ||||
|       echo $"Your System could not be determined." | ||||
|       echo | ||||
|       read -n 1 -s -r -p $"Press Enter to exit" | ||||
|       clear | ||||
|       exit 0 | ||||
|  | ||||
|   fi | ||||
|   #clear | ||||
|   read -n 1 -s -r -p $"Press Enter to exit" | ||||
|   clear | ||||
|  | ||||
|   } | ||||
|  | ||||
| remove(){ | ||||
|     sudo rm -f /usr/local/bin/wirepy /usr/local/bin/wirepy.py /usr/local/bin/start_wg.py \ | ||||
|     /usr/local/bin/wp_app_config.py cls_mth_fc.py /usr/local/bin/ssl_encrypt.py /usr/local/bin/ssl_decrypt.py  | ||||
|     if [ $? -ne 0 ] | ||||
|       then | ||||
|         exit 0 | ||||
|     else  | ||||
|       systemctl --user disable wg_start.service | ||||
|       rm -r ~/.config/wire_py && rm -r ~/.config/systemd | ||||
|       sudo rm /usr/share/applications/Wire-Py.desktop | ||||
|       sudo rm /usr/share/locale/de/LC_MESSAGES/languages/de/wirepy.mo | ||||
|       sudo rm -r /usr/local/etc/ssl | ||||
|       which syncpy >/dev/null | ||||
|       if [ $? -ne 0 ] | ||||
|         then  | ||||
|           sudo rm -r /usr/share/icons/lx-icons &&  sudo rm -r /usr/share/TK-Themes   | ||||
|  | ||||
|       fi | ||||
|  | ||||
|       echo | ||||
|       read -p "Press Enter to exit..." | ||||
|  | ||||
|     echo -e "$BLUE"The installer found that they are not in the group sudo."" | ||||
|     echo -e "with "$RED"su -"$BLUE" "they can enter the root shell in which they then"" | ||||
|     echo -e "enter "$GREEN""usermod -aG sudo $USER.""$BLUE"" | ||||
|     echo -e ""after logging in from the system, they can then run Wire-Py install again." $NORMAL" | ||||
|     read -n 1 -s -r -p $"To close the Window press a button" | ||||
|     clear | ||||
|     exit 0 | ||||
|     fi | ||||
|  | ||||
|   } | ||||
|  | ||||
| elif grep -i 'mint\|ubuntu\|pop|' /etc/os-release > /dev/null 2>&1 | ||||
|   then | ||||
|       install_file_with | ||||
|  | ||||
|  | ||||
| elif grep -i 'arch' /etc/os-release > /dev/null 2>&1 | ||||
| which wirepy >/dev/null | ||||
| if [ $? -eq 0 ] | ||||
|     then | ||||
|         groups > /tmp/isgroup | ||||
|         echo "Do you want to update/reinstall or uninstall wirepy?" | ||||
|         echo | ||||
|         echo "Update/reinstall: press y, uninstall press r" | ||||
|         echo | ||||
|         read -n 1 -s -r -p "Cancel with any other key..."  result | ||||
|         case $result in | ||||
|             [y]* ) clear; install; exit;; | ||||
|             [Y]* ) clear; install; exit;; | ||||
|             [j]* ) clear; install; exit;; | ||||
|             [J]* ) clear; install; exit;; | ||||
|             [r]* ) clear; remove; exit;; | ||||
|             [R]* ) clear; remove; exit;; | ||||
|         esac | ||||
|         clear | ||||
|         if grep 'wheel' /tmp/isgroup | ||||
|           then | ||||
|               install_arch_d | ||||
|         else | ||||
|             echo "The installer found that they are not in the group sudo." | ||||
|             echo "The sudoers file must be edited with" | ||||
|             echo -e "$RED""su -""$NORMAL" | ||||
|             echo -e "$GREEN"""EDITOR=nano visudo"""$NORMAL" | ||||
|             echo "Find the line:" | ||||
|             echo "## Uncomment to allow members of group wheel to execute any command" | ||||
|             echo "remove '#' on  # %wheel ALL=(ALL) ALL and save the file" | ||||
|             echo -e "then enter "$GREEN"gpasswd -a $USER wheel.""$NORMAL" | ||||
|             echo "after logging in from the system, they can then run Wire-Py install again." | ||||
|             read -n 1 -s -r -p $"To close the Window press a button" | ||||
|             clear | ||||
|             exit 0 | ||||
|  | ||||
|         fi | ||||
|  | ||||
| elif grep -i '|manjaro\|garuda\|endeavour|' /etc/os-release > /dev/null 2>&1 | ||||
|     then | ||||
|         install_arch_d | ||||
|  | ||||
|  | ||||
| elif grep -i 'fedora' /etc/os-release > /dev/null 2>&1 | ||||
|     then | ||||
|         if ! which python3-tkinter &> /dev/null | ||||
|             then sudo dnf install python3-tkinter -y | ||||
|  | ||||
|                 sudo cp -u wg_main.py start_wg.py cls_mth_fc.py && \ | ||||
|                 sudo mkdir -p /etc/wire_py && sudo touch /etc/wire_py/keys && \ | ||||
|                 sudo cp -u settings /etc/wire_py/ && \ | ||||
|                 sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ | ||||
|                 sudo cp -uR wp-icons lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \ | ||||
|                 sudo chown -R root:root /etc/wire_py && sudo chmod 755 /etc/wire_py && \ | ||||
|                 sudo ln -sf /usr/bin/wirepy.py /usr/local/bin/wirepy && \ | ||||
|                 sudo cp -u org.wirepy.policy /usr/share/polkit-1/actions/ && \ | ||||
|                 sudo cp -u Wire-Py.desktop /usr/share/applications/ && \ | ||||
|                 sudo cp -u wg_start.service /lib/systemd/system/ && \ | ||||
|                 sudo systemctl enable wg_start.service | ||||
|  | ||||
|         fi | ||||
| elif grep -i 'suse' /etc/os-release > /dev/null 2>&1 | ||||
|     then | ||||
|         if ! which python311-tk &> /dev/null | ||||
|             then sudo zypper install python311-tk | ||||
|                  sudo cp -u wg_main.py start_wg.py cls_mth_fc.py && \ | ||||
|                  sudo mkdir -p /etc/wire_py && sudo touch /etc/wire_py/keys && \ | ||||
|                  sudo cp -u settings /etc/wire_py/ && \ | ||||
|                  sudo cp -u languages/de/*.mo /usr/share/locale/de/LC_MESSAGES/ && \ | ||||
|                  sudo cp -uR wp-icons lx-icons /usr/share/icons/ && sudo cp -uR TK-Themes /usr/share/ && \ | ||||
|                  sudo chown -R root:root /etc/wire_py && sudo chmod 755 /etc/wire_py && \ | ||||
|                  sudo ln -sf /usr/bin/wirepy.py /usr/local/bin/wirepy && \ | ||||
|                  sudo cp -u org.wirepy.policy /usr/share/polkit-1/actions/ && \ | ||||
|                  sudo cp -u Wire-Py.desktop /usr/share/applications/ && \ | ||||
|                  sudo cp -u wg_start.service /lib/systemd/system/ && \ | ||||
|                  sudo systemctl enable wg_start.service | ||||
|         fi | ||||
| else | ||||
|     clear | ||||
|     echo $"Your System could not be determined." | ||||
|     echo | ||||
|     read -n 1 -s -r -p $"To close the window press a button" | ||||
|     clear | ||||
|     exit 0 | ||||
| fi | ||||
| #clear | ||||
| read -n 1 -s -r -p $"To close the Window press a button" | ||||
| clear | ||||
|  | ||||
|  | ||||
|   install        | ||||
|     | ||||
| fi         | ||||
| Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB | 
| Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB | 
| Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB | 
| Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB | 
| Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB | 
| Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB | 
| Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB | 
| Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB | 
| Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB | 
| Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB | 
| Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB | 
| Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB | 
| Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB | 
| Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB | 
| Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB | 
| Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB | 
| Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB | 
| Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB | 
| Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB | 
| Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB | 
| Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB | 
| Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB | 
| Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB | 
| Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB | 
| Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB | 
| Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB | 
| Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB | 
| Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB | 
| Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB | 
| Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB | 
| Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB | 
| Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB | 
| Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB | 
							
								
								
									
										15
									
								
								manage_tunnel.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | ||||
| #!/usr/bin/python3 | ||||
| from pathlib import Path | ||||
| from subprocess import check_call | ||||
| from tkinter import filedialog, ttk | ||||
| from cls_mth_fc 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() | ||||
|  | ||||
| @@ -1,28 +1,34 @@ | ||||
| #!/usr/bin/python3 | ||||
| ''' This Script decrypt Wireguardfiles for Wirepy users ''' | ||||
| """ This Script decrypt Wireguard files for Wirepy users """ | ||||
|  | ||||
| import os | ||||
| from subprocess import check_call | ||||
| from pathlib import Path | ||||
| import shutil | ||||
| uname = Path('/tmp/.loguser') | ||||
| from pathlib import Path | ||||
| from subprocess import check_call | ||||
| from wp_app_config import AppConfig | ||||
|  | ||||
| with open(uname, 'r') as f: | ||||
|     logname = f.readline() | ||||
|      | ||||
| ''' Dirname "tlecdewg" = Tunnel Encrypt Decrypt Wireguard ''' | ||||
| dirname = Path('/tmp/tlecdcwg/') | ||||
| keyfile = '/usr/local/etc/ssl/pwgk.pem' | ||||
| uname: Path = Path("/tmp/.log_user") | ||||
|  | ||||
| dirname2 = ('/home/' + logname + '/.config/wire_py/') | ||||
| detl = os.listdir(dirname2) | ||||
| os.chdir(dirname2) | ||||
| detl.remove('keys') | ||||
| detl.remove('settings') | ||||
| if os.path.exists(dirname2 + 'pbwgk.pem'): | ||||
|     detl.remove('pbwgk.pem') | ||||
| 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" | ||||
|  | ||||
| if not keyfile.is_file(): | ||||
|  | ||||
|     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/" | ||||
| detl: list[str] = os.listdir(AppConfig.TEMP_DIR2) | ||||
| os.chdir(AppConfig.TEMP_DIR2) | ||||
| detl.remove("keys") | ||||
| detl.remove("settings") | ||||
| if os.path.exists(f"{AppConfig.TEMP_DIR2}pbwgk.pem"): | ||||
|     detl.remove("pbwgk.pem") | ||||
|     for detunnels in detl: | ||||
|         tlname2 = detunnels[:-4] + '.conf' | ||||
|         extpath = str(dirname) + '/' + tlname2 | ||||
|         check_call(['openssl', 'pkeyutl', '-decrypt', '-inkey', keyfile, '-in', detunnels, '-out', extpath]) | ||||
|         shutil.chown(extpath, 1000, 1000) | ||||
|         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]) | ||||
|         shutil.chown(extpath, 1000, 1000) | ||||
|   | ||||
| @@ -1,49 +1,46 @@ | ||||
| #!/usr/bin/python3 | ||||
| ''' This Script encrypt Wireguardfiles for Wirepy users for more Security''' | ||||
| """ This Script encrypt Wireguardfiles for Wirepy users for more Security """ | ||||
|  | ||||
| import os | ||||
| from subprocess import check_call | ||||
| from pathlib import Path | ||||
| import shutil | ||||
| from pathlib import Path | ||||
| from subprocess import check_call | ||||
| from cls_mth_fc import LxTools | ||||
| from wp_app_config import AppConfig | ||||
|  | ||||
| uname = Path('/tmp/.loguser') | ||||
| #uname: Path = Path("/tmp/.log_user") | ||||
|  | ||||
| with open(uname, 'r') as f: | ||||
|     logname = f.readline() | ||||
| #log_name = AppConfig.USER_FILE.read_text(encoding="utf-8") | ||||
|  | ||||
| keyfile = Path(f'/home/{logname}/.config/wire_py/pbwgk.pem') | ||||
| dirname = Path('/tmp/tlecdcwg/') | ||||
| pkeyfile = '/usr/local/etc/ssl/pwgk.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', pkeyfile, '-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 dirname.exists(): | ||||
|         tl = os.listdir(str(dirname)) | ||||
|         cpth = str(keyfile) | ||||
|         cryptfiles = cpth[:-9] | ||||
|  | ||||
|     if AppConfig.TEMP_DIR.exists(): | ||||
|         tl = LxTools.get_file_name(AppConfig.TEMP_DIR) | ||||
|         CPTH: str = f"{keyfile}" | ||||
|         CRYPTFILES: str = CPTH[:-9] | ||||
|  | ||||
|         if keyfile.exists() and len(tl) != 0: | ||||
|             for tunnels in tl: | ||||
|                 sourcetl = str(dirname) + '/' + tunnels | ||||
|                 tlname = cryptfiles + tunnels[:-5] + '.dat' | ||||
|                 check_call(['openssl', 'pkeyutl', '-encrypt', '-inkey', keyfile, '-pubin', '-in', sourcetl, '-out', tlname]) | ||||
|                 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,]) | ||||
|  | ||||
| else: | ||||
|  | ||||
|     if dirname.exists(): | ||||
|         tl = os.listdir(str(dirname)) | ||||
|         cpth = str(keyfile) | ||||
|         cryptfiles = cpth[:-9] | ||||
|     if AppConfig.TEMP_DIR.exists(): | ||||
|         tl: list[str] = os.listdir(f"{AppConfig.TEMP_DIR}") | ||||
|         CPTH: str = f"{keyfile}" | ||||
|         CRYPTFILES: str = CPTH[:-9] | ||||
|  | ||||
|         if keyfile.exists() and len(tl) != 0: | ||||
|             for tunnels in tl: | ||||
|                 sourcetl = str(dirname) + '/' + tunnels | ||||
|                 tlname = cryptfiles + tunnels[:-5] + '.dat' | ||||
|                 check_call(['openssl', 'pkeyutl', '-encrypt', '-inkey', keyfile, '-pubin', '-in', sourcetl, '-out', tlname]) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|                 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]) | ||||
|   | ||||
							
								
								
									
										21
									
								
								start_wg.py
									
									
									
									
									
								
							
							
						
						| @@ -1,14 +1,15 @@ | ||||
| #!/usr/bin/python3 | ||||
| from subprocess import check_call | ||||
| """ | ||||
|  This script belongs to wirepy and is for the auto start of the tunnel   | ||||
| """ | ||||
| from pathlib import Path | ||||
| from subprocess import check_call | ||||
|  | ||||
| path_to_file = Path(Path.home() / '.config/wire_py/settings') | ||||
|  | ||||
| with open(path_to_file, 'r') as a_con: | ||||
|     lines = a_con.readlines() | ||||
|     a_con = lines[7].strip() | ||||
|     if a_con != 'off': | ||||
|         check_call(['nmcli', 'connection', 'up', a_con]) | ||||
|     else: | ||||
|         pass | ||||
| path_to_file = Path(Path.home() / ".config/wire_py/settings") | ||||
|  | ||||
| a_con = Path(path_to_file).read_text(encoding="utf-8").splitlines(keepends=True) | ||||
| a_con = a_con[7].strip() | ||||
| if a_con != "off": | ||||
|     check_call(["nmcli", "connection", "up", a_con]) | ||||
| else: | ||||
|     pass | ||||
|   | ||||
							
								
								
									
										1211
									
								
								wg_main.py
									
									
									
									
									
								
							
							
						
						
							
								
								
									
										899
									
								
								wirepy.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,899 @@ | ||||
| #!/usr/bin/python3 | ||||
| """ | ||||
| this script is a simple GUI for managing Wireguard Tunnels | ||||
| """ | ||||
| import gettext | ||||
| import locale | ||||
| import os | ||||
| import shutil | ||||
| import subprocess | ||||
| import sys | ||||
| import tkinter as tk | ||||
| import webbrowser | ||||
| from pathlib import Path | ||||
| from subprocess import check_call | ||||
| from tkinter import TclError, filedialog, ttk | ||||
|  | ||||
| from cls_mth_fc import (Create, GiteaUpdate, Tunnel, Tooltip, LxTools) | ||||
| from wp_app_config import AppConfig, Msg | ||||
|  | ||||
| LxTools.uos() | ||||
| Create.dir_and_files() | ||||
| Create.make_dir() | ||||
| Create.decrypt() | ||||
| # 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year | ||||
| VERSION: str = "v. 2.04.1725" | ||||
|  | ||||
| res = GiteaUpdate.api_down("https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases", VERSION, AppConfig.SETTINGS_FILE) | ||||
|  | ||||
| class Wirepy(tk.Tk): | ||||
|     """ | ||||
|     Class Wirepy this is the Main Window of wirepy | ||||
|     """ | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
|  | ||||
|         self.my_tool_tip = None | ||||
|         self.x_width = AppConfig.UI_CONFIG["window_size"][0] | ||||
|         self.y_height = AppConfig.UI_CONFIG["window_size"][1] | ||||
|         self.monitor_center_x = int(self.winfo_screenwidth() / 2 - (self.x_width / 2)) | ||||
|         self.monitor_center_y = int(self.winfo_screenheight() / 2 - (self.y_height / 2)) | ||||
|         self.resizable(AppConfig.UI_CONFIG["resizable_window"][0], AppConfig.UI_CONFIG["resizable_window"][1]) | ||||
|         self.title(AppConfig.UI_CONFIG["window_title"]) | ||||
|         self.geometry(f"{self.x_width}x{self.y_height}+{self.monitor_center_x}+{self.monitor_center_y}") | ||||
|         self.columnconfigure(0, weight=1) | ||||
|         self.rowconfigure(0, weight=1) | ||||
|         self.style = ttk.Style(self) | ||||
|         self.tk.call("source", f"{AppConfig.SYSTEM_PATHS["tcl_path"]}/water.tcl") | ||||
|         lines = AppConfig.SETTINGS_FILE.read_text() | ||||
|         if "light\n" in lines: | ||||
|             self.tk.call("set_theme", "light") | ||||
|         else: | ||||
|             self.tk.call("set_theme", "dark") | ||||
|  | ||||
|         # Load the image file from the disk | ||||
|         self.wg_icon = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_vpn"]) | ||||
|  | ||||
|         # Set it as the window icon | ||||
|         self.iconphoto(True, self.wg_icon) | ||||
|  | ||||
|         tips = LxTools.if_tip(AppConfig.SETTINGS_FILE) | ||||
|         FrameWidgets(self, tips_enabled=tips).grid() | ||||
|  | ||||
|  | ||||
| class FrameWidgets(ttk.Frame): | ||||
|     """ | ||||
|     ttk frame class for better structure | ||||
|     """ | ||||
|     def __init__(self, container, tips_enabled=None, **kwargs): | ||||
|         super().__init__(container, **kwargs) | ||||
|  | ||||
|         self.tunnel = Tunnel() | ||||
|         self.lb_tunnel = None | ||||
|         self.btn_stst = None | ||||
|         self.endpoint = None | ||||
|         self.dns = None | ||||
|         self.address = None | ||||
|         self.auto_con = None | ||||
|         self.wg_vpn_start = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_start"]) | ||||
|         self.wg_vpn_stop = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_stop"]) | ||||
|         self.imp_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_import"]) | ||||
|         self.tr_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_trash"]) | ||||
|         self.exp_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_export"]) | ||||
|         self.warning_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_error"]) | ||||
|         self.tips_enabled = tips_enabled if tips_enabled is not None else LxTools.if_tip(AppConfig.SETTINGS_FILE) | ||||
|         # Frame for Menu | ||||
|         self.menu_frame = ttk.Frame(self) | ||||
|         self.menu_frame.configure(relief="flat") | ||||
|         self.menu_frame.grid(column=0, row=0, columnspan=4, sticky="w") | ||||
|  | ||||
|         # App Menu | ||||
|         self.version_lb = ttk.Label(self.menu_frame, text=VERSION) | ||||
|         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: {VERSION[2:]}", self.tips_enabled) | ||||
|  | ||||
|         self.options_btn = ttk.Menubutton(self.menu_frame, text=_("Options")) | ||||
|         self.options_btn.grid(column=1, columnspan=1, row=0) | ||||
|  | ||||
|         Tooltip(self.options_btn, _("Click for Settings"), self.tips_enabled) | ||||
|  | ||||
|         set_update = tk.IntVar() | ||||
|         set_tip = tk.BooleanVar() | ||||
|         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(set_update.get()), variable=set_update) | ||||
|         self.settings.add_checkbutton(label=_("Disable Tooltips"), | ||||
|                                       command=lambda: self.tooltip(set_tip.get()), variable=set_tip) | ||||
|         self.settings.add_command(label=_("Light"), command=self.theme_change_light) | ||||
|         self.settings.add_command(label=_("Dark"), command=self.theme_change_dark) | ||||
|  | ||||
|         # About BTN Menu / Label | ||||
|         self.about_btn = ttk.Button( | ||||
|         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) | ||||
|  | ||||
|         # Update and Tooltip Label | ||||
|         self.updates_lb = ttk.Label(self.menu_frame) | ||||
|         self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10) | ||||
|  | ||||
|         # View Checkbox to enable or disable Tooltip | ||||
|         if tips: | ||||
|             set_tip.set(value=False) | ||||
|         else: | ||||
|             set_tip.set(value=True) | ||||
|  | ||||
|         # View Checkbox for enable or disable Updates | ||||
|         if res == "False": | ||||
|             set_update.set(value=1) | ||||
|             self.updates_lb.configure(text=_("Update search off")) | ||||
|  | ||||
|             Tooltip(self.updates_lb, _("Updates you have disabled"), self.tips_enabled) | ||||
|  | ||||
|         elif res == "No Internet Connection!": | ||||
|             self.updates_lb.configure(text=_("No Server Connection!"), foreground="red") | ||||
|         elif res == "No Updates": | ||||
|             self.updates_lb.configure(text=_("No Updates")) | ||||
|  | ||||
|             Tooltip(self.updates_lb, _("Congratulations! Wire-Py is up to date"), self.tips_enabled) | ||||
|  | ||||
|         else: | ||||
|             set_update.set(value=0) | ||||
|             text = f"Update {res} {_("available!")}" | ||||
|  | ||||
|             # Update BTN Menu | ||||
|             self.update_btn = ttk.Menubutton(self.menu_frame, text=text) | ||||
|             self.update_btn.grid(column=4, columnspan=3, row=0, padx=0) | ||||
|  | ||||
|             Tooltip(self.update_btn, _("Click to download new version"), self.tips_enabled) | ||||
|  | ||||
|             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"https://git.ilunix.de/punix/Wire-Py/archive/{res}.zip",  | ||||
|                                                     res, AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"])) | ||||
|  | ||||
|         # Show active Tunnel | ||||
|         self.a = Tunnel.active() | ||||
|  | ||||
|         # Label Frame 1 | ||||
|         self.lb_frame_btn_lbox = ttk.Frame(self) | ||||
|         self.lb_frame_btn_lbox.configure(relief="flat") | ||||
|         self.lb_frame_btn_lbox.grid(column=0, rowspan=3, row=1) | ||||
|  | ||||
|         # Label Frame 2 | ||||
|         self.lb_frame = ttk.Frame(self) | ||||
|         self.lb_frame.configure(relief="solid") | ||||
|         self.lb_frame.grid(column=2, row=2, sticky="snew", padx=20, pady=5) | ||||
|  | ||||
|         # Label Frame 3 | ||||
|         self.lb_frame2 = ttk.Frame(self) | ||||
|         self.lb_frame2.configure(relief="solid") | ||||
|         self.lb_frame2.grid(column=2, row=3, sticky="snew", padx=20, pady=5) | ||||
|  | ||||
|         # 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) | ||||
|  | ||||
|         # Bottom Frame 5 | ||||
|         self.lb_frame4 = ttk.Frame(self) | ||||
|         self.lb_frame4.configure(relief="flat") | ||||
|         self.lb_frame4.grid(column=2, row=5, columnspan=3, sticky="e", padx=15) | ||||
|  | ||||
|         # Show active Label | ||||
|         self.select_tunnel = None | ||||
|         self.lb = ttk.Label(self, text=_("Active: ")) | ||||
|         self.lb.config(font=("Ubuntu", 11, "bold")) | ||||
|         self.lb.grid(column=2, row=1, padx=15, pady=4, sticky="w") | ||||
|  | ||||
|         # Label to Show active Tunnel | ||||
|         self.str_var = tk.StringVar(value=self.a) | ||||
|         self.color_label() | ||||
|  | ||||
|         # Interface Label | ||||
|         self.interface = ttk.Label(self.lb_frame, text=_("Interface")) | ||||
|         self.interface.grid(column=0, row=3, sticky="we", padx=120) | ||||
|         self.interface.config(font=("Ubuntu", 9)) | ||||
|  | ||||
|         # Peer Label | ||||
|         self.peer = ttk.Label(self.lb_frame2, text=_("Peer")) | ||||
|         self.peer.config(font=("Ubuntu", 9)) | ||||
|         self.peer.grid(column=0, row=4, sticky="we", padx=130) | ||||
|  | ||||
|         # Listbox with Scrollbar | ||||
|         self.l_box = tk.Listbox(self.lb_frame_btn_lbox, selectmode="single") | ||||
|         self.l_box.config(relief="ridge", font=("Ubuntu", 12, "bold")) | ||||
|         self.l_box.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.grid(column=1, rowspan=4, row=0, sticky="nse") | ||||
|         self.l_box.configure(yscrollcommand=self.scrollbar.set) | ||||
|  | ||||
|         # Tunnel List | ||||
|         self.tl = LxTools.get_file_name(AppConfig.TEMP_DIR) | ||||
|         for tunnels in self.tl: | ||||
|             self.l_box.insert("end", tunnels) | ||||
|             self.l_box.update() | ||||
|  | ||||
|         # Button Vpn | ||||
|         if self.a != "": | ||||
|             self.stop() | ||||
|             data = self.handle_tunnel_data(self.a) | ||||
|         else: | ||||
|             self.start() | ||||
|  | ||||
|             # Address Label | ||||
|             self.add = tk.StringVar() | ||||
|             self.DNS = tk.StringVar() | ||||
|             self.enp = tk.StringVar() | ||||
|             self.reset_fields() | ||||
|             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.grid(column=0, row=1, padx=15, pady=8) | ||||
|  | ||||
|         Tooltip(self.btn_i, _("Click to import a Wireguard Tunnel"), self.tips_enabled) | ||||
|  | ||||
|         # 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.grid(column=0, row=2, padx=15, pady=8) | ||||
|  | ||||
|         if self.l_box.size() == 0: | ||||
|             Tooltip(self.btn_tr, _("No tunnels to delete in the list"), self.tips_enabled) | ||||
|         else: | ||||
|             Tooltip(self.btn_tr, _("Click to delete a Wireguard Tunnel\nSelect from the list!"), self.tips_enabled) | ||||
|  | ||||
|         # 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.grid(column=0, row=3, padx=15, pady=8) | ||||
|  | ||||
|         if self.l_box.size() == 0: | ||||
|             Tooltip(self.btn_exp, _("No Tunnels in List for Export"), self.tips_enabled) | ||||
|         else: | ||||
|             Tooltip(self.btn_exp, _("Click to export all\nWireguard Tunnel to Zipfile"), self.tips_enabled) | ||||
|  | ||||
|         # Label Entry | ||||
|         self.lb_rename = ttk.Entry(self.lb_frame4, width=20) | ||||
|         self.lb_rename.grid(column=2, row=0, padx=8, pady=10, sticky="ne") | ||||
|         self.lb_rename.insert(0, _("Max. 12 characters!")) | ||||
|         self.lb_rename.config(state="disable") | ||||
|  | ||||
|         if self.l_box.size() != 0: | ||||
|             Tooltip(self.lb_rename, _("To rename a tunnel, you need to\nselect a tunnel from the list"), self.tips_enabled) | ||||
|         else: | ||||
|             Tooltip(self.lb_rename, _("To rename a tunnel, at least one must be in the list"), self.tips_enabled) | ||||
|  | ||||
|         # Button Rename | ||||
|         self.btn_rename = ttk.Button(self.lb_frame4, text=_("Rename"), state="disable", command=self.tl_rename, | ||||
|                                      padding=4, style="RnButton.TButton") | ||||
|         self.btn_rename.grid(column=3, row=0, padx=5, pady=10, sticky="ne") | ||||
|  | ||||
|         # Check Buttons | ||||
|         self.selected_option = tk.IntVar() | ||||
|         self.autoconnect_var = tk.StringVar() | ||||
|         self.autoconnect_var.set(f"{self.auto_con}") | ||||
|  | ||||
|         # Frame for Labels, Entry and Button | ||||
|         self.autoconnect = ttk.Label(self.lb_frame3, textvariable=self.autoconnect_var, width=15) | ||||
|         self.autoconnect.config(font=("Ubuntu", 11)) | ||||
|         self.autoconnect.grid(column=1, row=0, sticky="e", pady=19) | ||||
|         self.wg_autostart = ttk.Checkbutton(self.lb_frame3, text=_("Autoconnect on:"), variable=self.selected_option, | ||||
|                                             command=self.box_set) | ||||
|         self.wg_autostart.grid(column=0, row=0, pady=15, padx=15, sticky="nw") | ||||
|  | ||||
|         if self.l_box.size() >= 1 and len(self.l_box.curselection()) >= 1: | ||||
|             Tooltip(self.wg_autostart, Msg.TTIP["autostart"], tself.tips_enabled) | ||||
|  | ||||
|         if self.l_box.size() == 0: | ||||
|             Tooltip(self.wg_autostart, Msg.TTIP["autostart_info"], self.tips_enabled) | ||||
|  | ||||
|         else: | ||||
|  | ||||
|             Tooltip(self.wg_autostart, Msg.TTIP["autostart"], self.tips_enabled) | ||||
|  | ||||
|         self.on_off() | ||||
|  | ||||
|  | ||||
|     @staticmethod | ||||
|     def update_setting(update_res) -> None: | ||||
|         """ | ||||
|         write off or on in file | ||||
|         Args: | ||||
|             update_res (int): argument that is passed contains 0 or 1 | ||||
|         """ | ||||
|         if update_res == 1: | ||||
|             lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) | ||||
|             lines[1] = 'off\n'  | ||||
|             Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") | ||||
|  | ||||
|         else: | ||||
|             lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) | ||||
|             lines[1] = 'on\n'  | ||||
|             Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") | ||||
|  | ||||
|     @staticmethod | ||||
|     def tooltip(tip) -> None: | ||||
|         """ | ||||
|         write True or False in a file | ||||
|         Args: | ||||
|             tip (bool): argument that is passed contains True or False | ||||
|         """ | ||||
|         if tip: | ||||
|             lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) | ||||
|             lines[5] = 'False\n'  | ||||
|             Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") | ||||
|  | ||||
|         else: | ||||
|             lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) | ||||
|             lines[5] = 'True\n'  | ||||
|             Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") | ||||
|  | ||||
|     @staticmethod | ||||
|     def about() -> None: | ||||
|         """ | ||||
|         a tk.Toplevel window | ||||
|         """ | ||||
|         def link_btn() -> str | None: | ||||
|             webbrowser.open("https://git.ilunix.de/punix/Wire-Py") | ||||
|  | ||||
|         msg_t = _("Wire-Py a simple Wireguard Gui for Linux systems.\n\n" | ||||
|                 "Wire-Py is open source software written in Python.\n\n" | ||||
|                 "Email: polunga40@unity-mail.de also likes for donation.\n\n" | ||||
|                 "Use without warranty!\n") | ||||
|  | ||||
|         LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_vpn"], _("Info"), msg_t, _("Go to Wire-Py git"), link_btn) | ||||
|  | ||||
|     def theme_change_light(self) -> None: | ||||
|         """ | ||||
|         Set a light theme | ||||
|         """ | ||||
|         if self.tk.call("ttk::style", "theme", "use") == "water-dark": | ||||
|             self.tk.call("set_theme", "light") | ||||
|             lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)  # (keepends=True) = not changed | ||||
|             lines[3] = 'light\n'  | ||||
|             Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") | ||||
|             self.color_label() | ||||
|  | ||||
|     def theme_change_dark(self) -> None: | ||||
|         """ | ||||
|         Set a dark theme | ||||
|         """ | ||||
|         if not self.tk.call("ttk::style", "theme", "use") == "water-dark": | ||||
|             self.tk.call("set_theme", "dark") | ||||
|             lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True) | ||||
|             lines[3] = 'dark\n'  | ||||
|             Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") | ||||
|             self.color_label() | ||||
|  | ||||
|     def start(self) -> None: | ||||
|         """ | ||||
|         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.grid(column=0, row=0, padx=5, pady=8) | ||||
|  | ||||
|         tl = LxTools.get_file_name(AppConfig.TEMP_DIR) | ||||
|         if len(self.tl) == 0: | ||||
|             Tooltip(self.btn_stst, Msg.TTIP["empty_list"], self.tips_enabled) | ||||
|         else: | ||||
|             Tooltip(self.btn_stst, Msg.TTIP["start_tl"], self.tips_enabled) | ||||
|  | ||||
|     def handle_tunnel_data(self, tunnel_name: str) -> tuple[str, str, str, str | None]: | ||||
|         """_summary_ | ||||
|  | ||||
|         Args: | ||||
|             tunnel_name (str): name of a tunnel | ||||
|  | ||||
|         Returns: | ||||
|             tuple[str, str]: tuple with tunnel data | ||||
|         """ | ||||
|         wg_read = f"/tmp/tlecdcwg/{tunnel_name}.conf" | ||||
|         with open(wg_read, "r", encoding="utf-8") as file: | ||||
|             data = Tunnel.con_to_dict(file) | ||||
|             self.init_and_report(data) | ||||
|             self.show_data() | ||||
|             return data | ||||
|  | ||||
|     def color_label(self) -> None: | ||||
|         """ | ||||
|         View activ Tunnel in the color green or yellow | ||||
|         """ | ||||
|         lines = AppConfig.SETTINGS_FILE.read_text() | ||||
|         if "light\n" in lines: | ||||
|             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.config(font=("Ubuntu", 11, "bold")) | ||||
|         self.lb_tunnel.grid(column=2, padx=10, row=1) | ||||
|  | ||||
|     def stop(self) -> None: | ||||
|         """ | ||||
|         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.grid(column=0, row=0, padx=5, pady=8) | ||||
|  | ||||
|         Tooltip(self.btn_stst, Msg.TTIP["stop_tl"], self.tips_enabled) | ||||
|  | ||||
|     def reset_fields(self) -> None: | ||||
|         """ | ||||
|         reset data from labels | ||||
|         """ | ||||
|         fields = [self.add, self.DNS, self.enp] | ||||
|         for field in fields: | ||||
|             field.set("") | ||||
|  | ||||
|     def import_sl(self) -> None: | ||||
|         """validity check of wireguard config files""" | ||||
|  | ||||
|         Create.dir_and_files() | ||||
|         try: | ||||
|             filepath = filedialog.askopenfilename( | ||||
|                 initialdir=f"{Path.home()}",  | ||||
|                 title=_("Select Wireguard config File"), | ||||
|                 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: | ||||
|                 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"]) | ||||
|                     else: | ||||
|                         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:] | ||||
|                             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) | ||||
|                             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) | ||||
|                             Create.encrypt() | ||||
|                          | ||||
|                         self.str_var.set("") | ||||
|                         self.a = Tunnel.active() | ||||
|                         self.l_box.insert(0, self.a) | ||||
|                         self.wg_autostart.configure(state="normal") | ||||
|                         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.tips_enabled) | ||||
|                         Tooltip(self.btn_tr, Msg.TTIP["trash_tl"], self.tips_enabled) | ||||
|                         Tooltip(self.btn_exp, Msg.TTIP["export_tl"], self.tips_enabled) | ||||
|                         Tooltip(self.btn_rename, Msg.TTIP["rename_tl"], self.tips_enabled) | ||||
|                          | ||||
|                         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"]) | ||||
|             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"]) | ||||
|  | ||||
|         except EOFError as e: | ||||
|             print(e) | ||||
|         except TypeError: | ||||
|             print("File import: abort by user...") | ||||
|         except FileNotFoundError: | ||||
|             print("File import: abort by user...") | ||||
|         except subprocess.CalledProcessError: | ||||
|             print("Tunnel exist!") | ||||
|  | ||||
|     def delete(self) -> None: | ||||
|         """ | ||||
|         delete Wireguard Tunnel | ||||
|         """ | ||||
|         try: | ||||
|             self.select_tunnel = self.l_box.curselection() | ||||
|             select_tl = self.l_box.get(self.select_tunnel[0]) | ||||
|             with open(f"/tmp/tlecdcwg/{select_tl}.conf", "r+", encoding="utf-8") as file2: | ||||
|                 key = Tunnel.con_to_dict(file2) | ||||
|                 pre_key = key[3] | ||||
|             check_call(["nmcli", "connection", "delete", select_tl]) | ||||
|             self.l_box.delete(self.select_tunnel[0]) | ||||
|             with open(AppConfig.SETTINGS_FILE, "r", encoding="utf-8") as set_f6: | ||||
|                 lines6 = set_f6.readlines() | ||||
|                 if (select_tl == lines6[7].strip() | ||||
|                     and "off\n" not in lines6[7].strip()): | ||||
|                     lines6[7] = "off\n" | ||||
|                     with open(AppConfig.SETTINGS_FILE, "w", encoding="utf-8") as set_f7: | ||||
|                         set_f7.writelines(lines6) | ||||
|                     self.selected_option.set(0) | ||||
|                     self.autoconnect_var.set(_("no Autoconnect")) | ||||
|             is_encrypt = Path.home() / f".config/wire_py/{select_tl}.dat" | ||||
|             if is_encrypt.is_file(): | ||||
|                 Path.unlink(f"{Path.home()}/.config/wire_py/{select_tl}.dat") | ||||
|             Path.unlink(f"/tmp/tlecdcwg/{select_tl}.conf") | ||||
|             with open(AppConfig.KEYS_FILE, "r", encoding="utf-8") as readfile: | ||||
|                 with open(f"{Path.home()}/.config/wire_py/keys2", "w", encoding="utf-8") as writefile: | ||||
|                     for line in readfile: | ||||
|                         if pre_key not in line.strip("\n"): | ||||
|                             writefile.write(line) | ||||
|             file_one = Path(f"{Path.home()}/.config/wire_py/keys2") | ||||
|             file_two = file_one.with_name("keys") | ||||
|             file_one.replace(file_two) | ||||
|             self.wg_autostart.configure(state="disabled") | ||||
|  | ||||
|             # for disabling checkbox when Listbox empty | ||||
|             if self.l_box.size() == 0: | ||||
|                 self.wg_autostart.configure(state="disabled") | ||||
|                 self.lb_rename.configure(state="disabled") | ||||
|                 Tooltip(self.wg_autostart, _("You must have at least one\ntunnel in the list,to use the autostart") | ||||
|                         , self.tips_enabled) | ||||
|  | ||||
|                 Tooltip(self.btn_exp, _("No Tunnels in List for Export"), self.tips_enabled) | ||||
|                 Tooltip(self.btn_stst, _("No tunnels to start in the list"), self.tips_enabled) | ||||
|                 Tooltip(self.lb_rename, _("To rename a tunnel, at least one must be in the list"), tips, ) | ||||
|                 self.lb_rename.insert(0, _("Max. 12 characters!")) | ||||
|  | ||||
|             if self.a != "" and self.a == select_tl: | ||||
|                 self.str_var.set(value="") | ||||
|                 self.start() | ||||
|                 self.l_box.update() | ||||
|                 self.reset_fields() | ||||
|  | ||||
|         except IndexError: | ||||
|  | ||||
|             if self.l_box.size() != 0: | ||||
|  | ||||
|                 LxTools.msg_window(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"]) | ||||
|  | ||||
|     def enable_check_box(self, _) -> None: | ||||
|         """ | ||||
|         checkbox for enable autostart Tunnel | ||||
|         """ | ||||
|         Create.files_for_autostart() | ||||
|         if self.l_box.size() != 0: | ||||
|             self.wg_autostart.configure(state="normal") | ||||
|             self.lb_rename.config(state="normal") | ||||
|             self.lb_rename.delete(0, tk.END) | ||||
|             self.btn_rename.config(state="normal") | ||||
|  | ||||
|     def on_off(self) -> None: | ||||
|         """ | ||||
|         Here it is checked whether the path to the file is there, if not, it is created. | ||||
|         Set (on), the selected tunnel is displayed in the label. | ||||
|         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) | ||||
|  | ||||
|         if lines[7] != "off\n": | ||||
|             print(f"{lines[7]} starts automatically when the system starts.") | ||||
|             self.selected_option.set(1) | ||||
|             self.autoconnect_var.set("") | ||||
|             self.auto_con = lines[7] | ||||
|  | ||||
|         else: | ||||
|             self.selected_option.set(0) | ||||
|             self.auto_con = _("no Autoconnect") | ||||
|             print("Autostart disabled.") | ||||
|         self.autoconnect_var.set("") | ||||
|         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.config(font=("Ubuntu", 11)) | ||||
|         self.autoconnect.grid(column=1, row=0, sticky="e", pady=19) | ||||
|  | ||||
|     def box_set(self) -> None: | ||||
|         """ | ||||
|         Configures the autostart for a selected tunnel. | ||||
|  | ||||
|         This method is called when the user changes the autostart checkbox. | ||||
|         It saves the selected tunnel in the configuration file so that it | ||||
|         will be automatically connected at system startup. | ||||
|  | ||||
|         If the checkbox is deactivated, 'off' is written to the configuration file | ||||
|         to disable the autostart. | ||||
|         """ | ||||
|         try: | ||||
|             select_tunnel = self.l_box.curselection() | ||||
|             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") | ||||
|  | ||||
|                 tl = LxTools.get_file_name(AppConfig.TEMP_DIR) | ||||
|  | ||||
|                 if len(tl) == 0: | ||||
|                     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[7] = select_tl | ||||
|                 Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8") | ||||
|  | ||||
|         except IndexError: | ||||
|             self.selected_option.set(1) | ||||
|  | ||||
|         self.on_off() | ||||
|  | ||||
|     def tl_rename(self) -> None: | ||||
|         """ | ||||
|         method to rename a tunnel | ||||
|         """ | ||||
|         name_of_file = LxTools.get_file_name(AppConfig.TEMP_DIR) | ||||
|         special_characters = ["\\", "/", "{", "}", " "] | ||||
|  | ||||
|         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"]) | ||||
|  | ||||
|         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"]) | ||||
|  | ||||
|         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"]) | ||||
|  | ||||
|         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"]) | ||||
|  | ||||
|         else: | ||||
|  | ||||
|             try: | ||||
|                 self.select_tunnel = self.l_box.curselection() | ||||
|                 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) | ||||
|                 source = Path(f"/tmp/tlecdcwg/{select_tl}.conf") | ||||
|                 destination = source.with_name(f"{self.lb_rename.get()}.conf") | ||||
|                 source.replace(destination) | ||||
|                 Path.unlink(f"{Path.home()}/.config/wire_py/{select_tl}.dat") | ||||
|  | ||||
|                 self.l_box.delete(self.select_tunnel[0]) | ||||
|                 self.l_box.insert("end", self.lb_rename.get()) | ||||
|                 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: | ||||
|                         theme_set5.writelines(lines5) | ||||
|                     self.autoconnect_var.set(value=new_a_connect) | ||||
|                 self.update_connection_display() | ||||
|                 Create.encrypt() | ||||
|  | ||||
|             except IndexError: | ||||
|  | ||||
|                 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 activate_tunnel(self, tunnel_name): | ||||
|         """Activates a tunnel after a delay""" | ||||
|         try: | ||||
|             # First check if the tunnel exists in NetworkManager | ||||
|             nm_connections = subprocess.run( | ||||
|                 ["nmcli", "-t", "-f", "NAME", "connection", "show"], | ||||
|                 check=True, | ||||
|                 stdout=subprocess.PIPE, | ||||
|                 text=True | ||||
|             ).stdout.strip().split('\n') | ||||
|              | ||||
|             # Find the actual connection name (it might have been modified) | ||||
|             actual_name = None | ||||
|             for conn in nm_connections: | ||||
|                 if tunnel_name in conn: | ||||
|                     actual_name = conn | ||||
|                     break | ||||
|              | ||||
|             if actual_name: | ||||
|                 # Use the actual connection name | ||||
|                 subprocess.run(["nmcli", "connection", "up", actual_name],  | ||||
|                             check=True,  | ||||
|                             stdout=subprocess.PIPE,  | ||||
|                             stderr=subprocess.PIPE) | ||||
|             else: | ||||
|                 # Use the original name as fallback | ||||
|                 subprocess.run(["nmcli", "connection", "up", tunnel_name],  | ||||
|                             check=True,  | ||||
|                             stdout=subprocess.PIPE,  | ||||
|                             stderr=subprocess.PIPE) | ||||
|              | ||||
|             # After successful activation, update the display | ||||
|             self.a = Tunnel.active() | ||||
|             self.str_var.set(self.a) | ||||
|             self.color_label() | ||||
|              | ||||
|             # Try to load the tunnel data | ||||
|             try: | ||||
|                 data = self.handle_tunnel_data(self.a) | ||||
|                 self.init_and_report(data) | ||||
|                 self.show_data() | ||||
|                 self.stop() | ||||
|             except Exception as e: | ||||
|                 print(f"Error loading tunnel data: {e}") | ||||
|          | ||||
|         except subprocess.CalledProcessError as e: | ||||
|             print(f"Error activating tunnel: {e}", "hier simma") | ||||
|  | ||||
|     def init_and_report(self, data=None) -> None: | ||||
|         """ | ||||
|         Displays the value address, DNS and peer in the labels | ||||
|         or empty it again | ||||
|         """ | ||||
|         # Address Label | ||||
|         self.add = tk.StringVar() | ||||
|         self.add.set(f"{_("Address:    ")}{data[0]}") | ||||
|         self.DNS = tk.StringVar() | ||||
|         self.DNS.set(f"       DNS:   {data[1]}") | ||||
|         self.enp = tk.StringVar() | ||||
|         self.enp.set(f"{_("Endpoint:    ")}{data[2]}") | ||||
|  | ||||
|     def show_data(self) -> None: | ||||
|         """ | ||||
|         shows data in the label | ||||
|         """ | ||||
|         # Address Label | ||||
|         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)) | ||||
|  | ||||
|         # DNS Label | ||||
|         self.dns = ttk.Label(self.lb_frame, textvariable=self.DNS, foreground="#0071ff") | ||||
|         self.dns.grid(column=0, row=7, sticky="w", padx=10, pady=6) | ||||
|         self.dns.config(font=("Ubuntu", 9)) | ||||
|  | ||||
|         # Endpoint Label | ||||
|         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)) | ||||
|  | ||||
|     def wg_switch(self, event=None) -> None: | ||||
|         """ | ||||
|         Deals with switching the VPN connection | ||||
|         """ | ||||
|         try: | ||||
|             if self.a == "": | ||||
|                 self.select_tunnel = self.l_box.curselection() | ||||
|                 select_tl = self.l_box.get(self.select_tunnel[0]) | ||||
|                 self.handle_connection_state("start", select_tl) | ||||
|  | ||||
|             else: | ||||
|                  | ||||
|                 data = self.handle_tunnel_data(self.a) | ||||
|                 if data: | ||||
|  | ||||
|                     self.handle_connection_state("stop") | ||||
|  | ||||
|         except IndexError: | ||||
|  | ||||
|             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"]) | ||||
|  | ||||
|             else: | ||||
|  | ||||
|                 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: | ||||
|         """ | ||||
|         central management for connection states | ||||
|  | ||||
|         Args: | ||||
|             action (str): "start", "stop" or "toggle" | ||||
|             tunnel_name (str, optional): name of a tunnel for a start-option. defaults to None. | ||||
|         """ | ||||
|         if action == "stop": | ||||
|             if self.a: | ||||
|                 check_call(["nmcli", "connection", "down", self.a]) | ||||
|                 self.update_connection_display() | ||||
|                 self.reset_fields() | ||||
|                 self.start() | ||||
|  | ||||
|         elif action == "start": | ||||
|             if tunnel_name or self.a: | ||||
|                 target_tunnel = tunnel_name or self.a | ||||
|                 check_call(["nmcli", "connection", "up", target_tunnel]) | ||||
|                 self.update_connection_display() | ||||
|                 data = self.handle_tunnel_data(self.a) | ||||
|                 self.init_and_report(data) | ||||
|                 self.show_data() | ||||
|                 self.color_label() | ||||
|                 self.stop() | ||||
|  | ||||
|         elif action == "toggle": | ||||
|             if self.a: | ||||
|                 self.handle_connection_state("stop") | ||||
|             else: | ||||
|                 self.handle_connection_state("start") | ||||
|  | ||||
|     def update_connection_display(self) -> None: | ||||
|         """ | ||||
|         Updated the display after connection changes | ||||
|         """ | ||||
|         self.a = Tunnel.active() | ||||
|         if not hasattr(self, "str_var"): | ||||
|             self.str_var = tk.StringVar() | ||||
|         self.str_var.set(self.a) | ||||
|         self.color_label() | ||||
|         self.show_data() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|  | ||||
|     _ = AppConfig.setup_translations() | ||||
|     tips = LxTools.if_tip(AppConfig.SETTINGS_FILE) | ||||
|     LxTools.sigi(AppConfig.TEMP_DIR, AppConfig.USER_FILE) | ||||
|     window = Wirepy() | ||||
|     """ | ||||
|     the hidden files are hidden in Filedialog | ||||
|     """ | ||||
|     try: | ||||
|         window.tk.call("tk_getOpenFile", "-foobarbaz") | ||||
|     except TclError: | ||||
|         pass | ||||
|     window.tk.call("set", "::tk::dialog::file::showHiddenBtn", "0") | ||||
|     window.tk.call("set", "::tk::dialog::file::showHiddenVar", "0") | ||||
|     window.mainloop() | ||||
|  | ||||
| LxTools.clean_files(AppConfig.TEMP_DIR, AppConfig.USER_FILE) | ||||
| sys.exit(0) | ||||
| Before Width: | Height: | Size: 5.7 KiB | 
| Before Width: | Height: | Size: 5.7 KiB | 
| Before Width: | Height: | Size: 12 KiB | 
| Before Width: | Height: | Size: 10 KiB | 
| Before Width: | Height: | Size: 5.1 KiB | 
| Before Width: | Height: | Size: 1.6 KiB | 
| Before Width: | Height: | Size: 5.7 KiB | 
| Before Width: | Height: | Size: 2.2 KiB | 
| Before Width: | Height: | Size: 2.7 KiB | 
| Before Width: | Height: | Size: 2.7 KiB | 
							
								
								
									
										178
									
								
								wp_app_config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,178 @@ | ||||
| #!/usr/bin/python3 | ||||
| """App configuration for Wire-Py""" | ||||
|  | ||||
| import gettext | ||||
| 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/") | ||||
|  | ||||
|     # Base paths | ||||
|     BASE_DIR: Path = Path.home() | ||||
|     CONFIG_DIR: Path = BASE_DIR / ".config/wire_py" | ||||
|     TEMP_DIR: Path = Path("/tmp/tlecdcwg") | ||||
|     USER_FILE: Path = Path("/tmp/.log_user") | ||||
|  | ||||
|     # Configuration files | ||||
|     SETTINGS_FILE: Path = CONFIG_DIR / "settings" | ||||
|     KEYS_FILE: Path = CONFIG_DIR / "keys" | ||||
|     AUTOSTART_SERVICE: Path = Path.home() / ".config/systemd/user/wg_start.service" | ||||
|      | ||||
|     # Default settings | ||||
|     DEFAULT_SETTINGS: Dict[str, Any] = { | ||||
|         "updates": "on", | ||||
|         "theme": "light", | ||||
|         "tooltip": True, | ||||
|         "autostart": "off" | ||||
|     } | ||||
|      | ||||
|     # 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) | ||||
|     } | ||||
|      | ||||
|     # System-dependent paths | ||||
|     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" | ||||
|          | ||||
|     } | ||||
|      | ||||
|     # Images and icons paths | ||||
|     IMAGE_PATHS: Dict[str, str] = { | ||||
|         "icon_vpn": "/usr/share/icons/lx-icons/48/wg_vpn.png", | ||||
|         "icon_msg": "/usr/share/icons/lx-icons/48/wg_msg.png", | ||||
|         "icon_import": "/usr/share/icons/lx-icons/48/wg_import.png", | ||||
|         "icon_export": "/usr/share/icons/lx-icons/48/wg_export.png", | ||||
|         "icon_trash": "/usr/share/icons/lx-icons/48/wg_trash.png", | ||||
|         "icon_start": "/usr/share/icons/lx-icons/48/wg_vpn-start.png", | ||||
|         "icon_stop": "/usr/share/icons/lx-icons/48/wg_vpn-stop.png", | ||||
|         "icon_info": "/usr/share/icons/lx-icons/64/info.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 | ||||
|         """ | ||||
|         locale.bindtextdomain(AppConfig.APP_NAME, AppConfig.LOCALE_DIR) | ||||
|         gettext.bindtextdomain(AppConfig.APP_NAME, AppConfig.LOCALE_DIR) | ||||
|         gettext.textdomain(AppConfig.APP_NAME) | ||||
|         return gettext.gettext | ||||
|  | ||||
|     @classmethod | ||||
|     def ensure_directories(cls) -> None: | ||||
|         """Ensures that all required directories exist""" | ||||
|         cls.CONFIG_DIR.mkdir(parents=True, exist_ok=True) | ||||
|         cls.TEMP_DIR.mkdir(parents=True, exist_ok=True) | ||||
|      | ||||
|     @classmethod | ||||
|     def create_default_settings(cls) -> None: | ||||
|         """Creates default settings if they don't exist""" | ||||
|         if not cls.SETTINGS_FILE.exists(): | ||||
|             content = "\n".join(f"[{k.upper()}]\n{v}" for k, v in cls.DEFAULT_SETTINGS.items()) | ||||
|             cls.SETTINGS_FILE.write_text(content) | ||||
|      | ||||
|     @classmethod | ||||
|     def get_image_paths(cls) -> Dict[str, Path]: | ||||
|         """Returns paths to UI images""" | ||||
|         return { | ||||
|             "main_icon": cls.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" | ||||
|         } | ||||
|      | ||||
|     @classmethod | ||||
|     def get_autostart_content(cls) -> str: | ||||
|         """Returns the content for the autostart service file""" | ||||
|         return """[Unit] | ||||
| Description=Automatic Tunnel Start | ||||
| After=network-online.target | ||||
|  | ||||
| [Service] | ||||
| Type=oneshot | ||||
| ExecStartPre=/bin/sleep 5 | ||||
| ExecStart=/usr/local/bin/start_wg.py | ||||
| [Install] | ||||
| WantedBy=default.target""" | ||||
|  | ||||
| # 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"), | ||||
|         "ren_err": _("Renaming not possible"), | ||||
|         "exp_succ": _("Export successful"), | ||||
|         "exp_in_home": _("Your zip file is in home directory"), | ||||
|         "imp_err": _("Import Error"), | ||||
|         "exp_err": _("Export Error"), | ||||
|         "exp_try": _("Export failed! Please try again"), | ||||
|         "tl_first": _("Please first import tunnel"), | ||||
|         "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"), | ||||
|         "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") | ||||
|  | ||||
|     }     | ||||
|     TTIP: Dict[str, str] = { | ||||
|         #Strings for Tooltips | ||||
|         "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"), | ||||
|         "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"), | ||||
|         "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") | ||||
|  | ||||
|     } | ||||
|   | ||||