diff --git a/app.py b/app.py index 70bb36656..1c964d876 100644 --- a/app.py +++ b/app.py @@ -3,10 +3,12 @@ import sys import io import os -from route import app +from route import app, socketio try: if __name__ == "__main__": - app.run() + PORT = 7200 + HOST = '0.0.0.0' + socketio.run(app, host=HOST, port=PORT) except Exception as ex: print ex diff --git a/class/core/public.py b/class/core/public.py index e8e3bfa98..f219f103b 100755 --- a/class/core/public.py +++ b/class/core/public.py @@ -851,3 +851,34 @@ def get_string_arr(t): if s1 == s_arr[i][j]: t_arr.append(str(i) + str(j)) return t_arr + + +def getSSHPort(): + try: + file = '/etc/ssh/sshd_config' + conf = ReadFile(file) + rep = "#*Port\s+([0-9]+)\s*\n" + port = re.search(rep, conf).groups(0)[0] + return int(port) + except: + return 22 + + +def getSSHStatus(): + if os.path.exists('/usr/bin/apt-get'): + status = execShell("service ssh status | grep -P '(dead|stop)'") + else: + import system_api + version = system_api.system_api().getSystemVersion() + if version.find(' Mac ') != -1: + return True + if version.find(' 7.') != -1: + status = execShell("systemctl status sshd.service | grep 'dead'") + else: + status = execShell( + "/etc/init.d/sshd status | grep -e 'stopped' -e '已停'") + if len(status[0]) > 3: + status = False + else: + status = True + return status diff --git a/plugins/webssh/index.html b/plugins/webssh/index.html index 6b0ad312e..a5a499950 100755 --- a/plugins/webssh/index.html +++ b/plugins/webssh/index.html @@ -1,14 +1,10 @@ - \ No newline at end of file diff --git a/plugins/webssh/js/webssh.js b/plugins/webssh/js/webssh.js index 883064e0a..7cd01e883 100755 --- a/plugins/webssh/js/webssh.js +++ b/plugins/webssh/js/webssh.js @@ -1,6 +1,6 @@ -function web_shell() { - var termCols = 100; - var termRows = 29; +function web_shell2() { + var termCols = 50; + var termRows = 12; var sendTotal = 0; if(!socket)socket = io.connect(); var term = new Terminal({ cols: termCols, rows: termRows, screenKeys: true, useStyle: true}); @@ -9,6 +9,7 @@ function web_shell() { term.setOption('cursorBlink', true); socket.on('server_response', function (data) { + console.log('server_response',data); term.write(data.data); if (data.data == '\r\n登出\r\n' || data.data == '登出\r\n' || data.data == '\r\nlogout\r\n' || data.data == 'logout\r\n') { @@ -26,6 +27,7 @@ function web_shell() { } term.on('data', function (data) { + console.log('data',data); socket.emit('webssh', data); }); @@ -33,7 +35,7 @@ function web_shell() { var term_box = layer.open({ type: 1, title: "宝塔终端", - area: ['920px','640px'], + area: ['480px','360px'], closeBtn: 2, shadeClose: false, content: '
\ @@ -109,9 +111,6 @@ function web_shell() {
  • \ 粘贴选中项\
  • \ -
  • \ - 翻译\ -
  • \
  • \ 百度搜索\
  • \ @@ -166,17 +165,6 @@ function web_shell() { } -function shell_translate_text() { - remove_ssh_menu(); - var selectText = getCookie('ssh_selection'); - var loadT = layer.msg('正在翻译...', { icon: 16, time: 1000 * 60, }); - $.get('https://www.bt.cn/api/index/fanyi', { query: selectText }, function (rdata) { - layer.close(loadT); - layer.msg("原文: " + rdata.src + '
    译文: ' + rdata.dst, { time: 1000 * 10, shadeClose: true, shade: 0.01 }); - }, 'JSONP'); - gterm.focus(); -} - function shell_to_baidu() { var selectText = getCookie('ssh_selection'); remove_ssh_menu(); diff --git a/requirements.txt b/requirements.txt index c6b46b9c8..115efc02c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ flask flask_session +flask_socketio gunicorn psutil pillow diff --git a/route/__init__.py b/route/__init__.py index 4261b162b..548c3b77b 100755 --- a/route/__init__.py +++ b/route/__init__.py @@ -10,6 +10,7 @@ import uuid reload(sys) sys.setdefaultencoding('utf8') + from datetime import timedelta from flask import Flask @@ -23,18 +24,25 @@ from flask import url_for from flask_session import Session + sys.path.append(os.getcwd() + "/class/core") import db import public import config_api - app = Flask(__name__, template_folder='templates/default') app.config.version = config_api.config_api().getVersion() # app.config['SECRET_KEY'] = os.urandom(24) # app.secret_key = uuid.UUID(int=uuid.getnode()).hex[-12:] app.config['SECRET_KEY'] = uuid.UUID(int=uuid.getnode()).hex[-12:] app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7) + +# socketio +sys.path.append("/usr/local/lib/python2.7/site-packages") +from flask_socketio import SocketIO, emit, send +socketio = SocketIO() +socketio.init_app(app) + try: from flask_sqlalchemy import SQLAlchemy app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/py_mw_session.db' @@ -195,3 +203,111 @@ def index(reqClass=None, reqAction=None, reqData=None): eval_str = "__import__('" + className + "')." + className + '()' newInstance = eval(eval_str) return publicObject(newInstance, reqAction) + +ssh = None +shell = None +try: + import paramiko + ssh = paramiko.SSHClient() +except: + public.execShell('pip install paramiko==2.0.2 &') + + +def connect_ssh(): + global shell, ssh + print 'connect_ssh' + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + ssh.connect('127.0.0.1', public.getSSHPort()) + except Exception as e: + print 'connect_ssh:', str(e) + if public.getSSHStatus(): + try: + ssh.connect('localhost', public.getSSHPort()) + except: + return False + import firewalls + fw = firewalls.firewalls() + get = common.dict_obj() + get.status = '0' + fw.SetSshStatus(get) + ssh.connect('127.0.0.1', public.GetSSHPort()) + get.status = '1' + fw.SetSshStatus(get) + shell = ssh.invoke_shell(term='xterm', width=100, height=29) + shell.setblocking(0) + return True + + +# 取数据对象 +def get_input_data(data): + pdata = common.dict_obj() + for key in data.keys(): + pdata[key] = str(data[key]) + return pdata + + +@socketio.on('webssh') +def webssh(msg): + emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'}) + print 'webssh', msg + if not isLogined(): + emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'}) + return None + global shell, ssh + ssh_success = True + if not shell: + ssh_success = connect_ssh() + if not shell: + emit('server_response', { + 'data': public.getMsg('INIT_WEBSSH_CONN_ERR')}) + return + if shell.exit_status_ready(): + ssh_success = connect_ssh() + if not ssh_success: + emit('server_response', { + 'data': public.getMsg('INIT_WEBSSH_CONN_ERR')}) + return + shell.send(msg) + try: + time.sleep(0.005) + recv = shell.recv(4096) + emit('server_response', {'data': recv.decode("utf-8")}) + except Exception as ex: + pass + + +@socketio.on('connect_event') +def connected_msg(msg): + connect_ssh() + if not isLogined(): + print 'not login' + emit(pdata.s_response, {'data': public.getMsg('INIT_WEBSSH_LOGOUT')}) + return None + global shell, ssh + print 'connect_event:connected_msg', msg + try: + recv = shell.recv(8192) + print recv + print recv.decode("utf-8") + emit('server_response', {'data': recv.decode("utf-8")}) + except Exception as e: + print 'connect_event:' + str(e) + + +@socketio.on('panel') +def websocket_test(data): + pdata = get_input_data(data) + if not isLogined(): + emit(pdata.s_response, { + 'data': public.returnData(-1, '会话丢失,请重新登陆面板!\r\n')}) + return None + mods = ['site', 'ftp', 'database', 'ajax', 'system', 'crontab', 'files', + 'config', 'panel_data', 'plugin', 'ssl', 'auth', 'firewall', 'panel_wxapp'] + if not pdata['s_module'] in mods: + result = public.returnMsg(False, "INIT_WEBSOCKET_ERR") + else: + result = eval("%s(pdata)" % pdata['s_module']) + if not hasattr(pdata, 's_response'): + pdata.s_response = 'response' + emit(pdata.s_response, {'data': result}) diff --git a/route/static/app/public.js b/route/static/app/public.js index 9495a9789..f49081f26 100755 --- a/route/static/app/public.js +++ b/route/static/app/public.js @@ -1201,12 +1201,14 @@ function loadImage(){ }); } - +var socket, gterm; function webShell() { - var termCols = 100; - var termRows = 29; + var termCols = 50; + var termRows = 12; var sendTotal = 0; - if(!socket)socket = io.connect(); + if(!socket){ + socket = io.connect(); + } var term = new Terminal({ cols: termCols, rows: termRows, screenKeys: true, useStyle: true}); term.open(); gterm = term @@ -1236,8 +1238,8 @@ function webShell() { var term_box = layer.open({ type: 1, - title: "宝塔终端", - area: ['920px','640px'], + title: "本地终端", + area: ['480px','300px'], closeBtn: 2, shadeClose: false, content: '
    \ @@ -1307,18 +1309,9 @@ function webShell() { var menudiv = ''; $("body").append(menudiv); $(".contextmenu").css({ @@ -1370,16 +1363,16 @@ function webShell() { } -function shell_translate_text() { - remove_ssh_menu(); - var selectText = getCookie('ssh_selection'); - var loadT = layer.msg('正在翻译...', { icon: 16, time: 1000 * 60, }); - $.get('https://www.bt.cn/api/index/fanyi', { query: selectText }, function (rdata) { - layer.close(loadT); - layer.msg("原文: " + rdata.src + '
    译文: ' + rdata.dst, { time: 1000 * 10, shadeClose: true, shade: 0.01 }); - }, 'JSONP'); - gterm.focus(); -} +// function shell_translate_text() { +// remove_ssh_menu(); +// var selectText = getCookie('ssh_selection'); +// var loadT = layer.msg('正在翻译...', { icon: 16, time: 1000 * 60, }); +// $.get('https://www.bt.cn/api/index/fanyi', { query: selectText }, function (rdata) { +// layer.close(loadT); +// layer.msg("原文: " + rdata.src + '
    译文: ' + rdata.dst, { time: 1000 * 10, shadeClose: true, shade: 0.01 }); +// }, 'JSONP'); +// gterm.focus(); +// } function shell_to_baidu() { var selectText = getCookie('ssh_selection'); diff --git a/route/static/css/site.css b/route/static/css/site.css index ee1858cf4..20c12694f 100755 --- a/route/static/css/site.css +++ b/route/static/css/site.css @@ -4646,4 +4646,34 @@ select[disabled]{ } .btswitch-btn.bt-waf-firewall{ width:2.4em;height:1.4em;margin-bottom: 0 -} \ No newline at end of file +} + + +/*6.0终端样式*/ +.term-box{ + padding:0 10px 10px; + background-color:#333333; +} +.shell-text-input .bt-input-text-shell{ + width:100%; + padding:10px 10px 0; + border:0 none; + height:60px; + overflow:auto; + resize:none; +} +.shell-text-input .bt-input-text-shell:focus,.shell-text-input .bt-input-text-shell:active{ + border:0 none; + outline:none; +} +.shell-btn-group{ + height:30px; + position:absolute; + bottom:10px; + right:10px; +} +.shell_btn_close{ + margin-right:8px; +} + + diff --git a/route/templates/default/layout.html b/route/templates/default/layout.html index f2370723c..ed1c744c4 100755 --- a/route/templates/default/layout.html +++ b/route/templates/default/layout.html @@ -39,15 +39,23 @@ + + + + + + + + - - + + {% block content %}{% endblock %}