Compare commits
15 Commits
21-04-2025
...
28-04-2025
Author | SHA1 | Date | |
---|---|---|---|
0cdad100b6 | |||
2cdc40f414 | |||
2311661735 | |||
c10667ec21 | |||
08bef8fe6e | |||
2e94a324a6 | |||
18ed97bf20 | |||
5dcfc91621 | |||
5fb4e68867 | |||
19d413ea97 | |||
213f772f40 | |||
6f02724daa | |||
53f66ea76d | |||
3039dbecb0 | |||
eadc2a06bf |
6
.idea/workspace.xml
generated
6
.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 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" />
|
||||
@ -60,7 +64,7 @@
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"Shell Script.install.executor": "Run",
|
||||
"Shell Script.run_as.executor": "Run",
|
||||
"git-widget-placeholder": "21-04-2025-new-tooltip",
|
||||
"git-widget-placeholder": "28-04-2025-more-methods-and-optimize-methods",
|
||||
"last_opened_file_path": "/home/punix/Pyapps/wire-py",
|
||||
"settings.editor.selected.configurable": "ml.llm.LLMConfigurable"
|
||||
}
|
||||
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"workbench.settings.openDefaultSettings": true
|
||||
}
|
@ -41,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.
|
||||
|
Binary file not shown.
BIN
__pycache__/manage_tunnel.cpython-312.pyc
Normal file
BIN
__pycache__/manage_tunnel.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/wp_app_config.cpython-312.pyc
Normal file
BIN
__pycache__/wp_app_config.cpython-312.pyc
Normal file
Binary file not shown.
261
cls_mth_fc.py
261
cls_mth_fc.py
@ -14,16 +14,11 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from subprocess import check_call, CompletedProcess
|
||||
from tkinter import ttk, Toplevel
|
||||
|
||||
from wp_app_config import AppConfig, Msg
|
||||
import requests
|
||||
|
||||
APP = "wirepy"
|
||||
LOCALE_DIR = "/usr/share/locale/"
|
||||
locale.bindtextdomain(APP, LOCALE_DIR)
|
||||
gettext.bindtextdomain(APP, LOCALE_DIR)
|
||||
gettext.textdomain(APP)
|
||||
_ = gettext.gettext
|
||||
|
||||
# Translate
|
||||
_ = AppConfig.setup_translations()
|
||||
|
||||
class Create:
|
||||
"""
|
||||
@ -41,7 +36,7 @@ class Create:
|
||||
pth: Path = Path.home() / ".config/wire_py"
|
||||
pth.mkdir(parents=True, exist_ok=True)
|
||||
sett: Path = Path.home() / ".config/wire_py/settings"
|
||||
ks: Path = Path.home() / ".config/wire_py/keys"
|
||||
AppConfig.KEYS_FILE
|
||||
|
||||
if sett.exists():
|
||||
pass
|
||||
@ -50,11 +45,11 @@ class Create:
|
||||
sett.touch()
|
||||
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() -> None:
|
||||
@ -80,11 +75,10 @@ class Create:
|
||||
def make_dir() -> None:
|
||||
"""Folder Name "tlecdewg" = Tunnel Encrypt Decrypt Wireguard"""
|
||||
|
||||
folder_path: Path = Path("/tmp/tlecdcwg/")
|
||||
if folder_path.exists():
|
||||
if AppConfig.TEMP_DIR.exists():
|
||||
pass
|
||||
else:
|
||||
folder_path.mkdir()
|
||||
AppConfig.TEMP_DIR.mkdir()
|
||||
|
||||
@staticmethod
|
||||
def decrypt() -> None:
|
||||
@ -125,6 +119,31 @@ class LxTools(tk.Tk):
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def get_file_name(path: Path, i: int = 5) -> List[str]:
|
||||
"""
|
||||
Recursively searches the specified path for files and returns a list of filenames,
|
||||
with the last 'i' characters of each filename removed.
|
||||
|
||||
This method is useful for obtaining filenames without specific file extensions,
|
||||
e.g., to remove '.conf' from Wireguard configuration files.
|
||||
|
||||
Args:
|
||||
path (Path): The directory path to search
|
||||
i (int, optional): Number of characters to remove from the end of each filename.
|
||||
Default is 5, which typically corresponds to the length of '.conf'.
|
||||
|
||||
Returns:
|
||||
List[str]: A list of filenames without the last 'i' characters
|
||||
|
||||
Example:
|
||||
If path contains files like 'tunnel1.conf', 'tunnel2.conf' and i=5,
|
||||
the method returns ['tunnel1', 'tunnel2'].
|
||||
"""
|
||||
lists_file = list(path.rglob("*"))
|
||||
lists_file = [conf_file.name[:-i] for conf_file in lists_file]
|
||||
return lists_file
|
||||
|
||||
@staticmethod
|
||||
def uos() -> None:
|
||||
"""
|
||||
@ -135,19 +154,18 @@ class LxTools(tk.Tk):
|
||||
"""
|
||||
log_name: str = f"{Path.home()}"[6:]
|
||||
file: Path = Path.home() / "/tmp/.log_user"
|
||||
with open(file, "w", encoding="utf-8") as f:
|
||||
f.write(log_name)
|
||||
Path(file).write_text(log_name, encoding="utf-8")
|
||||
|
||||
@staticmethod
|
||||
def clean_files(folder_path: Path = None, file: Path = None) -> None:
|
||||
def clean_files(TEMP_DIR: Path = None, file: Path = None) -> None:
|
||||
"""
|
||||
method that can be added after need to delete a folder and a file when quitting.
|
||||
Args:
|
||||
:param file: default None
|
||||
:param folder_path: default None
|
||||
:param AppConfig.TEMP_DIR: default None
|
||||
"""
|
||||
if folder_path is not None:
|
||||
shutil.rmtree(folder_path)
|
||||
if AppConfig.TEMP_DIR is not None:
|
||||
shutil.rmtree(AppConfig.TEMP_DIR)
|
||||
if file is not None:
|
||||
Path.unlink(file)
|
||||
|
||||
@ -156,22 +174,21 @@ class LxTools(tk.Tk):
|
||||
"""
|
||||
method that writes in file whether tooltip is displayed or not
|
||||
"""
|
||||
with open(path, "r", encoding="utf-8") as set_f2:
|
||||
lines2 = set_f2.readlines()
|
||||
if "False\n" in lines2:
|
||||
tip = False
|
||||
else:
|
||||
tip = True
|
||||
return tip
|
||||
|
||||
lines = Path(path).read_text(encoding="utf-8")
|
||||
if "False\n" in lines:
|
||||
tip = False
|
||||
else:
|
||||
tip = True
|
||||
return tip
|
||||
|
||||
@staticmethod
|
||||
def msg_window(img_w: str, img_i: str, w_title: str, w_txt: str, txt2: Optional[str] = None,
|
||||
def msg_window(image_path: Path, image_path2: Path, w_title: str, w_txt: str, txt2: Optional[str] = None,
|
||||
com: Optional[str] = None) -> None:
|
||||
"""
|
||||
Creates message windows
|
||||
|
||||
:argument img_w = Image for TK window which is displayed to the left of the text
|
||||
:argument img_i = Image for Task Icon
|
||||
: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
|
||||
@ -181,7 +198,7 @@ class LxTools(tk.Tk):
|
||||
msg.resizable(width=False, height=False)
|
||||
msg.title(w_title)
|
||||
msg.configure(pady=15, padx=15)
|
||||
msg.img = tk.PhotoImage(file=img_w)
|
||||
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)
|
||||
@ -202,8 +219,8 @@ class LxTools(tk.Tk):
|
||||
button: ttk.Button = ttk.Button(msg, text="OK", command=msg.destroy, padding=4)
|
||||
button.grid(column=0, columnspan=2, row=1)
|
||||
|
||||
img_i: tk.PhotoImage = tk.PhotoImage(file=img_i)
|
||||
msg.iconphoto(True, img_i)
|
||||
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()
|
||||
@ -252,85 +269,10 @@ class LxTools(tk.Tk):
|
||||
signal.signal(signal.SIGHUP, signal_handler)
|
||||
|
||||
|
||||
class GiteaUpdate:
|
||||
"""
|
||||
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 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, img_w: str = None, img_i: str = None, img_w2: str = None, img_i2: str = None) -> None:
|
||||
"""
|
||||
Downloads new version of wirepy
|
||||
|
||||
Args:
|
||||
urld: Download URL
|
||||
res: Result filename
|
||||
img_w: Image for TK window which is displayed to the left of the text
|
||||
img_i: Image for Task Icon
|
||||
img_w2: Image for TK window which is displayed to the left of the text
|
||||
img_i2: 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(img_w, img_i, wt, msg_t)
|
||||
|
||||
else:
|
||||
|
||||
wt: str = _("Download error")
|
||||
msg_t: str = _("Download failed! Please try again")
|
||||
LxTools.msg_window(img_w2, img_i2, wt, msg_t)
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
|
||||
wt: str = _("Download error")
|
||||
msg_t: str = _("Download failed! No internet connection!")
|
||||
LxTools.msg_window(img_w2, img_i2, wt, msg_t)
|
||||
|
||||
|
||||
class Tunnel:
|
||||
"""
|
||||
Class of Methods for Wire-Py
|
||||
"""
|
||||
|
||||
"""
|
||||
@classmethod
|
||||
def con_to_dict(cls, file: TextIO) -> Tuple[str, str, str, Optional[str]]:
|
||||
"""
|
||||
@ -394,22 +336,23 @@ class Tunnel:
|
||||
"""
|
||||
Returns a list of Wireguard tunnel names
|
||||
"""
|
||||
folder_path: Path = Path("/tmp/tlecdcwg/")
|
||||
wg_s: List[str] = os.listdir(folder_path)
|
||||
AppConfig.TEMP_DIR: Path = Path("/tmp/tlecdcwg/")
|
||||
wg_s: List[str] = os.listdir(AppConfig.TEMP_DIR)
|
||||
|
||||
return wg_s
|
||||
|
||||
@staticmethod
|
||||
def export(img_w: str = None, img_i: str = None, img_w2: str = None, img_i2: str = None, sl: str = None, pfit:str = None) -> None:
|
||||
def export(image_path: Path = None, image_path2: Path = None, image_path3: Path = None, image_path4: Path = None,
|
||||
title: Dict = None, window_msg: Dict = None) -> None:
|
||||
"""
|
||||
This will export the tunnels.
|
||||
A zipfile with the current date and time is created
|
||||
in the user's home directory with the correct right
|
||||
Args:
|
||||
img_w: Image for TK window which is displayed to the left of the text
|
||||
img_i: Image for Task Icon
|
||||
img_w2: Image for TK window which is displayed to the left of the text
|
||||
img_i2: Image for Task Icon
|
||||
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")
|
||||
@ -425,22 +368,95 @@ class Tunnel:
|
||||
with zipfile.ZipFile(f"{wg_tar}.zip", "r") as zf:
|
||||
if len(zf.namelist()) != 0:
|
||||
|
||||
msg_t: str = _("Your zip file is in home directory")
|
||||
LxTools.msg_window(img_w, img_i, _("Export Successful"), 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:
|
||||
|
||||
msg_t: str = _("Export failed! Please try again")
|
||||
LxTools.msg_window(img_w2, img_i2, _("Export error"), msg_t)
|
||||
LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"], Msg.STR["exp_err"], Msg.STR["exp_try"])
|
||||
|
||||
else:
|
||||
|
||||
LxTools.msg_window(img_w, img_i2, sl, pfit)
|
||||
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 GiteaUpdate:
|
||||
"""
|
||||
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 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
|
||||
@ -485,6 +501,7 @@ class Tooltip:
|
||||
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:
|
||||
"""
|
||||
|
10
install
10
install
@ -17,7 +17,7 @@ install_file_with(){
|
||||
exit 0
|
||||
else
|
||||
sudo apt install python3-tk && \
|
||||
sudo cp -fv wirepy.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \
|
||||
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/ && \
|
||||
@ -43,7 +43,7 @@ install_arch_d(){
|
||||
exit 0
|
||||
else
|
||||
sudo pacman -S --noconfirm tk python3 python-requests && \
|
||||
sudo cp -fv wirepy.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \
|
||||
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/ && \
|
||||
@ -120,7 +120,7 @@ install(){
|
||||
exit 0
|
||||
else
|
||||
sudo dnf install python3-tkinter -y
|
||||
sudo cp -fv wirepy.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \
|
||||
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/ && \
|
||||
@ -145,7 +145,7 @@ install(){
|
||||
rm -r ~/.config/wire_py && rm -r ~/.config/systemd
|
||||
exit 0
|
||||
else
|
||||
sudo cp -fv wirepy.py start_wg.py cls_mth_fc.py ssl_encrypt.py ssl_decrypt.py /usr/local/bin/ && \
|
||||
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/ && \
|
||||
@ -181,7 +181,7 @@ install(){
|
||||
|
||||
remove(){
|
||||
sudo rm -f /usr/local/bin/wirepy /usr/local/bin/wirepy.py /usr/local/bin/start_wg.py \
|
||||
/usr/local/bin/cls_mth_fc.py /usr/local/bin/ssl_encrypt.py /usr/local/bin/ssl_decrypt.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
|
||||
|
15
manage_tunnel.py
Normal file
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()
|
||||
|
@ -5,31 +5,30 @@ import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from subprocess import check_call
|
||||
from wp_app_config import AppConfig
|
||||
|
||||
uname: Path = Path("/tmp/.log_user")
|
||||
|
||||
with open(uname, "r", encoding="utf-8") as f:
|
||||
log_name = f.readline()
|
||||
log_name = Path(uname).read_text(encoding="utf-8")
|
||||
|
||||
# Folder Name "tlecdewg" = Tunnel Encrypt Decrypt Wireguard
|
||||
folder_path: Path = Path("/tmp/tlecdcwg/")
|
||||
keyfile: Path = Path(f"/home/{log_name}/.config/wire_py/pbwgk.pem")
|
||||
PKEYFILE: Path = "/usr/local/etc/ssl/pwgk.pem"
|
||||
#PKEYFILE: Path = "/usr/local/etc/ssl/pwgk.pem"
|
||||
|
||||
if not keyfile.is_file():
|
||||
|
||||
check_call(["openssl", "rsa", "-in", 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)
|
||||
|
||||
folder_path2 = f"/home/{log_name}/.config/wire_py/"
|
||||
detl: list[str] = os.listdir(folder_path2)
|
||||
os.chdir(folder_path2)
|
||||
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"{folder_path2}pbwgk.pem"):
|
||||
if os.path.exists(f"{AppConfig.TEMP_DIR2}pbwgk.pem"):
|
||||
detl.remove("pbwgk.pem")
|
||||
for detunnels in detl:
|
||||
tlname2 = f"{detunnels[:-4]}.conf"
|
||||
extpath = f"{folder_path}/{tlname2}"
|
||||
check_call(["openssl", "pkeyutl", "-decrypt", "-inkey", PKEYFILE, "-in", detunnels, "-out", extpath])
|
||||
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)
|
||||
|
@ -5,43 +5,42 @@ import os
|
||||
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 = Path("/tmp/.log_user")
|
||||
#uname: Path = Path("/tmp/.log_user")
|
||||
|
||||
with open(uname, "r", encoding="utf-8") as f:
|
||||
log_name: str = f.readline()
|
||||
#log_name = AppConfig.USER_FILE.read_text(encoding="utf-8")
|
||||
|
||||
keyfile: Path = Path(f"/home/{log_name}/.config/wire_py/pbwgk.pem")
|
||||
folder_path: Path = 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 folder_path.exists():
|
||||
tl = os.listdir(f"{folder_path}")
|
||||
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 = f"{folder_path}/{tunnels}"
|
||||
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 folder_path.exists():
|
||||
tl: list[str] = os.listdir(f"{folder_path}")
|
||||
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 = f"{folder_path}/{tunnels}"
|
||||
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])
|
||||
|
15
start_wg.py
15
start_wg.py
@ -7,12 +7,9 @@ from subprocess import check_call
|
||||
|
||||
path_to_file = Path(Path.home() / ".config/wire_py/settings")
|
||||
|
||||
with open(path_to_file, "r", encoding="utf-8") as a_con:
|
||||
|
||||
# This function is for the independent autostarted of the previously selected tunnel
|
||||
lines = a_con.readlines()
|
||||
a_con = lines[7].strip()
|
||||
if a_con != "off":
|
||||
check_call(["nmcli", "connection", "up", a_con])
|
||||
else:
|
||||
pass
|
||||
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
|
||||
|
178
wp_app_config.py
Normal file
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")
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user