From d6a4a0588c83f9bc21e3d5017a0006a3051fecc7 Mon Sep 17 00:00:00 2001 From: Mikael Nordin Date: Thu, 26 Nov 2020 16:56:06 +0100 Subject: [PATCH] v0.0.2 --- MANIFEST.in | 1 + build/lib/wireguide/logo.png | Bin 0 -> 7699 bytes build/lib/wireguide/wireguide | 392 ++++++++++++++++++++++++++ dist/wireguide-0.0.1-py3-none-any.whl | Bin 18419 -> 30444 bytes dist/wireguide-0.0.1.tar.gz | Bin 5871 -> 15028 bytes setup.py | 3 +- wireguide.egg-info/PKG-INFO | 7 +- wireguide.egg-info/SOURCES.txt | 2 + wireguide/wireguide | 2 +- 9 files changed, 400 insertions(+), 7 deletions(-) create mode 100644 MANIFEST.in create mode 100644 build/lib/wireguide/logo.png create mode 100755 build/lib/wireguide/wireguide diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..872256e --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include wireguide/logo.png diff --git a/build/lib/wireguide/logo.png b/build/lib/wireguide/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9ada82d554931f2ab94ef4e525edde46c4631629 GIT binary patch literal 7699 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 E1M+Eq+5i9m literal 0 HcmV?d00001 diff --git a/build/lib/wireguide/wireguide b/build/lib/wireguide/wireguide new file mode 100755 index 0000000..5e85216 --- /dev/null +++ b/build/lib/wireguide/wireguide @@ -0,0 +1,392 @@ +#!/usr/bin/env python3 +""" +This is a program that can manage Wireguard Configuration graphically +""" +import configparser +import os +import re +import sys +import uuid +from socket import AF_INET + +import gi +import wx +import wx.adv + +gi.require_version("NM", "1.0") +from gi.repository import NM # pylint: disable=wrong-import-position + + +class WireFrame(wx.Frame): # pylint: disable=too-many-ancestors,too-many-instance-attributes + """ + The WireGUIde wx.Frame + """ + def __init__(self, *args, **kw): + super().__init__(*args, **kw) + + self.version = 0.1 + + # Get active conns from NetworkManager + self.client = NM.Client.new(None) + self.conns = self.get_wg_conns() + self.active_conns = self.get_wg_aconns() + + # Set up for loaded configs + self.inactive_conns = get_inactive_conns() + + # create a panel in the frame + self.pnl = wx.Panel(self) + + # and create a sizer to manage the layout of child widgets + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.write_to_sizer() + self.pnl.SetSizer(self.sizer) + + # create a menu bar + self.make_menu_bar() + + # and a status bar + self.statusbar = self.CreateStatusBar(style=wx.BORDER_NONE) + self.set_status() + + self.timer = wx.Timer(self) + self.count = 0 + + self.Bind(wx.EVT_TIMER, self.do_on_timer) + self.Bind(wx.EVT_PAINT, self.timing) + self.Show() + + def about_clicked(self, event): # pylint: disable=unused-argument + """Display an About Dialog""" + about = "WireGUIde is a GUI for WireGuard." + lic_text = """ + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see .""" + #wx.MessageBox(about, "About WireGUIde" ,wx.OK | wx.ICON_INFORMATION) + info = wx.adv.AboutDialogInfo() + info.SetIcon(wx.Icon('logo.png', wx.BITMAP_TYPE_PNG)) + info.SetName('WireGUIde') + info.SetVersion(str(self.version)) + info.SetDescription(about) + info.SetCopyright('(C) 2020 Mikael Nordin') + info.SetWebSite('https://github.com/mickenordin') + info.SetLicence(lic_text) + info.AddDeveloper('Mikael Nordin') + info.AddDocWriter('Mikael Nordin') + info.AddArtist('Mikael Nordin') + + wx.adv.AboutBox(info) + + def activate_button_clicked(self, event, conn): # pylint: disable=unused-argument + """ + This activates an imported config + """ + print(conn.get_id()) + self.client.add_connection_async(conn, False, None, self.add_callback, + None) + self.remove_inactive(conn) + + def add_callback(self, client, result, data): # pylint: disable=unused-argument + """ + This is here to let us know if the connection was successful or not + """ + try: + client.add_connection_finish(result) + print( + "The connection profile has been successfully added to NetworkManager." + ) + except Exception as exception: # pylint: disable=broad-except + sys.stderr.write("Error: %s\n" % exception) + self.active_conns = self.get_wg_aconns() + self.conns = self.get_wg_conns() + self.write_to_sizer() + + def create_conn_from_file(self, pathname): + """ + Read a WireGuardUI config file and convert it in to + an object that can be user by NetworkManager + """ + filename = os.path.basename(pathname) + try: + config = configparser.ConfigParser() + config.read(pathname) + iname = self.get_next_int_name() + profile = NM.SimpleConnection.new() + s_con = NM.SettingConnection.new() + s_con.set_property(NM.SETTING_CONNECTION_ID, iname) + s_con.set_property(NM.SETTING_CONNECTION_INTERFACE_NAME, iname) + s_con.set_property(NM.SETTING_CONNECTION_UUID, str(uuid.uuid4())) + s_con.set_property(NM.SETTING_CONNECTION_TYPE, + NM.SETTING_WIREGUARD_SETTING_NAME) + + s_wireguard = NM.SettingWireGuard.new() + s_wireguard.set_property(NM.SETTING_WIREGUARD_PRIVATE_KEY, + config['Interface']['PrivateKey']) + s_peer = NM.WireGuardPeer.new() + s_peer.set_endpoint(config['Peer']['Endpoint'], False) + s_peer.set_public_key(config['Peer']['PublicKey'], False) + s_peer.append_allowed_ip(config['Peer']['AllowedIPs'], False) + s_wireguard.append_peer(s_peer) + + s_ip4 = NM.SettingIP4Config.new() + s_ip4_address = NM.IPAddress(AF_INET, + config['Interface']['Address'], + int(32)) + s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "manual") + s_ip4.add_address(s_ip4_address) + s_ip4.add_dns(config['Interface']['DNS']) + + profile.add_setting(s_con) + profile.add_setting(s_ip4) + profile.add_setting(s_wireguard) + return profile + + except IOError: + wx.LogError("Cannot open file '%s'." % filename) + return None + + def deactivate_button_clicked(self, event, conn): # pylint: disable=unused-argument + """ + This deactivates an active config + """ + print(conn.get_id()) + self.client.deactivate_connection_async(conn, None, self.de_callback, + conn) + conn.get_connection().delete_async(None, None, None) + + def de_callback(self, client, result, data): # pylint: disable=unused-argument + """ + This is here to let us know if the deactivation was successful or not + """ + try: + client.deactivate_connection_finish(result) + print( + "The connection profile has been successfully removed from NetworkManager." + ) + except Exception as exception: # pylint: disable=broad-except + sys.stderr.write("Error: %s\n" % exception) + self.active_conns = self.get_wg_aconns() + self.conns = self.get_wg_conns() + self.write_to_sizer() + + def do_on_timer(self, event): # pylint: disable=unused-argument + """ + Do stuff to redraw the window when the timer times out + Ths is because connections might change outside of WireGUIde + """ + self.count += 1 + if self.count == 5: + self.client.reload_connections_async() + self.active_conns = self.get_wg_aconns() + self.conns = self.get_wg_conns() + self.set_status() + self.write_to_sizer() + self.count = 0 + + def exit_clicked(self, event): # pylint: disable=unused-argument + """ + Close the frame, terminating the application. + """ + self.Close(True) + + def file_chooser_clicked(self, event): # pylint: disable=unused-argument + """ + This is what happens when you click on the file chooser + """ + with wx.FileDialog(self, + "Open WireGuard config file", + wildcard="WireGuard files (*.conf)|*.conf", + style=wx.FD_OPEN + | wx.FD_FILE_MUST_EXIST) as file_dialog: + + if file_dialog.ShowModal() == wx.ID_CANCEL: + return # the user changed their mind + + # Proceed loading the file chosen by the user + pathname = file_dialog.GetPath() + new_conn = self.create_conn_from_file(pathname) + self.inactive_conns.append(new_conn) + self.write_to_sizer() + + def get_next_int_name(self): + """ + Determins what we should call the next interface + """ + temp = [] + for conn in self.conns: + temp.append(re.findall(r'\d+', conn.get_interface_name())) + for conn in self.inactive_conns: + temp.append(re.findall(r'\d+', conn.get_interface_name())) + numbers = [int(item) for sublist in temp for item in sublist] + if not numbers: + num = 0 + else: + numbers.sort(reverse=True) + num = numbers[0] + 1 + return "wg" + str(num) + + def get_wg_aconns(self): + """ + Reads all active wireguard connections from NetworkManager + and returns them as objects in an array + """ + mconns = [] + wgconns = self.client.get_active_connections() + for conn in wgconns: + if conn.get_connection_type() == NM.SETTING_WIREGUARD_SETTING_NAME: + mconns.append(conn) + return mconns + + def get_wg_conns(self): + """ + Reads all current wireguard connections from NetworkManager + and returns them as objects in an array + """ + mconns = [] + wgconns = self.client.get_connections() + for conn in wgconns: + if conn.get_connection_type() == NM.SETTING_WIREGUARD_SETTING_NAME: + mconns.append(conn) + return mconns + + def make_menu_bar(self): + """ + A menu bar is composed of menus, which are composed of menu items. + This method builds a set of menus and binds handlers to be called + when the menu item is selected. + """ + + file_menu = wx.Menu() + file_chooser_item = file_menu.Append(-1, "&Open...\tCtrl-O", + "Select WireGuard config file") + file_menu.AppendSeparator() + exit_item = file_menu.Append(wx.ID_EXIT) + + help_menu = wx.Menu() + about_item = help_menu.Append(wx.ID_ABOUT) + + menu_bar = wx.MenuBar() + menu_bar.Append(file_menu, "&File") + menu_bar.Append(help_menu, "&Help") + + self.SetMenuBar(menu_bar) + + self.Bind(wx.EVT_MENU, self.file_chooser_clicked, file_chooser_item) + self.Bind(wx.EVT_MENU, self.exit_clicked, exit_item) + self.Bind(wx.EVT_MENU, self.about_clicked, about_item) + + def remove_inactive(self, conn): + """ + Remove the inactive connection from the array + """ + for i in range(len(self.inactive_conns)): + if self.inactive_conns[i].get_id() == conn.get_id(): + self.inactive_conns.pop(i) + + def set_status(self): + """ + Update the status bar + """ + status = str(len(self.active_conns)) + " active connection(s)" + self.statusbar.SetStatusText(status) + + def timing(self, event): # pylint: disable=unused-argument + """ + Start a timer + """ + self.timer.Start(20) + + def write_to_sizer(self): + """ + We use the BoxSizer to hold our configs + This method redraws the sizer + """ + self.sizer.Clear(delete_windows=True) + if len(self.active_conns) > 0: + hd1 = wx.StaticText(self.pnl) + hd1.SetLabelMarkup("Active connections") + self.sizer.Add(hd1, 0, wx.ALIGN_CENTER) + for conn in self.active_conns: + statstr = wx.StaticText(self.pnl) + info = get_info_as_text(conn) + statstr.SetLabelMarkup(info) + self.sizer.Add(statstr, + wx.SizerFlags().Border(wx.TOP | wx.LEFT, 25)) + dbtn = wx.Button(self.pnl, -1, "Deactivate") + self.sizer.Add(dbtn, 0, wx.ALIGN_CENTER) + self.Bind(wx.EVT_BUTTON, + lambda event, mconn=conn: self. + deactivate_button_clicked(event, mconn), + dbtn) + if len(self.inactive_conns) > 0: + hd2 = wx.StaticText(self.pnl) + hd2.SetLabelMarkup("Imported configs") + self.sizer.Add(hd2, 0, wx.ALIGN_CENTER) + if self.inactive_conns: + for conn in self.inactive_conns: + statstr = wx.StaticText(self.pnl) + info = get_info_as_text(conn) + statstr.SetLabelMarkup(info) + self.sizer.Add( + statstr, + wx.SizerFlags().Border(wx.TOP | wx.LEFT, 25)) + btn = wx.Button(self.pnl, -1, "Activate") + self.sizer.Add(btn, 0, wx.ALIGN_CENTER) + self.Bind(wx.EVT_BUTTON, + lambda event, mconn=conn: self. + activate_button_clicked(event, mconn), + btn) + if (len(self.active_conns) == 0) and (len(self.inactive_conns) == 0): + hd0 = wx.StaticText(self.pnl) + hd0.SetLabelMarkup("No configs available") + missingstr = wx.StaticText(self.pnl) + missingstr.SetLabelMarkup( + "Please choose a config file from the file menu (CTRL+O).") + self.sizer.Add(hd0, 0, wx.ALIGN_CENTER) + self.sizer.Add(missingstr, 0, wx.ALIGN_LEFT) + self.sizer.Layout() + + +def get_inactive_conns(): + """ + TODO: Not implemented yet + """ + minactive_conns = [] + #return empty array for now, we cant read configs from stash yet + return minactive_conns + + +def get_info_as_text(aconn): + """ + Returns info about a connection as text + """ + try: + conn = aconn.get_connection() + except Exception: # pylint: disable=broad-except + conn = aconn + mid = conn.get_id() + miname = conn.get_interface_name() + muuid = conn.get_uuid() + info = "id: " + mid + '\n' + info += "interface name: " + miname + '\n' + info += "uuid: " + muuid + '\n' + return info + + +if __name__ == '__main__': + # When this module is run (not imported) then create the app, the + # frame, show it, and start the event loop. + app = wx.App() + frm = WireFrame(None, title='WireGUIde') + frm.Show() + app.MainLoop() diff --git a/dist/wireguide-0.0.1-py3-none-any.whl b/dist/wireguide-0.0.1-py3-none-any.whl index d95d76fe881da82db84d0a26c37998ab79a3fab8..cfb132a3e030d6584fa52bfb50addd4178ededdb 100644 GIT binary patch delta 13432 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 delta 1462 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 literal 5871 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