Index: third_party/pexpect/examples/cgishell.cgi |
diff --git a/third_party/pexpect/examples/cgishell.cgi b/third_party/pexpect/examples/cgishell.cgi |
new file mode 100644 |
index 0000000000000000000000000000000000000000..23bef5f54f7eb4745ccca1ef5fc689a55eef4082 |
--- /dev/null |
+++ b/third_party/pexpect/examples/cgishell.cgi |
@@ -0,0 +1,766 @@ |
+#!/usr/bin/python |
+##!/usr/bin/env python |
+"""CGI shell server |
+ |
+This exposes a shell terminal on a web page. |
+It uses AJAX to send keys and receive screen updates. |
+The client web browser needs nothing but CSS and Javascript. |
+ |
+ --hostname : sets the remote host name to open an ssh connection to. |
+ --username : sets the user name to login with |
+ --password : (optional) sets the password to login with |
+ --port : set the local port for the server to listen on |
+ --watch : show the virtual screen after each client request |
+ |
+This project is probably not the most security concious thing I've ever built. |
+This should be considered an experimental tool -- at best. |
+""" |
+ |
+from __future__ import absolute_import |
+from __future__ import print_function |
+ |
+import sys,os |
+sys.path.insert (0,os.getcwd()) # let local modules precede any installed modules |
+import socket, random, string, traceback, cgi, time, getopt, getpass, threading, resource, signal |
+import pxssh, pexpect, ANSI |
+ |
+def exit_with_usage(exit_code=1): |
+ print(globals()['__doc__']) |
+ os._exit(exit_code) |
+ |
+def client (command, host='localhost', port=-1): |
+ """This sends a request to the server and returns the response. |
+ If port <= 0 then host is assumed to be the filename of a Unix domain socket. |
+ If port > 0 then host is an inet hostname. |
+ """ |
+ if port <= 0: |
+ s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
+ s.connect(host) |
+ else: |
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
+ s.connect((host, port)) |
+ s.send(command) |
+ data = s.recv (2500) |
+ s.close() |
+ return data |
+ |
+def server (hostname, username, password, socket_filename='/tmp/server_sock', daemon_mode = True, verbose=False): |
+ """This starts and services requests from a client. |
+ If daemon_mode is True then this forks off a separate daemon process and returns the daemon's pid. |
+ If daemon_mode is False then this does not return until the server is done. |
+ """ |
+ if daemon_mode: |
+ mypid_name = '/tmp/%d.pid' % os.getpid() |
+ daemon_pid = daemonize(daemon_pid_filename=mypid_name) |
+ time.sleep(1) |
+ if daemon_pid != 0: |
+ os.unlink(mypid_name) |
+ return daemon_pid |
+ |
+ virtual_screen = ANSI.ANSI (24,80) |
+ child = pxssh.pxssh() |
+ try: |
+ child.login (hostname, username, password, login_naked=True) |
+ except: |
+ return |
+ if verbose: print('login OK') |
+ virtual_screen.write (child.before) |
+ virtual_screen.write (child.after) |
+ |
+ if os.path.exists(socket_filename): os.remove(socket_filename) |
+ s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
+ s.bind(socket_filename) |
+ os.chmod(socket_filename, 0o777) |
+ if verbose: print('Listen') |
+ s.listen(1) |
+ |
+ r = roller (endless_poll, (child, child.PROMPT, virtual_screen)) |
+ r.start() |
+ if verbose: print("started screen-poll-updater in background thread") |
+ sys.stdout.flush() |
+ try: |
+ while True: |
+ conn, addr = s.accept() |
+ if verbose: print('Connected by', addr) |
+ data = conn.recv(1024) |
+ request = data.split(' ', 1) |
+ if len(request)>1: |
+ cmd = request[0].strip() |
+ arg = request[1].strip() |
+ else: |
+ cmd = request[0].strip() |
+ arg = '' |
+ |
+ if cmd == 'exit': |
+ r.cancel() |
+ break |
+ elif cmd == 'sendline': |
+ child.sendline (arg) |
+ time.sleep(0.1) |
+ shell_window = str(virtual_screen) |
+ elif cmd == 'send' or cmd=='xsend': |
+ if cmd=='xsend': |
+ arg = arg.decode("hex") |
+ child.send (arg) |
+ time.sleep(0.1) |
+ shell_window = str(virtual_screen) |
+ elif cmd == 'cursor': |
+ shell_window = '%x,%x' % (virtual_screen.cur_r, virtual_screen.cur_c) |
+ elif cmd == 'refresh': |
+ shell_window = str(virtual_screen) |
+ elif cmd == 'hash': |
+ shell_window = str(hash(str(virtual_screen))) |
+ |
+ response = [] |
+ response.append (shell_window) |
+ if verbose: print('\n'.join(response)) |
+ sent = conn.send('\n'.join(response)) |
+ if sent < len (response): |
+ if verbose: print("Sent is too short. Some data was cut off.") |
+ conn.close() |
+ except e: |
+ pass |
+ r.cancel() |
+ if verbose: print("cleaning up socket") |
+ s.close() |
+ if os.path.exists(socket_filename): os.remove(socket_filename) |
+ if verbose: print("server done!") |
+ |
+class roller (threading.Thread): |
+ """This class continuously loops a function in a thread. |
+ This is basically a thin layer around Thread with a |
+ while loop and a cancel. |
+ """ |
+ def __init__(self, function, args=[], kwargs={}): |
+ threading.Thread.__init__(self) |
+ self.function = function |
+ self.args = args |
+ self.kwargs = kwargs |
+ self.finished = threading.Event() |
+ def cancel(self): |
+ """Stop the roller.""" |
+ self.finished.set() |
+ def run(self): |
+ while not self.finished.isSet(): |
+ self.function(*self.args, **self.kwargs) |
+ |
+def endless_poll (child, prompt, screen, refresh_timeout=0.1): |
+ """This keeps the screen updated with the output of the child. |
+ This will be run in a separate thread. See roller class. |
+ """ |
+ #child.logfile_read = screen |
+ try: |
+ s = child.read_nonblocking(4000, 0.1) |
+ screen.write(s) |
+ except: |
+ pass |
+ |
+def daemonize (stdin=None, stdout=None, stderr=None, daemon_pid_filename=None): |
+ """This runs the current process in the background as a daemon. |
+ The arguments stdin, stdout, stderr allow you to set the filename that the daemon reads and writes to. |
+ If they are set to None then all stdio for the daemon will be directed to /dev/null. |
+ If daemon_pid_filename is set then the pid of the daemon will be written to it as plain text |
+ and the pid will be returned. If daemon_pid_filename is None then this will return None. |
+ """ |
+ UMASK = 0 |
+ WORKINGDIR = "/" |
+ MAXFD = 1024 |
+ |
+ # The stdio file descriptors are redirected to /dev/null by default. |
+ if hasattr(os, "devnull"): |
+ DEVNULL = os.devnull |
+ else: |
+ DEVNULL = "/dev/null" |
+ if stdin is None: stdin = DEVNULL |
+ if stdout is None: stdout = DEVNULL |
+ if stderr is None: stderr = DEVNULL |
+ |
+ try: |
+ pid = os.fork() # fork first child |
+ except OSError as e: |
+ raise Exception("%s [%d]" % (e.strerror, e.errno)) |
+ |
+ if pid != 0: |
+ os.waitpid(pid,0) |
+ if daemon_pid_filename is not None: |
+ daemon_pid = int(file(daemon_pid_filename,'r').read()) |
+ return daemon_pid |
+ else: |
+ return None |
+ |
+ # first child |
+ os.setsid() |
+ signal.signal(signal.SIGHUP, signal.SIG_IGN) |
+ |
+ try: |
+ pid = os.fork() # fork second child |
+ except OSError as e: |
+ raise Exception("%s [%d]" % (e.strerror, e.errno)) |
+ |
+ if pid != 0: |
+ if daemon_pid_filename is not None: |
+ file(daemon_pid_filename,'w').write(str(pid)) |
+ os._exit(0) # exit parent (the first child) of the second child. |
+ |
+ # second child |
+ os.chdir(WORKINGDIR) |
+ os.umask(UMASK) |
+ |
+ maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] |
+ if maxfd == resource.RLIM_INFINITY: |
+ maxfd = MAXFD |
+ |
+ # close all file descriptors |
+ for fd in range(0, maxfd): |
+ try: |
+ os.close(fd) |
+ except OSError: # fd wasn't open to begin with (ignored) |
+ pass |
+ |
+ os.open (DEVNULL, os.O_RDWR) # standard input |
+ |
+ # redirect standard file descriptors |
+ si = open(stdin, 'r') |
+ so = open(stdout, 'a+') |
+ se = open(stderr, 'a+', 0) |
+ os.dup2(si.fileno(), sys.stdin.fileno()) |
+ os.dup2(so.fileno(), sys.stdout.fileno()) |
+ os.dup2(se.fileno(), sys.stderr.fileno()) |
+ |
+ return 0 |
+ |
+def client_cgi (): |
+ """This handles the request if this script was called as a cgi. |
+ """ |
+ sys.stderr = sys.stdout |
+ ajax_mode = False |
+ TITLE="Shell" |
+ SHELL_OUTPUT="" |
+ SID="NOT" |
+ print("Content-type: text/html;charset=utf-8\r\n") |
+ try: |
+ form = cgi.FieldStorage() |
+ if 'ajax' in form: |
+ ajax_mode = True |
+ ajax_cmd = form['ajax'].value |
+ SID=form['sid'].value |
+ if ajax_cmd == 'send': |
+ command = 'xsend' |
+ arg = form['arg'].value.encode('hex') |
+ result = client (command + ' ' + arg, '/tmp/'+SID) |
+ print(result) |
+ elif ajax_cmd == 'refresh': |
+ command = 'refresh' |
+ result = client (command, '/tmp/'+SID) |
+ print(result) |
+ elif ajax_cmd == 'cursor': |
+ command = 'cursor' |
+ result = client (command, '/tmp/'+SID) |
+ print(result) |
+ elif ajax_cmd == 'exit': |
+ command = 'exit' |
+ result = client (command, '/tmp/'+SID) |
+ print(result) |
+ elif ajax_cmd == 'hash': |
+ command = 'hash' |
+ result = client (command, '/tmp/'+SID) |
+ print(result) |
+ elif 'sid' not in form: |
+ SID=random_sid() |
+ print(LOGIN_HTML % locals()); |
+ else: |
+ SID=form['sid'].value |
+ if 'start_server' in form: |
+ USERNAME = form['username'].value |
+ PASSWORD = form['password'].value |
+ dpid = server ('127.0.0.1', USERNAME, PASSWORD, '/tmp/'+SID) |
+ SHELL_OUTPUT="daemon pid: " + str(dpid) |
+ else: |
+ if 'cli' in form: |
+ command = 'sendline ' + form['cli'].value |
+ else: |
+ command = 'sendline' |
+ SHELL_OUTPUT = client (command, '/tmp/'+SID) |
+ print(CGISH_HTML % locals()) |
+ except: |
+ tb_dump = traceback.format_exc() |
+ if ajax_mode: |
+ print(str(tb_dump)) |
+ else: |
+ SHELL_OUTPUT=str(tb_dump) |
+ print(CGISH_HTML % locals()) |
+ |
+def server_cli(): |
+ """This is the command line interface to starting the server. |
+ This handles things if the script was not called as a CGI |
+ (if you run it from the command line). |
+ """ |
+ try: |
+ optlist, args = getopt.getopt(sys.argv[1:], 'h?d', ['help','h','?', 'hostname=', 'username=', 'password=', 'port=', 'watch']) |
+ except Exception as e: |
+ print(str(e)) |
+ exit_with_usage() |
+ |
+ command_line_options = dict(optlist) |
+ options = dict(optlist) |
+ # There are a million ways to cry for help. These are but a few of them. |
+ if [elem for elem in command_line_options if elem in ['-h','--h','-?','--?','--help']]: |
+ exit_with_usage(0) |
+ |
+ hostname = "127.0.0.1" |
+ #port = 1664 |
+ username = os.getenv('USER') |
+ password = "" |
+ daemon_mode = False |
+ if '-d' in options: |
+ daemon_mode = True |
+ if '--watch' in options: |
+ watch_mode = True |
+ else: |
+ watch_mode = False |
+ if '--hostname' in options: |
+ hostname = options['--hostname'] |
+ if '--port' in options: |
+ port = int(options['--port']) |
+ if '--username' in options: |
+ username = options['--username'] |
+ if '--password' in options: |
+ password = options['--password'] |
+ else: |
+ password = getpass.getpass('password: ') |
+ |
+ server (hostname, username, password, '/tmp/mysock', daemon_mode) |
+ |
+def random_sid (): |
+ a=random.randint(0,65535) |
+ b=random.randint(0,65535) |
+ return '%04x%04x.sid' % (a,b) |
+ |
+def parse_host_connect_string (hcs): |
+ """This parses a host connection string in the form |
+ username:password@hostname:port. All fields are options expcet hostname. A |
+ dictionary is returned with all four keys. Keys that were not included are |
+ set to empty strings ''. Note that if your password has the '@' character |
+ then you must backslash escape it. |
+ """ |
+ if '@' in hcs: |
+ p = re.compile (r'(?P<username>[^@:]*)(:?)(?P<password>.*)(?!\\)@(?P<hostname>[^:]*):?(?P<port>[0-9]*)') |
+ else: |
+ p = re.compile (r'(?P<username>)(?P<password>)(?P<hostname>[^:]*):?(?P<port>[0-9]*)') |
+ m = p.search (hcs) |
+ d = m.groupdict() |
+ d['password'] = d['password'].replace('\\@','@') |
+ return d |
+ |
+def pretty_box (s, rows=24, cols=80): |
+ """This puts an ASCII text box around the given string. |
+ """ |
+ top_bot = '+' + '-'*cols + '+\n' |
+ return top_bot + '\n'.join(['|'+line+'|' for line in s.split('\n')]) + '\n' + top_bot |
+ |
+def main (): |
+ if os.getenv('REQUEST_METHOD') is None: |
+ server_cli() |
+ else: |
+ client_cgi() |
+ |
+# It's mostly HTML and Javascript from here on out. |
+CGISH_HTML="""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
+<html> |
+<head> |
+<title>%(TITLE)s %(SID)s</title> |
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
+<style type=text/css> |
+a {color: #9f9; text-decoration: none} |
+a:hover {color: #0f0} |
+hr {color: #0f0} |
+html,body,textarea,input,form |
+{ |
+font-family: "Courier New", Courier, mono; |
+font-size: 8pt; |
+color: #0c0; |
+background-color: #020; |
+margin:0; |
+padding:0; |
+border:0; |
+} |
+input { background-color: #010; } |
+textarea { |
+border-width:1; |
+border-style:solid; |
+border-color:#0c0; |
+padding:3; |
+margin:3; |
+} |
+</style> |
+ |
+<script language="JavaScript"> |
+function focus_first() |
+{if (document.forms.length > 0) |
+{var TForm = document.forms[0]; |
+for (i=0;i<TForm.length;i++){ |
+if ((TForm.elements[i].type=="text")|| |
+(TForm.elements[i].type=="textarea")|| |
+(TForm.elements[i].type.toString().charAt(0)=="s")) |
+{document.forms[0].elements[i].focus();break;}}}} |
+ |
+// JavaScript Virtual Keyboard |
+// If you like this code then buy me a sandwich. |
+// Noah Spurrier <noah@noah.org> |
+var flag_shift=0; |
+var flag_shiftlock=0; |
+var flag_ctrl=0; |
+var ButtonOnColor="#ee0"; |
+ |
+function init () |
+{ |
+ // hack to set quote key to show both single quote and double quote |
+ document.form['quote'].value = "'" + ' "'; |
+ //refresh_screen(); |
+ poll(); |
+ document.form["cli"].focus(); |
+} |
+function get_password () |
+{ |
+ var username = prompt("username?",""); |
+ var password = prompt("password?",""); |
+ start_server (username, password); |
+} |
+function multibrowser_ajax () |
+{ |
+ var xmlHttp = false; |
+/*@cc_on @*/ |
+/*@if (@_jscript_version >= 5) |
+ try |
+ { |
+ xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); |
+ } |
+ catch (e) |
+ { |
+ try |
+ { |
+ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); |
+ } |
+ catch (e2) |
+ { |
+ xmlHttp = false; |
+ } |
+ } |
+@end @*/ |
+ |
+ if (!xmlHttp && typeof XMLHttpRequest != 'undefined') |
+ { |
+ xmlHttp = new XMLHttpRequest(); |
+ } |
+ return xmlHttp; |
+} |
+function load_url_to_screen(url) |
+{ |
+ xmlhttp = multibrowser_ajax(); |
+ //window.XMLHttpRequest?new XMLHttpRequest(): new ActiveXObject("Microsoft.XMLHTTP"); |
+ xmlhttp.onreadystatechange = update_virtual_screen; |
+ xmlhttp.open("GET", url); |
+ xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"); |
+ xmlhttp.send(null); |
+} |
+function update_virtual_screen() |
+{ |
+ if ((xmlhttp.readyState == 4) && (xmlhttp.status == 200)) |
+ { |
+ var screen_text = xmlhttp.responseText; |
+ document.form["screen_text"].value = screen_text; |
+ //var json_data = json_parse(xmlhttp.responseText); |
+ } |
+} |
+function poll() |
+{ |
+ refresh_screen(); |
+ timerID = setTimeout("poll()", 2000); |
+ // clearTimeout(timerID); |
+} |
+//function start_server (username, password) |
+//{ |
+// load_url_to_screen('cgishell.cgi?ajax=serverstart&username=' + escape(username) + '&password=' + escape(password); |
+//} |
+function refresh_screen() |
+{ |
+ load_url_to_screen('cgishell.cgi?ajax=refresh&sid=%(SID)s'); |
+} |
+function query_hash() |
+{ |
+ load_url_to_screen('cgishell.cgi?ajax=hash&sid=%(SID)s'); |
+} |
+function query_cursor() |
+{ |
+ load_url_to_screen('cgishell.cgi?ajax=cursor&sid=%(SID)s'); |
+} |
+function exit_server() |
+{ |
+ load_url_to_screen('cgishell.cgi?ajax=exit&sid=%(SID)s'); |
+} |
+function type_key (chars) |
+{ |
+ var ch = '?'; |
+ if (flag_shiftlock || flag_shift) |
+ { |
+ ch = chars.substr(1,1); |
+ } |
+ else if (flag_ctrl) |
+ { |
+ ch = chars.substr(2,1); |
+ } |
+ else |
+ { |
+ ch = chars.substr(0,1); |
+ } |
+ load_url_to_screen('cgishell.cgi?ajax=send&sid=%(SID)s&arg=' + escape(ch)); |
+ if (flag_shift || flag_ctrl) |
+ { |
+ flag_shift = 0; |
+ flag_ctrl = 0; |
+ } |
+ update_button_colors(); |
+} |
+ |
+function key_shiftlock() |
+{ |
+ flag_ctrl = 0; |
+ flag_shift = 0; |
+ if (flag_shiftlock) |
+ { |
+ flag_shiftlock = 0; |
+ } |
+ else |
+ { |
+ flag_shiftlock = 1; |
+ } |
+ update_button_colors(); |
+} |
+ |
+function key_shift() |
+{ |
+ if (flag_shift) |
+ { |
+ flag_shift = 0; |
+ } |
+ else |
+ { |
+ flag_ctrl = 0; |
+ flag_shiftlock = 0; |
+ flag_shift = 1; |
+ } |
+ update_button_colors(); |
+} |
+function key_ctrl () |
+{ |
+ if (flag_ctrl) |
+ { |
+ flag_ctrl = 0; |
+ } |
+ else |
+ { |
+ flag_ctrl = 1; |
+ flag_shiftlock = 0; |
+ flag_shift = 0; |
+ } |
+ |
+ update_button_colors(); |
+} |
+function update_button_colors () |
+{ |
+ if (flag_ctrl) |
+ { |
+ document.form['Ctrl'].style.backgroundColor = ButtonOnColor; |
+ document.form['Ctrl2'].style.backgroundColor = ButtonOnColor; |
+ } |
+ else |
+ { |
+ document.form['Ctrl'].style.backgroundColor = document.form.style.backgroundColor; |
+ document.form['Ctrl2'].style.backgroundColor = document.form.style.backgroundColor; |
+ } |
+ if (flag_shift) |
+ { |
+ document.form['Shift'].style.backgroundColor = ButtonOnColor; |
+ document.form['Shift2'].style.backgroundColor = ButtonOnColor; |
+ } |
+ else |
+ { |
+ document.form['Shift'].style.backgroundColor = document.form.style.backgroundColor; |
+ document.form['Shift2'].style.backgroundColor = document.form.style.backgroundColor; |
+ } |
+ if (flag_shiftlock) |
+ { |
+ document.form['ShiftLock'].style.backgroundColor = ButtonOnColor; |
+ } |
+ else |
+ { |
+ document.form['ShiftLock'].style.backgroundColor = document.form.style.backgroundColor; |
+ } |
+ |
+} |
+function keyHandler(e) |
+{ |
+ var pressedKey; |
+ if (document.all) { e = window.event; } |
+ if (document.layers) { pressedKey = e.which; } |
+ if (document.all) { pressedKey = e.keyCode; } |
+ pressedCharacter = String.fromCharCode(pressedKey); |
+ type_key(pressedCharacter+pressedCharacter+pressedCharacter); |
+ alert(pressedCharacter); |
+// alert(' Character = ' + pressedCharacter + ' [Decimal value = ' + pressedKey + ']'); |
+} |
+//document.onkeypress = keyHandler; |
+//if (document.layers) |
+// document.captureEvents(Event.KEYPRESS); |
+//http://sniptools.com/jskeys |
+//document.onkeyup = KeyCheck; |
+function KeyCheck(e) |
+{ |
+ var KeyID = (window.event) ? event.keyCode : e.keyCode; |
+ type_key(String.fromCharCode(KeyID)); |
+ e.cancelBubble = true; |
+ window.event.cancelBubble = true; |
+} |
+</script> |
+ |
+</head> |
+ |
+<body onload="init()"> |
+<form id="form" name="form" action="/cgi-bin/cgishell.cgi" method="POST"> |
+<input name="sid" value="%(SID)s" type="hidden"> |
+<textarea name="screen_text" cols="81" rows="25">%(SHELL_OUTPUT)s</textarea> |
+<hr noshade="1"> |
+ <input name="cli" id="cli" type="text" size="80"><br> |
+<table border="0" align="left"> |
+<tr> |
+<td width="86%%" align="center"> |
+ <input name="submit" type="submit" value="Submit"> |
+ <input name="refresh" type="button" value="REFRESH" onclick="refresh_screen()"> |
+ <input name="refresh" type="button" value="CURSOR" onclick="query_cursor()"> |
+ <input name="hash" type="button" value="HASH" onclick="query_hash()"> |
+ <input name="exit" type="button" value="EXIT" onclick="exit_server()"> |
+ <br> |
+ <input type="button" value="Esc" onclick="type_key('\\x1b\\x1b')" /> |
+ <input type="button" value="` ~" onclick="type_key('`~')" /> |
+ <input type="button" value="1!" onclick="type_key('1!')" /> |
+ <input type="button" value="2@" onclick="type_key('2@\\x00')" /> |
+ <input type="button" value="3#" onclick="type_key('3#')" /> |
+ <input type="button" value="4$" onclick="type_key('4$')" /> |
+ <input type="button" value="5%%" onclick="type_key('5%%')" /> |
+ <input type="button" value="6^" onclick="type_key('6^\\x1E')" /> |
+ <input type="button" value="7&" onclick="type_key('7&')" /> |
+ <input type="button" value="8*" onclick="type_key('8*')" /> |
+ <input type="button" value="9(" onclick="type_key('9(')" /> |
+ <input type="button" value="0)" onclick="type_key('0)')" /> |
+ <input type="button" value="-_" onclick="type_key('-_\\x1F')" /> |
+ <input type="button" value="=+" onclick="type_key('=+')" /> |
+ <input type="button" value="BkSp" onclick="type_key('\\x08\\x08\\x08')" /> |
+ <br> |
+ <input type="button" value="Tab" onclick="type_key('\\t\\t')" /> |
+ <input type="button" value="Q" onclick="type_key('qQ\\x11')" /> |
+ <input type="button" value="W" onclick="type_key('wW\\x17')" /> |
+ <input type="button" value="E" onclick="type_key('eE\\x05')" /> |
+ <input type="button" value="R" onclick="type_key('rR\\x12')" /> |
+ <input type="button" value="T" onclick="type_key('tT\\x14')" /> |
+ <input type="button" value="Y" onclick="type_key('yY\\x19')" /> |
+ <input type="button" value="U" onclick="type_key('uU\\x15')" /> |
+ <input type="button" value="I" onclick="type_key('iI\\x09')" /> |
+ <input type="button" value="O" onclick="type_key('oO\\x0F')" /> |
+ <input type="button" value="P" onclick="type_key('pP\\x10')" /> |
+ <input type="button" value="[ {" onclick="type_key('[{\\x1b')" /> |
+ <input type="button" value="] }" onclick="type_key(']}\\x1d')" /> |
+ <input type="button" value="\\ |" onclick="type_key('\\\\|\\x1c')" /> |
+ <br> |
+ <input type="button" id="Ctrl" value="Ctrl" onclick="key_ctrl()" /> |
+ <input type="button" value="A" onclick="type_key('aA\\x01')" /> |
+ <input type="button" value="S" onclick="type_key('sS\\x13')" /> |
+ <input type="button" value="D" onclick="type_key('dD\\x04')" /> |
+ <input type="button" value="F" onclick="type_key('fF\\x06')" /> |
+ <input type="button" value="G" onclick="type_key('gG\\x07')" /> |
+ <input type="button" value="H" onclick="type_key('hH\\x08')" /> |
+ <input type="button" value="J" onclick="type_key('jJ\\x0A')" /> |
+ <input type="button" value="K" onclick="type_key('kK\\x0B')" /> |
+ <input type="button" value="L" onclick="type_key('lL\\x0C')" /> |
+ <input type="button" value="; :" onclick="type_key(';:')" /> |
+ <input type="button" id="quote" value="'" onclick="type_key('\\x27\\x22')" /> |
+ <input type="button" value="Enter" onclick="type_key('\\n\\n')" /> |
+ <br> |
+ <input type="button" id="ShiftLock" value="Caps Lock" onclick="key_shiftlock()" /> |
+ <input type="button" id="Shift" value="Shift" onclick="key_shift()" /> |
+ <input type="button" value="Z" onclick="type_key('zZ\\x1A')" /> |
+ <input type="button" value="X" onclick="type_key('xX\\x18')" /> |
+ <input type="button" value="C" onclick="type_key('cC\\x03')" /> |
+ <input type="button" value="V" onclick="type_key('vV\\x16')" /> |
+ <input type="button" value="B" onclick="type_key('bB\\x02')" /> |
+ <input type="button" value="N" onclick="type_key('nN\\x0E')" /> |
+ <input type="button" value="M" onclick="type_key('mM\\x0D')" /> |
+ <input type="button" value=", <" onclick="type_key(',<')" /> |
+ <input type="button" value=". >" onclick="type_key('.>')" /> |
+ <input type="button" value="/ ?" onclick="type_key('/?')" /> |
+ <input type="button" id="Shift2" value="Shift" onclick="key_shift()" /> |
+ <input type="button" id="Ctrl2" value="Ctrl" onclick="key_ctrl()" /> |
+ <br> |
+ <input type="button" value=" FINAL FRONTIER " onclick="type_key(' ')" /> |
+</td> |
+</tr> |
+</table> |
+</form> |
+</body> |
+</html> |
+""" |
+ |
+LOGIN_HTML="""<html> |
+<head> |
+<title>Shell Login</title> |
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
+<style type=text/css> |
+a {color: #9f9; text-decoration: none} |
+a:hover {color: #0f0} |
+hr {color: #0f0} |
+html,body,textarea,input,form |
+{ |
+font-family: "Courier New", Courier, mono; |
+font-size: 8pt; |
+color: #0c0; |
+background-color: #020; |
+margin:3; |
+padding:0; |
+border:0; |
+} |
+input { background-color: #010; } |
+input,textarea { |
+border-width:1; |
+border-style:solid; |
+border-color:#0c0; |
+padding:3; |
+margin:3; |
+} |
+</style> |
+<script language="JavaScript"> |
+function init () |
+{ |
+ document.login_form["username"].focus(); |
+} |
+</script> |
+</head> |
+<body onload="init()"> |
+<form name="login_form" method="POST"> |
+<input name="start_server" value="1" type="hidden"> |
+<input name="sid" value="%(SID)s" type="hidden"> |
+username: <input name="username" type="text" size="30"><br> |
+password: <input name="password" type="password" size="30"><br> |
+<input name="submit" type="submit" value="enter"> |
+</form> |
+<br> |
+</body> |
+</html> |
+""" |
+ |
+if __name__ == "__main__": |
+ try: |
+ main() |
+ except Exception as e: |
+ print(str(e)) |
+ tb_dump = traceback.format_exc() |
+ print(str(tb_dump)) |
+ |