diff --git a/README.md b/README.md index 3552263..40b277d 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ mkminchroot ssh-multirun : Runs the same command on multiple machines +ssh-proxy +: Systray applet to enabled/disable an SSH proxy tunnel + ssh-reboot : Reboots a machine via `ssh` diff --git a/sshproxy b/sshproxy new file mode 100755 index 0000000..199a9e4 --- /dev/null +++ b/sshproxy @@ -0,0 +1,146 @@ +#!/usr/bin/env python + +# ©2020 Shzublox, BrainreckedTech +# Licensed under the GPL v3 + +import subprocess, wx, wx.adv + +PROGRAM_NAME = 'SSH Proxy' +STOPPED_ICON = "/usr/share/pixmaps/sshproxy-unused.png" +STARTED_ICON = "/usr/share/pixmaps/sshproxy-active.png" +DEFAULT_PORT = "8080" +DEFAULT_ADDR = "proxy" + +def create_menu_item(menu, label, func): + item = wx.MenuItem(menu, -1, label) + menu.Bind(wx.EVT_MENU, func, id=item.GetId()) + menu.Append(item) + return item + +class MyTaskBarIcon(wx.adv.TaskBarIcon): + def __init__(self, frame): + wx.adv.TaskBarIcon.__init__(self) + self.frame = frame + + self.SetIcon(self.frame.stopped_icon, PROGRAM_NAME) + self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.leftclicked) + + def CreatePopupMenu(self): + menu = wx.Menu() + create_menu_item(menu, 'Configure', self.configure) + create_menu_item(menu, 'Exit', self.frame.close) + return menu + + def leftclicked(self, event): + if self.frame.ssh: + self.frame.on_stop(None) + else: + self.frame.on_start(None) + + def configure(self, event): + self.frame.Show() + self.frame.Restore() + +class MyFrame(wx.Frame): + def __init__(self, parent, stopped_icon, started_icon): + wx.Frame.__init__(self, parent, title=PROGRAM_NAME, + style = wx.DEFAULT_FRAME_STYLE & + ~(wx.RESIZE_BORDER | wx.MINIMIZE_BOX + | wx.MAXIMIZE_BOX | wx.CLOSE_BOX)) + + self.ssh = None + self.stopped_icon = stopped_icon + self.started_icon = started_icon + + self.SetIcon(stopped_icon) + + self.tray = MyTaskBarIcon(self) + self.Bind(wx.EVT_ICONIZE, self.iconize) + self.Bind(wx.EVT_CLOSE, self.close) + + panel_sizer = wx.FlexGridSizer(cols=1) + text_sizer = wx.FlexGridSizer(cols=2) + button_sizer = wx.BoxSizer() + panel = wx.Panel(self) + + portlabel = wx.StaticText(panel, label="Port: ") + self.portbox = wx.TextCtrl(panel, value=DEFAULT_PORT, size=(300, -1)) + + remotelabel = wx.StaticText(panel, label="Remote: ") + self.remotebox = wx.TextCtrl(panel, value=DEFAULT_ADDR, size=(300, -1)) + + self.startbutton = wx.Button(panel, label="Start") + self.stopbutton = wx.Button(panel, label="Stop") + + self.stopbutton.Disable() + + text_sizer.Add(portlabel, 1, wx.EXPAND) + text_sizer.Add(self.portbox, 1, wx.EXPAND) + text_sizer.Add(remotelabel, 1, wx.EXPAND) + text_sizer.Add(self.remotebox, 1, wx.EXPAND) + text_sizer.Fit(self) + + button_sizer.Add(self.startbutton, 1, wx.EXPAND) + button_sizer.Add(self.stopbutton, 1, wx.EXPAND) + button_sizer.Fit(self) + + panel_sizer.Add(text_sizer, 1, wx.EXPAND) + panel_sizer.Add(button_sizer, 1, wx.EXPAND) + panel_sizer.Fit(self) + + self.startbutton.Bind(wx.EVT_BUTTON, self.on_start) + self.stopbutton.Bind(wx.EVT_BUTTON, self.on_stop) + + self.SetSizer(panel_sizer) + + def close(self, event): + self.tray.RemoveIcon() + self.tray.Destroy() + self.Destroy() + + def iconize(self, event): + if self.IsIconized(): + self.Show(False) + self.Restore() + + def on_start(self, event): + if self.portbox.GetValue() == "" or self.remotebox.GetValue() == "": + return + + self.startbutton.Disable() + self.stopbutton.Enable() + self.tray.SetIcon(self.started_icon) + self.ssh = subprocess.Popen(["ssh", "-ND", + "%s" % self.portbox.GetValue(), + "%s" % self.remotebox.GetValue()], + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE, + universal_newlines = True) + + def on_stop(self, event): + self.startbutton.Enable() + self.stopbutton.Disable() + self.tray.SetIcon(self.stopped_icon) + if self.ssh: + self.ssh.terminate() + self.ssh = None + +def main(): + app = wx.App(False) + + image = wx.Image(STOPPED_ICON, wx.BITMAP_TYPE_ANY) + bmp = wx.Bitmap(image) + stopped_icon = wx.Icon() + stopped_icon.CopyFromBitmap(bmp) + + image = wx.Image(STARTED_ICON, wx.BITMAP_TYPE_ANY) + bmp = wx.Bitmap(image) + started_icon = wx.Icon() + started_icon.CopyFromBitmap(bmp) + + frame = MyFrame(None, stopped_icon, started_icon) + app.MainLoop() + +if __name__ == "__main__": + main() diff --git a/sshproxy-active.png b/sshproxy-active.png new file mode 100644 index 0000000..004d4bc Binary files /dev/null and b/sshproxy-active.png differ diff --git a/sshproxy-unused.png b/sshproxy-unused.png new file mode 100644 index 0000000..0bd6d1e Binary files /dev/null and b/sshproxy-unused.png differ