125 lines
5.2 KiB
Python
125 lines
5.2 KiB
Python
|
import paramiko, os, sys, subprocess, get_runtime, wx # , keyring
|
||
|
from typing import NoReturn
|
||
|
from ui import Frame
|
||
|
from threading import Thread
|
||
|
|
||
|
|
||
|
def main():
|
||
|
host = frame.host.GetValue()
|
||
|
localhost = frame.localhost.GetValue()
|
||
|
netid = frame.net_id.GetValue()
|
||
|
sshPass = frame.password.GetValue()
|
||
|
password = frame.vnc_passwd.GetValue()
|
||
|
kill_when_exit = frame.kill_when_exit.GetValue()
|
||
|
|
||
|
if not host or not localhost or not netid or not sshPass or not password:
|
||
|
wx.MessageBox("At least one of the box are left empty. Please make sure you fill out ALL boxes!!",
|
||
|
"Empty Input", wx.ICON_ERROR)
|
||
|
return
|
||
|
frame.run.Enable(False)
|
||
|
ssh = paramiko.SSHClient()
|
||
|
sys.stdout.write(f'connecting to {host}\n')
|
||
|
frame.status.SetLabelText(f'connecting to host')
|
||
|
port = get_server(ssh, host, netid, sshPass, password)
|
||
|
if int(port) == -1:
|
||
|
wx.MessageBox("Your netID and password for that netID does not match the one in the ECE system!", "Wrong "
|
||
|
"Credentials", wx.ICON_ERROR)
|
||
|
frame.run.Enable(True)
|
||
|
frame.status.SetLabelText(u"Click 'RUN' to begin, hover over any boxes to show hints")
|
||
|
return
|
||
|
display = port
|
||
|
if int(port) < 10:
|
||
|
port = "0" + port
|
||
|
port = "59" + port
|
||
|
java = os.path.join(get_runtime.RUNTIME_PATH, get_runtime.get_java_path())
|
||
|
frame.status.SetLabelText(f'initializing java')
|
||
|
vnc_cmd = f'{java} -jar VNC_UWEE.jar -host="{localhost}" -port="{port}" -sshHost="{host}" -sshUser="{netid}" -sshPassword="{sshPass}" -password="{password}"'
|
||
|
frame.status.SetLabelText(f'VNC session started!')
|
||
|
out = subprocess.Popen(vnc_cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
|
||
|
stdout, stderr = out.communicate()
|
||
|
open("launcher.log", "w").write(stderr.decode('utf-8'))
|
||
|
if out.returncode:
|
||
|
sys.stderr.write(f"{stderr.decode('utf-8')}\nProgram crashed with code {out.returncode}")
|
||
|
|
||
|
if kill_when_exit:
|
||
|
kill_srv(ssh, host, netid, sshPass, display)
|
||
|
frame.run.Enable(True)
|
||
|
frame.status.SetLabelText(u"Click 'RUN' to begin, hover over any boxes to show hints")
|
||
|
|
||
|
|
||
|
def get_server(client: paramiko.SSHClient, host: str, username: str, password: str, vnc_passwd: str) -> str:
|
||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||
|
try:
|
||
|
client.connect(host, username=username, password=password)
|
||
|
except paramiko.ssh_exception.AuthenticationException:
|
||
|
return '-1'
|
||
|
sys.stdout.write("connected, sending command\n")
|
||
|
ssh_stdin, ssh_stdout, ssh_stderr = client.exec_command("vncserver && vncserver -list")
|
||
|
ssh_stdin.channel.shutdown_write()
|
||
|
|
||
|
if "You will require a password to access your desktops" in ssh_stderr.read().decode('utf-8'):
|
||
|
# create the vncserver's password if not done so, then create the session again and just return, since ssh_stdout did not refreshes outside the if
|
||
|
# TODO: add option that user can have a view-only password
|
||
|
ssh_stdin, ssh_stdout, ssh_stderr = client.exec_command("vncpasswd")
|
||
|
ssh_stdin.write(f"{vnc_passwd}\n")
|
||
|
ssh_stdin.write(f"{vnc_passwd}\n")
|
||
|
ssh_stdin.write("n\n")
|
||
|
ssh_stdin.flush()
|
||
|
ssh_stdin, ssh_stdout, ssh_stderr = client.exec_command("vncserver && vncserver -list")
|
||
|
return ssh_stdout.readlines()[-1].split()[0][1:]
|
||
|
return ssh_stdout.readlines()[-1].split()[0][1:]
|
||
|
|
||
|
|
||
|
def kill_srv(client: paramiko.SSHClient, host: str, username: str, password: str, port: str) -> NoReturn:
|
||
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||
|
client.connect(host, username=username, password=password)
|
||
|
client.exec_command(f"vncserver -kill :{port}")
|
||
|
|
||
|
|
||
|
def on_chk(e):
|
||
|
if frame.localhost_ck.GetValue():
|
||
|
frame.localhost.Enable(False)
|
||
|
frame.localhost.SetValue("127.0.0.1")
|
||
|
else:
|
||
|
frame.localhost.Enable(True)
|
||
|
|
||
|
|
||
|
def run(e):
|
||
|
# wrapper for main to ensure is not frozen I guess
|
||
|
task = Thread(target=main)
|
||
|
task.setDaemon(True)
|
||
|
task.start()
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
console_title = 'Program Crashed! Here are the details' # this is there for now to redirect any errors
|
||
|
app = wx.App(useBestVisual=True)
|
||
|
frame = Frame(None)
|
||
|
app.SetTopWindow(frame)
|
||
|
# set where the uncaught errors should be displayed
|
||
|
console = wx.PyOnDemandOutputWindow(console_title)
|
||
|
console.SetParent(frame)
|
||
|
# sys.stderr = console
|
||
|
frame.SetTitle("ECE-SSH_dev_1.1")
|
||
|
frame.run.Bind(wx.EVT_BUTTON, run)
|
||
|
frame.Bind(wx.EVT_CHECKBOX, on_chk)
|
||
|
frame.Show()
|
||
|
app.MainLoop()
|
||
|
|
||
|
# MAGIC_USERNAME_KEY = 'im_the_magic_username_key'
|
||
|
#
|
||
|
# # the service is just a namespace for your app
|
||
|
# service_id = 'IM_YOUR_APP!'
|
||
|
#
|
||
|
# username = 'dustin'
|
||
|
#
|
||
|
# # save password
|
||
|
# keyring.set_password(service_id, username, "password")
|
||
|
#
|
||
|
# # optionally, abuse `set_password` to save username onto keyring
|
||
|
# # we're just using some known magic string in the username field
|
||
|
# keyring.set_password(service_id, MAGIC_USERNAME_KEY, username)
|
||
|
# # username = keyring.get_password(service_id, MAGIC_USERNAME_KEY)
|
||
|
# # password = keyring.get_password(service_id, username)
|
||
|
# # print(username, password)
|