mirror of https://github.com/jumpserver/jumpserver
修正导入select错误
parent
1bc15e57a6
commit
9a897e0cf4
|
@ -8,5 +8,5 @@ urlpatterns = patterns('',
|
|||
url(r'^history/$', log_history),
|
||||
url(r'^log_kill/', log_kill),
|
||||
url(r'^record/$', log_record),
|
||||
url(r'web_terminal/$', web_terminal),
|
||||
url(r'^web_terminal/$', web_terminal),
|
||||
)
|
|
@ -11,9 +11,6 @@ from models import Log
|
|||
from jumpserver.settings import web_socket_host
|
||||
|
||||
|
||||
web_socket_host = 'ws://j:8080/monitor'
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def log_list(request, offset):
|
||||
""" 显示日志 """
|
||||
|
@ -51,7 +48,7 @@ def log_list(request, offset):
|
|||
|
||||
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
|
||||
|
||||
web_socket_uri = web_socket_host
|
||||
web_monitor_uri = '%s/monitor' % web_socket_host
|
||||
return render_to_response('jlog/log_%s.html' % offset, locals(), context_instance=RequestContext(request))
|
||||
|
||||
|
||||
|
@ -106,5 +103,6 @@ def log_record(request):
|
|||
|
||||
|
||||
def web_terminal(request):
|
||||
web_terminal_uri = '%s/terminal' % web_socket_host
|
||||
return render_to_response('jlog/web_terminal.html', locals())
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ root_pw = secret234
|
|||
|
||||
|
||||
[websocket]
|
||||
web_socket_host = 192.168.40.140:3000
|
||||
web_socket_host = ws://192.168.244.129:3000
|
||||
|
||||
|
||||
[mail]
|
||||
|
|
241
run_tornado.py
241
run_tornado.py
|
@ -1,241 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
__author__ = 'liuzheng'
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from tornado.options import options, define, parse_command_line
|
||||
import tornado.wsgi
|
||||
import tornado.web
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.web
|
||||
import tornado.ioloop
|
||||
import tornado.websocket
|
||||
import pty
|
||||
import io
|
||||
import struct
|
||||
import string
|
||||
import random
|
||||
import fcntl
|
||||
import termios
|
||||
import tornado.process
|
||||
import tornado.options
|
||||
import signal
|
||||
import utils
|
||||
import getpass
|
||||
from connect import Jtty
|
||||
|
||||
define('port', type=int, default=8000)
|
||||
|
||||
ioloop = tornado.ioloop.IOLoop.instance()
|
||||
|
||||
class Terminal(tornado.websocket.WebSocketHandler):
|
||||
terminals = set()
|
||||
|
||||
def pty(self):
|
||||
# Make a "unique" id in 4 bytes
|
||||
self.uid = ''.join(
|
||||
random.choice(
|
||||
string.ascii_lowercase + string.ascii_uppercase +
|
||||
string.digits)
|
||||
for _ in range(4))
|
||||
|
||||
self.pid, self.fd = pty.fork()
|
||||
# print "pid:",self.pid,"fd",self.fd,"uid",self.uid
|
||||
if self.pid == 0:
|
||||
# print "Login as", self.user
|
||||
os.execv("/usr/bin/ssh", [self.user, "localhost"])
|
||||
# self.callee = utils.User(name=self.user)
|
||||
# self.determine_user()
|
||||
self.shell()
|
||||
else:
|
||||
self.communicate()
|
||||
|
||||
def determine_user(self):
|
||||
if self.callee is None:
|
||||
# If callee is now known and we have unsecure connection
|
||||
user = self.user
|
||||
|
||||
try:
|
||||
self.callee = utils.User(name=user)
|
||||
except Exception:
|
||||
# self.log.debug("Can't switch to user %s" % user, exc_info=True)
|
||||
self.callee = utils.User(name='nobody')
|
||||
|
||||
assert self.callee is not None
|
||||
|
||||
def shell(self):
|
||||
try:
|
||||
os.chdir(self.path or self.callee.dir)
|
||||
except Exception:
|
||||
pass
|
||||
env = os.environ
|
||||
# If local and local user is the same as login user
|
||||
# We set the env of the user from the browser
|
||||
# Usefull when running as root
|
||||
if self.caller == self.callee:
|
||||
env.update(self.socket.env)
|
||||
env["TERM"] = "xterm-256color"
|
||||
env["COLORTERM"] = "butterfly"
|
||||
env["HOME"] = self.callee.dir
|
||||
# print(self.callee.dir)
|
||||
env["LOCATION"] = "http%s://%s:%d/" % (
|
||||
"s" if not True else "",
|
||||
"localhost", 8001)
|
||||
env["PATH"] = '%s:%s' % (os.path.abspath(os.path.join(
|
||||
os.path.dirname(__file__), 'bin')), env.get("PATH"))
|
||||
|
||||
try:
|
||||
tty = os.ttyname(0).replace('/dev/', '')
|
||||
except Exception:
|
||||
tty = ''
|
||||
|
||||
if self.caller != self.callee:
|
||||
try:
|
||||
os.chown(os.ttyname(0), self.callee.uid, -1)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
utils.add_user_info(
|
||||
self.uid,
|
||||
tty, os.getpid(),
|
||||
self.callee.name, self.request.headers['Host'])
|
||||
|
||||
if os.path.exists('/usr/bin/su'):
|
||||
args = ['/usr/bin/su']
|
||||
else:
|
||||
args = ['/bin/su']
|
||||
|
||||
if sys.platform == 'linux':
|
||||
args.append('-p')
|
||||
if tornado.options.options.shell:
|
||||
args.append('-s')
|
||||
args.append(tornado.options.options.shell)
|
||||
args.append(self.callee.name)
|
||||
os.execvpe(args[0], args, env)
|
||||
|
||||
def communicate(self):
|
||||
fcntl.fcntl(self.fd, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
|
||||
self.reader = io.open(
|
||||
self.fd,
|
||||
'rb',
|
||||
buffering=0,
|
||||
closefd=False
|
||||
)
|
||||
self.writer = io.open(
|
||||
self.fd,
|
||||
'wt',
|
||||
encoding='utf-8',
|
||||
closefd=False
|
||||
)
|
||||
ioloop.add_handler(
|
||||
self.fd, self.shellHandle, ioloop.READ | ioloop.ERROR)
|
||||
|
||||
def allow_draft76(self):
|
||||
# for iOS 5.0 Safari
|
||||
return True
|
||||
|
||||
def check_origin(self, origin):
|
||||
return True
|
||||
|
||||
def open(self):
|
||||
print "term socket open"
|
||||
self.fd = None
|
||||
self.closed = False
|
||||
self.socket = utils.Socket(self.ws_connection.stream.socket)
|
||||
self.set_nodelay(True)
|
||||
self.path = None
|
||||
self.user = getpass.getuser()
|
||||
self.caller = self.callee = None
|
||||
# self.user = "liuzheng"
|
||||
self.callee = None
|
||||
|
||||
Terminal.terminals.add(self)
|
||||
|
||||
self.pty()
|
||||
print self.fd
|
||||
|
||||
def on_message(self, msg):
|
||||
print "on_message ", msg
|
||||
if not hasattr(self, 'writer'):
|
||||
self.on_close()
|
||||
self.close()
|
||||
return
|
||||
if msg[0] == 'C': # Change screen
|
||||
c, r = map(int, msg[1:].split(','))
|
||||
s = struct.pack("HHHH", r, c, 0, 0)
|
||||
fcntl.ioctl(self.fd, termios.TIOCSWINSZ, s)
|
||||
elif msg[0] == 'R': # Run shell
|
||||
self.writer.write(msg[1:])
|
||||
self.writer.flush()
|
||||
|
||||
def shellHandle(self, f, events):
|
||||
if events & ioloop.READ:
|
||||
try:
|
||||
read = self.reader.read()
|
||||
except IOError:
|
||||
read = ''
|
||||
|
||||
if read and len(read) != 0 and self.ws_connection:
|
||||
self.write_message(read.decode('utf-8', 'replace'))
|
||||
else:
|
||||
events = ioloop.ERROR
|
||||
|
||||
if events & ioloop.ERROR:
|
||||
self.on_close()
|
||||
self.close()
|
||||
|
||||
def on_close(self):
|
||||
print "term close", self.uid
|
||||
if self.closed:
|
||||
return
|
||||
self.closed = True
|
||||
|
||||
if getattr(self, 'pid', 0) == 0:
|
||||
return
|
||||
|
||||
utils.rm_user_info(self.uid, self.pid)
|
||||
|
||||
try:
|
||||
ioloop.remove_handler(self.fd)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
os.close(self.fd)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
os.kill(self.pid, signal.SIGKILL)
|
||||
os.waitpid(self.pid, 0)
|
||||
except Exception:
|
||||
pass
|
||||
Terminal.terminals.remove(self)
|
||||
|
||||
|
||||
class Index(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
self.render('templates/terminal.html')
|
||||
|
||||
|
||||
def main():
|
||||
sys.path.append('./jumpserver') # path to your project if needed
|
||||
|
||||
parse_command_line()
|
||||
|
||||
tornado_app = tornado.web.Application(
|
||||
[
|
||||
('/ws/terminal', Terminal),
|
||||
('/ws/Terminal', Index),
|
||||
])
|
||||
|
||||
server = tornado.httpserver.HTTPServer(tornado_app)
|
||||
server.listen(options.port)
|
||||
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -16,32 +16,22 @@ import tornado.gen
|
|||
from tornado.websocket import WebSocketClosedError
|
||||
|
||||
from tornado.options import define, options
|
||||
from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE, IN_MODIFY
|
||||
from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE, IN_MODIFY, AsyncNotifier
|
||||
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
|
||||
import gevent
|
||||
# from gevent import monkey
|
||||
# monkey.patch_all()
|
||||
# import gevent
|
||||
from gevent.socket import wait_read, wait_write
|
||||
from gevent.select import select
|
||||
from gevent.event import Event
|
||||
|
||||
import paramiko
|
||||
from paramiko import PasswordRequiredException
|
||||
from paramiko.dsskey import DSSKey
|
||||
from paramiko.rsakey import RSAKey
|
||||
from paramiko.ssh_exception import SSHException
|
||||
|
||||
import socket
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
from StringIO import StringIO
|
||||
|
||||
define("port", default=8080, help="run on the given port", type=int)
|
||||
define("port", default=3000, help="run on the given port", type=int)
|
||||
define("host", default='0.0.0.0', help="run port on", type=str)
|
||||
|
||||
|
||||
|
@ -80,7 +70,7 @@ def file_monitor(path='.', client=None):
|
|||
print "You should monitor a file"
|
||||
sys.exit(3)
|
||||
else:
|
||||
print "now starting monitor %s." %path
|
||||
print "now starting monitor %s." % path
|
||||
global f
|
||||
f = open(path, 'r')
|
||||
st_size = os.stat(path)[6]
|
||||
|
@ -88,7 +78,6 @@ def file_monitor(path='.', client=None):
|
|||
|
||||
while True:
|
||||
try:
|
||||
print "hello world"
|
||||
notifier.process_events()
|
||||
if notifier.check_events():
|
||||
notifier.read_events()
|
||||
|
@ -101,7 +90,6 @@ def file_monitor(path='.', client=None):
|
|||
class Application(tornado.web.Application):
|
||||
def __init__(self):
|
||||
handlers = [
|
||||
(r'/', MainHandler),
|
||||
(r'/monitor', MonitorHandler),
|
||||
(r'/terminal', WebTerminalHandler),
|
||||
]
|
||||
|
@ -164,11 +152,6 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
|
|||
MonitorHandler.threads.remove(MonitorHandler.threads[client_index])
|
||||
|
||||
|
||||
class MainHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
self.render('log_watch.html')
|
||||
|
||||
|
||||
class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
||||
tasks = []
|
||||
|
|
@ -37,7 +37,7 @@ client.connect({
|
|||
*/
|
||||
|
||||
function WSSHClient() {
|
||||
};
|
||||
}
|
||||
|
||||
WSSHClient.prototype._generateEndpoint = function(options) {
|
||||
console.log(options);
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
|
||||
function init(obj){
|
||||
var file_path = obj.attr('file_path');
|
||||
var wsUri = '{{ web_socket_uri }}';
|
||||
var wsUri = '{{ web_monitor_uri }}';
|
||||
var socket = new WebSocket(wsUri + '?file_path=' + file_path);
|
||||
socket.onopen = function(evt){
|
||||
socket.send(file_path)
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>wssh</title>
|
||||
<title>Jumpserver web terminal</title>
|
||||
|
||||
<link href="/static/css/plugins/bootstrap.min.css" rel="stylesheet" />
|
||||
<style>
|
||||
body {
|
||||
padding-top: 60px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
|
@ -29,139 +27,56 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="#">wssh</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- Connection form -->
|
||||
|
||||
<form id="connect" class="form-horizontal">
|
||||
<fieldset>
|
||||
<legend>Connect to a remote SSH server</legend>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Destination
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="username"
|
||||
class="input-small"
|
||||
placeholder="root" />
|
||||
<div class="input-prepend">
|
||||
<span class="add-on">@</span><input
|
||||
type="text"
|
||||
id="hostname"
|
||||
class="input-large"
|
||||
placeholder="localhost" />
|
||||
<span class="add-on">port</span><input
|
||||
type="text"
|
||||
id="portnumber"
|
||||
class="input-small"
|
||||
value=22 />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Authentication method
|
||||
</label>
|
||||
|
||||
<div class="controls">
|
||||
<label class="radio">
|
||||
<input type="radio" name="authentication_method"
|
||||
value="password" checked />
|
||||
Password
|
||||
</label>
|
||||
|
||||
<label class="radio">
|
||||
<input type="radio" name="authentication_method"
|
||||
value="private_key" />
|
||||
Private Key
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" id="password_authentication">
|
||||
<label class="control-label">
|
||||
Password
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="password" id="password"
|
||||
class="input-large" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="private_key_authentication">
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Private Key
|
||||
</label>
|
||||
<div class="controls">
|
||||
<textarea id="private_key" rows="6"
|
||||
class="input-xxlarge"></textarea>
|
||||
<p class="help-block">
|
||||
Copy & Paste your SSH private from
|
||||
<code>~/.ssh/id_rsa</code> or
|
||||
<code>~/.ssh/id_dsa</code>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Key Passphrase
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="password" id="key_passphrase"
|
||||
class="input-large" />
|
||||
<p class="help-block">
|
||||
Enter your private key passphrase if it
|
||||
is encrypted. Leave empty otherwise.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Command
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="command" class="input-large" />
|
||||
<p class="help-block">
|
||||
Enter command to be executed or
|
||||
empty for interactive.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Connect
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div id="term">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="application/javascript" src="/static/js/jquery-2.1.1.js">
|
||||
</script>
|
||||
<script type="application/javascript" src="/static/js/term.js">
|
||||
</script>
|
||||
<script type="application/javascript" src="/static/js/wssh.js">
|
||||
</script>
|
||||
<script type="application/javascript">
|
||||
function WSSHClient() {
|
||||
}
|
||||
|
||||
WSSHClient.prototype.connect = function(options) {
|
||||
var endpoint = '{{ web_terminal_uri }}';
|
||||
|
||||
if (window.WebSocket) {
|
||||
this._connection = new WebSocket(endpoint);
|
||||
}
|
||||
else if (window.MozWebSocket) {
|
||||
this._connection = MozWebSocket(endpoint);
|
||||
}
|
||||
else {
|
||||
options.onError('WebSocket Not Supported');
|
||||
return ;
|
||||
}
|
||||
|
||||
this._connection.onopen = function() {
|
||||
options.onConnect();
|
||||
};
|
||||
|
||||
this._connection.onmessage = function (evt) {
|
||||
var data = JSON.parse(evt.data.toString());
|
||||
if (data.error !== undefined) {
|
||||
options.onError(data.error);
|
||||
}
|
||||
else {
|
||||
options.onData(data.data);
|
||||
}
|
||||
};
|
||||
|
||||
this._connection.onclose = function(evt) {
|
||||
options.onClose();
|
||||
};
|
||||
};
|
||||
|
||||
WSSHClient.prototype.send = function(data) {
|
||||
this._connection.send(JSON.stringify({'data': data}));
|
||||
};
|
||||
|
||||
function openTerminal(options) {
|
||||
var client = new WSSHClient();
|
||||
var term = new Terminal(80, 24, function(key) {
|
||||
|
@ -191,84 +106,11 @@
|
|||
|
||||
<script type='application/javascript'>
|
||||
$(document).ready(function() {
|
||||
$('#ssh').hide();
|
||||
$('#private_key_authentication', '#connect').hide();
|
||||
var options = {
|
||||
};
|
||||
|
||||
$('input:radio[value=private_key]', '#connect').click(
|
||||
function() {
|
||||
$('#password_authentication').hide();
|
||||
$('#private_key_authentication').show();
|
||||
}
|
||||
);
|
||||
|
||||
$('input:radio[value=password]', '#connect').click(
|
||||
function() {
|
||||
$('#password_authentication').show();
|
||||
$('#private_key_authentication').hide();
|
||||
}
|
||||
);
|
||||
|
||||
$('#connect').submit(function(ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
function validate(fields) {
|
||||
var success = true;
|
||||
fields.forEach(function(field) {
|
||||
if (!field.val()) {
|
||||
field.closest('.control-group')
|
||||
.addClass('error');
|
||||
success = false;
|
||||
}
|
||||
});
|
||||
return success;
|
||||
}
|
||||
|
||||
// Clear errors
|
||||
$('.error').removeClass('error');
|
||||
|
||||
var username = $('input:text#username');
|
||||
var hostname = $('input:text#hostname');
|
||||
var portnumber = $('input:text#portnumber');
|
||||
var command = $('input:text#command');
|
||||
|
||||
var authentication = $(
|
||||
'input[name=authentication_method]:checked',
|
||||
'#connect').val();
|
||||
var options = {
|
||||
username: username.val(),
|
||||
hostname: hostname.val(),
|
||||
command: command.val(),
|
||||
authentication_method: authentication
|
||||
};
|
||||
|
||||
var port = parseInt(portnumber.val())
|
||||
if (port > 0 && port < 65535) {
|
||||
$.extend(options, {port: port});
|
||||
} else {
|
||||
$.extend(options, {port: 22});
|
||||
}
|
||||
|
||||
if (authentication == 'password') {
|
||||
var password = $('input:password#password');
|
||||
if (!validate([username, hostname, password]))
|
||||
return false;
|
||||
$.extend(options, {password: password.val()});
|
||||
} else if (authentication == 'private_key') {
|
||||
var private_key = $('textarea#private_key');
|
||||
if (!validate([username, hostname, private_key]))
|
||||
return false;
|
||||
$.extend(options, {private_key: private_key.val()});
|
||||
var key_passphrase = $('input:password#key_passphrase');
|
||||
if (key_passphrase.val()) {
|
||||
$.extend(options,
|
||||
{key_passphrase: key_passphrase.val()});
|
||||
}
|
||||
}
|
||||
|
||||
$('#connect').hide();
|
||||
$('#ssh').show();
|
||||
openTerminal(options);
|
||||
});
|
||||
$('#ssh').show();
|
||||
openTerminal(options);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
Loading…
Reference in New Issue