416 lines
13 KiB
Python
Executable File
416 lines
13 KiB
Python
Executable File
""" Wireguard Classes and Method for Wire-Py """
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import time
|
|
import tkinter as tk
|
|
import zipfile
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from subprocess import check_call
|
|
from tkinter import ttk
|
|
import requests
|
|
|
|
|
|
''' 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year '''
|
|
version = 'v. 1.10.2124'
|
|
|
|
path_to_file2 = Path('/etc/wire_py/settings.conf')
|
|
_u = Path.read_text(Path('/tmp/_u'))
|
|
|
|
UPDATE_API_URL = 'https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases'
|
|
|
|
|
|
class WirePyUpdate:
|
|
@staticmethod
|
|
def api_down():
|
|
try:
|
|
response = requests.get(UPDATE_API_URL)
|
|
response_dict = response.json()
|
|
response_dict = response_dict[0]
|
|
with open(path_to_file2, '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!'
|
|
|
|
@staticmethod
|
|
def download():
|
|
try:
|
|
url = f'https://git.ilunix.de/punix/Wire-Py/archive/{res}.zip'
|
|
to_down = 'wget -qP ' + str(_u) + ' ' + url
|
|
result = subprocess.call(to_down, shell=True)
|
|
if result == 0:
|
|
shutil.chown(str(_u) + f'/{res}.zip', 1000, 1000)
|
|
"""img_w, img_i, w_title, w_txt hand over"""
|
|
iw = r'/usr/share/icons/wp-icons/64/info.png'
|
|
ii = r'/usr/share/icons/wp-icons/48/wg_vpn.png'
|
|
wt = 'Download Successful'
|
|
msg_t = 'Your zip file is in home directory'
|
|
msg_window(iw, ii, wt, msg_t)
|
|
|
|
else:
|
|
"""img_w, img_i, w_title, w_txt hand over"""
|
|
iw = r'/usr/share/icons/wp-icons/64/error.png'
|
|
ii = r'/usr/share/icons/wp-icons/48/wg_msg.png'
|
|
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/wp-icons/64/error.png'
|
|
ii = r'/usr/share/icons/wp-icons/48/wg_msg.png'
|
|
wt = 'Download error'
|
|
msg_t = 'Download failed! No internet connection!'
|
|
msg_window(iw, ii, wt, msg_t)
|
|
|
|
|
|
res = WirePyUpdate.api_down()
|
|
|
|
|
|
|
|
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/wp-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
|
|
"""
|
|
|
|
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 != None and com != 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()
|
|
|
|
|
|
class Tunnel:
|
|
|
|
"""
|
|
Show the active tunnel in green or yellow in the label
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.StrVar = None
|
|
self.lb_tunnel = None
|
|
self.lb_frame2 = None
|
|
self.lb_frame = None
|
|
self.endpoint = None
|
|
self.dns = None
|
|
self.address = None
|
|
self.enp = None
|
|
self.DNS = None
|
|
self.add = None
|
|
|
|
def color(self):
|
|
with open(path_to_file2, 'r') as read_file:
|
|
lines = read_file.readlines()
|
|
if 'light\n' in lines:
|
|
self.lb_tunnel = ttk.Label(self, textvariable=self.StrVar, foreground='green')
|
|
|
|
else:
|
|
self.lb_tunnel = ttk.Label(self, textvariable=self.StrVar, foreground='yellow')
|
|
|
|
self.lb_tunnel.config(font=('Ubuntu', 11, 'bold'))
|
|
self.lb_tunnel.grid(column=2, padx=10, row=1)
|
|
|
|
|
|
"""
|
|
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):
|
|
|
|
dictlist = []
|
|
for lines in file.readlines():
|
|
line_plit = lines.split()
|
|
dictlist = dictlist + line_plit
|
|
dictlist.remove('[Interface]')
|
|
dictlist.remove('[Peer]')
|
|
for items in dictlist:
|
|
if items == '=':
|
|
dictlist.remove(items)
|
|
|
|
''' 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 = {}
|
|
for elements in new_list:
|
|
final_dict[elements[0]] = elements[1]
|
|
|
|
''' end... result a Dictionary '''
|
|
|
|
address = final_dict['Address']
|
|
dns = 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']
|
|
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()
|
|
if not active:
|
|
active = ''
|
|
else:
|
|
active = active[0]
|
|
|
|
return active
|
|
|
|
|
|
"""
|
|
Displays the value address, DNS and peer in the labels
|
|
or empty it again
|
|
"""
|
|
|
|
|
|
def init_and_report(self, data=None):
|
|
""" Address Label """
|
|
self.add = tk.StringVar()
|
|
self.add.set('Address: ' + data[0])
|
|
self.DNS = tk.StringVar()
|
|
self.DNS.set(' DNS: ' + data[1])
|
|
self.enp = tk.StringVar()
|
|
self.enp.set('Endpoint: ' + data[2])
|
|
|
|
def label_empty(self):
|
|
self.add.set('')
|
|
self.DNS.set('')
|
|
self.enp.set('')
|
|
|
|
def show_data(self):
|
|
""" 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))
|
|
|
|
|
|
"""
|
|
Shows all existing Wireguard tunnels
|
|
"""
|
|
|
|
@staticmethod
|
|
def list():
|
|
wg_s = os.popen('nmcli con show | grep -iPo "(.*)(wireguard)"').read().split()
|
|
|
|
''' tl = Tunnel list # Show of 4.Element in list '''
|
|
tl = wg_s[::3]
|
|
return tl
|
|
|
|
|
|
"""
|
|
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():
|
|
_u1 = str(_u[6:])
|
|
now_time = datetime.now()
|
|
now_datetime = now_time.strftime('wg-exp-' + '%m-%d-%Y' + '-' + '%H:%M')
|
|
tl = Tunnel.list()
|
|
|
|
try:
|
|
if len(tl) != 0:
|
|
wg_tar = str(_u) + '/' + now_datetime
|
|
shutil.copytree('/etc/wire_py', '/tmp/wire_py', dirs_exist_ok=True)
|
|
source = Path('/tmp/wire_py')
|
|
Path.unlink(Path(source) / 'wg_py', missing_ok=True)
|
|
Path.unlink(Path(source) / '.keys', missing_ok=True)
|
|
Path.unlink(Path(source) / 'settings.conf', missing_ok=True)
|
|
shutil.make_archive(wg_tar, 'zip', source)
|
|
shutil.chown(wg_tar + '.zip', 1000, 1000)
|
|
shutil.rmtree(source)
|
|
with zipfile.ZipFile((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/wp-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)
|
|
|
|
else:
|
|
|
|
"""img_w, img_i, w_title, w_txt hand over"""
|
|
iw = r'/usr/share/icons/wp-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)
|
|
|
|
else:
|
|
|
|
"""img_w, img_i, w_title, w_txt hand over"""
|
|
iw = r'/usr/share/icons/wp-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)
|
|
|
|
except TypeError:
|
|
pass
|
|
|
|
@staticmethod
|
|
def if_tip():
|
|
with open(path_to_file2, 'r') as set_file2:
|
|
lines2 = set_file2.readlines()
|
|
if 'False\n' in lines2:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
tips = Tunnel.if_tip()
|
|
|
|
class FileHandle:
|
|
"""
|
|
This class will display the autostart label which
|
|
Tunnel is automatically started regardless of the active tunnel.
|
|
The selected tunnel is written into a file to read it after the start of the system.
|
|
"""
|
|
|
|
def __init__(self):
|
|
|
|
self.wg_autostart = None
|
|
self.autoconnect = None
|
|
self.auto_con = None
|
|
self.autoconnect_var = None
|
|
self.tl = None
|
|
self.selected_option = None
|
|
self.l_box = None
|
|
|
|
def box_set(self):
|
|
|
|
try:
|
|
select_tunnel = self.l_box.curselection()
|
|
select_tl = self.l_box.get(select_tunnel[0])
|
|
|
|
if self.selected_option.get() == 0:
|
|
with open(path_to_file2, 'r') as set_file3:
|
|
lines3 = set_file3.readlines()
|
|
lines3[7] = 'off'
|
|
with open(path_to_file2, 'w') as set_file3:
|
|
set_file3.writelines(lines3)
|
|
|
|
tl = Tunnel.list()
|
|
|
|
if len(tl) == 0:
|
|
self.wg_autostart.configure(state='disabled')
|
|
|
|
if self.selected_option.get() >= 1:
|
|
with open(path_to_file2, 'r') as set_file3:
|
|
lines3 = set_file3.readlines()
|
|
lines3[7] = select_tl
|
|
with open(path_to_file2, 'w') as set_file3:
|
|
set_file3.writelines(lines3)
|
|
|
|
except IndexError:
|
|
self.selected_option.set(1)
|
|
|
|
OnOff.on_off(self)
|
|
|
|
|
|
class OnOff:
|
|
"""
|
|
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
|
|
"""
|
|
|
|
def __init__(self):
|
|
|
|
self.wg_autostart = None
|
|
self.selected_option = None
|
|
self.auto_con = None
|
|
self.autoconnect = None
|
|
self.autoconnect_var = None
|
|
self.lb_frame_buttons = None
|
|
|
|
def on_off(self):
|
|
with open(path_to_file2, 'r') as set_file4:
|
|
lines4 = set_file4.readlines()
|
|
|
|
if lines4[7] != 'off':
|
|
self.selected_option.set(1)
|
|
self.autoconnect_var.set('')
|
|
self.auto_con = lines4[7]
|
|
|
|
else:
|
|
|
|
self.wg_autostart.configure(state='disabled')
|
|
self.auto_con = 'no Autoconnect'
|
|
self.autoconnect_var.set('')
|
|
self.autoconnect_var = tk.StringVar()
|
|
self.autoconnect_var.set(self.auto_con)
|
|
|
|
self.autoconnect = ttk.Label(self, textvariable=self.autoconnect_var, foreground='#0071ff')
|
|
self.autoconnect.config(font=('Ubuntu', 11))
|
|
self.autoconnect.grid(column=0, row=4, sticky='ne', pady=19)
|