PobHelp/pobhelp.py
#!/usr/bin/env python3
import wx,wx.html,sys
from gui import *
from ftpd import *
from vncd import *
from guiUtils import *
import subprocess,os, urllib3 ,threading, ctypes,socket,time
# Python deps: wxpython4, urllib3, pyftpdlib, psutil(only win32),gettext_windows(only win32)
# Linux deps: x11vnc,tigervnc,openvpn,pkexec(polkit)
# Windows deps: all included in bundle
VERSION="0.1"
import locale, gettext
if (os.name=="nt"):
import gettext_windows
gettext_windows.setup_env()
try:
t = gettext.translation('pobhelp', getScriptDir()+os.sep+'locale')
_ = t.gettext
except:
_ = gettext.gettext
def find_procs_by_name(name):
import psutil
ls = []
for p in psutil.process_iter(['name']):
if p.info['name'] == name:
ls.append(p)
return ls
def getConfigDirPath():
from os.path import expanduser
home = expanduser("~")
if sys.platform == 'win32':
configDir=home+"\\AppData\\Local\\pobhelp\\"
elif sys.platform == 'linux':
configDir=home+"/.config/pobhelp/"
elif sys.platform== "darwin":
configDir=home+"/.config/pobhelp/"
else:
configDir=home+"/.config/pobhelp/"
return configDir
def getHomePath():
from os.path import expanduser
home = expanduser("~")
if sys.platform == 'win32':
configDir=home
elif sys.platform == 'linux':
configDir=home
elif sys.platform== "darwin":
configDir=home
else:
configDir=home
return configDir
def getScriptDir():
if getattr(sys, 'frozen', False):
return sys._MEIPASS
else:
return os.path.dirname(os.path.abspath(__file__))
class frmblackboard(TfrmBlackboard):
def __init__( self, parent ):
TfrmBlackboard.__init__( self, parent )
self.SetTitle(_("Blackboard"))
self.lblWriteHere.SetLabel(_("Write here:"))
self.btClose.SetLabel(_("Close"))
def onclose(self,evt):
self.Hide()
class dialogVpnClient(TdlgVpnClient):
host=None
port=None
p=None
def __init__( self, parent ):
TdlgVpnClient.__init__( self, parent )
self.lblHost.SetLabel(_("Host"))
self.lblPort.SetLabel(_("Port"))
self.btCancel.SetLabel(_("Cancel"))
self.btConnect.SetLabel(_("Connect"))
self.chkServerMode.SetLabel(_("Server mode"))
def onText(self,evt):
p=self.txtVpn.GetCaretPosition()
self.txtVpn.ScrollIntoView(p,wx.WXK_END)
def stopProcess(self,evt):
if (os.name=="posix"):
if (self.chkServerMode.GetValue()==False):
os.system("pkexec ip link delete dev phc")
else:
os.system("pkexec ip link delete dev phs")
out=subprocess.run(["ip", "link","show"],stdout=subprocess.PIPE)
wx.CallAfter(self.txtVpn.Clear)
wx.CallAfter(self.txtVpn.WriteText,out.stdout)
wx.CallAfter(self.txtVpn.WriteText,"\nif a device named 'phs' or 'phc' does not appear, the VPN is not active")
elif (os.name=="nt"):
os.system("taskkill /T /F /pid "+str(self.p.pid))
wx.CallAfter(self.chkServerMode.Enable, True)
vpnConfs=getConfigDirPath()+"phs.conf"
vpnConfc=getConfigDirPath()+"phc.conf"
if os.path.exists(vpnConfs): os.remove(vpnConfs)
if os.path.exists(vpnConfc): os.remove(vpnConfc)
def runProcessPosix(self,cmd):
wx.CallAfter(self.txtVpn.Clear)
wx.CallAfter(self.txtVpn.WriteText,"*** Starting vpn... ***\n")
subprocess.run(cmd,stdout=subprocess.PIPE)
out=subprocess.run(["ip", "link","show"],stdout=subprocess.PIPE)
wx.CallAfter(self.txtVpn.WriteText,out.stdout)
wx.CallAfter(self.txtVpn.WriteText,"\nif a device named 'phs' or 'phc' does not appear, the VPN is not active")
wx.CallAfter(self.btConnect.Enable, True)
wx.CallAfter(self.chkServerMode.Enable, False)
def runProcessWin(self,cmd):
self.p=subprocess.Popen(cmd, shell=True,bufsize=0 ,stdout=subprocess.PIPE)
wx.CallAfter(self.btConnect.Enable, False)
while self.p.poll() is None :
out = self.p.stdout.readline().decode("utf-8")
if (out) :
wx.CallAfter(self.txtVpn.WriteText,out)
wx.CallAfter(self.btConnect.Enable, True)
wx.CallAfter(self.txtVpn.WriteText,"*** VPN terminated. ***")
def setConn(self,event):
host=self.entryHostVpn.GetValue()
port=self.entryPortVpn.GetValue()
self.txtVpn.Clear()
if (self.chkServerMode.GetValue()==False):
#Client Mode Vpn
phc='''[Interface]
Address = 19.19.19.2/24
PrivateKey = sAPcPaK3UJ0h6a7fr7rTA/PEVNPZqgcJ+SPYKeqBYmQ=
[Peer]
PublicKey = 4oLQenWEyB2QpsspEvVnpGAQn6bP2aNqjthBlnZv4zw=
PresharedKey = Qikwbha9RHIeeCVDOvT3Op7U11LkIM78vcChJQgLr1o=
AllowedIPs = 19.19.19.0/24
Endpoint = {host}:{port}
PersistentKeepalive = 25
'''
phc = phc.replace("{port}", port)
phc = phc.replace("{host}", host)
vpnConf=getConfigDirPath()+"phc.conf"
f = open(vpnConf, "w")
f.write(phc)
f.close()
if (os.name=="posix"):
cmd=["pkexec" ,"wg-quick" ,"up",vpnConf]
thCmd = threading.Thread(target=self.runProcessPosix,args=(cmd,))
thCmd.daemon = True
thCmd.start()
elif (os.name=="nt"):
cmd=[getScriptDir()+"\Openvpn-bundle\openvpn.exe" ,"--cd",getScriptDir(), "--config", "client.ovpn", "--remote", host ,port]
print(cmd)
thCmd = threading.Thread(target=self.runProcessWin,args=(cmd,))
thCmd.daemon = True
thCmd.start()
else:
#Server mode Vpn
phs='''[Interface]
Address = 19.19.19.1/24
ListenPort = {port}
PrivateKey = YAd/aEUx7zIp8/IEQ7T9zdtwrbkduGFxagZErxoJknA=
[Peer]
#client 1
PublicKey = XJf+7fUIUfRBUeH8UnK8ngurmcZg8u8zUYRss5yPDVM=
PresharedKey = Qikwbha9RHIeeCVDOvT3Op7U11LkIM78vcChJQgLr1o=
AllowedIPs = 19.19.19.2/32
'''
phs = phs.replace("{port}", port)
vpnConf=getConfigDirPath()+"phs.conf"
f = open(vpnConf, "w")
f.write(phs)
f.close()
if (os.name=="posix"):
cmd=["pkexec" ,"wg-quick" ,"up",vpnConf]
thCmd = threading.Thread(target=self.runProcessPosix,args=(cmd,))
thCmd.daemon = True
thCmd.start()
elif (os.name=="nt"):
cmd=[getScriptDir()+"\Openvpn-bundle\openvpn.exe" ,"--cd",getScriptDir(), "--config", "server.ovpn", "--port", port]
thCmd = threading.Thread(target=self.runProcessWin,args=(cmd,))
thCmd.daemon = True
thCmd.start()
class mainWin(TPobhelpGui):
clientVpn=None
ftpdDialog=None
blackboard=None
vncServer=None
p=None
def __init__( self,parent ):
TPobhelpGui.__init__( self, parent )
self.menuBar.SetMenuLabel(3, _("Tools"))
self.menuBar.SetMenuLabel(4, _("Help"))
self.chkListen.SetLabel(_("Give help"))
self.lblHost.SetLabel(_("Hostname"))
self.lblPort.SetLabel(_("Port"))
self.btConnect.SetLabelMarkup(_("<b>Connect</b>"))
self.btDisconnect.SetLabelMarkup(_("<b>Disconnect</b>"))
self.mnuItemBlackboard.SetItemLabel(_("Blackboard"))
self.mnuRemminaVNCI.SetItemLabel(_("Run Remmina inverse vnc"))
self.manuItemQuit.SetItemLabel(_("Quit"))
self.mnuItemAbout.SetItemLabel(_("About"))
def showBlackboard(self,evt):
self.blackboard.Show()
def onAbout(self, evt):
import wx.adv
aboutInfo = wx.adv.AboutDialogInfo()
aboutInfo.SetName("Pobhelp")
aboutInfo.SetVersion(VERSION)
icon=os.path.join(getScriptDir(),'lifesaver.png')
aboutInfo.SetIcon(wx.Icon(icon, wx.BITMAP_TYPE_PNG))
aboutInfo.SetDescription(_("A simple gui for helpdesking"))
aboutInfo.SetCopyright(_("Released under GNU/GPL v2 License \n\n Author: Fabio Di Matteo - fadimatteo@gmail.com"))
aboutInfo.SetWebSite("https://github.com/pobfdm/pobhelp")
aboutInfo.AddDeveloper("Fabio Di Matteo - fadimatteo@gmail.com")
#aboutInfo.AddArtist("")
wx.adv.AboutBox(aboutInfo)
def genRemminaFile(self,port):
fileRemmina = '''
[remmina]
keymap=
colordepth=16
listenport=''' +port +'''
quality=9
ssh_tunnel_password=
postcommand=
server=
username=
name=VNC Listen Mode
ssh_tunnel_enabled=0
enable-autostart=0
password=
precommand=
disableclipboard=0
group=Casa
disablepasswordstoring=0
protocol=VNCI
disableencryption=0
viewonly=0
ssh_tunnel_server=
ssh_tunnel_loopback=0
ssh_tunnel_auth=0
ignore-tls-errors=1
ssh_tunnel_username=
ssh_tunnel_passphrase=
ssh_tunnel_privatekey=
notes_text=
showcursor=0
disableserverinput=0
window_maximize=0
window_width=1148
window_height=510
viewmode=1
scale=1
'''
textfile = open(getHomePath()+"/.config/pobhelp/inverse.remmina", "w")
textfile.write(fileRemmina)
textfile.close()
def getPublicIpRaw(self):
url = "http://api.ipify.org/?format=raw"
http = urllib3.PoolManager()
r = http.request('GET', url)
wx.CallAfter(self.entryHost.SetValue, r.data)
def saveLast(self):
f=os.path.join(getConfigDirPath(),"lastHost.conf")
self.entryHost.SaveFile(f)
f=os.path.join(getConfigDirPath(),"lastPort.conf")
self.entryPort.SaveFile(f)
def runCmd(self,cmd):
wx.CallAfter(self.statusBar.SetStatusText, "Connecting...")
time.sleep(1)
if (self.chkListen.GetValue()==True):
#Listen Mode
try:
self.p=subprocess.Popen(cmd,bufsize=50 ,stderr=subprocess.PIPE)
except:
cmd=(["vncviewer","-AlertOnFatalError","-Shared","-listen",self.entryPort.GetValue()])
self.p=subprocess.Popen(cmd,bufsize=50 ,stderr=subprocess.PIPE)
while self.p.poll() is None :
line = self.p.stderr.readline()
if ("Listening" in str(line)):
wx.CallAfter(self.statusBar.SetStatusText, "Listening...")
wx.CallAfter(self.statusBar.SetStatusText, _("Disconnected."))
wx.CallAfter(self.btConnect.Enable, True)
wx.CallAfter(self.btDisconnect.Enable, False)
wx.CallAfter(self.entryHost.Enable, True)
wx.CallAfter(self.entryPort.Enable, True)
else:
#Connect Mode
self.p=subprocess.Popen(cmd,bufsize=50 ,stderr=subprocess.PIPE)
while self.p.poll() is None :
line = self.p.stderr.readline()
if ("link_rate" in str(line)):
wx.CallAfter(self.statusBar.SetStatusText, "Connected.")
wx.CallAfter(self.statusBar.SetStatusText, _("Disconnected."))
wx.CallAfter(self.btConnect.Enable, True)
wx.CallAfter(self.btDisconnect.Enable, False)
wx.CallAfter(self.entryHost.Enable, True)
wx.CallAfter(self.entryPort.Enable, True)
def runCmdWin(self,cmd):
if (self.chkListen.GetValue()==True):
#Listen Mode
p=subprocess.Popen(cmd,shell=False)
startCheck=True
while(startCheck==True):
time.sleep(3)
if (len(find_procs_by_name("tvnviewer.exe"))>0):
wx.CallAfter(self.statusBar.SetStatusText, "Listening...")
else:
startCheck=False
wx.CallAfter(self.statusBar.SetStatusText, _("Disconnected."))
wx.CallAfter(self.btConnect.Enable, True)
wx.CallAfter(self.btDisconnect.Enable, False)
wx.CallAfter(self.entryHost.Enable, True)
wx.CallAfter(self.entryPort.Enable, True)
else:
#Connect mode
p=subprocess.Popen(cmd,shell=False)
startCheck=True
while(startCheck==True):
time.sleep(3)
if (len(find_procs_by_name("tvnserver.exe"))>2):
wx.CallAfter(self.statusBar.SetStatusText, "Connected.")
else:
startCheck=False
wx.CallAfter(self.statusBar.SetStatusText, _("Disconnected."))
wx.CallAfter(self.btConnect.Enable, True)
wx.CallAfter(self.btDisconnect.Enable, False)
wx.CallAfter(self.entryHost.Enable, True)
wx.CallAfter(self.entryPort.Enable, True)
def quit(self, event):
print("Quitting...")
try:
if (self.vncServer.p!=None):
self.vncServer.p.kill()
except:
print("Vnc server is sill alive!")
wx.CallAfter(sys.exit)
def chkListenClicked(self,event):
if (self.chkListen.GetValue()==True):
self.entryHost.SetValue("localhost")
publicIP = threading.Thread(target=self.getPublicIpRaw, args=())
publicIP.daemon = True
publicIP.start()
self.entryHost.Disable()
else:
self.entryHost.SetValue("")
self.entryHost.Enable()
self.entryPort.SetValue("")
def runRemminaVNCI(self,evt):
if not (self.entryPort.GetValue()):
Warn(self,"Fill port please!", 'Warning')
return
self.genRemminaFile(self.entryPort.GetValue())
cmd=(["remmina", "-c",getHomePath()+"/.config/pobhelp/inverse.remmina"])
try:
subprocess.Popen(cmd)
except:
Warn(self,"Remmina is not installed!", 'Warning')
def connect(self,event):
if not (self.entryHost.GetValue() and self.entryPort.GetValue()):
Warn(self,"Fill host and port please!", 'Warning')
return
if (self.chkVpnMode.GetValue()==True):
win.clientVpn.entryHostVpn.SetValue(self.entryHost.GetValue())
win.clientVpn.entryPortVpn.SetValue(self.entryPort.GetValue())
win.clientVpn.setConn(None)
self.btConnect.Disable()
self.btDisconnect.Enable()
self.entryHost.Disable()
self.entryPort.Disable()
self.saveLast()
if (self.chkListen.GetValue()==True):
#Listen Mode
self.statusBar.SetStatusText("Listen to port %s" % self.entryPort.GetValue())
if (os.name=="posix"):
self.genRemminaFile(self.entryPort.GetValue())
cmd=(["remmina", "-c",getHomePath()+"/.config/pobhelp/inverse.remmina"])
thCmd = threading.Thread(target=self.runCmd ,args=(cmd,))
thCmd.daemon = True
thCmd.start()
elif (os.name=="nt"):
cmd=([getScriptDir()+"/TightVNC-bundle/tvnviewer.exe", "-listen", "-port",self.entryPort.GetValue()])
self.entryPort.SetValue("5500")
#thCmd = threading.Thread(target=self.runCmdWin ,args=(cmd,))
#thCmd.daemon = True
#thCmd.start()
wx.CallAfter(self.statusBar.SetStatusText, "Listening...")
p=subprocess.Popen(cmd)
else:
#Connect Mode
if (os.name=="posix"):
self.startChecking=True
wx.CallAfter(self.statusBar.SetStatusText, "Connecting...")
cmd=(["x11vnc","--connect_or_exit",self.entryHost.GetValue()+":"+self.entryPort.GetValue()])
thCmd = threading.Thread(target=self.runCmd ,args=(cmd,))
thCmd.daemon = True
thCmd.start()
elif (os.name=="nt"):
cmd=([getScriptDir()+"/TightVNC-bundle/tvnserver.exe", "-controlservice", "-connect", self.entryHost.GetValue()+"::"+self.entryPort.GetValue()])
wx.CallAfter(self.statusBar.SetStatusText, _("Connecting..."))
subprocess.Popen(cmd)
#self.startChecking=True
wx.CallAfter(self.statusBar.SetStatusText, "Connecting...")
#thCmd = threading.Thread(target=self.runCmdWin ,args=(cmd,))
#thCmd.daemon = True
#thCmd.start()
def disconnect(self,event):
self.btConnect.Enable()
self.btDisconnect.Disable()
if (self.chkListen.GetValue()==True):
#Listen Mode
self.statusBar.SetStatusText("Disconnected to port %s" % self.entryPort.GetValue())
if (os.name=="posix"):
self.p.kill()
elif (os.name=="nt"):
cmd=(["taskkill","/im","tvnviewer.exe","/f"])
thCmd = threading.Thread(target=self.runCmd ,args=(cmd,))
thCmd.daemon = True
thCmd.start()
wx.CallAfter(self.statusBar.SetStatusText, _("Disconnected."))
wx.CallAfter(self.btConnect.Enable, True)
wx.CallAfter(self.btDisconnect.Enable, False)
wx.CallAfter(self.entryHost.Enable, True)
wx.CallAfter(self.entryPort.Enable, True)
else:
#Connect Mode
if (os.name=="posix"):
self.p.kill()
cmd=(["x11vnc","-remote","stop"])
thCmd = threading.Thread(target=self.runCmd ,args=(cmd,))
thCmd.daemon = True
thCmd.start()
self.p.kill()
elif (os.name=="nt"):
cmd=([getScriptDir()+"/TightVNC-bundle/tvnserver.exe","-controlservice", "-disconnectall" ])
p=subprocess.Popen(cmd)
wx.CallAfter(self.statusBar.SetStatusText, _(_("Disconnected.")))
wx.CallAfter(self.btConnect.Enable, True)
wx.CallAfter(self.btDisconnect.Enable, False)
wx.CallAfter(self.entryHost.Enable, True)
wx.CallAfter(self.entryPort.Enable, True)
def runVpnClient(self,event):
self.clientVpn.Show()
def runFTPDdialog(self, event):
self.ftpdDialog.Show()
def runVncServerDialog(self, event):
self.vncServer.Show()
if __name__ == '__main__':
#Change to script dir
os.chdir(os.path.dirname(os.path.realpath(__file__)))
app = wx.App()
win = mainWin(None)
win.clientVpn=dialogVpnClient(win)
win.ftpdDialog=dlgFTPD(win)
win.vncServer=frmVncServer(win)
win.ftpdDialog.entryUser.SetValue("admin")
win.ftpdDialog.entryPassword.SetValue("admin")
win.ftpdDialog.entryPort.SetValue("2121")
win.ftpdDialog.dirPkrFTPRoot.SetPath(getHomePath())
win.blackboard=frmblackboard(win)
win.blackboard.SetIcon(wx.Icon(getScriptDir()+"/lifesaver.ico"))
#if (os.name=="nt"):
# win.mnuVncServer.Enable(False)
try:
os.makedirs( getConfigDirPath(), 0o755 );
except FileExistsError:
f=os.path.join(getConfigDirPath(),"lastHost.conf")
if (os.path.isfile(f)):
win.entryHost.LoadFile(f)
f=os.path.join(getConfigDirPath(),"lastPort.conf")
if (os.path.isfile(f)):
win.entryPort.LoadFile(f)
win.statusBar.SetStatusText("Ready.")
win.SetIcon(wx.Icon(getScriptDir()+"/lifesaver.ico"))
win.btDisconnect.Disable()
win.Show(True)
app.MainLoop()